first commit of the OpenCaps module for ATutor, create by Anotnio Gamba as part of...
authorgreg gay <ggay@ocad.ca>
Tue, 12 Oct 2010 18:55:49 +0000 (18:55 -0000)
committergreg gay <ggay@ocad.ca>
Tue, 12 Oct 2010 18:55:49 +0000 (18:55 -0000)
173 files changed:
mods/atutor_opencaps/README [new file with mode: 0755]
mods/atutor_opencaps/doc/index.html [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/LICENSE.txt [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/README.txt [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/flowplayer-3.2.2.min.js [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/flowplayer-3.2.2.swf [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/flowplayer.audio-3.2.0.swf [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/flowplayer.captions-3.2.1.swf [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/flowplayer.content-3.2.0.swf [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/flowplayer.controls-3.2.1.swf [new file with mode: 0755]
mods/atutor_opencaps/flowplayer/index.html [new file with mode: 0755]
mods/atutor_opencaps/images/AtOpenCaps.png [new file with mode: 0755]
mods/atutor_opencaps/images/index.html [new file with mode: 0755]
mods/atutor_opencaps/images/poster.jpg [new file with mode: 0755]
mods/atutor_opencaps/include/atoc.js [new file with mode: 0755]
mods/atutor_opencaps/include/basic.js [new file with mode: 0755]
mods/atutor_opencaps/include/classes/ATOC_Debug.php [new file with mode: 0755]
mods/atutor_opencaps/include/classes/ATOC_Json.php [new file with mode: 0755]
mods/atutor_opencaps/include/classes/ATOC_ProjectManager.php [new file with mode: 0755]
mods/atutor_opencaps/include/classes/ATOC_ServerFiles.php [new file with mode: 0755]
mods/atutor_opencaps/include/config.inc.php [new file with mode: 0755]
mods/atutor_opencaps/include/index.html [new file with mode: 0755]
mods/atutor_opencaps/include/vitals.inc.php [new file with mode: 0755]
mods/atutor_opencaps/index.php [new file with mode: 0755]
mods/atutor_opencaps/index_admin.php [new file with mode: 0755]
mods/atutor_opencaps/index_instructor.php [new file with mode: 0755]
mods/atutor_opencaps/module.css [new file with mode: 0755]
mods/atutor_opencaps/module.php [new file with mode: 0755]
mods/atutor_opencaps/module.sql [new file with mode: 0755]
mods/atutor_opencaps/module.xml [new file with mode: 0755]
mods/atutor_opencaps/module_install.php [new file with mode: 0755]
mods/atutor_opencaps/module_uninstall.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/about.txt [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/imported/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/imported/noname.JSON [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/imported/noname.srt [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/imported/noname.txt [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_DFXP_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_DvdStl_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_JSONcc_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_MPlayer_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_MicroDvd_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_QTSMIL_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_QTtext_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_RealText_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_Sami_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_Scc_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_SubRipSrt_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_SubViewer_format.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CaptionCollection_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CaptionFormat_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_Caption_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CcService_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_ConversionManager_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTag.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagCollection.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagTrace.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagTraceManager.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_CcUtilVital_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_TimeUtil_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_TxtFileTools_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/config.inc.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/include/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/conversion_service/index.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/editor.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/error_log [new file with mode: 0755]
mods/atutor_opencaps/opencaps/export.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/help.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/application_edit.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/application_get.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/application_put.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/arrow_right.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/asterisk_yellow.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/bullet_delete.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/clip_leftedge.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/clip_next.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/clip_prev.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/clip_rightedge.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/cross.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/door_out.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/end.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/ffwd.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/ffwd2.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/last_start.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/logo.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/middlebar.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/page_gear.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/pause.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/play.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/pressplay.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/rewind.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/rewind2.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/slider-bg-1.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/slider-bg-2.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/slider-handle-ghost.gif [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/slider-handle.gif [new file with mode: 0755]
mods/atutor_opencaps/opencaps/images/start.png [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/basic_header.inc.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/captionCollection_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/caption_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/clip_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/db_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/project_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/system_OcAtutor_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/system_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/time_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/classes/user_class.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/config.inc.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/footer.inc.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/header.inc.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/matterhorn.inc.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/vitals.inc.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/include/workflow.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/index.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/install/config_template.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/install/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/install/oc_schema.sql [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/AC_QuickTime.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/editor.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/export.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/GPL-LICENSE.txt [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/MIT-LICENSE.txt [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/jARIA.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/jquery-1.2.3.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/jquery-1.2.6.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/jquery-1.3.2.min.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/jquery.dimensions.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/jquery.keyboard-a11y.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/jquery.tabindex.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/ui.base.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/ui.core.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/ui.dialog.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/ui.draggable.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/ui.droppable.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/jquery/ui.slider.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/json/json2.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/preview.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/settings.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/start.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/start_remote.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/js/utils.js [new file with mode: 0755]
mods/atutor_opencaps/opencaps/license.txt [new file with mode: 0755]
mods/atutor_opencaps/opencaps/loadmedia.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/login.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/logout.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/preview.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/projects/12-d0679f0984ba38ffc572d0d9718091d37059d5b6/opencaps.json [new file with mode: 0755]
mods/atutor_opencaps/opencaps/projects/3-d0679f0984ba38ffc572d0d9718091d37059d5b6/opencaps.json [new file with mode: 0755]
mods/atutor_opencaps/opencaps/projects/index.html [new file with mode: 0755]
mods/atutor_opencaps/opencaps/projects/layouts/smil_0.mov [new file with mode: 0755]
mods/atutor_opencaps/opencaps/projects/layouts/smil_1.mov [new file with mode: 0755]
mods/atutor_opencaps/opencaps/projects/layouts/smil_2.mov [new file with mode: 0755]
mods/atutor_opencaps/opencaps/projects/opencaps.json [new file with mode: 0755]
mods/atutor_opencaps/opencaps/projects/player_template.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/register.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/scripts/install.sh [new file with mode: 0755]
mods/atutor_opencaps/opencaps/scripts/install_remote_only.sh [new file with mode: 0755]
mods/atutor_opencaps/opencaps/settings.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/start.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/start_remote.php [new file with mode: 0755]
mods/atutor_opencaps/opencaps/styles.css [new file with mode: 0755]
mods/atutor_opencaps/opencaps/styles_ff.css [new file with mode: 0755]
mods/atutor_opencaps/opencaps/styles_ie.css [new file with mode: 0755]
mods/atutor_opencaps/opencaps/styles_public.css [new file with mode: 0755]
mods/atutor_opencaps/player.php [new file with mode: 0755]
mods/atutor_opencaps/service.php [new file with mode: 0755]
mods/atutor_opencaps/service_test.php [new file with mode: 0755]

diff --git a/mods/atutor_opencaps/README b/mods/atutor_opencaps/README
new file mode 100755 (executable)
index 0000000..a109a08
--- /dev/null
@@ -0,0 +1,179 @@
+***********************************\r
+AtOpenCaps: Atutor-OpenCaps Module                                             \r
+***********************************\r
+       Copyright (C) 2010                           \r
+       Written by Antonio Gamba-Bari\r
+       Adaptive Technology Resource Centre - University of Toronto\r
+\r
+       This program is free software. You can redistribute it and/or\r
+       modify it under the terms of the GNU General Public License\r
+       as published by the Free Software Foundation.\r
+\r
+***********************************\r
+\r
+MODULE DETAILS:\r
+---------------\r
+Module Name: AtOpenCaps\r
+version: 1.0\r
+License: GPL\r
+Languages: English (en), Spanish (es-es)\r
+\r
+AtOpenCaps is an Atutor's module; integrating Atutor with OpenCaps, \r
+an open source web-based captioning tool. \r
+\r
+This module loads media and caption files stored in Atutor's course content \r
+directory and manages all transactions needed to deliver and create caption \r
+files using OpenCaps web captioning editor. \r
+\r
+This module provides a modified version of the OpenCaps web captioning tool \r
+and it is located in the "opencaps" directory. However, for updates and future \r
+compatibility, you must check and download new version from the OpenCaps website.\r
+\r
+This module also includes a version of FlowPlayer for previewing captioned projects. \r
+\r
+For additional updates or documentation about the tools used in this module,\r
+please visit:\r
+* Atutor: http://atutor.ca\r
+* OpenCaps: http://opencaps.atrc.utoronto.ca\r
+* Flow Player: http://flowplayer.org\r
+\r
+For revisions, comments, constructive criticism/feedback,\r
+please post an issue at http://www.atutor.ca \r
+and use the keyword  "AtOpenCaps" in your post. \r
+I will try to get back to you as soon as I can.\r
+\r
+Enjoy ! Anto;)\r
+\r
+***********************************\r
+Acknowledgments \r
+***********************************\r
+Special thank you to Heidi Valles, Greg Gay, and Harris Wong \r
+for their support and acute help when I found my self lost.\r
+\r
+Additionally, I want to thank "Google Summer Code" \r
+(http://socghop.appspot.com/)for funding this project.\r
+\r
+\r
+\r
+\r
+***********************************\r
+TABLE OF CONTENTS\r
+***********************************\r
+1. Installation\r
+       1.1. Setting Directory Permissions\r
+       1.2. Un-installation Notes\r
+       1.3. Known Issues\r
+\r
+2. Using AtOpenCaps\r
+       2.1. Uploading Media Files\r
+       2.2. Creating Projects\r
+       2.3. Start Captioning\r
+       2.4. Playing Captioned Media\r
+\r
+3. The Future of This Module\r
+\r
+***********************************\r
+1. Installation\r
+***********************************\r
+\r
+***********************************\r
+1.1. Setting Directory Permissions\r
+***********************************\r
+Open Caps requires reading and writing permissions in two directories: \r
+\r
+/ATutor/mods/AtOpenCaps/opencaps/projects\r
+/ATutor/mods/AtOpenCaps/opencaps/conversion_service\r
+\r
+Please set these permissions accordingly. \r
+\r
+***********************************\r
+1.2. Un-installation Notes\r
+***********************************\r
+AtOpenCaps uses Atutor database to store matching-pairs of media and caption files. \r
+When removing AtOpenCaps module, the the administrator can decide whether to delete this database or not.\r
+\r
+However, removing this module will NOT delete any media file or \r
+captions already stored in the course content directory. \r
+\r
+***********************************\r
+1.3. Known Issues\r
+***********************************\r
+This module was developed at a moment when Atutor is expanding \r
+its compatibility with new media players and captioning media formats. \r
+At the same time, OpenCaps is currently developing new strategies for \r
+communicating with external systems. \r
+\r
+For this reasons, AtOpenCaps module presents the following known issues:\r
+\r
+a) When OpenCaps is loaded for first time. An empty screen shows up. \r
+It is necessary to reload the page and then it will work.\r
+\r
+b) Atutor content rendering class is not ready to display the adequate \r
+tags for flowplayer version flowplayer-3.2.2.swf. Proper handlers are \r
+needed to allow Atutor core code to load the following FlowPlayer plugins:\r
+\r
+       - flowplayer.audio-3.2.0.swf\r
+       - flowplayer.captions-3.2.1.swf\r
+       - flowplayer.content-3.2.0.swf\r
+       - flowplayer.content-3.2.0.swf\r
+\r
+***********************************\r
+2. Using AtOpenCaps\r
+***********************************\r
+\r
+***********************************\r
+2.1. Uploading Media Files\r
+***********************************\r
+To upload a file click on the "Upload Media" tab. This will open Atutor's \r
+File Management utility and allow the user to upload files to the course \r
+content directory. For additional documentation about this utility, \r
+please review "Atutor HandBook": (http://help.atutor.ca/index/index.php).\r
+\r
+***********************************\r
+2.2. Creating Projects\r
+***********************************\r
+In order to create a new project, the user must first upload media \r
+files by clicking on the Upload Media tab. \r
+\r
+To Create a new caption Project, click on the "Add Project" tab. \r
+Then,  set a name of the project, select one of the available media \r
+files from the list, and select either to create an empty caption file \r
+or type the name of a caption file already uploaded to the course content.\r
+\r
+The user can also specify the width and height of the media file. \r
+This will be use to set the adequate size when playing captioning projects. \r
+If not width or height are set, a default size will be used (320x240)\r
+\r
+Note that if the user selects the option "Select An existing Caption", \r
+the name of the existing caption file must be typed manually. \r
+For example, "my_caption_file.srt"\r
+\r
+***********************************\r
+2.3. Start Captioning\r
+***********************************\r
+To start captioning, simply click on "My Caption Projects". \r
+Then, click on the name of the project. This will lunch Open Caps editing tool. \r
+\r
+Note: Once you have finished captioning, remember to click on the link "Finish".\r
+Then, click on the button "Submit Captions to Atutor".  \r
+\r
+***********************************\r
+2.4. Playing Captioned Media\r
+***********************************\r
+To preview a captioning project, click on the "Preview" tab. \r
+Note that by clicking on this link the last project will be opened.\r
+\r
+Finally, click on the image and the Flow player will be loaded \r
+using the corresponding media and caption file.\r
+\r
+***********************************\r
+3. The Future of This Module\r
+***********************************\r
+Although AtOpenCaps version 1.0 provides the basic communication \r
+between OpenCaps and Atutor, the ways in which captioning media can be \r
+played on the web is rapidly evolving. This means that there are many \r
+players out there capable of playing captioned media. \r
+\r
+The future development of this module will include compatibility with \r
+new players as well as a wide range of caption formats.\r
+\r
diff --git a/mods/atutor_opencaps/doc/index.html b/mods/atutor_opencaps/doc/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/flowplayer/LICENSE.txt b/mods/atutor_opencaps/flowplayer/LICENSE.txt
new file mode 100755 (executable)
index 0000000..2a00962
--- /dev/null
@@ -0,0 +1,721 @@
+The Flowplayer Free version is released under the
+GNU GENERAL PUBLIC LICENSE Version 3 (GPL).
+
+The GPL requires that you not remove the Flowplayer copyright notices
+from the user interface. See section 5.d below.
+
+Commercial licenses are available. The commercial player version
+does not require any Flowplayer notices or texts and also provides
+some additional features.
+
+========================================================================
+
+ADDITIONAL TERM per GPL Section 7
+If you convey this program (or any modifications of it) and assume
+contractual liability for the program to recipients of it, you agree
+to indemnify Flowplayer, Ltd. for any liability that those contractual
+assumptions impose on Flowplayer, Ltd.
+
+Except as expressly provided herein, no trademark rights are granted in
+any trademarks of Flowplayer, Ltd. Licensees are granted a limited,
+non-exclusive right to use the mark Flowplayer and the Flowplayer logos
+in connection with unmodified copies of the Program and the copyright
+notices required by section 5.d of the GPL license. For the purposes
+of this limited trademark license grant, customizing the Flowplayer
+by skinning, scripting, or including PlugIns provided by Flowplayer, Ltd.
+is not considered modifying the Program.
+
+Licensees that do modify the Program, taking advantage of the open-source
+license, may not use the Flowplayer mark or Flowplayer logos and must
+change the fullscreen notice (and the non-fullscreen notice, if that
+option is enabled), the copyright notice in the dialog box, and the
+notice on the Canvas as follows:
+
+the full screen (and non-fullscreen equivalent, if activated) notice
+should read: "Based on Flowplayer source code"; in the context menu
+(right-click menu), the link to "About Flowplayer free version #.#.#"
+can remain. The copyright notice can remain, but must be supplemented with
+an additional notice, stating that the licensee modified the Flowplayer. 
+A suitable notice might read "Flowplayer Source code modified by ModOrg 2009";
+for the canvas, the notice should read "Based on Flowplayer source code".
+In addition, licensees that modify the Program must give the modified
+Program a new name that is not confusingly similar to Flowplayer and
+may not distribute it under the name Flowplayer.
+
+========================================================================
+
+
+                    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/mods/atutor_opencaps/flowplayer/README.txt b/mods/atutor_opencaps/flowplayer/README.txt
new file mode 100755 (executable)
index 0000000..f35bc19
--- /dev/null
@@ -0,0 +1,302 @@
+Version history:
+
+3.2.2
+-----
+Fixes:
+- Now recognizes following kind of urls as audio clips: 'mp3:audiostreamname' (ulrs with mp3 prefix and no extension)
+- Now ignores the duration from metadata if we already got one. Fix required for pseudostreaming
+- Fix to reuse buffered data when replaying a clip
+
+3.2.1
+---------
+- Support for RTMP redirects (tested with Wowza loadbalancing)
+- Fixed video size when no size info available in clip metadata
+
+Fixes:
+- Fix to correctly detect if the player SWF name contains a version number and if it does also use the version number
+when it automatically loads the controls plugin.
+
+3.2.0
+-----
+- canvas, controlbar and the content plugin backgound color and border color can be now given with rgb() and rgba() CSS style syntax
+- Added onMouseOver() and onMouseOut() listener registration methods to the Flowplayer API
+- enhancements to RSS playlist. Converted parsing to E4X, yahoo media and flowplayer namespace support. 
+- added feature to obtain bitrate and dimension information to a new clip custom property "bitrates" for future support for bitrate choosing. 
+- added getter for playerSwfName config
+- if clip.url has the string "mp3:" in it, the clip.type will report 'audio'
+- added setKeyboardShortcutsEnabled(), addKeyListener(), removeKeyListener() to FlowplayerBase
+Fixes:
+- onSeek() was not fired when seeking while paused and when using RTMP. An extra onStart was fired too.
+- fireErrorExternal() was not working properly with an error PlayerEvent
+- countPlugins() was throwing an error when a plugin was not found
+- external swf files were not scaled properly
+- the logo was unnecessary shown when going fullscreen if logo.displayTime was being used
+- added a loadPluginWithConfig method to FlowplayerBase, accessible from javascript. Fixed double onload callback call.
+- now handles cuepoint parameters injected using the Adobe Media Encoder
+- showPlugin was not working when config.play was null
+- handles 3-part duration values included in FLV metadata, like "500.123.123"
+- player wasn't always reaching end of video
+- fixed broken buffering: false
+- fixed event dispatching when embedding flowplayer without flowplayer.js (=without playlist config field)
+- fixed safari crashes when unloading player
+- fixed scrubber behaviour with a playlist containing 2 images (or swf) in a row
+- fixed errors in logs when using an RSS playlist
+- fixed OverlayPlayButton that was showing even if it shouldn't on some cases
+- fixed wrong behavior when onBeforeFinish was returning false within playlists
+- /!\ Don't use the fadeIn / fadeOut controlbar's API while using autoHide.
+- fixed play state button with images
+- fixed splash image flickering
+
+3.1.5
+-----
+Fixes:
+- The player went to a locked state when resuming playback after a period that was long enought to send the
+netConnection to an invalid state. Now when resuming playback on an invalid connection the clip starts again from
+the beginning. This is only when using RTMP connections and does not affect progressive download playback.
+- Custom netConnect and netStream events did not pass the info object to JS listeners
+
+3.1.4
+-----
+Fixes:
+- player did not initialize if the controlbar plugin was disabled and if the play button overlay was disabled with play: null
+- works properly without cachebusting on IE
+- RSS playlist parsing now respects the isDefault attribute used in mRSS media group items
+- Fixed passing of connection arguments
+
+3.1.3
+-----
+- enhancements to RSS playlist parsing: Now skips all media:content that have unsupported types. Now the type attribute
+of the media:content element is mandatory and has to be present in the RSS file
+- Possibility to pass a RSS file name with playFeed("playlist.rss") and setPlaylist("playlist.rss") calls.
+- changes to the ConnectionProvider and URLResolver APIs
+- Now automatically uses a plugin that is called 'rtmp' for all clips that have the rtmp-protocol in their URLs.
+- Added possibility to specify all clip properties in an RSS playlist
+
+Fixes:
+- the result of URL resolvers in now cached, and the resolvers will not be used again when a clip is replayed
+- some style properties like 'backgroundGradient' had no effect in config
+- video goes tiny on Firefox: http://flowplayer.org/forum/8/23226
+- RSS playlists: The 'type' attribute value 'audio/mp3' in the media:content element caused an error.
+- Dispatches onMetadata() if an URL resolver changes the clip URL (changes to a different file)
+- error codes and error message were not properly passed to onEvent JS listeners
+
+3.1.2
+-----
+- The domain of the logo url must the same domain from where the player SWF is loaded from.
+- Fullscreen can be toggled by doublclick on the video area.
+Fixes:
+- Player was not initialized correctly when instream playlists were used and the provider used in the instream clips was defined in the common clip.
+- A separator in the Context Menu made the callbacks in the following menu items out of order. Related forum post: http://flowplayer.org/forum/8/22541
+- the width and height settings of a logo were ignored if the logo was a sWF file
+- volume control and mute/unmute were not working after an instream clip had been played
+- now possible to use RTMP for mp3 files
+- Issue 12: cuepointMultiplier was undefined in the clip object set to JS event listeners
+- Issue 14: onBeforeStop was unnecessarily fired when calling setPlaylist() and the player was not playing,
+            additionally onStop was never fired even if onBeforeStop was
+- fixed screen vertical placement problems that reappeared with 3.1.1
+- The rotating animation now has the same size and position as it has after initialized
+
+3.1.1
+-----
+- External configuration files
+- Instream playback
+- Added toggleFullscreen() the API
+- Possibility to specify controls configuration in clips
+- Seek target position is now sent in the onBeforeSeek event
+Fixes:
+- The screen size was initially too small on Firefox (Mac)
+- Did not persist a zero volume value: http://www.flowplayer.org/forum/8/18413
+
+3.1.0
+-----
+New features:
+- clip's can have urlResolvers and connectionProviders
+- Added new configuration options 'connectionCallbacks' and 'streamCallbacks'. Both accept an Array of event names as a value.
+  When these events get fired on the connection or stream object, corresponding Clip events will be fired by the player.
+  This can be used for example when firing custom events from RTMP server apps
+- Added new clip event types: 'onConnectionEvent' and 'onStreamEvent' these get fired when the predefined events happen on the connection and stream objects.
+- Added Security.allowDomain() to allow loaded plugins to script the player
+- Added addClip(clip, index) to the API, index is optional
+- Possibility to view videos without metadata, using clip.metaData: false
+- Now the player's preloader uses the rotating animation instead of a percent text to indicate the progress
+  of loading the player SWF. You can disable the aninamtion by setting buffering: false
+- calling close() now does not send the onStop event
+- Clip's custom properties are now present in the root of the clip argument in all clip events that are sent to JS.
+
+Bug fixes:
+- The preloader sometimes failed to initialize the player
+- Allow seeking while in buffering state: http://flowplayer.org/forum/8/16505
+- Replay of a RTMP stream was failing after the connection had expired
+- Security error when clicking on the screen if there is an image in the playlist loaded from a foreign domain
+- loadPlugin() was not working
+- now fullscreen works with Flash versions older than 9.0.115, in versions that do not support hardware scaling
+- replaying a RTMP stream with an image in front of the stream in the playlist was not working (video stayed hidden). Happened
+  because the server does not send metadata if replaying the same stream.
+- the scrubber is disabled if the clip is not seekable in the first frame: http://flowplayer.org/forum/8/16526
+  By default if the clip has one of following extensions (the typical flash video extensions) it is seekable
+  in the first frame: 'f4b', 'f4p', 'f4v', 'flv'. Added new clip property seekableOnBegin that can be used to override the default.  
+
+3.0.6
+-----
+- added possibility to associate a linkUrl and linkWindow to the canvas
+Fixes:
+- fix for entering fullscreen for Flash versions that don't support the hardware scaled fullscreen-mode
+- when showing images the duration tracking starts only after the image has been completely loaded: http://flowplayer.org/forum/2/15301
+- fix for verifying license keys for domains that have more than 4 labels in them
+- if plugin loading failis because of a IO error, the plugin will be discarded and the player initialization continues:
+
+3.0.4
+-----
+- The "play" pseudo-plugin now supports fadeIn(), fadeOut(), showPlugin(), hidePlugin() and
+  additionally you can configure it like this:
+  // make only the play button invisible (buffering animation is still used)
+  play: { display: 'none' }
+  // disable the play button and the buffering animation
+  play: null
+  // disable the buffering animation
+  buffering: null 
+- Added possibility to seek when in the buffering state: http://flowplayer.org/forum/3/13896
+- Added copyright notices and other GPL required entries to the user interface
+
+Fixes:
+- clip urls were not resolved correctly if the HTML page URL had a query string starting with a question mark (http://flowplayer.org/forum/8/14016#post-14016)
+- Fixed context menu for with IE (commercial version)
+- a cuepoint at time zero was fired several times
+- screen is now arranged correctly even when only bottom or top is defined for it in the configuration
+- Fixed context menu for with IE (commercial version)
+- a cuepoint at time zero was fired several times
+- screen is now arranged correctly even when only bottom or top is defined for it in the configuration
+- Now possible to call play() in an onError handler: http://flowplayer.org/forum/8/12939
+- Does not throw an error if the player cannot persist the volume on the client computer: http://flowplayer.org/forum/8/13286#post-13495
+- Triggering fullscreen does not pause the player in IE
+- The play button overlay no longer has a gap between it's pieces when a label is used: http://flowplayer.org/forum/8/14250
+- clip.update() JS call now resets the duration
+- a label configured for the play button overlay did not work in the commercial version
+
+3.0.3
+-----
+- fixed cuepoint firing: Does not skip cuepoints any more
+- Plugins can now be loaded from a different domain to the flowplayer.swf
+- Specifying a clip to play by just using the 'clip' node in the configuration was not working, a playlist definition was required. This is now fixed.
+- Fixed: A playlist with different providers caused the onMetadata event to fire events with metadata from the previous clip in the playlist. Occurred when moving in the playlist with next() and prev()
+- the opacity setting now works with the logo
+- fadeOut() call to the "screen" plugin was sending the listenerId and pluginName arguments in wrong order
+- stop(), pause(), resume(), close() no longer return the flowplayer object to JS
+- changing the size of the screen in a onFullscreen listener now always works, there was a bug that caused this to fail occasionally
+- fixed using arbitrary SWFs as plugins
+- the API method setPlaylist() no longer starts playing if autoPlay: true, neither it starts buffering if autoBuffering: true
+- the API method play() now accepts an array of clip objects as an argument, the playlist is replaced with the specified clips and playback starts from the 1st clip
+
+3.0.2
+-----
+- setting play: null now works again
+- pressing the play again button overlay does not open a linkUrl associated with a clip
+- now displays a live feed even when the RTMP server does not send any metadata and the onStart method is not therefore dispatched
+- added onMetaData clip event
+- fixed 'orig' scaling: the player went to 'fit' scaling after coming back from fullscreen. This is now fixed and the original dimensions are preserved in non-fullscreen mode.
+- cuepoint times are now given in milliseconds, the firing precision is 100 ms. All cuepoint times are rounded to the nearest 100 ms value (for example 1120 rounds to 1100) 
+- backgroundGradient was drawn over the background image in the canvas and in the content and controlbar plugins. Now it's drawn below the image.
+- added cuepointMultiplier property to clips. This can be used to multiply the time values read from cuepoint metadata embedded into video files.
+- the player's framerate was increased to 24 FPS, makes all animations smoother
+
+3.0.1
+-----
+- Fixed negative cuepoints from common clip. Now these are properly propagated to the clips in playlist.
+- buffering animation is now the same size as the play button overlay
+- commercial version now supports license keys that allows the use of subdomains
+- error messages are now automatically hidden after a 4 second delay. They are also hidden when a new clips
+  starts playing (when onBeforeBegin is fired)
+- added possibility to disable the buffering animation like so: buffering: false
+- pressing the play button overlay does not open a linkUrl associated with a clip
+- license key verification failed if a port number was used in the URL (like in this url: http://mydomain.com:8080/video.html)
+- added audio support, clip has a new "image" property
+- workaround for missing "NetStream.Play.Start" notfication that was happending with Red5. Because of this issue the video was not shown.
+- commercial version has the possibility to change the zIndex of the logo
+
+3.0.0
+-----
+- Removed security errors that happened when loading images from foreign domains (domains other than the domain of the core SWF).
+  Using a backgroundImage on canvas, in the content plugin, and for the controls is also possible to be loaded
+  from a foreign domain - BUT backgroundRepeat cannot be used for foreign images.
+- Now allows the embedding HTML to script the player even if the player is loaded from another domain.
+- Added a 'live' property to Clips, used for live streams.
+- A player embedded to a foreign domain now loads images, css files and other resources from the domain where the palyer SWF was loaded from. This is to generate shorter embed-codes.
+- Added linkUrl and linkWindow properties to the logo, in commercial version you can set these to point to a linked page. The linked page gets opened
+  when the logo is clicked.  Possible values for linkWindow:
+    * "_self" specifies the current frame in the current window.
+    * "_blank" specifies a new window.
+    * "_parent" specifies the parent of the current frame.
+    * "_top" specifies the top-level frame in the current window.
+- Added linkUrl and linkWindow properties to clips. The linked page is opened when the video are is clicked and the corresponding clip has a linkUrl specified.
+- Made the play button overlay and the "Play again" button slightly bigger.
+
+RC4
+---
+- Now shows a "Play again" button at the end of the video/playlist
+- Commercial version shows a Flowplayer logo if invalidKey was supplied, but the otherwise the player works
+- setting play: null in configuration will disable the play button overlay
+- setting opacity for "play" also sets it for the buffering animation
+- Fixed firing of cuepoints too early. Cuepoint firing is now based on stream time and does not rely on timers
+- added onXMPData event listener
+- Should not stop playback too early before the clip is really completed
+- The START event is now delayed so that the metadata is available when the event is fired, METADATA event was removed,
+  new event BEGIN that is dispatched when the playback has been successfully started. Metadata is not normally
+  available when BEGIN is fired. 
+
+RC3
+---
+- stopBuffering() now dispatches the onStop event first if the player is playing/paused/buffering at the time of calling it
+- fixed detection of images based on file extensions
+- fixed some issues with having images in the playlist
+- made it possible to autoBuffer next video while showing an image (image without a duration)
+
+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/mods/atutor_opencaps/flowplayer/flowplayer-3.2.2.min.js b/mods/atutor_opencaps/flowplayer/flowplayer-3.2.2.min.js
new file mode 100755 (executable)
index 0000000..7232437
--- /dev/null
@@ -0,0 +1,24 @@
+/* 
+ * flowplayer.js 3.2.2. The Flowplayer API
+ * 
+ * Copyright 2010 Flowplayer Oy
+ * 
+ * This file is part of Flowplayer.
+ * 
+ * Flowplayer 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.
+ * 
+ * Flowplayer 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 Flowplayer.  If not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Date: 2010-05-20 17:15:38 +0000 (Thu, 20 May 2010)
+ * Revision: 480 
+ */
+(function(){function g(o){console.log("$f.fireEvent",[].slice.call(o))}function k(q){if(!q||typeof q!="object"){return q}var o=new q.constructor();for(var p in q){if(q.hasOwnProperty(p)){o[p]=k(q[p])}}return o}function m(t,q){if(!t){return}var o,p=0,r=t.length;if(r===undefined){for(o in t){if(q.call(t[o],o,t[o])===false){break}}}else{for(var s=t[0];p<r&&q.call(s,p,s)!==false;s=t[++p]){}}return t}function c(o){return document.getElementById(o)}function i(q,p,o){if(typeof p!="object"){return q}if(q&&p){m(p,function(r,s){if(!o||typeof s!="function"){q[r]=s}})}return q}function n(s){var q=s.indexOf(".");if(q!=-1){var p=s.slice(0,q)||"*";var o=s.slice(q+1,s.length);var r=[];m(document.getElementsByTagName(p),function(){if(this.className&&this.className.indexOf(o)!=-1){r.push(this)}});return r}}function f(o){o=o||window.event;if(o.preventDefault){o.stopPropagation();o.preventDefault()}else{o.returnValue=false;o.cancelBubble=true}return false}function j(q,o,p){q[o]=q[o]||[];q[o].push(p)}function e(){return"_"+(""+Math.random()).slice(2,10)}var h=function(t,r,s){var q=this,p={},u={};q.index=r;if(typeof t=="string"){t={url:t}}i(this,t,true);m(("Begin*,Start,Pause*,Resume*,Seek*,Stop*,Finish*,LastSecond,Update,BufferFull,BufferEmpty,BufferStop").split(","),function(){var v="on"+this;if(v.indexOf("*")!=-1){v=v.slice(0,v.length-1);var w="onBefore"+v.slice(2);q[w]=function(x){j(u,w,x);return q}}q[v]=function(x){j(u,v,x);return q};if(r==-1){if(q[w]){s[w]=q[w]}if(q[v]){s[v]=q[v]}}});i(this,{onCuepoint:function(x,w){if(arguments.length==1){p.embedded=[null,x];return q}if(typeof x=="number"){x=[x]}var v=e();p[v]=[x,w];if(s.isLoaded()){s._api().fp_addCuepoints(x,r,v)}return q},update:function(w){i(q,w);if(s.isLoaded()){s._api().fp_updateClip(w,r)}var v=s.getConfig();var x=(r==-1)?v.clip:v.playlist[r];i(x,w,true)},_fireEvent:function(v,y,w,A){if(v=="onLoad"){m(p,function(B,C){if(C[0]){s._api().fp_addCuepoints(C[0],r,B)}});return false}A=A||q;if(v=="onCuepoint"){var z=p[y];if(z){return z[1].call(s,A,w)}}if(y&&"onBeforeBegin,onMetaData,onStart,onUpdate,onResume".indexOf(v)!=-1){i(A,y);if(y.metaData){if(!A.duration){A.duration=y.metaData.duration}else{A.fullDuration=y.metaData.duration}}}var x=true;m(u[v],function(){x=this.call(s,A,y,w)});return x}});if(t.onCuepoint){var o=t.onCuepoint;q.onCuepoint.apply(q,typeof o=="function"?[o]:o);delete t.onCuepoint}m(t,function(v,w){if(typeof w=="function"){j(u,v,w);delete t[v]}});if(r==-1){s.onCuepoint=this.onCuepoint}};var l=function(p,r,q,t){var o=this,s={},u=false;if(t){i(s,t)}m(r,function(v,w){if(typeof w=="function"){s[v]=w;delete r[v]}});i(this,{animate:function(y,z,x){if(!y){return o}if(typeof z=="function"){x=z;z=500}if(typeof y=="string"){var w=y;y={};y[w]=z;z=500}if(x){var v=e();s[v]=x}if(z===undefined){z=500}r=q._api().fp_animate(p,y,z,v);return o},css:function(w,x){if(x!==undefined){var v={};v[w]=x;w=v}r=q._api().fp_css(p,w);i(o,r);return o},show:function(){this.display="block";q._api().fp_showPlugin(p);return o},hide:function(){this.display="none";q._api().fp_hidePlugin(p);return o},toggle:function(){this.display=q._api().fp_togglePlugin(p);return o},fadeTo:function(y,x,w){if(typeof x=="function"){w=x;x=500}if(w){var v=e();s[v]=w}this.display=q._api().fp_fadeTo(p,y,x,v);this.opacity=y;return o},fadeIn:function(w,v){return o.fadeTo(1,w,v)},fadeOut:function(w,v){return o.fadeTo(0,w,v)},getName:function(){return p},getPlayer:function(){return q},_fireEvent:function(w,v,x){if(w=="onUpdate"){var z=q._api().fp_getPlugin(p);if(!z){return}i(o,z);delete o.methods;if(!u){m(z.methods,function(){var B=""+this;o[B]=function(){var C=[].slice.call(arguments);var D=q._api().fp_invoke(p,B,C);return D==="undefined"||D===undefined?o:D}});u=true}}var A=s[w];if(A){var y=A.apply(o,v);if(w.slice(0,1)=="_"){delete s[w]}return y}return o}})};function b(q,G,t){var w=this,v=null,D=false,u,s,F=[],y={},x={},E,r,p,C,o,A;i(w,{id:function(){return E},isLoaded:function(){return(v!==null&&v.fp_play!=undefined&&!D)},getParent:function(){return q},hide:function(H){if(H){q.style.height="0px"}if(w.isLoaded()){v.style.height="0px"}return w},show:function(){q.style.height=A+"px";if(w.isLoaded()){v.style.height=o+"px"}return w},isHidden:function(){return w.isLoaded()&&parseInt(v.style.height,10)===0},load:function(J){if(!w.isLoaded()&&w._fireEvent("onBeforeLoad")!==false){var H=function(){u=q.innerHTML;if(u&&!flashembed.isSupported(G.version)){q.innerHTML=""}flashembed(q,G,{config:t});if(J){J.cached=true;j(x,"onLoad",J)}};var I=0;m(a,function(){this.unload(function(K){if(++I==a.length){H()}})})}return w},unload:function(J){if(this.isFullscreen()&&/WebKit/i.test(navigator.userAgent)){if(J){J(false)}return w}if(u.replace(/\s/g,"")!==""){if(w._fireEvent("onBeforeUnload")===false){if(J){J(false)}return w}D=true;try{if(v){v.fp_close();w._fireEvent("onUnload")}}catch(H){}var I=function(){v=null;q.innerHTML=u;D=false;if(J){J(true)}};setTimeout(I,50)}else{if(J){J(false)}}return w},getClip:function(H){if(H===undefined){H=C}return F[H]},getCommonClip:function(){return s},getPlaylist:function(){return F},getPlugin:function(H){var J=y[H];if(!J&&w.isLoaded()){var I=w._api().fp_getPlugin(H);if(I){J=new l(H,I,w);y[H]=J}}return J},getScreen:function(){return w.getPlugin("screen")},getControls:function(){return w.getPlugin("controls")._fireEvent("onUpdate")},getLogo:function(){try{return w.getPlugin("logo")._fireEvent("onUpdate")}catch(H){}},getPlay:function(){return w.getPlugin("play")._fireEvent("onUpdate")},getConfig:function(H){return H?k(t):t},getFlashParams:function(){return G},loadPlugin:function(K,J,M,L){if(typeof M=="function"){L=M;M={}}var I=L?e():"_";w._api().fp_loadPlugin(K,J,M,I);var H={};H[I]=L;var N=new l(K,null,w,H);y[K]=N;return N},getState:function(){return w.isLoaded()?v.fp_getState():-1},play:function(I,H){var J=function(){if(I!==undefined){w._api().fp_play(I,H)}else{w._api().fp_play()}};if(w.isLoaded()){J()}else{if(D){setTimeout(function(){w.play(I,H)},50)}else{w.load(function(){J()})}}return w},getVersion:function(){var I="flowplayer.js 3.2.0";if(w.isLoaded()){var H=v.fp_getVersion();H.push(I);return H}return I},_api:function(){if(!w.isLoaded()){throw"Flowplayer "+w.id()+" not loaded when calling an API method"}return v},setClip:function(H){w.setPlaylist([H]);return w},getIndex:function(){return p}});m(("Click*,Load*,Unload*,Keypress*,Volume*,Mute*,Unmute*,PlaylistReplace,ClipAdd,Fullscreen*,FullscreenExit,Error,MouseOver,MouseOut").split(","),function(){var H="on"+this;if(H.indexOf("*")!=-1){H=H.slice(0,H.length-1);var I="onBefore"+H.slice(2);w[I]=function(J){j(x,I,J);return w}}w[H]=function(J){j(x,H,J);return w}});m(("pause,resume,mute,unmute,stop,toggle,seek,getStatus,getVolume,setVolume,getTime,isPaused,isPlaying,startBuffering,stopBuffering,isFullscreen,toggleFullscreen,reset,close,setPlaylist,addClip,playFeed,setKeyboardShortcutsEnabled,isKeyboardShortcutsEnabled").split(","),function(){var H=this;w[H]=function(J,I){if(!w.isLoaded()){return w}var K=null;if(J!==undefined&&I!==undefined){K=v["fp_"+H](J,I)}else{K=(J===undefined)?v["fp_"+H]():v["fp_"+H](J)}return K==="undefined"||K===undefined?w:K}});w._fireEvent=function(Q){if(typeof Q=="string"){Q=[Q]}var R=Q[0],O=Q[1],M=Q[2],L=Q[3],K=0;if(t.debug){g(Q)}if(!w.isLoaded()&&R=="onLoad"&&O=="player"){v=v||c(r);o=v.clientHeight;m(F,function(){this._fireEvent("onLoad")});m(y,function(S,T){T._fireEvent("onUpdate")});s._fireEvent("onLoad")}if(R=="onLoad"&&O!="player"){return}if(R=="onError"){if(typeof O=="string"||(typeof O=="number"&&typeof M=="number")){O=M;M=L}}if(R=="onContextMenu"){m(t.contextMenu[O],function(S,T){T.call(w)});return}if(R=="onPluginEvent"||R=="onBeforePluginEvent"){var H=O.name||O;var I=y[H];if(I){I._fireEvent("onUpdate",O);return I._fireEvent(M,Q.slice(3))}return}if(R=="onPlaylistReplace"){F=[];var N=0;m(O,function(){F.push(new h(this,N++,w))})}if(R=="onClipAdd"){if(O.isInStream){return}O=new h(O,M,w);F.splice(M,0,O);for(K=M+1;K<F.length;K++){F[K].index++}}var P=true;if(typeof O=="number"&&O<F.length){C=O;var J=F[O];if(J){P=J._fireEvent(R,M,L)}if(!J||P!==false){P=s._fireEvent(R,M,L,J)}}m(x[R],function(){P=this.call(w,O,M);if(this.cached){x[R].splice(K,1)}if(P===false){return false}K++});return P};function B(){if($f(q)){$f(q).getParent().innerHTML="";p=$f(q).getIndex();a[p]=w}else{a.push(w);p=a.length-1}A=parseInt(q.style.height,10)||q.clientHeight;E=q.id||"fp"+e();r=G.id||E+"_api";G.id=r;t.playerId=E;if(typeof t=="string"){t={clip:{url:t}}}if(typeof t.clip=="string"){t.clip={url:t.clip}}t.clip=t.clip||{};if(q.getAttribute("href",2)&&!t.clip.url){t.clip.url=q.getAttribute("href",2)}s=new h(t.clip,-1,w);t.playlist=t.playlist||[t.clip];var H=0;m(t.playlist,function(){var J=this;if(typeof J=="object"&&J.length){J={url:""+J}}m(t.clip,function(K,L){if(L!==undefined&&J[K]===undefined&&typeof L!="function"){J[K]=L}});t.playlist[H]=J;J=new h(J,H,w);F.push(J);H++});m(t,function(J,K){if(typeof K=="function"){if(s[J]){s[J](K)}else{j(x,J,K)}delete t[J]}});m(t.plugins,function(J,K){if(K){y[J]=new l(J,K,w)}});if(!t.plugins||t.plugins.controls===undefined){y.controls=new l("controls",null,w)}y.canvas=new l("canvas",null,w);function I(J){if(!w.isLoaded()&&w._fireEvent("onBeforeClick")!==false){w.load()}return f(J)}u=q.innerHTML;if(u.replace(/\s/g,"")!==""){if(q.addEventListener){q.addEventListener("click",I,false)}else{if(q.attachEvent){q.attachEvent("onclick",I)}}}else{if(q.addEventListener){q.addEventListener("click",f,false)}w.load()}}if(typeof q=="string"){var z=c(q);if(!z){throw"Flowplayer cannot access element: "+q}else{q=z;B()}}else{B()}}var a=[];function d(o){this.length=o.length;this.each=function(p){m(o,p)};this.size=function(){return o.length}}window.flowplayer=window.$f=function(){var p=null;var o=arguments[0];if(!arguments.length){m(a,function(){if(this.isLoaded()){p=this;return false}});return p||a[0]}if(arguments.length==1){if(typeof o=="number"){return a[o]}else{if(o=="*"){return new d(a)}m(a,function(){if(this.id()==o.id||this.id()==o||this.getParent()==o){p=this;return false}});return p}}if(arguments.length>1){var t=arguments[1],q=(arguments.length==3)?arguments[2]:{};if(typeof t=="string"){t={src:t}}t=i({bgcolor:"#000000",version:[9,0],expressInstall:"http://static.flowplayer.org/swf/expressinstall.swf",cachebusting:true},t);if(typeof o=="string"){if(o.indexOf(".")!=-1){var s=[];m(n(o),function(){s.push(new b(this,k(t),k(q)))});return new d(s)}else{var r=c(o);return new b(r!==null?r:o,t,q)}}else{if(o){return new b(o,t,q)}}}return null};i(window.$f,{fireEvent:function(){var o=[].slice.call(arguments);var q=$f(o[0]);return q?q._fireEvent(o.slice(1)):null},addPlugin:function(o,p){b.prototype[o]=p;return $f},each:m,extend:i});if(typeof jQuery=="function"){jQuery.fn.flowplayer=function(q,p){if(!arguments.length||typeof arguments[0]=="number"){var o=[];this.each(function(){var r=$f(this);if(r){o.push(r)}});return arguments.length?o[arguments[0]]:new d(o)}return this.each(function(){$f(this,k(q),p?k(p):{})})}}})();(function(){var h=document.all,j="http://www.adobe.com/go/getflashplayer",c=typeof jQuery=="function",e=/(\d+)[^\d]+(\d+)[^\d]*(\d*)/,b={width:"100%",height:"100%",id:"_"+(""+Math.random()).slice(9),allowfullscreen:true,allowscriptaccess:"always",quality:"high",version:[3,0],onFail:null,expressInstall:null,w3c:false,cachebusting:false};if(window.attachEvent){window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}})}function i(l,f){if(f){for(key in f){if(f.hasOwnProperty(key)){l[key]=f[key]}}}return l}function a(f,n){var m=[];for(var l in f){if(f.hasOwnProperty(l)){m[l]=n(f[l])}}return m}window.flashembed=function(f,m,l){if(typeof f=="string"){f=document.getElementById(f.replace("#",""))}if(!f){return}if(typeof m=="string"){m={src:m}}return new d(f,i(i({},b),m),l)};var g=i(window.flashembed,{conf:b,getVersion:function(){var f;try{f=navigator.plugins["Shockwave Flash"].description.slice(16)}catch(n){try{var l=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");f=l&&l.GetVariable("$version")}catch(m){}}f=e.exec(f);return f?[f[1],f[3]]:[0,0]},asString:function(l){if(l===null||l===undefined){return null}var f=typeof l;if(f=="object"&&l.push){f="array"}switch(f){case"string":l=l.replace(new RegExp('(["\\\\])',"g"),"\\$1");l=l.replace(/^\s?(\d+\.?\d+)%/,"$1pct");return'"'+l+'"';case"array":return"["+a(l,function(o){return g.asString(o)}).join(",")+"]";case"function":return'"function()"';case"object":var m=[];for(var n in l){if(l.hasOwnProperty(n)){m.push('"'+n+'":'+g.asString(l[n]))}}return"{"+m.join(",")+"}"}return String(l).replace(/\s/g," ").replace(/\'/g,'"')},getHTML:function(o,l){o=i({},o);var n='<object width="'+o.width+'" height="'+o.height+'" id="'+o.id+'" name="'+o.id+'"';if(o.cachebusting){o.src+=((o.src.indexOf("?")!=-1?"&":"?")+Math.random())}if(o.w3c||!h){n+=' data="'+o.src+'" type="application/x-shockwave-flash"'}else{n+=' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'}n+=">";if(o.w3c||h){n+='<param name="movie" value="'+o.src+'" />'}o.width=o.height=o.id=o.w3c=o.src=null;o.onFail=o.version=o.expressInstall=null;for(var m in o){if(o[m]){n+='<param name="'+m+'" value="'+o[m]+'" />'}}var p="";if(l){for(var f in l){if(l[f]){var q=l[f];p+=f+"="+(/function|object/.test(typeof q)?g.asString(q):q)+"&"}}p=p.slice(0,-1);n+='<param name="flashvars" value=\''+p+"' />"}n+="</object>";return n},isSupported:function(f){return k[0]>f[0]||k[0]==f[0]&&k[1]>=f[1]}});var k=g.getVersion();function d(f,n,m){if(g.isSupported(n.version)){f.innerHTML=g.getHTML(n,m)}else{if(n.expressInstall&&g.isSupported([6,65])){f.innerHTML=g.getHTML(i(n,{src:n.expressInstall}),{MMredirectURL:location.href,MMplayerType:"PlugIn",MMdoctitle:document.title})}else{if(!f.innerHTML.replace(/\s/g,"")){f.innerHTML="<h2>Flash version "+n.version+" or greater is required</h2><h3>"+(k[0]>0?"Your version is "+k:"You have no flash plugin installed")+"</h3>"+(f.tagName=="A"?"<p>Click here to download latest version</p>":"<p>Download latest version from <a href='"+j+"'>here</a></p>");if(f.tagName=="A"){f.onclick=function(){location.href=j}}}if(n.onFail){var l=n.onFail.call(this);if(typeof l=="string"){f.innerHTML=l}}}}if(h){window[n.id]=document.getElementById(n.id)}i(this,{getRoot:function(){return f},getOptions:function(){return n},getConf:function(){return m},getApi:function(){return f.firstChild}})}if(c){jQuery.tools=jQuery.tools||{version:"3.2.0"};jQuery.tools.flashembed={conf:b};jQuery.fn.flashembed=function(l,f){return this.each(function(){$(this).data("flashembed",flashembed(this,l,f))})}}})();
\ No newline at end of file
diff --git a/mods/atutor_opencaps/flowplayer/flowplayer-3.2.2.swf b/mods/atutor_opencaps/flowplayer/flowplayer-3.2.2.swf
new file mode 100755 (executable)
index 0000000..598c3e2
Binary files /dev/null and b/mods/atutor_opencaps/flowplayer/flowplayer-3.2.2.swf differ
diff --git a/mods/atutor_opencaps/flowplayer/flowplayer.audio-3.2.0.swf b/mods/atutor_opencaps/flowplayer/flowplayer.audio-3.2.0.swf
new file mode 100755 (executable)
index 0000000..09514e7
Binary files /dev/null and b/mods/atutor_opencaps/flowplayer/flowplayer.audio-3.2.0.swf differ
diff --git a/mods/atutor_opencaps/flowplayer/flowplayer.captions-3.2.1.swf b/mods/atutor_opencaps/flowplayer/flowplayer.captions-3.2.1.swf
new file mode 100755 (executable)
index 0000000..b2588a3
Binary files /dev/null and b/mods/atutor_opencaps/flowplayer/flowplayer.captions-3.2.1.swf differ
diff --git a/mods/atutor_opencaps/flowplayer/flowplayer.content-3.2.0.swf b/mods/atutor_opencaps/flowplayer/flowplayer.content-3.2.0.swf
new file mode 100755 (executable)
index 0000000..33498f4
Binary files /dev/null and b/mods/atutor_opencaps/flowplayer/flowplayer.content-3.2.0.swf differ
diff --git a/mods/atutor_opencaps/flowplayer/flowplayer.controls-3.2.1.swf b/mods/atutor_opencaps/flowplayer/flowplayer.controls-3.2.1.swf
new file mode 100755 (executable)
index 0000000..6187440
Binary files /dev/null and b/mods/atutor_opencaps/flowplayer/flowplayer.controls-3.2.1.swf differ
diff --git a/mods/atutor_opencaps/flowplayer/index.html b/mods/atutor_opencaps/flowplayer/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/images/AtOpenCaps.png b/mods/atutor_opencaps/images/AtOpenCaps.png
new file mode 100755 (executable)
index 0000000..b4132af
Binary files /dev/null and b/mods/atutor_opencaps/images/AtOpenCaps.png differ
diff --git a/mods/atutor_opencaps/images/index.html b/mods/atutor_opencaps/images/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/images/poster.jpg b/mods/atutor_opencaps/images/poster.jpg
new file mode 100755 (executable)
index 0000000..8a4f293
Binary files /dev/null and b/mods/atutor_opencaps/images/poster.jpg differ
diff --git a/mods/atutor_opencaps/include/atoc.js b/mods/atutor_opencaps/include/atoc.js
new file mode 100755 (executable)
index 0000000..5cda5a2
--- /dev/null
@@ -0,0 +1,88 @@
+var xmlHttp\r
+var elementToUpdate = "";\r
+\r
+function openCcProject(projectId)\r
+{ \r
+       xmlHttp=GetXmlHttpObject()\r
+       if (xmlHttp==null)\r
+        {\r
+        alert ("Browser does not support HTTP Request")\r
+        return\r
+        }\r
+       \r
+       // set html element to update\r
+       elementToUpdate = "ATOC_editor";\r
+       \r
+       // set script URL\r
+       var url="mods/AtOpenCaps/include/open_caps_iframe.php"\r
+       \r
+       // set url par name\r
+       url=url+"?id="+projectId\r
+       \r
+       //url=url+"&sid="+Math.random()\r
+       xmlHttp.onreadystatechange=stateChanged \r
+       xmlHttp.open("GET",url,true)\r
+       xmlHttp.send(null)\r
+}\r
+\r
+\r
+function openFileManager()\r
+{ \r
+       xmlHttp=GetXmlHttpObject()\r
+       if (xmlHttp==null)\r
+        {\r
+        alert ("Browser does not support HTTP Request")\r
+        return\r
+        }\r
+       \r
+       // set html element to update\r
+       elementToUpdate = "ATOC_fileManager";\r
+       \r
+       // set script URL\r
+       //var url="mods/_core/file_manager/index.php?framed=1&popup=0"\r
+       var url="mods/AtOpenCaps/include/iframe_fileManager.php"\r
+       //var url="http://localhost/php/_myphp/__phpOO/ATutor_Devel/ATutor-2.0-beta1/mods/AtOpenCaps/include/iframe_fileManager.php"\r
+       //alert(url)\r
+\r
+       // set url par name\r
+       //url=url+"?action=fileManager"\r
+       \r
+       xmlHttp.onreadystatechange=stateChanged \r
+       xmlHttp.open("GET",url,true)\r
+       xmlHttp.send(null)\r
+}\r
+\r
+/*\r
+       update display\r
+*/\r
+function stateChanged() \r
+{ \r
+       if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")\r
+       { \r
+               // set name of <div> id where to show the result\r
+               document.getElementById(elementToUpdate).innerHTML=xmlHttp.responseText;\r
+       } \r
+}\r
+\r
+function GetXmlHttpObject()\r
+{\r
+var xmlHttp=null;\r
+try\r
+ {\r
+ // Firefox, Opera 8.0+, Safari\r
+ xmlHttp=new XMLHttpRequest();\r
+ }\r
+catch (e)\r
+ {\r
+ //Internet Explorer\r
+ try\r
+  {\r
+  xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");\r
+  }\r
+ catch (e)\r
+  {\r
+  xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");\r
+  }\r
+ }\r
+return xmlHttp;\r
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/include/basic.js b/mods/atutor_opencaps/include/basic.js
new file mode 100755 (executable)
index 0000000..037af45
--- /dev/null
@@ -0,0 +1,31 @@
+<!--\r
+function show_hide(a){\r
+  var e=document.getElementById(a);\r
+  //if(!e)return true;\r
+  if(e.style.display=="none"){\r
+    e.style.display="block"\r
+  } else {\r
+    e.style.display="none"\r
+  }\r
+  //return false;\r
+}\r
+        \r
+function changeDivContent(nameOfDiv,newContent)\r
+{\r
+       var div = document.getElementById(nameOfDiv);\r
+       if(div)\r
+       {\r
+               div.innerHTML = newContent;\r
+       }\r
+}\r
+\r
+function confirmDelete(action)\r
+{\r
+       if(confirm("Do you want to delete this project?\nNote: your media files will not be deleted."))\r
+       {\r
+               document.getElementById(action).value = "deleteProject";\r
+               document.getElementById('atocForm').submit();\r
+       } \r
+}\r
+\r
+-->
\ No newline at end of file
diff --git a/mods/atutor_opencaps/include/classes/ATOC_Debug.php b/mods/atutor_opencaps/include/classes/ATOC_Debug.php
new file mode 100755 (executable)
index 0000000..d789a71
--- /dev/null
@@ -0,0 +1,52 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+class AtOpenCapsDebug\r
+{\r
+\r
+       /**\r
+        * Static function: shows AT session and cookie variables \r
+        */\r
+       static public function _seeAlSessionVars()\r
+       {\r
+               // trace $_SESSION\r
+               \r
+               if (count($_SESSION) == 0)\r
+               {\r
+                echo '<br/> Noting in $_SESSION ';\r
+               } else {\r
+               \r
+               echo '<h3>Displaying PHP $_SESSION and $_COOKIE variables</h3>';\r
+               echo '<br/><p>$_SESSION vars</p>';\r
+                       while ($var = each($_SESSION))\r
+                   {\r
+                           printf ("Key <b>%s</b> = <b>%s</b><br>", $var['key'], $var['value']);\r
+                   } \r
+               }\r
+               \r
+               if (count($_COOKIE) == 0)\r
+               {\r
+                echo '<br/> No cookies set';\r
+               } else {\r
+               \r
+               echo '<br/><br/><p>$_COOKIE vars</p>';\r
+               while ($var1 = each($_COOKIE))\r
+                   {\r
+                   printf ("Key <b>%s</b> = <b>%s</b><br>", $var1['key'], $var1['value']);\r
+                   } \r
+               }\r
+               echo '<br/><br/>';\r
+       } // end _seeAlSessionVars\r
+       \r
+} // end AtOpenCapsDebug class\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/include/classes/ATOC_Json.php b/mods/atutor_opencaps/include/classes/ATOC_Json.php
new file mode 100755 (executable)
index 0000000..14499ad
--- /dev/null
@@ -0,0 +1,46 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+class OcJsonFileProject\r
+{\r
+       // set here all the global vars\r
+       public $id;\r
+       public $title;\r
+       public $login;\r
+       public $mediaFile;\r
+       public $captionFile;\r
+       public $timeStamp;\r
+       public $returnFormat;\r
+       \r
+       /**\r
+        * @desc setVars\r
+        * @param String $varName\r
+        * @param String $varValue\r
+        */\r
+       public function setVars($varName, $varValue)\r
+       {\r
+               $this->$varName = $varValue;\r
+       }\r
+       \r
+       /**\r
+        * @desc addProjectData\r
+        * @param String $theProjectData\r
+        */\r
+       public function addProjectData($theProjectData)\r
+       {\r
+               \r
+               $this->results[]=$theProjectData;\r
+       }\r
+\r
+} // end class\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/include/classes/ATOC_ProjectManager.php b/mods/atutor_opencaps/include/classes/ATOC_ProjectManager.php
new file mode 100755 (executable)
index 0000000..599253e
--- /dev/null
@@ -0,0 +1,326 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+class ATOCProjectManager\r
+{\r
+       /*\r
+       private $id;\r
+       private $login;\r
+       private $courseId;\r
+       private $name;\r
+       private $mediaFile;\r
+       private $captionFile;\r
+       private $date;\r
+       */\r
+       \r
+       /**\r
+        * @desc Load Projects\r
+        * @param String $theLogin\r
+        * @param int $theCourseId\r
+        * @param int $theId\r
+        * @return Array $myProjects\r
+        */\r
+       public function _loadProjects($theLogin, $theCourseId, $theId)\r
+       {\r
+               //echo '<h3>START method: _loadProjects()</h3>';\r
+\r
+               global $db;\r
+               \r
+               $myProjects = array();\r
+               $myGetMediaObj = new OcJsonFileProject();\r
+               \r
+               $sql = "SELECT * FROM ".TABLE_PREFIX."atopencaps_mod WHERE login = '".$theLogin."' AND courseId = ".$theCourseId;\r
+               $sqlWhere = '';\r
+\r
+               if($theId!=0)\r
+               {\r
+                       $sqlWhere .= ' AND id = '.$theId;\r
+               } \r
+               \r
+               $sqlOrder = ' ORDER BY id DESC';\r
+               $sql .= $sqlWhere.$sqlOrder;\r
+                       //echo "<p>".$sql.'</p>';\r
+\r
+               $result = mysql_query($sql, $db);\r
+               $num_affected = mysql_affected_rows($db);\r
+               \r
+               if ($ocAtSettings['debugMode'] && $num_affected==0)\r
+               {\r
+                       $ocAtSettings['messages'] = '<p>_loadProjects(): no data to load </p>';\r
+               }\r
+               \r
+               // get all project data into an array. \r
+               $myCounter = 0;\r
+               while ($row = @mysql_fetch_assoc($result)) \r
+               {\r
+                       //$existing_accounts[$row['public_field']];\r
+                       $myProjects[$myCounter]['id'] = $row['id'];\r
+                       $myProjects[$myCounter]['login'] = $row['login'];\r
+                       $myProjects[$myCounter]['courseId'] = $row['courseId'];\r
+                       $myProjects[$myCounter]['name'] = $row['name'];\r
+                       $myProjects[$myCounter]['mediaFile'] = $row['mediaFile'];\r
+                       $myProjects[$myCounter]['captionFile'] = $row['captionFile'];\r
+                       $myProjects[$myCounter]['timeStamp'] = $row['timeStamp'];\r
+                       $myProjects[$myCounter]['width'] = $row['width'];\r
+                       $myProjects[$myCounter]['height'] = $row['height'];\r
+                       \r
+                       $myCounter++;\r
+                       //echo "<BR/>ID: ".$row['id'];\r
+               } // end while\r
+\r
+               return $myProjects;\r
+\r
+       } // _loadProjects()\r
+\r
+\r
+       /**\r
+        * @desc _createCcFile\r
+        * @param String $theMediaFile\r
+        * @return String $theCaptionFile\r
+        */\r
+       public function _createCcFile($theMediaFile)\r
+       {\r
+               global $ocAtSettings; //\r
+\r
+               $theNewFileName = '';\r
+               $bol=false;\r
+               $theCaptionFile = '';\r
+               $theCaptionFilePath = '';\r
+               $theCaptionFilePathFull = '';\r
+               $i = 0;\r
+               \r
+               while (!$bol)\r
+               {\r
+                       $ccNameTemp = explode('.',$theMediaFile);\r
+                       //print_r($ccNameTemp);\r
+                       if ($i==0)\r
+                       {\r
+                               $theCaptionFile = $ccNameTemp[0].'.'.$ocAtSettings['defaultCcExt'];\r
+                       } else {\r
+                               $theCaptionFile = $ccNameTemp[0].'_'.$i.'.'.$ocAtSettings['defaultCcExt'];\r
+                       }\r
+\r
+                       // fix path\r
+                       $theCaptionFilePath = str_replace('/',$ocAtSettings['dirSep'],$theCaptionFile);\r
+       \r
+                       $theCaptionFilePathFull = AT_CONTENT_DIR.$_SESSION['course_id'].$ocAtSettings['dirSep'].$theCaptionFilePath;\r
+                       \r
+                       if (!file_exists($theCaptionFilePathFull))\r
+                       {\r
+                               $bol=true;\r
+                       }\r
+                       $i++;\r
+                       \r
+               } // end while\r
+       \r
+               file_put_contents($theCaptionFilePathFull, '');\r
+               return $theCaptionFile;\r
+\r
+       } // end createNewCcFile\r
+       \r
+\r
+       /**\r
+        * @desc Set Active Project\r
+        * @param int $theId\r
+        * @param string $theLogin\r
+        * @param int $theCourseId\r
+        * @param string $theSessionId\r
+        */\r
+       public function _setActiveProject($theId, $theLogin, $theCourseId, $theSessionId)\r
+       {\r
+               global $db, $ocAtSettings; // load AT db object\r
+               \r
+               // split id \r
+               $temId = explode('-',$theId);\r
+               \r
+               if($theId!=0 && $theLogin!='' && $theCourseId!=0 && $theSessionId!='')\r
+               {\r
+                       $sql = "UPDATE ".TABLE_PREFIX."atopencaps_mod SET sessionId='$theSessionId'";\r
+                       $sql .= " WHERE id = $theId AND login='$theLogin' AND courseId=$theCourseId";\r
+                       $result = mysql_query($sql, $db);\r
+                       $num_affected = mysql_affected_rows($db);\r
+                               //echo '<br/>'.$sql;\r
+                       $result = null;\r
+               }\r
+               \r
+       } // end _setActiveProject\r
+       \r
+       \r
+       /**\r
+        * @desc Add/Edit/Delete captioning Project.\r
+        * @param int $theId\r
+        * @param string $theLogin\r
+        * @param int $theCourseId\r
+        * @param string $theName\r
+        * @param string $theMediaFile\r
+        * @param string $theCaptionFile\r
+        * @param int $theWidth\r
+        * @param int $theHeight\r
+        * @param int $theAction\r
+        */\r
+       public function _addEditProject($theId, $theLogin, $theCourseId, $theName, $theMediaFile, $theCaptionFile, $theWidth, $theHeight, $theAction='')\r
+       {\r
+\r
+               global $db, $ocAtSettings; // load AT db object\r
+               \r
+               if ($theAction=="deleteProject")\r
+               {\r
+                       $sql = "DELETE FROM ".TABLE_PREFIX."atopencaps_mod";\r
+                       $sql .= " WHERE id = $theId AND login='$theLogin'";\r
+               \r
+               } else if ($theId != 0)\r
+               {\r
+                       // UPDATE\r
+                       $sql = "UPDATE ".TABLE_PREFIX."atopencaps_mod SET name='$theName', mediaFile='$theMediaFile', captionFile='$theCaptionFile', width='".$theWidth."', height='".$theHeight."'";\r
+                       $sql .= " WHERE id = $theId AND login='$theLogin'";\r
+\r
+               } else {\r
+                       \r
+                       // create caption file if does not exist\r
+                       if($theCaptionFile=='')\r
+                       {\r
+                               $theCaptionFile = $this->_createCcFile($theMediaFile);\r
+                       }\r
+\r
+                       // INSERT\r
+                       $sql = "INSERT INTO ".TABLE_PREFIX."atopencaps_mod (`login`, `courseId`, `name`, `mediaFile`, `captionFile`, `width`, `height`) VALUES";\r
+                       $sql .= "('".$theLogin."', ".$theCourseId.", '".$theName."', '".$theMediaFile."', '".$theCaptionFile."', '".$theWidth."', '".$theHeight."')";\r
+                               \r
+               }\r
+               \r
+                       //echo $sql;\r
+               // run SQL \r
+               $result = mysql_query($sql, $db);\r
+               $num_affected = mysql_affected_rows($db);\r
+               $result = null;\r
+               \r
+       } // end addProject()\r
+       \r
+       /**\r
+        * @desc _getProjecDataJson\r
+        * @param unknown_type $theId\r
+        * @param unknown_type $theBaseUrl\r
+        * @return unknown\r
+        */\r
+       public function _getProjecDataJson($theId, $theBaseUrl)\r
+       \r
+       {\r
+               global $db, $ocAtSettings;\r
+               \r
+               // split id \r
+               $temId = explode('-',$theId);\r
+       \r
+               $myProjects = array();\r
+               $myGetMediaObj = new OcJsonFileProject();\r
+               \r
+               $sql = "SELECT * FROM ".TABLE_PREFIX."atopencaps_mod WHERE id = $temId[0] AND sessionId ='$temId[1]'";\r
+       \r
+               $result = mysql_query($sql, $db);\r
+               $num_affected = mysql_affected_rows($db);\r
+               \r
+               // debug\r
+               if ($ocAtSettings['debugMode'] && $num_affected==0)\r
+               {\r
+                       echo "<p>_getProjecDataJson() function reported that: there are no Captioning Projects matching the criteria \r
+                       <br/>SQL: ".$sql.'</p>';\r
+               }\r
+               \r
+               // get all project data into an array. \r
+               $myCounter = 0;\r
+               while ($row = mysql_fetch_assoc($result)) \r
+               {\r
+                               // build object to JSON\r
+                               $myGetMediaObj->setVars('id',$theId);\r
+                               $myGetMediaObj->setVars('login',$row['login']);\r
+                               $myGetMediaObj->setVars('title',$row['name']);\r
+                               \r
+                               $rex1 = '/(http:|https:)/i';\r
+                               \r
+                               if (preg_match($rex1, $row['mediaFile']))\r
+                               {\r
+                                       $myGetMediaObj->setVars('mediaFile',''.$row['mediaFile']);\r
+                                       $myGetMediaObj->setVars('captionFile',$theBaseUrl.'content/'.$row['courseId'].'/'.$row['captionFile']);\r
+                                       \r
+                               } else if ($ocAtSettings['contentUrlType']== 0) {\r
+                                       $myGetMediaObj->setVars('mediaFile',$theBaseUrl.'get.php/'.''.$row['mediaFile']);\r
+                                       $myGetMediaObj->setVars('captionFile',$theBaseUrl.'get.php/'.''.$row['captionFile']);\r
+                                       \r
+                               } else if ($ocAtSettings['contentUrlType']== 1) {\r
+                                       $myGetMediaObj->setVars('mediaFile',$theBaseUrl.'content/'.$row['courseId'].'/'.$row['mediaFile']);\r
+                                       $myGetMediaObj->setVars('captionFile',$theBaseUrl.'content/'.$row['courseId'].'/'.$row['captionFile']);\r
+                                       \r
+                               }\r
+                               \r
+                               $myGetMediaObj->setVars('timeStamp',$row['timeStamp']);\r
+                               $myGetMediaObj->setVars('returnFormat',$ocAtSettings['ccReturnFormat']);\r
+                               \r
+               } // end while\r
+               \r
+               $jsonFile = json_encode($myGetMediaObj);\r
+               \r
+               return $jsonFile;\r
+\r
+\r
+       } // _getProjecDataJason()\r
+       \r
+       \r
+       /**\r
+        * @desc _saveCaptionData\r
+        * @param String $theId\r
+        * @param String $theCcData\r
+        * @param int $theWidth\r
+        * @param int $theHeight\r
+        */\r
+       public function _saveCaptionData($theId,$theCcData,$theWidth,$theHeight)\r
+       {\r
+               global $db, $ocAtSettings;\r
+               \r
+               $temId = explode('-',$theId);\r
+               \r
+               $sql = "SELECT * FROM ".TABLE_PREFIX."atopencaps_mod WHERE id = $temId[0] AND sessionId ='$temId[1]'";\r
+               \r
+               $result = mysql_query($sql, $db);\r
+               $num_affected = mysql_affected_rows($db);\r
+               \r
+               $row = mysql_fetch_assoc($result);\r
+\r
+               if ($row['captionFile']!='')\r
+               {\r
+                       // fix path\r
+                       $theCaptionFilePath = str_replace('/',$ocAtSettings['dirSep'],$row['captionFile']);\r
+                       \r
+                       $theCaptionFilePathFull = AT_CONTENT_DIR.$row['courseId'].$ocAtSettings['dirSep'].$theCaptionFilePath;\r
+                       \r
+                       file_put_contents($theCaptionFilePathFull, $theCcData);\r
+\r
+                       // update metadata\r
+                       if ($theWidth!='' && $theHeight!='')\r
+                       {\r
+                               $sqlUpdateMetadata = "UPDATE ".TABLE_PREFIX."atopencaps_mod SET width='".$theWidth."', height='".$theHeight."'";\r
+                               $sqlUpdateMetadata .=  " WHERE id = $temId[0] AND sessionId ='$temId[1]'";\r
+                               //$sqlUpdateMetadata .=  " AND login='$theLogin'";\r
+                               //echo '<br/>'.$sqlUpdateMetadata;\r
+                               $result1 = mysql_query($sqlUpdateMetadata, $db);\r
+                               $result1 = null;\r
+                       }\r
+                       $result = null;\r
+               \r
+                       //return  '<h3>Data Saved in : '.$row['captionFile'].'</h3>';\r
+                       return '<p>Data Saved in : '.$theCaptionFilePathFull.'</p>';\r
+               }\r
+\r
+       } // _saveCaptionData()\r
+       \r
+       \r
+} // end class\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/include/classes/ATOC_ServerFiles.php b/mods/atutor_opencaps/include/classes/ATOC_ServerFiles.php
new file mode 100755 (executable)
index 0000000..3e69b7c
--- /dev/null
@@ -0,0 +1,65 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+class ServerFiles\r
+{\r
+       \r
+       /**\r
+        * @desc directoryToArray\r
+        * @param String $directory\r
+        * @param bool $recursive\r
+        * @return Array\r
+        */\r
+       public function directoryToArray($directory, $recursive) \r
+       {\r
+               global $ocAtSettings;\r
+               \r
+               $rex = '/^.*\.('.$ocAtSettings['supportedMedia'].')$/i';\r
+               $sep = '\\';\r
+               $array_items = array();\r
+               if ($handle = opendir($directory)) {\r
+                       while (false !== ($file = readdir($handle))) {\r
+                               if ($file != "." && $file != "..") {\r
+                                       if (is_dir($directory. $sep . $file)) {\r
+                                               if($recursive) \r
+                                               {\r
+                                                       $array_items = array_merge($array_items,$this->directoryToArray($directory. $sep . $file, $recursive));\r
+                                               }\r
+                                               //add if add only known files\r
+                                               if (preg_match($rex, $file))\r
+                                               {\r
+                                                       //$file = $directory . $sep . $file;\r
+                                                       $array_items[] = preg_replace("/\/\//si", $sep, $file);\r
+                                                       //echo '<br/>'.$file;   \r
+                                               }\r
+                                               \r
+                                       } else {\r
+                                               if (preg_match($rex, $file))\r
+                                               {\r
+                                                       $file = $directory . $sep . $file;\r
+                                                       //$file = $sep . $file;\r
+                                                       $file = str_replace(AT_CONTENT_DIR.''.$_SESSION['course_id'].$sep, '', $file);\r
+                                                       $file = str_replace('\\', '/', $file);\r
+                                                       $array_items[] = preg_replace("/\/\//si", $sep, $file);\r
+                                                       //echo '<br/>'.$file;   \r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       closedir($handle);\r
+               }\r
+               return $array_items;\r
+       } // end directoryToArray\r
+       \r
+} // end class ServerFiles\r
+?>\r
diff --git a/mods/atutor_opencaps/include/config.inc.php b/mods/atutor_opencaps/include/config.inc.php
new file mode 100755 (executable)
index 0000000..640d6e0
--- /dev/null
@@ -0,0 +1,54 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+/*\r
+ * default value = ''; \r
+ * set this only if using an external instace of Open Caps\r
+  */\r
+$ocAtSettings['ocWebPath'] = '';\r
+\r
+/*\r
+ * default caption format \r
+ */\r
+$ocAtSettings['ccReturnFormat'] = 'SubRipSrt';  \r
+\r
+/*\r
+ * default file extension for caption format \r
+ */\r
+$ocAtSettings['defaultCcExt'] = 'srt'; \r
+\r
+\r
+/*\r
+ * Media File Formats to look for in AT File Manager\r
+ */\r
+$ocAtSettings['supportedMedia'] = 'mov|mp4|flv|mpg4|avi|mp3|mov|qt|mp4|m4v|mpg|mpeg|dv|mp3|wav|aac|midi|au|avi|aiff';\r
+\r
+/*\r
+ * default = 0; uses AT/get.php to access files\r
+ * = 1, uses AT/content/[courseId]/[fileName]\r
+ */\r
+$ocAtSettings['contentUrlType'] = 1;\r
+\r
+/*\r
+ *  default value = false; \r
+ * changing this will break connectivity with Open Caps. \r
+ * So do NOT set this = true unless you know what you are doing\r
+ */\r
+$ocAtSettings['debugMode'] = false;\r
+\r
+/*\r
+ *  default value = false; \r
+ * if set to true, the module will show all AT session and cookie variables \r
+ */\r
+$ocAtSettings['showAtVars'] = false; \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/include/index.html b/mods/atutor_opencaps/include/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/include/vitals.inc.php b/mods/atutor_opencaps/include/vitals.inc.php
new file mode 100755 (executable)
index 0000000..7a9de3a
--- /dev/null
@@ -0,0 +1,134 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                                                                                              */\r
+/****************************************************************/\r
+/* Copyright (c) 2010                                           */\r
+/* Written by Antonio Gamba                                                                    */\r
+/* Adaptive Technology Resource Centre / University of Toronto  */\r
+/*                                                              */\r
+/* This program is free software. You can redistribute it and/or*/\r
+/* modify it under the terms of the GNU General Public License  */\r
+/* as published by the Free Software Foundation.                               */\r
+/****************************************************************/\r
+\r
+// load AtOpenCaps config File\r
+include_once('include/config.inc.php');\r
+\r
+// load AtOpenCaps Classes\r
+       //include_once('classes/ATOCSecurityManager_class.php');\r
+include_once('include/classes/ATOC_Debug.php');\r
+include_once('include/classes/ATOC_ProjectManager.php');\r
+include_once('include/classes/ATOC_ServerFiles.php');\r
+include_once('include/classes/ATOC_Json.php');\r
+\r
+// errors \r
+$ocAtSettings['messages'] = array();\r
+$ocAtSettings['lang'] = array();\r
+\r
+/*\r
+$ocAtSettings['lang']['atoc_notActiveCourseError'] = '"Note: In order to use this module you MUST login as an instructor. <br/> This Module only works when you are working on a particular course."';\r
+$ocAtSettings['lang']['atoc_projectDeleted'] = 'Project Deleted';\r
+$ocAtSettings['lang']['atoc_projectUpdated'] = 'Project Updated';\r
+$ocAtSettings['lang']['atoc_projectCreated'] = ' New Project Created';\r
+$ocAtSettings['lang']['atoc_debugModeActive'] = '******** Debug Mode is Active ******** ';\r
+$ocAtSettings['lang']['atoc_backToContentLinkAlt'] = 'Back To: Content';\r
+$ocAtSettings['lang']['atoc_myCaptionProjectsLink'] = 'My Caption Projects';\r
+$ocAtSettings['lang']['atoc_uploadMediaLink'] = 'Upload Media';\r
+$ocAtSettings['lang']['atoc_addProjectLink'] = 'Add Captioning Project';\r
+$ocAtSettings['lang']['atoc_captionEditorLink'] = 'Caption Editor';\r
+$ocAtSettings['lang']['atoc_previewLink'] = 'Preview';\r
+$ocAtSettings['lang']['atoc_helpLink'] = 'Help';\r
+$ocAtSettings['lang']['atoc_noIframeSupportedError'] = 'This option will not work correctly.<br/>Unfortunately, your browser does not support inline frames.';\r
+$ocAtSettings['lang']['atoc_noMediaFileFound'] = 'There are NO media files in the course content Directory';\r
+$ocAtSettings['lang']['atoc_uploadMediaMsg'] = 'Upload Media in order to start a captioning Project.';\r
+$ocAtSettings['lang']['atoc_projectName'] = 'Project Name';\r
+$ocAtSettings['lang']['atoc_mediaName'] = 'Media File';\r
+$ocAtSettings['lang']['atoc_mediaWidth'] = 'Width';\r
+$ocAtSettings['lang']['atoc_mediaHeight'] = 'Height';\r
+$ocAtSettings['lang']['atoc_newCaptionFileMsg'] = 'Create a new Caption File';\r
+$ocAtSettings['lang']['atoc_existCaptionFileMsg'] = 'Select An existing Caption';\r
+$ocAtSettings['lang']['atoc_addProjectButtonLabel'] = 'Add Captioning Project';\r
+$ocAtSettings['lang']['atoc_projectsNotFoundError'] = 'No Projects found';\r
+$ocAtSettings['lang']['atoc_saveProjectButtonLabel'] = 'Save';\r
+$ocAtSettings['lang']['atoc_deleteProjectButtonLabel'] = 'Delete';\r
+$ocAtSettings['lang']['atoc_editProjectLink'] = 'Edit';\r
+$ocAtSettings['lang']['atoc_previewProjectLink'] = 'Preview';\r
+$ocAtSettings['lang']['atoc_htmlCode'] = 'HTML Code';\r
+*/\r
+\r
+\r
+// Spanish\r
+/*\r
+$ocAtSettings['lang']['atoc_notActiveCourseError'] = '"Nota: Para poder usar este m&oacute;dulo Ud. debe ser in instructor/Profesor.<br/> Este m&oacute;dulo solo est&aacute; activo cuando el se est&aacute; tramajando en un curso"';\r
+$ocAtSettings['lang']['atoc_projectDeleted'] = 'Se ha borrado el Proyecto Seleccionado';\r
+$ocAtSettings['lang']['atoc_projectUpdated'] = 'El projecto ha sido Actualizado';\r
+$ocAtSettings['lang']['atoc_projectCreated'] = ' Se ha Creado un nuevo Proyecto';\r
+$ocAtSettings['lang']['atoc_debugModeActive'] = '******** El modo Debug/depuraci&oacute;n está activo  ******** ';\r
+$ocAtSettings['lang']['atoc_backToContentLinkAlt'] = 'Ir a Contenido';\r
+$ocAtSettings['lang']['atoc_myCaptionProjectsLink'] = 'Mis Proyectos';\r
+$ocAtSettings['lang']['atoc_uploadMediaLink'] = 'Adicionar Archivos';\r
+$ocAtSettings['lang']['atoc_addProjectLink'] = 'Crear Nuevo Proyecto';\r
+$ocAtSettings['lang']['atoc_captionEditorLink'] = 'Editar Subt&iacute;tulos';\r
+$ocAtSettings['lang']['atoc_previewLink'] = 'Vista Previa';\r
+$ocAtSettings['lang']['atoc_helpLink'] = 'Ayuda';\r
+$ocAtSettings['lang']['atoc_noIframeSupportedError'] = 'Su Navegador no soporta iframes.<br/>Se recomienda actualizar el navegador de Internet';\r
+$ocAtSettings['lang']['atoc_noMediaFileFound'] = 'NO se han encontrado archivos de video/audio en el directorio del curso';\r
+$ocAtSettings['lang']['atoc_uploadMediaMsg'] = 'Suba archivos para iniciar un proyecto de Subt&iacute;tulos.';\r
+$ocAtSettings['lang']['atoc_projectName'] = 'Nombre del Proyecto';\r
+$ocAtSettings['lang']['atoc_mediaName'] = 'Archivo (video/audio)';\r
+$ocAtSettings['lang']['atoc_mediaWidth'] = 'Ancho';\r
+$ocAtSettings['lang']['atoc_mediaHeight'] = 'Alto';\r
+$ocAtSettings['lang']['atoc_newCaptionFileMsg'] = 'Crear un nuevo archivo de Subt&iacute;tulos';\r
+$ocAtSettings['lang']['atoc_existCaptionFileMsg'] = 'Usar un archivo de Subt&iacute;tulos existente';\r
+$ocAtSettings['lang']['atoc_addProjectButtonLabel'] = 'Crear un nuevo Proyecto de Subt&iacute;tulos';\r
+$ocAtSettings['lang']['atoc_projectsNotFoundError'] = 'No se han encontrado Proyectos';\r
+$ocAtSettings['lang']['atoc_saveProjectButtonLabel'] = 'Guardar';\r
+$ocAtSettings['lang']['atoc_deleteProjectButtonLabel'] = 'Borrar';\r
+$ocAtSettings['lang']['atoc_editProjectLink'] = 'Editar';\r
+$ocAtSettings['lang']['atoc_previewProjectLink'] = 'Vista Previa';\r
+$ocAtSettings['lang']['atoc_htmlCode'] = 'C&oacute;digo HTML';\r
+*/\r
+\r
+// look for Win OS file structure \r
+if (preg_match('/WIN/', PHP_OS))\r
+{\r
+       $ocAtSettings['serverOs']  = 'win'; \r
+}\r
+\r
+if ($ocAtSettings['serverOs']=='win')\r
+{\r
+       $ocAtSettings['dirSep'] = "\\"; \r
+       \r
+} else {\r
+       $ocAtSettings['dirSep'] = "/"; \r
+}\r
+\r
+// if project id active is isset\r
+if (isset($_GET['id']) && $_GET['id']!='')\r
+{\r
+       $_SESSION['ATOC_activeProjectId']= $_GET['id'];\r
+}\r
+\r
+// set session active id\r
+if (!isset($_SESSION['ATOC_activeProjectId']))\r
+{\r
+       $_SESSION['ATOC_activeProjectId'] = '';\r
+}\r
+\r
+// get actions variables\r
+if(isset($_POST['action']))\r
+{\r
+       $ocAtAction = $_POST['action']; \r
+} else {\r
+\r
+       // get actions variables\r
+       if(isset($_GET['action']))\r
+       {\r
+               $ocAtAction = $_GET['action']; \r
+       } else {\r
+       \r
+               $ocAtAction = '';\r
+       }\r
+}\r
+$ocAtSettings['atWebPath'] = '';\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/index.php b/mods/atutor_opencaps/index.php
new file mode 100755 (executable)
index 0000000..8612c44
--- /dev/null
@@ -0,0 +1,418 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+// load AT vitals\r
+define('AT_INCLUDE_PATH', '../../include/');\r
+require (AT_INCLUDE_PATH.'vitals.inc.php');\r
+authenticate(AT_PRIV_OPEN_CAPS);\r
+require (AT_INCLUDE_PATH.'header.inc.php');\r
+\r
+// load ATutor-OpenCaps Module Vitals \r
+include_once('include/vitals.inc.php');\r
+\r
+if ($ocAtSettings['contentUrlType']==0)\r
+{\r
+       $contentURL = AT_BASE_HREF.'get.php/'.''.'';\r
+       \r
+} else if ($ocAtSettings['contentUrlType']==1){\r
+       $contentURL = AT_BASE_HREF.'content/'.$_SESSION['course_id'].'/'.'';\r
+} \r
+               \r
+if($_SESSION['course_id']==-1)\r
+{\r
+       $ocAtSettings['messages'][]= $ocAtSettings['lang']['atoc_notActiveCourseError'];\r
+}\r
+// update project meta data \r
+if ($ocAtAction=='updateProject' || $ocAtAction=='deleteProject')\r
+{\r
+       $myProjectManager = new ATOCProjectManager();\r
+       $activeProjectData = $myProjectManager->_addEditProject($_POST['id'],$_SESSION['login'],$_SESSION['course_id'],$_POST['name'],$_POST['mediaFile'],$_POST['captionFile'],$_POST['width'],$_POST['height'],$ocAtAction);\r
+\r
+       if ($ocAtAction=='deleteProject')\r
+       {\r
+               $ocAtSettings['messages'][]= $ocAtSettings['lang']['atoc_projectDeleted'];\r
+       } else {\r
+               $ocAtSettings['messages'][]= $ocAtSettings['lang']['atoc_projectUpdated'];\r
+       }\r
+       \r
+       $ocAtAction='';\r
+}\r
+\r
+// addProject: if step 1 \r
+if ($ocAtAction=='addProject' && $_POST['step']=='1')\r
+{\r
+       if($_POST['ccOption']==0)\r
+       {\r
+               $captionFile = "";\r
+               \r
+       } else {\r
+               $captionFile = $_POST['captionFile'];\r
+       }\r
+\r
+       // run Project Manager Class\r
+       $myProjectManager = new ATOCProjectManager();\r
+       $myProjectManager->_addEditProject(0, $_SESSION['login'], $_SESSION['course_id'], $_POST['projectName'], $_POST['mediaFile'], $captionFile,$_POST['width'],$_POST['height']);\r
+       $ocAtAction='';\r
+       $ocAtSettings['messages'][] = $ocAtSettings['lang']['atoc_projectCreated'].': <br/><i>'.$_POST['projectName'].'</i>';\r
+       \r
+} // end step 1\r
+\r
+if($ocAtSettings['ocWebPath'] == '')\r
+{\r
+       $ocWebPath_replace = str_replace('index.php','opencaps/',$_SERVER['SCRIPT_NAME']);\r
+       $ocAtSettings['ocWebPath'] = 'http://'.$_SERVER['HTTP_HOST'].''.$ocWebPath_replace;\r
+}\r
+\r
+if ($ocAtSettings['debugMode'])\r
+{\r
+       echo '<h1>'.$ocAtSettings['lang']['atoc_debugModeActive'].'</h1>';\r
+}\r
+?>\r
+<script src="mods/AtOpenCaps/include/basic.js"></script>\r
+<script src="mods/AtOpenCaps/include/atoc.js"></script>\r
+<script src="mods/AtOpenCaps/flowplayer/flowplayer-3.2.2.min.js"></script>\r
+<link rel="stylesheet" type="text/css" href="mods/AtOpenCaps/module.css">\r
+\r
+<div id="AtOpenCaps">\r
+       <?php\r
+       if (count($ocAtSettings['messages'])>0)\r
+       {\r
+               echo '<div id="info">';\r
+               \r
+               for($i=0;$i<count($ocAtSettings['messages']);$i++)\r
+               {\r
+                       echo '<p>'.$ocAtSettings['messages'][$i].'</p>';\r
+               }\r
+               echo '</div>';\r
+       }\r
+\r
+       // show AT vars\r
+       if($ocAtSettings['showAtVars'])\r
+       {\r
+               AtOpenCapsDebug::_seeAlSessionVars();\r
+       } \r
+        ?>\r
+       \r
+       <div id="ATOC_links">\r
+               <div id="subnavlistcontainer">\r
+                       <div id="subnavbacktopage">\r
+                               <a href="<?php echo AT_BASE_HREF; ?>mods/_core/content/index.php">\r
+                               <img height="11" border="0" width="10" style="float: left;" src="<?php echo AT_BASE_HREF; ?>images/arrowicon.gif" alt="<?php echo _AT('atoc_backToContentLinkAlt'); ?>"></a>&nbsp;\r
+                       </div>\r
+               </div> \r
+\r
+       <ul id="subnavlist">\r
+        <li <?php if($ocAtAction=='') {?> class="active" <?php }?>><a href="mods/AtOpenCaps/index.php"><?php echo _AT('atoc_myCaptionProjectsLink'); ?>        </a></li>\r
+        <li <?php if($ocAtAction=='fileManager') {?> class="active" <?php }?>><a href="mods/AtOpenCaps/index.php?action=fileManager"><?php echo _AT('atoc_uploadMediaLink'); ?></a></li>\r
+        <li <?php if($ocAtAction=='addProject') {?> class="active" <?php }?>><a href="mods/AtOpenCaps/index.php?action=addProject&step=0"><?php echo _AT('atoc_addProjectLink'); ?></a></li>\r
+        <li <?php if($ocAtAction=='ccEditor') {?> class="active" <?php }?>><a href="mods/AtOpenCaps/index.php?action=ccEditor<?php \r
+                       if ($_SESSION['ATOC_activeProjectId']!='')\r
+                       {\r
+                               echo '&id='.$_SESSION['ATOC_activeProjectId'];\r
+                       } \r
+                       \r
+                       ?>"><?php echo _AT('atoc_captionEditorLink'); ?></a></li>\r
+        <li <?php if($ocAtAction=='preview') {?> class="active" <?php }?>><a href="mods/AtOpenCaps/index.php?action=preview<?php \r
+                       if ($_SESSION['ATOC_activeProjectId']!='')\r
+                       {\r
+                               echo '&id='.$_SESSION['ATOC_activeProjectId'];\r
+                       } \r
+                       \r
+                       ?>"><?php echo _AT('atoc_previewLink'); ?></a></li>\r
+       <li <?php if($ocAtAction=='atOcAbout') {?> class="active" <?php }?>><a href="mods/AtOpenCaps/index.php?action=atOcAbout"><?php echo _AT('atoc_helpLink'); ?></a></li>\r
+       </ul> \r
+       </div>\r
+\r
+       <?php\r
+       if ($ocAtAction=='ccEditor')\r
+       {\r
+               // run Project Manager Class\r
+               if($_SESSION['ATOC_activeProjectId']!='')\r
+               {\r
+                       $activeProjectId = $_GET['id'];\r
+                       \r
+                       // set the active id in session\r
+                       $_SESSION['ATOC_activeProjectId'] = $activeProjectId; \r
+                       \r
+               } else {\r
+                       // get the last project\r
+                       $myProjectManager = new ATOCProjectManager();\r
+                       $myOcProjects = $myProjectManager->_loadProjects($_SESSION['login'],$_SESSION['course_id'],0);\r
+                       $activeProjectId = $myOcProjects[0]['id']; \r
+                       \r
+                       // get the last project\r
+                       $myProjectManager = null;\r
+               }\r
+               \r
+\r
+               // set active session ID\r
+               $myProjectManager = new ATOCProjectManager();\r
+               $myProjectManager->_setActiveProject($activeProjectId,$_SESSION['login'],$_SESSION['course_id'],$_SESSION['token']);\r
+               $activeProjectId .= '-'.$_SESSION['token'];\r
+\r
+               if($ocAtSettings['debugMode'])\r
+               {\r
+                       // testing service before sending data \r
+                       $theServiceUrl = AT_BASE_HREF.'mods/AtOpenCaps/service.php?id='.$activeProjectId.'&action=getMedia'; \r
+                       $theJson = file_get_contents($theServiceUrl);\r
+                       $media_info = json_decode($theJson);\r
+                       $JsonDebug = '';\r
+                       $JsonDebug .= '\r
+                       <h3>Open Caps service: getMedia</h3>\r
+                       <form name="debugJson" id="debugJson" method="post" action="">\r
+                         <textarea name="jsonArray" cols="80" rows="10" id="jsonArray">\r
+URL: '.$theServiceUrl;\r
+                       foreach ($media_info as $name=>$value)\r
+                       {\r
+                               $JsonDebug .= '\r
+\r
+'.$name.': '.$value;\r
+                       } \r
+                       $JsonDebug .='\r
+</textarea>\r
+                       </form>\r
+                       ';\r
+                       echo $JsonDebug;\r
+               } // end debug\r
+               \r
+               \r
+               $ccEditorHtml = '<div id="ATOC_editor" class="input-form">\r
+<iframe style="overflow-y: scroll;" scrolling="no" height="780px" frameborder="0" width="100%" align="top" class="wrapper" \r
+src="'.$ocAtSettings['ocWebPath'].'/index.php?id='.$activeProjectId.'&athome='.AT_BASE_HREF.'" name="AtOpenCaps" id="AtOpenCaps">\r
+'._AT('atoc_noIframeSupportedError').'\r
+</iframe>\r
+               </div>';\r
+               \r
+               echo $ccEditorHtml;\r
+                               \r
+               \r
+       } // end if ccEditor\r
+\r
+       else if ($ocAtAction=='fileManager')\r
+       {\r
+               echo '<div id="ATOC_fileManager" class="input-form">';\r
+               echo '\r
+<iframe style="overflow-y: scroll;" scrolling="no" height="600px" frameborder="0" width="100%" align="top" \r
+src="'.AT_BASE_HREF.'mods/_core/file_manager/index.php?framed=1&popup=0" name="ATFileManager" id="ATFileManager">\r
+'._AT('atoc_noIframeSupportedError').'\r
+</iframe>\r
+</div>\r
+';\r
+       }\r
+\r
+       else if ($ocAtAction=='preview')\r
+       {\r
+               $myProjectManager = new ATOCProjectManager();\r
+               $myPreviewProject = $myProjectManager->_loadProjects($_SESSION['login'],$_SESSION['course_id'],$_GET['id']);\r
+               \r
+               // set width and  height\r
+               if ($myPreviewProject[0]['width']=='')\r
+               {\r
+                       $playerWidth=320;\r
+                       \r
+               } else {\r
+                       $playerWidth = $myPreviewProject[0]['width'];\r
+               }\r
+               \r
+                       // set width and  height\r
+               if ($myPreviewProject[0]['height']=='')\r
+               {\r
+                       $playerHeight=240;\r
+                       \r
+               } else {\r
+                       $playerHeight = $myPreviewProject[0]['height'];\r
+               }\r
+\r
+               $playerHtml = '\r
+<div id="ATOC_preview" class="input-form">';\r
+               $playerHtml .='\r
+<iframe scrolling="yes" width="100%" height="'.($playerHeight+50).'px" frameborder="0" align="top" \r
+src="'.AT_BASE_HREF.'mods/AtOpenCaps/player.php?mediaFile='.$contentURL.$myPreviewProject[0]['mediaFile'].'&captionFile='.$contentURL.$myPreviewProject[0]['captionFile'].'\r
+&width='.$playerWidth.'&height='.$playerHeight.'" name="ATPlayer" id="ATPlayer">\r
+       This option will not work correctly. \r
+       Unfortunately, your browser does not support inline frames.\r
+</iframe>\r
+</div>\r
+';\r
+               echo $playerHtml;               \r
+               \r
+       }\r
+\r
+       else if ($ocAtAction=='addProject')\r
+       {\r
+       ?>\r
+       <div id="ATOC_addCcProject" class="input-form">\r
+       <form name="addProject" id="addProject" method="post" action="<?php echo $_SERVER['PHP_SELF']?>">\r
+       <?php   \r
+               // step 0\r
+               if (isset($_GET['step']) && $_GET['step']=='0')\r
+               {\r
+                       // start server files class \r
+                       $theServerDir = AT_CONTENT_DIR.''.$_SESSION['course_id'];\r
+                       $myServerFiles = new ServerFiles($theServerDir);\r
+                       $myFileArray = $myServerFiles->directoryToArray($theServerDir, true);\r
+               \r
+                       // if not media files found\r
+                       if (count($myFileArray)==0)\r
+                       {\r
+                               echo '<p>'._AT('atoc_noMediaFileFound').'</p>';\r
+                               echo '<p><a href="mods/AtOpenCaps/index.php?action=fileManager">'._AT('atoc_uploadMediaMsg').'</a></p>';\r
+                       } else {\r
+                               //echo "<p>Select one of the available media files:</p>";\r
+                       ?>\r
+                         <p><strong><?php echo _AT('atoc_projectName');?>:</strong> \r
+                           <input name="projectName" id="projectName" value="" type="text" size="35"/>\r
+                         </p>\r
+                         <p><strong><?php echo _AT('atoc_mediaName'); ?>:</strong> \r
+                 <select name="mediaFile" id="mediaFile">\r
+                               <?php \r
+                               for ($i=0;$i<count($myFileArray);$i++)\r
+                               {\r
+                                       echo '<option value="'.$myFileArray[$i].'">'.$myFileArray[$i].'</option>';\r
+                               } // end for\r
+                               ?>\r
+                 </select>\r
+                 </p>\r
+                 <p>\r
+                 <strong><?php echo _AT('atoc_mediaWidth'); ?>:</strong> <input name="width" id="width" value="" type="text" size="4"/>\r
+                  <strong><?php echo _AT('atoc_mediaHeight'); ?>:</strong> <input name="height" id="height" value="" type="text" size="4"/>\r
+                 </p>\r
+                         <p><strong> \r
+                           <input name="ccOption" type="radio" value="0" checked>\r
+                           <?php echo _AT('atoc_newCaptionFileMsg'); ?><br>\r
+                           <input type="radio" name="ccOption" value="1">\r
+                           <?php echo _AT('atoc_existCaptionFileMsg'); ?>:  \r
+                           <input name="captionFile" id="captionFile" type="text"/>\r
+                           </strong></p>\r
+                         <p> \r
+                           <input name="step" id="step" value="1" type="hidden"/>\r
+                           <input name="action" id="action" value="addProject" type="hidden"/>\r
+                           <input name="addProject" type="submit" class="button" id="addProject" value="<?php echo _AT('atoc_addProjectButtonLabel');?>" />\r
+                         </p>\r
+                       <?php                           \r
+                       } // end if not files\r
+               } // end step 0\r
+               ?>\r
+       \r
+</form>\r
+</div>\r
+<?php\r
+\r
+       } // end addProject\r
+\r
+       // listing my current projects\r
+       else if ($ocAtAction=='' || (($ocAtAction=='editProject')&& $_GET['id']!=''))\r
+       {\r
+               //echo "<h4>My Projects</h4>";\r
+               echo '<div id="ATOC_projects" class="input-form">';\r
+               // run Project Manager Class\r
+               $myProjectManager = new ATOCProjectManager();\r
+               $myOcProjects = $myProjectManager->_loadProjects($_SESSION['login'],$_SESSION['course_id'],0);\r
+               //print_r($myOcProjects);\r
+               \r
+               if (count($myOcProjects)==0)\r
+               {\r
+                       echo '<p>'._AT('atoc_projectsNotFoundError').'.<p/>';\r
+                       echo '<p><a href="mods/AtOpenCaps/index.php?action=addProject&step=0">'._AT('atoc_addProjectLink').'</a><p/>';\r
+               } else {\r
+               //echo '<br/>Total Projects: '.count($myOcProjects);\r
+                       \r
+               $myProjectsHtml = '';\r
+               $myProjectsHtml .= '\r
+               <form name="atocForm" id="atocForm" method="post" action="'.$_SERVER['PHP_SELF'].'">\r
+                 <table width="100%" border="0" cellspacing="2" cellpadding="5">\r
+                   <tr class="ATOC_labels"> \r
+                     <td width="40%">'._AT('atoc_projectName').'</td>\r
+                     <td width="25%">'._AT('atoc_mediaName').'</td>\r
+                     <td width="25%">'._AT('atoc_captionName').'</td>\r
+                     <td width="5%">&nbsp;</td>\r
+                     <td width="5%">&nbsp;</td>\r
+                   </tr>\r
+               ';\r
+                       // load project in a table\r
+                       $flip = 1;\r
+                       for ($i=0; $i<count($myOcProjects);$i++)\r
+                       {\r
+                               if ($flip==1)\r
+                               {\r
+                                       $bgColor = 'bgcolor="#EAEBD8"';\r
+                               } else {\r
+                                       $bgColor = '';\r
+                               }\r
+                               $flip *= -1;\r
+                               \r
+                             if($ocAtAction=='editProject' && $myOcProjects[$i]['id']==$_GET['id'])\r
+                             {\r
+                               $myProjectsHtml .= '\r
+                           <tr '.$bgColor.'>\r
+                               <td><a name="oc_'.$myOcProjects[$i]['id'].'"></a><input name="id" id="id" value="'.$myOcProjects[$i]['id'].'" type="hidden"/>\r
+                               <input name="name" id="name" value="'.$myOcProjects[$i]['name'].'" type="text" size="35"/></td>\r
+                               <td><input name="mediaFile" id="mediaFile" value="'.$myOcProjects[$i]['mediaFile'].'" type="text" size="35"/>\r
+                               <br/>'._AT('atoc_mediaWidth').': <input name="width" id="width" value="'.$myOcProjects[$i]['width'].'" type="text" size="4"/>\r
+                               <br/>'._AT('atoc_mediaHeight').': <input name="height" id="height" value="'.$myOcProjects[$i]['height'].'" type="text" size="4"/>\r
+                               </td>\r
+                               <td><input name="captionFile" id="captionFile" value="'.$myOcProjects[$i]['captionFile'].'" type="text" size="35"/></td>\r
+                               <td><input name="editProject" type="submit" class="button" id="editProject" value="'._AT('atoc_saveProjectButtonLabel').'" />\r
+                               <input name="action" id="action" value="updateProject" type="hidden"/>\r
+                               </td>\r
+                               <td><input name="deleteProject" type="button" class="button" id="deleteProject" value="'._AT('atoc_deleteProjectButtonLabel').'" onClick="confirmDelete(\'action\')" /></td>\r
+                           </tr>\r
+                               \r
+                               ';\r
+                             \r
+                             } else {\r
+                                     $myProjectsHtml .= '\r
+                                <tr '.$bgColor.'>'.\r
+                                   '<td class="ATOC_projecLink"><a href="mods/AtOpenCaps/index.php?action=ccEditor&id='.$myOcProjects[$i]['id'].'">'.$myOcProjects[$i]['name'].'</a></td>\r
+                                   <td><a href="'.$contentURL.''.$myOcProjects[$i]['mediaFile'].'">'.$myOcProjects[$i]['mediaFile'].'</a>&nbsp;</td>\r
+                                   <td><a href="'.$contentURL.''.$myOcProjects[$i]['captionFile'].'">'.$myOcProjects[$i]['captionFile'].'</a>&nbsp;</td>\r
+                               <td><a href="'.$_SERVER['PHP_SELF'].'?action=editProject&id='.$myOcProjects[$i]['id'].'#'.'oc_'.$myOcProjects[$i]['id'].'">['._AT('atoc_editProjectLink').']</a></td>\r
+                               <td><a href="'.$_SERVER['PHP_SELF'].'?action=preview&id='.$myOcProjects[$i]['id'].'">['._AT('atoc_previewProjectLink').']</a></td>\r
+                           </tr>\r
+                                    ';\r
+                             } // end if edit project\r
+                                   \r
+                       } // end for\r
+                       \r
+                       \r
+               $myProjectsHtml .= '\r
+                 </table>\r
+                 </form>\r
+               ';\r
+               echo $myProjectsHtml;\r
+               \r
+               } //  end if not projects found\r
+               \r
+               echo '</div>';\r
+       } // end listing \r
+       \r
+       // if about/help\r
+       else if ($ocAtAction == 'atOcAbout')\r
+       {\r
+               $atOc_readme = file_get_contents('README');\r
+               $atOc_readme = str_replace(chr(13),'<br/>',$atOc_readme);               \r
+               $atOc_readme = str_replace(chr(32),'&nbsp;',$atOc_readme);\r
+               $atOc_readme = str_replace(chr(9),'&nbsp;&nbsp;&nbsp;',$atOc_readme);\r
+               $atOcAboutHtml = '<div id="ATOC_about" class="input-form">\r
+               <p>'.$atOc_readme.'</p>\r
+               \r
+               </div>\r
+               ';\r
+               echo $atOcAboutHtml;\r
+               \r
+       } // end if about/help\r
+       ?>\r
+\r
+</div>\r
+\r
+<?php require (AT_INCLUDE_PATH.'footer.inc.php'); ?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/index_admin.php b/mods/atutor_opencaps/index_admin.php
new file mode 100755 (executable)
index 0000000..df245e9
--- /dev/null
@@ -0,0 +1,23 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+define('AT_INCLUDE_PATH', '../../include/');\r
+require (AT_INCLUDE_PATH.'vitals.inc.php');\r
+admin_authenticate(AT_ADMIN_PRIV_OPEN_CAPS);\r
+require (AT_INCLUDE_PATH.'header.inc.php');\r
+?>\r
+\r
+<p>Please login as an instructor to access this module</p>\r
+\r
+<?php require (AT_INCLUDE_PATH.'footer.inc.php'); ?>\r
+\r
diff --git a/mods/atutor_opencaps/index_instructor.php b/mods/atutor_opencaps/index_instructor.php
new file mode 100755 (executable)
index 0000000..c2eab59
--- /dev/null
@@ -0,0 +1,16 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+header('Location: index.php');\r
+exit;\r
+?>\r
+\r
diff --git a/mods/atutor_opencaps/module.css b/mods/atutor_opencaps/module.css
new file mode 100755 (executable)
index 0000000..e98b45b
--- /dev/null
@@ -0,0 +1,47 @@
+div#AtOpenCaps {\r
+\r
+}\r
+\r
+div#ATOC_playerPreview {\r
+       border: 0px solid #ccc;\r
+       margin-right: auto;\r
+       margin-left: auto;\r
+       float: left;\r
+}\r
+       \r
+div#ATOC_preview_code {\r
+       border: 1px solid #ccc;\r
+       padding: 10px;\r
+       margin-right: auto;\r
+       margin-left: auto;\r
+       background-color: #efefef;\r
+       color: #444;\r
+       margin-top: 30px;\r
+       margin-bottom: 30px;\r
+       float: right;\r
+}\r
+\r
+\r
+div#Abase {\r
+       border: 1px solid #ccc;\r
+       padding: 10px;\r
+       width: 95%;\r
+       margin-right: auto;\r
+       margin-left: auto;\r
+       background-color: #efefef;\r
+       color: #444;\r
+       margin-top: 30px;\r
+       margin-bottom: 30px;\r
+       float: right;\r
+}\r
+\r
+.ATOC_projecLink {\r
+       font-size: 1.5em;\r
+}\r
+\r
+.ATOC_labels {\r
+       font-size: 1.1em;\r
+       text-align: center;\r
+       padding: 1em 1em;\r
+\r
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/module.php b/mods/atutor_opencaps/module.php
new file mode 100755 (executable)
index 0000000..5743fb3
--- /dev/null
@@ -0,0 +1,90 @@
+<?php\r
+/*******\r
+ * doesn't allow this file to be loaded with a browser.\r
+ */\r
+if (!defined('AT_INCLUDE_PATH')) { exit; }\r
+\r
+/******\r
+ * this file must only be included within a Module obj\r
+ */\r
+//if (!isset($this) || (isset($this) && (strtolower(get_class($this)) != 'module'))) { exit(__FILE__ . ' is not a Module'); }\r
+\r
+/*******\r
+ * assign the instructor and admin privileges to the constants.\r
+ */\r
+//define('AT_PRIV_ATOPENCAPS',       $this->getPrivilege());\r
+//define('AT_ADMIN_PRIV_ATOPENCAPS', $this->getAdminPrivilege());\r
+\r
+// Add menu item into "Manage" => "Content" \r
+$this->_pages['mods/_core/content/index.php']['children'] = array('mods/AtOpenCaps/index.php');\r
+\r
+\r
+/*******\r
+ * create a side menu box/stack.\r
+ */\r
+//$this->_stacks['AtOpenCaps'] = array('title_var'=>'AtOpenCaps', 'file'=>'mods/AtOpenCaps/side_menu.inc.php');\r
+// ** possible alternative: **\r
+//$this->addStack('OpenCaps', array('title_var' => 'OpenCaps', 'file' => './side_menu.inc.php');\r
+//$this->addStack('OpenCaps', array('title_var' => 'OpenCaps', 'file' => 'side_menu.inc.php');\r
+\r
+/*******\r
+ * if this module is to be made available to students on the Home or Main Navigation.\r
+ */\r
+$_group_tool = $_student_tool = 'mods/AtOpenCaps/index.php';\r
+\r
+/*******\r
+ * add the admin pages when needed.\r
+\r
+if (admin_authenticate(AT_ADMIN_PRIV_CMSMS_FEUSERS, TRUE) || admin_authenticate(AT_ADMIN_PRIV_ADMIN, TRUE)) {\r
+       $this->_pages[AT_NAV_ADMIN] = array('mods/AtOpenCaps/index_admin.php');\r
+       $this->_pages['mods/AtOpenCaps/index_admin.php']['title_var'] = 'Captioning';\r
+       $this->_pages['mods/AtOpenCaps/index_admin.php']['parent']    = AT_NAV_ADMIN;\r
+}\r
+ */\r
+\r
+/*******\r
+ * instructor Manage section:\r
+ */\r
+//$this->_pages['mods/AtOpenCaps/index_instructor.php']['title_var'] = 'AtOpenCaps';\r
+//$this->_pages['mods/AtOpenCaps/index_instructor.php']['parent']   = 'tools/index.php';\r
+// ** possible alternative: **\r
+// $this->pages['./index_instructor.php']['title_var'] = 'AtOpenCaps';\r
+// $this->pages['./index_instructor.php']['parent']    = 'tools/index.php';\r
+\r
+\r
+\r
+\r
+// adding module to content edit page\r
+//$this->_pages['mods/AtOpenCaps/index_mystart.php']['title'] = 'edit_content_opencaps';\r
+//$this->_pages['mods/AtOpenCaps/index_mystart.php']['parent'] = 'mods/_core/editor/edit_content.php';\r
+//$this->_pages['mods/AtOpenCaps/index_instructor.php']['guide'] = 'instructor/?p=content_edit.php';\r
+\r
+\r
+// ADD TO CONTENT\r
+$this->_pages['mods/_core/content/index.php']['children'] = array('mods/AtOpenCaps/index.php');\r
+\r
+\r
+/*******\r
+ * student page.\r
+ */\r
+// this not working for some reason; and breaking the shift of AT language compatibility \r
+//$this->_pages['mods/AtOpenCaps/index.php']['title_var'] = _AT('atoc_moduleName');\r
+\r
+$this->_pages['mods/AtOpenCaps/index.php']['title_var'] = 'Captioning';\r
+$this->_pages['mods/AtOpenCaps/index.php']['img']       = 'mods/AtOpenCaps/images/AtOpenCaps.png';\r
+\r
+\r
+/* public pages */\r
+       //$this->_pages[AT_NAV_PUBLIC] = array('mods/AtOpenCaps/index_public.php');\r
+       //$this->_pages['mods/AtOpenCaps/index_public.php']['title_var'] = 'AtOpenCaps';\r
+       //$this->_pages['mods/AtOpenCaps/index_public.php']['parent'] = AT_NAV_PUBLIC;\r
+\r
+/* my start page pages */\r
+//$this->_pages[AT_NAV_START]  = array('mods/AtOpenCaps/index_mystart.php');\r
+//$this->_pages['mods/AtOpenCaps/index_mystart.php']['title_var'] = 'AtOpenCaps';\r
+//$this->_pages['mods/AtOpenCaps/index_mystart.php']['parent'] = AT_NAV_START;\r
+\r
+function AtOpenCaps_get_group_url($group_id) {\r
+       return 'mods/AtOpenCaps/index.php';\r
+}\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/module.sql b/mods/atutor_opencaps/module.sql
new file mode 100755 (executable)
index 0000000..ec4ed97
--- /dev/null
@@ -0,0 +1,77 @@
+CREATE TABLE `atopencaps_mod` (\r
+  `id` int(10) unsigned NOT NULL auto_increment,\r
+  `login` varchar(100) character set utf8 NOT NULL,\r
+  `courseId` int(10) unsigned NOT NULL,\r
+  `name` varchar(255) character set utf8 NOT NULL,\r
+  `mediaFile` varchar(255) character set utf8 NOT NULL,\r
+  `captionFile` varchar(255) character set utf8 default NULL,\r
+  `timeStamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,\r
+  `width` varchar(255) default NULL,\r
+  `height` varchar(255) default NULL,\r
+  `sessionId` varchar(255) default NULL,\r
+  PRIMARY KEY  (`id`)\r
+) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;\r
+\r
+# Module Language - EN\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_moduleName','Captioning',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_notActiveCourseError','Note: In order to use this module you MUST login as an instructor. <br/> This Module only works when you are working on a particular course.',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_projectDeleted','Project Deleted',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_projectUpdated','Project Updated',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_projectCreated',' New Project Created',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_debugModeActive','******** Debug Mode is Active ******** ',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_backToContentLinkAlt','Back To: Content',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_myCaptionProjectsLink','My Caption Projects',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_uploadMediaLink','Upload Media',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_addProjectLink','Add Captioning Project',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_captionEditorLink','Caption Editor',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_previewLink','Preview',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_helpLink','Help',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_noIframeSupportedError','This option will not work correctly.<br/>Unfortunately, your browser does not support inline frames.',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_noMediaFileFound','There are NO media files in the course content Directory',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_uploadMediaMsg','Upload Media in order to start a captioning Project.',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_projectName','Project Name',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_mediaName','Media File',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_captionName','Caption File',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_mediaWidth','Width',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_mediaHeight','Height',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_newCaptionFileMsg','Create a new Caption File',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_existCaptionFileMsg','Select An existing Caption',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_addProjectButtonLabel','Add Captioning Project',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_projectsNotFoundError','No Projects found',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_saveProjectButtonLabel','Save',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_deleteProjectButtonLabel','Delete',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_editProjectLink','Edit',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_previewProjectLink','Preview',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('en', 'AtOpenCaps','atoc_htmlCode','HTML Code',NOW(),'');\r
+\r
+# Module Language - ES\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_moduleName','Subt&iacute;tulos',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_notActiveCourseError','Nota: Para poder usar este m&oacute;dulo Ud. debe ser in instructor/Profesor.<br/> Este m&oacute;dulo solo est&aacute; activo cuando el se est&aacute; tramajando en un curso',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_projectDeleted','Se ha borrado el Proyecto Seleccionado',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_projectUpdated','El projecto ha sido Actualizado',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_projectCreated',' Se ha Creado un nuevo Proyecto',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_debugModeActive','******** El modo Debug/depuraci&oacute;n está activo  ******** ',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_backToContentLinkAlt','Ir a Contenido',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_myCaptionProjectsLink','Mis Proyectos',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_uploadMediaLink','Adicionar Archivos',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_addProjectLink','Crear Nuevo Proyecto',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_captionEditorLink','Editar Subt&iacute;tulos',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_previewLink','Vista Previa',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_helpLink','Ayuda',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_noIframeSupportedError','Su Navegador no soporta iframes.<br/>Se recomienda actualizar el navegador de Internet',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_noMediaFileFound','NO se han encontrado archivos de video/audio en el directorio del curso',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_uploadMediaMsg','Upload archivos para iniciar un proyecto de Subt&iacute;tulos.',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_projectName','Nombre del Proyecto',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_mediaName','Archivo (video/audio)',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_captionName','Archivo de Subt&iacute;tulos',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_mediaWidth','Ancho',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_mediaHeight','Alto',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_newCaptionFileMsg','Crear un nuevo archivo de Subt&iacute;tulos',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_existCaptionFileMsg','Usar un archivo de Subt&iacute;tulos existente',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_addProjectButtonLabel','Crear un nuevo Proyecto de Subt&iacute;tulos',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_projectsNotFoundError','No se han encontrado Proyectos',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_saveProjectButtonLabel','Guardar',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_deleteProjectButtonLabel','Borrar',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_editProjectLink','Editar',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_previewProjectLink','Vista Previa',NOW(),'');\r
+INSERT INTO `language_text` VALUES ('es-es', 'AtOpenCaps','atoc_htmlCode','C&oacute;digo HTML',NOW(),'');\r
diff --git a/mods/atutor_opencaps/module.xml b/mods/atutor_opencaps/module.xml
new file mode 100755 (executable)
index 0000000..90d4d2f
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1"?> \r
+<module version="1.0"> \r
+    <name lang="en">AtOpenCaps</name> \r
+    <description lang="en">AtOpenCaps is a module that integrates Atutor with OpenCaps, an open source web-based captioning tool. This module uses media and caption files stored in Atutor's course content directory and manages all transactions needed to deliver caption files to Open Caps editor and retrieve updated captions. This module also includes a version of FlowPlayer for playing captioned projects. \r
+</description> \r
+    <maintainers>\r
+        <maintainer> \r
+            <name>Antonio Gamba Bari</name> \r
+            <email>antonio.gambabari@utoronto.ca</email> \r
+        </maintainer>\r
+    </maintainers> \r
+    <url>http://atutor.ca</url> \r
+    <license>GPL</license> \r
+       <release> \r
+        <version>1.0</version> \r
+        <date>2010-08-10</date> \r
+        <state>beta</state> \r
+        <notes>See details in README file.</notes> \r
+    </release> \r
+</module>\r
diff --git a/mods/atutor_opencaps/module_install.php b/mods/atutor_opencaps/module_install.php
new file mode 100755 (executable)
index 0000000..7fc2e33
--- /dev/null
@@ -0,0 +1,80 @@
+<?php\r
+/****************************************************************/\r
+/* ATutor                                                                                                              */\r
+/****************************************************************/\r
+/* Copyright (c) 2002-2009                                                                             */\r
+/* Adaptive Technology Resource Centre / University of Toronto  */\r
+/* http://atutor.ca                                                                                            */\r
+/*                                                              */\r
+/* This program is free software. You can redistribute it and/or*/\r
+/* modify it under the terms of the GNU General Public License  */\r
+/* as published by the Free Software Foundation.                               */\r
+/****************************************************************/\r
+// $Id: module_install.php 8406 2009-04-01 20:38:44Z hwong $\r
+\r
+/*******\r
+ * the line below safe-guards this file from being accessed directly from\r
+ * a web browser. It will only execute if required from within an ATutor script,\r
+ * in our case the Module::install() method.\r
+ */\r
+if (!defined('AT_INCLUDE_PATH')) { exit; }\r
+\r
+/*******\r
+ * Note: the many options for these variables are used to decrease confusion.\r
+ *       TRUE | FALSE | 1 will be the convention.\r
+ *\r
+ * $_course_privilege\r
+ *     specifies the type of instructor privilege this module uses.\r
+ *     set to empty | FALSE | 0   to disable any privileges.\r
+ *     set to 1 | AT_PRIV_ADMIN   to use the instructor only privilege.\r
+ *     set to TRUE | 'new'        to create a privilege specifically for this module:\r
+ *                                will make this module available as a student privilege.\r
+ *\r
+ * $_admin_privilege\r
+ *    specifies the type of ATutor administrator privilege this module uses.\r
+ *    set to FALSE | AT_ADMIN_PRIV_ADMIN   to use the super administrator only privilege.\r
+ *    set to TRUE | 'new'                  to create a privilege specifically for this module:\r
+ *                                         will make this module available as an administrator privilege.\r
+ *\r
+ *\r
+ * $_cron_interval\r
+ *    if non-zero specifies in minutes how often the module's cron job should be run.\r
+ *    set to 0 or not set to disable.\r
+ */\r
+$_course_privilege = TRUE; // possible values: FALSE | AT_PRIV_ADMIN | TRUE\r
+$_admin_privilege  = TRUE; // possible values: FALSE | TRUE\r
+$_cron_interval    = 0; \r
+\r
+\r
+/********\r
+ * the following code is used for creating a module-specific directory.\r
+ * it generates appropriate error messages to aid in its creation.\r
+ */\r
+\r
+$directory = AT_CONTENT_DIR .'AtOpenCaps';\r
+// check if the directory is writeable\r
+if (!is_dir($directory) && !@mkdir($directory)) {\r
+       $msg->addError(array('MODULE_INSTALL', '<li>'.$directory.' does not exist. Please create it.</li>'));\r
+} else if (!is_writable($directory) && @chmod($directory, 0666)) {\r
+       $msg->addError(array('MODULE_INSTALL', '<li>'.$directory.' is not writeable. On Unix issue the command <kbd>chmod a+rw</kbd>.</li>'));\r
+}\r
+\r
+\r
+/******\r
+ * the following code checks if there are any errors (generated previously)\r
+ * then uses the SqlUtility to run any database queries it needs, ie. to create\r
+ * its own tables.\r
+ */\r
+if (!$msg->containsErrors() && file_exists(dirname(__FILE__) . '/module.sql')) {\r
+       // deal with the SQL file:\r
+       require(AT_INCLUDE_PATH . 'classes/sqlutility.class.php');\r
+       $sqlUtility =& new SqlUtility();\r
+\r
+       /*\r
+        * the SQL file could be stored anywhere, and named anything, "module.sql" is simply\r
+        * a convention we're using.\r
+        */\r
+       $sqlUtility->queryFromFile(dirname(__FILE__) . '/module.sql', TABLE_PREFIX);\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/module_uninstall.php b/mods/atutor_opencaps/module_uninstall.php
new file mode 100755 (executable)
index 0000000..8e9f443
--- /dev/null
@@ -0,0 +1,49 @@
+<?php\r
+/****************************************************************/\r
+/* ATutor                                                                                                              */\r
+/****************************************************************/\r
+/* Copyright (c) 2002-2009                                                                             */\r
+/* Adaptive Technology Resource Centre / University of Toronto  */\r
+/* http://atutor.ca                                                                                            */\r
+/*                                                              */\r
+/* This program is free software. You can redistribute it and/or*/\r
+/* modify it under the terms of the GNU General Public License  */\r
+/* as published by the Free Software Foundation.                               */\r
+/****************************************************************/\r
+// $Id: module_uninstall.php 8406 2009-04-01 20:38:44Z hwong $\r
+\r
+/*******\r
+ * module_uninstall.php performs reversion of module_install.php\r
+ */\r
+\r
+/*******\r
+ * the line below safe-guards this file from being accessed directly from\r
+ * a web browser. It will only execute if required from within an ATutor script,\r
+ * in our case the Module::uninstall() method.\r
+ */\r
+if (!defined('AT_INCLUDE_PATH')) { exit; }\r
+\r
+/********\r
+ * the following code is used for removing a module-specific directory created in module_install.php.\r
+ * it generates appropriate error messages to aid in its creation.\r
+ */\r
+$directory = AT_CONTENT_DIR .'AtOpenCaps';\r
+\r
+/******\r
+ * the following code checks if there are any errors (generated previously)\r
+ * then uses the SqlUtility to run reverted database queries of module.sql, \r
+ * ie. "create table" statement in module.sql is run as drop according table.\r
+ */\r
+if (!$msg->containsErrors() && file_exists(dirname(__FILE__) . '/module.sql')) {\r
+       // deal with the SQL file:\r
+       require(AT_INCLUDE_PATH . 'classes/sqlutility.class.php');\r
+       $sqlUtility =& new SqlUtility();\r
+\r
+       /*\r
+        * the SQL file could be stored anywhere, and named anything, "module.sql" is simply\r
+        * a convention we're using.\r
+        */\r
+       $sqlUtility->revertQueryFromFile(dirname(__FILE__) . '/module.sql', TABLE_PREFIX);\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/about.txt b/mods/atutor_opencaps/opencaps/conversion_service/about.txt
new file mode 100755 (executable)
index 0000000..a6e487e
--- /dev/null
@@ -0,0 +1,26 @@
+Caption Format Conversion Service
+
+Written by: 
+Antonio Gambabari
+antonio.gambabari@utoronto.ca
+
+This version: 
+November 2009
+
+Supported import formats:
+Timed Text (DFXP)
+QTtext
+SubRip
+JSON for OpenCaps
+
+Supported export formats:
+Timed Text (DFXP)
+DVD STL
+MicroDVD
+QT text
+SAMI
+SubRip
+SubViewer
+JSON for OpenCaps
+
+To use the conversion service on its own, go to (opencaps url)/conversion_service/ in your browser.
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/imported/index.html b/mods/atutor_opencaps/opencaps/conversion_service/imported/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/imported/noname.JSON b/mods/atutor_opencaps/opencaps/conversion_service/imported/noname.JSON
new file mode 100755 (executable)
index 0000000..c41593a
--- /dev/null
@@ -0,0 +1 @@
+{"collectionName":"","txtStylesGlobal":[],"captionCollection":[{"inTime":"00:00:00.000","outTime":"00:00:23.196","caption":"ok lang is ok","textStyles":[]},{"inTime":"00:00:29.594","outTime":"00:01:40.218","caption":"adfsdafsda","textStyles":[]},{"inTime":"00:01:46.299","outTime":"00:02:06.786","caption":"afdsfs","textStyles":[]}]}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/imported/noname.srt b/mods/atutor_opencaps/opencaps/conversion_service/imported/noname.srt
new file mode 100755 (executable)
index 0000000..0805c58
--- /dev/null
@@ -0,0 +1,12 @@
+1
+00:00:00,000 --> 00:00:23,196
+ok lang is oku000alove yoy php.flash
+
+2
+00:00:29,594 --> 00:01:40,218
+adfsdafsda
+
+3
+00:01:46,299 --> 00:02:06,786
+afdsfs
+
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/imported/noname.txt b/mods/atutor_opencaps/opencaps/conversion_service/imported/noname.txt
new file mode 100755 (executable)
index 0000000..72c0502
--- /dev/null
@@ -0,0 +1,19 @@
+{QTtext}{font: Tahoma}{plain}{size:18}{textColor: 45824,45824,45824}{backColor: 0,0,0}{justify:center}{timeScale: 1000}{timeStamps:absolute}{keyedtext:on}{language:0}{height:114}{width:334}{textEncoding:0}\r
+[00:00:00.000]\r
+hola anto\r
+[00:00:15.390]\r
+[00:00:21.174]\r
+22222222*******2222222\r
+[00:00:37.041]\r
+[00:00:39.556]\r
+33333333*******3333333\r
+[00:01:04.672]\r
+[00:01:07.436]\r
+4444444444*******44444444\r
+[00:01:12.210]\r
+[00:01:15.982]\r
+5555555*******5555555\r
+[00:01:21.263]\r
+[00:01:21.377]\r
+6666666666************666666666666\r
+[00:01:25.500]\r
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_DFXP_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_DFXP_format.php
new file mode 100755 (executable)
index 0000000..9962b79
--- /dev/null
@@ -0,0 +1,282 @@
+<?php\r
+/**\r
+ * DFXP Class\r
+ */\r
+class DFXP extends CaptionFormat\r
+{\r
+       private $textStyles = array();  \r
+       \r
+\r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString) {\r
+               \r
+               // include classes for XML parser\r
+               include_once('include/classes/core_XmlTag.php');\r
+               include_once('include/classes/core_XmlTagCollection.php');\r
+               include_once('include/classes/core_XmlTagTrace.php');\r
+               \r
+               // create a xml parser \r
+               $myXmlParse = new XmlTagTrace($theCCString,'P',4);\r
+               \r
+               // print xml collection\r
+               //$myXmlParse->toString();\r
+               \r
+               // get xml collection\r
+               $myXmlTagCollection = $myXmlParse->getCollection();\r
+               \r
+        //include_once('CaptionCollection.php');\r
+        $myCcCollection = new CaptionCollection();\r
+\r
+        foreach ($myXmlTagCollection as $xmlTagObj) \r
+        {              \r
+               //echo '<br/>Begin Time: '.$xmlTagObj->getTagAttribute('BEGIN');\r
+               //echo '<br/>End Time: '.$xmlTagObj->getTagAttribute('END'); \r
+               //echo '<br>Caption:'.$xmlTagObj->getTagValue();\r
+               \r
+               $txtStylesArr = Array();\r
+               $newCaption = new Caption($xmlTagObj->getTagAttribute('BEGIN').'0',$xmlTagObj->getTagAttribute('END').'0',$xmlTagObj->getTagValue(),$txtStylesArr);\r
+               \r
+               // add captions to the collection\r
+                       $myCcCollection->addCaption($newCaption);\r
+                       \r
+        } // end for \r
+       \r
+           //$myCcCollection->toString();\r
+               \r
+        return $myCcCollection;\r
+                \r
+       } // end importCC()\r
+       \r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               $ttCaption = '';\r
+       \r
+               $myCollection = $theCollection->getCollection();\r
+               \r
+               // add header\r
+               $ttCaption .= $this->getTTHeader();\r
+               \r
+               // Caption counter\r
+               $capCount = 0;\r
+\r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       $capCount++;\r
+                       \r
+                       // adding caption number - for debug purpuses \r
+                       //$captionObj->getCaption() = "[CAP no. $capCount]" . " ". $captionObj->getCaption();\r
+                       \r
+                       // adapt \n character to <br/>\r
+                       //$fixCap = "[CAP no. $capCount] : ". CcUtil::ccNewLineToBr($captionObj->getCaption(),' <br/>'); \r
+                       $fixCap = "". TxtFileTools::ccNewLineToBr($captionObj->getCaption(),' <br />');\r
+\r
+                       // convert qt to TT time format\r
+                       $ttTimeIn = $this->timeQtToTT($captionObj->getInTime());\r
+                       $ttTimeOut = $this->timeQtToTT($captionObj->getOutTime());\r
+       \r
+                       // ading TTcaptions\r
+                       $ttCaption .= "".$this->getTTCaption($ttTimeIn,$ttTimeOut,$fixCap,$captionObj->getTextStyles());\r
+\r
+                       // show caption object\r
+                       //$captionObj->toString();\r
+                       \r
+               } // end foreach\r
+               \r
+               //  close TT file\r
+               $ttCaption .= $this->getTTClose();\r
+               \r
+               return $ttCaption;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a QText caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               $isValid = false;\r
+               $patternCheck = "/({(QTtext)})/"; // RegExp to look for QText \r
+               preg_match_all($patternCheck,$theCCString,$patternFound);\r
+               \r
+               if(count($patternFound)>0)\r
+               {\r
+                       $isValid = true;\r
+               }\r
+\r
+               return $isValid;\r
+               \r
+       } // end  checkFormat() \r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'Timed Text (TT) Authoring Format 1.0 \96 Distribution Format Exchange Profile (DFXP)';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return 'This is the most comprehensive caption format ever !!\r
+               XML based.\r
+               Additional information at <a href="http://www.w3.org/TR/2006/CR-ttaf1-dfxp-20061116/">W3-dfxp</a>';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '1.0';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'dfxp.xml';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/(<tt xmlns="http:\/\/www.w3.org\/2006\/04\/ttaf1)/';\r
+               \r
+               return $idPattern;\r
+       }\r
+       \r
+       public function allowsTextStyles()\r
+       {\r
+               return '1';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               \r
+       }\r
+\r
+\r
+/*////////////////////////////////////////////////////////\r
+        Functions for TT - Timed Text Conversion\r
+//////////////////////////////////////////////////////*/\r
+\r
+\r
+/**\r
+ * creates a TT Caption \r
+ * @return String $ttCaption A TT formatted caption \r
+ * @param string $capInTime Caption start time (e.g 0:00:00.80)\r
+ * @param string $capOutTime Caption end time (e.g 0:00:00.80)\r
+ * @param String $caption caption, with all styles\r
+ * @param Array $txtStyles Array with text styles in the caption\r
+ */\r
+private function getTTCaption($capInTime,$capOutTime,$caption,$txtStyles)\r
+{\r
+        \r
+// <p begin="0:00:00.00" end="0:00:00.80">1 begining</p>\r
+\r
+        $ttCaption = "";\r
+        \r
+               // Find if text alignment in $txtStyles array\r
+               if (isset($txtStyles['text-align']))\r
+               {\r
+                       if ($txtStyles['text-align']=='right')\r
+                       {\r
+        // Add right alignment style\r
+        $ttCaption = '\r
+        <p begin="'.$capInTime.'" end="'.$capOutTime.'" style="txtRight">'.$caption.'</p>';                            \r
+                       } \r
+                       else if ($txtStyles['text-align']=='left')\r
+                       {\r
+        // Add right alignment style\r
+        $ttCaption = '\r
+        <p begin="'.$capInTime.'" end="'.$capOutTime.'" style="txtLeft">'.$caption.'</p>';\r
+                       }\r
+                       else if ($txtStyles['text-align']=='center')\r
+                       {\r
+        $ttCaption = '\r
+        <p begin="'.$capInTime.'" end="'.$capOutTime.'">'.$caption.'</p>';\r
+\r
+                       }\r
+                       \r
+               } else {\r
+                       // no text style, creates a plain caption   \r
+        $ttCaption = '\r
+        <p begin="'.$capInTime.'" end="'.$capOutTime.'">'.$caption.'</p>';\r
+               \r
+               } // end if\r
+        \r
+\r
+\r
+        return $ttCaption;\r
+        \r
+} // end getTTCaption()\r
+\r
+/**\r
+ * Converts QT time to TT Time; drops last right number on the time format\r
+ * @return String $ttTime TT time format 00:01:10.28"\r
+ * @param String $qtTime QT time Format; "00:01:10.280"\r
+ */\r
+private function timeQtToTT($qtTime)\r
+{\r
+        $ttTime = substr($qtTime, 0, 11); // returns "d"   ;\r
+        return $ttTime;\r
+} // end timeQtToTT\r
+\r
+/// TT Header \r
+private function getTTHeader()\r
+{\r
+// common vars\r
+$textFont = "Arial";\r
+$textFontWeight = "normal";\r
+$textFontStyle = "normal";\r
+$textSize = "12";\r
+$textJustify = "center";\r
+\r
+// unique vars \r
+$capTitle = 'This is a sample SAMI 1.0 caption';\r
+$textHtmlColor = "white";\r
+$bgHtmlColor = "black";\r
+$capLangName = "English";\r
+$capLangCode= "EN-US-CC";\r
+\r
+$capTT_header = '<?xml version="1.0" encoding="UTF-8"?>\r
+<tt xmlns="http://www.w3.org/2006/04/ttaf1"\r
+      xmlns:tts="http://www.w3.org/2006/04/ttaf1#styling" xml:lang="en">\r
+  <head>\r
+    <styling>\r
+      <style id="txtRight" tts:textAlign="right" tts:color="cyan"/>\r
+      <style id="txtLeft" tts:textAlign="left" tts:color="#FCCA03"/>\r
+      <style id="defaultSpeaker" tts:fontSize="'.$textSize.'px" tts:fontFamily="'.$textFont.'" tts:fontWeight="'.$textFontWeight.'" tts:fontStyle="'.$textFontStyle.'" tts:textDecoration="none" tts:color="'.$textHtmlColor.'" tts:backgroundColor="'.$bgHtmlColor.'" tts:textAlign="'.$textJustify.'" />\r
+      <style id="defaultCaption" tts:fontSize="14px" tts:fontFamily="SansSerif" tts:fontWeight="normal" tts:fontStyle="normal" tts:textDecoration="none" tts:color="white" tts:backgroundColor="black" tts:textAlign="left" />\r
+    </styling>\r
+  </head>\r
+  <body id="ccbody" style="defaultSpeaker">\r
+    <div xml:lang="en">';\r
+    \r
+        return $capTT_header;\r
+\r
+} // end getTTHeader()\r
+\r
+\r
+// Time Text Close\r
+private function getTTClose()\r
+{\r
+// alternative close   "<div xml:lang="en"/>"\r
+$capTT_close = '\r
+    </div>\r
+  </body>\r
+</tt>'\r
+;\r
+    return $capTT_close;\r
+}\r
+       \r
+}  // end classQText \r
+?>\r
+\r
+\r
+\r
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_DvdStl_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_DvdStl_format.php
new file mode 100755 (executable)
index 0000000..76533d3
--- /dev/null
@@ -0,0 +1,119 @@
+<?php\r
+/**\r
+ * DvdStl Class\r
+ */\r
+class DvdStl extends CaptionFormat\r
+{\r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString)\r
+       {\r
+               \r
+       } // end importCC()\r
+       \r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+               \r
+               $myCollection = $theCollection->getCollection();\r
+               \r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       $fixCap = TxtFileTools::ccNewLineToBr($captionObj->getCaption(),' ');\r
+                       \r
+                       $ccExport .= $captionObj->getInTime().', '.$captionObj->getOutTime().", ".$fixCap."\n\n";\r
+                       \r
+               } // end foreach\r
+               \r
+               return $ccExport;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a srt caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               \r
+       } // end checkFormat()\r
+       \r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'Spruce STL';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return 'Caption format used by DVD Studio and Avid in mac OS.\r
+               Very popular.\r
+               This format can be used to create DVD captions on Mac OS';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '???';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'stl';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               //$idPattern = '/([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{2})(.*)([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{2})(.*)/';\r
+               $idPattern = '/unknownZZZ/';\r
+               //00:00:03:24 , 00:00:06:29 , Did you read the paper today?\r
+               return $idPattern;\r
+       }\r
+\r
+       public function allowsTextStyles()\r
+       {\r
+               return '1';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '//English subtitles\r
+$FontName           = Arial\r
+$FontSize           = 36\r
+$HorzAlign          = Center\r
+$VertAlign          = Bottom\r
+$XOffset            = 0\r
+$YOffset            = 0\r
+$ColorIndex1        = 0\r
+$ColorIndex2        = 2\r
+$ColorIndex3        = 8\r
+$ColorIndex4        = 3\r
+$Contrast1          = 15\r
+$Contrast2          = 0\r
+$Contrast3          = 15\r
+$Contrast4          = 0\r
+$ForceDisplay       = FALSE\r
+$FadeIn             = 3\r
+$FadeOut            = 7\r
+$TapeOffset         = FALSE\r
+\r
+00:00:03:24 , 00:00:06:29 , Did you read the paper today?\r
+00:00:10:07 , 00:00:12:21 , No, did Edwards quote me right?\r
+00:00:14:19 , 00:00:25:28 , Actually, ^IBrillstein^I said you were | unimaginably full of yourself\r
+';\r
+       }\r
+\r
+} // end Dvd Class\r
+\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_JSONcc_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_JSONcc_format.php
new file mode 100755 (executable)
index 0000000..e6d6747
--- /dev/null
@@ -0,0 +1,113 @@
+<?php\r
+/**\r
+ * JSONcc Class\r
+ */\r
+class JSONcc extends CaptionFormat\r
+{\r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theJsonString)\r
+       {               \r
+               $theCcArray = json_decode($theJsonString,true);\r
+               \r
+               // Create a Caption Collection Object\r
+               $theCollection = new CaptionCollection();\r
+       \r
+               // set all global text styles using JSON-decoded array ???????\r
+               $theCollection->setTxtStylesGlobal($theCcArray['global_caption_styles']);\r
+\r
+               // check if there are captions in the captionCollection array and then add them to the Collection\r
+               if (count($theCcArray['clip_collection']['clips'])!=0 )\r
+               {                       \r
+                       foreach ($theCcArray['clip_collection']['clips'] as $CapArray)\r
+                       {\r
+                               // create a Caption Object\r
+                               $newCaptionObj = new Caption($CapArray['inTime'],$CapArray['outTime'],$CapArray['caption_text'],$CapArray['caption_styles']);\r
+                                                               \r
+                               // add caption object to the CaptionCollection \r
+                               $theCollection->addCaption($newCaptionObj);\r
+                       } // end foreach        \r
+               }// end if\r
+                               \r
+               return $theCollection; \r
+               \r
+       } // end importCC()\r
+       \r
+       \r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               $ccExport = '';\r
+  \r
+               // Use php built-in json encoder\r
+               $ccExport = json_encode($theCollection);\r
+\r
+               return $ccExport;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a JSON caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               \r
+       } // end checkFormat()\r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'JSON';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return 'JSON is a data representation model + much more. Captions can be played on any browser/OS using JavaScrinpt. However, plaing the video/audio binary files will require additional plugins such as QuickTime, Windows Media Player, etc... in order to load in a browser ';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '1.0';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'JSON';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               //$idPattern = '/(.*)/'; // match any pattern\r
+               $idPattern = '/"clips":\[/'; \r
+               \r
+               \r
+               return $idPattern;\r
+       }\r
+\r
+       public function allowsTextStyles()\r
+       {\r
+               return '1';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+\r
+       \r
+       \r
+} // end CCJSON Class\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_MPlayer_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_MPlayer_format.php
new file mode 100755 (executable)
index 0000000..951e150
--- /dev/null
@@ -0,0 +1,110 @@
+<?php\r
+/**\r
+ * MPlayer Class\r
+ */\r
+class MPlayer extends CaptionFormat\r
+{\r
+       private $textStyles = array();  \r
+       \r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString) \r
+       {\r
+               return'';\r
+                                \r
+       } // end importCC()\r
+\r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+       \r
+               $myCollection = $theCollection->getCollection();\r
+               \r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       \r
+               } // end foreach\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a QText caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               return '';\r
+               \r
+       } // end  checkFormat() \r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'MPlayer';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return 'This is the native format used by the popular and open source Mplayer video player. \r
+               If you have a video file, Mplayer will be able to play it almost on any OS (Win, Mac, Linux), and use many different caption formats as well !!\r
+               The best candidate !!';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '???';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'mpl';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/unknown/';\r
+               //\r
+               return $idPattern;\r
+       }\r
+       \r
+       public function allowsTextStyles()\r
+       {\r
+               return '????';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '\r
+0,85,0,caption 1 \r
+85,148,0,caption 2\r
+148,182,0,caption 3\r
+182,269,0,caption 4\r
+269,358,0,caption 5\r
+358,414,0,caption 6\r
+414,497,0,caption 7\r
+497,534,0,caption 8\r
+589,642,0,caption 9\r
+642,694,0,caption 10\r
+694,783,0,caption 11\r
+783,844,0,caption 12\r
+844,896,0,caption 13\r
+               \r
+               ';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+       \r
+}  // end MPlayer class \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_MicroDvd_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_MicroDvd_format.php
new file mode 100755 (executable)
index 0000000..b8270e0
--- /dev/null
@@ -0,0 +1,171 @@
+<?php\r
+\r
+/**\r
+ * MicroDvd Class\r
+ */\r
+class MicroDvd extends CaptionFormat\r
+{\r
+       private $textStyles = array();  \r
+       \r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString) {\r
+               //global $ins, $caps, $outs, $num_clips,$proj_caption;\r
+               $clips = array();\r
+               $clip_string = '';\r
+           \r
+               //$contents = file_get_contents($theCCFile);\r
+               $contents = $theCCString;\r
+        \r
+        // clean malformed patterns creted when saving files on win notepad\r
+        $toSearch = array(chr(13).chr(10));\r
+        $toReplace = array(chr(10));\r
+        $contents = str_replace($toSearch,$toReplace,$contents);\r
+        \r
+        // Defining QText known pattenrs;\r
+        $pattern_QT_time_format = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3})\]";\r
+        $pattern_QT_time_format_magpie = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{2})\]";\r
+        \r
+        $num_clips = preg_match_all("/$pattern_QT_time_format/", $contents, $clips);\r
+        \r
+        // if caption file is not QT and comes from MapPie time format\r
+               if ($num_clips == 0)\r
+               {\r
+                   $num_clips = preg_match_all("/$pattern_QT_time_format_magpie/", $contents, $clips);\r
+               }\r
+                   \r
+               //$num_clips = $num_clips/2; // this is not needed\r
+               \r
+               // create a collection object\r
+               include_once('CaptionCollection.php');\r
+               $myQTextCollection = new CaptionCollection();\r
+               \r
+               \r
+               // build data arrays looing through $clips QT format: 1) Split using QT time format, Find all times\r
+               for ($i=0; $i<$num_clips; $i=$i+2) {            \r
+                       \r
+                // 2) Find all content in between QT time START and END using /s flag to capture also break lines\r
+                $match_this = '/\['.$clips[1][$i].'\]\n(.*)\n\['.$clips[1][$i+1].'\]\n/s';                     \r
+                preg_match($match_this, $contents, $clip_bit);\r
+                \r
+                // add captions to the collection\r
+                $myQTextCollection->addCaptions($clips[1][$i],$clip_bit[1],$clips[1][$i+1]);\r
+                \r
+                /*\r
+                $ins[] = $clips[1][$i];\r
+                $caps[] = $clip_bit[1];\r
+                $outs[] = $clips[1][$i+1];\r
+                               */\r
+\r
+               } // end for \r
+       \r
+               return $myQTextCollection;\r
+                \r
+       } // end importCC()\r
+\r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+       \r
+               $myCollection = $theCollection->getCollection();\r
+               \r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       \r
+                       $miliSecIN = TimeUtil::timeQtToSami($captionObj->getInTime());\r
+                       $miliSecOUT = TimeUtil::timeQtToSami($captionObj->getOutTime());\r
+                       $fixCap = TxtFileTools::ccNewLineToBr($captionObj->getCaption(),' ');\r
+                       \r
+                       $ccExport .= "{".$miliSecIN."}{".$miliSecOUT."}".$fixCap."\n";\r
+                       \r
+               } // end foreach\r
+               \r
+               return $ccExport;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a QText caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               $isValid = false;\r
+               $patternCheck = "/({(QTtext)})/"; // RegExp to look for QText \r
+               preg_match_all($patternCheck,$theCCString,$patternFound);\r
+               \r
+               if(count($patternFound)>0)\r
+               {\r
+                       $isValid = true;\r
+               }\r
+\r
+               return $isValid;\r
+               \r
+       } // end  checkFormat() \r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'MicroDvd';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return 'Caption Format used by the popular video player MicroDVD';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '???';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'sub';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/unknown/';\r
+               //\r
+               return $idPattern;\r
+       }\r
+\r
+       public function allowsTextStyles()\r
+       {\r
+               return '0';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '\r
+{4952}{6082}caption 1\r
+{6084}{8977}caption 2\r
+{8979}{11928}caption 3\r
+{11930}{13795}caption 4\r
+{13797}{16569}caption 5\r
+{16571}{17816}caption 6\r
+{19656}{21412}caption 7\r
+{21414}{23133}caption 8\r
+{23135}{26100}caption 9\r
+{26102}{28141}caption 10\r
+{28143}{29867}caption 11\r
+';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+       \r
+}  // end MicroDvd class \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_QTSMIL_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_QTSMIL_format.php
new file mode 100755 (executable)
index 0000000..c5aac7a
--- /dev/null
@@ -0,0 +1,150 @@
+<?php\r
+/**\r
+ * QTSMIL Class\r
+ */\r
+class QTSMIL extends CaptionFormat\r
+{\r
+\r
+       private $textStyles = array();  \r
+       \r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString) {\r
+               //global $ins, $caps, $outs, $num_clips,$proj_caption;\r
+               $clips = array();\r
+               $clip_string = '';\r
+           \r
+               //$contents = file_get_contents($theCCFile);\r
+               $contents = $theCCString;\r
+        \r
+        // clean malformed patterns creted when saving files on win notepad\r
+        $toSearch = array(chr(13).chr(10));\r
+        $toReplace = array(chr(10));\r
+        $contents = str_replace($toSearch,$toReplace,$contents);\r
+        \r
+        // Defining QText known pattenrs;\r
+        $pattern_QT_time_format = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3})\]";\r
+        $pattern_QT_time_format_magpie = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{2})\]";\r
+        \r
+        $num_clips = preg_match_all("/$pattern_QT_time_format/", $contents, $clips);\r
+        \r
+        // if caption file is not QT and comes from MapPie time format\r
+               if ($num_clips == 0)\r
+               {\r
+                   $num_clips = preg_match_all("/$pattern_QT_time_format_magpie/", $contents, $clips);\r
+               }\r
+                   \r
+               //$num_clips = $num_clips/2; // this is not needed\r
+               \r
+               // create a collection object\r
+               include_once('CaptionCollection.php');\r
+               $myQTextCollection = new CaptionCollection();\r
+               \r
+               \r
+               // build data arrays looing through $clips QT format: 1) Split using QT time format, Find all times\r
+               for ($i=0; $i<$num_clips; $i=$i+2) {            \r
+                       \r
+                // 2) Find all content in between QT time START and END using /s flag to capture also break lines\r
+                $match_this = '/\['.$clips[1][$i].'\]\n(.*)\n\['.$clips[1][$i+1].'\]\n/s';                     \r
+                preg_match($match_this, $contents, $clip_bit);\r
+                \r
+                // add captions to the collection\r
+                $myQTextCollection->addCaptions($clips[1][$i],$clip_bit[1],$clips[1][$i+1]);\r
+                \r
+                /*\r
+                $ins[] = $clips[1][$i];\r
+                $caps[] = $clip_bit[1];\r
+                $outs[] = $clips[1][$i+1];\r
+                               */\r
+\r
+               } // end for \r
+       \r
+               return $myQTextCollection;\r
+                \r
+       } // end importCC()\r
+\r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+       \r
+               $myCollection = $theCollection->getCollection();\r
+       \r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       \r
+               } // end foreach\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a QText caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               $isValid = false;\r
+               $patternCheck = "/({(QTtext)})/"; // RegExp to look for QText \r
+               preg_match_all($patternCheck,$theCCString,$patternFound);\r
+               \r
+               if(count($patternFound)>0)\r
+               {\r
+                       $isValid = true;\r
+               }\r
+\r
+               return $isValid;\r
+               \r
+       } // end  checkFormat() \r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return '';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return '';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return '';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/unknown/';\r
+               //\r
+               return $idPattern;\r
+       }\r
+\r
+       public function allowsTextStyles()\r
+       {\r
+               return '1';\r
+       }\r
+       public function template()\r
+       {\r
+               $ccTemplate = '';\r
+               \r
+               return $ccTemplate;\r
+       }       \r
+\r
+}  // end classQText \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_QTtext_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_QTtext_format.php
new file mode 100755 (executable)
index 0000000..f3c466c
--- /dev/null
@@ -0,0 +1,517 @@
+<?php\r
+/**\r
+ * QTtext Class\r
+ */\r
+class QTtext extends CaptionFormat\r
+{\r
+       private $textStyles = array();  \r
+       \r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString) \r
+       {\r
+               //echo 'show the replaced TQtext:<form><textarea name="textarea" cols="120" rows="5">'. $theCCString. '</textarea></form>';\r
+               \r
+               // clean malformed patterns creted when files were saved on win notepad\r
+        //$toSearch = array(chr(13).chr(10));\r
+        //$toReplace = array(chr(10));\r
+               \r
+               $toSearch = array(chr(13).chr(10),chr(13),chr(10).chr(32).chr(10),chr(10).chr(10) ); // this default break line in Capscribe Desktop - Mac OS\r
+        $toReplace = array(chr(10),chr(10),chr(10),chr(10));\r
+               \r
+        //$toSearch = chr(13); // this default break line in Capscribe Desktop - Mac OS\r
+        //$toReplace = chr(10);\r
+               \r
+               $theCCString = str_replace($toSearch,$toReplace,$theCCString);\r
+       \r
+               // get all lines in array\r
+               $allLines = split(chr(10),$theCCString);\r
+               $controlTime = 0; // control time marks IN and OUT\r
+               $controlCaptionLines = 0; // control the number of lines of one caption \r
+               $addCaptionControl = 0; //Start Adding caption when = 1\r
+               $isTime=0;\r
+               $captionCounter = 0; // Total number of captions found\r
+               \r
+               $timesIn = array();\r
+               $timesOut = array();\r
+               $captions = array();\r
+               \r
+        // Defining QText known pattenrs;\r
+               $qtPatternRegEx = "/({(.*?)})/";  \r
+               $pattern_QT_time_format_000 = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3})\]";\r
+        $pattern_QT_time_format_00 = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{2})\]";\r
+        $pattern_QT_time_format_selected = '';\r
+           \r
+        // determine if miliseconds are in 2 of 3 digit format \r
+        if (preg_match("/$pattern_QT_time_format_000/", $theCCString))\r
+        {\r
+               $pattern_QT_time_format_selected = $pattern_QT_time_format_000;\r
+        } \r
+        else if (preg_match("/$pattern_QT_time_format_00/", $theCCString)) \r
+        {\r
+               $pattern_QT_time_format_selected = $pattern_QT_time_format_00;\r
+        }\r
+               \r
+        //  loop through caption lines\r
+        for ($i=0; $i<count($allLines);$i++)\r
+        {\r
+               //echo '<br/>';\r
+               //echo '<br/>Line ('.$i.') *** '.($allLines[$i]).'';\r
+               \r
+               // is this a time mark ?\r
+               $isTime = preg_match("/$pattern_QT_time_format_selected/", $allLines[$i]);\r
+               \r
+               // if it is a time mark, start converting else is a caption n lines\r
+               if ($isTime==1)\r
+               {\r
+                       // clean up time mark '[]' characters\r
+                       $allLines[$i] = str_replace('[','',$allLines[$i]);\r
+                       $allLines[$i] = str_replace(']','',$allLines[$i]);\r
+                       \r
+                       // Is this the First time mark?\r
+                       if ($controlTime == 0)\r
+                       {\r
+                               // ok get the first time mark and wait for the time out mark \r
+                               $timesIn[] = $allLines[$i]; // mm this is not java style... FIX ME!!\r
+                               $controlTime = 2;\r
+                               // start caption text and wait for n lines\r
+                               $captions[$captionCounter]= '';\r
+                                       $addCaptionControl = 1;\r
+                               $currentIndex = $captionCounter;\r
+                               $captionCounter++;\r
+                                       //echo '------ This The first time TIME MARK';\r
+                       }\r
+                       \r
+                   // Is this the Time IN of the caption?\r
+                       else if ($controlTime == 1)\r
+                       {\r
+                               // add time in\r
+                               $timesIn[] = $allLines[$i]; // mm this is not java style... FIX ME!!\r
+                               $controlTime = 2;\r
+                               // start caption text and wait for n lines\r
+                               $captions[$captionCounter]= '';\r
+                               $addCaptionControl = 1;\r
+                               $currentIndex = $captionCounter;\r
+                               $captionCounter++;\r
+                                       //echo '------ This is IN TIME MARK';\r
+                       }\r
+\r
+                   // Is this the Time Out of the caption?\r
+                       else if ($controlTime == 2)\r
+                       {\r
+                               // add time in\r
+                               $timesOut[] = $allLines[$i]; // mm this is not java style... FIX ME!!\r
+                               $controlTime = 1;\r
+                               $addCaptionControl = 0;\r
+                                       //echo '------ This is OUT TIME MARK';\r
+                       }\r
+                       \r
+               } else {\r
+                       \r
+                       // start adding captions\r
+                       if ($addCaptionControl==1)\r
+                       {\r
+                               // add new line to the current caption\r
+                               $captions[$currentIndex] .= $allLines[$i].chr(10);\r
+                               //echo '------ The caption'.$captions[$currentIndex];\r
+                       }\r
+               } // end if\r
+               \r
+        } // end for \r
+        \r
+        // create a collection object\r
+        $myQTextCollection = new CaptionCollection();\r
+        \r
+        /*\r
+        echo '<br/><br/>Total Captions Found:  '.$captionCounter;\r
+        echo '<br/><br/>Total TIME IN:  '.count($timesIn);\r
+        echo '<br/><br/>Total TIME OUT:  '.count($timesOut);\r
+        echo '<br/><br/>Total CAPTIONS:  '.count($captions);\r
+        */\r
+        \r
+        // test in a text area\r
+               //echo '<form><textarea cols="100" rows="10">';\r
+           ///*\r
+        for ($j=0;$j<$captionCounter;$j++)\r
+           {\r
+            \r
+            // get all QT styles found in caption text\r
+            preg_match_all($qtPatternRegEx,$captions[$j],$captionStylesFound);\r
+\r
+            // clean all QT styles from the caption  \r
+            $captions[$j] = str_replace($captionStylesFound[0], "", $captions[$j]);\r
+            \r
+            // show the plain text Caption\r
+            //echo '<br/><br/>'.$captions[$j];\r
+            \r
+            /*\r
+            // show all QT found in caption line\r
+            foreach ($captionStylesFound[0] as $allStyleAttrib => $allStyleValue)\r
+            {\r
+               echo '<br/>'.$allStyleAttrib.' = '.$allStyleValue;\r
+            }\r
+            */        \r
+\r
+                       $textStyles = Array();\r
+                       \r
+            // add text styles features to caption text styles array\r
+            if (isset($captionStylesFound[0]))\r
+            {\r
+                foreach ($captionStylesFound[0] as $txtStyle)\r
+                {\r
+                       //$textStyles[] = $txtStyle;\r
+                       //echo '<br/>'.$txtStyle;\r
+                       \r
+                       //adding only known text styles\r
+                       if ($txtStyle == '{justify:center}')\r
+                       {\r
+                               $textStyles['text-align'] = 'center';\r
+                       } else if ($txtStyle == '{justify:left}')\r
+                       {\r
+                               $textStyles['text-align'] = 'left';\r
+                       }                                       \r
+                       else if ($txtStyle == '{justify:right}')\r
+                       {\r
+                               $textStyles['text-align'] = 'right';\r
+                       } else {\r
+                               // adding QT formats\r
+                               //$textStyles['QT'.$txtStyle] = $txtStyle.'-- NOT used yet';\r
+                       } // end if else\r
+                } // end for each\r
+            } // end if\r
+\r
+            // add a capton only if all values are set\r
+                \r
+                       if (isset($timesIn[$j]) && isset($timesOut[$j]) && isset($captions[$j]))\r
+                       {\r
+                               // Create a Caption Object\r
+                               $newCaption = new Caption($timesIn[$j],$timesOut[$j],$captions[$j],$textStyles);\r
+                \r
+                // print added caption\r
+                //echo $newCaption->toString(); \r
+\r
+                // add caption object to the collection\r
+                $myQTextCollection->addCaption($newCaption);\r
+                }\r
+            \r
+            /*\r
+            echo chr(10).'IN:  '.$timesIn[$j];\r
+               echo chr(10).'OUT:  '.$timesOut[$j];\r
+               echo chr(10).'Caption:  '.$captions[$j];\r
+               */\r
+                //echo chr(10).'Caption:  '.$captions[$j];\r
+                \r
+           }// end for    \r
+           //*/\r
+\r
+                       //echo '</textarea></form>';         \r
+        \r
+                       \r
+        // print for test\r
+        //echo $myQTextCollection->toString();\r
+                       \r
+        return $myQTextCollection;\r
+                \r
+       } // end importCC()\r
+\r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+       \r
+               $myCollection = $theCollection->getCollection();\r
+               \r
+               // add QT header\r
+               $ccExport .= $this->getHeader()."\r\n";\r
+               \r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       // add time in\r
+                       $ccExport .= '['.$captionObj->getInTime().']'."\r\n";\r
+                       \r
+                       // Convert <br/> into \n character\r
+                       $fixCaption = str_replace('<BR />',"\r\n",$captionObj->getCaption());\r
+                       //echo '<br/>'.$fixCaption;\r
+                       \r
+                       // get getTextStyles array from caption object\r
+                       $ccTxtStyles = $captionObj->getTextStyles();\r
+                       \r
+                               //$ccTxtStyles = $this->getDefaultStyles($captionObj->getTextAtribute('text-align'));\r
+                       \r
+                       //  check if the caption has text styles\r
+                       if (count($ccTxtStyles)!=0)\r
+                       {\r
+                               // loop all txt styles\r
+                               foreach ($ccTxtStyles as $txtAttrib => $txtValue)\r
+                               {\r
+                                       // HERE parse any known txt style and apply it to the caption\r
+                                       \r
+                                       // only for text alignment in QT\r
+                                       if ($txtValue=='center' || $txtValue=='left' || $txtValue=='right')\r
+                                       {\r
+                                               // get the txt align default values\r
+                                               $thisTxtAlign = $this->getDefaultStyles($txtValue,strlen($fixCaption));\r
+                                                       //echo '<br/>'.$fixCaption;\r
+                                                       //echo '<br/> Lenght: '.strlen($fixCaption);\r
+                                               \r
+                                               // add default text styles to the caption \r
+                                               $fixCaption = $thisTxtAlign.$fixCaption;\r
+                                       } // end if\r
+                                       \r
+                               } // end for\r
+                                       \r
+                       } // end if txt styles\r
+                       \r
+                       // add caption(s) to export string \r
+                       //$ccExport .= $fixCaption;\r
+                       $ccExport .= $fixCaption."\r\n";\r
+                       \r
+                       // add time out\r
+                       $ccExport .= '['.$captionObj->getOutTime().']'."\r\n";\r
+                       \r
+               } // end foreach\r
+               \r
+               \r
+               // Remove any doble break line (already done in import string.. but just in case captions lines bring this issue;) \r
+               //-- $ccExport = str_replace(chr(10).chr(10),chr(10),$ccExport);\r
+               \r
+               return $ccExport;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a QText caption file\r
+        *\r
+        * @param String $theCCString A caption file as text = string\r
+        * @return Boolean\r
+        */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               \r
+               $isValid = false;\r
+               $patternCheck = "/({(QTtext)})/"; // RegExp to look for QText \r
+               preg_match_all($patternCheck,$theCCString,$patternFound);\r
+               \r
+               if(count($patternFound)>0)\r
+               {\r
+                       $isValid = true;\r
+               }\r
+\r
+               return $isValid;\r
+               \r
+       } // end  checkFormat() \r
+\r
+       /**\r
+        * Get the name of the Caption Format Class\r
+        *\r
+        * @return String $captionFormatname The name of the Caption Format\r
+        */\r
+       public function getName()\r
+       {\r
+               $captionFormatname = 'Quick Time Text';\r
+               \r
+               return $captionFormatname;\r
+       }\r
+       \r
+       /**\r
+        * Get the Description of the Caption Format\r
+        *\r
+        * @return String $captionAbout Description of the Caption Format\r
+        */\r
+       public function getAbout()\r
+       {\r
+               $captionAbout = 'This format can be used by Quick Time Player.\r
+               This is the native format of CAPSCRIBE !!! \r
+               Additional information can be found at <a href="http://www.apple.com/quicktime/tutorials/texttracks.html">Apple Website</a>';\r
+               \r
+               return $captionAbout;\r
+               \r
+               \r
+       }\r
+       \r
+       /**\r
+        * Get the version of the caption format class\r
+        *\r
+        * @return String $theVersion The Version of the Caption Format as String\r
+        */\r
+       public function getVersion()\r
+       {\r
+               $theVersion = '1.0';\r
+                \r
+               return $theVersion;\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               $theExtension = 'txt';\r
+                \r
+               return $theExtension;\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/({QTtext})/';\r
+               //$idPattern = "/({(.*?)})/";\r
+               //$qtPatternRegEx = "/({(.*?)})/";\r
+               \r
+               return $idPattern;\r
+       }\r
+       \r
+       public function allowsTextStyles()\r
+       {\r
+               return '1';\r
+       }       \r
+\r
+       public function template()\r
+       {\r
+               $ccTemplate = '\r
+{QTtext}{font: Comic Sans MS}{italic}{size:18}{textColor: 65280,65280,65280}{backColor: 0,0,0}{justify:center}{timeScale: 1000}{timeStamps:absolute}{keyedtext:on}{language:0}{height:156}{width:383}{textEncoding:0}\r
+[00:00:00.002]\r
+caption 1 line1\r
+caption 1 line2\r
+[00:00:02.849]\r
+[00:00:02.851]\r
+caption 2 line1\r
+caption 2 line2\r
+[00:00:04.950]\r
+[00:00:04.952]\r
+caption 3\r
+[00:00:06.082]\r
+\r
+... or ...\r
+\r
+{QTtext} {font:Tahoma}\r
+{plain} {size:20}\r
+{timeScale:30}\r
+{width:160} {height:32}\r
+{timeStamps:absolute} {language:0}\r
+[00:00:00.00]\r
+caption 1 - using Bold style?\r
+[00:00:02.84]\r
\r
+[00:00:02.85]\r
+caption 2\r
+[00:00:04.95]\r
\r
+[00:00:04.95]\r
+caption 3\r
+[00:00:06.08]\r
+\r
+';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+\r
+/*////////////////////////////////////////////////////////\r
+        Functions for QText conversion\r
+//////////////////////////////////////////////////////*/\r
+       \r
+       /**\r
+        * Creates the QText default header.. soon this method will receive all the needed parameters\r
+        *\r
+        * @return String $myHeader The QText default header\r
+        */\r
+       private function getHeader()\r
+       {\r
+               /*\r
+               {font: Tahoma}\r
+               {plain}\r
+               {size:18}\r
+               {textColor: 45824,45824,45824}\r
+               {backColor: 0,0,0}\r
+               {justify:center}\r
+               {timeScale: 1000}\r
+               {timeStamps:absolute}\r
+               {keyedtext:on}\r
+               {language:0}\r
+               {height:114}\r
+               {width:334}\r
+               {textEncoding:0}\r
+                */\r
+               \r
+               // common vars\r
+               $textFont = "Comic Sans MS";\r
+               $textSize = "18";\r
+               $textJustify = "center";\r
+\r
+               // Unique QText header Variables                \r
+               $myHeader = '{QTtext}';\r
+               $myHeader .= '{font: '.$textFont.'}';\r
+               //$myHeader .= '{plain}';\r
+               //$myHeader .= '{size: '.$textSize.'}';\r
+               $myHeader .= '{textColor: 65280,65280,0}';\r
+               $myHeader .= '{backColor: 0,0,0}';\r
+               $myHeader .= '{justify:'.$textJustify.'}';\r
+               $myHeader .= '{timeScale: 1000}';\r
+               $myHeader .= '{timeStamps:absolute}';\r
+               $myHeader .= '{keyedtext:on}'; ///  WHAT IS THIS????? FIX ME\r
+               $myHeader .= '{language:0}'; // working on ...\r
+               $myHeader .= '{width:114}'; // working on ...\r
+               $myHeader .= '{height:334}'; // working on ...\r
+               $myHeader .= '{textEncoding:0}';\r
+               // ... and much more can be set here acording to QT specification ...\r
+               \r
+               /*\r
+               {anti-alias: onOrOff }\r
+               {doNotDisplay: onOrOff }\r
+               {doNotAutoScale: onOrOff }\r
+               */\r
+               \r
+               $myHeader = '{QTtext}{font: Tahoma}{plain}{size:18}{textColor: 45824,45824,45824}{backColor: 0,0,0}{justify:center}{timeScale: 1000}{timeStamps:absolute}{keyedtext:on}{language:0}{height:114}{width:334}{textEncoding:0}';\r
+               \r
+               return $myHeader;\r
+       }       // end getHeader\r
+       \r
+       /**\r
+        * Sets default QT text styles at the caption level. No text style implemented yet at the word level \r
+        * @param String $txtAlign The text alignment, (e.g. 'left', 'right') if null assumed center\r
+        * @return String $myStyles the QText styles to be added before the caption text.\r
+        */\r
+       private function getDefaultStyles($txtAlign,$txtLength )\r
+       {\r
+               // {hilitecolor:3000,0,0}{hilite:0,103}{font:Tahoma}{size:18}{textcolor:45824,45824,45824}{backcolor:0,0,0}{justify:center}{plain}( \r
+               $myStyles = '';\r
+               //$myStyles .= '{hilitecolor:3000,0,0}{hilite:0,139}{font:Tahoma}';\r
+               $myStyles .= '{hilitecolor:3000,0,0}{hilite:0,'.$txtLength.'}{font:Tahoma}{size:18}{backcolor:0,0,0}';\r
+               \r
+               if ($txtAlign == 'left')\r
+               {\r
+                       $myStyles .= '{textcolor:65280,55040,18432}{justify:'.$txtAlign.'}';\r
+               } \r
+               else if ($txtAlign == 'right')\r
+               {\r
+                       $myStyles .= '{textcolor:26112,65280,65280}{justify:'.$txtAlign.'}';\r
+               }\r
+               else \r
+               {\r
+                       $myStyles .= '{textcolor:45824,45824,45824}{justify:center}';\r
+               }\r
+               // and much more to be added here... !! \r
+               \r
+               /**\r
+               {plain} Plain text.\r
+               {bold} Bold text.\r
+               {italic} Italic text.\r
+               {underline} Underlined text.\r
+               {outline} Outlined text.\r
+               {shadow} Text with a drop shadow.\r
+               {condense} Text with spacing between characters decreased.\r
+               {extend} Text with spacing between characters increased. \r
+                */\r
+               //$myStyles .= '{plain}';\r
+               \r
+               return $myStyles;\r
+       \r
+       }\r
+}  // end classQText \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_RealText_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_RealText_format.php
new file mode 100755 (executable)
index 0000000..b76add3
--- /dev/null
@@ -0,0 +1,122 @@
+<?php\r
+/**\r
+ * RealText Class\r
+ */\r
+class RealText extends CaptionFormat\r
+{\r
+       private $textStyles = array();\r
+       \r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString)\r
+       {\r
+               \r
+       } // end importCC()\r
+       \r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+               \r
+               $myCollection = $theCollection->getCollection();\r
+               \r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       \r
+               } // end foreach\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a srt caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               \r
+       } // end checkFormat()\r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'Real Time';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return 'This Caption format can be played by Real Player.';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '???';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'rt';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '';\r
+               $idPattern .= '/'; // open regex\r
+               $idPattern .= '('; // start class pattern\r
+               $idPattern .= '\<Time begin="';\r
+               $idPattern .= '[0-9]{1}:[0-9]{2}:[0-9]{2}.[0-9]{1}"'; // 1 digit at the begining and 1 at the end\r
+               $idPattern .= '|'; // or\r
+               $idPattern .= '\<Time begin="';\r
+               $idPattern .= '[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{1}"'; // 2 digit at the begining and 1 at the end\r
+               $idPattern .= '|'; // or\r
+               $idPattern .= '\<Time begin="';\r
+               $idPattern .= '[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{2}"'; // 2 digit at the begining and 2 at the end\r
+               $idPattern .= ')'; // end class pattern\r
+               $idPattern .= '/'; // close regex\r
+               \r
+               return $idPattern;\r
+       }\r
+       \r
+       public function allowsTextStyles()\r
+       {\r
+               return '1';\r
+       }       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '\r
+<window bgcolor="000000" wordwrap="true" duration="00:00:02.00">\r
+<font size="+1" face="Arial" color="#FFFFFF">\r
+<center>\r
+<time begin="00:00:00.00"/><clear/>\r
+First caption here.\r
+<time begin="00:00:01.00"/><clear/>\r
+Final caption here.\r
+<time begin="00:00:02.00"/><clear/>\r
+</center>\r
+</font>\r
+</window> \r
+\r
+.... or ..... \r
+\r
+<Time begin="01:99:99.01"/><clear/>\r
+First caption here.\r
+<Time begin="02:99:99.02"/><clear/>\r
+Final caption here.\r
+<Time begin="03:99:99.03"/><clear/>\r
+';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+       \r
+} // end Class\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_Sami_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_Sami_format.php
new file mode 100755 (executable)
index 0000000..b363a48
--- /dev/null
@@ -0,0 +1,227 @@
+<?php\r
+/**\r
+ * Sami Class\r
+ */\r
+class Sami extends CaptionFormat\r
+{\r
+       private $textStyles = array();\r
+\r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString)\r
+       {\r
+               $ccTarget = '';\r
+               \r
+       } // end importCC()\r
+       \r
+\r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+       \r
+               $myCollection = $theCollection->getCollection();\r
+       \r
+               // start SAMI Caption\r
+               $samiCaption = "";\r
+       \r
+               // add header\r
+               $samiCaption .= $this->getSamiHeader();\r
+               \r
+               // Caption counter\r
+               $capCount = 0;\r
+\r
+               // Building Sami caption \r
+               $fileContent = '';\r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+       \r
+                       $capCount++;\r
+\r
+                       // convert to qt to Sami time format\r
+                       $samiTimeIn = TimeUtil::timeQtToSami($captionObj->getInTime());\r
+                       $samiTimeOut = TimeUtil::timeQtToSami($captionObj->getOutTime());\r
+                       \r
+                       $captionStyles = $captionObj->getTextStyles();\r
+                       \r
+                       $fixCap = TxtFileTools::ccNewLineToBr($captionObj->getCaption(),' <br/>');\r
+                       \r
+                       // ading caption to String \r
+                               //$samiCaption .= "". $this->getSamiCaption($samiTime,$fixCap,"QT");\r
+                       \r
+                       // new adding empty caption when time out\r
+                       $samiCaption .= "". $this->getSamiCaption($samiTimeIn,$samiTimeOut,$fixCap,$captionObj->getTextStyles());\r
+        \r
+               } // end for each caption \r
+\r
+               //  close SAMi file\r
+               $samiCaption .= $this->getSamiClose();\r
+               \r
+               $samiCaption .= "";\r
+               \r
+               $ccExport = $samiCaption;\r
+                               \r
+               return $ccExport;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a SAMI caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               \r
+       } // end checkFormat()\r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'SAMI';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return 'This caption format can be played by Windows Media Player on Windows OS. ';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '1.0';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'smi';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/(<SAMI>)/';\r
+               \r
+               return $idPattern;\r
+       }\r
+\r
+       public function allowsTextStyles()\r
+       {\r
+               return '1';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+\r
+\r
+/*////////////////////////////////////////////////////////\r
+        Functions for SAMI conversion\r
+//////////////////////////////////////////////////////*/\r
+\r
+/**\r
+ * creates a SAMI Caption \r
+ * @return String $samiCaption A SAMI formatted caption \r
+ * @param int $capInTime Caption start time in miliseconds 1 sec = 1000\r
+ * @param int $capOutTime Caption end time in miliseconds 1 sec = 1000\r
+ * @param String $caption caption, with all styles\r
+ * @param Array $txtStyles Array with text styles in the caption \r
+ */\r
+private function getSamiCaption($capInTime,$capOutTime,$caption,$txtStyles)\r
+{\r
+       $samiCaption = "";\r
+       $captionReFormated = "";\r
+                \r
+       // Find if text alignment in $txtStyles array\r
+       if (isset($txtStyles['text-align']))\r
+       {\r
+               if ($txtStyles['text-align']=='right')\r
+               {\r
+                       $caption = '<table align=right><span style="color:#00FFFF">'.$caption.'</span></table>';\r
+               }\r
+               else if ($txtStyles['text-align']=='left')\r
+               {\r
+                       $caption = '<table align=left><span style="color:#FCCA03">'.$caption.'</span></table>';\r
+               }\r
+               else if ($txtStyles['text-align']=='center')\r
+               {\r
+                       $caption = '<table align=center>'.$caption.'</table>';\r
+               }\r
+       }\r
+                \r
+                \r
+    // Create SAMI Caption\r
+       $samiCaption = '\r
+        <SYNC start='.$capInTime.'><P>'.$caption.'</P></SYNC>';\r
+                \r
+        // add an empty caption when caption finishes if caption's lenght is more than x sec\r
+        // prevents caption for displaying it if next caption is to ahead  //// still working\r
+               $captionLenght = $capOutTime-$capInTime; \r
+        if ($captionLenght>2000)\r
+        {\r
+       $samiCaption .= '\r
+        <SYNC start='.$capOutTime.'><P>&nbsp;</P></SYNC>';\r
+        }\r
+        \r
+        return $samiCaption;\r
+        \r
+} // end getSamiCaption\r
+\r
+\r
+// SAMI Header \r
+private function getSamiHeader()\r
+{\r
+// common vars\r
+$textFont = "Arial";\r
+$textFontWeight = "normal";\r
+$textSize = "18";\r
+$textJustify = "center";\r
+\r
+// unique vars for SAMI\r
+$capTitle = 'This is a sample SAMI 1.0 caption';\r
+$textHtmlColor = "#FFFFFF";\r
+$bgHtmlColor = "#000000";\r
+$capLangName = "English";\r
+$capLangCode= "EN-US-CC";\r
+\r
+$capSAMI_header = '<SAMI>\r
+<HEAD>\r
+<TITLE>'.$capTitle.'</TITLE>\r
+<STYLE TYPE="text/css">\r
+<!--\r
+P { margin:  2px 20% 0px 20%; font-size:'.$textSize.'; font-family: '.$textFont.'; font-weight: '.$textFontWeight.'; color: '.$textHtmlColor.'; background-color: '.$bgHtmlColor.'; text-align: '.$textJustify.'; }\r
+.ENUSCC { name: '.$capLangName.'; lang: '.$capLangCode.'; }\r
+.txtRight { font-size:'.$textSize.'; font-family: '.$textFont.'; font-weight: '.$textFontWeight.'; color: #00FFFF; background-color: '.$bgHtmlColor.'; text-align: right; } \r
+.txtLeft { font-size:'.$textSize.'; font-family: '.$textFont.'; font-weight: '.$textFontWeight.'; color: #FCCA03; background-color: '.$bgHtmlColor.'; text-align: left; } \r
+-->\r
+</STYLE>\r
+</HEAD>\r
+<BODY>';\r
+    return $capSAMI_header;\r
+} // end getSamiHeader()\r
+\r
+\r
+// SAMI Close\r
+private function getSamiClose()\r
+{\r
+$capSAMI_close = '\r
+</BODY>\r
+</SAMI>';\r
+    return $capSAMI_close;\r
+}\r
+\r
+       \r
+       \r
+} // end CCsami Class\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_Scc_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_Scc_format.php
new file mode 100755 (executable)
index 0000000..b7b2317
--- /dev/null
@@ -0,0 +1,149 @@
+<?php\r
+/**\r
+ * Scc Class\r
+ */\r
+class Scc extends CaptionFormat\r
+{\r
+       private $textStyles = array();\r
+\r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString)\r
+       {\r
+               $ccTarget = '';\r
+               \r
+       } // end importCC()\r
+\r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               /*\r
+                * <br/>Based on the SCC convertion class by Colin McFadden at <br/>\r
+                * <a href="http://blog.lib.umn.edu/mcfa0086/discretecosine/2008_10.html">http://blog.lib.umn.edu/mcfa0086/discretecosine/2008_10.html</a>'; \r
+               */\r
+               \r
+               $ccExport = '';\r
+               \r
+               $myCollection = $theCollection->getCollection();\r
+               \r
+               // include SCC external convertor\r
+               include("include/classes/ext_SccConvert_class.php");\r
+               \r
+               $startTC = "00:00:00:00";\r
+               \r
+               //create a SCC captionConvert instance\r
+               $sccCaptions = new captionConvert($startTC);\r
+\r
+\r
+               // Building Sami caption \r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+       \r
+                       //$capCount++;\r
+\r
+               $beginTime = $captionObj->getInTime();\r
+               $captionContents = $captionObj->getCaption();\r
+               \r
+               // clean any xml style\r
+               $toSearch = array('<b>','</b>','<u>','</u>','<i>','</i>','<br/>','<br>','<BR/>','\n',chr(10)); \r
+               $toReplace = '';\r
+                       $captionContents = str_replace($toSearch,$toReplace,$captionContents);\r
+\r
+                       // add SCC captions \r
+               $sccCaptions->addCaption($beginTime, $captionContents);\r
+                       \r
+                       //$fixCap = CcUtil::ccNewLineToBr($captionObj->getCaption(),' <br/>');\r
+       \r
+               } // end for each caption \r
+                               \r
+               // ading caption to String \r
+               $ccExport .= ''.$sccCaptions->outputCaptions();\r
+\r
+               \r
+               return $ccExport;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a SAMI caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               \r
+       } // end checkFormat()\r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'SCC - Scenarist Closed Caption';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return 'This caption format is one of the standards in the TV industry. <br>SCC is used by M4V movies targeted for the Apple iPhone, iPod Touch and iPod Nano.<br/> As documented in <a href="http://ncam.wgbh.org/mm/m4vcaps.html">http://ncam.wgbh.org/mm/m4vcaps.html</a>';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '1.0';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'scc';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/(Scenarist_SCC V1.0)/';\r
+               \r
+               return $idPattern;\r
+       }\r
+\r
+       public function allowsTextStyles()\r
+       {\r
+               return '0';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '\r
+Scenarist_SCC V1.0\r
+\r
+00:00:00:00 942c 942c\r
+\r
+00:00:00:-21 94ae 94ae 9420 9420 10d0 10d0 a8c4 d629 2020 57e5 ece3 ef6d e520 f4ef 2061 2080 13d0 13d0 64e5 6def 6e73 f4f2 61f4 e9ef 6e20 efe6 2061 e3e3 e573 73e9 62ec e520 1370 1370 76e9 64e5 efae 2054 e5f8 f420 bc62 3e62 efec 6420 54e5 f8f4 2020 942f 942f\r
+\r
+00:00:02:00 94ae 94ae 9420 9420 10d0 10d0 a8c4 d629 2020 5468 e973 20e9 7320 6120 e3ef 6d6d e5f2 e3e9 61ec 2080 13d0 13d0 e6ef f220 c7f2 6170 e56e 75f4 7320 e3e5 f2e5 61ec 2c20 942f 942f\r
+\r
+00:00:04:03 94ae 94ae 9420 9420 10d0 10d0 a8c4 d629 2020 f7e9 f468 2061 6464 e564 20e3 ecef 73e5 6420 13d0 13d0 e361 70f4 e9ef 6e73 2020 942f 942f\r
+\r
+00:00:05:06 94ae 94ae 9420 9420 10d0 10d0 a8c4 d629 2020 616e 6420 64e5 73e3 f2e9 70f4 e976 e520 76e9 64e5 ef2c 2020 13d0 13d0 2075 73e9 6e67 2073 70e5 e5e3 6820 7379 6ef4 68e5 73e9 7320 1370 1370 f4e5 e368 6eef ecef 6779 ae20 942f 942f\r
+\r
+00:00:08:03 94ae 94ae 9420 9420 10d0 10d0 a8c4 d629 2020 c4e5 7075 f479 20c2 61f2 6ee5 7920 46e9 e6e5 2080 13d0 13d0 e56e f4e5 f273 2020 20f4 68e5 20cd 6179 62e5 f2f2 7920 1370 1370 d368 e5f2 e9e6 e6a7 7320 4fe6 e6e9 e3e5 2c20 942f 942f\r
+\r
+00:00:11:02 94ae 94ae 9420 9420 10d0 10d0 a8c4 d629 2020 f7e9 f468 2061 20f4 f261 7920 e3ef 6ef4 61e9 6ee9 6e67 2020 13d0 13d0 f468 e520 c7f2 6170 e56e 75f4 7320 62f2 e561 6be6 6173 f4ae 2080 942f 942f\r
+\r
+00:00:12:28 94ae 94ae 9420 9420 10d0 10d0 a8c4 d629 2020 d368 e5f2 e9e6 e620 c16e 6479 2054 6179 ecef f220 e973 2080 13d0 13d0 ece5 616e e96e 6720 20ef 6e20 f468 e520 e6f2 ef6e f420 efe6 2068 e973 2080 1370 1370 64e5 736b 2c20 942f 942f\r
+\r
+00:00:15:21 94ae 94ae 9420 9420 10d0 10d0 a8c4 d629 2020 f2e5 6164 e96e 6720 f468 e520 6ee5 f773 7061 70e5 f2ae 2080 942f 942f\r
+\r
+';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+\r
+       \r
+} // end Scc Class\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_SubRipSrt_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_SubRipSrt_format.php
new file mode 100755 (executable)
index 0000000..4ff92f0
--- /dev/null
@@ -0,0 +1,204 @@
+<?php\r
+/**\r
+ * SubRipSrt Class\r
+ */\r
+class SubRipSrt extends CaptionFormat\r
+{\r
+       private $textStyles = array();\r
+\r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString) \r
+       {\r
+               $ccImport = '';\r
+\r
+        // clean malformed patterns creted when saving files on win notepad\r
+        $toSearch = array(chr(13).chr(10));\r
+        $toReplace = array(chr(10));\r
+        $theCCString = str_replace($toSearch,$toReplace,$theCCString);\r
+                \r
+        // split each caption by \n\n\r
+        $allCaptions=split(chr(10).chr(10),$theCCString);\r
+                \r
+        // create a collection object\r
+        $myCollection = new CaptionCollection();\r
+        \r
+        $txtStyles = Array();\r
+        \r
+        $counter=0;\r
+        \r
+        foreach($allCaptions as $singleCaption)\r
+        {\r
+               \r
+               //echo '<br/>'.chr(10).''.$counter;\r
+               \r
+               // split each line of the single caption\r
+               $captionParts=split(chr(10),$singleCaption);\r
+               \r
+               // add captions if minimal time and caption are set\r
+               if (isset($captionParts[1]) && isset($captionParts[2]))\r
+               {\r
+                       $counter++;\r
+                       $timeMark = '';\r
+                       $captionLines = '';\r
+                       \r
+                       // fix milisecond separator "," by "."\r
+                       $captionParts[1] = str_replace(',','.',$captionParts[1]);       \r
+                       \r
+                       // get time marks on line 2\r
+                       $timeMark = split('-->',$captionParts[1]);\r
+       \r
+                       // get time in and out\r
+                       $timeIn = trim($timeMark[0]);\r
+                       $timeOut = trim($timeMark[1]);\r
+                       \r
+                               $captionLines = $captionParts[2]; // add caption line 1\r
+                               \r
+                       // if caption has two lines\r
+                       if (count($captionParts)==4)\r
+                       {       \r
+                               $captionLines .= ''.chr(10).$captionParts[3]; // add a new line + caption line 2\r
+                       }\r
+                       \r
+                       // Create a caption Object\r
+                       $theNewCaption = new Caption($timeIn,$timeOut,$captionLines,$txtStyles);\r
+                       \r
+                               // add caption to CaptionCollection\r
+                               $myCollection->addCaption($theNewCaption); \r
+       \r
+                       \r
+                       //echo ''.chr(10).'IN: '.$timeIn.'****'.' OUT:'.$timeOut;\r
+                       //echo ''.chr(10).''.$captionLines;\r
+               }\r
+               \r
+        } // end foreach\r
+       \r
+           return $myCollection;\r
+                \r
+       } // end importCC()\r
+\r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+       \r
+               $myCollection = $theCollection->getCollection();\r
+  \r
+               // fix time Srt Time Format\r
+               $toSearch = array('.');\r
+        $toReplace = array(',');\r
+        \r
+               $srtCounter = 0;\r
+               \r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       \r
+                       $srtCounter++;\r
+                       \r
+                       // fix QT time to SRT format, replace "." by ","\r
+                       $srtInTime = $captionObj->getInTime();\r
+                       $srtInTime  = str_replace($toSearch,$toReplace,$srtInTime);\r
+                       \r
+                       $srtOutTime = $captionObj->getOutTime();\r
+                       $srtOutTime  = str_replace($toSearch,$toReplace,$srtOutTime);\r
+                       \r
+                       $srtCaption = $captionObj->getCaption();\r
+                       $srtCaption = str_replace('<BR/>',chr(10),$srtCaption);\r
+                       $srtCaption = str_replace('<br/>',chr(10),$srtCaption);\r
+                        \r
+                       $ccExport .= "$srtCounter\n".$srtInTime." --> ".$srtOutTime."\n".$srtCaption."\n\n";\r
+                       \r
+               } // end foreach\r
+               \r
+               // Fix if there are more than the two empty line separator (standard)\r
+               $ccExport = str_replace(chr(10).chr(10).chr(10),chr(10).chr(10),$ccExport);\r
+               \r
+               return $ccExport;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a QText caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               $isValid = false;\r
+               $patternCheck = "/({(QTtext)})/"; // RegExp to look for QText \r
+               preg_match_all($patternCheck,$theCCString,$patternFound);\r
+               \r
+               if(count($patternFound)>0)\r
+               {\r
+                       $isValid = true;\r
+               }\r
+\r
+               return $isValid;\r
+               \r
+       } // end  checkFormat() \r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'SubRip - Srt';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return '???';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '???';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'srt';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/([0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3}) (-->) ([0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3})/';\r
+               //$idPattern = '/([0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3})/';\r
+               //$idPattern = '';\r
+               //$idPattern .= '/'; // start pattern\r
+               \r
+               //$idPattern .= '([0-9]{2}\n)'; \r
+                \r
+               //$idPattern .= '/'; // end pattern\r
+\r
+               return $idPattern;\r
+       }\r
+       \r
+       public function allowsTextStyles()\r
+       {\r
+               return '0';\r
+       }       \r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '\r
+1\r
+00:00:42,360 --> 00:00:48,360\r
+With this device we can\r
+give anything an attitude.\r
+\r
+2\r
+';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+}  // end SubRipSrt \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_SubViewer_format.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/cc_SubViewer_format.php
new file mode 100755 (executable)
index 0000000..56f38ea
--- /dev/null
@@ -0,0 +1,117 @@
+<?php\r
+/**\r
+ * SubViewer Class\r
+ */\r
+class SubViewer extends CaptionFormat\r
+{\r
+       /**\r
+        * Imports a caption string into a CaptionCollection \r
+        *\r
+        * @param String $theCCString the caption file as string\r
+        * @return CaptionCollection $myCcCollection A CaptionCollection Object\r
+        */\r
+       public function importCC($theCCString)\r
+       {\r
+               \r
+       } // end importCC()\r
+       \r
+       /**\r
+        * Exports a CaptionCollection object into a string\r
+        *\r
+        * @param CaptionCollection $theCollection A CaptionCollection Object\r
+        * @return String $captionString The caption as a String\r
+        */\r
+       public function exportCC($theCollection)\r
+       {\r
+               \r
+               $ccExport = '';\r
+               \r
+               $myCollection = $theCollection->getCollection();\r
+\r
+               foreach ($myCollection as $captionObj)\r
+               {\r
+                       // add in time\r
+                       $ccExport.= chr(10).$captionObj->getInTime();\r
+                       \r
+                       $ccExport.= ',';\r
+                       \r
+                       // add out time\r
+                       $ccExport.= $captionObj->getOutTime();\r
+                       \r
+                       // fix caption to subViewer v. 1\r
+                       $fixCaption = str_replace(chr(10),'',$captionObj->getCaption());\r
+                       $fixCaption = str_replace('<BR/>','',$fixCaption);\r
+                       \r
+                       // add caption\r
+                       $ccExport.= chr(10).$fixCaption.chr(10);\r
+\r
+               } // end foreach\r
+               \r
+               return $ccExport;\r
+               \r
+       } // end  exportCC()\r
+       \r
+       /**\r
+        * Verify if the caption file is a srt caption file \r
+       */\r
+       public function checkFormat($theCCString)\r
+       {\r
+               \r
+       } // end checkFormat()\r
+\r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return 'SubViewer - Sub';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return '????';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '???';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return 'sub';\r
+       }\r
+       \r
+       public function getIdPattern()\r
+       {\r
+               $idPattern = '/([0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{2})(,)([0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{2})/';\r
+\r
+               return $idPattern;\r
+       }\r
+       \r
+       public function allowsTextStyles()\r
+       {\r
+               return '0';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '\r
+00:04:35.03,00:04:38.82\r
+Hello guys... please seat down...\r
+\r
+00:05:00.19,00:05:03.47\r
+M. Franklin,[br]are you crazy?\r
+\r
+????\r
+[00:00:00]\r
+caption 1 - using Bold style?\r
+[00:00:02]\r
+\r
+';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+       \r
+} // end SubViewer Class\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/index.html b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/ccformats/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CaptionCollection_class.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CaptionCollection_class.php
new file mode 100755 (executable)
index 0000000..1fa47fb
--- /dev/null
@@ -0,0 +1,120 @@
+<?php\r
+\r
+/**\r
+ * This class represents a collection of captions \r
+ * 1. Create an instance\r
+ * 2. load captions\r
+ */\r
+class CaptionCollection\r
+{\r
+       public $collectionName = ''; // The name that wraps the collection. \r
+       public $txtStylesGlobal = array(); // Holds any global text style. (e.g. $txtStylesGlobal['text-align'] = 'center', $txtStylesGlobal['text-font'] = 'Arial', $txtStylesGlobal['text-size'] = '14', etc...)\r
+       public $captionCollection = array(); // The collection of Caption objects\r
+       \r
+       /**\r
+       * Class Constructor \r
+       */\r
+       public function __construct()\r
+       {\r
+               /*\r
+                * empty for now... (we don't know what the caption will contain...)\r
+                * It seems logical and much more practical \r
+                * to create first an empty CaptionCollection  \r
+                * and then add to it as needed, \r
+                * finally, get the collection object\r
+                */\r
+       }\r
+       \r
+       /**\r
+        * Adds a Caption Object to the $captionCollection array \r
+        * @param Object $theCcObject a Caption Object\r
+        * @return void\r
+        */     \r
+       public function addCaption($theCcObject)\r
+       {\r
+               // add Caption to the Caption Collection \r
+               $this->captionCollection[] = $theCcObject; // this a php-based approach... java will need a push/count solution \r
+               \r
+       } // end addCaptions()\r
+\r
+       /**\r
+        * Sets all the Global text style attributes\r
+        * @param Array $theGlobalStyles Array containing all the global text styles  \r
+        */\r
+       public function setTxtStylesGlobal($theGlobalStyles)\r
+       {\r
+               $this->txtStylesGlobal = $theGlobalStyles;\r
+       }       \r
+       \r
+       /**\r
+        * Sets the value of a single Global text style attribute\r
+        * @param String $theAtt Attribute name\r
+        * @param String $theValue Attribute Value \r
+        */\r
+       public function setTxtStylesGlobalAtt($theAtt,$theValue)\r
+       {\r
+               $this->txtStylesGlobal[$theAtt]=$theValue;\r
+       } // end setTxtStylesGlobalAtt()\r
+       \r
+       /**\r
+        * Sets the collection Name\r
+        *\r
+        * @param String $theCollectionName\r
+        */\r
+       public function setCollectionName($theCollectionName)\r
+       {\r
+               $this->collectionName = $theCollectionName;\r
+       }\r
+       \r
+       /**\r
+        * Gets Collection Name\r
+        *\r
+        * @return String $collectionName\r
+        */\r
+       public function getCollectionName()\r
+       {\r
+               return $this->collectionName;\r
+       }\r
+       \r
+       /**\r
+        * Returns this CaptionCollection object\r
+        *\r
+        * @return CaptionCollection \r
+        */\r
+       public function getCollection()\r
+       {\r
+               return $this->captionCollection;\r
+       }  \r
+\r
+       public function toString()\r
+       {\r
+               $ccCount=0;\r
+               echo '<br/><h3>Collection Name: '.$this->getCollectionName().'</h3>';\r
+               echo 'Total Captions Found: '.count($this->captionCollection);\r
+\r
+               if (count($this->txtStylesGlobal)!=0)\r
+               {\r
+                       echo '<br/><br/><b>[Global]  Styles</b>';\r
+                       \r
+                       foreach ($this->txtStylesGlobal as $txtStyleName => $txtStyleValue)\r
+                       {\r
+                               echo '<br/> -----'.$txtStyleName.' = '.$txtStyleValue;\r
+                       }\r
+               } \r
+               \r
+               echo '<br/><br/><b>Printing Captions in the collection... </b>';\r
+               \r
+               foreach ($this->captionCollection as $captionObj)\r
+               {\r
+                       $ccCount++;\r
+\r
+                       // call Caption's toString();\r
+                       echo '<br/><br/>'.$ccCount;\r
+                       $captionObj->toString();\r
+\r
+               } // foreach end \r
+\r
+       } //toString() end\r
+\r
+} // end CaptionCollection Class  \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CaptionFormat_class.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CaptionFormat_class.php
new file mode 100755 (executable)
index 0000000..d903b9e
--- /dev/null
@@ -0,0 +1,69 @@
+<?php\r
+abstract class CaptionFormat\r
+{\r
+       \r
+       /**\r
+        * This is the importCC() abstract method. All caption formats MUST override this method.  \r
+        *\r
+        * @param String $theCCString A caption file as a string\r
+        */\r
+       abstract protected function importCC($theCCString);\r
+       \r
+       /**\r
+        * This is the exportCC() abstract method. All caption formats MUST override this method.\r
+        *\r
+        * @param unknown_type $theCollection\r
+        */\r
+       abstract protected function exportCC($theCollection);\r
+       //public function exportCC(&$theCollection)     { ; }\r
+       \r
+       /**\r
+        * This is the checkFormat() abstract method. All caption formats MUST override this method. and define\r
+        *\r
+        * @param unknown_type $theCCString\r
+        */\r
+       abstract protected function checkFormat($theCCString);\r
+       // new added must be redefine in subclass\r
+       \r
+       /*\r
+        * Here functions to re-define\r
+        */\r
+       public function getName()\r
+       {\r
+               return '';\r
+       }\r
+       \r
+       public function getAbout()\r
+       {\r
+               return '';\r
+       }\r
+       \r
+       public function getVersion()\r
+       {\r
+               return '';\r
+       }\r
+               \r
+       public function getFileExtension()\r
+       {\r
+               return '';\r
+       }\r
+\r
+       public function getIdPattern()\r
+       {\r
+               return '';\r
+       }\r
+       \r
+       public function allowsTextStyles()\r
+       {\r
+               return '';\r
+       }\r
+       \r
+       public function template()\r
+       {\r
+               $ccTemplate = '';\r
+               \r
+               return $ccTemplate;\r
+       }\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_Caption_class.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_Caption_class.php
new file mode 100755 (executable)
index 0000000..8ec7e59
--- /dev/null
@@ -0,0 +1,156 @@
+<?php\r
+/**\r
+ * This class represents a sinlge caption and all the allowed features (time, text styles, etc.) \r
+ */\r
+\r
+class Caption\r
+{\r
+       public $inTime;\r
+       public $outTime;\r
+       public $caption;\r
+       public $textStyles = array(); // \r
+       \r
+       /**\r
+        * Class Constructor: \r
+        * @param String $theInTime\r
+        * @param String $theOutTime\r
+        * @param String $theCaption\r
+        * @param Array $theTextStyles as a reference\r
+        * @return void\r
+        */\r
+       function __construct($theInTime, $theOutTime, $theCaption,$theTextStyles)\r
+       {\r
+               $this->inTime = $theInTime;\r
+               $this->outTime = $theOutTime;\r
+               $this->caption = $theCaption;\r
+               $this->textStyles= $theTextStyles;\r
+       } // __construct() end\r
+\r
+               // SET  Functions\r
+               \r
+       /**\r
+        * Sets value of caption IN time\r
+        * @param String $theInTime\r
+        * @return void         \r
+        */\r
+       public function setInTime($theInTime)\r
+       {\r
+               $this->inTime = $theInTime;\r
+       }\r
+       \r
+       /**\r
+        * Sets value of caption OUT time\r
+        * @param String $theOutTime\r
+        * @return void         \r
+        */\r
+       public function setOutTime($theOutTime)\r
+       {\r
+               $this->outTime = $theOutTime;\r
+       }       \r
+\r
+       /**\r
+        * Sets value of a caption (multiple lines allowed)\r
+        * @param String $theCaption\r
+        * @return void         \r
+        */\r
+       public function setCaption($theCaption)\r
+       {\r
+               $this->caption = $theCaption;\r
+       }       \r
+\r
+       /**\r
+        * Sets value of Caption text style attribute\r
+        * @param String $theAtt Attribute name\r
+        * @param String $theValue Attribute Value \r
+        */\r
+       public function setTextAtribute($theAtt,$theValue)\r
+       {\r
+               $this->textStyles[$theAtt]=$theValue;\r
+       }\r
+\r
+               // GET  Functions\r
+               \r
+       /**\r
+        * Gets value of Caption IN Time\r
+        * @return String inTime Caption        \r
+        */\r
+       public function getInTime()\r
+       {\r
+               return $this->inTime;\r
+       }\r
+       \r
+       /**\r
+        * Gets value of Caption OUT Time\r
+        * @return String outTime Caption       \r
+        */     \r
+       public function getOutTime()\r
+       {\r
+               return $this->outTime;\r
+       }\r
+       \r
+\r
+       /**\r
+        * Gets value of Caption text\r
+        * @return String inTime Caption text   \r
+        */\r
+       public function getCaption()\r
+       {\r
+               return $this->caption;\r
+       }\r
+               \r
+       /**\r
+        * Gets text style array\r
+        * @return Array $theTextStyles Txt Styles Array        \r
+        */     \r
+       public function getTextStyles()\r
+       {\r
+               return $this->textStyles;       \r
+       }\r
+\r
+\r
+       /**\r
+        * Gets value of Caption text style attribute\r
+        * @param String $theAtt Attribute name\r
+        * @return String $Value Attribute Value        \r
+        */     \r
+       public function getTextAtribute($theAtt)\r
+       {\r
+               return $this->textStyles[$theAtt];\r
+       }\r
+\r
+       /**\r
+        * Print all values of the Caption as a String\r
+        */     \r
+       public function toString()\r
+       {\r
+               echo "<br/><b>In Time: </b>". $this->getInTime()."";\r
+               echo "<br/><b>Out Time: </b>". $this->getOutTime()."";\r
+               echo "<br/><b>Caption: </b>". $this->getCaption()."";\r
+               \r
+               if (count($this->textStyles!=0))\r
+               {\r
+                       if (count($this->textStyles)==0)\r
+                       {\r
+                               //echo '<br/>----(NO text styles found)';\r
+                       } else {\r
+               \r
+                               echo '<br/><b>------[Caption] Styles: </b>';\r
+                               \r
+                               // Display all text attributes in the caption\r
+                               foreach ($this->textStyles as $styleName=>$styleValue)\r
+                               {\r
+                                       echo '<br/> -----'.$styleName.' = '.$styleValue;\r
+                               } // foreach end\r
+                       }// end if\r
+                       \r
+               } //if end\r
+               \r
+       }// toString() end \r
+       \r
+       // return this caption object\r
+       public function getThisCaption()\r
+       {\r
+               return $this;\r
+       }\r
+} // end class Caption\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CcService_class.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_CcService_class.php
new file mode 100755 (executable)
index 0000000..ccd8ba5
--- /dev/null
@@ -0,0 +1,57 @@
+<?php\r
+class CcService\r
+{      \r
+       // Unique Variables\r
+       private $ccResult; // $ccResult = 0 returns a caption string, $ccResult = 1 returns the caption URL\r
+       private $ccSourceURL; // The URL where the caption source file is located\r
+       \r
+       // variables to be passed to ConversionManager Class \r
+       private $ccStringTarget; // Caption Target file as String\r
+       private $ccSourceFileName; // File Name of the Source caption\r
+       private $ccTypeTarget; // Class name of the target caption format (e.g. 'Sami', or 'QTtext')\r
+       \r
+\r
+       public function __construct($theCcResult,$theCcSourceURL,$theCcTypeTarget,$theFileName)\r
+       {\r
+               // assign parameters to class members \r
+\r
+               $this->ccResult = $theCcResult;\r
+               $this->ccSourceURL = $theCcSourceURL;\r
+                               \r
+               $this->ccStringTarget = '';\r
+               $this->ccTypeTarget = $theCcTypeTarget;\r
+               $this->ccSourceFileName = $theFileName;\r
+                       \r
+               $this->_startService();\r
+       }\r
+       \r
+       private function _startService()\r
+       {\r
+               global $rosettaCCSettings;\r
+               \r
+               // download remote caption file\r
+               $myCCString = file_get_contents($this->ccSourceURL);\r
+               \r
+               $myCCString = stripslashes($myCCString);\r
+               \r
+                       // Start a convertion Manager Instance\r
+               $myCcManager = new ConversionManager($myCCString,$this->ccTypeTarget,$this->ccSourceFileName);\r
+               \r
+                       // get the Caption Target URL\r
+       $ccTargetUrl = $myCcManager->getCcTargetUrl();\r
+                       \r
+       if($this->ccResult==0)\r
+       {\r
+               // get the target file as a String\r
+               $ccTargetString = TxtFileTools::fileToString($ccTargetUrl); \r
+               echo $ccTargetString;\r
+       }\r
+       else if ($this->ccResult==1)\r
+       {\r
+               echo $rosettaCCSettings['uploadDir'].'/'.$ccTargetUrl;\r
+       }\r
+       \r
+\r
+       }\r
+}\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_ConversionManager_class.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_ConversionManager_class.php
new file mode 100755 (executable)
index 0000000..6c26954
--- /dev/null
@@ -0,0 +1,246 @@
+<?php\r
+/**\r
+ * Name: ConversionManager class\r
+ * Author: Antonio Gamba Bari - antonio.gambabari@utoronto.ca. ARTC, University of Toronto.\r
+ * Last Update: July 22, 2009\r
+ * \r
+ * Description: This class performs all the conversion functions\r
+ * 1. Start a conversion\r
+ * 2. Retrieve a caption file\r
+ * 3. Load all caption formats inc files\r
+ * 3. Autodetect caption format\r
+ * 4. Build a Collection of Captions\r
+ * 5. Call export method from the proper CaptionFormat sub-class \r
+ */\r
+\r
+class ConversionManager\r
+{\r
+       private $ccStringTarget; // Caption Target file as String\r
+       private $ccSourceFileName; // File Name of the Source caption \r
+       private $ccTargetExt; // File Extension of the caption file  \r
+       private $ccTypeSource; // Class name of the source caption format\r
+       private $ccTypeTarget; // Class name of the target caption format\r
+       private $ccFormats = Array(); // array containing all the class names of the supported caption formats\r
+       private $ccTargetUrl; // relative path to target caption file\r
+       public $ccImportedCollection; // The target CaptionCollection Object\r
+       \r
+       \r
+       /**\r
+        * Class Constructor: Receives a caption string, parameters and returns the target caption as string\r
+        *\r
+        * @param String $theCaption The Caption File as String\r
+        * @param String $theTarget The target Type = Class name of target sub-class\r
+        * @param String $theFileName The name of the source caption file \r
+        */\r
+       public function __construct($theCaption,$theTarget,$theFileName)\r
+       {\r
+               global $rosettaCCSettings;\r
+               /*\r
+                * start conversion \r
+                */\r
+               // assign parameters to class members \r
+               $this->ccTypeTarget = $theTarget;\r
+               $this->ccSourceFileName = $theFileName;\r
+               $this->ccTypeSource = ''; // initialize $ccTypeSource = ''\r
+               \r
+               // load caption formats \r
+               $this->ccFormats = CcUtilVital::ccFormatsLoad();\r
+\r
+               /*\r
+                * run detection function on imported caption string\r
+                * Note: the type of the source caption is not a parametter. This means that for stability \r
+                * purposes the conversion tool MUST identify the format. Otherwhise, many unexpected and \r
+                * incorrect conversions may occur   \r
+                */ \r
+               $this->ccTypeSource = $this->_ccAutoDetect($theCaption);                \r
+                       \r
+               // proceed only if caption format is detected  \r
+               if($this->ccTypeSource!='')\r
+               {\r
+                               //echo '<br/><br/> Caption format Detected: <b>'.$this->ccTypeSource.'</b>';\r
+\r
+                       /*\r
+                        * Invoques import function in caption format subclass\r
+                        * Note: here we know the name of the Caption format class from the $this->ccTypeSource (the value assigned by the autodetection function) \r
+                        */\r
+                       $ccSourceObj = new $this->ccTypeSource();\r
+                       \r
+                       // get a CaptionCollection Object \r
+                       $this->ccImportedCollection = $ccSourceObj->importCC($theCaption); \r
+                       \r
+                               //echo '<br/><br/>Uploaded Caption file was loaded into a CaptionCollection';\r
+                       \r
+                       // Initialize exported collection string\r
+                       $this->ccStringTarget = '';\r
+                       \r
+                       // run export function\r
+                       $this->ccStringTarget = $this->_ccExport();\r
+                       \r
+                       // print target format in a form for debuging purposes only\r
+                               //echo '<form><textarea name="textarea" cols="120" rows="10">'. $this->ccStringTarget . '</textarea></form>';\r
+                       \r
+                       //$this->_ccExport();\r
+                       \r
+                       // verify if the Target format has been provided \r
+                       if ($this->ccStringTarget!='')\r
+                       {\r
+                               // Save collection in DB as serialized string\r
+                                       //DbTools::collectionInBdSave($this->ccImportedCollection, $theFileName);\r
+                               \r
+                               // FINALLY !! if all goes right save exported caption into a file \r
+                               $theConvertedFile = $this->_saveExported();\r
+                               // display player test option\r
+                                       //PlayerTools::displayPlayerOp($theConvertedFile);\r
+                               \r
+                               // force downlaod: only when no comments or debuging mode \r
+                                               //TxtFileTools::downloadFile($theConvertedFile);\r
+                               \r
+                               // set the relative path of the target caption file\r
+                               $this->ccTargetUrl = $theConvertedFile;\r
+\r
+                       }\r
+\r
+                       \r
+               } else {\r
+                       echo 'The format of source Caption was not recognized.';\r
+               };\r
+               \r
+               // return $ccSourceFormat\r
+                               \r
+       }// end __construct() \r
+\r
+       public function getCcTargetUrl()\r
+       {\r
+               return $this->ccTargetUrl;              \r
+       }\r
+       \r
+       /**\r
+        * Gets the file name without extension of a file\r
+        *\r
+        * @param String $theFilename Name of the file\r
+        * @return String $targetFileName\r
+        */\r
+       private function _buildExportFileName()\r
+       {\r
+               $targetFileName = substr($this->ccSourceFileName, 0, -3);\r
+               return $targetFileName;\r
+       }\r
+       \r
+       private function _saveExported()\r
+       {\r
+                       //global $rosettaCCSettings;\r
+               // build the proper name to save converted caption\r
+               $theCCname = $this->_buildExportFileName().$this->ccTargetExt;\r
+               \r
+                       //$fullFileUrl = $rosettaCCSettings['uploadDir'].'/'.$theCCname;\r
+                \r
+               // save exported collection in a file \r
+               TxtFileTools::stringToFile($theCCname,$this->ccStringTarget);\r
+\r
+               // return the generated file name\r
+               return $theCCname;\r
+               \r
+               // download the generated caption file \r
+               //CcUtil::downloadFile($fullFileUrl);\r
+                                 \r
+       }\r
+\r
+       /**\r
+        * Gets a CaptionCollection object and return the target caption file as string\r
+        *\r
+        * @return unknown\r
+        */\r
+       private function _ccExport()\r
+       {\r
+               $ccTargetString = '';\r
+\r
+               //echo '<br/><br/>...creating an object of the target format: '.$this->ccTypeTarget;\r
+               //echo '<br/><br/>I AM a '.$ccObjExp->getName().' Object';\r
+\r
+               if ($this->ccTypeTarget!='0')\r
+               {\r
+                       // create an instance of the target Caption Format\r
+                       $ccObjExp = new $this->ccTypeTarget();\r
+                       \r
+                       // get the extension of the target Caption\r
+                       $this->ccTargetExt = $ccObjExp->getFileExtension();\r
+                       //echo '<br/>The extension of the Target Caption is: '. $this->ccTargetExt; \r
+                       \r
+                       // call export method in caption format instance\r
+                       $ccTargetString = $ccObjExp->exportCC($this->ccImportedCollection);\r
+\r
+               } // end if\r
+               \r
+               //echo '<br/>Target Collection: <br/>'.$ccTargetString;\r
+               return $ccTargetString;\r
+       } // end _ccExport()\r
+       \r
+       /**\r
+        * Import caption as a sting and return a Caption Collection\r
+        * @param String $theCaption Caption file as a String    \r
+        * @param String $theCcFormatClassName The class name of the caption source\r
+        * @return CaptionCollection $importedCollection Return a Caption Collection Object  \r
+        */\r
+       private function _ccImport($theCaption,$theCcFormatClassName)\r
+       {\r
+               // Create an instance of the source Caption Format\r
+               $myCcSourceObj = new $theCcFormatClassName();\r
+               \r
+               // import the caption into a CaptionCollection Object\r
+               return $myCcSourceObj->importCC($theCaption);\r
+               \r
+       } // _ccImport() end\r
+\r
+       /**\r
+        * Auto detect format of a caption string using the unique pattern provided by each caption format \r
+        * @param String $theCaption Caption file as a String    \r
+        * @return String $formatfound Return detected caption format or '' if not found  \r
+        */\r
+       private function _ccAutoDetect($theCaption)\r
+       {\r
+               //echo '<br/>Total Formats to Auto-detect: '.count($this->ccFormats);\r
+               \r
+               $formatfound = '';\r
+               \r
+               // instanciate each caption format sub-class and call getIdPattern() \r
+               foreach ($this->ccFormats as $ccId)\r
+               { \r
+                       // testing here a polymorphic behaviour \r
+                               //echo '<br/>.....Detecting format: '.$ccId;\r
+                       $theCcIdPattern = '';\r
+                       $ccObj = new $ccId(); // Create an instance of a caption format\r
+                       $theCcIdPattern = $ccObj->getIdPattern(); // get the pattern identifying the caption format\r
+                       //echo '<br/>***** '.$ccId.' = '.$theCcIdPattern;\r
+                       \r
+                       // look for the pattern in the caption string\r
+                       if (preg_match($theCcIdPattern,$theCaption)==1)\r
+                       {\r
+                                       //echo '<br/>!! Caption Format Dettected!! ***** '.$ccId.' = '.$theCcIdPattern; \r
+                                       //echo '<br/>Caption Format Dettected: <b>'.$ccId.'</b>';\r
+                               \r
+                               // set the detected format\r
+                               $formatfound = $ccId;\r
+                               \r
+                               return $formatfound;\r
+                               break; // stop detecting caption format\r
+                       }\r
+\r
+               } // foreach end\r
+\r
+               return $formatfound;\r
+               \r
+       } // _ccAutoDetect() end\r
+       \r
+       public function getCaptionFormats()\r
+       {\r
+               return $this->ccFormats;\r
+       }\r
+       \r
+       public function getImportedCollection()\r
+       {\r
+               return $this->ccImportedCollection;\r
+       }\r
+\r
+       \r
+} // class end \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTag.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTag.php
new file mode 100755 (executable)
index 0000000..2068a39
--- /dev/null
@@ -0,0 +1,162 @@
+<?php\r
+// \r
+/**\r
+ * XML Parser: this class defines an XML Tag   \r
+ */\r
+\r
+class XmlTag\r
+{\r
+       private $tagName;\r
+       private $tagType;\r
+       private $tagLevel;\r
+       private $tagValue;\r
+       private $tagAttrib = array();\r
+\r
+       // working on...\r
+       private $tagState; // True or false ; \r
+       //private $tagState; // 1=complete, 2=open, 3=cdata, 4=close\r
+       \r
+       /**\r
+        * Constructor: creates a XML tag object\r
+        *\r
+        * @param String $theTagName\r
+        * @param String $theTagType\r
+        * @param String $theTagLevel\r
+        * @param String $theTagValue\r
+        * @param Array $theTagAtrib\r
+        */\r
+       function __construct($theTagName,$theTagType,$theTagLevel,$theTagValue,$theTagAtrib)\r
+\r
+       // Constructor without attributes\r
+       //function __construct($theTagName,$theTagType,$theTagLevel,$theTagValue)\r
+       {\r
+               $this->tagName = $theTagName;\r
+               $this->tagType = $theTagType;\r
+               $this->tagLevel = $theTagLevel;\r
+               $this->tagValue = $theTagValue;\r
+               $this->tagAttrib = $theTagAtrib;\r
+               \r
+       } // __construct() end\r
+               \r
+       public function getTagValue()\r
+       {\r
+               return $this->tagValue;         \r
+       }\r
+       \r
+       public function getTagAttribute($attribName)\r
+       {\r
+               if (isset($this->tagAttrib[$attribName]))\r
+               {\r
+                       return $this->tagAttrib[$attribName];\r
+               } else {\r
+                       return '';\r
+               }\r
+\r
+       }\r
+        \r
+       /**\r
+        * Adds a value to the xml tagValue\r
+        *\r
+        * @param String $theTagValueAdded The value to be added\r
+        */\r
+       public function addToTagValue($theTagValueAdded)\r
+       {\r
+               $this->tagValue .= $theTagValueAdded;\r
+       }\r
+\r
+       /**\r
+        * Adds a child xml tag as a value to other parent tag value. \r
+        * \r
+        * @param String $theTagAdded The tag yo be \r
+        * @param String $theTagState\r
+        */\r
+       public function addChildTagAsValue($theTagAdded,$theTagState,$theTagValue)\r
+       {\r
+               \r
+               // add <BR> Tag\r
+               if (($theTagAdded=='BR') && ($theTagState=='complete'))\r
+               {\r
+                       $this->tagValue .= '<BR/>'.$theTagValue;\r
+               }\r
+               \r
+               // open and close Bold tag \r
+               if (($theTagAdded=='B') && ($theTagState=='complete'))\r
+               {\r
+                       $this->tagValue .= '<b>'.$theTagValue.'</b>';\r
+               }\r
+\r
+               // open and close Italics tag \r
+               if (($theTagAdded=='I') && ($theTagState=='complete'))\r
+               {\r
+                       $this->tagValue .= '<i>'.$theTagValue.'</i>';\r
+               }\r
+\r
+               if (($theTagAdded=='U') && ($theTagState=='complete'))\r
+               {\r
+                       $this->tagValue .= '<u>'.$theTagValue.'</u>';\r
+               }\r
+               \r
+       } // end addChildTagAsValue\r
+\r
+\r
+       /**\r
+        * Adds an attribute and value to the XML tag   \r
+        *\r
+        * @param String $attName\r
+        * @param String $attValue\r
+        */\r
+       public function addAttribute($attName,$attValue)\r
+       {\r
+               $this->tagAttrib[$attName] = $attValue;\r
+               \r
+       } // end addAttribute()\r
+       \r
+       /**\r
+        * Set the state of the XML tag\r
+        *\r
+        * @param Boolean $theState True or False\r
+        */\r
+       public function setTagState($theState)\r
+       {\r
+               $this->tagState = $theState;\r
+               \r
+       } // end setTagState()\r
+\r
+       /**\r
+        * Print all values of the XML tag as a String\r
+        */     \r
+       public function toString()\r
+       {\r
+               // check if the tag is ready to show\r
+               if ($this->tagState==true)\r
+               {\r
+                       echo "<br><br><b>Tag Name: </b>". $this->tagName;\r
+                       echo "<br><b>Tag Type: </b>". $this->tagType;\r
+                       echo "<br><b>Tag Level: </b>". $this->tagLevel;\r
+                       echo "<br><b>Tag Value: </b>". $this->tagValue;\r
+                       \r
+                       // print data if the tag has attributes\r
+                       if (count($this->tagAttrib!=0))\r
+                       {\r
+                               echo '<br/><b>Tag Attributes: </b>';\r
+                               \r
+                               // Display all tag attributes; name and value\r
+                               foreach ($this->tagAttrib as $attribName => $attribValue)\r
+                               {\r
+                                       echo '<br/>------'.$attribName.' = '.$attribValue;\r
+                               } // foreach end\r
+                       \r
+                       } else {\r
+                               echo '<br/>NO Attributes found.';\r
+                       } //end if attributes\r
+                       \r
+               // end if is tag is ready\r
+               } else {\r
+                       echo '<br/><br/> --- ops!! The XML tag is not ready .... Showing NO data';\r
+               } // end if XML tag is ready\r
+               \r
+       }// toString() end\r
+       \r
+       \r
+} // end class XmlParse\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagCollection.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagCollection.php
new file mode 100755 (executable)
index 0000000..7e1da63
--- /dev/null
@@ -0,0 +1,38 @@
+<?php\r
+// \r
+/**\r
+ * What is like to be an XML Tag?   \r
+ */\r
+\r
+class XmlTagCollection\r
+{\r
+       private $xmlTagCollection = array(); // a collection of XML tag objects\r
+       \r
+       public function addXmlTagObject($theXmlTagObject)\r
+       {\r
+               $this->xmlTagCollection[] = $theXmlTagObject;\r
+       }\r
+       \r
+       public function getXmlTagCollection()\r
+       {\r
+               //echo '<br><br>XmlTagCollection Class -> getXmlTagCollection()<br>Tot in XmlTagCollection: '.count($this->xmlTagCollection);\r
+               return $this->xmlTagCollection;\r
+       }\r
+       \r
+       /**\r
+        * Print all values of the XML tag object \r
+        */     \r
+       public function toString()\r
+       {\r
+               echo "<br><br>Total <b>".$this->xmlTagCollection."</b> Tags = ".count($this->xmlTagCollection)."";\r
+                       \r
+               // Display all tag attributes in the tag\r
+               foreach ($this->xmlTagCollection as $xmlTagObject)\r
+               {\r
+                       $xmlTagObject->toString();\r
+               } // foreach end\r
+               \r
+       }// toString() end \r
+       \r
+} // end class XmlTagCollection\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagTrace.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagTrace.php
new file mode 100755 (executable)
index 0000000..9f26605
--- /dev/null
@@ -0,0 +1,242 @@
+<?php\r
+// \r
+/**\r
+ * This class provides the functionality to trace an xml tag \r
+ */\r
+\r
+class XmlTagTrace\r
+{\r
+       private $tagToTrace; // the xml tag to be collected\r
+       private $tagToTraceLevel; // The level of the xml tag bo be collected/traced\r
+       private $xmlString; // Xml data as string\r
+       \r
+       private $xmlTag; // temporary object to store XML object while reading xml array\r
+       private $xmlTagState; // true or false if tracing tag is done\r
+       private $myXmlCollection; // collection of the traced xml tag\r
+       \r
+       /**\r
+        * Class Constructor: starts tracing a XML tag. It recieves a xml TagName and xml TagLevel\r
+        * @param String $theXmlString XML data as String\r
+        * @param String $theTagToTrace XML Tag to trace \r
+        * @param String $theTagToTraceLevel Level of the XML tag to trace\r
+        */\r
+       function __construct($theXmlString,$theTagToTrace,$theTagToTraceLevel)\r
+       {\r
+       \r
+               // set the XML data\r
+               //$this->xmlString = $theXmlString;\r
+               \r
+               // set the tag to trace and the starting level\r
+               $this->tagToTrace = $theTagToTrace;\r
+               $this->tagToTraceLevel = $theTagToTraceLevel;\r
+               \r
+               // create XML tag Collection\r
+               $this->myXmlCollection = new XmlTagCollection();\r
+               \r
+               // start tracing\r
+               $this->traceXmlTag($theXmlString);              \r
+       } // __construct() end\r
+\r
+       /**\r
+        * Returns the XML tag Collection\r
+        *\r
+        */\r
+       public function getCollection()\r
+       {\r
+               //get from here of from XmlTagCollection collection object???\r
+               return $this->myXmlCollection->getXmlTagCollection();\r
+               //return $this->myXmlCollection;\r
+               //echo '<br>From '\r
+               \r
+                       \r
+       }// end getCollection()\r
+       \r
+       /**\r
+        * Creates an XML parcer and Iterates through array\r
+        *\r
+        * @param unknown_type $theXmlString\r
+        */\r
+       private function traceXmlTag($theXmlString)\r
+       {\r
+               // create XML parser\r
+               $p = xml_parser_create();\r
+               \r
+               // parse XML data into array\r
+               xml_parse_into_struct($p, $theXmlString, $xmlVals, $xmlIndex);\r
+               \r
+               // free XML parser \r
+               xml_parser_free($p);\r
+               \r
+               // initialize XML object ????\r
+               //$myXmlTag = new XmlTag()\r
+\r
+               \r
+               // start looping xml array\r
+               for($i = 0; $i < count($xmlVals); $i++) \r
+               {\r
+                       // initialize XML data\r
+                       $theTagName='';\r
+                       $theTagType='';\r
+                       $theTagLevel='';\r
+                       $theTagValue='';\r
+                       $theTagAtrib = Array();\r
+                       \r
+                       // verify data before adding\r
+                       if (isset($xmlVals[$i]['tag']))\r
+                       {\r
+                               $theTagName = $xmlVals[$i]['tag'];\r
+                       }\r
+                       \r
+                       if (isset($xmlVals[$i]['type']))\r
+                       {\r
+                               $theTagType = $xmlVals[$i]['type'];\r
+                       }\r
+                       \r
+                       if (isset($xmlVals[$i]['level']))\r
+                       {\r
+                               $theTagLevel = $xmlVals[$i]['level'];\r
+                       }\r
+                       \r
+                       if (isset($xmlVals[$i]['value']))\r
+                       {\r
+                               $theTagValue = $xmlVals[$i]['value'];\r
+                       }\r
+\r
+                       if (isset($xmlVals[$i]['attributes']))\r
+                       {\r
+                               $theTagAtrib = $xmlVals[$i]['attributes'];\r
+                       }                       \r
+                       \r
+                       // set xml data\r
+                       $this->setXmlData($theTagName,$theTagType,$theTagLevel,$theTagValue,$theTagAtrib);\r
+                       \r
+               \r
+               } // end for loop xml array\r
+               \r
+       } // end traceXmlTag()\r
+       \r
+       /**\r
+        * Recieves Xml data from each tag and determines if values should be collected \r
+        * this to trace <P> and <div> tags  \r
+        *\r
+        * @param String $theTagName\r
+        * @param String $theTagType\r
+        * @param String $theTagLevel\r
+        * @param String $theTagValue\r
+        * @param String $theTagAtrib\r
+        */\r
+       private function setXmlData($theTagName,$theTagType,$theTagLevel,$theTagValue,$theTagAtrib)\r
+       {\r
+               \r
+               //echo '<br/>'.$this->tagToTrace;\r
+               \r
+               // verify also if the level is lower !!!!\r
+               \r
+               //echo '<br/>'.$theTagName;\r
+               // verify if this data is from the xml tag being traced/collected\r
+               if ($theTagName == $this->tagToTrace)\r
+               {\r
+                       \r
+                       //echo '<br/>'.$theTagName.' TAG IS THE SAME';\r
+                       //echo '<br/>Value: '.$theTagValue.'';\r
+                       \r
+                       \r
+                       // if tag is complete. The tag has NO children\r
+                       if ($theTagType=='complete')\r
+                       {\r
+                               // create a XmlTag object\r
+                               $this->xmlTag = new XmlTag($theTagName,$theTagType,$theTagLevel,$theTagValue,$theTagAtrib);\r
+                               \r
+                               // tracing this tag is done.  \r
+                               $this->xmlTagState = true;\r
+                               \r
+                               $this->xmlTag->setTagState(true);\r
+                               \r
+                               //echo '<br/>'.$theTagName.' TAG is complete !!!';\r
+                               \r
+                               //$this->xmlTag->toString();\r
+                               \r
+                               // add to collection\r
+                               $this->myXmlCollection->addXmlTagObject($this->xmlTag);\r
+                               \r
+                               // reset temp object\r
+                               $this->xmlTag = null;\r
+\r
+                       } // end if complete\r
+\r
+                       // if tag is open. tag do have children\r
+                       else if ($theTagType=='open')\r
+                       {\r
+                               // create a new XmlTag object\r
+                               $this->xmlTag = new XmlTag($theTagName,$theTagType,$theTagLevel,$theTagValue,$theTagAtrib);\r
+                               \r
+                               // tracing this tag is NOT done.  \r
+                               $this->xmlTagState = false;\r
+                               \r
+                               //echo '<br/>'.$theTagName.' TAG is Open !!!';\r
+                               \r
+                       } // end if\r
+\r
+                       // if tag cdata. Getting data of the traced Tag, after any children data\r
+                       else if ($theTagType=='cdata')\r
+                       {\r
+                               // add value to traced tag \r
+                               // OJO !! This skips any child value \r
+                               $this->xmlTag->addToTagValue($theTagValue);\r
+                               \r
+                               // tracing this tag is NOT done.  \r
+                               $this->xmlTagState = false;\r
+                               //echo '<br/>'.$theTagName.' TAG is cdata!!!';\r
+                               \r
+                               \r
+                       } // end if\r
+\r
+                       // if tag close. Getting data of the traced Tag is done\r
+                       else if ($theTagType=='close')\r
+                       {\r
+                               // add value of traced tag \r
+                               $this->xmlTag->addToTagValue($theTagValue);\r
+                               \r
+                               // tracing this tag is NOT done.  \r
+                               $this->xmlTagState = true;\r
+                               \r
+                               $this->xmlTag->setTagState(true);\r
+                               //echo '<br/>'.$theTagName.' TAG is close!!!';\r
+                               \r
+                               //add to collection\r
+                               $this->myXmlCollection->addXmlTagObject($this->xmlTag);\r
+                               \r
+                               // reset temp object\r
+                               $this->xmlTag = null;\r
+                               \r
+                       } // end if\r
+                       \r
+                       \r
+               }// end if tracing xml tag\r
+\r
+               /*\r
+                * if the tag is a children. the tagToTraceLevel is lower than the current TagLevel \r
+                * this for all tags like <br/>, <b>, <i>, <u>, or even for <span> inside our traced tag\r
+                */\r
+               if ($this->tagToTraceLevel<$theTagLevel && (isset($this->xmlTag)))\r
+               {\r
+                       // adding children data to tag as value \r
+                       $this->xmlTag->addChildTagAsValue($theTagName,$theTagType,$theTagValue);\r
+                       \r
+               } // end if\r
+               \r
+               \r
+       } // end setXmlData()\r
+       \r
+       /**\r
+        * Print all values of the XML tag as a String\r
+        */     \r
+       public function toString()\r
+       {\r
+               $this->myXmlCollection->toString();\r
+\r
+               \r
+       }// toString() end \r
+       \r
+} // end class XmlTagTrace\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagTraceManager.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/core_XmlTagTraceManager.php
new file mode 100755 (executable)
index 0000000..d495716
--- /dev/null
@@ -0,0 +1,174 @@
+<?php\r
+\r
+\r
+class XmlManager\r
+{\r
+       private $xmlDataString; // the xml data as string\r
+       private $captionCollection; // the Caption Collection\r
+       //\r
+\r
+       function __construct($theXmlString)\r
+       {\r
+               $this->xmlDataString = $theXmlString;\r
+               \r
+               // create a caption Collection \r
+               $myCaptionCollcton = new CaptionCollection();\r
+               $this->captionCollection = $myCaptionCollcton;\r
+               \r
+               // start loopXmlData\r
+               $this->loopXmlData();\r
+               \r
+       } // end constructor  \r
+\r
+       /**\r
+        * Parses an XML string into an myltidimentional array\r
+        *\r
+        * @param String $theXmlString The xml file as string\r
+        * @return Array $xmlInArray \r
+        */\r
+       public function loopXmlData()\r
+       {\r
+               // create XML parser\r
+               $p = xml_parser_create();\r
+               \r
+               //xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);\r
+\r
+               xml_parse_into_struct($p, $this->xmlDataString, $vals, $index);\r
+               \r
+               // free parser \r
+               xml_parser_free($p);\r
+               \r
+               \r
+               // create a Xmlparse Object tracing for <P> tags at level 4 (this the case of DFXP files) \r
+               $myXmlParse = new XmlParse('P','4');\r
+               \r
+               \r
+               // start looping xml array\r
+               for ($i = 0; $i < count($vals); $i++) \r
+               {\r
+                       $myXmlParse->setXmlData();\r
+                       \r
+                       \r
+                       // *************************************** GET CAPTION DATA ---- START\r
+                       \r
+                       // if P tag is complete \r
+                       if($ccBuild == 3) \r
+                       {\r
+                               // get caption value\r
+                               $ccText = $vals[$i]['value'];\r
+                               \r
+                               // get attributes array \r
+                               $capAttrib = $vals[$i]['attributes'];\r
+                               \r
+                               // get time in and out of the caption\r
+                               $ccTimeIn = $capAttrib['BEGIN'];\r
+                               $ccTimeOut = $capAttrib['END'];\r
+                               \r
+                               $newCaptionDone = 1;\r
+\r
+                               $newCaption = new Caption($ccTimeIn,$ccTimeOut,$ccText,$noStyles);\r
+                               //$new\r
+                               //$countCC++;\r
+                       \r
+                       }  else if($ccBuild == 1) {\r
+                               \r
+                               \r
+                                       \r
+                       // if there are other tags inside P\r
+                       } else if (($ccBuild == 2) && isset($vals[$i]['value'])) {\r
+                               \r
+                               // add other parts of the caption text\r
+                               $ccText .= $vals[$i]['value'];\r
+                       \r
+                       // if is the end of the caption\r
+                       } else if (($ccBuild == 4) && isset($vals[$i]['value'])) {\r
+                               \r
+                               // add other parts of the caption text if is set\r
+                                       $ccText .= $vals[$i]['value'];\r
+                       }\r
+                       \r
+                       \r
+                       // *************************************** GET CAPTION DATA ---- END\r
+                       \r
+                       // just print each tag info\r
+                       echo '<br/>Tag: '.$vals[$i]['tag'];\r
+                       echo '<br/>Type: '.$vals[$i]['type'];\r
+                       echo '<br/>Level: '.$vals[$i]['level'];\r
+\r
+                       if(isset($vals[$i]['attributes']))\r
+                       {\r
+                               foreach ($vals[$i]['attributes'] as $theAtt => $theVal)\r
+                               {\r
+                                       //echo '<br/>Attributes: '.$vals[$i]['attributes'];\r
+                                       echo '<br/>------ '.$theAtt.': '.$theVal;\r
+                               }\r
+                       }\r
+                       \r
+                       if(isset($vals[$i]['value']))\r
+                       {\r
+                               echo '<br/>Value: '.$vals[$i]['value'];\r
+                       }\r
+                       \r
+                       echo '<hr>';\r
+               } // end for \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               \r
+               /*\r
+               echo "Index array\n";\r
+               echo "Total in array Index: ".count($index)."\n";\r
+               print_r($index);\r
+               echo "\nVals array\n";\r
+               echo "Total in array vals: ".count($vals)."\n";\r
+               print_r($vals);\r
+               */\r
+               \r
+               \r
+               \r
+               /*\r
+               foreach($vals as $val)\r
+               {\r
+                       $totInArr = count($val);\r
+                       echo '<br/>tot in Val = '.$totInArr;\r
+                       //echo '<br/>Val = '.$val;\r
+                       foreach ($val as $theVal)\r
+                       {\r
+                               echo '<br/>the val = '.$theVal;\r
+                               \r
+                       }  // end for 2\r
+                       \r
+               } // end for 1\r
+               */\r
+               \r
+               \r
+               //return $vals;\r
+               \r
+       } // end loopXmlData()\r
+       \r
+       /**\r
+        * Print class Data\r
+        *\r
+        */\r
+       public function toString()\r
+       {\r
+               echo '<br/> xmlDataString: '.$this->xmlDataString;\r
+               echo '<br/> tagToTrace: '.$this->tagToTrace;\r
+               echo '<br/> tagToTraceLevel: '.$this->tagToTraceLevel;\r
+               \r
+       }\r
+} // end XmlManager class \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/index.html b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_CcUtilVital_class.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_CcUtilVital_class.php
new file mode 100755 (executable)
index 0000000..aeb19f5
--- /dev/null
@@ -0,0 +1,61 @@
+<?php\r
+class CcUtilVital\r
+{\r
+\r
+       /**\r
+        * Loads all Caption Formats and return an array with class names\r
+        * Essential !!\r
+        *\r
+        */\r
+       static public function ccFormatsLoad()\r
+       {\r
+               global $rosettaCCSettings; // load global vars\r
+               \r
+               $ccFormats = array(); // stores all caption formats allowed\r
+               \r
+               $dir = $rosettaCCSettings['ccformats'];\r
+               $ccFormatsString = '';\r
+               $ccFileNameFormatRegex = '/cc_(.*?)_format/'; // (e.g. "cc_(QTtext)_format.php")\r
+               $countCcFiles = 0;\r
+\r
+               // verify if the directory exists\r
+               if ($handle = opendir($dir)) \r
+               {\r
+                   // read all files in the dir and include Caption Format files\r
+                   while (false !== ($file = readdir($handle))) \r
+                   {\r
+                       if (!is_dir($file))\r
+                       {\r
+                               // build a string with all file names\r
+                               $ccFormatsString .= ''.$file.';';\r
+                               \r
+                               // include the caption format file\r
+                                       include_once($dir.'/'.$file);\r
+                               \r
+                               $countCcFiles++;\r
+                       }\r
+                       }\r
+               } \r
+                       // close dir handler \r
+                       closedir($handle);\r
+\r
+                       // get all Class names from the string using regex\r
+                       preg_match_all($ccFileNameFormatRegex, $ccFormatsString, $ccFormatsPat);\r
+                       \r
+                       // add Class names to $ccFormats global Array\r
+                       for ($j=0;$j<count($ccFormatsPat[1]);$j++)\r
+                       {\r
+                               $ccFormats[] = $ccFormatsPat[1][$j];\r
+                       }\r
+                       // sort $ccFormats array \r
+                       asort($ccFormats);\r
+                       \r
+                       return $ccFormats;\r
+                        \r
+       } // ccFormatsLoad() end\r
+\r
+       \r
+       \r
+       \r
+} // end class CcUtilEssential  \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_TimeUtil_class.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_TimeUtil_class.php
new file mode 100755 (executable)
index 0000000..27379b9
--- /dev/null
@@ -0,0 +1,186 @@
+<?php\r
+class TimeUtil \r
+{\r
+       \r
+       /**\r
+        * Converts milliseconds time mark into 00:00:00:000 format (QT native format)\r
+        *\r
+        * @param int $miliSecTime A time format in miliseconds (e.g. 26070) 1000 = 1 second\r
+        * @return String $qtTimeString A QT mark in 00:00:00:000 format\r
+        */\r
+       static public function timeSamiToQt($miliSecTime)\r
+       {\r
+               $qtTimeString = '';\r
+               //  milliseconds holder \r
+               $myMiliSecTime = $miliSecTime;\r
+               \r
+               // basic constant knowledge, values in milliseconds\r
+               $anHour = 3600000; // 60*60*1000\r
+               $aMin = 60000; // 60*1000\r
+               $aSec = 1000; // 1 * 1000\r
+               \r
+               // temp holders for to store equivalent  hh, mm, sec, milisec\r
+               $myHours = 0;\r
+               $myMins = 0;\r
+               $mySec = 0;\r
+                               //$myMsec = 0; /// not using it.!!! \r
+               \r
+        // initialize timeArray\r
+               $timeArray = array();\r
+               $timeArray['hour'] = '';\r
+               $timeArray['min'] = '';\r
+               $timeArray['sec'] = '';\r
+               $timeArray['msec'] = '';                \r
+               \r
+               // parsing millisecodns QT time format 00:00:00.000\r
+\r
+               // is time mark at least an hour?\r
+               if($miliSecTime>=$anHour)\r
+               {\r
+                       // get only the int value\r
+                       $myHours = intval($miliSecTime/$anHour);\r
+\r
+                       // set the tot milliseconds left after removing number of hour(s) \r
+                       $myMiliSecTime -= ($myHours*$anHour);\r
+\r
+                       // set the current hours add leading 0 if needed\r
+                       if ($myHours<10)\r
+                       {\r
+                               $timeArray['hour'] = '0'.$myHours;\r
+                       } else {\r
+                               $timeArray['hour'] = ''.$myHours; \r
+                       }\r
+               } else {\r
+                       $timeArray['hour'] = '00';\r
+               }\r
+               \r
+               // Is time mark at least a minute? or rather, how many minutes are left?\r
+               if($myMiliSecTime>=$aMin-1)\r
+               {\r
+                       // get only the int value\r
+                       $myMins = intval($myMiliSecTime/$aMin);\r
+                                               \r
+                       // set the milliseconds left after removing total of minute(s) \r
+                       $myMiliSecTime -= ($myMins*$aMin);\r
+                       \r
+                       // set the current minutes and add leading 0 if needed\r
+                       if ($myMins<10)\r
+                       {\r
+                               $timeArray['min'] = '0'.$myMins;\r
+                       } else {\r
+                               $timeArray['min'] = ''. $myMins;\r
+                       }\r
+               } else {\r
+                       $timeArray['min'] = '00';\r
+               }\r
+               \r
+               // does it have seconds, or rather, how many seconds are left\r
+               if($myMiliSecTime>=$aSec)\r
+               {\r
+                       // get only the int value\r
+                       $mySec = intval($myMiliSecTime/$aSec);\r
+\r
+                       // set the milliseconds left after removing total of seconds\r
+                       $myMiliSecTime -= ($mySec*$aSec);\r
+                        \r
+                       // set the current number of seconds in time array, and add leading 0 if needed\r
+                       if ($mySec<10)\r
+                       {\r
+                               $timeArray['sec'] = '0'.$mySec;\r
+                       } else {\r
+                               $timeArray['sec'] = ''.$mySec;\r
+                       }\r
+               } else {\r
+                       $timeArray['sec'] = '00';\r
+               }\r
+               \r
+               // here a fix for adding leading zeros to milliseconds (e.g. 1=001, 10=010)  \r
+               if($myMiliSecTime>0)\r
+               {\r
+                       $tempMilliSec = 0 + (0.001 * $myMiliSecTime);\r
+                       $tempMilliSecArray = explode('.',$tempMilliSec); // split using '.' as separator\r
+                       $myMiliSecTimeString = ''. $tempMilliSecArray[1]; // get only the decimal value as a string\r
+\r
+                       // add one zero after the sting value if $myMiliSecTimeString has 2 character\r
+                       if (strlen($myMiliSecTimeString)==2)\r
+                       {\r
+                               $myMiliSecTimeString .= '0';\r
+                       } \r
+                       // add two zeros after the sting value if $myMiliSecTimeString has 1 character\r
+                       else if (strlen($myMiliSecTimeString)==1)\r
+                       {\r
+                               $myMiliSecTimeString .= '00';\r
+                       }\r
+                       \r
+                       // set  millisecodns  \r
+                       $timeArray['msec'] = $myMiliSecTimeString;\r
+               } else {\r
+                       $timeArray['msec'] = '000'; // no milliseconds left\r
+               } \r
+\r
+               // concatenate values\r
+               $qtTimeString = ''.$timeArray['hour'].':'.$timeArray['min'].':'.$timeArray['sec'].'.'.$timeArray['msec'];\r
+               \r
+               return $qtTimeString;\r
+               \r
+       } // end samiToQtTime()\r
+\r
+       /**\r
+        * Converts QT time to miliseconds format (Accepted by SAMI 1.0 and other CCformats)\r
+        * @return int $samiTime Time in miliseconds format; 1000 = 1. sec\r
+        * @param String $qtTime QT time Format; (e.g. "00:01:10.280")\r
+        */\r
+       static public function timeQtToSami($qtTime)\r
+       {\r
+           // Known patterns: 1, 2, or 3 decimals for millisecond definition\r
+               $pattern_time_000 = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3})\]";\r
+       $pattern_time_00 = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{2})\]";\r
+       $pattern_time_0 = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{1})\]";\r
+       $pattern_selected = '';\r
+               \r
+       // If pattern is 3 digit\r
+       if(preg_match('/'.$pattern_time_000.'/',$qtTime))\r
+           {\r
+               $pattern_selected = $pattern_time_000;\r
+           }\r
+           // If pattern is 2 digit\r
+       if(preg_match('/'.$pattern_time_00.'/',$qtTime))\r
+           {\r
+               $pattern_selected = $pattern_time_00;\r
+           }\r
+           // If pattern is 1 digit\r
+       if(preg_match('/'.$pattern_time_0.'/',$qtTime))\r
+           {\r
+               $pattern_selected = $pattern_time_0;\r
+           }\r
+           \r
+           $t1 = 0; // hours (e.g. [01])\r
+           $t2 = 0; // minutes (e.g. [12])\r
+           $t3 = 0; // seconds (e.g. [01.123])\r
+           \r
+           $qtTimeParts = split(':',$qtTime); // split QT time mark into an array\r
+           \r
+           $t1 += $qtTimeParts[0]; // adding hours\r
+           $t2 += $qtTimeParts[1]; // adding minutes\r
+           $t3 += $qtTimeParts[2]; // adding seconds and miliseconds\r
+\r
+           // millisecond equivalents\r
+           $t1 *= 3600000; // 1 hour = 60*60*1000\r
+           $t2 *= 60000; // 1 minute = 60*1000\r
+           $t3 *= 1000; // 1 second = 1*1000 \r
+           \r
+           // get time in milliseconds\r
+           $samiTime = $t1 + $t2 + $t3;\r
+\r
+           return $samiTime;\r
+       \r
+       } // end timeQtToSami() \r
+\r
+       \r
+       \r
+       /********************************\r
+        * still working on more time functions \r
+        *********************************/     \r
+\r
+} // end TimeUtil\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_TxtFileTools_class.php b/mods/atutor_opencaps/opencaps/conversion_service/include/classes/static_TxtFileTools_class.php
new file mode 100755 (executable)
index 0000000..3f51d65
--- /dev/null
@@ -0,0 +1,107 @@
+<?php\r
+class TxtFileTools\r
+{\r
+\r
+\r
+       /**\r
+        * Saves a String into a file and return the file URL\r
+        *\r
+        * @param String $theFileName The file Name\r
+        * @param String $theString The value to save as a String\r
+        * @return String $fullFileUrl The full path of where file is saved  \r
+        */\r
+       static public function stringToFile($theFileName, $theString) \r
+       {\r
+               global $rosettaCCSettings;\r
+               \r
+               $fullFileUrl = $rosettaCCSettings['uploadDir'].'/'.$theFileName;\r
+               \r
+               // save file to disk \r
+               file_put_contents($fullFileUrl, $theString);\r
+               \r
+                       //echo '<br/><br/>Target Caption File saved in: <b>'.$theFileName.'</b> <a href="'.$fullFileUrl.'"> [Download Caption]</a>';\r
+               \r
+               return $fullFileUrl;\r
+               \r
+       } // stringToFile\r
+\r
+       /**\r
+        * Loads a Caption File and return it as String\r
+        * @param $theFileName The full URL of the file\r
+        * @return $ccString The caption file as String\r
+        */\r
+       static public function fileToString($theFileName) \r
+       {\r
+               global $rosettaCCSettings;\r
+               \r
+               $ccString = file_get_contents($rosettaCCSettings['uploadDir'].'/'.$theFileName);\r
+               \r
+               /*\r
+          clean malformed pattern for ANSI files:\r
+          This is harmless for any well formed caption.\r
+          fixing captions saved in win notepad\r
+        */\r
+        $toSearch = array(chr(13).chr(10));\r
+        $toReplace = array(chr(10));\r
+        $contents = str_replace($toSearch,$toReplace,$ccString);\r
+        \r
+        return $ccString;\r
+       }       \r
+\r
+       /**\r
+        * Forces a browser to download a file stored in the server \r
+        * @param $exfile The full URL of the file\r
+        */\r
+       static public function downloadFile($exfile) \r
+       {\r
+               // verify if the file exists\r
+               if (file_exists($exfile)) \r
+               {\r
+                       header('Content-Description: File Transfer');\r
+                       header('Content-Type: application/octet-stream');\r
+                       header('Content-Disposition: attachment; filename='.basename($exfile));\r
+                       header('Content-Transfer-Encoding: binary');\r
+                       header('Expires: 0');\r
+                       header('Cache-Control: must-revalidate, post-check=0, pre-check=0');\r
+                       header('Pragma: public');\r
+                       header('Content-Length: ' . filesize($exfile));\r
+                       //header("Content-type: $type"); ????????\r
+                       ob_clean();\r
+                       flush();\r
+                       readfile($exfile);\r
+                       exit;\r
+                       \r
+               } // end if\r
+               \r
+       } // end downloadFile() \r
+\r
+       /**\r
+        * Replaces all <br/> tags in a string with chr(10) characters\r
+        *\r
+        * @param String $theHtmlString The string containign <br> HTML tags \r
+        * @return unknown\r
+        */\r
+       static public function ccBrToNewLine($theHtmlString)\r
+       {\r
+               $a = array(chr(10));\r
+               $b = array('<br>','<BR>','<br/>','<BR/>' );\r
+               $stringWithBreakLines = str_replace($a, $b, $theHtmlString);\r
+               return $stringWithBreakLines;\r
+       }\r
+\r
+       /**\r
+        * Replaces the break line character "char(10)" by a specified character \r
+        *\r
+        * @param String $theCaption The caption containing char(10) characters as line separators \r
+        * @param char $theChar The String used to replace the break line character\r
+        * @return unknown\r
+        */static public function ccNewLineToBr($theCaption, $theChar)\r
+       {\r
+               $a = ''.chr(10);\r
+               $b = $theChar;\r
+               $newString = str_replace($a, $b, $theCaption);\r
+               return $newString;\r
+       }\r
+       \r
+} // end class TxtFileTools\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/config.inc.php b/mods/atutor_opencaps/opencaps/conversion_service/include/config.inc.php
new file mode 100755 (executable)
index 0000000..15f3ad8
--- /dev/null
@@ -0,0 +1,41 @@
+<?php\r
+/*////////////////////////////////////////////////////////\r
+        global vars: (these may be shared)\r
+//////////////////////////////////////////////////////*/\r
+\r
+define('MAX_FILE_SIZE',        '10485760'); //10M\r
+\r
+// store the Caption Formats available\r
+$ccFormats = Array();\r
+\r
+\r
+/*////////////////////////////////////////////////////////\r
+        global settings\r
+//////////////////////////////////////////////////////*/\r
+$rosettaCCSettings = Array();\r
+$rosettaCCSettings['fileMaxSize'] = 5000000;\r
+$rosettaCCSettings['uploadDir'] = 'imported';\r
+$rosettaCCSettings['ccformats'] = './include/classes/ccformats';\r
+\r
+// define server OS\r
+define('SERVER_OS','linux'); \r
+\r
+// Absolute URL\r
+define('ROSETTA_WEB_PATH','http://filoante.com/capscribe/service');\r
+\r
+// Root folder\r
+define('ROSETTA_ROOT_PATH','/capscribe/service'); // linux server\r
+\r
+// determine if the server has get_magic_quotes_gpc on \r
+if ( get_magic_quotes_gpc() == 1 ) \r
+{\r
+       $rosettaCCSettings['get_magic_quotes_gpc'] = 1;\r
+       //echo '<br/>get_magic_quotes_gpc = 1';\r
+} else {\r
+       $rosettaCCSettings['get_magic_quotes_gpc'] = 0;\r
+       //echo '<br/>get_magic_quotes_gpc != 1';\r
+}\r
+\r
+\r
+\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/include/index.html b/mods/atutor_opencaps/opencaps/conversion_service/include/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/conversion_service/index.php b/mods/atutor_opencaps/opencaps/conversion_service/index.php
new file mode 100755 (executable)
index 0000000..9860796
--- /dev/null
@@ -0,0 +1,71 @@
+<?php\r
+\r
+// Load configuration file\r
+include('include/config.inc.php');\r
+\r
+// Core classes\r
+include('include/classes/core_Caption_class.php');\r
+include('include/classes/core_CaptionCollection_class.php');\r
+include('include/classes/core_CaptionFormat_class.php');\r
+include('include/classes/core_ConversionManager_class.php');\r
+include('include/classes/core_CcService_class.php');\r
+\r
+// Vitals \r
+include('include/classes/static_CcUtilVital_class.php');\r
+include('include/classes/static_TimeUtil_class.php');\r
+include('include/classes/static_TxtFileTools_class.php');\r
+\r
+\r
+// get values from GET method\r
+\r
+if ( (isset($_GET['cc_url'])) && (isset($_GET['cc_target'])) && (isset($_GET['cc_result'])) && (isset($_GET['cc_name'])))\r
+{\r
+       //$myCcService = new CcService(0,'http://localhost/php/_myphp/__phpOO/RosettaCaption/imported/Abbott_Costello_captions.Jsrt','JSONcc','Caption_service_test.txt')\r
+$myCcService = new CcService($_GET['cc_result'],$_GET['cc_url'],$_GET['cc_target'],$_GET['cc_name']);  \r
+\r
+} else { \r
+\r
+$htmlForm = '\r
+<html>\r
+<head>\r
+<title>RosettaCCService</title>\r
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">\r
+</head>\r
+\r
+<body>\r
+<form name="form1" method="get" action="">\r
+  <strong>cc_url</strong> - CaptionUrl: \r
+  <input name="cc_url" type="text" id="cc_url" value="" size="40" />\r
+  <br>\r
+  <strong>cc_result - Type of Result: </strong> \r
+  <input name="cc_result" type="text" id="cc_result" value="0" size="3" maxlength="1" />\r
+  if 0 returns a caption string, if = 1 returns the URL where target caption is \r
+  found<br>\r
+  <strong>cc_target</strong> - Type of Target Caption: \r
+  <select name="cc_target" id="cc_target">\r
+    <option value="0">---</option>\r
+    <option value="DFXP">DFXP</option>\r
+    <option value="DvdStl">DvdStl</option>\r
+    <option value="JSONcc" selected>JSONcc</option>\r
+    <option value="MPlayer">MPlayer</option>\r
+    <option value="MicroDvd">MicroDvd</option>\r
+    <option value="QTSMIL">QTSMIL</option>\r
+    <option value="QTtext">QTtext</option>\r
+    <option value="RealText">RealText</option>\r
+    <option value="Sami">Sami</option>\r
+    <option value="Scc">Scc</option>\r
+    <option value="SubRipSrt">SubRipSrt</option>\r
+    <option value="SubViewer">SubViewer</option>\r
+  </select>\r
+  <br>\r
+  <strong>cc_name</strong> - Name of the Caption: \r
+  <input name="cc_name" type="text" id="cc_name" value="Name_of_the_caption.___" />\r
+  <br>\r
+  <input type="submit" name="Submit" value="Submit">\r
+</form>\r
+</body>\r
+</html>\r
+';\r
+echo $htmlForm;\r
+}\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/editor.php b/mods/atutor_opencaps/opencaps/editor.php
new file mode 100755 (executable)
index 0000000..0e8a9d9
--- /dev/null
@@ -0,0 +1,123 @@
+<?php \r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+define('INCLUDE_PATH', 'include/');\r
+require(INCLUDE_PATH.'vitals.inc.php');\r
+\r
+require(INCLUDE_PATH.'header.inc.php'); \r
+?>     \r
+\r
+<script language="javascript" type="text/javascript" src="js/editor.js"></script>                                      \r
+\r
+       <div id="movie_status"></div>                           \r
+       \r
+       <div id="movie-container">              \r
+               <object id="mymovie" width="340" height="<?php echo $this_proj->media_height; ?>" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0">\r
+               <param name="src" value="<?php echo $this_proj->media_loc; ?>" />\r
+               <param name="enablejavascript" value="true" />\r
+               <param name="postdomevents" value="true" />\r
+               <param name="controller" value="false" />\r
+               <param name="autoplay" value="false" />\r
+               <param name="scale" value="aspect" />\r
+               <embed src="<?php echo $this_proj->media_loc; ?>" width="340" height="<?php echo $this_proj->media_height; ?>" pluginspage="http://www.apple.com/quicktime/download/" enablejavascript="true" name="mymovie" id="mymovie_embed" postdomevents="true" controller="false" autoplay="false" scale="aspect" />\r
+               </object>               \r
+                               \r
+               <div id="movie-controls">\r
+                       <div style="text-align:center; margin-top:-3px;">\r
+                               <div id="current-time"></div> / <div id="duration"></div>\r
+                       </div>\r
+                       \r
+                       <div id='m_timeline'>\r
+                               <div id="m_handle"></div>       \r
+                       </div>                                  \r
+                               \r
+                       <div style="float:left;"><a href="#" onclick="clip.previous();"><img src="images/clip_prev.png" alt="Previous Clip" title="Previous Clip" /></a></div> \r
+                       <div style="float:right;"><a href="#" onclick="clip.next();"><img src="images/clip_next.png" alt="Next Clip" title="Next Clip" /></a></div>\r
+       \r
+                       <div style="text-align:center;">\r
+                               <!--  a href="#" onmousedown="movie.pressPlay()" onmouseup="movie.pressStop()"><img src="images/pressplay.png" alt="Press Play" title="Press Play" id="pressButton" /></a>&nbsp; --> \r
+                               <a href="#" onmousedown="movie.normPlay()"><img src="images/play.png" alt="Play" title="Play" id="playButton" /></a>\r
+                       </div>\r
+\r
+               </div>\r
+               \r
+               <div id="clip-info">\r
+                       <div style="font-weight:bold;text-decoration:underline; text-align:left;" id="clip-name"></div><br />\r
+                       <!--  div style="text-align:left">Total Clips: <div id="numclips" style="display:inline"></div></div -->\r
+               </div>\r
+\r
+               \r
+               <div id="make-clip">\r
+                       <input type="button" name="Make Clip" value="Make Clip" class="button" style="width:7em" onclick="movie.saveClip()" id="makeclip"  />\r
+               </div>\r
+                                       \r
+               <div id="clip-controls">\r
+                       <!--  div id="clip-time"></div> / <div id="clip-duration"></div -->\r
+\r
+                       <div id="in-info">\r
+                               <div style="float:left" id="in-time"></div><div style="float:right" id="in-undo"></div><br />\r
+                               <a href="#" onclick="clip.addPrevSpace()" id="addprev"><img src="images/clip_leftedge.png" alt="Add previous space to clip" title="Add previous space to clip" style="padding-top:10px; padding-right:5px;" /></a> \r
+                               <input type="button" id="in" name="in" value="In" class="button" onclick="clip.newInTime();" />\r
+                       </div>\r
+\r
+                       <div id="out-info">\r
+                               <div style="float:left" id="out-undo"></div><div style="float:right" id="out-time"></div><br />\r
+                               <input type="button" id="out" name="out" value="Out" class="button" onclick="clip.newOutTime();" /> \r
+                               <a href="#" onclick="clip.addNextSpace()" id="addnext"><img src="images/clip_rightedge.png" alt="Add next space to clip" title="Add next space to clip" style="padding-top:10px; padding-left:5px;" /></a>\r
+                       </div>                          \r
+\r
+                       <div id="clip-timeline">\r
+                               <div id='c_timeline' class='ui-slider-clip' >\r
+                                       <div id="c_handle"></div>       \r
+                               </div>                                  \r
+                       </div>  \r
+                                       \r
+                       <div id="clip-buttons">                 \r
+                       <div style="float:left;margin-top:1.4em;">\r
+                               <a href="#" onclick="clip.goToStart()"><img src="images/start.png" alt="Go to start of clip" title="Go to start of clip" /></a>&nbsp;\r
+                               <a href="#" onclick="clip.stepBack(33)"><img src="images/rewind2.png" alt="Step back .033 second" title="Step back .033 seconds" /></a>&nbsp;\r
+                               <a href="#" onclick="clip.stepBack(100)"><img src="images/rewind.png" alt="Step back .100 second" title="Step back .100 second" /></a>\r
+                       </div>  \r
+\r
+                       <div style="float:right;margin-top:1.4em;">\r
+                               <a href="#" onclick="clip.stepForward(100)"><img src="images/ffwd.png" alt="Step forward .100 second" title="Step forward .100 second" /></a>&nbsp;\r
+                               <a href="#" onclick="clip.stepForward(33)"><img src="images/ffwd2.png" alt="Step forward .033 second" title="Step forward .033 second" /></a>&nbsp; \r
+                               <a href="#" onclick="clip.goToEnd()"><img src="images/end.png" alt="Go to end of clip" title="Go to end of clip" /></a> \r
+                       </div>                                          \r
+                                                                       \r
+                       <div style="text-align:center; margin-top:5px;">                \r
+                               <!--  a href="#" onmousedown="clip.pressPlay()" onmouseup="clip.pressStop()"><img src="images/pressplay.png" alt="Press Play" title="Press Play" id="clip-pressButton" /></a>&nbsp; --> \r
+                               <a href="#" onclick="clip.normPlay()"><img src="images/play.png" alt="Play Clip" title="Play Clip" id="clip-playButton" /></a>&nbsp;\r
+                               <a href="#" onclick="clip.lastPlay();"><img src="images/last_start.png" alt="Last play" title="Last play" /></a>\r
+                       </div>\r
+                       </div>\r
+               </div>          \r
+               <div id="captions">\r
+                       <textarea cols="5" rows="4" style="margin-left:-5px;width:250px; height:75px;font-size:15px;" id="caption-text"></textarea><br />\r
+               </div>\r
+       \r
+       </div>\r
+\r
+       <div id="info-container">\r
+               <!-- div id="submenubar">\r
+                       <ul>\r
+                               <li id="clips-subtab"><a id="clip-tab" href="#" onclick="displayClips();">Clip Timeline</a></li>\r
+                               <li id="detail-subtab"><a id="detail-tab" href="#" onclick="displayDetails()">Details</a></li>\r
+                       </ul>\r
+               </div -->\r
+               <div style="background-color:#b5c3d9; padding:5px;"><div id="show_hide_caps"></div></div>       \r
+               <div id="info-tab"></div>\r
+       </div>\r
+\r
+<?php require('include/footer.inc.php'); ?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/error_log b/mods/atutor_opencaps/opencaps/error_log
new file mode 100755 (executable)
index 0000000..9b610fa
--- /dev/null
@@ -0,0 +1 @@
+[15-Aug-2010 23:56:54] PHP Warning:  Cannot modify header information - headers already sent by (output started at /home/filoa3/public_html/a2/ATutor/mods/AtOpenCaps/opencaps/include/classes/project_class.php:186) in /home/filoa3/public_html/a2/ATutor/mods/AtOpenCaps/opencaps/include/classes/system_class.php on line 94
diff --git a/mods/atutor_opencaps/opencaps/export.php b/mods/atutor_opencaps/opencaps/export.php
new file mode 100755 (executable)
index 0000000..d3020cc
--- /dev/null
@@ -0,0 +1,77 @@
+<?php \r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+define('INCLUDE_PATH', 'include/');\r
+require(INCLUDE_PATH.'vitals.inc.php');\r
+\r
+if (isset($_POST['remote_submit'])) {\r
+       //$this_proj->remoteUpdate($_SESSION['rid']);\r
+       $this_system->putCaps($this_proj->id);\r
+} else if (isset($_POST['format'])) {\r
+       $this_proj->exportCaption($_POST['format']);\r
+}\r
+\r
+require(INCLUDE_PATH.'header.inc.php'); \r
+\r
+?>\r
+\r
+<script language="javascript" type="text/javascript" src="js/export.js"></script>\r
+\r
+<div id="content">\r
+       <form action="export.php" method="post" id="form">\r
+\r
+       <?php if (isset($systems) && isset($_SESSION['rid'])) { ?>\r
+       <h3>Send Captions to <?php echo $systems[$_SESSION['rid']]['name']; ?></h3>                                     \r
+               <p>If you are finished captioning this project, use the button below to update the system with your caption file.</p>\r
+               <p><input type="submit" name="remote_submit" value="Submit Captions to <?php echo $systems[$_SESSION['rid']]['name']; ?>" /></p>\r
+       <?php }  ?>\r
+       \r
+               <h3>Export Caption File</h3>\r
+               <p>You may export your captions in a variety of formats. Choose a format to receive a download of that caption file:</p>        \r
+\r
+               <input type="hidden" name="format" />\r
+               <ul id="export-list">\r
+                       <!--  li><a href="javascript:set_format('json')">Complete Package</a><br />Zip of original movie, caption file, SMIL file, and accessible html player</li -->\r
+                       <li><a href="javascript:set_format('DFXP')">Timed Text (DFXP)</a></li>\r
+                       <li><a href="javascript:set_format('DvdStl')">DVD STL</a></li>\r
+                       <li><a href="javascript:set_format('MicroDvd')">MicroDVD</a></li>\r
+                       <!-- li><a href="javascript:set_format('MPlayer')">MPlayer</a></li -->\r
+                       <li><a href="javascript:set_format('QTtext')">QT text</a></li>\r
+                       <!-- li><a href="javascript:set_format('RealText')">Real Text</a></li -->\r
+                       <li><a href="javascript:set_format('Sami')">SAMI</a></li>\r
+                       <li><a href="javascript:set_format('SubRipSrt')">SubRip</a></li>\r
+                       <li><a href="javascript:set_format('SubViewer')">SubViewer</a></li>\r
+                       <li><a href="javascript:set_format('json')">JSON for OpenCaps</a></li>                          \r
+                       <!-- li><a href="javascript:set_format('Scc')">SCC</a></li -->                                                                                  \r
+               </ul>\r
+\r
+               <h3>Export Transcript</h3>\r
+               <p>Coming soon.</p>\r
+               <!--  ul id="export-list">\r
+                       <li><a href="javascript:set_format('plain')">Transcript</a> - a plain text file of the captions, separated by new lines</li>                                                                            \r
+               </ul -->\r
+               \r
+               <?php \r
+               if (extension_loaded('zip')) { ?>\r
+               <h3>Export Complete Project</h3>\r
+               <ul id="export-list">\r
+                       <li><a href="javascript:set_format('all')">Complete Package</a> - .zip of original movie, caption file, SMIL file (layout in preview), and accessible html player</li>                                                                          \r
+               </ul>\r
+               <?php } ?>\r
+       </form>\r
+       \r
+       <h3>Close</h3>          \r
+       <p>Once you have exported your work to save it, you may now <a href="start.php"><img style="margin-bottom:-3px;" src="images/cross.png" alt="" /> <strong>Close</strong></a> this project.</p>\r
+</div>\r
+<?php require(INCLUDE_PATH.'footer.inc.php'); ?>\r
diff --git a/mods/atutor_opencaps/opencaps/help.php b/mods/atutor_opencaps/opencaps/help.php
new file mode 100755 (executable)
index 0000000..7203a37
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+require('include/vitals.inc.php'); 
+
+require('include/header.inc.php'); 
+
+?>
+       
+       <div id="content">
+               <p>Coming soon...</p>
+               
+       </div>
+<?php require('include/footer.inc.php'); ?>    
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/images/application_edit.png b/mods/atutor_opencaps/opencaps/images/application_edit.png
new file mode 100755 (executable)
index 0000000..fb2efb8
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/application_edit.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/application_get.png b/mods/atutor_opencaps/opencaps/images/application_get.png
new file mode 100755 (executable)
index 0000000..28e41ea
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/application_get.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/application_put.png b/mods/atutor_opencaps/opencaps/images/application_put.png
new file mode 100755 (executable)
index 0000000..c30cf59
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/application_put.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/arrow_right.png b/mods/atutor_opencaps/opencaps/images/arrow_right.png
new file mode 100755 (executable)
index 0000000..b1a1819
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/arrow_right.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/asterisk_yellow.png b/mods/atutor_opencaps/opencaps/images/asterisk_yellow.png
new file mode 100755 (executable)
index 0000000..22a1290
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/asterisk_yellow.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/bullet_delete.png b/mods/atutor_opencaps/opencaps/images/bullet_delete.png
new file mode 100755 (executable)
index 0000000..bd6271b
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/bullet_delete.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/clip_leftedge.png b/mods/atutor_opencaps/opencaps/images/clip_leftedge.png
new file mode 100755 (executable)
index 0000000..2de8836
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/clip_leftedge.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/clip_next.png b/mods/atutor_opencaps/opencaps/images/clip_next.png
new file mode 100755 (executable)
index 0000000..ce378bc
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/clip_next.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/clip_prev.png b/mods/atutor_opencaps/opencaps/images/clip_prev.png
new file mode 100755 (executable)
index 0000000..eb53ca1
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/clip_prev.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/clip_rightedge.png b/mods/atutor_opencaps/opencaps/images/clip_rightedge.png
new file mode 100755 (executable)
index 0000000..36acc97
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/clip_rightedge.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/cross.png b/mods/atutor_opencaps/opencaps/images/cross.png
new file mode 100755 (executable)
index 0000000..1514d51
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/cross.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/door_out.png b/mods/atutor_opencaps/opencaps/images/door_out.png
new file mode 100755 (executable)
index 0000000..2541d2b
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/door_out.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/end.png b/mods/atutor_opencaps/opencaps/images/end.png
new file mode 100755 (executable)
index 0000000..648cfcc
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/end.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/ffwd.png b/mods/atutor_opencaps/opencaps/images/ffwd.png
new file mode 100755 (executable)
index 0000000..20d3350
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/ffwd.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/ffwd2.png b/mods/atutor_opencaps/opencaps/images/ffwd2.png
new file mode 100755 (executable)
index 0000000..cfa1231
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/ffwd2.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/index.html b/mods/atutor_opencaps/opencaps/images/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/images/last_start.png b/mods/atutor_opencaps/opencaps/images/last_start.png
new file mode 100755 (executable)
index 0000000..8287d3b
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/last_start.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/logo.png b/mods/atutor_opencaps/opencaps/images/logo.png
new file mode 100755 (executable)
index 0000000..a0ddbb0
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/logo.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/middlebar.png b/mods/atutor_opencaps/opencaps/images/middlebar.png
new file mode 100755 (executable)
index 0000000..4f58603
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/middlebar.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/page_gear.png b/mods/atutor_opencaps/opencaps/images/page_gear.png
new file mode 100755 (executable)
index 0000000..8e83281
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/page_gear.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/pause.png b/mods/atutor_opencaps/opencaps/images/pause.png
new file mode 100755 (executable)
index 0000000..b8f02e6
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/pause.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/play.png b/mods/atutor_opencaps/opencaps/images/play.png
new file mode 100755 (executable)
index 0000000..aee4018
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/play.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/pressplay.png b/mods/atutor_opencaps/opencaps/images/pressplay.png
new file mode 100755 (executable)
index 0000000..7a92ae6
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/pressplay.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/rewind.png b/mods/atutor_opencaps/opencaps/images/rewind.png
new file mode 100755 (executable)
index 0000000..f4f6eaa
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/rewind.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/rewind2.png b/mods/atutor_opencaps/opencaps/images/rewind2.png
new file mode 100755 (executable)
index 0000000..9fd7908
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/rewind2.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/slider-bg-1.png b/mods/atutor_opencaps/opencaps/images/slider-bg-1.png
new file mode 100755 (executable)
index 0000000..b7d806e
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/slider-bg-1.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/slider-bg-2.png b/mods/atutor_opencaps/opencaps/images/slider-bg-2.png
new file mode 100755 (executable)
index 0000000..2fb763d
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/slider-bg-2.png differ
diff --git a/mods/atutor_opencaps/opencaps/images/slider-handle-ghost.gif b/mods/atutor_opencaps/opencaps/images/slider-handle-ghost.gif
new file mode 100755 (executable)
index 0000000..cf88250
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/slider-handle-ghost.gif differ
diff --git a/mods/atutor_opencaps/opencaps/images/slider-handle.gif b/mods/atutor_opencaps/opencaps/images/slider-handle.gif
new file mode 100755 (executable)
index 0000000..33b14d6
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/slider-handle.gif differ
diff --git a/mods/atutor_opencaps/opencaps/images/start.png b/mods/atutor_opencaps/opencaps/images/start.png
new file mode 100755 (executable)
index 0000000..258b896
Binary files /dev/null and b/mods/atutor_opencaps/opencaps/images/start.png differ
diff --git a/mods/atutor_opencaps/opencaps/include/basic_header.inc.php b/mods/atutor_opencaps/opencaps/include/basic_header.inc.php
new file mode 100755 (executable)
index 0000000..2e214ad
--- /dev/null
@@ -0,0 +1,66 @@
+<?php 
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+?>
+
+<!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=utf-8" />
+       <title>OpenCaps - An online inclusive media editor</title>
+       
+       <script language="JavaScript" src="js/jquery/jquery-1.2.6.js" type="text/javascript"></script>
+       <script language="JavaScript" src="js/json/json2.js" type="text/javascript"></script>
+       <script language="JavaScript" src="js/utils.js" type="text/javascript"></script>
+               
+       <link rel="stylesheet" href="styles.css" type="text/css" />
+       <link rel="stylesheet" href="styles_public.css" type="text/css" />
+       <!--[if IE]>
+               <link href="styles_ie.css" rel="stylesheet" type="text/css" />
+       <![endif]-->    
+
+</head>
+<body>
+
+       <?php if ($_SESSION['mid'] && $_SESSION['mid']!='99999' && !DISABLE_LOCAL) { ?>
+       <div style="float:right; margin-top:-5px;font-size:smaller;">
+               <img style="margin-bottom:-3px;" src="images/door_out.png" alt="" /> <a href="logout.php">Logout</a>
+       </div>
+               
+       <?php 
+       }
+       
+       if (isset($_SESSION['errors'])) {
+               echo '<div class="error"><strong>Error:</strong><br />';
+               foreach ($_SESSION['errors'] as $errmsg) {
+                       echo $errmsg.'<br />';  
+               }
+               echo '</div>';
+               unset($_SESSION['errors']);
+       }
+       if (isset($_SESSION['feedback'])) {
+               echo '<div class="feedback"><strong>Feedback:</strong><br />';
+               foreach ($_SESSION['feedback'] as $fbmsg) {
+                       echo $fbmsg.'<br />';   
+               }
+               echo '</div>';
+               unset($_SESSION['feedback']);
+       }
+       if (isset($_SESSION['notices'])) {
+               echo '<div class="notice"><strong>Notice:</strong><br />';
+               foreach ($_SESSION['notices'] as $nmsg) {
+                       echo $nmsg.'<br />';    
+               }
+               echo '</div>';
+               unset($_SESSION['notices']);
+       }       
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/captionCollection_class.php b/mods/atutor_opencaps/opencaps/include/classes/captionCollection_class.php
new file mode 100755 (executable)
index 0000000..5ba4d87
--- /dev/null
@@ -0,0 +1,125 @@
+<?php\r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Antonio Gamba Bari\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+/**\r
+ * This class represents a collection of captions \r
+ * 1. Create an instance\r
+ * 2. load captions\r
+ */\r
+class CaptionCollection\r
+{\r
+       public $collectionName = ''; // the name that holds the entiry collection.. this particularly important for JSON export\r
+       public $txtStylesGlobal = array(); // holds any global text style. (e.g. $txtStylesGlobal['text-align'] = 'center', $txtStylesGlobal['text-font'] = 'Arial', $txtStylesGlobal['text-size'] = '14', etc...)\r
+       public $captionCollection = array(); // a collection of Caption objects\r
+       \r
+       /**\r
+       * Class Constructor \r
+       */\r
+       public function __construct()\r
+       {\r
+               /*\r
+                * empty for now... (we don't know what the caption will contain...)\r
+                * It seems logical and much more practical \r
+                * to create first an empty CaptionCollection  \r
+                * and then add to it as needed, \r
+                * finally, get the collection object\r
+                */\r
+       }\r
+       \r
+       /**\r
+        * Adds a Caption Object to the $captionCollection array \r
+        * @param Object $theCcObject a Caption Object\r
+        * @return void\r
+        */     \r
+       public function addCaption($theCcObject)\r
+       {\r
+               // add Caption to the Caption Collection \r
+               $this->captionCollection[] = $theCcObject; // this a php-based approach... java will need a push/count solution \r
+               \r
+       } // end addCaptions()\r
+\r
+       /**\r
+        * Sets all the Global text style attributes\r
+        * @param Array $theGlobalStyles Array containing all the global text styles  \r
+        */\r
+       public function setTxtStylesGlobal($theGlobalStyles)\r
+       {\r
+               $this->txtStylesGlobal = $theGlobalStyles;\r
+       }       \r
+       \r
+       /**\r
+        * Sets the value a single Global text style attribute\r
+        * @param String $theAtt Attribute name\r
+        * @param String $theValue Attribute Value \r
+        */\r
+       public function setTxtStylesGlobalAtt($theAtt,$theValue)\r
+       {\r
+               $this->txtStylesGlobal[$theAtt]=$theValue;\r
+       } // end setTxtStylesGlobalAtt()\r
+       \r
+       /**\r
+        * Return this object\r
+        *\r
+        * @return CaptionCollection \r
+        */\r
+       public function getCollection()\r
+       {\r
+               return $this->captionCollection;\r
+       }  \r
+\r
+       public function toString()\r
+       {\r
+               $ccCount=0;\r
+               echo '<br/><h3>Printing a Rosetta Collection</h3>';\r
+               echo 'Total Captions Found: '.count($this->captionCollection);\r
+\r
+               echo '<br/><br/><b>[Global]  Styles</b>';\r
+               if (count($this->txtStylesGlobal)==0)\r
+               {\r
+                       echo ' (NO text styles found)';\r
+               }\r
+               \r
+               foreach ($this->txtStylesGlobal as $txtStyleName => $txtStyleValue)\r
+               {\r
+                       echo '<br/> -----'.$txtStyleName.' = '.$txtStyleValue;\r
+               }\r
+               \r
+               echo '<br/><br/><b>Printing Captions in the collection... </b>';\r
+               foreach ($this->captionCollection as $captionObj)\r
+               {\r
+                       $ccCount++;\r
+                       // building a new to string\r
+                       /* \r
+                       \r
+                       echo "<br><b>In Time: </b>". $captionObj->getInTime()."";\r
+                       echo "<br><b>Out Time: </b>". $captionObj->getOutTime()."";\r
+                       echo "<br><b>Caption: </b>". $captionObj->getCaption()."";\r
+                       \r
+            // display text styles\r
+            foreach ($captionStylesFound as $txtStyle)\r
+            {\r
+               $captionObj->\r
+               //$textStyles[] = $txtStyle;\r
+            }\r
+                       */\r
+                       // call Caption's toString();\r
+                       echo '<br/><br/>'.$ccCount;\r
+                       $captionObj->toString();\r
+\r
+               } // foreach end \r
+\r
+       } //toString() end\r
+\r
+} // end CaptionCollection Class  \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/caption_class.php b/mods/atutor_opencaps/opencaps/include/classes/caption_class.php
new file mode 100755 (executable)
index 0000000..8070e5c
--- /dev/null
@@ -0,0 +1,27 @@
+<?php\r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+class caption {\r
+       public $caption;\r
+       public $textStyles = array(); // \r
+       \r
+       function __construct($theCaption,$theTextStyles) {\r
+               $this->caption = $theCaption;\r
+               $this->textStyles= $theTextStyles;\r
+               \r
+       }\r
+}\r
+\r
+\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/clip_class.php b/mods/atutor_opencaps/opencaps/include/classes/clip_class.php
new file mode 100755 (executable)
index 0000000..24eed2d
--- /dev/null
@@ -0,0 +1,65 @@
+<?php\r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+/* an array of clips */\r
+class clipCollection {\r
+       \r
+       public $clips = array();\r
+       public $global_caption_styles = array(); //global caption styles\r
+       \r
+       public function __construct() {\r
+       }\r
+       \r
+       public function addClip($clip) {\r
+               $this->clips[] = $clip;\r
+       } \r
\r
+} \r
+\r
+/* an actual clip */\r
+class clip {\r
+       public $inTime;\r
+       public $outTime;\r
+       public $duration;\r
+       \r
+       public $inTimeMilli;\r
+       public $outTimeMilli;   \r
+       public $durationMilli;\r
+       \r
+       // should these two be in a caption object?\r
+       public $caption_text; \r
+       public $captionStyles = array();\r
+       \r
+       //public $description;\r
+       \r
+       function __construct($in, $out, $caption) {\r
+               $intime = new time($in, false);\r
+               $this->inTime = $intime->formatted;\r
+               $this->inTimeMilli = $intime->ms; \r
+\r
+               $outtime = new time($out, false);\r
+               $this->outTime = $outtime->formatted;\r
+               $this->outTimeMilli = $outtime->ms; \r
+               \r
+               $this->durationMilli = $this->outTimeMilli - $this->inTimeMilli;\r
+               $dur = new time($this->durationMilli, true);\r
+               $this->duration = $dur->formatted;              \r
+                               \r
+               $this->caption_text = $caption;\r
+       }\r
+}\r
+\r
+\r
+\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/db_class.php b/mods/atutor_opencaps/opencaps/include/classes/db_class.php
new file mode 100755 (executable)
index 0000000..80ca441
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+class database { 
+       public $db;
+       
+       public function __construct() {
+               $this->connect();                                       
+       }
+
+       private function connect() {
+                                               
+               require(INCLUDE_PATH.'config.inc.php');
+               $this->db = @mysql_connect(DB_HOST . ':' . DB_PORT, DB_USER, DB_PASSWORD);
+               if (!$this->db) {
+                       $_SESSION['errors'][] = 'Unable to connect to database. <br />';
+               }
+               if (!@mysql_select_db(DB_NAME, $this->db)) {
+                       $_SESSION['errors'][] = 'Connection established, but database "'.DB_NAME.'" cannot be selected. <br />';
+               }               
+               
+               if (isset($_SESSION['errors'])) {
+                       include(INCLUDE_PATH."basic_header.inc.php");
+                       include(INCLUDE_PATH."footer.inc.php");                 
+                       exit;
+               }
+               
+               return true;
+       }
+       
+       /* adds a new proj to the db, returns proj id */
+       public function addProj($proj) {
+                               
+               $sql = "INSERT INTO projects VALUES (0, $_SESSION[mid], '$proj->name', '$proj->media_loc', 0, NOW())";          
+               if (!$result = mysql_query($sql, $this->db)) {
+                       $_SESSION['errors'][] = 'Database error - could not add project.';
+                       return false;
+               }
+               return mysql_insert_id();
+       }       
+       
+       public function updateProj($proj) {
+               $sql = "UPDATE projects SET name='".$proj->name."', video_file='".$proj->media_loc."' WHERE project_id=".$proj->id;             
+               if (!$result = mysql_query($sql, $this->db)) {
+                       $err = 'Database error <br />';
+                       exit;   
+               }
+               return true;            
+       }
+       
+
+       
+       /*public function getProjInfo($id) {
+               global $db;
+               
+               $sql = "SELECT name, video_file, layout_preset, last_accessed FROM projects WHERE project_id=".intval($id);
+               $result = mysql_query($sql, $db);
+       
+               if ($row = mysql_fetch_assoc($result)) {
+                       return $row;
+               }       
+       }
+       
+       public function getMovie() {
+               global $db;
+               
+               $sql = "SELECT video_file FROM projects WHERE project_id=".intval($_SESSION['pid']);
+               $result = mysql_query($sql, $db);
+       
+               if ($row = mysql_fetch_assoc($result)) {
+                       return 'projects/'.$_SESSION['pid'].'/movies/'.$row['video_file'];
+               }       
+       
+       }*/     
+}
+
+
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/index.html b/mods/atutor_opencaps/opencaps/include/classes/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/include/classes/project_class.php b/mods/atutor_opencaps/opencaps/include/classes/project_class.php
new file mode 100755 (executable)
index 0000000..e8fd255
--- /dev/null
@@ -0,0 +1,503 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+class project {
+       //public $owner;
+       
+       public $id;
+       public $name;
+       //public $prefs;
+
+       public $media_loc; //url to media file
+       public $media_height;
+       public $media_width;
+       public $duration;
+       
+       public $caption_loc; //url to caption json file
+       public $clip_collection;  // holds everything: captions, descriptions, etc.
+
+       public $layout;
+       
+       /* new project object belonging to member */
+       function __construct() {
+               $this->clip_collection = new clipCollection();  
+       }
+       
+       /* create a new project */
+       function createNew($name, $media, $captions) {  
+               global $this_db;
+               
+               $this->name = $name;
+               $this->layout = 0;
+                               
+               //enter into db 
+               $this->id = $this_db->addProj($this);
+               
+               if (isset($_SESSION['errors'])) {
+                       header("Location:start.php");
+                       exit;
+               }
+               
+               $_SESSION['pid'] = $this->id;           
+               
+               //make project folder
+               if (!file_exists('projects/'.$this->id.'/')) {
+                       @mkdir('projects/'.$this->id.'/');
+                       @copy('projects/index.html', 'projects/'.$this->id.'/index.html');
+               }               
+               
+               // if uploaded
+               if (is_array($media)) { 
+                       $this->media_loc = 'projects/'.$this->id.'/'.$media['name'];
+                               
+                       if ( !move_uploaded_file($media['tmp_name'], 'projects/'.$this->id.'/'.basename($media['name'])) ) {
+                               $_SESSION['errors'][] = "Problem uploading media file - can't copy file to server. The file may exceed file size limits. Try a smaller file or contact your server administrator.";
+                               
+                               $this->delete($this->id);
+                               return;                         
+                       }
+                       
+               // if URL       
+               } else {
+                       $this->media_loc = $media;      
+               }
+                                               
+               //convert caption file to quicktime &  save
+               if (!empty($captions['tmp_name'])) {    
+                                                       
+                       $this->importCaptions($captions);       
+               }
+                                       
+               //save reference file
+               $json = json_encode(get_object_vars($this));            
+               $this->saveJson($json, $this->id);                              
+               $this_db->updateProj($this);
+               
+               return $this->id;
+       }
+       
+       /* open user project */
+       function open($pid) {   
+               global $this_db;        
+               $sql = "UPDATE projects SET last_accessed=NOW() WHERE project_id=$pid AND member_id=$_SESSION[mid]";
+               if (!$result = mysql_query($sql, $this_db->db)) {
+                       echo 'Database error: '.mysql_error();
+                       exit;   
+               }
+               
+               $_SESSION['pid'] = $pid;        
+       }                       
+       
+       
+       /* save uploaded media - returns location of file */
+       function saveMedia($upload) {
+               $dir = 'projects';
+               if (!move_uploaded_file($file['tmp_name'], $dir.'/'.basename($file['name'])) ) {
+                       //$err = "Problem uploading file - can't copy file to server. The file may exceed file size limits. Try a smaller file or contact your server administrator.";
+               }
+       }
+       
+       /* list the current user's projects */
+       function printUserProjects($pageNum) {
+               global $this_db, $stripslashes, $addslashes;
+               
+               if (!isset($pageNum))
+                       $pageNum = 1;
+                               
+               $projsPerPage = 20;
+                       
+               //printing page numbers
+               $sql  = "SELECT project_id FROM projects WHERE member_id=".intval($_SESSION['mid']);
+               $result  = @mysql_query($sql, $this_db->db);
+               $numrows = @mysql_num_rows($result);
+                       
+               $maxPage = ceil($numrows/$projsPerPage);
+                       
+                       $nav  = 'Page: ';               
+                       for($page = 1; $page <= $maxPage; $page++) {
+                          if ($page == $pageNum) {
+                             $nav .= " $page "; 
+                          } else {
+                             $nav .= ' <a href="start.php?page='.$page.'">'.$page.'</a> ';
+                          }
+                       }               
+                       
+                       if ($maxPage > 1)
+                               echo $nav."<br /><br />";
+                       
+                       $offset = ($pageNum - 1) * $projsPerPage;
+                       $sql = "SELECT * FROM projects WHERE member_id=".intval($_SESSION['mid'])." ORDER BY last_accessed DESC LIMIT $offset, $projsPerPage";
+                       $result = @mysql_query($sql, $this_db->db);             
+                       
+               
+               if ($numrows == 0) {
+                       echo "No projects yet.";
+               } else {
+                       echo '<ul class="proj-list">';                  
+                       while ($row = @mysql_fetch_assoc($result)) {                                    
+                               echo '<li><label><input type="radio" name="proj" value='.$row['project_id'].' /> '.$stripslashes($row['name']).'</label> (<a href="#" onClick="confirmDelete('.$row['project_id'].', \''.$addslashes($row['name']).'\');">Delete</a>)</li>';
+                       }
+                       echo '</ul>';   
+                       echo "<div style='text-align:right;'><input type='submit' class='button' style='width:6em;margin-top:5px;' name='submit_new' value='Submit' /></div>";          
+                       
+               }                       
+       }
+       
+       function saveJson($json, $pid) {
+               global $stripslashes;\r
+                               
+               $json_path = INCLUDE_PATH.'../projects/'.$pid.'/';
+                       
+               if (!file_exists($json_path))
+                       mkdir($json_path);\r
+                       \r
+               // addede by ANTO\r
+               ///////////////////////////////////////////\r
+               if (get_magic_quotes_gpc()) \r
+               {\r
+                       $json = stripslashes($json);\r
+               \r
+               }\r
+               // second test using regexp\r
+               $validJsonRegExp = '/"clips":\[/'; // can be better tho\r
+               if (!preg_match($validJsonRegExp, $validJsonRegExp))\r
+               {\r
+                       $json = str_replace('\"','"',$json);\r
+               }\r
+               //end added by ANTO\r
+               ///////////////////////////////////////////\r
+               
+\r
+               if (!@file_put_contents($json_path.'opencaps.json', $stripslashes($json))) {
+                       echo 'Could not create project file.';
+               }       \r
+       }
+       
+       function importCaptions($capfile, $upload=true) {               
+               global $page, $remote_systems;
+               \r
+               // added by anto\r
+               if (OC_DEBUG_MODE_ON)\r
+               {\r
+                       $ocAtDebugMsg = '*************************';\r
+                       $ocAtDebugMsg .= '<br/>';\r
+                       $ocAtDebugMsg .= '<b>importCaptions() - class: project</b>';\r
+                       $ocAtDebugMsg .= '<br/>';\r
+                       $ocAtDebugMsg .= '<br/>Session ID: '.$_SESSION['pid'];\r
+                       $ocAtDebugMsg .= '<br/>$this->id: '.$this->id;\r
+                       $ocAtDebugMsg .= '<br/><br/>';\r
+                       $ocAtDebugMsg .= '*************************';\r
+                       ///echo $ocAtDebugMsg;\r
+                       $_SESSION['feedback'][] = $ocAtDebugMsg;\r
+               }\r
+               
+               $page = explode('/',$_SERVER["SCRIPT_NAME"]); 
+               $page = end($page);
+               
+               $page_len = strlen($page)+1;
+               
+               $ccollection = new clipCollection() ;
+               
+               //save
+               if ($upload) {
+                       if( !move_uploaded_file( $capfile['tmp_name'], INCLUDE_PATH.'../projects/'.$this->id.'/'.basename($capfile['name'])) ) {
+                               $_SESSION['errors'][] = "Problem uploading caption file - can't copy file to server.";                  
+                               $this->delete($this->id);
+                               return;
+                       }
+                       
+                       $base_url = substr('http://'.$_SERVER["SERVER_NAME"].$_SERVER["SCRIPT_NAME"], 0, -$page_len);                                   
+                       $caption_file = urlencode('../projects/'.$this->id.'/'.basename($capfile['name']));                                             
+                       
+               } else {                        
+                       /* system - matterhorn */
+                       $page_len += strlen("include/");
+                       $base_url = substr('http://'.$_SERVER["SERVER_NAME"].$_SERVER["SCRIPT_NAME"], 0, -$page_len);                                   
+                       
+                       $uri = substr($capfile, strlen($remote_systems[$_SESSION['rid']]['url']));
+                       $caps = matterhornAuth($_SESSION['rid'], $uri);
+                       $caption_file = INCLUDE_PATH.'../projects/'.$this->id.'/'.'captions.xml';
+                       @file_put_contents($caption_file, $caps);                       
+               }
+                                       
+               $convert_url = $base_url.'/conversion_service/?cc_url='.$caption_file.'&cc_result=0&cc_target=JSONcc&cc_name=noname.___';                                       
+               $json_captions = json_decode(@file_get_contents($convert_url)); 
+                               
+               if (!empty($json_captions) && $json_captions != "The format of source Caption was not recognized.") {                   
+                       
+                       foreach ($json_captions->captionCollection as $clip) {                          
+                               $this_clip = new clip($clip->inTime, $clip->outTime, trim($clip->caption));
+                               $ccollection->addClip($this_clip);
+                       }       
+
+                       $_SESSION['feedback'][] = "Captions imported successfully.";\r
+                       $_SESSION['feedback'][] = "id: ".$this->id;
+                                                                               
+               } else  {
+                       $_SESSION['errors'][] = "Problem uploading caption file - the format is incorrect, or unsupported.";
+               }               
+               
+               $this->clip_collection = $ccollection;
+                       
+               //save reference file
+               $json = json_encode(get_object_vars($this));            
+               \r
+               \r
+               // changed by ANTO\r
+               $this->saveJson($json, $_SESSION['pid']);               
+
+               return;
+
+       }               
+       
+       
+       function exportCaption($format) {
+
+               if ($format == "all") {
+                               $this->export_pkg();                            
+                                               
+               } else if ($format == "json") {
+                               $cappath = INCLUDE_PATH.'../projects/'.$this->id.'/'.'opencaps.json';
+                               //make a copy of the json that has the proj name as prefix
+                               
+                                               
+               } else {
+                       $base_url = substr('http://'.$_SERVER["SERVER_NAME"].$_SERVER["SCRIPT_NAME"], 0, -10);          
+                       
+                       $convert_url = $base_url.'conversion_service/?cc_url='.urlencode('../projects/'.$this->id.'/opencaps.json').'&cc_result=0&cc_target='.$format.'&cc_name=noname.___';    
+                       $formatted_captions = @file_get_contents($convert_url);
+                       if (!empty($formatted_captions)) {
+                               $formatted_captions = trim($formatted_captions);                                
+                               $cappath = INCLUDE_PATH.'../projects/'.$this->id.'/'.str_replace(' ', '_', $this->name).'_';
+                       
+                               switch($format) {
+                                       case "DFXP":
+                                               $cappath = $cappath.'captions.dfxp.xml';
+                                               break;
+       
+                                       case "DvdStl":
+                                               $cappath = $cappath.'captions.stl';
+                                               break;                                  
+                                               
+                                       case "MicroDvd":
+                                               $cappath = $cappath.'captions.sub';
+                                               break;
+                                               
+                                       case "MPlayer":
+                                               $cappath = $cappath.'captions.MPsub';
+                                               break;
+                                               
+                                       case "QTtext":                                          
+                                               $formatted_captions = $formatted_captions."\r\n".'['.$this->duration.']'; /* white cap background hack */                                               
+                                               $cappath = $cappath.'captions.txt';
+                                               break;                                  
+       
+                                       case "RealText":
+                                               $cappath = $cappath.'captions.rt';
+                                               break;  
+                                                                                       
+                                       case "Sami":
+                                               $cappath = $cappath.'capscribe.smi';
+                                               break;
+       
+                                       case "SubRipSrt":
+                                               $cappath = $cappath.'captions.srt';
+                                               break;
+                                               
+                                       case "Scc":
+                                               $cappath = $cappath.'captions.scc';
+                                               break;          
+       
+                                       case "SubViewer":
+                                               $cappath = $cappath.'captions.sub';
+                                               break;                                          
+                               }
+       
+                               @file_put_contents($cappath, $formatted_captions);
+                       }
+               }
+               export_file($cappath);  
+               exit;           
+       }
+       
+       function delete($proj_id) {
+               global $this_db;
+                               
+               if (deleteDir('../projects/'.$proj_id."/")) {                           
+                       $sql = "DELETE from projects WHERE project_id=".$proj_id." AND member_id=".$_SESSION['mid'];
+                       $result = mysql_query($sql, $this_db->db);                      
+               } else {
+                       //echo "Project could not be deleted.";
+               }
+       }
+
+       function preview($layout) {     
+               $this->layout = $layout;
+               
+               //send this to the conversion service
+               $base_url = substr('http://'.$_SERVER["SERVER_NAME"].$_SERVER["SCRIPT_NAME"], 0, -20);          
+               $json_url = urlencode($base_url.'projects/'.$this->id.'/opencaps.json');
+               $request = $base_url."conversion_service/?cc_url=".$json_url."&cc_result=0&cc_target=QTtext&cc_name=noname.___";
+                       
+               //create the qt-text file
+               $qt_text = @file_get_contents($request)."\r\n".'['.$this->duration.']'; 
+               @file_put_contents('../projects/'.$this->id.'/captions.txt', $qt_text);
+
+               //send the embed height back as a response
+               $eheight = $this->get_smil('save');
+               if ($eheight >= 100)
+                       echo $eheight;
+               else 
+                       echo '100';
+       }
+       
+
+       function get_smil($method="") {
+               $layout = $this->layout; 
+                                               
+               $contents = @file_get_contents(INCLUDE_PATH.'../projects/layouts/smil_'.$layout.'.mov');
+               $contents = str_replace("%rootwidth%", $this->media_width, $contents);
+               
+               $vid_file_name = end(explode('/',$this->media_loc));
+       
+               if ($this->media_loc == 'projects/'.$this->id.'/'.$vid_file_name)
+                       $contents = str_replace("%video%", $vid_file_name, $contents);
+               else
+                       $contents = str_replace("%video%", $this->media_loc, $contents);
+                       
+               $contents = str_replace("%duration%", $this->duration, $contents);
+               $contents = str_replace("%width%", $this->media_width, $contents);
+               $contents = str_replace("%height%", $this->media_height, $contents);
+               
+               $contents = str_replace("%capwidth%", $this->media_width-10, $contents);
+               
+               if ($layout == 0) { //cap below
+                       $contents = str_replace("%rootheight%", $this->media_height+85, $contents);
+                       $obj_height = $this->media_height+100;
+                       $contents = str_replace("%captop%", $this->media_height+10, $contents);
+                       $contents = str_replace("%capheight%", 135, $contents);  //affects font size
+                       
+               } else if ($layout == 1) { //cap bottom
+                       $contents = str_replace("%rootheight%", $this->media_height, $contents);
+                       $obj_height = $this->media_height+30;
+                       $contents = str_replace("%captop%", $this->media_height-75, $contents);
+                       $contents = str_replace("%capheight%", 135, $contents);
+                       
+               } else { //caption only
+                       $contents = str_replace("%rootheight%", 85, $contents);
+                       $obj_height = 155;
+                       $contents = str_replace("%captop%", 10, $contents);
+                       $contents = str_replace("%capheight%", 135, $contents);
+               }
+
+               if ($method == "save") {
+                       $proj_smil = INCLUDE_PATH.'../projects/'.$this->id.'/smil_'.$layout.'.mov';
+                       @file_put_contents($proj_smil, $contents);
+                       return $obj_height;     
+               } else {
+                       return $contents;
+               }
+       }       
+       
+       function export_pkg() {                                         
+               //create zipfile
+               $zip = new ZipArchive();
+               
+               $proj_name = str_replace(' ', '', $this->name);
+               $proj_name = str_replace("'", '', $proj_name);  
+               $zipfile = $proj_name.".zip";
+               if ($zip->open(INCLUDE_PATH.'../projects/'.$this->id.'/'.$zipfile, ZIPARCHIVE::CREATE)!==TRUE) {
+                       exit("cannot open <$zipfile>\n");
+               }
+               
+               $zip->addEmptyDir($proj_name);
+               
+               //add smil
+               $contents = $this->get_smil();          
+               $zip->addFromString($proj_name.'/smil.mov', $contents);
+       
+               //create player from template   
+               $contents = file_get_contents(INCLUDE_PATH.'../projects/player_template.php');
+               $contents = str_replace("%width%", $this->media_width, $contents);
+               $contents = str_replace("%height%", $this->media_height+135, $contents);                
+                       
+               //add player
+               $zip->addFromString($proj_name.'/player.html', $contents);
+                               
+               //add captions          
+               $zip->addFile(INCLUDE_PATH.'../projects/'.$this->id.'/captions.txt', $proj_name.'/captions.txt');
+               
+               //add movie if not a URL
+               if (current(explode('/', $this->media_loc)) == "projects") {
+                       $media_name = end(explode('/', $this->media_loc));
+                       $zip->addFile($this->media_loc, $proj_name.'/'.$media_name);
+               }
+                               
+               $zip->close();          
+               //export_file(INCLUDE_PATH.'../projects/'.$this->id.'/'.$zipfile);
+               unlink(INCLUDE_PATH.'../projects/'.$this->id.'/'.$zipfile);
+               exit;           
+       }       
+       
+       function editName($name) {
+               global $addslashes, $this_db;
+                               
+               $this->name = $addslashes($name);
+               
+               //save reference file
+               $json = json_encode(get_object_vars($this));            
+               $this->saveJson($json, $this->id);                              
+               $this_db->updateProj($this);            
+       }
+       
+}      
+
+
+/* utility functions */
+
+/* force download of a file in browser */
+function export_file($exfile) {
+       if (file_exists($exfile)) {
+               header('Content-Description: File Transfer');
+               header('Content-Type: application/octet-stream');
+               header('Content-Disposition: attachment; filename='.basename($exfile));
+               header('Content-Transfer-Encoding: binary');
+               header('Expires: 0');
+               header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+               header('Pragma: public');
+               header('Content-Length: '.filesize($exfile));
+               ob_clean();
+               flush();
+               readfile($exfile);
+       }
+}
+
+/* delete a directory and its contents */
+function deleteDir($dir) {
+       $dh = @opendir($dir);
+       while ( $file = @readdir($dh) ) {
+               if ( $file != '.' || $file != '..') {
+                       @unlink($dir.$file);
+                       //if ( ! @unlink ( $dir . '/' . $obj ) ) deleteDir ( $dir . '/' . $obj, true )
+               }
+       }
+       @closedir ($dh);
+       if (@rmdir($dir))
+               return true;
+       else
+               return false;
+}
+
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/system_OcAtutor_class.php b/mods/atutor_opencaps/opencaps/include/classes/system_OcAtutor_class.php
new file mode 100755 (executable)
index 0000000..65d535f
--- /dev/null
@@ -0,0 +1,37 @@
+<?php\r
+/****************************************************************/\r
+/* OpenCaps Module                                             \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+class OcAtutor\r
+{\r
+       public static function putCaps($uri, $action, $id, $ccData)\r
+       {\r
+               if ($ccData!='The format of source Caption was not recognized.')\r
+               {\r
+                       //$uri = '../../service.php?';\r
+                       $uri .= '?';\r
+                       $ch = curl_init($uri);\r
+                       $encoded = 'id='.$id.'&action='.$action.'&cc='.''.urlencode($ccData).'';\r
+                       curl_setopt($ch, CURLOPT_POSTFIELDS,  $encoded);\r
+                       curl_setopt($ch, CURLOPT_HEADER, 0);\r
+                       curl_setopt($ch, CURLOPT_POST, 1);\r
+                       curl_exec($ch);\r
+                       curl_close($ch);\r
+                       if(OC_DEBUG_MODE_ON)\r
+                       {\r
+                               echo '<br/> Encoded Data sent to Server:<br/> '.$encoded.'<br/>';\r
+                       }\r
+               } // end putCaps\r
+       \r
+       } // end class\r
+}\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/system_class.php b/mods/atutor_opencaps/opencaps/include/classes/system_class.php
new file mode 100755 (executable)
index 0000000..2d320d1
--- /dev/null
@@ -0,0 +1,328 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+class system {
+       
+       public $system_id;
+       public $name;
+       private $type; 
+
+       public $base_url;       
+       private $get_url;
+       private $put_url;
+       
+       private $username; //optional
+       private $password; //optional
+       
+       
+       /* new system connection */
+       function __construct($system_id) {
+               global $systems;
+               
+               $_SESSION['rid'] = $system_id;
+               
+               /* load in system info from config file */
+               $this->system_id = $system_id;
+               $this->name = $systems[$system_id]['name'];
+               $this->base_url = $systems[$system_id]['url'];
+               $this->type = $systems[$system_id]['type'];\r
+
+               $this->username = $systems[$system_id]['username'];
+               $this->password = $systems[$system_id]['password'];
+                                               
+               $this->get_url = $this->base_url."?action=getMedia"; // url for receiving media info
+               $this->put_url = $this->base_url."?action=putCaps"; // url for sending captions back
+               $this->returnFormat = 'DFXP';
+       }
+       
+       function openProject($id) {
+               global $this_proj, $supported_ext;
+               
+               $media_info = $this->getMedia();
+               
+               if (!empty($media_info)) {
+
+                       //check if correct format
+                       $ext = explode(".", $media_info->mediaFile);
+                       $ext = end($ext);
+       
+                       if (!@in_array($ext, $supported_ext)) {
+                               $_SESSION['errors'][] = "Media file format not supported.";
+                               include(INCLUDE_PATH."basic_header.inc.php");
+                               include(INCLUDE_PATH."footer.inc.php");
+                               exit;
+                       }       
+                                       
+                       //populate project vars                                 
+                       $this_proj->name = $media_info->title;
+                       $this_proj->media_loc = $media_info->mediaFile;
+                       $this_proj->clip_collection = new clipCollection();     
+                               
+                       //import existing captions, if any                      
+                       if (!empty($media_info->captionFile))                   
+                               $this->importSystemCaptions($media_info->captionFile);  
+                                                                               
+                       //save working file
+                       $json = json_encode(get_object_vars($this_proj));
+                       $this_proj->saveJson($json, $this_proj->id);
+                       
+               } else {                        
+                       $_SESSION['errors'][] = "Could not open project - no response from server.";
+                       include(INCLUDE_PATH."basic_header.inc.php");
+                       include(INCLUDE_PATH."footer.inc.php");
+                       exit;
+               }       
+
+               // set user as guest
+               $_SESSION['valid_user'] = true;
+               $_SESSION['mid'] = '99999';
+                                                       
+               header('Location:editor.php');
+               exit;
+               
+               return;         
+       }
+       
+       
+       function getMedia() {
+               global $this_proj;
+                                               
+               //get json              
+               switch ($this->type) {
+                       case 'matterhorn':
+                               $media_info = json_decode($this->matterhornAuth('/opencaps/rest/'.$this_proj->id));
+                               
+                               //convert naming
+                               $media_info->mediaFile = $media_info->mediaURL;
+                               $media_info->captionFile = $media_info->DFXPURL;
+                               unset($media_info->mediaURL);
+                               unset($media_info->DFXPURL);
+                               break;
+                               
+                       case 'atutor':                          
+                               $media_info = json_decode(@file_get_contents($this->get_url.'&id='.$this_proj->id));
+                               break;
+                               
+                       default:
+                               $media_info = json_decode(@file_get_contents($this->get_url.'&id='.$this_proj->id));                            
+                               break;
+               }       
+               return $media_info;     
+       }               
+       
+       function putCaps($id, $format="SubRipSrt") {
+               global $this_proj, $base_url, $systems;
+                               
+               //convert captions to required format
+               $convert_url = $base_url.'conversion_service/index.php?cc_url='.urlencode('../projects/'.$_SESSION['pid'].'/opencaps.json').'&cc_result=0&cc_target='.$format.'&cc_name=noname.txt';
+               $formatted_captions = trim(@file_get_contents($convert_url));\r
+               \r
+               if (OC_DEBUG_MODE_ON)\r
+               {\r
+                       $ocAtDebugMsg = '*************************';\r
+                       $ocAtDebugMsg .= '<br/>';\r
+                       $ocAtDebugMsg .= '<b>putCaps() - class: system</b>';\r
+                       $ocAtDebugMsg .= '<br/>';\r
+                       $ocAtDebugMsg .= '<br/>ID: '.$_SESSION['pid'];\r
+                       $ocAtDebugMsg .= '<br/>';\r
+                       $ocAtDebugMsg .= '<br/>Conversion Service URL:<br/> '.$convert_url;\r
+                       $ocAtDebugMsg .= '<br/>';\r
+                       $ocAtDebugMsg .= '<br/>Caption Data:<br/>'.$formatted_captions;\r
+                       $ocAtDebugMsg .= '<br/>';\r
+                       $ocAtDebugMsg .= '<br/>Base Url: '.$base_url;\r
+                       $ocAtDebugMsg .= '<br/><br/>';\r
+                       $ocAtDebugMsg .= '*************************';\r
+                       $_SESSION['feedback'][] = $ocAtDebugMsg;\r
+               }\r
+               
+               //send captions
+               if (!empty($formatted_captions)) {
+                       
+                       switch ($this->type) {
+                               case 'matterhorn':
+                                       $uri = '/opencaps/rest/'.$this_proj->id.'/TimedText/';                  
+                                       $response = matterhornAuth($this->id, $uri, $formatted_captions);                                       
+                                       break;
+                                       
+                               default:\r
+                                       /*\r
+                                        * ANTO APPROACH\r
+                                        */\r
+                                       // load and call atutor class\r
+                                       include_once('system_OcAtutor_class.php');\r
+                                       OcAtutor::putCaps($systems[ACTIVE_SYSTEM]['url'],'putCaps',$_SESSION['pid'],$formatted_captions);\r
+                                       break;
+                       }       \r
+                       /*\r
+                        * ANTO: this stuff is too accurate, really tells nothing about the success to the action (e.g. was the file updated?):\r
+                        * \r
+                       */                       \r
+                       if (empty($response)) {
+                               $_SESSION['feedback'][] = "Successfully updated server.";                       
+                       } else {                                
+                               $_SESSION['errors'][] = "Could not update remote server.";
+                               
+                       }\r
+               
+                       
+                       
+               } else {
+                       $_SESSION['errors'][] = "Could not convert captions to required format.";
+               }
+               
+               return true;    
+               
+       }
+       
+       function importSystemCaptions($capfile) {               
+               global $base_url, $this_proj;           
+               
+               $ccollection = new clipCollection() ;
+               
+               //get captions          
+               switch ($this->type) {
+                       case 'matterhorn':
+                               $uri = substr($capfile, strlen($remote_systems[$_SESSION['rid']]['url']));
+                               $caps = matterhornAuth($_SESSION['rid'], $uri);
+                               $caption_file = INCLUDE_PATH.'../projects/'.$this->id.'/'.'captions.xml';
+                               @file_put_contents($caption_file, $caps);       
+                               break;
+                               
+                       case 'atutor':
+                               $caption_file = $capfile;
+                               break;
+                               
+                       default:
+                               break;
+               }       
+                                       
+               $convert_url = $base_url.'/conversion_service/?cc_url='.$caption_file.'&cc_result=0&cc_target=JSONcc&cc_name=noname.___';                                       
+               $json_captions = json_decode(@file_get_contents($convert_url));\r
+\r
+               if (!empty($json_captions) && $json_captions != "The format of source Caption was not recognized.") {                   
+                       
+                       foreach ($json_captions->captionCollection as $clip) {                          
+                               $this_clip = new clip($clip->inTime, $clip->outTime, trim($clip->caption));
+                               $ccollection->addClip($this_clip);
+                       }       
+
+                       $_SESSION['feedback'][] = "Captions imported successfully.";
+                                                                               
+               } else  {
+                       $_SESSION['errors'][] = "Problem with caption file - the format is incorrect, or unsupported.";
+               }               
+               
+               $this_proj->clip_collection = $ccollection;
+                       
+               //save reference file
+               $json = json_encode(get_object_vars($this_proj));               
+               $this_proj->saveJson($json, $this->id);         
+               return;
+
+       }                       
+       
+       
+       /* digest auth for matterhorn systems */
+       function matterhornAuth($uri, $content='') {
+               global $this_proj;
+                       
+           $username = $this->username;
+           $password = $this->password;
+                       
+               $ch = curl_init();
+           curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+           
+           curl_setopt($ch, CURLOPT_URL, $systems[$rid]['url'].$uri);
+           curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+           curl_setopt($ch, CURLOPT_USERPWD, $username.':'.$password);   
+               curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Requested-Auth: Digest")); 
+               
+           if ($content == "media") {
+               curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
+               
+               $temp_file = 'projects/'.$this_proj->id.'/media'; //use tempname();
+               $fh = fopen($temp_file, 'w');
+                       curl_setopt($ch, CURLOPT_FILE, $fh);
+                       curl_exec($ch);
+                       curl_close($ch);
+                       fclose($fh); 
+                       return $temp_file;
+                       
+           } else if (!empty($content)) {
+                   curl_setopt($ch, CURLOPT_POST, 1);
+               curl_setopt($ch, CURLOPT_POSTFIELDS, $content);   
+           }
+               
+           $response = curl_exec($ch);
+           $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 
+       
+           curl_close($ch);
+       
+               return $response;       
+       }
+
+       
+       /* list a system's available projects */
+       function printProjects($pageNum=1) {
+                               
+               //check if connected
+               if (!@file_get_contents($this->url)) {
+                       echo "Can't connect to remote server.";
+                       return;
+               }
+               
+               $projsPerPage = 20;
+
+               $uri = "/opencaps/rest/list/processed.json";    
+               $remote_media = json_decode(matterhornAuth($rid, $uri));        
+                               
+               $numrows = $remote_media->total;                
+               $maxPage = ceil($numrows/$projsPerPage);
+                               
+               $nav  = 'Page: ';               
+               for($page = 1; $page <= $maxPage; $page++) {
+                  if ($page == $pageNum) {
+                     $nav .= " $page "; 
+                  } else {
+                     $nav .= ' <a href="start_remote.php?r='.$rid.'&page='.$page.'">'.$page.'</a> ';
+                  }
+               }               
+               
+               if ($maxPage > 1)
+                       echo $nav."<br /><br />";
+               
+               $offset = ($pageNum - 1) * $projsPerPage;
+               
+               $uri = "/opencaps/rest/list/processed.json?count=90&startPage=".($pageNum-1);           
+                               
+               //$remote_media = $remote_systems[$rid]['url']."/opencaps/rest/list/processed.json?count=$projsPerPage&startPage=".($pageNum-1);
+               
+               $_SESSION['rid'] = $rid;                
+               $remote_media = json_decode(matterhornAuth($rid, $uri));                
+                               
+               if (!empty($remote_media->results)) {
+                       echo '<ul class="proj-list">';
+                       foreach($remote_media->results as $rm) {                        
+                               echo '<li><label><input type="radio" name="proj" value='.$rm->id.' /> '.$rm->title.'</label></li>';
+                       }
+                       echo '</ul>';
+                       echo "<div style='text-align:right;'><input type='submit' class='button' style='width:6em;margin-top:5px;' name='startopen' value='Submit' /></div>";
+               } else {
+                       echo "No projects yet.";
+               }
+       }       
+       
+}      
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/time_class.php b/mods/atutor_opencaps/opencaps/include/classes/time_class.php
new file mode 100755 (executable)
index 0000000..ba4c458
--- /dev/null
@@ -0,0 +1,209 @@
+<?php\r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Antonio Gamba Bari\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+class time {\r
+       public $ms;\r
+       public $formatted;\r
+\r
+       function __construct($t, $milli=true) {\r
+               if ($milli) {\r
+                       $this->ms = $t;\r
+                       $this->formatted = $this->timeFormatted($t);\r
+               } else {\r
+                       $this->ms = $this->timeMilli($t);\r
+                       $this->formatted = $t;\r
+               }\r
+       }\r
+       \r
+       \r
+       /*\r
+        * Functions written by Antonio for the conversion service\r
+        */\r
+       \r
+       /**\r
+        * Converts milliseconds time mark into 00:00:00:000 format (QT native format)\r
+        *\r
+        * @param int $miliSecTime A time format in miliseconds (e.g. 26070) 1000 = 1 second\r
+        * @return String $qtTimeString A QT mark in 00:00:00:000 format\r
+        */\r
+       static public function timeFormatted($miliSecTime)\r
+       {\r
+               $qtTimeString = '';\r
+               //  milliseconds holder \r
+               $myMiliSecTime = $miliSecTime;\r
+               \r
+               // basic constant knowledge, values in milliseconds\r
+               $anHour = 3600000; // 60*60*1000\r
+               $aMin = 60000; // 60*1000\r
+               $aSec = 1000; // 1 * 1000\r
+               \r
+               // temp holders for to store equivalent  hh, mm, sec, milisec\r
+               $myHours = 0;\r
+               $myMins = 0;\r
+               $mySec = 0;\r
+                               //$myMsec = 0; /// not using it.!!! \r
+               \r
+        // initialize timeArray\r
+               $timeArray = array();\r
+               $timeArray['hour'] = '';\r
+               $timeArray['min'] = '';\r
+               $timeArray['sec'] = '';\r
+               $timeArray['msec'] = '';                \r
+               \r
+               // parsing millisecodns QT time format 00:00:00.000\r
+\r
+               // is time mark at least an hour?\r
+               if($miliSecTime>=$anHour)\r
+               {\r
+                       // get only the int value\r
+                       $myHours = intval($miliSecTime/$anHour);\r
+\r
+                       // set the tot milliseconds left after removing number of hour(s) \r
+                       $myMiliSecTime -= ($myHours*$anHour);\r
+\r
+                       // set the current hours add leading 0 if needed\r
+                       if ($myHours<10)\r
+                       {\r
+                               $timeArray['hour'] = '0'.$myHours;\r
+                       } else {\r
+                               $timeArray['hour'] = ''.$myHours; \r
+                       }\r
+               } else {\r
+                       $timeArray['hour'] = '00';\r
+               }\r
+               \r
+               // Is time mark at least a minute? or rather, how many minutes are left?\r
+               if($myMiliSecTime>=$aMin-1)\r
+               {\r
+                       // get only the int value\r
+                       $myMins = intval($myMiliSecTime/$aMin);\r
+                                               \r
+                       // set the milliseconds left after removing total of minute(s) \r
+                       $myMiliSecTime -= ($myMins*$aMin);\r
+                       \r
+                       // set the current minutes and add leading 0 if needed\r
+                       if ($myMins<10)\r
+                       {\r
+                               $timeArray['min'] = '0'.$myMins;\r
+                       } else {\r
+                               $timeArray['min'] = ''. $myMins;\r
+                       }\r
+               } else {\r
+                       $timeArray['min'] = '00';\r
+               }\r
+               \r
+               // does it have seconds, or rather, how many seconds are left\r
+               if($myMiliSecTime>=$aSec)\r
+               {\r
+                       // get only the int value\r
+                       $mySec = intval($myMiliSecTime/$aSec);\r
+\r
+                       // set the milliseconds left after removing total of seconds\r
+                       $myMiliSecTime -= ($mySec*$aSec);\r
+                        \r
+                       // set the current number of seconds in time array, and add leading 0 if needed\r
+                       if ($mySec<10)\r
+                       {\r
+                               $timeArray['sec'] = '0'.$mySec;\r
+                       } else {\r
+                               $timeArray['sec'] = ''.$mySec;\r
+                       }\r
+               } else {\r
+                       $timeArray['sec'] = '00';\r
+               }\r
+               \r
+               // here a fix for adding leading zeros to milliseconds (e.g. 1=001, 10=010)  \r
+               if($myMiliSecTime>0)\r
+               {\r
+                       $tempMilliSec = 0 + (0.001 * $myMiliSecTime);\r
+                       $tempMilliSecArray = explode('.',$tempMilliSec); // split using '.' as separator\r
+                       $myMiliSecTimeString = ''. $tempMilliSecArray[1]; // get only the decimal value as a string\r
+\r
+                       // add one zero after the sting value if $myMiliSecTimeString has 2 character\r
+                       if (strlen($myMiliSecTimeString)==2)\r
+                       {\r
+                               $myMiliSecTimeString .= '0';\r
+                       } \r
+                       // add two zeros after the sting value if $myMiliSecTimeString has 1 character\r
+                       else if (strlen($myMiliSecTimeString)==1)\r
+                       {\r
+                               $myMiliSecTimeString .= '00';\r
+                       }\r
+                       \r
+                       // set  millisecodns  \r
+                       $timeArray['msec'] = $myMiliSecTimeString;\r
+               } else {\r
+                       $timeArray['msec'] = '000'; // no milliseconds left\r
+               } \r
+\r
+               // concatenate values\r
+               $qtTimeString = ''.$timeArray['hour'].':'.$timeArray['min'].':'.$timeArray['sec'].'.'.$timeArray['msec'];\r
+               \r
+               return $qtTimeString;\r
+               \r
+       } // end samiToQtTime()\r
+\r
+       /**\r
+        * Converts QT time to milliseconds format (Accepted by SAMI 1.0 and other CCformats)\r
+        * @return int $samiTime Time in miliseconds format; 1000 = 1. sec\r
+        * @param String $qtTime QT time Format; (e.g. "00:01:10.280")\r
+        */\r
+       static public function timeMilli($qtTime)\r
+       {\r
+           // Known patterns: 1, 2, or 3 decimals for millisecond definition\r
+               $pattern_time_000 = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3})\]";\r
+       $pattern_time_00 = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{2})\]";\r
+       $pattern_time_0 = "\[([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{1})\]";\r
+       $pattern_selected = '';\r
+               \r
+       // If pattern is 3 digit\r
+       if(preg_match('/'.$pattern_time_000.'/',$qtTime))\r
+           {\r
+               $pattern_selected = $pattern_time_000;\r
+           }\r
+           // If pattern is 2 digit\r
+       if(preg_match('/'.$pattern_time_00.'/',$qtTime))\r
+           {\r
+               $pattern_selected = $pattern_time_00;\r
+           }\r
+           // If pattern is 1 digit\r
+       if(preg_match('/'.$pattern_time_0.'/',$qtTime))\r
+           {\r
+               $pattern_selected = $pattern_time_0;\r
+           }\r
+           \r
+           $t1 = 0; // hours (e.g. [01])\r
+           $t2 = 0; // minutes (e.g. [12])\r
+           $t3 = 0; // seconds (e.g. [01.123])\r
+           \r
+           $qtTimeParts = explode(':',$qtTime); // split QT time mark into an array\r
+           \r
+           $t1 += $qtTimeParts[0]; // adding hours\r
+           $t2 += $qtTimeParts[1]; // adding minutes\r
+           $t3 += $qtTimeParts[2]; // adding seconds and miliseconds\r
+\r
+           // millisecond equivalents\r
+           $t1 *= 3600000; // 1 hour = 60*60*1000\r
+           $t2 *= 60000; // 1 minute = 60*1000\r
+           $t3 *= 1000; // 1 second = 1*1000 \r
+           \r
+           // get time in milliseconds\r
+           $samiTime = $t1 + $t2 + $t3;\r
+\r
+           return $samiTime;\r
+       \r
+       }       \r
+\r
+} \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/classes/user_class.php b/mods/atutor_opencaps/opencaps/include/classes/user_class.php
new file mode 100755 (executable)
index 0000000..84b063a
--- /dev/null
@@ -0,0 +1,125 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+class user {
+       public $id;
+       public $username;
+       public $name;
+       
+       public $preferences = Array();
+       public $valid;
+
+       public function __construct($id, $username) {
+               $this->id = $id;
+               
+               if ($id = 99999)
+                       $this->username = "guest";
+               else
+                       $this->username = $username;
+                       
+               $this->valid = false;
+               
+               //default $preferences
+       }
+       
+       public function login($username, $password) {
+               global $this_db;
+               $row = '';
+               $result = '';
+               
+               //check if user exists in db with this password
+               if (isset($username, $password)) {
+                       /*if (version_compare(PHP_VERSION, '5.1.0', '>=')) {
+                               session_regenerate_id(TRUE);
+                       }*/
+                       
+                       if ($username=="guest" && $password=="guest") {
+                               $this->valid    = true;
+                               $this->id               = '99999';
+                               $this->username = $username;
+                               
+                               $_SESSION['valid_user'] = true;
+                               $_SESSION['mid'] = $this->id;
+                               $_SESSION['username'] = $this->username;
+                               
+                               return;
+                       }
+                               
+               
+                       $username = addslashes($username);
+                       $password = addslashes($password);
+               
+                       //$sql = "SELECT member_id, login, SHA1(CONCAT(password, '-', '".DB_PASSWORD."')) AS pass FROM members WHERE login='$this_login' AND SHA1(CONCAT(password, '$_SESSION[token]'))='$this_password'";
+                       
+                       $sql = "SELECT member_id, login, password FROM members WHERE login='$username' AND password='$password'";
+                       $result = mysql_query($sql, $this_db->db);
+               
+                       if ($row = mysql_fetch_assoc($result)) {
+                               
+                               $this->valid    = true;
+                               $this->id               = intval($row['member_id']);
+                               $this->username = $row['login'];
+                               
+                               $_SESSION['mid'] = $this->id;
+                               $_SESSION['username'] = $this->username;
+                               $_SESSION['valid_user'] = true;
+                               
+                               $sql = "UPDATE members SET last_login=NOW() WHERE member_id=$_SESSION[mid]";
+                               mysql_query($sql, $this_db->db);
+               
+                               $_SESSION['feedback'][] = 'Successfully logged in.';
+       
+                       } else {
+                               $this->valid    = false;
+                               $this->id               = 0;
+                               $this->username = '';
+                               $_SESSION['errors'][] = 'Invalid login.';                               
+                       }
+                       header('Location:start.php');
+                       exit;
+               }               
+               
+               //create cookies
+       }               
+       
+       /* checks if a user is logged in and valid */
+       public function authenticate() {
+               if ($this->valid) {
+                       return true;            
+               } 
+                       
+               return false;
+       }
+       
+       public function logout() {
+               unset($_SESSION['valid_user']);
+               unset($_SESSION['member_id']);
+               unset($_SESSION['errors']);             
+               $_SESSION['feedback'][] = 'Successfully logged out.';
+               
+               header('Location: index.php');
+               exit;
+       }
+
+       public function savePrefs() {
+               
+       }
+       
+       public function getPrefs() {
+               
+       }
+       
+}
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/config.inc.php b/mods/atutor_opencaps/opencaps/include/config.inc.php
new file mode 100755 (executable)
index 0000000..dd248b3
--- /dev/null
@@ -0,0 +1,48 @@
+<?php\r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+/* edit with correct values and copy to /include/config.inc.php */\r
+\r
+\r
+/* general config */\r
+define('MAX_FILE_SIZE',        '10485760'); //10M\r
+define('DISABLE_LOCAL',        true);\r
+define('ACTIVE_SYSTEM', '1');\r
+\r
+/* mysql config */\r
+define('DB_USER',              '');\r
+define('DB_PASSWORD',  '');\r
+define('DB_HOST',              'localhost');\r
+define('DB_PORT',              '3306');\r
+define('DB_NAME',       'opencaps');\r
+define('ACTIVE_SYSTEM', '1');\r
+define('MODULE_MODE_ON', true);\r
+define('OC_DEBUG_MODE_ON', false);\r
+\r
+/*\r
+ * added by Anto\r
+ */\r
+if(!isset($_SESSION['atutor_base_url']))\r
+{\r
+       if(isset($_GET['athome']) && $_GET['athome']!='')\r
+       {\r
+               $_SESSION['atutor_base_url'] = $_GET['athome'];\r
+       } else {\r
+               $_SESSION['atutor_base_url'] = '';\r
+       }\r
+}\r
+$systems[1]['url'] = $_SESSION['atutor_base_url'].'/mods/AtOpenCaps/service.php';\r
+$systems[1]['name'] = 'atutor';\r
+$systems[1]['type'] = 'atutor';\r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/footer.inc.php b/mods/atutor_opencaps/opencaps/include/footer.inc.php
new file mode 100755 (executable)
index 0000000..2bd0eea
--- /dev/null
@@ -0,0 +1,30 @@
+<?php 
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+?>
+
+               <br style="clear:both;" />
+       <div id="footer">
+               
+       </div>
+</div>
+
+<?php 
+       /*echo 'SESSION VARS<pre>';
+       print_r($_SESSION); 
+       echo '</pre>'; */
+?>
+
+       
+</body>
+</html>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/header.inc.php b/mods/atutor_opencaps/opencaps/include/header.inc.php
new file mode 100755 (executable)
index 0000000..5645040
--- /dev/null
@@ -0,0 +1,99 @@
+<?php 
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+?>
+
+<!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=utf-8" />
+       <meta http-equiv="content-script-type" content="text/javascript" />
+       
+       <title>OpenCaps - An online inclusive media editor</title>
+       <link rel="stylesheet" href="styles.css" type="text/css" />
+       <?php
+       /* browser detection for css */
+       $userAgent = $_SERVER['HTTP_USER_AGENT'];
+       
+       //Firefox on Win
+       if (preg_match('/firefox/i', $userAgent) && preg_match('/windows|win32/i', $userAgent)) { 
+               echo '<link rel="stylesheet" href="styles_ff.css" type="text/css" />';
+               
+       //IE
+       } else if (preg_match('/msie/i', $userAgent)) {
+               echo '<link rel="stylesheet" href="styles_ie.css" type="text/css" />';                  
+       
+       //Opera
+       } else if (preg_match('/opera/i', $userAgent)) {
+               echo '<link rel="stylesheet" href="styles_opera.css" type="text/css" />';                       
+       } 
+       ?>
+
+       <script language="javascript" type="text/javascript" src="js/AC_QuickTime.js"></script>
+       <script language="javascript" type="text/javascript" src="js/jquery/jquery-1.3.2.min.js"></script>
+       <script language="javascript" type="text/javascript" src="js/jquery/ui.core.js"></script>
+       <script language="javascript" type="text/javascript" src="js/jquery/ui.slider.js"></script>
+       <script language="javascript" type="text/javascript" src="js/json/json2.js"></script>
+       
+       <script language="javascript" type="text/javascript" src="js/utils.js"></script>
+
+</head>
+
+<body>
+<div id="container">           
+       <h1 style="margin:10px; float:left;"><img src="images/logo.png" alt="OpenCaps - a free, online caption editor" title="OpenCaps - a free, online caption editor" style="margin-top:7px;" /></h1>
+       
+       <div style="float:right; margin-top:5px; margin-right:10px;">
+               <span style="font-style:italic;"><?php echo $this_proj->name; ?></span>
+               <div id="last-saved"></div>
+       </div>
+
+       <div id="menubar">              
+               <ul>
+                       <li id="editor-tab"><a href="editor.php"><img style="margin-bottom:-3px;" src="images/application_edit.png" alt="arrow pointing right" /> Caption</a></li>
+                       <?php if(!DISABLE_LOCAL && !isset($_SESSION['rid'])) { ?><li id="preview-tab"><a href="preview.php"><img src="images/arrow_right.png" alt="arrow pointing right" style="margin-bottom:-3px;" /> Preview</a></li><?php } ?>
+                       <li id="settings-tab"><a href="settings.php"><img style="margin-bottom:-3px;" src="images/page_gear.png" alt="" /> Settings</a></li>
+                       <li id="export-tab"><a href="export.php"><img style="margin-bottom:-3px;" src="images/application_put.png" alt="" /> Finish</a></li>
+                       
+                       <?php if (!isset($_SESSION['rid'])) { ?>                        
+                       <!--  li id="close-tab"><a href="start.php"><img style="margin-bottom:-3px;" src="images/cross.png" alt="" /> Close</a></li -->
+                       <?php } ?>
+
+               </ul>
+       </div>
+       <?php 
+       if (isset($_SESSION['errors'])) {
+               echo '<div class="error"><strong>Error:</strong><br />';
+               foreach ($_SESSION['errors'] as $errmsg) {
+                       echo $errmsg.'<br />';  
+               }
+               echo '</div>';
+               unset($_SESSION['errors']);
+       }
+       if (isset($_SESSION['feedback'])) {
+               echo '<div class="feedback"><strong>Feedback:</strong><br />';
+               foreach ($_SESSION['feedback'] as $fbmsg) {
+                       echo $fbmsg.'<br />';   
+               }
+               echo '</div>';
+               unset($_SESSION['feedback']);
+       }
+       if (isset($_SESSION['notices'])) {
+               echo '<div class="notice"><strong>Notice:</strong><br />';
+               foreach ($_SESSION['notices'] as $nmsg) {
+                       echo $nmsg.'<br />';    
+               }
+               echo '</div>';
+               unset($_SESSION['notices']);
+       }       
+       ?>      
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/index.html b/mods/atutor_opencaps/opencaps/include/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/include/matterhorn.inc.php b/mods/atutor_opencaps/opencaps/include/matterhorn.inc.php
new file mode 100755 (executable)
index 0000000..8c98d21
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2010 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+if (!defined('INCLUDE_PATH')) {
+       define('INCLUDE_PATH', 'include/');
+}
+
+
+/* digest auth */
+function matterhornAuth($rid, $uri, $content='') {
+       global $remote_systems, $this_proj;
+               
+    $username = $remote_systems[$rid]['username'];
+    $password = $remote_systems[$rid]['password'];
+               
+       $ch = curl_init();
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    
+    curl_setopt($ch, CURLOPT_URL, $remote_systems[$rid]['url'].$uri);
+    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+    curl_setopt($ch, CURLOPT_USERPWD, $username.':'.$password);   
+       curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Requested-Auth: Digest")); 
+       
+    if ($content == "media") {
+       curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
+       
+       $temp_file = 'projects/'.$this_proj->id.'/media'; //use tempname();
+       $fh = fopen($temp_file, 'w');
+               curl_setopt($ch, CURLOPT_FILE, $fh);
+               curl_exec($ch);
+               curl_close($ch);
+               fclose($fh); 
+               return $temp_file;
+               
+    } else if (!empty($content)) {
+           curl_setopt($ch, CURLOPT_POST, 1);
+       curl_setopt($ch, CURLOPT_POSTFIELDS, $content);   
+    }
+        
+    $response = curl_exec($ch);
+    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 
+
+    curl_close($ch);
+
+       return $response;
+
+}
+
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/vitals.inc.php b/mods/atutor_opencaps/opencaps/include/vitals.inc.php
new file mode 100755 (executable)
index 0000000..319a76d
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2010 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+if (!defined('INCLUDE_PATH')) {
+       define('INCLUDE_PATH', 'include/');
+}
+
+require(INCLUDE_PATH.'classes/user_class.php');
+require(INCLUDE_PATH.'classes/db_class.php');
+require(INCLUDE_PATH.'classes/project_class.php');
+require(INCLUDE_PATH.'classes/clip_class.php');
+require(INCLUDE_PATH.'classes/caption_class.php');
+require(INCLUDE_PATH.'classes/time_class.php');
+require(INCLUDE_PATH.'classes/system_class.php');
+\r
+@session_start();
+
+require(INCLUDE_PATH.'config.inc.php');
+
+
+$supported_ext = array('mov', 'qt', 'mp4', 'm4v', 'mpg', 'mpeg', 'dv', 'mp3', 'wav', 'aac', 'midi', 'au', 'avi', 'aiff');
+$pub_pages = array("index.php", "login.php", "register.php", "start.php", "start_remote.php", "workflow.php");
+
+$page = explode('/',$_SERVER['PHP_SELF']); 
+$page = end($page);
+
+$base_url = substr('http://'.$_SERVER["SERVER_NAME"].$_SERVER["SCRIPT_NAME"], 0, -(strlen($page)));\r
+
+function my_add_null_slashes( $string ) {
+    return mysql_real_escape_string(stripslashes($string));
+}
+function my_null_slashes($string) {
+       return $string;
+}
+if ( get_magic_quotes_gpc() ) {
+       $addslashes   = 'my_add_null_slashes';
+       $stripslashes = 'stripslashes';
+} else {
+       $addslashes   = 'mysql_real_escape_string';
+       $stripslashes = 'my_null_slashes';
+}
+
+if (get_magic_quotes_gpc()) {
+       $addslashes   = 'my_add_null_slashes';
+       $stripslashes = 'my_null_slashes';
+} else {
+       $addslashes   = 'addslashes';
+       $stripslashes = 'stripslashes';
+}
+
+
+/* 
+ * check for valid user 
+ */
+
+$this_user = new user($_SESSION['mid'], $_SESSION['username']);
+
+if (!in_array($page, $pub_pages) && (!isset($_SESSION['valid_user']) || !$_SESSION['valid_user'] || !isset($_SESSION['mid']) || !$_SESSION['mid']) ) {
+       header("Location:start.php");
+       exit;
+}
+
+/* check if system connection */
+if (ACTIVE_SYSTEM)
+       $this_system = new system(ACTIVE_SYSTEM);               
+
+
+/* 
+ * connect to db 
+ */
+if (!isset($this_db) && !DISABLE_LOCAL) 
+       $this_db = new database();      
+
+       
+/*
+ * load project
+ */
+if (isset($_SESSION['pid']) || $page=="workflow.php") {
+       $this_proj = new project();
+       $this_proj->owner = &$this_user;
+       
+       if (isset($_SESSION['pid']))    
+               $this_proj->id = $_SESSION['pid'];
+       
+       if (!empty($this_proj->id))
+               setVals();      
+}
+
+function setVals() {
+       global $this_proj, $stripslashes;
+       
+       $json = json_decode($stripslashes(@file_get_contents(INCLUDE_PATH.'../projects/'.$_SESSION['pid'].'/opencaps.json')));
+       
+       $this_proj->id = $json->id;
+       $this_proj->name = $json->name;
+       //$this_proj->prefs = $json->prefs;
+
+       $this_proj->media_loc = $json->media_loc; 
+       $this_proj->media_height = $json->media_height;
+       $this_proj->media_width = $json->media_width;
+       $this_proj->duration = $json->duration;
+       $this_proj->layout = $json->layout;
+       
+       $this_proj->caption_loc = $json->caption_loc;
+       $this_proj->clip_collection = $json->clip_collection;
+
+}
+
+/* 
+ * check for valid project 
+if ($page != "index.php" && $page != "login.php" && $page != "logout.php" && $page != "register.php" && $page != "start.php" && $page != "adminTasks.php") { 
+       if (!isset($_SESSION['pid']) && empty($_SESSION['pid'])) {
+               echo "Project not loaded.";
+               exit;
+       }
+} 
+*/
+
+
+//check if using firefox
+/*if(!strstr($_SERVER['HTTP_USER_AGENT'], "Firefox")) {
+       $_SESSION['errors'][] = "At this time, Capscribe Web requires a Firefox browser.";
+       include(INCLUDE_PATH.'basic_header.inc.php');
+       include(INCLUDE_PATH.'footer.inc.php'); 
+       exit;
+}*/
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/include/workflow.php b/mods/atutor_opencaps/opencaps/include/workflow.php
new file mode 100755 (executable)
index 0000000..18111b8
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+
+/*
+ * This file receives a request from the js and processes it using existing classes.
+ * It's the AJAX-request manager. Should it be a class too?
+ * 
+ * everything here should call object functions. no real code here.
+ * 
+ */
+
+define('INCLUDE_PATH', '');
+require(INCLUDE_PATH.'vitals.inc.php');
+
+/* get a project loaded into the system: start new, open existing, load chosen */
+if ($_GET['task'] == "print_projs") {
+       if (isset($_GET['page']))       
+               $this_proj->printUserProjects($_GET['page']);
+       else
+               $this_proj->printUserProjects(1);
+       
+} else if ($_GET['task'] == "print_projs_remote") {    
+       if (isset($_GET['page']))
+               $this_system->printProjects($_GET['page']);
+       else
+               $this_system->printProjects();
+} else if ($_GET['task'] == "open_proj") {
+       $this_proj->open($_GET['pid']);
+
+} else if ($_GET['task'] == "open_proj_remote") {
+       $this_proj->openRemote($_GET['pid']);
+       
+} else if ($_GET['task'] == "proj_delete") {
+       $this_proj->delete($_GET['pid']);
+} 
+
+
+/*
+ * load json file into a project
+ */
+if ($_GET['task'] == 'get_json') {
+       $json_path = '../projects/'.$this_proj->id.'/';
+       echo $stripslashes(@file_get_contents($json_path.'opencaps.json'));
+       
+/*
+ * save project into json file
+ */    
+} else if ($_POST['task'] == 'save_json') {
+       $this_proj->saveJson($_POST['json'], $_POST['pid']);    
+       
+/*
+ * preview - create smil & qttext files based on layout
+ */    
+} else if ($_GET['task'] == "preview") {
+       $this_proj->preview($_GET['layout']);
+       
+/* export */   
+} else if ($_GET['task'] == "export") {
+       $exfile = $this_proj->exportCaption($_GET['format']);
+       export_file($exfile);
+
+/* start tabs */
+} else if ($_GET['task'] == "get_tabs") {
+       
+       if (isset($systems)) { 
+               echo '<ul>';
+               if(!DISABLE_LOCAL)              
+                       echo '<li id="home"><a href="start.php">Home</a></li>'; 
+                       
+               if (ACTIVE_SYSTEM)      
+                       echo'<li id="remote-'.ACTIVE_SYSTEM.'"><a href="start_remote.php?r='.ACTIVE_SYSTEM.'">'.$systems[ACTIVE_SYSTEM]['name'].'</a></li>';
+                       
+       /*      foreach ($systems as $key=>$remote) {
+                       echo'<li id="remote-'.$key.'"><a href="start_remote.php?r='.$key.'">'.$remote['name'].'</a></li>';
+               }
+       */      
+               echo '</ul>';           
+       }  
+}
+
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/index.php b/mods/atutor_opencaps/opencaps/index.php
new file mode 100755 (executable)
index 0000000..baa8e1e
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+define('INCLUDE_PATH', 'include/');
+require(INCLUDE_PATH.'vitals.inc.php');
+
+//remote system request - send captions back
+if (isset($_GET['id'])) {
+       $this_proj->id = $_GET['id'];
+       $_SESSION['pid'] = $this_proj->id;
+       
+       //check which system is pinging opencaps
+       if (isset($systems) && ACTIVE_SYSTEM != '') {
+               
+               /*$ref_url = substr($_SERVER['HTTP_REFERER'], 0, -(strlen($_SERVER['SCRIPT_FILENAME'])));
+               
+               echo $_SERVER['HTTP_REFERER'].' '.$_SERVER['HTTP_HOST'].'<br>';
+               echo $systems[2]['url'].' '.$ref_url;
+               exit; 
+               
+               foreach ($systems as $key=>$sys) {                      
+                       if (strpos($sys['url'], getenv("HTTP_REFERER"))) {
+                               $sys_id = $key;
+                       }
+               }*/
+               
+               $this_system->openProject($this_proj->id);
+                       
+
+       } else {
+               $_SESSION['errors'][] = "External system URL not recognised. Make sure to add this system to the OpenCaps config file.";                
+               header("Location:start.php");
+               exit;
+       }
+       //$_SESSION['rid'] = $rid;
+       //$this_proj->openRemote($this_proj->id, true);
+
+} else {
+       header("Location:start.php");
+       exit;
+}
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/install/config_template.php b/mods/atutor_opencaps/opencaps/install/config_template.php
new file mode 100755 (executable)
index 0000000..7e77f23
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+/* edit with correct values and copy to /include/config.inc.php */
+
+
+/* general config */
+define('MAX_FILE_SIZE',        '10485760'); //10M
+define('DISABLE_LOCAL',        false);
+define('ACTIVE_SYSTEM', '');
+
+
+/* mysql config */
+define('DB_USER',              'root');
+define('DB_PASSWORD',  'password');
+define('DB_HOST',              'localhost');
+define('DB_PORT',              '3306');
+define('DB_NAME',       'opencaps');
+
+/* matterhorn config */
+/*
+$systems[0]['url'] = 'http://localhost:8080';
+$systems[0]['name'] = 'Matterhorn Local';
+$systems[0]['username'] = 'username';
+$systems[0]['password'] = 'password';
+
+$systems[1]['url'] = 'http://nightly.opencastproject.org';
+$systems[1]['name'] = 'Matterhorn Nightly';
+$systems[1]['username'] = 'username';
+$systems[1]['password'] = 'password';
+*/
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/install/index.html b/mods/atutor_opencaps/opencaps/install/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/install/oc_schema.sql b/mods/atutor_opencaps/opencaps/install/oc_schema.sql
new file mode 100755 (executable)
index 0000000..138f728
--- /dev/null
@@ -0,0 +1,31 @@
+-- --------------------------------------------------------\r
+\r
+--\r
+-- Table structure for table `members`\r
+--\r
+\r
+CREATE TABLE IF NOT EXISTS `members` (\r
+  `member_id` mediumint(9) unsigned NOT NULL AUTO_INCREMENT,\r
+  `login` varchar(20) NOT NULL,\r
+  `password` varchar(40) NOT NULL,\r
+  `name` varchar(255) NOT NULL,\r
+  `email` varchar(100) NOT NULL,\r
+  `last_login` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r
+  PRIMARY KEY (`member_id`)\r
+) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;\r
+\r
+-- --------------------------------------------------------\r
+\r
+--\r
+-- Table structure for table `projects`\r
+--\r
+\r
+CREATE TABLE IF NOT EXISTS `projects` (\r
+  `project_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\r
+  `member_id` mediumint(8) unsigned NOT NULL,\r
+  `name` varchar(255) NOT NULL,\r
+  `video_file` varchar(255) NOT NULL,\r
+  `layout_preset` tinyint(3) unsigned NOT NULL,\r
+  `last_accessed` datetime NOT NULL,\r
+  PRIMARY KEY (`project_id`)\r
+) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;\r
diff --git a/mods/atutor_opencaps/opencaps/js/AC_QuickTime.js b/mods/atutor_opencaps/opencaps/js/AC_QuickTime.js
new file mode 100755 (executable)
index 0000000..b40e932
--- /dev/null
@@ -0,0 +1 @@
+/*\r\rFile: AC_QuickTime.js\r\rAbstract: This file contains functions to generate OBJECT and EMBED tags for QuickTime content.\r\rVersion: <1.2>\r\rDisclaimer: IMPORTANT:  This Apple software is supplied to you by Apple\rComputer, Inc. ("Apple") in consideration of your agreement to the\rfollowing terms, and your use, installation, modification or\rredistribution of this Apple software constitutes acceptance of these\rterms.  If you do not agree with these terms, please do not use,\rinstall, modify or redistribute this Apple software.\r\rIn consideration of your agreement to abide by the following terms, and\rsubject to these terms, Apple grants you a personal, non-exclusive\rlicense, under Apple's copyrights in this original Apple software (the\r"Apple Software"), to use, reproduce, modify and redistribute the Apple\rSoftware, with or without modifications, in source and/or binary forms;\rprovided that if you redistribute the Apple Software in its entirety and\rwithout modifications, you must retain this notice and the following\rtext and disclaimers in all such redistributions of the Apple Software. \rNeither the name, trademarks, service marks or logos of Apple Computer,\rInc. may be used to endorse or promote products derived from the Apple\rSoftware without specific prior written permission from Apple.  Except\ras expressly stated in this notice, no other rights or licenses, express\ror implied, are granted by Apple herein, including but not limited to\rany patent rights that may be infringed by your derivative works or by\rother works in which the Apple Software may be incorporated.\r\rThe Apple Software is provided by Apple on an "AS IS" basis.  APPLE\rMAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION\rTHE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS\rFOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND\rOPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.\r\rIN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL\rOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\rSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\rINTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,\rMODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED\rAND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),\rSTRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE\rPOSSIBILITY OF SUCH DAMAGE.\r\rCopyright Ã¥Â© 2006-2007 Apple Computer, Inc., All Rights Reserved\r\r*/ \r\r/*\r * This file contains functions to generate OBJECT and EMBED tags for QuickTime content. \r */\r\r/************** LOCALIZABLE GLOBAL VARIABLES ****************/\r\rvar gArgCountErr =     'The "%%" function requires an even number of arguments.'\r                              +       '\nArguments should be in the form "atttributeName", "attributeValue", ...';\r\r/******************** END LOCALIZABLE **********************/\r\rvar gTagAttrs                              = null;\rvar gQTGeneratorVersion         = 1.2;\rvar gQTBehaviorID                        = "qt_event_source";\rvar gQTEventsEnabled               = false;\r\rfunction AC_QuickTimeVersion()        { return gQTGeneratorVersion; }\r\rfunction _QTComplain(callingFcnName, errMsg)\r{\r    errMsg = errMsg.replace("%%", callingFcnName);\r     alert(errMsg);\r}\r\rfunction _QTIsMSIE()\r{\r    var ua = navigator.userAgent.toLowerCase();\r       var msie = /msie/.test(ua) && !/opera/.test(ua);\r\r      return msie;\r}\r\r\rfunction _QTGenerateBehavior()\r{\r      return objTag = '<!--[if IE]>'\r                          + '<object id="' + gQTBehaviorID + '" classid="clsid:CB927D12-4FF7-4a9e-A169-56E4B8A75598"></object>'\r                          + '<![endif]-->';\r}\r\rfunction _QTPageHasBehaviorObject(callingFcnName, args)\r{\r        var haveBehavior = false;\r      var objects = document.getElementsByTagName('object');\r \r       for ( var ndx = 0, obj; obj = objects[ndx]; ndx++ )\r    {\r              if ( obj.getAttribute('classid') == "clsid:CB927D12-4FF7-4a9e-A169-56E4B8A75598" )\r             {\r                      if ( obj.getAttribute('id') == gQTBehaviorID )\r                         haveBehavior = false;\r                  break;\r         }\r      }\r\r     return haveBehavior;\r}\r\r\rfunction _QTShouldInsertBehavior()\r{\r  var             shouldDo = false;\r\r     if ( gQTEventsEnabled && _QTIsMSIE() && !_QTPageHasBehaviorObject() )\r          shouldDo = true;\r       \r       return shouldDo;\r}\r\r\rfunction _QTAddAttribute(prefix, slotName, tagName)\r{\r     var             value;\r\r        value = gTagAttrs[prefix + slotName];\r  if ( null == value )\r           value = gTagAttrs[slotName];\r\r  if ( null != value )\r   {\r              if ( 0 == slotName.indexOf(prefix) && (null == tagName) )\r                      tagName = slotName.substring(prefix.length); \r          if ( null == tagName ) \r                        tagName = slotName;\r            return ' ' + tagName + '="' + value + '"';\r     }\r      else\r           return "";\r}\r\rfunction _QTAddObjectAttr(slotName, tagName)\r{\r   // don't bother if it is only for the embed tag\r        if ( 0 == slotName.indexOf("emb#") )\r           return "";\r\r    if ( 0 == slotName.indexOf("obj#") && (null == tagName) )\r              tagName = slotName.substring(4); \r\r     return _QTAddAttribute("obj#", slotName, tagName);\r}\r\rfunction _QTAddEmbedAttr(slotName, tagName)\r{\r    // don't bother if it is only for the object tag\r       if ( 0 == slotName.indexOf("obj#") )\r           return "";\r\r    if ( 0 == slotName.indexOf("emb#") && (null == tagName) )\r              tagName = slotName.substring(4); \r\r     return _QTAddAttribute("emb#", slotName, tagName);\r}\r\r\rfunction _QTAddObjectParam(slotName, generateXHTML)\r{\r   var             paramValue;\r    var             paramStr = "";\r var             endTagChar = (generateXHTML) ? ' />' : '>';\r\r   if ( -1 == slotName.indexOf("emb#") )\r  {\r              // look for the OBJECT-only param first. if there is none, look for a generic one\r              paramValue = gTagAttrs["obj#" + slotName];\r             if ( null == paramValue )\r                      paramValue = gTagAttrs[slotName];\r\r             if ( 0 == slotName.indexOf("obj#") )\r                   slotName = slotName.substring(4); \r     \r               if ( null != paramValue )\r                      paramStr = '<param name="' + slotName + '" value="' + paramValue + '"' + endTagChar;\r   }\r\r     return paramStr;\r}\r\rfunction _QTDeleteTagAttrs()\r{\r     for ( var ndx = 0; ndx < arguments.length; ndx++ )\r     {\r              var attrName = arguments[ndx];\r         delete gTagAttrs[attrName];\r            delete gTagAttrs["emb#" + attrName];\r           delete gTagAttrs["obj#" + attrName];\r   }\r}\r\r\r// generate an embed and object tag, return as a string\rfunction _QTGenerate(callingFcnName, generateXHTML, args)\r{\r      // is the number of optional arguments even?\r   if ( args.length < 4 || (0 != (args.length % 2)) )\r     {\r              _QTComplain(callingFcnName, gArgCountErr);\r             return "";\r     }\r      \r       // allocate an array, fill in the required attributes with fixed place params and defaults\r     gTagAttrs = new Object();\r      gTagAttrs["src"] = args[0];\r    gTagAttrs["width"] = args[1];\r  gTagAttrs["height"] = args[2];\r gTagAttrs["classid"] = "clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B";\r           //Impportant note: It is recommended that you use this exact classid in order to ensure a seamless experience for all viewers\r  gTagAttrs["pluginspage"] = "http://www.apple.com/quicktime/download/";\r\r        // set up codebase attribute with specified or default version before parsing args so\r  //  anything passed in will override\r   var activexVers = args[3]\r      if ( (null == activexVers) || ("" == activexVers) )\r            activexVers = "7,3,0,0";\r       gTagAttrs["codebase"] = "http://www.apple.com/qtactivex/qtplugin.cab#version=" + activexVers;\r\r var     attrName,\r              attrValue;\r\r    // add all of the optional attributes to the array\r     for ( var ndx = 4; ndx < args.length; ndx += 2)\r        {\r              attrName = args[ndx].toLowerCase();\r            attrValue = args[ndx + 1];\r\r            gTagAttrs[attrName] = attrValue;\r\r              if ( ("postdomevents" == attrName) && (attrValue.toLowerCase() != "false") )\r           {\r                      gQTEventsEnabled = true;\r                       if ( _QTIsMSIE() )\r                             gTagAttrs["obj#style"] = "behavior:url(#" + gQTBehaviorID + ")";\r               }\r      }\r\r     // init both tags with the required and "special" attributes\r   var objTag =  '<object '\r                                       + _QTAddObjectAttr("classid")\r                                  + _QTAddObjectAttr("width")\r                                    + _QTAddObjectAttr("height")\r                                   + _QTAddObjectAttr("codebase")\r                                 + _QTAddObjectAttr("name")\r                                     + _QTAddObjectAttr("id")\r                                       + _QTAddObjectAttr("tabindex")\r                                 + _QTAddObjectAttr("hspace")\r                                   + _QTAddObjectAttr("vspace")\r                                   + _QTAddObjectAttr("border")\r                                   + _QTAddObjectAttr("align")\r                                    + _QTAddObjectAttr("class")\r                                    + _QTAddObjectAttr("title")\r                                    + _QTAddObjectAttr("accesskey")\r                                        + _QTAddObjectAttr("noexternaldata")\r                                   + _QTAddObjectAttr("obj#style")\r                                        + '>'\r                                  + _QTAddObjectParam("src", generateXHTML);\r     var embedTag = '<embed '\r                                       + _QTAddEmbedAttr("src")\r                                       + _QTAddEmbedAttr("width")\r                                     + _QTAddEmbedAttr("height")\r                                    + _QTAddEmbedAttr("pluginspage")\r                                       + _QTAddEmbedAttr("name")\r                                      + _QTAddEmbedAttr("id")\r                                        + _QTAddEmbedAttr("align")\r                                     + _QTAddEmbedAttr("tabindex");\r\r        // delete the attributes/params we have already added\r  _QTDeleteTagAttrs("src","width","height","pluginspage","classid","codebase","name","tabindex",\r                                 "hspace","vspace","border","align","noexternaldata","class","title","accesskey","id","style");\r\r        // and finally, add all of the remaining attributes to the embed and object\r    for ( var attrName in gTagAttrs )\r      {\r              attrValue = gTagAttrs[attrName];\r               if ( null != attrValue )\r               {\r                      embedTag += _QTAddEmbedAttr(attrName);\r                 objTag += _QTAddObjectParam(attrName, generateXHTML);\r          }\r      } \r\r    // end both tags, we're done\r   return objTag + embedTag + '></em' + 'bed></ob' + 'ject' + '>';\r}\r\r\r// return the object/embed as a string\rfunction QT_GenerateOBJECTText()\r{\r  var     txt = _QTGenerate("QT_GenerateOBJECTText", false, arguments);\r  if ( _QTShouldInsertBehavior() )\r               txt = _QTGenerateBehavior() + txt;\r     return txt;\r}\r\rfunction QT_GenerateOBJECTText_XHTML()\r{\r        var     txt = _QTGenerate("QT_GenerateOBJECTText_XHTML", true, arguments);\r     if ( _QTShouldInsertBehavior() )\r               txt = _QTGenerateBehavior() + txt;\r     return txt;\r}\r\rfunction QT_WriteOBJECT()\r{\r     var     txt = _QTGenerate("QT_WriteOBJECT", false, arguments);\r if ( _QTShouldInsertBehavior() )\r               document.writeln(_QTGenerateBehavior());\r       document.writeln(txt);\r}\r\rfunction QT_WriteOBJECT_XHTML()\r{\r    var     txt = _QTGenerate("QT_WriteOBJECT_XHTML", true, arguments);\r    if ( _QTShouldInsertBehavior() )\r               document.writeln(_QTGenerateBehavior());\r       document.writeln(txt);\r}\r\rfunction QT_GenerateBehaviorOBJECT()\r{\r       return _QTGenerateBehavior();\r}\r\rfunction QT_ReplaceElementContents()\r{\r        var element = arguments[0];\r    var args = [];\r\r        // copy all other arguments we want to pass through to the fcn\r for ( var ndx = 1; ndx < arguments.length; ndx++ )\r             args.push(arguments[ndx]);\r\r    var     txt = _QTGenerate("QT_ReplaceElementContents", false, args);\r   if ( txt.length > 0 )\r          element.innerHTML = txt;\r}\r\r\rfunction QT_ReplaceElementContents_XHTML()\r{\r      var element = arguments[0];\r    var args = [];\r\r        // copy all other arguments we want to pass through to the fcn\r for ( var ndx = 1; ndx < arguments.length; ndx++ )\r             args.push(arguments[ndx]);\r\r    var     txt = _QTGenerate("QT_ReplaceElementContents_XHTML", true, args);\r      if ( txt.length > 0 )\r          element.innerHTML = txt;\r}\r\r
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/editor.js b/mods/atutor_opencaps/opencaps/js/editor.js
new file mode 100755 (executable)
index 0000000..677a01e
--- /dev/null
@@ -0,0 +1,883 @@
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+/* GLOBALS */\r
+\r
+var proj = proj || {};\r
+\r
+var MIN_CLIP_DUR = 400;\r
+\r
+var clip_playing = false;\r
+\r
+var movie = movie || {};\r
+var clip = clip || {};\r
+var movieObj = movieObj || {};\r
+\r
+num_clips = 0;\r
+clips = new Array();\r
+\r
+this_location = new Object;\r
+\r
+var json;\r
+var inClip;\r
+\r
+\r
+/* ****** */\r
+tab = 'clips';\r
+lastplay = 0;\r
+new_flag = 0;\r
+clocktimer = 0;\r
+curTime = 0;\r
+clipTime = 0;\r
+curClip = 0;\r
+curIn = 0;\r
+lastLoc = 1;\r
+\r
+pace = 0;\r
+timer = 0;\r
+numclips = 0;\r
+marker = "";\r
+clip_marker = "";\r
+\r
+//set values in seconds\r
+onemin = 60;\r
+onehr  = onemin*60;\r
+\r
+/* clip vars */\r
+temp_in = 0;\r
+temp_out = 0;\r
+temp_caps = '';\r
+dur = 0;\r
+extend = false;\r
+\r
+\r
+/*************************************** initialize */\r
+\r
+$(document).ready(function () {\r
+       $("#movie-controls").css("visibility", "hidden");\r
+       $("#clip-controls").css("visibility", "hidden");\r
+       $("#make-clip").css("visibility", "hidden");\r
+       $("#clip-info").css("visibility", "hidden");\r
+\r
+       $.get("include/workflow.php", { task: 'get_json' }, function(json) {\r
+               if (json) {                     \r
+                       proj = JSON.parse(json);\r
+                       startEditor();\r
+               }\r
+       });\r
+       \r
+       $("#caption-text").keyup( function(event) {             \r
+               //if ($("#caption-text").text() != this_location.caption_text) {\r
+                       $("#makeclip").removeAttr("disabled");\r
+                       temp_caps = 1;\r
+               //}\r
+       });\r
+});\r
+\r
+\r
+function confirmDelete(clipnum) {\r
+       if (confirm("Are you sure you want to delete Clip "+clipnum+"?")) {\r
+               deleteClip(clipnum);\r
+       }\r
+}\r
+\r
+function startEditor() {\r
+       movieObj = document.mymovie;\r
+       \r
+       //register listeners\r
+       RegisterListener('qt_play', 'mymovie', 'mymovie_embed', startTimeline);\r
+       RegisterListener('qt_pause', 'mymovie', 'mymovie_embed', pauseTimeline);\r
+       RegisterListener('qt_ended', 'mymovie', 'mymovie_embed', pauseTimeline);\r
+\r
+       /* show or hide side bar action */\r
+       $("#show_hide_caps").click(function() {\r
+               if ($("#info-tab").css("display") == "none") {\r
+                       $("#info-tab").show();\r
+                       $("#info-container").css("margin-left", "71%");\r
+                       $("#movie-container").css("width", "70%");\r
+                       \r
+                       $(this).html('<h4 style="margin:0px">Clips <img style="float:right" src="images/application_get.png" alt="hide clips" title="hide clips" /></h4>');\r
+               } else {\r
+                       $("#info-tab").hide();\r
+                       $("#info-container").css("margin-left", "97%");\r
+                       $("#movie-container").css("width", "96%");\r
+                       \r
+                       $(this).html('<img src="images/application_put.png" alt="show clips" title="show clips" />');   \r
+               }\r
+       });\r
+\r
+       /* hide clip side bar */\r
+       $("#info-tab").hide();\r
+       $("#info-container").css("margin-left", "97%");\r
+       $("#movie-container").css("width", "96%");\r
+       $("#show_hide_caps").html('<img src="images/application_put.png" alt="show clips" title="show clips" />');      \r
+               \r
+       \r
+       $("#editor-tab").addClass('current');\r
+       $("#clips-subtab").addClass('current');\r
+       \r
+       /* global proj related vars */\r
+       if (proj.clip_collection)\r
+               num_clips = proj.clip_collection.clips.length;\r
+\r
+       interval = window.setInterval("QTStatus()",100);        \r
+}\r
+\r
+function QTStatus() {\r
+       try {\r
+               if (movieObj.GetPluginStatus() == "Complete") {\r
+                       window.clearInterval(interval);\r
+                       $("#movie_status").html("");\r
+                       setDisplay();\r
+               } else {\r
+                       $("#movie_status").html("<strong>Loading media...</strong>");\r
+               }\r
+       } catch (err) {\r
+       }\r
+}\r
+\r
+function setDisplay() {\r
+       $("#movie-controls").css("visibility", "visible");\r
+       $("#clip-controls").css("visibility", "visible");\r
+       $("#make-clip").css("visibility", "visible");\r
+       $("#clip-info").css("visibility", "visible");\r
+       \r
+       $("#source-file").text(movieObj.GetURL());      \r
+\r
+       $("#duration").text(getFormattedTime(movieObj.GetDuration()));  \r
+       dur = parseInt(movieObj.GetDuration()/movieObj.GetTimeScale()*1000);\r
+\r
+       var mysize = movieObj.GetRectangle().split(',');\r
+       \r
+       /* set if audio file: min 250x100 */\r
+       if (mysize[3] >= 1)\r
+               proj.media_height = mysize[3];\r
+       else \r
+               proj.media_height = 1;\r
+       \r
+       if (mysize[2] >= 250)\r
+               proj.media_width = mysize[2];\r
+       else \r
+               proj.media_width = 250;\r
+\r
+       proj.duration = getFormattedTime2(dur);\r
+       clips = proj.clip_collection.clips;     \r
+               \r
+       $("#m_timeline").slider({ \r
+        min: 0, \r
+        max: dur,\r
+    \r
+        stop: function(e, ui) { \r
+               $("#m_timeline").slider("value", ui.value);\r
+        }, \r
+\r
+        slide: function(e, ui) { \r
+            $("#c_timeline").slider("value", ui.value); \r
+                       moveMovieAll(ui.value);\r
+        } \r
+    });    \r
+\r
+       //$("#show_hide_caps").html('<img src="images/application_get.png" style="margin-bottom:-3px;" alt="hide clips" title="hide clips" /> Clips');\r
+\r
+       pace = dur / parseInt($("#m_timeline").css("width"));\r
+\r
+       //isn't it always 0?\r
+       if (movieObj.GetTime() > 0) {\r
+               curTime = calcTime(movieObj.GetTime());\r
+       } else {\r
+               curTime = getFormattedTime2(0);\r
+       }\r
+       \r
+       $("#current-time").text(curTime);       \r
+       $("#clip-time").text(curTime);  \r
+       \r
+       curTime = getMilliseconds(curTime);\r
+       $("#makeclip").attr("disabled","disabled");\r
+\r
+       saveJson();\r
+}\r
+\r
+function moveMovie(time) { //time in milliseconds\r
+       movieObj.SetTime(time*movieObj.GetTimeScale()/1000);\r
+       setCurClip(time);  \r
+           \r
+       $("#current-time").text(getFormattedTime2(time));       \r
+       \r
+       clipTime = parseInt(time - this_location.inTimeMilli);\r
+       $("#clip-time").text(getFormattedTime2(clipTime));      \r
+\r
+       curTime = time;\r
+}\r
+\r
+function moveMovieAll(time) { //time in milliseconds\r
+       movieObj.SetTime(time*movieObj.GetTimeScale()/1000);\r
+       setCurClip(time);  \r
+       \r
+       $("#c_timeline").slider("value", time);\r
+    $("#m_timeline").slider("value", time); \r
+       $("#current-time").text(getFormattedTime2(time));       \r
+       \r
+       clipTime = parseInt(time - this_location.inTimeMilli);\r
+       $("#clip-time").text(getFormattedTime2(clipTime));      \r
+       curTime = time;\r
+}\r
+\r
+function startTimeline() {\r
+       /*if (getMilliseconds(calcTime(movieObj.GetTime())) == curTime-1) {\r
+               movieObj.SetTime((curTime*movieObj.GetTimeScale()/1000)+50);\r
+       }*/\r
+       runTimer();     \r
+       \r
+       this_location_dur = getMilliseconds($("#out-time").text())-getMilliseconds($("#in-time").text());\r
+       clip_pace = this_location_dur / parseInt($("#c_timeline").css("width"));\r
+       \r
+       updateMovieMarker(curTime);     \r
+       updateClipMarker(curTime);              \r
+}\r
+\r
+function pauseTimeline() {\r
+       clearTimeout(clocktimer);\r
+       clearTimeout(marker);\r
+       clearTimeout(clip_marker);\r
+}\r
+\r
+function updateMovieMarker(time) {     \r
+       $("#m_timeline").slider("value", time);\r
+       marker = setTimeout("updateMovieMarker(curTime)", pace);\r
+}\r
+\r
+function updateClipMarker(time) {      \r
+       $("#c_timeline").slider("value", time);\r
+       clip_marker = setTimeout("updateClipMarker(curTime)", clip_pace);\r
+}\r
+\r
+function runTimer() {\r
+       curTime = calcTime(movieObj.GetTime());\r
+\r
+       $("#current-time").text(curTime);       \r
+       curTime = getMilliseconds(curTime);\r
+               \r
+       clipTime = parseInt(curTime - getMilliseconds($("#in-time").text()));\r
+\r
+       if ( curTime==dur || curTime>getMilliseconds($("#out-time").text()) || curTime<getMilliseconds($("#in-time").text()) ) {        \r
+               if (clip_playing || curTime >= dur) {\r
+                       clip.pressStop();\r
+                       moveMovieAll(getMilliseconds($("#out-time").text()));\r
+                       return;\r
+               } else {\r
+                       setCurClip(curTime);\r
+               }\r
+       }\r
+       $("#clip-time").text(getFormattedTime2(clipTime));      \r
+       clocktimer = setTimeout("runTimer()",1);        \r
+}\r
+\r
+function setClipTimeline(cdur, cin, cout) { \r
+       //console.log('setClipTimeline', cin, cout);\r
+       \r
+       //destroy the old slider set up and create the new one\r
+    $("#c_timeline").slider("destroy");\r
+\r
+       $("#c_timeline").slider({ \r
+        min: cin, \r
+        max: cout,\r
+                  \r
+        stop: function(e, ui) { \r
+                       $("#c_timeline").slider("value", ui.value);\r
+        },\r
+        slide: function(e, ui) { \r
+            $("#m_timeline").slider("value", ui.value); \r
+                       moveMovieAll(ui.value);\r
+        } \r
+    });    \r
+}\r
+       \r
+function loadClips() {\r
+       $('#numclips').text(num_clips);\r
+       clips_html = '';\r
+               \r
+       if (num_clips > 0) {\r
+               for (var i in clips) {\r
+                                               \r
+                       //previous space\r
+                       if (clips[parseInt(i)-1] == undefined && clips[i].inTimeMilli>0) {\r
+                               space_dur = getFormattedTime2(clips[i].inTimeMilli-1);\r
+                               clips_html += '<div class="space"><span style="font-weight:bold;float:left;"><a href="#" onclick="javascript:resetClipWork();moveMovieAll(0);">Space before Clip 1</a></span><span style="float:right">'+ space_dur +'</span><span id="space'+i+'"></span><br style="clear:both;" /></div>';\r
+                       } else if ( clips[parseInt(i)-1] != undefined && (clips[i].inTimeMilli != parseInt(clips[parseInt(i)-1].outTimeMilli)+1)) { \r
+                               space_dur = getFormattedTime2(clips[i].inTimeMilli - clips[parseInt(i)-1].outTimeMilli -2);\r
+                               clips_html += '<div class="space"><span style="font-weight:bold;float:left;"><a href="#" onclick="javascript:resetClipWork();moveMovieAll('+(clips[parseInt(i)-1].outTimeMilli+1)+');">Space after Clip '+i+'</a></span><span style="float:right">'+ space_dur +'</span><span id="space'+i+'"></span><br style="clear:both;" /></div>';\r
+                       } \r
+                       \r
+                       //clip\r
+                       html_caption = clips[i].caption_text.replace(/\n/g, "<br />");                  \r
+                       clips[i].name = 'Clip '+(parseInt(i)+1);\r
+                       clips_html += '<div style="float:right; padding-top:5px;margin-right:5px;"><a href="#" onclick="javascript:confirmDelete('+(parseInt(i)+1)+');">X</a></div><div class="clip"><span class="clip-title"><a name="clip'+i+'" href="#" onclick="javascript:resetClipWork();moveMovieAll('+clips[i].inTimeMilli+');">'+clips[i].name+'</a></span><span id="clip'+(parseInt(i)+1)+'"></span><br />' + html_caption + '<br /><div style="float:right"> '+ clips[i].duration + '</div><span style="font-size:smaller">in: ' + clips[i].inTime + ' <br />out: '+ clips[i].outTime +'</span></div>';\r
+                               \r
+                       //last space\r
+                       if (clips[parseInt(i)+1] == undefined && clips[i].outTimeMilli<dur) {\r
+                               space_dur = getFormattedTime2(dur - clips[i].outTimeMilli-1);\r
+                               clips_html += '<div class="space"><span style="font-weight:bold;float:left;"><a href="#" onclick="javascript:resetClipWork();moveMovieAll('+parseInt(clips[i].outTimeMilli+1)+');">Space after Clip '+(parseInt(i)+1)+'</a></span><span style="float:right">'+ space_dur +'</span><span id="space'+(parseInt(i)+1)+'"></span><br style="clear:both;" /></div>';\r
+                       }\r
+                       i++;\r
+               }       \r
+               \r
+               $("#info-tab").html(clips_html);                \r
+       } else {\r
+               //no clips\r
+               clips_html = '<div class="space" style="border-bottom:0px"><span style="font-weight:bold;float:left;"><a href="#" onclick="javascript:resetClipWork();moveMovieAll(0);">Space</a></span><span style="float:right">'+ $("#duration").text() +'</span><br style="clear:both;" /></div>';\r
+               $("#info-tab").html(clips_html);\r
+               \r
+               new_flag = true;\r
+       }\r
+       setCurClip(curTime);\r
+}\r
+\r
+/*\r
+ * As the movie plays (or the playhead is moved), figure out what clip it's on \r
+ */ \r
+function setCurClip(time) {\r
+       \r
+       this_location = {};\r
+       inClip = false;\r
+       var asterisk = '';\r
+                       \r
+       if (temp_in) {\r
+               this_location.inTime = temp_in;\r
+               this_location.inTimeMilli = getMilliseconds(temp_in);\r
+       } else {\r
+               this_location.inTime = $("#in-time").text();\r
+               this_location.inTimeMilli = getMilliseconds(this_location.inTime);\r
+       }\r
+       if (temp_out) {\r
+               this_location.outTime = temp_out;\r
+               this_location.outTimeMilli = getMilliseconds(temp_out);\r
+       } else {\r
+               this_location.outTime = $("#out-time").text();\r
+               this_location.outTimeMilli = getMilliseconds(this_location.outTime);\r
+       }\r
+       \r
+       if (extend == true) {           \r
+               if( (temp_in && time < getMilliseconds(temp_in)) || (temp_out && time > getMilliseconds(temp_out) )) {\r
+                       resetClipWork();\r
+                       extend = false;\r
+               } else {\r
+                       return;\r
+               }\r
+       } else {\r
+               lastLoc = curClip;\r
+       }       \r
+       \r
+       if (num_clips == 0) {\r
+               //no clips\r
+               this_location.name = "Space";\r
+               \r
+               asterisk = "#space0";\r
+               if (!temp_in) {\r
+                       this_location.inTimeMilli = 0;\r
+                       this_location.inTime = getFormattedTime2(this_location.inTimeMilli);\r
+               }\r
+               if (!temp_out) {\r
+                       this_location.outTimeMilli = dur;\r
+                       this_location.outTime = getFormattedTime2(dur);\r
+               }\r
+               \r
+               this_location.caption_text = "";\r
+               curClip = 0;\r
+               $("#makeclip").val("Make Clip");\r
+               \r
+       } else {        \r
+               for (var i in clips) {\r
+                       if (time < clips[i].inTimeMilli && clips[parseInt(i)-1] == undefined) { \r
+                               //first space\r
+                               this_location.name = "Space before Clip 1";\r
+                               \r
+                               asterisk = "#space0";\r
+                                                               \r
+                               if (!temp_in) {\r
+                                       this_location.inTimeMilli = 0;\r
+                                       this_location.inTime = getFormattedTime2(this_location.inTimeMilli);\r
+                               }\r
+                               if (!temp_out) {\r
+                                       this_location.outTimeMilli = parseInt(clips[i].inTimeMilli)-1;\r
+                                       this_location.outTime = getFormattedTime2(this_location.outTimeMilli);\r
+                               }\r
+                               \r
+                               this_location.caption_text = "";\r
+                               curClip = 0;\r
+                               $("#makeclip").val("Make Clip");\r
+\r
+                               break;\r
+                       } else if ( (clips[parseInt(i)+1] == undefined || time < clips[parseInt(i)+1].inTimeMilli) && time > clips[i].outTimeMilli) {\r
+                               \r
+                               //space\r
+                               this_location.name = "Space after Clip "+ parseInt(parseInt(i)+1);\r
+                               \r
+                               if (!temp_in) { \r
+                                       this_location.inTimeMilli = clips[i].outTimeMilli+1;\r
+                                       this_location.inTime = getFormattedTime2(this_location.inTimeMilli);\r
+                               }\r
+\r
+                               if (!temp_out) {\r
+                                       if (clips[parseInt(i)+1] == undefined)\r
+                                               this_location.outTimeMilli = dur;\r
+                                       else\r
+                                               this_location.outTimeMilli = clips[parseInt(i)+1].inTimeMilli-1;\r
+                                       \r
+                                       this_location.outTime = getFormattedTime2(this_location.outTimeMilli);\r
+                               }\r
+                               \r
+                               this_location.caption_text = "";\r
+                               curClip = parseInt(i)+1;\r
+                               asterisk = "#space"+curClip;\r
+\r
+                               $("#makeclip").val("Make Clip");\r
+                               \r
+                               break;\r
+                       } else if (time >= clips[i].inTimeMilli && time <= clips[i].outTimeMilli) {\r
+                               //clip\r
+                               curClip = parseInt(i)+1;\r
+                               this_location = clips[i];\r
+                               inClip = true;\r
+                               $("#makeclip").val("Update Clip");\r
+                               \r
+                               asterisk = "#clip"+curClip;\r
+                               break;\r
+                       } else {                                \r
+                               //console.log("skipping this one", i, clips[i].inTimeMilli, clips[i].outTimeMilli);\r
+                       }\r
+               }       \r
+       }       \r
+       \r
+       // 'you are here' asterisk      \r
+       $("#space"+lastLoc).text("");                           \r
+       $("#clip"+lastLoc).text("");\r
+               \r
+       $(asterisk).html("&nbsp;<img src='images/asterisk_yellow.png' alt='current space' />");\r
+       \r
+       // in and out times\r
+       if (!temp_in) \r
+               $("#in-time").text(this_location.inTime);\r
+       if (!temp_out)                          \r
+               $("#out-time").text(this_location.outTime);\r
+                       \r
+       //duration\r
+       this_location.durationMilli = this_location.outTimeMilli - this_location.inTimeMilli;\r
+       this_location.duration = getFormattedTime2(this_location.durationMilli);                \r
+       $("#clip-duration").text(this_location.duration);\r
+\r
+       \r
+       // moved into a different clip or space\r
+       if ($("#clip-name").text() != this_location.name || (new_flag && !temp_in && !temp_out && !temp_caps)) {\r
+               \r
+               //caption text\r
+               $("#caption-text").val(this_location.caption_text);                     \r
+               \r
+               // user was working on a new clip but it gets reset when moving out of current clip\r
+               if (temp_in || temp_out || temp_caps) {  \r
+                       resetClipWork();\r
+               }\r
+               \r
+               //move scroll bar to clip\r
+               if (curClip>2)\r
+                       $("#info-tab").scrollTop(curClip*70);\r
+               else \r
+                       $("#info-tab").scrollTop(0);\r
+               \r
+               // update the clip timeline and move the playhead\r
+               setClipTimeline(this_location.durationMilli, this_location.inTimeMilli, this_location.outTimeMilli);\r
+       }\r
+       \r
+       // name\r
+       $("#clip-name").text(this_location.name);\r
+}\r
+/*************************************** movie controller buttons */\r
+\r
+movie.normPlay = function() {\r
+       if ($("#playButton").attr("src") == "images/play.png") {\r
+               movieObj.Play();\r
+               $("#playButton").attr("src", 'images/pause.png');\r
+               $("#clip-playButton").attr("src", 'images/pause.png');\r
+\r
+       } else {\r
+               movie.pressStop();      \r
+       }\r
+}\r
+\r
+movie.pressPlay = function() {\r
+       movieObj.Play();\r
+       $("#pressButton").attr("src", 'images/pause.png');\r
+}\r
+movie.pressStop = function() {\r
+       movieObj.Stop();\r
+       $("#playButton").attr("src", 'images/play.png');\r
+       $("#clip-playButton").attr("src", 'images/play.png');\r
+\r
+       $("#pressButton").attr("src", 'images/pressplay.png');\r
+}\r
+\r
+\r
+/*************************************** clip controller buttons */\r
+\r
+clip.normPlay = function() {           \r
+       if ($("#clip-playButton").attr("src") == "images/play.png") {\r
+               lastplay = curTime;\r
+               movieObj.Play();\r
+               $("#clip-playButton").attr("src", 'images/pause.png');\r
+               $("#playButton").attr("src", 'images/pause.png');\r
+               clip_playing = true;\r
+       } else {\r
+               clip.pressStop();       \r
+       }\r
+}\r
+\r
+clip.pressPlay = function() {\r
+       lastplay = curTime;\r
+       moveMovie(curTime);\r
+       movieObj.Play();\r
+       $("#clip-pressButton").attr("src", 'images/pause.png');\r
+       clip_playing = true;\r
+}\r
+clip.pressStop = function() {\r
+       movieObj.Stop();\r
+       var max = $("#c_timeline").slider("option", "max");\r
+       if (curTime > max)\r
+               moveMovie(max-1000);\r
+               \r
+       $("#clip-playButton").attr("src", 'images/play.png');\r
+       $("#playButton").attr("src", 'images/play.png');\r
+       $("#clip-pressButton").attr("src", 'images/pressplay.png');\r
+       clip_playing = false;   \r
+}\r
+\r
+function getIndex( myarray, item ) {\r
+       for (var i=0; i<myarray.length; i++) {\r
+               if (myarray[i] == item) {\r
+                       return i;\r
+               }\r
+       }\r
+}\r
+\r
+clip.previous = function() {   \r
+       //if in a clip\r
+       if (inClip && curClip > 1) {\r
+               //go to prev space (prev clip's out time +1)\r
+               if (clips[curClip-2].outTimeMilli+1 != clips[curClip-1].inTimeMilli) {\r
+                       moveMovieAll(clips[curClip-2].outTimeMilli+1);\r
+                       \r
+               //if no space, go to prev clip\r
+               } else {\r
+                       moveMovieAll(clips[curClip-2].inTimeMilli);             \r
+               }\r
+               \r
+       //if in a space, go to prev clip        \r
+       } else if (!inClip && curClip>0) {\r
+               moveMovieAll(clips[curClip-1].inTimeMilli);\r
+       //if in first space or clip, go to start        \r
+       } else {        \r
+               moveMovieAll(0);\r
+       }\r
+}\r
+clip.next = function() {       \r
+       //if in a clip\r
+       if (inClip && clips[curClip] != undefined) {\r
+               \r
+               //go to next space (next clip's out time +1)\r
+               if (clips[curClip].inTimeMilli != clips[curClip-1].outTimeMilli+1) {\r
+                       moveMovieAll(clips[curClip-1].outTimeMilli+1);\r
+                       \r
+               //if no space, go to next clip\r
+               } else  {\r
+                       moveMovieAll(clips[curClip].inTimeMilli);               \r
+               }\r
+               \r
+       //if in a space, go to next clip        \r
+       } else if (!inClip && clips[curClip] != undefined) {\r
+               moveMovieAll(clips[curClip].inTimeMilli);\r
+               \r
+       //if at the end \r
+       } else if (clips[clips.length-1] != undefined) {\r
+               if (clips[clips.length-1].outTimeMilli == dur)\r
+                       moveMovieAll(clips[clips.length-1].inTimeMilli);\r
+               else\r
+                       moveMovieAll(clips[clips.length-1].outTimeMilli+1);\r
+       }\r
+\r
+}\r
+\r
+clip.goToStart = function() {\r
+       moveMovieAll(getMilliseconds($("#in-time").text()));\r
+}\r
+clip.goToEnd = function() {\r
+       moveMovieAll(getMilliseconds($("#out-time").text()));\r
+}\r
+clip.stepBack = function(step) {\r
+       if (curTime >= step && (curTime-step >= getMilliseconds($("#in-time").text())) )\r
+               moveMovieAll(curTime - step);   \r
+}\r
+clip.stepForward = function(step) {            \r
+       if (  curTime+step <= getMilliseconds($("#out-time").text()) ) \r
+               moveMovieAll(curTime + step);   \r
+}\r
+\r
+clip.lastPlay = function() {           \r
+       moveMovieAll(lastplay); \r
+}\r
+\r
+/*************** making a clip */\r
+\r
+clip.newInTime = function() {\r
+       var clip_dur = 0;\r
+       clip_dur = this_location.outTimeMilli-curTime;  \r
+       if (clip_dur <= MIN_CLIP_DUR) {\r
+               alert("Too few frames to make a clip!");\r
+       } else {\r
+               $("#in").css("color","red");    \r
+               $("#in-time").css("color","red");\r
+               $("#clip-duration").css("color","red"); \r
+               $("#makeclip").removeAttr("disabled");\r
+               $("#clip-duration").text(getFormattedTime2(clip_dur));\r
+\r
+               //old_in = getMilliseconds($("#in-time").text());\r
+               \r
+               temp_in = getFormattedTime2(curTime);\r
+               $("#in-time").text(temp_in);\r
+                               \r
+               setClipTimeline(clip_dur, curTime, this_location.outTimeMilli);\r
+               moveMovieAll(curTime);\r
+                               \r
+               /*if (new_flag)\r
+                       $("#in-undo").html("<a href='#' onclick='javascript:clip.undoIn(0)'><img src='images/bullet_delete.png' alt='cancel in-time' title='cancel in-time' /></a>");\r
+               else if (inAClip())\r
+                       $("#in-undo").html("<a href='#' onclick='javascript:clip.undoIn("+milli_ins[curClip-1]+")'><img src='images/bullet_delete.png' alt='cancel in-time' title='cancel in-time' /></a>");\r
+               else    \r
+                       $("#in-undo").html("<a href='#' onclick='javascript:clip.undoIn("+milli_spaceins[curClip]+")'><img src='images/bullet_delete.png' alt='cancel in-time' title='cancel in-time' /></a>");\r
+               */\r
+       }       \r
+}\r
+\r
+\r
+clip.newOutTime = function() {\r
+       if (curTime != getMilliseconds($("#out-time").text())) {\r
+               var clip_dur = 0;\r
+\r
+               if (temp_in) {\r
+                       clip_dur = curTime-getMilliseconds(temp_in);\r
+               } else {\r
+                       clip_dur = curTime-getMilliseconds($("#in-time").text());\r
+               }               \r
+               \r
+               if (clip_dur <= MIN_CLIP_DUR) {\r
+                       alert("Too few frames to make a clip!");\r
+               } else {\r
+\r
+                       $("#out").css("color","red");\r
+                       $("#out-time").css("color","red");\r
+                       $("#clip-duration").css("color","red");\r
+                       $("#makeclip").removeAttr("disabled");          \r
+                       $("#clip-duration").text(getFormattedTime2(clip_dur));                  \r
+                       \r
+                       temp_out = getFormattedTime2(curTime);\r
+                       $("#out-time").text(temp_out);\r
+                       \r
+                       setClipTimeline(curTime - getMilliseconds($("#in-time").text()), getMilliseconds($("#in-time").text()), curTime);\r
+                       moveMovieAll(curTime);\r
+\r
+                       /*if (new_flag)\r
+                               $("#out-undo").html("<a href='#' onclick='javascript:clip.undoOut("+dur+")'><img src='images/bullet_delete.png' alt='cancel out-time' title='cancel out-time' /></a>");\r
+                       else if (inAClip())\r
+                               $("#out-undo").html("<a href='#' onclick='javascript:clip.undoOut("+milli_outs[curClip-1]+")'><img src='images/bullet_delete.png' alt='cancel out-time' title='cancel out-time' /></a>");\r
+                       else    \r
+                               $("#out-undo").html("<a href='#' onclick='javascript:clip.undoOut("+milli_spaceouts[curClip]+")'><img src='images/bullet_delete.png' alt='cancel out-time' title='cancel out-time' /></a>");\r
+                       */                                      \r
+               }\r
+       }\r
+}\r
+\r
+clip.addPrevSpace = function() {               \r
+               \r
+       //if the current clip's inTime is > 0 and also not equal to the prev clip's outTime\r
+       if (inClip && clips[curClip-1].inTimeMilli > 0 && ( clips[curClip-2]==undefined || clips[curClip-1].inTimeMilli != clips[curClip-2].outTimeMilli) ) {\r
+                               \r
+               var newin = 0;\r
+               \r
+               //make clip start = last clip's end     \r
+               if (clips[curClip-2] != undefined) {\r
+                       newin = clips[curClip-2].outTimeMilli + 1;\r
+               } else {\r
+                       newin = 0;\r
+               }\r
+               temp_in = getFormattedTime2(newin);\r
+               var oldout = getMilliseconds($("#out-time").text())\r
+               var caption_text = $("#caption-text").val();\r
+                               \r
+               //set new temp values\r
+               $("#in-time").css("color","red");\r
+               $("#in-time").text(temp_in);\r
+               \r
+               $("#clip-duration").css("color","red"); \r
+               $("#makeclip").removeAttr("disabled");\r
+               $("#makeclip").val("Update Clip");\r
+               \r
+               //$("#caption-text").val(caption_text);                         \r
+               $("#clip-duration").text(getFormattedTime2(oldout - newin));            \r
+               \r
+               extend = true;          \r
+               setClipTimeline(oldout - newin, newin, oldout);\r
+               moveMovieAll(curTime);\r
+               //$("#in-undo").html("<a href='#' onclick='javascript:clip.undoIn("+milli_ins[curClip-1]+")'><img src='images/bullet_delete.png' alt='cancel in-time' title='cancel in-time' /></a>");\r
+       }\r
+}\r
+\r
+clip.addNextSpace = function() {               \r
+       \r
+       if (inClip && clips[curClip-1].outTimeMilli < dur && (clips[curClip]==undefined || clips[curClip-1].outTimeMilli != clips[curClip].inTimeMilli)) {\r
+               var newout = 0;\r
+               //make clip start = last clip's end     \r
+               if (clips[curClip] != undefined) {\r
+                       newout = clips[curClip].inTimeMilli - 1;\r
+               } else {\r
+                       newout = dur;\r
+               }\r
+               temp_out = getFormattedTime2(newout);\r
+\r
+               var oldin = getMilliseconds($("#in-time").text())\r
+               var caption_text = $("#caption-text").val();\r
+               \r
+               //set new temp values\r
+               $("#out-time").css("color","red");\r
+               $("#out-time").text(temp_out);\r
+               \r
+               $("#clip-duration").css("color","red"); \r
+               $("#makeclip").removeAttr("disabled");\r
+               $("#makeclip").val("Update Clip");\r
+               \r
+               //$("#caption-text").val(caption_text);                         \r
+               $("#clip-duration").text(getFormattedTime2(newout - oldin));            \r
+                               \r
+               extend = true;          \r
+               setClipTimeline(newout - oldin, oldin, newout);\r
+               moveMovieAll(curTime);  \r
+               //$("#out-undo").html("<a href='#' onclick='javascript:clip.undoOut("+milli_outs[curClip-1]+")'><img src='images/bullet_delete.png' alt='cancel out-time' title='cancel out-time' /></a>");\r
+       }\r
+}\r
+\r
+/****** making/updating and saving clips **/\r
+\r
+movie.saveClip = function() {\r
+       var caption_text = $("#caption-text").val();\r
+       var clipnum = 0;\r
+               \r
+       // button should be disabled but double check that at least one time has changed, or caption text has changed\r
+       //if (temp_in || temp_out) {   \r
+               resetClipWork();\r
+               \r
+               if (!temp_in) {\r
+                       temp_in = $("#in-time").text();\r
+               }\r
+               if (!temp_out) {\r
+                       temp_out = $("#out-time").text();\r
+               }               \r
+               \r
+               this_location.inTime = temp_in;\r
+               this_location.outTime = temp_out;\r
+               this_location.inTimeMilli = getMilliseconds(temp_in);\r
+               this_location.outTimeMilli = getMilliseconds(temp_out);\r
+               \r
+               this_location.durationMilli = this_location.outTimeMilli - this_location.inTimeMilli;\r
+               this_location.duration = getFormattedTime2(this_location.durationMilli);\r
+               this_location.caption_text = caption_text;\r
+               \r
+               if($("#makeclip").val() == "Make Clip") { \r
+                       num_clips++;\r
+                       \r
+                       if (num_clips > 0) {\r
+                               //add to clips list\r
+                               clips[num_clips-1] = this_location;\r
+                               \r
+                               //sort clips by inTimeMilli\r
+                               clips.sort(function (a,b) { return a.inTimeMilli-b.inTimeMilli});\r
+                               \r
+                       } else {\r
+                               clips = new Array(); //clips\r
+                               clips[0] = this_location;\r
+                               \r
+                               new_flag = 0;\r
+                       }\r
+               } else {\r
+                       clips[curClip-1] = this_location;\r
+               }\r
+                                                                                       \r
+               //loadClips();\r
+               \r
+               var move_to = getMilliseconds(temp_out) + 1;\r
+                if (move_to < (dur - MIN_CLIP_DUR) ) {\r
+                        setTimeout("moveMovieAll("+move_to+")", 500);  \r
+                } else {\r
+                        setTimeout("moveMovie(curTime)", 500);                                          \r
+                }                              \r
+\r
+               \r
+               temp_in = '';\r
+               temp_out = '';\r
+               \r
+               saveJson();\r
+       //}\r
+}\r
+\r
+function deleteClip(clipnum) {\r
+       num_clips--;\r
+       clips.splice(clipnum-1, 1);\r
+       saveJson();     \r
+}\r
+\r
+function saveJson() {\r
+       //save file\r
+       json = JSON.stringify(proj);\r
+       \r
+       $.post("include/workflow.php", { task: 'save_json', json:json, pid:proj.id }, function(data) {\r
+               if (!data) { \r
+                       loadClips();\r
+               } else {\r
+                       alert(data);\r
+               }\r
+               \r
+       } );\r
+       \r
+       var d = new Date();\r
+\r
+       var curr_hour = d.getHours();\r
+       var curr_min = d.getMinutes();\r
+       \r
+       $("#last-saved").text('Last saved at '+curr_hour + ":" + ((curr_min < 10) ? "0" : "") + curr_min);\r
+}\r
+\r
+/****************reset UI */\r
+\r
+function resetClipWork() {\r
+       $("#in").css("color","black");  \r
+       $("#out").css("color","black"); \r
+       $("#in-time").css("color","black");\r
+       $("#out-time").css("color","black");                    \r
+       $("#clip-duration").css("color","black");       \r
+       temp_in = 0;\r
+       temp_out = 0;\r
+       temp_caps = ''; \r
+       \r
+       extend = false;\r
+       $("#makeclip").attr("disabled","disabled");\r
+       $("#in-undo").html("");\r
+       $("#out-undo").html("");\r
+\r
+}\r
+\r
+\r
diff --git a/mods/atutor_opencaps/opencaps/js/export.js b/mods/atutor_opencaps/opencaps/js/export.js
new file mode 100755 (executable)
index 0000000..e81e01f
--- /dev/null
@@ -0,0 +1,21 @@
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+$(document).ready(function () {\r
+       $("#export-tab").addClass('current');\r
+});\r
+\r
+function set_format(chosen_format) {\r
+  document.forms[0].format.value = chosen_format;\r
+  document.forms[0].submit() ;\r
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/index.html b/mods/atutor_opencaps/opencaps/js/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/GPL-LICENSE.txt b/mods/atutor_opencaps/opencaps/js/jquery/GPL-LICENSE.txt
new file mode 100755 (executable)
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/mods/atutor_opencaps/opencaps/js/jquery/MIT-LICENSE.txt b/mods/atutor_opencaps/opencaps/js/jquery/MIT-LICENSE.txt
new file mode 100755 (executable)
index 0000000..965a831
--- /dev/null
@@ -0,0 +1,20 @@
+Copyright (c) 2007 John Resig, http://jquery.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 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/mods/atutor_opencaps/opencaps/js/jquery/jARIA.js b/mods/atutor_opencaps/opencaps/js/jquery/jARIA.js
new file mode 100755 (executable)
index 0000000..cd48686
--- /dev/null
@@ -0,0 +1 @@
+(function(E){var C="http://www.w3.org/2005/07/aaa";var F=["main","secondary","navigation","banner","contentinfo","statements","note","seealso","search"];var A=new RegExp("^"+F.join("|")+"$");var D=E.browser.mozilla&&(parseFloat(E.browser.version)<1.9);var B=(function(){if(D){return function(I,G,H){if(typeof H!="undefined"){I.each(function(J,K){K.setAttributeNS(C,G,H)})}else{return I.get(0).getAttributeNS(C,G)}}}else{return function(I,G,H){if(typeof H!="undefined"){I.each(function(J,K){E(K).attr("aria-"+G,H)})}else{return I.attr("aria-"+G)}}}})();E.fn.extend({ariaRole:function(H){var G=this;if(H){H=(A.test(H)||!D)?H:"wairole:"+H;G.each(function(I,J){E(J).attr("role",H)});return G}else{var H=G.eq(0).attr("role");if(H){H=H.replace(/^wairole:/,"")}return H}},ariaState:function(){var G=arguments;var H=this;if(G.length==2){H.each(function(I,J){B(E(J),G[0],G[1])});return H}else{if(typeof G[0]=="string"){return B(H.eq(0),G[0])}else{H.each(function(I,J){E.each(G[0],function(K,L){E(J).ariaState(K,L)})});return H}}}});E.extend(E.expr[":"],{ariaRole:"jQuery(a).ariaRole()==m[3]",ariaState:"jQuery(a).ariaState(m[3].split(/=/)[0])==(/=/.test(m[3])?m[3].split(/=/)[1]:'true')"})})(jQuery);
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/jquery-1.2.3.js b/mods/atutor_opencaps/opencaps/js/jquery/jquery-1.2.3.js
new file mode 100755 (executable)
index 0000000..5899bd4
--- /dev/null
@@ -0,0 +1 @@
+(function(){if(window.jQuery){var _jQuery=window.jQuery}var jQuery=window.jQuery=function(selector,context){return new jQuery.prototype.init(selector,context)};if(window.$){var _$=window.$}window.$=jQuery;var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;var isSimple=/^.[^:#\[\.]*$/;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this}else{if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1]){selector=jQuery.clean([match[1]],context)}else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3]){return jQuery().find(selector)}else{this[0]=elem;this.length=1;return this}}else{selector=[]}}}else{return new jQuery(context).find(selector)}}else{if(jQuery.isFunction(selector)){return new jQuery(document)[jQuery.fn.ready?"ready":"load"](selector)}}}return this.setArray(selector.constructor==Array&&selector||(selector.jquery||selector.length&&selector!=window&&!selector.nodeType&&selector[0]!=undefined&&selector[0].nodeType)&&jQuery.makeArray(selector)||[selector])},jquery:"1.2.3",size:function(){return this.length},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num]},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this},each:function(callback,args){return jQuery.each(this,callback,args)},index:function(elem){var ret=-1;this.each(function(i){if(this==elem){ret=i}});return ret},attr:function(name,value,type){var options=name;if(name.constructor==String){if(value==undefined){return this.length&&jQuery[type||"attr"](this[0],name)||undefined}else{options={};options[name]=value}}return this.each(function(i){for(name in options){jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name))}})},css:function(key,value){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]){jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).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,false,function(elem){if(this.nodeType==1){this.appendChild(elem)}})},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1){this.insertBefore(elem,this.firstChild)}})},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this)})},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling)})},end:function(){return this.prevObject||jQuery([])},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem)});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems)},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0]}else{return this.cloneNode(true)}});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined){this[expando]=null}});if(events===true){this.find("*").andSelf().each(function(i){if(this.nodeType==3){return }var events=jQuery.data(this,"events");for(var type in events){for(var handler in events[type]){jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data)}}})}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,this))},not:function(selector){if(selector.constructor==String){if(isSimple.test(selector)){return this.pushStack(jQuery.multiFilter(selector,this,true))}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 !selector?this:this.pushStack(jQuery.merge(this.get(),selector.constructor==String?jQuery(selector).get():selector.length!=undefined&&(!selector.nodeName||jQuery.nodeName(selector,"form"))?selector:[selector]))},is:function(selector){return selector?jQuery.multiFilter(selector,this).length>0:false},hasClass:function(selector){return this.is("."+selector)},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0){return null}for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one){return value}values.push(value)}}return values}else{return(this[0].value||"").replace(/\r/g,"")}}return undefined}return this.each(function(){if(this.nodeType!=1){return }if(value.constructor==Array&&/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=value.constructor==Array?value:[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.length?this[0].innerHTML: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))},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)},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value==null){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data==undefined&&this.length){data=jQuery.data(this[0],key)}return data==null&&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)})},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse){elems.reverse()}}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr")){obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"))}var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script")){scripts=scripts.add(elem)}else{if(elem.nodeType==1){scripts=scripts.add(jQuery("script",elem).remove())}callback.call(obj,elem)}});scripts.each(evalScript)})}};jQuery.prototype.init.prototype=jQuery.prototype;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)}}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2}if(typeof target!="object"&&typeof target!="function"){target={}}if(length==1){target=this;i=0}for(;i<length;i++){if((options=arguments[i])!=null){for(var name in options){if(target===options[name]){continue}if(deep&&options[name]&&typeof options[name]=="object"&&target[name]&&!options[name].nodeType){target[name]=jQuery.extend(target[name],options[name])}else{if(options[name]!=undefined){target[name]=options[name]}}}}}return target};var expando="jQuery"+(new Date()).getTime(),uuid=0,windowData={};var exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i;jQuery.extend({noConflict:function(deep){window.$=_$;if(deep){window.jQuery=_jQuery}return jQuery},isFunction:function(fn){return !!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/function/i.test(fn+"")},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie){script.text=data}else{script.appendChild(document.createTextNode(data))}head.appendChild(script);head.removeChild(script)}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase()},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id){id=elem[expando]=++uuid}if(name&&!jQuery.cache[id]){jQuery.cache[id]={}}if(data!=undefined){jQuery.cache[id][name]=data}return name?jQuery.cache[id][name]:id},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id]){break}if(!name){jQuery.removeData(elem)}}}else{try{delete elem[expando]}catch(e){if(elem.removeAttribute){elem.removeAttribute(expando)}}delete jQuery.cache[id]}},each:function(object,callback,args){if(args){if(object.length==undefined){for(var name in object){if(callback.apply(object[name],args)===false){break}}}else{for(var i=0,length=object.length;i<length;i++){if(callback.apply(object[i],args)===false){break}}}}else{if(object.length==undefined){for(var name in object){if(callback.call(object[name],name,object[name])===false){break}}}else{for(var i=0,length=object.length,value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}}return object},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value)){value=value.call(elem,i)}return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value},className:{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}})},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(" "):""}},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name]}callback.call(elem);for(var name in options){elem.style[name]=old[name]}},css:function(elem,name,force){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;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0});val-=Math.round(padding+border)}if(jQuery(elem).is(":visible")){getWH()}else{jQuery.swap(elem,props,getWH)}return Math.max(0,val)}return jQuery.curCSS(elem,name,force)},curCSS:function(elem,name,force){var ret;function color(elem){if(!jQuery.browser.safari){return false}var ret=document.defaultView.getComputedStyle(elem,null);return !ret||ret.getPropertyValue("color")==""}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(elem.style,"opacity");return ret==""?"1":ret}if(jQuery.browser.opera&&name=="display"){var save=elem.style.outline;elem.style.outline="0 solid black";elem.style.outline=save}if(name.match(/float/i)){name=styleFloat}if(!force&&elem.style&&elem.style[name]){ret=elem.style[name]}else{if(document.defaultView&&document.defaultView.getComputedStyle){if(name.match(/float/i)){name="float"}name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var getComputedStyle=document.defaultView.getComputedStyle(elem,null);if(getComputedStyle&&!color(elem)){ret=getComputedStyle.getPropertyValue(name)}else{var swap=[],stack=[];for(var a=elem;a&&color(a);a=a.parentNode){stack.unshift(a)}for(var i=0;i<stack.length;i++){if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block"}}ret=name=="display"&&swap[stack.length-1]!=null?"none":(getComputedStyle&&getComputedStyle.getPropertyValue(name))||"";for(var i=0;i<swap.length;i++){if(swap[i]!=null){stack[i].style.display=swap[i]}}}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];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var style=elem.style.left,runtimeStyle=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;elem.style.left=ret||0;ret=elem.style.pixelLeft+"px";elem.style.left=style;elem.runtimeStyle.left=runtimeStyle}}}}return ret},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=="undefined"){context=context.ownerDocument||context[0]&&context[0].ownerDocument||document}jQuery.each(elems,function(i,elem){if(!elem){return }if(elem.constructor==Number){elem=elem.toString()}if(typeof elem=="string"){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+">"});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!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>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--){div=div.lastChild}if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?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])}}if(/^\s/.test(elem)){div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild)}}elem=jQuery.makeArray(div.childNodes)}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select"))){return }if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options){ret.push(elem)}else{ret=jQuery.merge(ret,elem)}});return ret},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8){return undefined}var fix=jQuery.isXMLDoc(elem)?{}:jQuery.props;if(name=="selected"&&jQuery.browser.safari){elem.parentNode.selectedIndex}if(fix[name]){if(value!=undefined){elem[fix[name]]=value}return elem[fix[name]]}else{if(jQuery.browser.msie&&name=="style"){return jQuery.attr(elem.style,"cssText",value)}else{if(value==undefined&&jQuery.browser.msie&&jQuery.nodeName(elem,"form")&&(name=="action"||name=="method")){return elem.getAttributeNode(name).nodeValue}else{if(elem.tagName){if(value!=undefined){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode){throw"type property can't be changed"}elem.setAttribute(name,""+value)}if(jQuery.browser.msie&&/href|src/.test(name)&&!jQuery.isXMLDoc(elem)){return elem.getAttribute(name,2)}return elem.getAttribute(name)}else{if(name=="opacity"&&jQuery.browser.msie){if(value!=undefined){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseFloat(value).toString()=="NaN"?"":"alpha(opacity="+value*100+")")}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100).toString():""}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase()});if(value!=undefined){elem[name]=value}return elem[name]}}}}},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"")},makeArray:function(array){var ret=[];if(typeof array!="array"){for(var i=0,length=array.length;i<length;i++){ret.push(array[i])}}else{ret=array.slice(0)}return ret},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++){if(array[i]==elem){return i}}return -1},merge:function(first,second){if(jQuery.browser.msie){for(var i=0;second[i];i++){if(second[i].nodeType!=8){first.push(second[i])}}}else{for(var i=0;second[i];i++){first.push(second[i])}}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=[];for(var i=0,length=elems.length;i<length;i++){if(!inv&&callback(elems[i],i)||inv&&!callback(elems[i],i)){ret.push(elems[i])}}return ret},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!==null&&value!=undefined){if(value.constructor!=Array){value=[value]}ret=ret.concat(value)}}return ret}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,innerHTML:"innerHTML",className:"className",value:"value",disabled:"disabled",checked:"checked",readonly:"readOnly",selected:"selected",maxlength:"maxLength",selectedIndex:"selectedIndex",defaultValue:"defaultValue",tagName:"tagName",nodeName:"nodeName"}});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))}});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++){jQuery(args[i])[original](this)}})}});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){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames)},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){jQuery(">*",this).remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments)}});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px")}});var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2])},"#":function(a,i,m){return a.getAttribute("id")==m[2]},":":{lt:function(a,i,m){return i<m[3]-0},gt:function(a,i,m){return i>m[3]-0},nth:function(a,i,m){return m[3]-0==i},eq:function(a,i,m){return m[3]-0==i},first:function(a,i){return i==0},last:function(a,i,m,r){return i==r.length-1},even:function(a,i){return i%2==0},odd:function(a,i){return i%2},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a},"only-child":function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling")},parent:function(a){return a.firstChild},empty:function(a){return !a.firstChild},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"},enabled:function(a){return !a.disabled},disabled:function(a){return a.disabled},checked:function(a){return a.checked},selected:function(a){return a.selected||jQuery.attr(a,"selected")},text:function(a){return"text"==a.type},radio:function(a){return"radio"==a.type},checkbox:function(a){return"checkbox"==a.type},file:function(a){return"file"==a.type},password:function(a){return"password"==a.type},submit:function(a){return"submit"==a.type},image:function(a){return"image"==a.type},reset:function(a){return"reset"==a.type},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button")},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},has:function(a,i,m){return jQuery.find(m[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem}).length}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r)}return cur},find:function(t,context){if(typeof t!="string"){return[t]}if(context&&context.nodeType!=1&&context.nodeType!=9){return[]}context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false;var re=quickChild;var m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++){for(var c=ret[i].firstChild;c;c=c.nextSibling){if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName)){r.push(c)}}}ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0){continue}foundToken=true}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling){if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id]){break}if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~"){merge[id]=true}r.push(n)}if(m=="+"){break}}}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0]){ret.shift()}done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length)}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]]}else{re2=quickClass;m=re2.exec(t)}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2]){oid=jQuery('[@id="'+m[2]+'"]',elem)[0]}ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[]}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object"){tag="param"}r=jQuery.merge(r,ret[i].getElementsByTagName(tag))}if(m[1]=="."){r=jQuery.classFilter(r,m[2])}if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++){if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break}}r=tmp}ret=r}t=t.replace(re2,"")}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t)}}if(t){ret=[]}if(ret&&context==ret[0]){ret.shift()}done=jQuery.merge(done,ret);return done},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass){tmp.push(r[i])}}return tmp},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break}}if(!m){break}if(m[1]==":"&&m[2]=="not"){r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3])}else{if(m[1]=="."){r=jQuery.classFilter(r,m[2],not)}else{if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2])){z=jQuery.attr(a,m[2])||""}if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not){tmp.push(a)}}r=tmp}else{if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling){if(n.nodeType==1){n.nodeIndex=c++}}merge[id]=true}var add=false;if(first==0){if(node.nodeIndex==last){add=true}}else{if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0){add=true}}if(add^not){tmp.push(node)}}r=tmp}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object"){fn=fn[m[2]]}if(typeof fn=="string"){fn=eval("false||function(a,i){return "+fn+";}")}r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r)},not)}}}}}return{r:r,t:t}},dir:function(elem,dir){var matched=[];var cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1){matched.push(cur)}cur=cur[dir]}return matched},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir]){if(cur.nodeType==1&&++num==result){break}}return cur},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&(!elem||n!=elem)){r.push(n)}}return r}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8){return }if(jQuery.browser.msie&&elem.setInterval!=undefined){elem=window}if(!handler.guid){handler.guid=this.guid++}if(data!=undefined){var fn=handler;handler=function(){return fn.apply(this,arguments)};handler.data=data;handler.guid=fn.guid}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){var val;if(typeof jQuery=="undefined"||jQuery.event.triggered){return val}val=jQuery.event.handle.apply(arguments.callee.elem,arguments);return val});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener){elem.addEventListener(type,handle,false)}else{if(elem.attachEvent){elem.attachEvent("on"+type,handle)}}}}handlers[handler.guid]=handler;jQuery.event.global[type]=true});elem=null},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8){return }var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)==".")){for(var type in events){this.remove(elem,type+(types||""))}}else{if(types.type){handler=types.handler;types=types.type}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler){delete events[type][handler.guid]}else{for(handler in events[type]){if(!parts[1]||events[type][handler].type==parts[1]){delete events[type][handler]}}}for(ret in events[type]){break}if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===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]}}})}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")}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data||[]);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true}if(!elem){if(this.global[type]){jQuery("*").add([window,document]).trigger(type,data)}}else{if(elem.nodeType==3||elem.nodeType==8){return undefined}var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift(this.fix({type:type,target:elem}))}data[0].type=type;if(exclusive){data[0].exclusive=true}if(jQuery.isFunction(jQuery.data(elem,"handle"))){val=jQuery.data(elem,"handle").apply(elem,data)}if(!fn&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false){val=false}if(event){data.shift()}if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined){val=ret}}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,"a")&&type=="click")){this.triggered=true;try{elem[type]()}catch(e){}}this.triggered=false}return val},handle:function(event){var val;event=jQuery.event.fix(event||window.event||{});var parts=event.type.split(".");event.type=parts[0];var handlers=jQuery.data(this,"events")&&jQuery.data(this,"events")[event.type],args=Array.prototype.slice.call(arguments,1);args.unshift(event);for(var j in handlers){var handler=handlers[j];args[0].handler=handler;args[0].data=handler.data;if(!parts[1]&&!event.exclusive||handler.type==parts[1]){var ret=handler.apply(this,args);if(val!==false){val=ret}if(ret===false){event.preventDefault();event.stopPropagation()}}}if(jQuery.browser.msie){event.target=event.preventDefault=event.stopPropagation=event.handler=event.data=null}return val},fix:function(event){var originalEvent=event;event=jQuery.extend({},originalEvent);event.preventDefault=function(){if(originalEvent.preventDefault){originalEvent.preventDefault()}originalEvent.returnValue=false};event.stopPropagation=function(){if(originalEvent.stopPropagation){originalEvent.stopPropagation()}originalEvent.cancelBubble=true};if(!event.target){event.target=event.srcElement||document}if(event.target.nodeType==3){event.target=originalEvent.target.parentNode}if(!event.relatedTarget&&event.fromElement){event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement}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)}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode)){event.which=event.charCode||event.keyCode}if(!event.metaKey&&event.ctrlKey){event.metaKey=event.ctrlKey}if(!event.which&&event.button){event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)))}return event},special:{ready:{setup:function(){bindReady();return },teardown:function(){return }},mouseenter:{setup:function(){if(jQuery.browser.msie){return false}jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true},teardown:function(){if(jQuery.browser.msie){return false}jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true},handler:function(event){if(withinElement(event,this)){return true}arguments[0].type="mouseenter";return jQuery.event.handle.apply(this,arguments)}},mouseleave:{setup:function(){if(jQuery.browser.msie){return false}jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true},teardown:function(){if(jQuery.browser.msie){return false}jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true},handler:function(event){if(withinElement(event,this)){return true}arguments[0].type="mouseleave";return jQuery.event.handle.apply(this,arguments)}}}};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){return this.each(function(){jQuery.event.add(this,type,function(event){jQuery(this).unbind(event);return(fn||data).apply(this,arguments)},fn&&data)})},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn)})},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn)})},triggerHandler:function(type,data,fn){if(this[0]){return jQuery.event.trigger(type,data,this[0],false,fn)}return undefined},toggle:function(){var args=arguments;return this.click(function(event){this.lastToggle=0==this.lastToggle?1:0;event.preventDefault();return args[this.lastToggle].apply(this,arguments)||false})},hover:function(fnOver,fnOut){return this.bind("mouseenter",fnOver).bind("mouseleave",fnOut)},ready:function(fn){bindReady();if(jQuery.isReady){fn.call(document,jQuery)}else{jQuery.readyList.push(function(){return fn.call(this,jQuery)})}return this}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.apply(document)});jQuery.readyList=null}jQuery(document).triggerHandler("ready")}}});var readyBound=false;function bindReady(){if(readyBound){return }readyBound=true;if(document.addEventListener&&!jQuery.browser.opera){document.addEventListener("DOMContentLoaded",jQuery.ready,false)}if(jQuery.browser.msie&&window==top){(function(){if(jQuery.isReady){return }try{document.documentElement.doScroll("left")}catch(error){setTimeout(arguments.callee,0);return }jQuery.ready()})()}if(jQuery.browser.opera){document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady){return }for(var i=0;i<document.styleSheets.length;i++){if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return }}jQuery.ready()},false)}if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady){return }if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return }if(numStyles===undefined){numStyles=jQuery("style, link[rel=stylesheet]").length}if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return }jQuery.ready()})()}jQuery.event.add(window,"load",jQuery.ready)}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,change,select,submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name)}});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem){try{parent=parent.parentNode}catch(error){parent=elem}}return parent==elem};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind()});jQuery.fn.extend({load:function(url,params,callback){if(jQuery.isFunction(url)){return this.bind("load",url)}var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off)}callback=callback||function(){};var type="GET";if(params){if(jQuery.isFunction(params)){callback=params;params=null}else{params=jQuery.param(params);type="POST"}}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified"){self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText)}self.each(callback,[res.responseText,status,res])}});return this},serialize:function(){return jQuery.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type))}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val}}):{name:elem.name,value:val}}).get()}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f)}});var jsc=(new Date).getTime();jQuery.extend({get:function(url,data,callback,type){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:{global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,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(s){var jsonp,jsre=/=\?(&|$)/g,status,data;s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));if(s.data&&s.processData&&typeof s.data!="string"){s.data=jQuery.param(s.data)}if(s.dataType=="jsonp"){if(s.type.toLowerCase()=="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"}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data){s.data=(s.data+"").replace(jsre,"="+jsonp+"$1")}s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();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&&s.type.toLowerCase()=="get"){var ts=(new Date()).getTime();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"")}if(s.data&&s.type.toLowerCase()=="get"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null}if(s.global&&!jQuery.active++){jQuery.event.trigger("ajaxStart")}if((!s.url.indexOf("http")||!s.url.indexOf("//"))&&s.dataType=="script"&&s.type.toLowerCase()=="get"){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset){script.charset=s.scriptCharset}if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script)}}}head.appendChild(script);return undefined}var requestDone=false;var xml=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();xml.open(s.type,s.url,s.async,s.username,s.password);try{if(s.data){xml.setRequestHeader("Content-Type",s.contentType)}if(s.ifModified){xml.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}xml.setRequestHeader("X-Requested-With","XMLHttpRequest");xml.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default)}catch(e){}if(s.beforeSend){s.beforeSend(xml)}if(s.global){jQuery.event.trigger("ajaxSend",[xml,s])}var onreadystatechange=function(isTimeout){if(!requestDone&&xml&&(xml.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xml)&&"error"||s.ifModified&&jQuery.httpNotModified(xml,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xml,s.dataType)}catch(e){status="parsererror"}}if(status=="success"){var modRes;try{modRes=xml.getResponseHeader("Last-Modified")}catch(e){}if(s.ifModified&&modRes){jQuery.lastModified[s.url]=modRes}if(!jsonp){success()}}else{jQuery.handleError(s,xml,status)}complete();if(s.async){xml=null}}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0){setTimeout(function(){if(xml){xml.abort();if(!requestDone){onreadystatechange("timeout")}}},s.timeout)}}try{xml.send(s.data)}catch(e){jQuery.handleError(s,xml,null,e)}if(!s.async){onreadystatechange()}function success(){if(s.success){s.success(data,status)}if(s.global){jQuery.event.trigger("ajaxSuccess",[xml,s])}}function complete(){if(s.complete){s.complete(xml,status)}if(s.global){jQuery.event.trigger("ajaxComplete",[xml,s])}if(s.global&&!--jQuery.active){jQuery.event.trigger("ajaxStop")}}return xml},handleError:function(s,xml,status,e){if(s.error){s.error(xml,status,e)}if(s.global){jQuery.event.trigger("ajaxError",[xml,s,e])}},active:0,httpSuccess:function(r){try{return !r.status&&location.protocol=="file:"||(r.status>=200&&r.status<300)||r.status==304||r.status==1223||jQuery.browser.safari&&r.status==undefined}catch(e){}return false},httpNotModified:function(xml,url){try{var xmlRes=xml.getResponseHeader("Last-Modified");return xml.status==304||xmlRes==jQuery.lastModified[url]||jQuery.browser.safari&&xml.status==undefined}catch(e){}return false},httpData:function(r,type){var ct=r.getResponseHeader("content-type");var xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0;var data=xml?r.responseXML:r.responseText;if(xml&&data.documentElement.tagName=="parsererror"){throw"parsererror"}if(type=="script"){jQuery.globalEval(data)}if(type=="json"){data=eval("("+data+")")}return data},param:function(a){var s=[];if(a.constructor==Array||a.jquery){jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value))})}else{for(var j in a){if(a[j]&&a[j].constructor==Array){jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this))})}else{s.push(encodeURIComponent(j)+"="+encodeURIComponent(a[j]))}}}return s.join("&").replace(/%20/g,"+")}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none"){this.style.display="block"}elem.remove()}}).end()},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none"}).end()},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle(fn,fn2):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]()})},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback)},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback)},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback)},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback)},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback)},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(){if(this.nodeType!=1){return false}var opt=jQuery.extend({},optall);var hidden=jQuery(this).is(":hidden"),self=this;for(var p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden){return jQuery.isFunction(opt.complete)&&opt.complete.apply(this)}if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");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";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit}if(parts[1]){end=((parts[1]=="-="?-1:1)*end)+start}e.custom(start,end,unit)}else{e.custom(start,val,"")}}});return true})},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx"}if(!type||(typeof type=="string"&&!fn)){return queue(this[0],type)}return this.each(function(){if(fn.constructor==Array){queue(this,type,fn)}else{queue(this,type).push(fn);if(queue(this,type).length==1){fn.apply(this)}}})},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue){this.queue([])}this.each(function(){for(var i=timers.length-1;i>=0;i--){if(timers[i].elem==this){if(gotoEnd){timers[i](true)}timers.splice(i,1)}}});if(!gotoEnd){this.dequeue()}return this}});var queue=function(elem,type,array){if(!elem){return undefined}type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array){q=jQuery.data(elem,type+"queue",array?jQuery.makeArray(array):[])}return q};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length){q[0].apply(this)}})};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:{slow:600,fast:200}[opt.duration])||400;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false){jQuery(this).dequeue()}if(jQuery.isFunction(opt.old)){opt.old.apply(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:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig){options.orig={}}}});jQuery.fx.prototype={update:function(){if(this.options.step){this.options.step.apply(this.elem,[this.now,this])}(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width"){this.elem.style.display="block"}},cur:function(force){if(this.elem[this.prop]!=null&&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},custom:function(from,to,unit){this.startTime=(new Date()).getTime();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd)}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.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(jQuery.timerId);jQuery.timerId=null}},13)}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height"){this.elem.style[this.prop]="1px"}jQuery(this.elem).show()},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(gotoEnd){var t=(new Date()).getTime();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){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){this.elem.style.display="none"}if(this.options.hide||this.options.show){for(var p in this.options.curAnim){jQuery.attr(this.elem.style,p,this.options.orig[p])}}}if(done&&jQuery.isFunction(this.options.complete)){this.options.complete.apply(this.elem)}return false}else{var n=t-this.startTime;this.state=n/this.options.duration;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);this.update()}return true}};jQuery.fx.step={scrollLeft:function(fx){fx.elem.scrollLeft=fx.now},scrollTop:function(fx){fx.elem.scrollTop=fx.now},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now)},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit}};jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem){with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),fixed=jQuery.css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop)}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2){border(offsetParent)}if(!fixed&&jQuery.css(offsetParent,"position")=="fixed"){fixed=true}offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(jQuery.css(parent,"display"))){add(-parent.scrollLeft,-parent.scrollTop)}if(mozilla&&jQuery.css(parent,"overflow")!="visible"){border(parent)}parent=parent.parentNode}if((safari2&&(fixed||jQuery.css(offsetChild,"position")=="absolute"))||(mozilla&&jQuery.css(offsetChild,"position")!="absolute")){add(-doc.body.offsetLeft,-doc.body.offsetTop)}if(fixed){add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop))}}results={top:top,left:left}}}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true))}function add(l,t){left+=parseInt(l)||0;top+=parseInt(t)||0}return results}})();
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/jquery-1.2.6.js b/mods/atutor_opencaps/opencaps/js/jquery/jquery-1.2.6.js
new file mode 100755 (executable)
index 0000000..88e661e
--- /dev/null
@@ -0,0 +1,3549 @@
+(function(){
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
+ */
+
+// Map over jQuery in case of overwrite
+var _jQuery = window.jQuery,
+// Map over the $ in case of overwrite
+       _$ = window.$;
+
+var 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)
+var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,
+
+// Is it a simple selector
+       isSimple = /^.[^:#\[\.]*$/,
+
+// Will speed up references to undefined, and allows munging its name.
+       undefined;
+
+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;
+                       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] );
+
+                                       // Make sure an element was located
+                                       if ( elem ){
+                                               // Handle the case where IE and Opera return items
+                                               // by name instead of ID
+                                               if ( elem.id != match[3] )
+                                                       return jQuery().find( selector );
+
+                                               // Otherwise, we inject the element directly into the jQuery object
+                                               return jQuery( elem );
+                                       }
+                                       selector = [];
+                               }
+
+                       // 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 )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
+
+               return this.setArray(jQuery.makeArray(selector));
+       },
+
+       // The current version of jQuery being used
+       jquery: "1.2.6",
+
+       // The number of elements contained in the matched element set
+       size: function() {
+               return this.length;
+       },
+
+       // The number of elements contained in the matched element set
+       length: 0,
+
+       // Get the Nth element in the matched element set OR
+       // Get the whole matched element set as a clean array
+       get: function( num ) {
+               return num == undefined ?
+
+                       // Return a 'clean' array
+                       jQuery.makeArray( 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 ) {
+               // Build a new jQuery matched element set
+               var ret = jQuery( elems );
+
+               // Add the old object onto the stack (as a reference)
+               ret.prevObject = this;
+
+               // 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 ) {
+               var ret = -1;
+
+               // 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 ( name.constructor == 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
+                       jQuery( html, this[0].ownerDocument )
+                               .clone()
+                               .insertBefore( this[0] )
+                               .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, false, function(elem){
+                       if (this.nodeType == 1)
+                               this.appendChild( elem );
+               });
+       },
+
+       prepend: function() {
+               return this.domManip(arguments, true, true, function(elem){
+                       if (this.nodeType == 1)
+                               this.insertBefore( elem, this.firstChild );
+               });
+       },
+
+       before: function() {
+               return this.domManip(arguments, false, false, function(elem){
+                       this.parentNode.insertBefore( elem, this );
+               });
+       },
+
+       after: function() {
+               return this.domManip(arguments, false, true, function(elem){
+                       this.parentNode.insertBefore( elem, this.nextSibling );
+               });
+       },
+
+       end: function() {
+               return this.prevObject || jQuery( [] );
+       },
+
+       find: function( selector ) {
+               var elems = jQuery.map(this, function(elem){
+                       return jQuery.find( selector, elem );
+               });
+
+               return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
+                       jQuery.unique( elems ) :
+                       elems );
+       },
+
+       clone: function( events ) {
+               // Do the clone
+               var ret = this.map(function(){
+                       if ( jQuery.browser.msie && !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 clone = this.cloneNode(true),
+                                       container = document.createElement("div");
+                               container.appendChild(clone);
+                               return jQuery.clean([container.innerHTML])[0];
+                       } else
+                               return this.cloneNode(true);
+               });
+
+               // Need to set the expando to null on the cloned set if it exists
+               // removeData doesn't work here, IE removes it from the original as well
+               // this is primarily for IE but the data expando shouldn't be copied over in any browser
+               var clone = ret.find("*").andSelf().each(function(){
+                       if ( this[ expando ] != undefined )
+                               this[ expando ] = null;
+               });
+
+               // Copy the events from the original to the clone
+               if ( events === true )
+                       this.find("*").andSelf().each(function(i){
+                               if (this.nodeType == 3)
+                                       return;
+                               var events = jQuery.data( this, "events" );
+
+                               for ( var type in events )
+                                       for ( var handler in events[ type ] )
+                                               jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
+                       });
+
+               // 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, this ) );
+       },
+
+       not: function( selector ) {
+               if ( selector.constructor == String )
+                       // test special case where just one selector is passed in
+                       if ( isSimple.test( selector ) )
+                               return this.pushStack( jQuery.multiFilter( selector, this, true ) );
+                       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 this.is( "." + selector );
+       },
+
+       val: function( value ) {
+               if ( value == undefined ) {
+
+                       if ( this.length ) {
+                               var elem = this[0];
+
+                               // 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.browser.msie && !option.attributes.value.specified ? option.text : option.value;
+
+                                                       // 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
+                               } else
+                                       return (this[0].value || "").replace(/\r/g, "");
+
+                       }
+
+                       return undefined;
+               }
+
+               if( value.constructor == Number )
+                       value += '';
+
+               return this.each(function(){
+                       if ( this.nodeType != 1 )
+                               return;
+
+                       if ( value.constructor == Array && /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 :
+                               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 ) );
+       },
+
+       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 );
+       },
+
+       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 );
+               });
+       },
+
+       domManip: function( args, table, reverse, callback ) {
+               var clone = this.length > 1, elems;
+
+               return this.each(function(){
+                       if ( !elems ) {
+                               elems = jQuery.clean( args, this.ownerDocument );
+
+                               if ( reverse )
+                                       elems.reverse();
+                       }
+
+                       var obj = this;
+
+                       if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
+                               obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
+
+                       var scripts = jQuery( [] );
+
+                       jQuery.each(elems, function(){
+                               var elem = clone ?
+                                       jQuery( this ).clone( true )[0] :
+                                       this;
+
+                               // execute all scripts after the elements have been injected
+                               if ( jQuery.nodeName( elem, "script" ) )
+                                       scripts = scripts.add( elem );
+                               else {
+                                       // Remove any inner scripts for later evaluation
+                                       if ( elem.nodeType == 1 )
+                                               scripts = scripts.add( jQuery( "script", elem ).remove() );
+
+                                       // Inject the elements into the document
+                                       callback.call( obj, elem );
+                               }
+                       });
+
+                       scripts.each( evalScript );
+               });
+       }
+};
+
+// 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 ( target.constructor == 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" && typeof target != "function" )
+               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;
+};
+
+var expando = "jQuery" + now(), uuid = 0, windowData = {},
+       // exclude the following css properties to add px
+       exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
+       // cache defaultView
+       defaultView = document.defaultView || {};
+
+jQuery.extend({
+       noConflict: function( deep ) {
+               window.$ = _$;
+
+               if ( deep )
+                       window.jQuery = _jQuery;
+
+               return jQuery;
+       },
+
+       // See test/unit/core.js for details concerning this function.
+       isFunction: function( fn ) {
+               return !!fn && typeof fn != "string" && !fn.nodeName &&
+                       fn.constructor != Array && /^[\s[]?function/.test( fn + "" );
+       },
+
+       // check if an element is in a (or is an) XML document
+       isXMLDoc: function( elem ) {
+               return elem.documentElement && !elem.body ||
+                       elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
+       },
+
+       // Evalulates a script in a global context
+       globalEval: function( data ) {
+               data = jQuery.trim( data );
+
+               if ( 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.browser.msie )
+                               script.text = data;
+                       else
+                               script.appendChild( document.createTextNode( 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();
+       },
+
+       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 ];
+               }
+       },
+
+       // 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 value && value.constructor == 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 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 ) {
+               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;
+                               var padding = 0, border = 0;
+                               jQuery.each( which, function() {
+                                       padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+                                       border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+                               });
+                               val -= Math.round(padding + border);
+                       }
+
+                       if ( jQuery(elem).is(":visible") )
+                               getWH();
+                       else
+                               jQuery.swap( elem, props, getWH );
+
+                       return Math.max(0, val);
+               }
+
+               return jQuery.curCSS( elem, name, force );
+       },
+
+       curCSS: function( elem, name, force ) {
+               var ret, style = elem.style;
+
+               // A helper method for determining if an element's values are broken
+               function color( elem ) {
+                       if ( !jQuery.browser.safari )
+                               return false;
+
+                       // defaultView is cached
+                       var ret = defaultView.getComputedStyle( elem, null );
+                       return !ret || ret.getPropertyValue("color") == "";
+               }
+
+               // We need to handle opacity special in IE
+               if ( name == "opacity" && jQuery.browser.msie ) {
+                       ret = jQuery.attr( style, "opacity" );
+
+                       return ret == "" ?
+                               "1" :
+                               ret;
+               }
+               // Opera sometimes will give the wrong display answer, this fixes it, see #2037
+               if ( jQuery.browser.opera && name == "display" ) {
+                       var save = style.outline;
+                       style.outline = "0 solid black";
+                       style.outline = save;
+               }
+
+               // 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 && !color( elem ) )
+                               ret = computedStyle.getPropertyValue( name );
+
+                       // If the element isn't reporting its values properly in Safari
+                       // then some display: none elements are involved
+                       else {
+                               var swap = [], stack = [], a = elem, i = 0;
+
+                               // Locate all of the parent display: none elements
+                               for ( ; a && color(a); a = a.parentNode )
+                                       stack.unshift(a);
+
+                               // Go through and make them visible, but in reverse
+                               // (It would be better if we knew the exact display type that they had)
+                               for ( ; i < stack.length; i++ )
+                                       if ( color( stack[ i ] ) ) {
+                                               swap[ i ] = stack[ i ].style.display;
+                                               stack[ i ].style.display = "block";
+                                       }
+
+                               // Since we flip the display style, we have to handle that
+                               // one special, otherwise get the value
+                               ret = name == "display" && swap[ stack.length - 1 ] != null ?
+                                       "none" :
+                                       ( computedStyle && computedStyle.getPropertyValue( name ) ) || "";
+
+                               // Finally, revert the display styles back
+                               for ( i = 0; i < swap.length; i++ )
+                                       if ( swap[ i ] != null )
+                                               stack[ i ].style.display = swap[ i ];
+                       }
+
+                       // 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 ) {
+               var ret = [];
+               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;
+
+               jQuery.each(elems, function(i, elem){
+                       if ( !elem )
+                               return;
+
+                       if ( elem.constructor == Number )
+                               elem += '';
+
+                       // 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 = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
+
+                               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.browser.msie &&
+                                       [ 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.browser.msie ) {
+
+                                       // String was a <table>, *may* have spurious <tbody>
+                                       var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
+                                               div.firstChild && div.firstChild.childNodes :
+
+                                               // String was a bare <thead> or <tfoot>
+                                               wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
+                                                       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 ( /^\s/.test( elem ) )
+                                               div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
+
+                               }
+
+                               elem = jQuery.makeArray( div.childNodes );
+                       }
+
+                       if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
+                               return;
+
+                       if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
+                               ret.push( elem );
+
+                       else
+                               ret = jQuery.merge( ret, elem );
+
+               });
+
+               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,
+                       msie = jQuery.browser.msie;
+
+               // 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" && jQuery.browser.safari )
+                               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;
+
+                               return elem[ name ];
+                       }
+
+                       if ( msie && 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 = msie && 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 ( msie && 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 || array.split || array.setInterval || array.call )
+                               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.browser.msie ) {
+                       while ( elem = second[ i++ ] )
+                               if ( elem.nodeType != 8 )
+                                       first[ pos++ ] = elem;
+
+               } else
+                       while ( elem = second[ i++ ] )
+                               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 );
+       }
+});
+
+var userAgent = navigator.userAgent.toLowerCase();
+
+// Figure out what browser is being used
+jQuery.browser = {
+       version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
+       safari: /webkit/.test( userAgent ),
+       opera: /opera/.test( userAgent ),
+       msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
+       mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
+};
+
+var styleFloat = jQuery.browser.msie ?
+       "styleFloat" :
+       "cssFloat";
+
+jQuery.extend({
+       // Check to see if the W3C box model is being used
+       boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
+
+       props: {
+               "for": "htmlFor",
+               "class": "className",
+               "float": styleFloat,
+               cssFloat: styleFloat,
+               styleFloat: styleFloat,
+               readonly: "readOnly",
+               maxlength: "maxLength",
+               cellspacing: "cellSpacing"
+       }
+});
+
+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 ) );
+       };
+});
+
+jQuery.each({
+       appendTo: "append",
+       prependTo: "prepend",
+       insertBefore: "before",
+       insertAfter: "after",
+       replaceAll: "replaceWith"
+}, function(name, original){
+       jQuery.fn[ name ] = function() {
+               var args = arguments;
+
+               return this.each(function(){
+                       for ( var i = 0, length = args.length; i < length; i++ )
+                               jQuery( args[ i ] )[ original ]( this );
+               });
+       };
+});
+
+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 ) {
+               jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
+       },
+
+       remove: function( selector ) {
+               if ( !selector || jQuery.filter( selector, [ this ] ).r.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 ).remove();
+
+               // Remove any remaining nodes
+               while ( this.firstChild )
+                       this.removeChild( this.firstChild );
+       }
+}, function(name, fn){
+       jQuery.fn[ name ] = function(){
+               return this.each( fn, arguments );
+       };
+});
+
+jQuery.each([ "Height", "Width" ], function(i, name){
+       var type = name.toLowerCase();
+
+       jQuery.fn[ type ] = function( size ) {
+               // Get window width or height
+               return this[0] == window ?
+                       // Opera reports document.body.client[Width/Height] properly in both quirks and standards
+                       jQuery.browser.opera && document.body[ "client" + name ] ||
+
+                       // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
+                       jQuery.browser.safari && window[ "inner" + name ] ||
+
+                       // 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(
+                                       Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
+                                       Math.max(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, size.constructor == String ? size : size + "px" );
+       };
+});
+
+// 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 chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
+               "(?:[\\w*_-]|\\\\.)" :
+               "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
+       quickChild = new RegExp("^>\\s*(" + chars + "+)"),
+       quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
+       quickClass = new RegExp("^([#.]?)(" + chars + "*)");
+
+jQuery.extend({
+       expr: {
+               "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
+               "#": function(a,i,m){return a.getAttribute("id")==m[2];},
+               ":": {
+                       // Position Checks
+                       lt: function(a,i,m){return i<m[3]-0;},
+                       gt: function(a,i,m){return i>m[3]-0;},
+                       nth: function(a,i,m){return m[3]-0==i;},
+                       eq: function(a,i,m){return m[3]-0==i;},
+                       first: function(a,i){return i==0;},
+                       last: function(a,i,m,r){return i==r.length-1;},
+                       even: function(a,i){return i%2==0;},
+                       odd: function(a,i){return i%2;},
+
+                       // Child Checks
+                       "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
+                       "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
+                       "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},
+
+                       // Parent Checks
+                       parent: function(a){return a.firstChild;},
+                       empty: function(a){return !a.firstChild;},
+
+                       // Text Check
+                       contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},
+
+                       // Visibility
+                       visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
+                       hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},
+
+                       // Form attributes
+                       enabled: function(a){return !a.disabled;},
+                       disabled: function(a){return a.disabled;},
+                       checked: function(a){return a.checked;},
+                       selected: function(a){return a.selected||jQuery.attr(a,"selected");},
+
+                       // Form elements
+                       text: function(a){return "text"==a.type;},
+                       radio: function(a){return "radio"==a.type;},
+                       checkbox: function(a){return "checkbox"==a.type;},
+                       file: function(a){return "file"==a.type;},
+                       password: function(a){return "password"==a.type;},
+                       submit: function(a){return "submit"==a.type;},
+                       image: function(a){return "image"==a.type;},
+                       reset: function(a){return "reset"==a.type;},
+                       button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
+                       input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},
+
+                       // :has()
+                       has: function(a,i,m){return jQuery.find(m[3],a).length;},
+
+                       // :header
+                       header: function(a){return /h\d/i.test(a.nodeName);},
+
+                       // :animated
+                       animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
+               }
+       },
+
+       // The regular expressions that power the parsing engine
+       parse: [
+               // Match: [@value='test'], [@foo]
+               /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
+
+               // Match: :contains('foo')
+               /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
+
+               // Match: :even, :last-child, #id, .class
+               new RegExp("^([:.#]*)(" + chars + "+)")
+       ],
+
+       multiFilter: function( expr, elems, not ) {
+               var old, cur = [];
+
+               while ( expr && expr != old ) {
+                       old = expr;
+                       var f = jQuery.filter( expr, elems, not );
+                       expr = f.t.replace(/^\s*,\s*/, "" );
+                       cur = not ? elems = f.r : jQuery.merge( cur, f.r );
+               }
+
+               return cur;
+       },
+
+       find: function( t, context ) {
+               // Quickly handle non-string expressions
+               if ( typeof t != "string" )
+                       return [ t ];
+
+               // check to make sure context is a DOM element or a document
+               if ( context && context.nodeType != 1 && context.nodeType != 9)
+                       return [ ];
+
+               // Set the correct context (if none is provided)
+               context = context || document;
+
+               // Initialize the search
+               var ret = [context], done = [], last, nodeName;
+
+               // Continue while a selector expression exists, and while
+               // we're no longer looping upon ourselves
+               while ( t && last != t ) {
+                       var r = [];
+                       last = t;
+
+                       t = jQuery.trim(t);
+
+                       var foundToken = false,
+
+                       // An attempt at speeding up child selectors that
+                       // point to a specific element tag
+                               re = quickChild,
+
+                               m = re.exec(t);
+
+                       if ( m ) {
+                               nodeName = m[1].toUpperCase();
+
+                               // Perform our own iteration and filter
+                               for ( var i = 0; ret[i]; i++ )
+                                       for ( var c = ret[i].firstChild; c; c = c.nextSibling )
+                                               if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
+                                                       r.push( c );
+
+                               ret = r;
+                               t = t.replace( re, "" );
+                               if ( t.indexOf(" ") == 0 ) continue;
+                               foundToken = true;
+                       } else {
+                               re = /^([>+~])\s*(\w*)/i;
+
+                               if ( (m = re.exec(t)) != null ) {
+                                       r = [];
+
+                                       var merge = {};
+                                       nodeName = m[2].toUpperCase();
+                                       m = m[1];
+
+                                       for ( var j = 0, rl = ret.length; j < rl; j++ ) {
+                                               var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
+                                               for ( ; n; n = n.nextSibling )
+                                                       if ( n.nodeType == 1 ) {
+                                                               var id = jQuery.data(n);
+
+                                                               if ( m == "~" && merge[id] ) break;
+
+                                                               if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
+                                                                       if ( m == "~" ) merge[id] = true;
+                                                                       r.push( n );
+                                                               }
+
+                                                               if ( m == "+" ) break;
+                                                       }
+                                       }
+
+                                       ret = r;
+
+                                       // And remove the token
+                                       t = jQuery.trim( t.replace( re, "" ) );
+                                       foundToken = true;
+                               }
+                       }
+
+                       // See if there's still an expression, and that we haven't already
+                       // matched a token
+                       if ( t && !foundToken ) {
+                               // Handle multiple expressions
+                               if ( !t.indexOf(",") ) {
+                                       // Clean the result set
+                                       if ( context == ret[0] ) ret.shift();
+
+                                       // Merge the result sets
+                                       done = jQuery.merge( done, ret );
+
+                                       // Reset the context
+                                       r = ret = [context];
+
+                                       // Touch up the selector string
+                                       t = " " + t.substr(1,t.length);
+
+                               } else {
+                                       // Optimize for the case nodeName#idName
+                                       var re2 = quickID;
+                                       var m = re2.exec(t);
+
+                                       // Re-organize the results, so that they're consistent
+                                       if ( m ) {
+                                               m = [ 0, m[2], m[3], m[1] ];
+
+                                       } else {
+                                               // Otherwise, do a traditional filter check for
+                                               // ID, class, and element selectors
+                                               re2 = quickClass;
+                                               m = re2.exec(t);
+                                       }
+
+                                       m[2] = m[2].replace(/\\/g, "");
+
+                                       var elem = ret[ret.length-1];
+
+                                       // Try to do a global search by ID, where we can
+                                       if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
+                                               // Optimization for HTML document case
+                                               var oid = elem.getElementById(m[2]);
+
+                                               // Do a quick check for the existence of the actual ID attribute
+                                               // to avoid selecting by the name attribute in IE
+                                               // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
+                                               if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
+                                                       oid = jQuery('[@id="'+m[2]+'"]', elem)[0];
+
+                                               // Do a quick check for node name (where applicable) so
+                                               // that div#foo searches will be really fast
+                                               ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];
+                                       } else {
+                                               // We need to find all descendant elements
+                                               for ( var i = 0; ret[i]; i++ ) {
+                                                       // Grab the tag name being searched for
+                                                       var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];
+
+                                                       // Handle IE7 being really dumb about <object>s
+                                                       if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
+                                                               tag = "param";
+
+                                                       r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
+                                               }
+
+                                               // It's faster to filter by class and be done with it
+                                               if ( m[1] == "." )
+                                                       r = jQuery.classFilter( r, m[2] );
+
+                                               // Same with ID filtering
+                                               if ( m[1] == "#" ) {
+                                                       var tmp = [];
+
+                                                       // Try to find the element with the ID
+                                                       for ( var i = 0; r[i]; i++ )
+                                                               if ( r[i].getAttribute("id") == m[2] ) {
+                                                                       tmp = [ r[i] ];
+                                                                       break;
+                                                               }
+
+                                                       r = tmp;
+                                               }
+
+                                               ret = r;
+                                       }
+
+                                       t = t.replace( re2, "" );
+                               }
+
+                       }
+
+                       // If a selector string still exists
+                       if ( t ) {
+                               // Attempt to filter it
+                               var val = jQuery.filter(t,r);
+                               ret = r = val.r;
+                               t = jQuery.trim(val.t);
+                       }
+               }
+
+               // An error occurred with the selector;
+               // just return an empty set instead
+               if ( t )
+                       ret = [];
+
+               // Remove the root context
+               if ( ret && context == ret[0] )
+                       ret.shift();
+
+               // And combine the results
+               done = jQuery.merge( done, ret );
+
+               return done;
+       },
+
+       classFilter: function(r,m,not){
+               m = " " + m + " ";
+               var tmp = [];
+               for ( var i = 0; r[i]; i++ ) {
+                       var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
+                       if ( !not && pass || not && !pass )
+                               tmp.push( r[i] );
+               }
+               return tmp;
+       },
+
+       filter: function(t,r,not) {
+               var last;
+
+               // Look for common filter expressions
+               while ( t && t != last ) {
+                       last = t;
+
+                       var p = jQuery.parse, m;
+
+                       for ( var i = 0; p[i]; i++ ) {
+                               m = p[i].exec( t );
+
+                               if ( m ) {
+                                       // Remove what we just matched
+                                       t = t.substring( m[0].length );
+
+                                       m[2] = m[2].replace(/\\/g, "");
+                                       break;
+                               }
+                       }
+
+                       if ( !m )
+                               break;
+
+                       // :not() is a special case that can be optimized by
+                       // keeping it out of the expression list
+                       if ( m[1] == ":" && m[2] == "not" )
+                               // optimize if only one selector found (most common case)
+                               r = isSimple.test( m[3] ) ?
+                                       jQuery.filter(m[3], r, true).r :
+                                       jQuery( r ).not( m[3] );
+
+                       // We can get a big speed boost by filtering by class here
+                       else if ( m[1] == "." )
+                               r = jQuery.classFilter(r, m[2], not);
+
+                       else if ( m[1] == "[" ) {
+                               var tmp = [], type = m[3];
+
+                               for ( var i = 0, rl = r.length; i < rl; i++ ) {
+                                       var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
+
+                                       if ( z == null || /href|src|selected/.test(m[2]) )
+                                               z = jQuery.attr(a,m[2]) || '';
+
+                                       if ( (type == "" && !!z ||
+                                                type == "=" && z == m[5] ||
+                                                type == "!=" && z != m[5] ||
+                                                type == "^=" && z && !z.indexOf(m[5]) ||
+                                                type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
+                                                (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
+                                                       tmp.push( a );
+                               }
+
+                               r = tmp;
+
+                       // We can get a speed boost by handling nth-child here
+                       } else if ( m[1] == ":" && m[2] == "nth-child" ) {
+                               var merge = {}, tmp = [],
+                                       // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+                                       test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+                                               m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
+                                               !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
+                                       // calculate the numbers (first)n+(last) including if they are negative
+                                       first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
+
+                               // loop through all the elements left in the jQuery object
+                               for ( var i = 0, rl = r.length; i < rl; i++ ) {
+                                       var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
+
+                                       if ( !merge[id] ) {
+                                               var c = 1;
+
+                                               for ( var n = parentNode.firstChild; n; n = n.nextSibling )
+                                                       if ( n.nodeType == 1 )
+                                                               n.nodeIndex = c++;
+
+                                               merge[id] = true;
+                                       }
+
+                                       var add = false;
+
+                                       if ( first == 0 ) {
+                                               if ( node.nodeIndex == last )
+                                                       add = true;
+                                       } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
+                                               add = true;
+
+                                       if ( add ^ not )
+                                               tmp.push( node );
+                               }
+
+                               r = tmp;
+
+                       // Otherwise, find the expression to execute
+                       } else {
+                               var fn = jQuery.expr[ m[1] ];
+                               if ( typeof fn == "object" )
+                                       fn = fn[ m[2] ];
+
+                               if ( typeof fn == "string" )
+                                       fn = eval("false||function(a,i){return " + fn + ";}");
+
+                               // Execute it against the current filter
+                               r = jQuery.grep( r, function(elem, i){
+                                       return fn(elem, i, m, r);
+                               }, not );
+                       }
+               }
+
+               // Return an array of filtered elements (r)
+               // and the modified expression string (t)
+               return { r: r, t: t };
+       },
+
+       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;
+       },
+
+       nth: function(cur,result,dir,elem){
+               result = result || 1;
+               var num = 0;
+
+               for ( ; cur; cur = cur[dir] )
+                       if ( cur.nodeType == 1 && ++num == result )
+                               break;
+
+               return cur;
+       },
+
+       sibling: function( n, elem ) {
+               var r = [];
+
+               for ( ; n; n = n.nextSibling ) {
+                       if ( n.nodeType == 1 && n != elem )
+                               r.push( n );
+               }
+
+               return r;
+       }
+});
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code orignated 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 ( jQuery.browser.msie && elem.setInterval )
+                       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, function() {
+                               // Pass arguments and context to original handler
+                               return fn.apply(this, arguments);
+                       });
+
+                       // 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
+                               if ( typeof jQuery != "undefined" && !jQuery.event.triggered )
+                                       return jQuery.event.handle.apply(arguments.callee.elem, arguments);
+                       });
+               // 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 parts = type.split(".");
+                       type = parts[0];
+                       handler.type = parts[1];
+
+                       // Get the current list of functions bound to this event
+                       var handlers = events[type];
+
+                       // Init the event handler queue
+                       if (!handlers) {
+                               handlers = events[type] = {};
+
+                               // Check for a special event handler
+                               // Only use addEventListener/attachEvent if the special
+                               // events handler returns false
+                               if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === 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 parts = type.split(".");
+                                       type = parts[0];
+
+                                       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 ( handler in events[type] )
+                                                               // Handle the removal of namespaced events
+                                                               if ( !parts[1] || events[type][handler].type == parts[1] )
+                                                                       delete events[type][handler];
+
+                                               // 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) === 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" );
+                       }
+               }
+       },
+
+       trigger: function(type, data, elem, donative, extra) {
+               // Clone the incoming data, if any
+               data = jQuery.makeArray(data);
+
+               if ( type.indexOf("!") >= 0 ) {
+                       type = type.slice(0, -1);
+                       var exclusive = true;
+               }
+
+               // Handle a global trigger
+               if ( !elem ) {
+                       // Only trigger if we've ever bound an event for it
+                       if ( this.global[type] )
+                               jQuery("*").add([window, document]).trigger(type, data);
+
+               // Handle triggering a single element
+               } else {
+                       // don't do events on text and comment nodes
+                       if ( elem.nodeType == 3 || elem.nodeType == 8 )
+                               return undefined;
+
+                       var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
+                               // Check to see if we need to provide a fake event, or not
+                               event = !data[0] || !data[0].preventDefault;
+
+                       // Pass along a fake event
+                       if ( event ) {
+                               data.unshift({
+                                       type: type,
+                                       target: elem,
+                                       preventDefault: function(){},
+                                       stopPropagation: function(){},
+                                       timeStamp: now()
+                               });
+                               data[0][expando] = true; // no need to fix fake event
+                       }
+
+                       // Enforce the right trigger type
+                       data[0].type = type;
+                       if ( exclusive )
+                               data[0].exclusive = true;
+
+                       // Trigger the event, it is assumed that "handle" is a function
+                       var handle = jQuery.data(elem, "handle");
+                       if ( handle )
+                               val = handle.apply( elem, data );
+
+                       // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
+                       if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
+                               val = false;
+
+                       // Extra functions don't get the custom event object
+                       if ( event )
+                               data.shift();
+
+                       // Handle triggering of extra function
+                       if ( extra && jQuery.isFunction( extra ) ) {
+                               // call the extra function and tack the current return value on the end for possible inspection
+                               ret = extra.apply( elem, val == null ? data : data.concat( val ) );
+                               // if anything is returned, give it precedence and have it overwrite the previous value
+                               if (ret !== undefined)
+                                       val = ret;
+                       }
+
+                       // Trigger the native events (except for clicks on links)
+                       if ( fn && donative !== false && val !== false && !(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;
+               }
+
+               return val;
+       },
+
+       handle: function(event) {
+               // returned undefined or false
+               var val, ret, namespace, all, handlers;
+
+               event = arguments[0] = jQuery.event.fix( event || window.event );
+
+               // Namespaced event handlers
+               namespace = event.type.split(".");
+               event.type = namespace[0];
+               namespace = namespace[1];
+               // Cache this now, all = true means, any handler
+               all = !namespace && !event.exclusive;
+
+               handlers = ( jQuery.data(this, "events") || {} )[event.type];
+
+               for ( var j in handlers ) {
+                       var handler = handlers[j];
+
+                       // Filter the functions by class
+                       if ( all || handler.type == namespace ) {
+                               // Pass in a reference to the handler function itself
+                               // So that we can later remove it
+                               event.handler = handler;
+                               event.data = handler.data;
+
+                               ret = handler.apply( this, arguments );
+
+                               if ( val !== false )
+                                       val = ret;
+
+                               if ( ret === false ) {
+                                       event.preventDefault();
+                                       event.stopPropagation();
+                               }
+                       }
+               }
+
+               return val;
+       },
+
+       fix: function(event) {
+               if ( event[expando] == true )
+                       return event;
+
+               // store a copy of the original event object
+               // and "clone" to set read-only properties
+               var originalEvent = event;
+               event = { originalEvent: originalEvent };
+               var 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 timeStamp toElement type view wheelDelta which".split(" ");
+               for ( var i=props.length; i; i-- )
+                       event[ props[i] ] = originalEvent[ props[i] ];
+
+               // Mark it as fixed
+               event[expando] = true;
+
+               // add preventDefault and stopPropagation since
+               // they will not work on the clone
+               event.preventDefault = function() {
+                       // if preventDefault exists run it on the original event
+                       if (originalEvent.preventDefault)
+                               originalEvent.preventDefault();
+                       // otherwise set the returnValue property of the original event to false (IE)
+                       originalEvent.returnValue = false;
+               };
+               event.stopPropagation = function() {
+                       // if stopPropagation exists run it on the original event
+                       if (originalEvent.stopPropagation)
+                               originalEvent.stopPropagation();
+                       // otherwise set the cancelBubble property of the original event to true (IE)
+                       originalEvent.cancelBubble = true;
+               };
+
+               // Fix timeStamp
+               event.timeStamp = event.timeStamp || now();
+
+               // 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 ){
+               // 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: {
+                       setup: function() {
+                               // Make sure the ready event is setup
+                               bindReady();
+                               return;
+                       },
+
+                       teardown: function() { return; }
+               },
+
+               mouseenter: {
+                       setup: function() {
+                               if ( jQuery.browser.msie ) return false;
+                               jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
+                               return true;
+                       },
+
+                       teardown: function() {
+                               if ( jQuery.browser.msie ) return false;
+                               jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
+                               return true;
+                       },
+
+                       handler: function(event) {
+                               // If we actually just moused on to a sub-element, ignore it
+                               if ( withinElement(event, this) ) return true;
+                               // Execute the right handlers by setting the event type to mouseenter
+                               event.type = "mouseenter";
+                               return jQuery.event.handle.apply(this, arguments);
+                       }
+               },
+
+               mouseleave: {
+                       setup: function() {
+                               if ( jQuery.browser.msie ) return false;
+                               jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
+                               return true;
+                       },
+
+                       teardown: function() {
+                               if ( jQuery.browser.msie ) return false;
+                               jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
+                               return true;
+                       },
+
+                       handler: function(event) {
+                               // If we actually just moused on to a sub-element, ignore it
+                               if ( withinElement(event, this) ) return true;
+                               // Execute the right handlers by setting the event type to mouseleave
+                               event.type = "mouseleave";
+                               return jQuery.event.handle.apply(this, arguments);
+                       }
+               }
+       }
+};
+
+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, fn ) {
+               return this.each(function(){
+                       jQuery.event.trigger( type, data, this, true, fn );
+               });
+       },
+
+       triggerHandler: function( type, data, fn ) {
+               return this[0] && jQuery.event.trigger( type, data, this[0], false, fn );
+       },
+
+       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.bind('mouseenter', fnOver).bind('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( function() { return fn.call(this, jQuery); } );
+
+               return this;
+       }
+});
+
+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 );
+                               });
+
+                               // 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 (see further below for it) and webkit nightlies currently support this event
+       if ( document.addEventListener && !jQuery.browser.opera)
+               // Use the handy event callback
+               document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
+
+       // If IE is used and is not in a frame
+       // Continually check to see if the document is ready
+       if ( jQuery.browser.msie && 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();
+       })();
+
+       if ( jQuery.browser.opera )
+               document.addEventListener( "DOMContentLoaded", function () {
+                       if (jQuery.isReady) return;
+                       for (var i = 0; i < document.styleSheets.length; i++)
+                               if (document.styleSheets[i].disabled) {
+                                       setTimeout( arguments.callee, 0 );
+                                       return;
+                               }
+                       // and execute any waiting functions
+                       jQuery.ready();
+               }, false);
+
+       if ( jQuery.browser.safari ) {
+               var numStyles;
+               (function(){
+                       if (jQuery.isReady) return;
+                       if ( document.readyState != "loaded" && document.readyState != "complete" ) {
+                               setTimeout( arguments.callee, 0 );
+                               return;
+                       }
+                       if ( numStyles === undefined )
+                               numStyles = jQuery("style, link[rel=stylesheet]").length;
+                       if ( document.styleSheets.length != numStyles ) {
+                               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,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);
+       };
+});
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function(event, elem) {
+       // Check if mouse(over|out) are still within the same parent element
+       var parent = event.relatedTarget;
+       // Traverse up the tree
+       while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
+       // Return true if we actually just moused on to a sub-element
+       return parent == elem;
+};
+
+// 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() {
+       jQuery("*").add(document).unbind();
+});
+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);
+               }
+
+               callback = callback || function(){};
+
+               // 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 {
+                               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 );
+
+                               self.each( callback, [res.responseText, status, res] );
+                       }
+               });
+               return this;
+       },
+
+       serialize: function() {
+               return jQuery.param(this.serializeArray());
+       },
+       serializeArray: function() {
+               return this.map(function(){
+                       return jQuery.nodeName(this, "form") ?
+                               jQuery.makeArray(this.elements) : this;
+               })
+               .filter(function(){
+                       return this.name && !this.disabled &&
+                               (this.checked || /select|textarea/i.test(this.nodeName) ||
+                                       /text|hidden|password/i.test(this.type));
+               })
+               .map(function(i, elem){
+                       var val = jQuery(this).val();
+                       return val == null ? null :
+                               val.constructor == Array ?
+                                       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",
+               timeout: 0,
+               contentType: "application/x-www-form-urlencoded",
+               processData: true,
+               async: true,
+               data: null,
+               username: null,
+               password: null,
+               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 remote = /^(?:\w+:)?\/\/([^\/?#]+)/;
+
+               // If we're requesting a remote document
+               // and trying to load JSON or Script with a GET
+               if ( s.dataType == "script" && type == "GET"
+                               && remote.test(s.url) && remote.exec(s.url)[1] != 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();
+                                               head.removeChild( script );
+                                       }
+                               };
+                       }
+
+                       head.appendChild(script);
+
+                       // We handle everything using the script element injection
+                       return undefined;
+               }
+
+               var requestDone = false;
+
+               // Create the request object; Microsoft failed to properly
+               // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
+               var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+
+               // 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
+               if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
+                       // cleanup active request counter
+                       s.global && jQuery.active--;
+                       // 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 transfer is complete and the data is available, or the request timed out
+                       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.dataFilter );
+                                       } 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();
+
+                               // 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 ) {
+                                               // Cancel the request
+                                               xhr.abort();
+
+                                               if( !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 ||
+                               jQuery.browser.safari && xhr.status == undefined;
+               } 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] ||
+                               jQuery.browser.safari && xhr.status == undefined;
+               } catch(e){}
+               return false;
+       },
+
+       httpData: function( xhr, type, filter ) {
+               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
+               if( filter )
+                       data = filter( data, type );
+
+               // 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 = 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 = [];
+
+               // If an array was passed in, assume that it is an array
+               // of form elements
+               if ( a.constructor == Array || a.jquery )
+                       // Serialize the form elements
+                       jQuery.each( a, function(){
+                               s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( 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 ( a[j] && a[j].constructor == Array )
+                                       jQuery.each( a[j], function(){
+                                               s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );
+                                       });
+                               else
+                                       s.push( encodeURIComponent(j) + "=" + encodeURIComponent( jQuery.isFunction(a[j]) ? a[j]() : a[j] ) );
+
+               // Return the resulting serialization
+               return s.join("&").replace(/%20/g, "+");
+       }
+
+});
+jQuery.fn.extend({
+       show: function(speed,callback){
+               return speed ?
+                       this.animate({
+                               height: "show", width: "show", opacity: "show"
+                       }, speed, callback) :
+
+                       this.filter(":hidden").each(function(){
+                               this.style.display = this.oldblock || "";
+                               if ( jQuery.css(this,"display") == "none" ) {
+                                       var elem = jQuery("<" + this.tagName + " />").appendTo("body");
+                                       this.style.display = elem.css("display");
+                                       // handle an edge condition where css is - div { display:none; } or similar
+                                       if (this.style.display == "none")
+                                               this.style.display = "block";
+                                       elem.remove();
+                               }
+                       }).end();
+       },
+
+       hide: function(speed,callback){
+               return speed ?
+                       this.animate({
+                               height: "hide", width: "hide", opacity: "hide"
+                       }, speed, callback) :
+
+                       this.filter(":visible").each(function(){
+                               this.oldblock = this.oldblock || jQuery.css(this,"display");
+                               this.style.display = "none";
+                       }).end();
+       },
+
+       // Save the old toggle function
+       _toggle: jQuery.fn.toggle,
+
+       toggle: function( fn, fn2 ){
+               return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
+                       this._toggle.apply( this, arguments ) :
+                       fn ?
+                               this.animate({
+                                       height: "toggle", width: "toggle", opacity: "toggle"
+                               }, fn, fn2) :
+                               this.each(function(){
+                                       jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+                               });
+       },
+
+       slideDown: function(speed,callback){
+               return this.animate({height: "show"}, speed, callback);
+       },
+
+       slideUp: function(speed,callback){
+               return this.animate({height: "hide"}, speed, callback);
+       },
+
+       slideToggle: function(speed, callback){
+               return this.animate({height: "toggle"}, speed, callback);
+       },
+
+       fadeIn: function(speed, callback){
+               return this.animate({opacity: "show"}, speed, callback);
+       },
+
+       fadeOut: function(speed, callback){
+               return this.animate({opacity: "hide"}, speed, callback);
+       },
+
+       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(){
+                       if ( this.nodeType != 1)
+                               return false;
+
+                       var opt = jQuery.extend({}, optall), p,
+                               hidden = 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" ) {
+                                       // 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;
+               });
+       },
+
+       queue: function(type, fn){
+               if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
+                       fn = type;
+                       type = "fx";
+               }
+
+               if ( !type || (typeof type == "string" && !fn) )
+                       return queue( this[0], type );
+
+               return this.each(function(){
+                       if ( fn.constructor == Array )
+                               queue(this, type, fn);
+                       else {
+                               queue(this, type).push( fn );
+
+                               if ( queue(this, type).length == 1 )
+                                       fn.call(this);
+                       }
+               });
+       },
+
+       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;
+       }
+
+});
+
+var queue = function( elem, type, array ) {
+       if ( elem ){
+
+               type = type || "fx";
+
+               var q = jQuery.data( elem, type + "queue" );
+
+               if ( !q || array )
+                       q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );
+
+       }
+       return q;
+};
+
+jQuery.fn.dequeue = function(type){
+       type = type || "fx";
+
+       return this.each(function(){
+               var q = queue(this, type);
+
+               q.shift();
+
+               if ( q.length )
+                       q[0].call( this );
+       });
+};
+
+jQuery.extend({
+
+       speed: function(speed, easing, fn) {
+               var opt = speed && speed.constructor == Object ? speed : {
+                       complete: fn || !fn && easing ||
+                               jQuery.isFunction( speed ) && speed,
+                       duration: speed,
+                       easing: fn && easing || easing && easing.constructor != Function && easing
+               };
+
+               opt.duration = (opt.duration && opt.duration.constructor == Number ?
+                       opt.duration :
+                       jQuery.fx.speeds[opt.duration]) || jQuery.fx.speeds.def;
+
+               // 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: [],
+       timerId: null,
+
+       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.display = "block";
+       },
+
+       // Get the current size
+       cur: function(force){
+               if ( this.elem[this.prop] != null && 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;
+               this.update();
+
+               var self = this;
+               function t(gotoEnd){
+                       return self.step(gotoEnd);
+               }
+
+               t.elem = this.elem;
+
+               jQuery.timers.push(t);
+
+               if ( jQuery.timerId == null ) {
+                       jQuery.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( jQuery.timerId );
+                                       jQuery.timerId = null;
+                               }
+                       }, 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
+               this.custom(0, this.cur());
+
+               // Make sure that we start at a small width/height to avoid any
+               // flash of content
+               if ( this.prop == "width" || this.prop == "height" )
+                       this.elem.style[this.prop] = "1px";
+
+               // 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 )
+                                       this.elem.style.display = "none";
+
+                               // 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]);
+                       }
+
+                       if ( done )
+                               // 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
+               def: 400
+       },
+       step: {
+               scrollLeft: function(fx){
+                       fx.elem.scrollLeft = fx.now;
+               },
+
+               scrollTop: function(fx){
+                       fx.elem.scrollTop = fx.now;
+               },
+
+               opacity: function(fx){
+                       jQuery.attr(fx.elem.style, "opacity", fx.now);
+               },
+
+               _default: function(fx){
+                       fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+               }
+       }
+});
+// The Offset Method
+// Originally By Brandon Aaron, part of the Dimension Plugin
+// http://jquery.com/plugins/project/dimensions
+jQuery.fn.offset = function() {
+       var left = 0, top = 0, elem = this[0], results;
+
+       if ( elem ) with ( jQuery.browser ) {
+               var parent       = elem.parentNode,
+                   offsetChild  = elem,
+                   offsetParent = elem.offsetParent,
+                   doc          = elem.ownerDocument,
+                   safari2      = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
+                   css          = jQuery.curCSS,
+                   fixed        = css(elem, "position") == "fixed";
+
+               // Use getBoundingClientRect if available
+               if ( elem.getBoundingClientRect ) {
+                       var box = elem.getBoundingClientRect();
+
+                       // Add the document scroll offsets
+                       add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+                               box.top  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
+
+                       // IE adds the HTML element's border, by default it is medium which is 2px
+                       // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
+                       // IE 7 standards mode, the border is always 2px
+                       // This border/offset is typically represented by the clientLeft and clientTop properties
+                       // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
+                       // Therefore this method will be off by 2px in IE while in quirksmode
+                       add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
+
+               // Otherwise loop through the offsetParents and parentNodes
+               } else {
+
+                       // Initial element offsets
+                       add( elem.offsetLeft, elem.offsetTop );
+
+                       // Get parent offsets
+                       while ( offsetParent ) {
+                               // Add offsetParent offsets
+                               add( offsetParent.offsetLeft, offsetParent.offsetTop );
+
+                               // Mozilla and Safari > 2 does not include the border on offset parents
+                               // However Mozilla adds the border for table or table cells
+                               if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
+                                       border( offsetParent );
+
+                               // Add the document scroll offsets if position is fixed on any offsetParent
+                               if ( !fixed && css(offsetParent, "position") == "fixed" )
+                                       fixed = true;
+
+                               // Set offsetChild to previous offsetParent unless it is the body element
+                               offsetChild  = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
+                               // Get next offsetParent
+                               offsetParent = offsetParent.offsetParent;
+                       }
+
+                       // Get parent scroll offsets
+                       while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
+                               // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
+                               if ( !/^inline|table.*$/i.test(css(parent, "display")) )
+                                       // Subtract parent scroll offsets
+                                       add( -parent.scrollLeft, -parent.scrollTop );
+
+                               // Mozilla does not add the border for a parent that has overflow != visible
+                               if ( mozilla && css(parent, "overflow") != "visible" )
+                                       border( parent );
+
+                               // Get next parent
+                               parent = parent.parentNode;
+                       }
+
+                       // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
+                       // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
+                       if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
+                               (mozilla && css(offsetChild, "position") != "absolute") )
+                                       add( -doc.body.offsetLeft, -doc.body.offsetTop );
+
+                       // Add the document scroll offsets if position is fixed
+                       if ( fixed )
+                               add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+                                       Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
+               }
+
+               // Return an object with top and left properties
+               results = { top: top, left: left };
+       }
+
+       function border(elem) {
+               add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
+       }
+
+       function add(l, t) {
+               left += parseInt(l, 10) || 0;
+               top += parseInt(t, 10) || 0;
+       }
+
+       return results;
+};
+
+
+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;
+               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;
+
+               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
+
+       // innerHeight and innerWidth
+       jQuery.fn["inner" + name] = function(){
+               return this[ name.toLowerCase() ]() +
+                       num(this, "padding" + tl) +
+                       num(this, "padding" + br);
+       };
+
+       // outerHeight and outerWidth
+       jQuery.fn["outer" + name] = function(margin) {
+               return this["inner" + name]() +
+                       num(this, "border" + tl + "Width") +
+                       num(this, "border" + br + "Width") +
+                       (margin ?
+                               num(this, "margin" + tl) + num(this, "margin" + br) : 0);
+       };
+
+});})();
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/jquery-1.3.2.min.js b/mods/atutor_opencaps/opencaps/js/jquery/jquery-1.3.2.min.js
new file mode 100755 (executable)
index 0000000..55c2e6d
--- /dev/null
@@ -0,0 +1,19 @@
+/*\r
+ * jQuery JavaScript Library v1.3.2\r
+ * http://jquery.com/\r
+ *\r
+ * Copyright (c) 2009 John Resig\r
+ * Dual licensed under the MIT and GPL licenses.\r
+ * http://docs.jquery.com/License\r
+ *\r
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)\r
+ * Revision: 6246\r
+ */\r
+(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)})}});\r
+/*\r
+ * Sizzle CSS Selector Engine - v0.9.3\r
+ *  Copyright 2009, The Dojo Foundation\r
+ *  Released under the MIT, BSD, and GPL Licenses.\r
+ *  More information: http://sizzlejs.com/\r
+ */\r
+(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/mods/atutor_opencaps/opencaps/js/jquery/jquery.dimensions.js b/mods/atutor_opencaps/opencaps/js/jquery/jquery.dimensions.js
new file mode 100755 (executable)
index 0000000..b52ff25
--- /dev/null
@@ -0,0 +1 @@
+(function(B){B.dimensions={version:"@VERSION"};B.each(["Height","Width"],function(D,C){B.fn["inner"+C]=function(){if(!this[0]){return }var F=C=="Height"?"Top":"Left",E=C=="Height"?"Bottom":"Right";return this.css("display")!="none"?this[0]["client"+C]:A(this,C.toLowerCase())+A(this,"padding"+F)+A(this,"padding"+E)};B.fn["outer"+C]=function(F){if(!this[0]){return }var H=C=="Height"?"Top":"Left",E=C=="Height"?"Bottom":"Right";F=B.extend({margin:false},F||{});var G=this.css("display")!="none"?this[0]["offset"+C]:A(this,C.toLowerCase())+A(this,"border"+H+"Width")+A(this,"border"+E+"Width")+A(this,"padding"+H)+A(this,"padding"+E);return G+(F.margin?(A(this,"margin"+H)+A(this,"margin"+E)):0)}});B.each(["Left","Top"],function(D,C){B.fn["scroll"+C]=function(E){if(!this[0]){return }return E!=undefined?this.each(function(){this==window||this==document?window.scrollTo(C=="Left"?E:B(window)["scrollLeft"](),C=="Top"?E:B(window)["scrollTop"]()):this["scroll"+C]=E}):this[0]==window||this[0]==document?self[(C=="Left"?"pageXOffset":"pageYOffset")]||B.boxModel&&document.documentElement["scroll"+C]||document.body["scroll"+C]:this[0]["scroll"+C]}});B.fn.extend({position:function(){var H=0,G=0,F=this[0],I,C,E,D;if(F){E=this.offsetParent();I=this.offset();C=E.offset();I.top-=A(F,"marginTop");I.left-=A(F,"marginLeft");C.top+=A(E,"borderTopWidth");C.left+=A(E,"borderLeftWidth");D={top:I.top-C.top,left:I.left-C.left}}return D},offsetParent:function(){var C=this[0].offsetParent;while(C&&(!/^body|html$/i.test(C.tagName)&&B.css(C,"position")=="static")){C=C.offsetParent}return B(C)}});function A(C,D){return parseInt(B.curCSS(C.jquery?C[0]:C,D,true))||0}})(jQuery);
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/jquery.keyboard-a11y.js b/mods/atutor_opencaps/opencaps/js/jquery/jquery.keyboard-a11y.js
new file mode 100755 (executable)
index 0000000..c719d1b
--- /dev/null
@@ -0,0 +1 @@
+(function(J){J.a11y=J.a11y||{};J.a11y.keys={UP:38,DOWN:40,LEFT:37,RIGHT:39,SPACE:32,ENTER:13,TAB:9,CTRL:17,SHIFT:16,ALT:18};J.a11y.orientation={HORIZONTAL:0,VERTICAL:1,BOTH:2};var T="keyboard-a11y";var N="selectionContext";var P="userHandlers";var c="defaultActivate";var U={next:J.a11y.keys.DOWN,previous:J.a11y.keys.UP};var B={next:J.a11y.keys.RIGHT,previous:J.a11y.keys.LEFT};var Z=function(e){return(e.jquery)?e[0]:e};var O=function(f,e,g){if(f.willLeaveContainer){f.willLeaveContainer(e.activeItem)}else{if(f.willUnselect){f.willUnselect(e.activeItem)}}if(!g){e.activeItem=null}};var A=function(j,f){if(!j.modifier){return true}var g=j.modifier;var h=(g&&f.ctrlKey);var e=(g&&f.altKey);var i=(g&&f.shiftKey);return(h||e||i)};var F=function(e){return function(f){if(f.which===e.key&&e.activateHandler&&A(e,f)){e.activateHandler(f.target,f);f.preventDefault()}}};var M=function(e,f){if(f){f(e)}};var W=function(f,e){if(e){e(f)}};var E=function(g,e,f){W(g,f.willUnselect)};var X=function(e,f,g){if(f.activeItem){E(f.activeItem,f,g)}e=Z(e);if(f.selectables.index(e)===-1){return }f.activeItem=e;M(e,g.willSelect)};var d=function(e,f){return function(g){X(g.target,e,f);return g.stopPropagation()}};var G=function(e,f){return function(g){E(g.target,e,f);return g.stopPropagation()}};var a=function(f){var g=f.selectables;var i=f.activeItem;var h=(!i)?-1:g.index(i);var e=h+1;e=(e>=g.length)?e=0:e;g.eq(e).focus()};var L=function(e){var f=e.selectables;var i=e.activeItem;var h=(!i)?0:f.index(i);var g=h-1;g=(g<0)?f.length-1:g;f.eq(g).focus()};var I=function(e,g,f){return function(h){if(h.which===g.next){a(e);h.preventDefault()}else{if(h.which===g.previous){L(e);h.preventDefault()}}}};var S=function(e){var f;if(e===J.a11y.orientation.HORIZONTAL){f=B}else{f=U}return f};var Q=function(f,e,g){return function(h){var i=(g.constructor===Function)?g():g;if(f.focusIsLeavingContainer){i=false}if(i&&h.target===e.get(0)){if(!f.activeItem){a(f)}else{jQuery(f.activeItem).focus()}}return h.stopPropagation()}};var Y=function(e){return function(f){e.focusIsLeavingContainer=false;return f.stopPropagation()}};var V=function(e){e.each(function(f,g){g=J(g);if(!g.hasTabindex()||(g.tabindex()<0)){g.tabindex(0)}})};var b=function(h,l,e,f){var k=[];J(e).each(function(i,m){k.push({modifier:null,key:m,activateHandler:l})});if(f&&f.additionalBindings){k=k.concat(f.additionalBindings)}for(var g=0;g<k.length;g=g+1){var j=k[g];h.keydown(F(j))}};var C=function(f,e,g){return function(h){if(h.which!==J.a11y.keys.TAB){return }O(f,e,g);if(h.shiftKey){e.focusIsLeavingContainer=true}}};var D=function(g,e,h,j,i){h=h||{};var l=J.extend({},j,i);var k=S(l.direction);var f={activeItem:undefined,selectables:e,focusIsLeavingContainer:false};g.keydown(I(f,k,h));g.keydown(C(h,f,l.rememberSelectionState));g.focus(Q(f,g,l.shouldSelectOnFocus));g.blur(Y(f));e.tabindex(-1);e.focus(d(f,h));e.blur(G(f,h));return f};var K=function(f,e){return function(g){if(!e){return }g=Z(g);if(f.index(g)===-1){return }e(g)}};var R=function(f,e){var g=f.data(T);return g?g[e]:undefined};var H=function(f,e,h){var g=f.data(T)||{};g[e]=h;f.data(T,g)};J.fn.tabbable=function(){V(this);return this};J.fn.selectable=function(f,g,h){var e=D(J(f),this,g,this.selectable.defaults,h);H(this,N,e);H(this,P,g);return this};J.fn.activatable=function(f,e){b(this,f,this.activatable.defaults.keys,e);H(this,c,K(this,f));return this};J.fn.select=function(e){e.focus();return this};J.fn.selectNext=function(){a(R(this,N));return this};J.fn.selectPrevious=function(){L(R(this,N));return this};J.fn.currentSelection=function(){return J(R(this,N).activeItem)};J.fn.activate=function(f){var e=R(this,c);e(f);return this};J.fn.activatable.defaults={keys:[J.a11y.keys.ENTER,J.a11y.keys.SPACE]};J.fn.selectable.defaults={direction:this.VERTICAL,shouldSelectOnFocus:true,rememberSelectionState:true}})(jQuery);
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/jquery.tabindex.js b/mods/atutor_opencaps/opencaps/js/jquery/jquery.tabindex.js
new file mode 100755 (executable)
index 0000000..bda3e75
--- /dev/null
@@ -0,0 +1 @@
+(function(C){var E=function(){return C.browser.msie?"tabIndex":"tabindex"};var B=function(G){if(G.length<=0){return undefined}if(!G.hasTabindexAttr()){return A(G)?Number(0):undefined}var F=G[0].getAttribute(E());return Number(F)};var D=function(F,G){return F.each(function(H,I){C(I).attr(E(),G)})};var A=function(F){if(F.length<=0){return false}return jQuery(F[0]).is("a, input, button, select, area, textarea, object")};C.fn.tabindex=function(F){if(F!==null&&F!==undefined){return D(this,F)}else{return B(this)}};C.fn.removeTabindex=function(){return this.each(function(F,G){C(G).removeAttr(E())})};C.fn.hasTabindexAttr=function(){if(this.length<=0){return false}var F=this[0].getAttributeNode(E());return F?F.specified:false};C.fn.hasTabindex=function(){return this.hasTabindexAttr()||A(this)}})(jQuery);
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/ui.base.js b/mods/atutor_opencaps/opencaps/js/jquery/ui.base.js
new file mode 100755 (executable)
index 0000000..0f0af4e
--- /dev/null
@@ -0,0 +1 @@
+(function(C){C.ui=C.ui||{};C.extend(C.ui,{plugin:{add:function(E,F,H){var G=C.ui[E].prototype;for(var D in H){G.plugins[D]=G.plugins[D]||[];G.plugins[D].push([F,H[D]])}},call:function(D,E,G){var H=D.plugins[E];if(!H){return }for(var F=0;F<H.length;F++){if(D.options[H[F][0]]){H[F][1].apply(D.element,G)}}}},cssCache:{},css:function(D){if(C.ui.cssCache[D]){return C.ui.cssCache[D]}var E=C('<div class="ui-resizable-gen">').addClass(D).css({position:"absolute",top:"-5000px",left:"-5000px",display:"block"}).appendTo("body");C.ui.cssCache[D]=!!((!/auto|default/.test(E.css("cursor"))||(/^[1-9]/).test(E.css("height"))||(/^[1-9]/).test(E.css("width"))||!(/none/).test(E.css("backgroundImage"))||!(/transparent|rgba\(0, 0, 0, 0\)/).test(E.css("backgroundColor"))));try{C("body").get(0).removeChild(E.get(0))}catch(F){}return C.ui.cssCache[D]},disableSelection:function(D){D.unselectable="on";D.onselectstart=function(){return false};if(D.style){D.style.MozUserSelect="none"}},enableSelection:function(D){D.unselectable="off";D.onselectstart=function(){return true};if(D.style){D.style.MozUserSelect=""}},hasScroll:function(G,E){var D=/top/.test(E||"top")?"scrollTop":"scrollLeft",F=false;if(G[D]>0){return true}G[D]=1;F=G[D]>0?true:false;G[D]=0;return F}});C.each(["Left","Top"],function(E,D){if(!C.fn["scroll"+D]){C.fn["scroll"+D]=function(F){return F!=undefined?this.each(function(){this==window||this==document?window.scrollTo(D=="Left"?F:C(window)["scrollLeft"](),D=="Top"?F:C(window)["scrollTop"]()):this["scroll"+D]=F}):this[0]==window||this[0]==document?self[(D=="Left"?"pageXOffset":"pageYOffset")]||C.boxModel&&document.documentElement["scroll"+D]||document.body["scroll"+D]:this[0]["scroll"+D]}}});var B=C.fn.remove;C.fn.extend({position:function(){var F=this.offset();var E=this.offsetParent();var D=E.offset();return{top:F.top-A(this[0],"marginTop")-D.top-A(E,"borderTopWidth"),left:F.left-A(this[0],"marginLeft")-D.left-A(E,"borderLeftWidth")}},offsetParent:function(){var D=this[0].offsetParent;while(D&&(!/^body|html$/i.test(D.tagName)&&C.css(D,"position")=="static")){D=D.offsetParent}return C(D)},mouseInteraction:function(D){return this.each(function(){new C.ui.mouseInteraction(this,D)})},removeMouseInteraction:function(D){return this.each(function(){if(C.data(this,"ui-mouse")){C.data(this,"ui-mouse").destroy()}})},remove:function(){this.trigger("remove");return B.apply(this,arguments)}});function A(D,E){return parseInt(C.curCSS(D.jquery?D[0]:D,E,true))||0}C.ui.mouseInteraction=function(F,E){var D=this;this.element=F;C.data(this.element,"ui-mouse",this);this.options=C.extend({},E);C(F).bind("mousedown.draggable",function(){return D.click.apply(D,arguments)});if(C.browser.msie){C(F).attr("unselectable","on")}C(F).mouseup(function(){if(D.timer){clearInterval(D.timer)}})};C.extend(C.ui.mouseInteraction.prototype,{destroy:function(){C(this.element).unbind("mousedown.draggable")},trigger:function(){return this.click.apply(this,arguments)},click:function(F){if(F.which!=1||C.inArray(F.target.nodeName.toLowerCase(),this.options.dragPrevention||[])!=-1||(this.options.condition&&!this.options.condition.apply(this.options.executor||this,[F,this.element]))){return true}var E=this;var D=function(){E._MP={left:F.pageX,top:F.pageY};C(document).bind("mouseup.draggable",function(){return E.stop.apply(E,arguments)});C(document).bind("mousemove.draggable",function(){return E.drag.apply(E,arguments)});if(!E.initalized&&Math.abs(E._MP.left-F.pageX)>=E.options.distance||Math.abs(E._MP.top-F.pageY)>=E.options.distance){if(E.options.start){E.options.start.call(E.options.executor||E,F,E.element)}if(E.options.drag){E.options.drag.call(E.options.executor||E,F,this.element)}E.initialized=true}};if(this.options.delay){if(this.timer){clearInterval(this.timer)}this.timer=setTimeout(D,this.options.delay)}else{D()}return false},stop:function(D){var E=this.options;if(!this.initialized){return C(document).unbind("mouseup.draggable").unbind("mousemove.draggable")}if(this.options.stop){this.options.stop.call(this.options.executor||this,D,this.element)}C(document).unbind("mouseup.draggable").unbind("mousemove.draggable");this.initialized=false;return false},drag:function(D){var E=this.options;if(C.browser.msie&&!D.button){return this.stop.apply(this,[D])}if(!this.initialized&&(Math.abs(this._MP.left-D.pageX)>=E.distance||Math.abs(this._MP.top-D.pageY)>=E.distance)){if(this.options.start){this.options.start.call(this.options.executor||this,D,this.element)}this.initialized=true}else{if(!this.initialized){return false}}if(E.drag){E.drag.call(this.options.executor||this,D,this.element)}return false}})})(jQuery);
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/ui.core.js b/mods/atutor_opencaps/opencaps/js/jquery/ui.core.js
new file mode 100755 (executable)
index 0000000..1f82d3a
--- /dev/null
@@ -0,0 +1,519 @@
+/*\r
+ * jQuery UI 1.7.2\r
+ *\r
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\r
+ * Dual licensed under the MIT (MIT-LICENSE.txt)\r
+ * and GPL (GPL-LICENSE.txt) licenses.\r
+ *\r
+ * http://docs.jquery.com/UI\r
+ */\r
+;jQuery.ui || (function($) {\r
+\r
+var _remove = $.fn.remove,\r
+       isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);\r
+\r
+//Helper functions and ui object\r
+$.ui = {\r
+       version: "1.7.2",\r
+\r
+       // $.ui.plugin is deprecated.  Use the proxy pattern instead.\r
+       plugin: {\r
+               add: function(module, option, set) {\r
+                       var proto = $.ui[module].prototype;\r
+                       for(var i in set) {\r
+                               proto.plugins[i] = proto.plugins[i] || [];\r
+                               proto.plugins[i].push([option, set[i]]);\r
+                       }\r
+               },\r
+               call: function(instance, name, args) {\r
+                       var set = instance.plugins[name];\r
+                       if(!set || !instance.element[0].parentNode) { return; }\r
+\r
+                       for (var i = 0; i < set.length; i++) {\r
+                               if (instance.options[set[i][0]]) {\r
+                                       set[i][1].apply(instance.element, args);\r
+                               }\r
+                       }\r
+               }\r
+       },\r
+\r
+       contains: function(a, b) {\r
+               return document.compareDocumentPosition\r
+                       ? a.compareDocumentPosition(b) & 16\r
+                       : a !== b && a.contains(b);\r
+       },\r
+\r
+       hasScroll: function(el, a) {\r
+\r
+               //If overflow is hidden, the element might have extra content, but the user wants to hide it\r
+               if ($(el).css('overflow') == 'hidden') { return false; }\r
+\r
+               var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',\r
+                       has = false;\r
+\r
+               if (el[scroll] > 0) { return true; }\r
+\r
+               // TODO: determine which cases actually cause this to happen\r
+               // if the element doesn't have the scroll set, see if it's possible to\r
+               // set the scroll\r
+               el[scroll] = 1;\r
+               has = (el[scroll] > 0);\r
+               el[scroll] = 0;\r
+               return has;\r
+       },\r
+\r
+       isOverAxis: function(x, reference, size) {\r
+               //Determines when x coordinate is over "b" element axis\r
+               return (x > reference) && (x < (reference + size));\r
+       },\r
+\r
+       isOver: function(y, x, top, left, height, width) {\r
+               //Determines when x, y coordinates is over "b" element\r
+               return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width);\r
+       },\r
+\r
+       keyCode: {\r
+               BACKSPACE: 8,\r
+               CAPS_LOCK: 20,\r
+               COMMA: 188,\r
+               CONTROL: 17,\r
+               DELETE: 46,\r
+               DOWN: 40,\r
+               END: 35,\r
+               ENTER: 13,\r
+               ESCAPE: 27,\r
+               HOME: 36,\r
+               INSERT: 45,\r
+               LEFT: 37,\r
+               NUMPAD_ADD: 107,\r
+               NUMPAD_DECIMAL: 110,\r
+               NUMPAD_DIVIDE: 111,\r
+               NUMPAD_ENTER: 108,\r
+               NUMPAD_MULTIPLY: 106,\r
+               NUMPAD_SUBTRACT: 109,\r
+               PAGE_DOWN: 34,\r
+               PAGE_UP: 33,\r
+               PERIOD: 190,\r
+               RIGHT: 39,\r
+               SHIFT: 16,\r
+               SPACE: 32,\r
+               TAB: 9,\r
+               UP: 38\r
+       }\r
+};\r
+\r
+// WAI-ARIA normalization\r
+if (isFF2) {\r
+       var attr = $.attr,\r
+               removeAttr = $.fn.removeAttr,\r
+               ariaNS = "http://www.w3.org/2005/07/aaa",\r
+               ariaState = /^aria-/,\r
+               ariaRole = /^wairole:/;\r
+\r
+       $.attr = function(elem, name, value) {\r
+               var set = value !== undefined;\r
+\r
+               return (name == 'role'\r
+                       ? (set\r
+                               ? attr.call(this, elem, name, "wairole:" + value)\r
+                               : (attr.apply(this, arguments) || "").replace(ariaRole, ""))\r
+                       : (ariaState.test(name)\r
+                               ? (set\r
+                                       ? elem.setAttributeNS(ariaNS,\r
+                                               name.replace(ariaState, "aaa:"), value)\r
+                                       : attr.call(this, elem, name.replace(ariaState, "aaa:")))\r
+                               : attr.apply(this, arguments)));\r
+       };\r
+\r
+       $.fn.removeAttr = function(name) {\r
+               return (ariaState.test(name)\r
+                       ? this.each(function() {\r
+                               this.removeAttributeNS(ariaNS, name.replace(ariaState, ""));\r
+                       }) : removeAttr.call(this, name));\r
+       };\r
+}\r
+\r
+//jQuery plugins\r
+$.fn.extend({\r
+       remove: function() {\r
+               // Safari has a native remove event which actually removes DOM elements,\r
+               // so we have to use triggerHandler instead of trigger (#3037).\r
+               $("*", this).add(this).each(function() {\r
+                       $(this).triggerHandler("remove");\r
+               });\r
+               return _remove.apply(this, arguments );\r
+       },\r
+\r
+       enableSelection: function() {\r
+               return this\r
+                       .attr('unselectable', 'off')\r
+                       .css('MozUserSelect', '')\r
+                       .unbind('selectstart.ui');\r
+       },\r
+\r
+       disableSelection: function() {\r
+               return this\r
+                       .attr('unselectable', 'on')\r
+                       .css('MozUserSelect', 'none')\r
+                       .bind('selectstart.ui', function() { return false; });\r
+       },\r
+\r
+       scrollParent: function() {\r
+               var scrollParent;\r
+               if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {\r
+                       scrollParent = this.parents().filter(function() {\r
+                               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));\r
+                       }).eq(0);\r
+               } else {\r
+                       scrollParent = this.parents().filter(function() {\r
+                               return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));\r
+                       }).eq(0);\r
+               }\r
+\r
+               return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;\r
+       }\r
+});\r
+\r
+\r
+//Additional selectors\r
+$.extend($.expr[':'], {\r
+       data: function(elem, i, match) {\r
+               return !!$.data(elem, match[3]);\r
+       },\r
+\r
+       focusable: function(element) {\r
+               var nodeName = element.nodeName.toLowerCase(),\r
+                       tabIndex = $.attr(element, 'tabindex');\r
+               return (/input|select|textarea|button|object/.test(nodeName)\r
+                       ? !element.disabled\r
+                       : 'a' == nodeName || 'area' == nodeName\r
+                               ? element.href || !isNaN(tabIndex)\r
+                               : !isNaN(tabIndex))\r
+                       // the element and all of its ancestors must be visible\r
+                       // the browser may report that the area is hidden\r
+                       && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length;\r
+       },\r
+\r
+       tabbable: function(element) {\r
+               var tabIndex = $.attr(element, 'tabindex');\r
+               return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable');\r
+       }\r
+});\r
+\r
+\r
+// $.widget is a factory to create jQuery plugins\r
+// taking some boilerplate code out of the plugin code\r
+function getter(namespace, plugin, method, args) {\r
+       function getMethods(type) {\r
+               var methods = $[namespace][plugin][type] || [];\r
+               return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);\r
+       }\r
+\r
+       var methods = getMethods('getter');\r
+       if (args.length == 1 && typeof args[0] == 'string') {\r
+               methods = methods.concat(getMethods('getterSetter'));\r
+       }\r
+       return ($.inArray(method, methods) != -1);\r
+}\r
+\r
+$.widget = function(name, prototype) {\r
+       var namespace = name.split(".")[0];\r
+       name = name.split(".")[1];\r
+\r
+       // create plugin method\r
+       $.fn[name] = function(options) {\r
+               var isMethodCall = (typeof options == 'string'),\r
+                       args = Array.prototype.slice.call(arguments, 1);\r
+\r
+               // prevent calls to internal methods\r
+               if (isMethodCall && options.substring(0, 1) == '_') {\r
+                       return this;\r
+               }\r
+\r
+               // handle getter methods\r
+               if (isMethodCall && getter(namespace, name, options, args)) {\r
+                       var instance = $.data(this[0], name);\r
+                       return (instance ? instance[options].apply(instance, args)\r
+                               : undefined);\r
+               }\r
+\r
+               // handle initialization and non-getter methods\r
+               return this.each(function() {\r
+                       var instance = $.data(this, name);\r
+\r
+                       // constructor\r
+                       (!instance && !isMethodCall &&\r
+                               $.data(this, name, new $[namespace][name](this, options))._init());\r
+\r
+                       // method call\r
+                       (instance && isMethodCall && $.isFunction(instance[options]) &&\r
+                               instance[options].apply(instance, args));\r
+               });\r
+       };\r
+\r
+       // create widget constructor\r
+       $[namespace] = $[namespace] || {};\r
+       $[namespace][name] = function(element, options) {\r
+               var self = this;\r
+\r
+               this.namespace = namespace;\r
+               this.widgetName = name;\r
+               this.widgetEventPrefix = $[namespace][name].eventPrefix || name;\r
+               this.widgetBaseClass = namespace + '-' + name;\r
+\r
+               this.options = $.extend({},\r
+                       $.widget.defaults,\r
+                       $[namespace][name].defaults,\r
+                       $.metadata && $.metadata.get(element)[name],\r
+                       options);\r
+\r
+               this.element = $(element)\r
+                       .bind('setData.' + name, function(event, key, value) {\r
+                               if (event.target == element) {\r
+                                       return self._setData(key, value);\r
+                               }\r
+                       })\r
+                       .bind('getData.' + name, function(event, key) {\r
+                               if (event.target == element) {\r
+                                       return self._getData(key);\r
+                               }\r
+                       })\r
+                       .bind('remove', function() {\r
+                               return self.destroy();\r
+                       });\r
+       };\r
+\r
+       // add widget prototype\r
+       $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);\r
+\r
+       // TODO: merge getter and getterSetter properties from widget prototype\r
+       // and plugin prototype\r
+       $[namespace][name].getterSetter = 'option';\r
+};\r
+\r
+$.widget.prototype = {\r
+       _init: function() {},\r
+       destroy: function() {\r
+               this.element.removeData(this.widgetName)\r
+                       .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled')\r
+                       .removeAttr('aria-disabled');\r
+       },\r
+\r
+       option: function(key, value) {\r
+               var options = key,\r
+                       self = this;\r
+\r
+               if (typeof key == "string") {\r
+                       if (value === undefined) {\r
+                               return this._getData(key);\r
+                       }\r
+                       options = {};\r
+                       options[key] = value;\r
+               }\r
+\r
+               $.each(options, function(key, value) {\r
+                       self._setData(key, value);\r
+               });\r
+       },\r
+       _getData: function(key) {\r
+               return this.options[key];\r
+       },\r
+       _setData: function(key, value) {\r
+               this.options[key] = value;\r
+\r
+               if (key == 'disabled') {\r
+                       this.element\r
+                               [value ? 'addClass' : 'removeClass'](\r
+                                       this.widgetBaseClass + '-disabled' + ' ' +\r
+                                       this.namespace + '-state-disabled')\r
+                               .attr("aria-disabled", value);\r
+               }\r
+       },\r
+\r
+       enable: function() {\r
+               this._setData('disabled', false);\r
+       },\r
+       disable: function() {\r
+               this._setData('disabled', true);\r
+       },\r
+\r
+       _trigger: function(type, event, data) {\r
+               var callback = this.options[type],\r
+                       eventName = (type == this.widgetEventPrefix\r
+                               ? type : this.widgetEventPrefix + type);\r
+\r
+               event = $.Event(event);\r
+               event.type = eventName;\r
+\r
+               // copy original event properties over to the new event\r
+               // this would happen if we could call $.event.fix instead of $.Event\r
+               // but we don't have a way to force an event to be fixed multiple times\r
+               if (event.originalEvent) {\r
+                       for (var i = $.event.props.length, prop; i;) {\r
+                               prop = $.event.props[--i];\r
+                               event[prop] = event.originalEvent[prop];\r
+                       }\r
+               }\r
+\r
+               this.element.trigger(event, data);\r
+\r
+               return !($.isFunction(callback) && callback.call(this.element[0], event, data) === false\r
+                       || event.isDefaultPrevented());\r
+       }\r
+};\r
+\r
+$.widget.defaults = {\r
+       disabled: false\r
+};\r
+\r
+\r
+/** Mouse Interaction Plugin **/\r
+\r
+$.ui.mouse = {\r
+       _mouseInit: function() {\r
+               var self = this;\r
+\r
+               this.element\r
+                       .bind('mousedown.'+this.widgetName, function(event) {\r
+                               return self._mouseDown(event);\r
+                       })\r
+                       .bind('click.'+this.widgetName, function(event) {\r
+                               if(self._preventClickEvent) {\r
+                                       self._preventClickEvent = false;\r
+                                       event.stopImmediatePropagation();\r
+                                       return false;\r
+                               }\r
+                       });\r
+\r
+               // Prevent text selection in IE\r
+               if ($.browser.msie) {\r
+                       this._mouseUnselectable = this.element.attr('unselectable');\r
+                       this.element.attr('unselectable', 'on');\r
+               }\r
+\r
+               this.started = false;\r
+       },\r
+\r
+       // TODO: make sure destroying one instance of mouse doesn't mess with\r
+       // other instances of mouse\r
+       _mouseDestroy: function() {\r
+               this.element.unbind('.'+this.widgetName);\r
+\r
+               // Restore text selection in IE\r
+               ($.browser.msie\r
+                       && this.element.attr('unselectable', this._mouseUnselectable));\r
+       },\r
+\r
+       _mouseDown: function(event) {\r
+               // don't let more than one widget handle mouseStart\r
+               // TODO: figure out why we have to use originalEvent\r
+               event.originalEvent = event.originalEvent || {};\r
+               if (event.originalEvent.mouseHandled) { return; }\r
+\r
+               // we may have missed mouseup (out of window)\r
+               (this._mouseStarted && this._mouseUp(event));\r
+\r
+               this._mouseDownEvent = event;\r
+\r
+               var self = this,\r
+                       btnIsLeft = (event.which == 1),\r
+                       elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);\r
+               if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {\r
+                       return true;\r
+               }\r
+\r
+               this.mouseDelayMet = !this.options.delay;\r
+               if (!this.mouseDelayMet) {\r
+                       this._mouseDelayTimer = setTimeout(function() {\r
+                               self.mouseDelayMet = true;\r
+                       }, this.options.delay);\r
+               }\r
+\r
+               if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {\r
+                       this._mouseStarted = (this._mouseStart(event) !== false);\r
+                       if (!this._mouseStarted) {\r
+                               event.preventDefault();\r
+                               return true;\r
+                       }\r
+               }\r
+\r
+               // these delegates are required to keep context\r
+               this._mouseMoveDelegate = function(event) {\r
+                       return self._mouseMove(event);\r
+               };\r
+               this._mouseUpDelegate = function(event) {\r
+                       return self._mouseUp(event);\r
+               };\r
+               $(document)\r
+                       .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)\r
+                       .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);\r
+\r
+               // preventDefault() is used to prevent the selection of text here -\r
+               // however, in Safari, this causes select boxes not to be selectable\r
+               // anymore, so this fix is needed\r
+               ($.browser.safari || event.preventDefault());\r
+\r
+               event.originalEvent.mouseHandled = true;\r
+               return true;\r
+       },\r
+\r
+       _mouseMove: function(event) {\r
+               // IE mouseup check - mouseup happened when mouse was out of window\r
+               if ($.browser.msie && !event.button) {\r
+                       return this._mouseUp(event);\r
+               }\r
+\r
+               if (this._mouseStarted) {\r
+                       this._mouseDrag(event);\r
+                       return event.preventDefault();\r
+               }\r
+\r
+               if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {\r
+                       this._mouseStarted =\r
+                               (this._mouseStart(this._mouseDownEvent, event) !== false);\r
+                       (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));\r
+               }\r
+\r
+               return !this._mouseStarted;\r
+       },\r
+\r
+       _mouseUp: function(event) {\r
+               $(document)\r
+                       .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)\r
+                       .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);\r
+\r
+               if (this._mouseStarted) {\r
+                       this._mouseStarted = false;\r
+                       this._preventClickEvent = (event.target == this._mouseDownEvent.target);\r
+                       this._mouseStop(event);\r
+               }\r
+\r
+               return false;\r
+       },\r
+\r
+       _mouseDistanceMet: function(event) {\r
+               return (Math.max(\r
+                               Math.abs(this._mouseDownEvent.pageX - event.pageX),\r
+                               Math.abs(this._mouseDownEvent.pageY - event.pageY)\r
+                       ) >= this.options.distance\r
+               );\r
+       },\r
+\r
+       _mouseDelayMet: function(event) {\r
+               return this.mouseDelayMet;\r
+       },\r
+\r
+       // These are placeholder methods, to be overriden by extending plugin\r
+       _mouseStart: function(event) {},\r
+       _mouseDrag: function(event) {},\r
+       _mouseStop: function(event) {},\r
+       _mouseCapture: function(event) { return true; }\r
+};\r
+\r
+$.ui.mouse.defaults = {\r
+       cancel: null,\r
+       distance: 1,\r
+       delay: 0\r
+};\r
+\r
+})(jQuery);\r
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/ui.dialog.js b/mods/atutor_opencaps/opencaps/js/jquery/ui.dialog.js
new file mode 100755 (executable)
index 0000000..89e55d0
--- /dev/null
@@ -0,0 +1 @@
+(function(B){B.ui=B.ui||{};B.fn.extend({dialog:function(D,E){var C=Array.prototype.slice.call(arguments,1);return this.each(function(){if(typeof D=="string"){var F=B.data(this,"ui-dialog")||B.data(B(this).parents(".ui-dialog:first").find(".ui-dialog-content")[0],"ui-dialog");F[D].apply(F,C)}else{if(!B(this).is(".ui-dialog-content")){new B.ui.dialog(this,D)}}})}});B.ui.dialog=function(E,M){this.options=M=B.extend({},B.ui.dialog.defaults,M&&M.modal?{resizable:false}:{},M);this.element=E;var L=this;B.data(this.element,"ui-dialog",this);B(E).bind("setData.dialog",function(O,N,P){M[N]=P}).bind("getData.dialog",function(O,N){return M[N]});var F=B(E).addClass("ui-dialog-content");if(!F.parent().length){F.appendTo("body")}F.wrap(document.createElement("div")).wrap(document.createElement("div"));var I=F.parent().addClass("ui-dialog-container").css({position:"relative"});var K=this.uiDialog=I.parent().hide().addClass("ui-dialog").css({position:"absolute",width:M.width,height:M.height,overflow:"hidden"});var C=F.attr("className").split(" ");B.each(C,function(N,O){if(O!="ui-dialog-content"){K.addClass(O)}});if(M.resizable&&B.fn.resizable){K.append('<div class="ui-resizable-n ui-resizable-handle"></div>').append('<div class="ui-resizable-s ui-resizable-handle"></div>').append('<div class="ui-resizable-e ui-resizable-handle"></div>').append('<div class="ui-resizable-w ui-resizable-handle"></div>').append('<div class="ui-resizable-ne ui-resizable-handle"></div>').append('<div class="ui-resizable-se ui-resizable-handle"></div>').append('<div class="ui-resizable-sw ui-resizable-handle"></div>').append('<div class="ui-resizable-nw ui-resizable-handle"></div>');K.resizable({maxWidth:M.maxWidth,maxHeight:M.maxHeight,minWidth:M.minWidth,minHeight:M.minHeight})}I.prepend('<div class="ui-dialog-titlebar"></div>');var D=B(".ui-dialog-titlebar",I);var J=(M.title)?M.title:(F.attr("title"))?F.attr("title"):"";D.append('<span class="ui-dialog-title">'+J+"</span>");D.append('<a href="#" class="ui-dialog-titlebar-close"><span>X</span></a>');this.uiDialogTitlebarClose=B(".ui-dialog-titlebar-close",D).hover(function(){B(this).addClass("ui-dialog-titlebar-close-hover")},function(){B(this).removeClass("ui-dialog-titlebar-close-hover")}).mousedown(function(N){N.stopPropagation()}).click(function(){L.close();return false}).keydown(function(N){var O=27;N.keyCode&&N.keyCode==O&&L.close()});var G=0;B.each(M.buttons,function(){G=1;return false});if(G==1){K.append('<div class="ui-dialog-buttonpane"></div>');var H=B(".ui-dialog-buttonpane",K);B.each(M.buttons,function(N,P){var O=B(document.createElement("button")).text(N).click(P);H.append(O)})}if(M.draggable&&B.fn.draggable){K.draggable({handle:".ui-dialog-titlebar",start:function(){L.activate()}})}K.mousedown(function(){L.activate()});D.click(function(){L.activate()});M.bgiframe&&B.fn.bgiframe&&K.bgiframe();this.open=function(){M.modal&&A.show(L,M.overlay);K.appendTo("body");var P=B(window),S=B(document),R=S.scrollTop(),Q=S.scrollLeft();if(M.position.constructor==Array){R+=M.position[1];Q+=M.position[0]}else{switch(M.position){case"center":R+=(P.height()/2)-(K.height()/2);Q+=(P.width()/2)-(K.width()/2);break;case"top":R+=0;Q+=(P.width()/2)-(K.width()/2);break;case"right":R+=(P.height()/2)-(K.height()/2);Q+=(P.width())-(K.width());break;case"bottom":R+=(P.height())-(K.height());Q+=(P.width()/2)-(K.width()/2);break;case"left":R+=(P.height()/2)-(K.height()/2);Q+=0;break;default:R+=(P.height()/2)-(K.height()/2);Q+=(P.width()/2)-(K.width()/2)}}R=R<S.scrollTop()?S.scrollTop():R;K.css({top:R,left:Q});K.show();L.activate();var N=null;var O={options:M};this.uiDialogTitlebarClose.focus();B(this.element).triggerHandler("dialogopen",[N,O],M.open)};this.activate=function(){var N=0;B(".ui-dialog:visible").each(function(){N=Math.max(N,parseInt(B(this).css("z-index"),10))});A.$el&&A.$el.css("z-index",++N);K.css("z-index",++N)};this.close=function(){M.modal&&A.hide();K.hide();var O=null;var N={options:M};B(this.element).triggerHandler("dialogclose",[O,N],M.close)};if(M.autoOpen){this.open()}};B.extend(B.ui.dialog,{defaults:{autoOpen:true,bgiframe:false,buttons:[],draggable:true,height:200,minHeight:100,minWidth:150,modal:false,overlay:{},position:"center",resizable:true,width:300}});var A={$el:null,events:B.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(C){return C+".ui-dialog-overlay"}).join(" "),show:function(F,E){if(this.$el){return }this.dialog=F;this.selects=this.ie6&&B("select:visible").css("visibility","hidden");var G=this.width();var C=this.height();this.$el=B("<div/>").appendTo(document.body).addClass("ui-dialog-overlay").css(B.extend({borderWidth:0,margin:0,padding:0,position:"absolute",top:0,left:0,width:G,height:C},E));B("a, :input").bind(this.events,function(){if(B(this).parents(".ui-dialog").length==0){F.uiDialogTitlebarClose.focus();return false}});B(document).bind("keydown.ui-dialog-overlay",function(H){var I=27;H.keyCode&&H.keyCode==I&&F.close()});$overlay=this.$el;function D(){$overlay.css({width:G,height:C}).css({width:A.width(),height:A.height()})}B(window).bind("resize.ui-dialog-overlay",D);F.uiDialog.is(".ui-draggable")&&F.uiDialog.data("stop.draggable",D);F.uiDialog.is(".ui-resizable")&&F.uiDialog.data("stop.resizable",D)},hide:function(){B("a, :input").add([document,window]).unbind(".ui-dialog-overlay");this.ie6&&this.selects.css("visibility","visible");this.$el=null;B(".ui-dialog-overlay").remove()},height:function(){var C;if(this.ie6&&(B(document.body).height()<B(window).height())&&!(document.documentElement.scrollTop||(this.dialog.uiDialog.offset().top+this.dialog.uiDialog.height())>B(window).height())){C=B(window).height()}else{C=B(document).height()}return C+"px"},width:function(){var C;if(this.ie6&&(B(document.body).width()<B(window).width())&&!(document.documentElement.scrollLeft||(this.dialog.uiDialog.offset().left+this.dialog.uiDialog.width())>B(window).width())){C=B(window).width()}else{C=B(document).width()}return C+"px"},ie6:B.browser.msie&&B.browser.version<7,selects:null}})(jQuery);
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/ui.draggable.js b/mods/atutor_opencaps/opencaps/js/jquery/ui.draggable.js
new file mode 100755 (executable)
index 0000000..60e8470
--- /dev/null
@@ -0,0 +1 @@
+(function(A){A.fn.extend({draggable:function(C){var B=Array.prototype.slice.call(arguments,1);return this.each(function(){if(typeof C=="string"){var D=A.data(this,"draggable");if(D){D[C].apply(D,B)}}else{if(!A.data(this,"draggable")){new A.ui.draggable(this,C)}}})}});A.ui.draggable=function(D,C){var B=this;this.element=A(D);A.data(D,"draggable",this);this.element.addClass("ui-draggable");this.options=A.extend({},C);var E=this.options;A.extend(E,{helper:E.ghosting==true?"clone":(E.helper||"original"),handle:E.handle?(A(E.handle,D)[0]?A(E.handle,D):this.element):this.element,appendTo:E.appendTo||"parent"});A(D).bind("setData.draggable",function(G,F,H){B.options[F]=H}).bind("getData.draggable",function(G,F){return B.options[F]});A(E.handle).mouseInteraction({executor:this,delay:E.delay,distance:E.distance||1,dragPrevention:E.cancel||E.cancel===""?E.cancel.toLowerCase().split(","):["input","textarea","button","select","option"],start:this.start,stop:this.stop,drag:this.drag,condition:function(F){return !(F.target.className.indexOf("ui-resizable-handle")!=-1||this.options.disabled)}});if(E.helper=="original"&&(this.element.css("position")=="static"||this.element.css("position")=="")){this.element.css("position","relative")}if(E.cursorAt&&E.cursorAt.constructor==Array){E.cursorAt={left:E.cursorAt[0],top:E.cursorAt[1]}}};A.extend(A.ui.draggable.prototype,{plugins:{},ui:function(B){return{helper:this.helper,position:this.position,absolutePosition:this.positionAbs,instance:this,options:this.options,element:this.element}},propagate:function(C,B){A.ui.plugin.call(this,C,[B,this.ui()]);return this.element.triggerHandler(C=="drag"?C:"drag"+C,[B,this.ui()],this.options[C])},destroy:function(){if(!A.data(this.element[0],"draggable")){return }this.options.handle.removeMouseInteraction();this.element.removeClass("ui-draggable ui-draggable-disabled").removeData("draggable").unbind(".draggable")},enable:function(){this.element.removeClass("ui-draggable-disabled");this.options.disabled=false},disable:function(){this.element.addClass("ui-draggable-disabled");this.options.disabled=true},setContrains:function(B,C,E,D){this.minLeft=B;this.maxLeft=C;this.minTop=E;this.maxTop=D;this.constrainsSet=true},checkConstrains:function(){if(!this.constrainsSet){return }if(this.position.left<this.minLeft){this.position.left=this.minLeft}if(this.position.left>this.maxLeft-this.helperProportions.width){this.position.left=this.maxLeft-this.helperProportions.width}if(this.position.top<this.minTop){this.position.top=this.minTop}if(this.position.top>this.maxTop-this.helperProportions.height){this.position.top=this.maxTop-this.helperProportions.height}},recallOffset:function(D){var C={left:this.elementOffset.left-this.offsetParentOffset.left,top:this.elementOffset.top-this.offsetParentOffset.top};var B=this.helper.css("position")=="relative";this.originalPosition={left:(B?parseInt(this.helper.css("left"),10)||0:C.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft)),top:(B?parseInt(this.helper.css("top"),10)||0:C.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop))};this.offset={left:this._pageX-this.originalPosition.left,top:this._pageY-this.originalPosition.top}},start:function(D){var E=this.options;if(A.ui.ddmanager){A.ui.ddmanager.current=this}this.helper=typeof E.helper=="function"?A(E.helper.apply(this.element[0],[D])):(E.helper=="clone"?this.element.clone().appendTo((E.appendTo=="parent"?this.element[0].parentNode:E.appendTo)):this.element);if(this.helper[0]!=this.element[0]){this.helper.css("position","absolute")}if(!this.helper.parents("body").length){this.helper.appendTo((E.appendTo=="parent"?this.element[0].parentNode:E.appendTo))}this.offsetParent=(function(F){while(F){if(F.style&&(/(absolute|relative|fixed)/).test(A.css(F,"position"))){return A(F)}F=F.parentNode?F.parentNode:null}return A("body")})(this.helper[0].parentNode);this.elementOffset=this.element.offset();this.offsetParentOffset=this.offsetParent.offset();var C={left:this.elementOffset.left-this.offsetParentOffset.left,top:this.elementOffset.top-this.offsetParentOffset.top};this._pageX=D.pageX;this._pageY=D.pageY;this.clickOffset={left:D.pageX-this.elementOffset.left,top:D.pageY-this.elementOffset.top};var B=this.helper.css("position")=="relative";this.originalPosition={left:(B?parseInt(this.helper.css("left"),10)||0:C.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft)),top:(B?parseInt(this.helper.css("top"),10)||0:C.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop))};if(this.element.css("position")=="fixed"){this.originalPosition.top-=this.offsetParent[0]==document.body?A(document).scrollTop():this.offsetParent[0].scrollTop;this.originalPosition.left-=this.offsetParent[0]==document.body?A(document).scrollLeft():this.offsetParent[0].scrollLeft}this.offset={left:D.pageX-this.originalPosition.left,top:D.pageY-this.originalPosition.top};if(this.element[0]!=this.helper[0]){this.offset.left+=parseInt(this.element.css("marginLeft"),10)||0;this.offset.top+=parseInt(this.element.css("marginTop"),10)||0}this.propagate("start",D);this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()};if(A.ui.ddmanager&&!E.dropBehaviour){A.ui.ddmanager.prepareOffsets(this,D)}if(E.cursorAt){if(E.cursorAt.top!=undefined||E.cursorAt.bottom!=undefined){this.offset.top-=this.clickOffset.top-(E.cursorAt.top!=undefined?E.cursorAt.top:(this.helperProportions.height-E.cursorAt.bottom));this.clickOffset.top=(E.cursorAt.top!=undefined?E.cursorAt.top:(this.helperProportions.height-E.cursorAt.bottom))}if(E.cursorAt.left!=undefined||E.cursorAt.right!=undefined){this.offset.left-=this.clickOffset.left-(E.cursorAt.left!=undefined?E.cursorAt.left:(this.helperProportions.width-E.cursorAt.right));this.clickOffset.left=(E.cursorAt.left!=undefined?E.cursorAt.left:(this.helperProportions.width-E.cursorAt.right))}}return false},clear:function(){if(A.ui.ddmanager){A.ui.ddmanager.current=null}this.helper=null},stop:function(B){if(A.ui.ddmanager&&!this.options.dropBehaviour){A.ui.ddmanager.drop(this,B)}this.propagate("stop",B);if(this.cancelHelperRemoval){return false}if(this.options.helper!="original"){this.helper.remove()}this.clear();return false},drag:function(B){this.position={top:B.pageY-this.offset.top,left:B.pageX-this.offset.left};this.positionAbs={left:B.pageX-this.clickOffset.left,top:B.pageY-this.clickOffset.top};this.checkConstrains();this.position=this.propagate("drag",B)||this.position;this.checkConstrains();A(this.helper).css({left:this.position.left+"px",top:this.position.top+"px"});if(A.ui.ddmanager){A.ui.ddmanager.drag(this,B)}return false}});A.ui.plugin.add("draggable","cursor",{start:function(D,C){var B=A("body");if(B.css("cursor")){C.options._cursor=B.css("cursor")}B.css("cursor",C.options.cursor)},stop:function(C,B){if(B.options._cursor){A("body").css("cursor",B.options._cursor)}}});A.ui.plugin.add("draggable","zIndex",{start:function(D,C){var B=A(C.helper);if(B.css("zIndex")){C.options._zIndex=B.css("zIndex")}B.css("zIndex",C.options.zIndex)},stop:function(C,B){if(B.options._zIndex){A(B.helper).css("zIndex",B.options._zIndex)}}});A.ui.plugin.add("draggable","opacity",{start:function(D,C){var B=A(C.helper);if(B.css("opacity")){C.options._opacity=B.css("opacity")}B.css("opacity",C.options.opacity)},stop:function(C,B){if(B.options._opacity){A(B.helper).css("opacity",B.options._opacity)}}});A.ui.plugin.add("draggable","revert",{stop:function(E,D){var B=D.instance,C=A(B.helper);B.cancelHelperRemoval=true;A(D.helper).animate({left:B.originalPosition.left,top:B.originalPosition.top},parseInt(D.options.revert,10)||500,function(){if(D.options.helper!="original"){C.remove()}if(!C){B.clear()}})}});A.ui.plugin.add("draggable","iframeFix",{start:function(D,C){var F=C.options;if(C.instance.slowMode){return }if(F.iframeFix.constructor==Array){for(var B=0;B<F.iframeFix.length;B++){var E=A(F.iframeFix[B]).offset({border:false});A('<div class="DragDropIframeFix"" style="background: #fff;"></div>').css("width",A(F.iframeFix[B])[0].offsetWidth+"px").css("height",A(F.iframeFix[B])[0].offsetHeight+"px").css("position","absolute").css("opacity","0.001").css("z-index","1000").css("top",E.top+"px").css("left",E.left+"px").appendTo("body")}}else{A("iframe").each(function(){var G=A(this).offset({border:false});A('<div class="DragDropIframeFix" style="background: #fff;"></div>').css("width",this.offsetWidth+"px").css("height",this.offsetHeight+"px").css("position","absolute").css("opacity","0.001").css("z-index","1000").css("top",G.top+"px").css("left",G.left+"px").appendTo("body")})}},stop:function(C,B){if(B.options.iframeFix){A("div.DragDropIframeFix").each(function(){this.parentNode.removeChild(this)})}}});A.ui.plugin.add("draggable","containment",{start:function(E,C){var G=C.options;var B=C.instance;if((G.containment.left!=undefined||G.containment.constructor==Array)&&!G._containment){return }if(!G._containment){G._containment=G.containment}if(G._containment=="parent"){G._containment=this[0].parentNode}if(G._containment=="document"){G.containment=[0,0,A(document).width(),(A(document).height()||document.body.parentNode.scrollHeight)]}else{var D=A(G._containment)[0];var F=A(G._containment).offset();G.containment=[F.left,F.top,F.left+(D.offsetWidth||D.scrollWidth),F.top+(D.offsetHeight||D.scrollHeight)]}var H=G.containment;C.instance.setContrains(H[0]-(B.offset.left-B.clickOffset.left),H[2]-(B.offset.left-B.clickOffset.left),H[1]-(B.offset.top-B.clickOffset.top),H[3]-(B.offset.top-B.clickOffset.top))}});A.ui.plugin.add("draggable","grid",{drag:function(E,D){var F=D.options;var C=D.instance.originalPosition.left+Math.round((E.pageX-D.instance._pageX)/F.grid[0])*F.grid[0];var B=D.instance.originalPosition.top+Math.round((E.pageY-D.instance._pageY)/F.grid[1])*F.grid[1];D.instance.position.left=C;D.instance.position.top=B}});A.ui.plugin.add("draggable","axis",{drag:function(C,B){var D=B.options;if(D.constraint){D.axis=D.constraint}switch(D.axis){case"x":B.instance.position.top=B.instance.originalPosition.top;break;case"y":B.instance.position.left=B.instance.originalPosition.left;break}}});A.ui.plugin.add("draggable","scroll",{start:function(C,B){var D=B.options;D.scrollSensitivity=D.scrollSensitivity||20;D.scrollSpeed=D.scrollSpeed||20;B.instance.overflowY=function(E){do{if(/auto|scroll/.test(E.css("overflow"))||(/auto|scroll/).test(E.css("overflow-y"))){return E}E=E.parent()}while(E[0].parentNode);return A(document)}(this);B.instance.overflowX=function(E){do{if(/auto|scroll/.test(E.css("overflow"))||(/auto|scroll/).test(E.css("overflow-x"))){return E}E=E.parent()}while(E[0].parentNode);return A(document)}(this)},drag:function(D,C){var E=C.options;var B=C.instance;if(B.overflowY[0]!=document&&B.overflowY[0].tagName!="HTML"){if(B.overflowY[0].offsetHeight-(C.position.top-B.overflowY[0].scrollTop+B.clickOffset.top)<E.scrollSensitivity){B.overflowY[0].scrollTop=B.overflowY[0].scrollTop+E.scrollSpeed}if((C.position.top-B.overflowY[0].scrollTop+B.clickOffset.top)<E.scrollSensitivity){B.overflowY[0].scrollTop=B.overflowY[0].scrollTop-E.scrollSpeed}}else{if(D.pageY-A(document).scrollTop()<E.scrollSensitivity){A(document).scrollTop(A(document).scrollTop()-E.scrollSpeed)}if(A(window).height()-(D.pageY-A(document).scrollTop())<E.scrollSensitivity){A(document).scrollTop(A(document).scrollTop()+E.scrollSpeed)}}if(B.overflowX[0]!=document&&B.overflowX[0].tagName!="HTML"){if(B.overflowX[0].offsetWidth-(C.position.left-B.overflowX[0].scrollLeft+B.clickOffset.left)<E.scrollSensitivity){B.overflowX[0].scrollLeft=B.overflowX[0].scrollLeft+E.scrollSpeed}if((C.position.top-B.overflowX[0].scrollLeft+B.clickOffset.left)<E.scrollSensitivity){B.overflowX[0].scrollLeft=B.overflowX[0].scrollLeft-E.scrollSpeed}}else{if(D.pageX-A(document).scrollLeft()<E.scrollSensitivity){A(document).scrollLeft(A(document).scrollLeft()-E.scrollSpeed)}if(A(window).width()-(D.pageX-A(document).scrollLeft())<E.scrollSensitivity){A(document).scrollLeft(A(document).scrollLeft()+E.scrollSpeed)}}C.instance.recallOffset(D)}});A.ui.plugin.add("draggable","snap",{start:function(C,B){B.instance.snapElements=[];A(B.options.snap===true?".ui-draggable":B.options.snap).each(function(){var E=A(this);var D=E.offset();if(this!=B.instance.element[0]){B.instance.snapElements.push({item:this,width:E.outerWidth(),height:E.outerHeight(),top:D.top,left:D.left})}})},drag:function(I,M){var K=M.options.snapTolerance||20;var D=M.absolutePosition.left,C=D+M.instance.helperProportions.width,O=M.absolutePosition.top,N=O+M.instance.helperProportions.height;for(var H=M.instance.snapElements.length-1;H>=0;H--){var E=M.instance.snapElements[H].left,B=E+M.instance.snapElements[H].width,Q=M.instance.snapElements[H].top,L=Q+M.instance.snapElements[H].height;if(!((E-K<D&&D<B+K&&Q-K<O&&O<L+K)||(E-K<D&&D<B+K&&Q-K<N&&N<L+K)||(E-K<C&&C<B+K&&Q-K<O&&O<L+K)||(E-K<C&&C<B+K&&Q-K<N&&N<L+K))){continue}if(M.options.snapMode!="inner"){var J=Math.abs(Q-N)<=20;var P=Math.abs(L-O)<=20;var G=Math.abs(E-C)<=20;var F=Math.abs(B-D)<=20;if(J){M.position.top=Q-M.instance.offset.top+M.instance.clickOffset.top-M.instance.helperProportions.height}if(P){M.position.top=L-M.instance.offset.top+M.instance.clickOffset.top}if(G){M.position.left=E-M.instance.offset.left+M.instance.clickOffset.left-M.instance.helperProportions.width}if(F){M.position.left=B-M.instance.offset.left+M.instance.clickOffset.left}}if(M.options.snapMode!="outer"){var J=Math.abs(Q-O)<=20;var P=Math.abs(L-N)<=20;var G=Math.abs(E-D)<=20;var F=Math.abs(B-C)<=20;if(J){M.position.top=Q-M.instance.offset.top+M.instance.clickOffset.top}if(P){M.position.top=L-M.instance.offset.top+M.instance.clickOffset.top-M.instance.helperProportions.height}if(G){M.position.left=E-M.instance.offset.left+M.instance.clickOffset.left}if(F){M.position.left=B-M.instance.offset.left+M.instance.clickOffset.left-M.instance.helperProportions.width}}}}})})(jQuery);
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/ui.droppable.js b/mods/atutor_opencaps/opencaps/js/jquery/ui.droppable.js
new file mode 100755 (executable)
index 0000000..ac60ad2
--- /dev/null
@@ -0,0 +1 @@
+(function(A){A.fn.extend({droppable:function(C){var B=Array.prototype.slice.call(arguments,1);return this.each(function(){if(typeof C=="string"){var D=A.data(this,"droppable");if(D){D[C].apply(D,B)}}else{if(!A.data(this,"droppable")){new A.ui.droppable(this,C)}}})}});A.ui.droppable=function(D,B){this.element=A(D);A.data(D,"droppable",this);this.element.addClass("ui-droppable");var E=this.options=B=A.extend({},A.ui.droppable.defaults,B);var C=E.accept;E=A.extend(E,{accept:E.accept&&E.accept.constructor==Function?E.accept:function(F){return A(F).is(C)}});A(D).bind("setData.droppable",function(G,F,H){E[F]=H}).bind("getData.droppable",function(G,F){return E[F]});this.proportions={width:this.element.outerWidth(),height:this.element.outerHeight()};A.ui.ddmanager.droppables.push({item:this,over:0,out:1})};A.extend(A.ui.droppable,{defaults:{disabled:false,tolerance:"intersect"}});A.extend(A.ui.droppable.prototype,{plugins:{},ui:function(B){return{instance:this,draggable:(B.currentItem||B.element),helper:B.helper,position:B.position,absolutePosition:B.positionAbs,options:this.options,element:this.element}},destroy:function(){var B=A.ui.ddmanager.droppables;for(var C=0;C<B.length;C++){if(B[C].item==this){B.splice(C,1)}}this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable")},enable:function(){this.element.removeClass("ui-droppable-disabled");this.options.disabled=false},disable:function(){this.element.addClass("ui-droppable-disabled");this.options.disabled=true},over:function(C){var B=A.ui.ddmanager.current;if(!B||(B.currentItem||B.element)[0]==this.element[0]){return }if(this.options.accept.call(this.element,(B.currentItem||B.element))){A.ui.plugin.call(this,"over",[C,this.ui(B)]);this.element.triggerHandler("dropover",[C,this.ui(B)],this.options.over)}},out:function(C){var B=A.ui.ddmanager.current;if(!B||(B.currentItem||B.element)[0]==this.element[0]){return }if(this.options.accept.call(this.element,(B.currentItem||B.element))){A.ui.plugin.call(this,"out",[C,this.ui(B)]);this.element.triggerHandler("dropout",[C,this.ui(B)],this.options.out)}},drop:function(D,C){var B=C||A.ui.ddmanager.current;if(!B||(B.currentItem||B.element)[0]==this.element[0]){return }var E=false;this.element.find(".ui-droppable").each(function(){var F=A.data(this,"droppable");if(F.options.greedy&&A.ui.intersect(B,{item:F,offset:F.element.offset()},F.options.tolerance)){E=true;return false}});if(E){return }if(this.options.accept.call(this.element,(B.currentItem||B.element))){A.ui.plugin.call(this,"drop",[D,this.ui(B)]);this.element.triggerHandler("drop",[D,this.ui(B)],this.options.drop)}},activate:function(C){var B=A.ui.ddmanager.current;A.ui.plugin.call(this,"activate",[C,this.ui(B)]);if(B){this.element.triggerHandler("dropactivate",[C,this.ui(B)],this.options.activate)}},deactivate:function(C){var B=A.ui.ddmanager.current;A.ui.plugin.call(this,"deactivate",[C,this.ui(B)]);if(B){this.element.triggerHandler("dropdeactivate",[C,this.ui(B)],this.options.deactivate)}}});A.ui.intersect=function(L,F,J){if(!F.offset){return false}var D=L.positionAbs.left,C=D+L.helperProportions.width,I=L.positionAbs.top,H=I+L.helperProportions.height;var E=F.offset.left,B=E+F.item.proportions.width,K=F.offset.top,G=K+F.item.proportions.height;switch(J){case"fit":if(!((H-(L.helperProportions.height/2)>K&&I<K)||(I<G&&H>G)||(C>E&&D<E)||(D<B&&C>B))){return false}if(H-(L.helperProportions.height/2)>K&&I<K){return 1}if(I<G&&H>G){return 2}if(C>E&&D<E){return 1}if(D<B&&C>B){return 2}break;case"intersect":return(E<D+(L.helperProportions.width/2)&&C-(L.helperProportions.width/2)<B&&K<I+(L.helperProportions.height/2)&&H-(L.helperProportions.height/2)<G);break;case"pointer":return(E<(L.positionAbs.left+L.clickOffset.left)&&(L.positionAbs.left+L.clickOffset.left)<B&&K<(L.positionAbs.top+L.clickOffset.top)&&(L.positionAbs.top+L.clickOffset.top)<G);break;case"touch":return((I>=K&&I<=G)||(H>=K&&H<=G)||(I<K&&H>G))&&((D>=E&&D<=B)||(C>=E&&C<=B)||(D<E&&C>B));break;default:return false;break}};A.ui.ddmanager={current:null,droppables:[],prepareOffsets:function(D,F){var B=A.ui.ddmanager.droppables;var E=F?F.type:null;for(var C=0;C<B.length;C++){if(B[C].item.options.disabled||(D&&!B[C].item.options.accept.call(B[C].item.element,(D.currentItem||D.element)))){continue}B[C].offset=A(B[C].item.element).offset();B[C].item.proportions={width:B[C].item.element.outerWidth(),height:B[C].item.element.outerHeight()};if(E=="dragstart"){B[C].item.activate.call(B[C].item,F)}}},drop:function(B,C){A.each(A.ui.ddmanager.droppables,function(){if(!this.item.options.disabled&&A.ui.intersect(B,this,this.item.options.tolerance)){this.item.drop.call(this.item,C)}if(!this.item.options.disabled&&this.item.options.accept.call(this.item.element,(B.currentItem||B.element))){this.out=1;this.over=0;this.item.deactivate.call(this.item,C)}})},drag:function(B,C){if(B.options.refreshPositions){A.ui.ddmanager.prepareOffsets(B,C)}A.each(A.ui.ddmanager.droppables,function(){if(this.item.disabled||this.greedyChild){return }var E=A.ui.intersect(B,this,this.item.options.tolerance);var F=!E&&this.over==1?"out":(E&&this.over==0?"over":null);if(!F){return }var D=A.data(this.item.element[0],"droppable");if(D.options.greedy){this.item.element.parents(".ui-droppable").each(function(){var G=this;A.each(A.ui.ddmanager.droppables,function(){if(this.item.element[0]!=G){return }this[F]=0;this[F=="out"?"over":"out"]=1;this.greedyChild=(F=="over"?1:0);this.item[F=="out"?"over":"out"].call(this.item,C);return false})})}this[F]=1;this[F=="out"?"over":"out"]=0;this.item[F].call(this.item,C)})}};A.ui.plugin.add("droppable","activeClass",{activate:function(C,B){A(this).addClass(B.options.activeClass)},deactivate:function(C,B){A(this).removeClass(B.options.activeClass)},drop:function(C,B){A(this).removeClass(B.options.activeClass)}});A.ui.plugin.add("droppable","hoverClass",{over:function(C,B){A(this).addClass(B.options.hoverClass)},out:function(C,B){A(this).removeClass(B.options.hoverClass)},drop:function(C,B){A(this).removeClass(B.options.hoverClass)}})})(jQuery);
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/jquery/ui.slider.js b/mods/atutor_opencaps/opencaps/js/jquery/ui.slider.js
new file mode 100755 (executable)
index 0000000..9b8f221
--- /dev/null
@@ -0,0 +1,558 @@
+/*\r
+ * jQuery UI Slider 1.7.2\r
+ *\r
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\r
+ * Dual licensed under the MIT (MIT-LICENSE.txt)\r
+ * and GPL (GPL-LICENSE.txt) licenses.\r
+ *\r
+ * http://docs.jquery.com/UI/Slider\r
+ *\r
+ * Depends:\r
+ *     ui.core.js\r
+ */\r
+\r
+(function($) {\r
+\r
+$.widget("ui.slider", $.extend({}, $.ui.mouse, {\r
+\r
+       _init: function() {\r
+\r
+               var self = this, o = this.options;\r
+               this._keySliding = false;\r
+               this._handleIndex = null;\r
+               this._detectOrientation();\r
+               this._mouseInit();\r
+\r
+               this.element\r
+                       .addClass("ui-slider"\r
+                               + " ui-slider-" + this.orientation\r
+                               + " ui-widget"\r
+                               + " ui-widget-content"\r
+                               + " ui-corner-all");\r
+\r
+               this.range = $([]);\r
+\r
+               if (o.range) {\r
+\r
+                       if (o.range === true) {\r
+                               this.range = $('<div></div>');\r
+                               if (!o.values) o.values = [this._valueMin(), this._valueMin()];\r
+                               if (o.values.length && o.values.length != 2) {\r
+                                       o.values = [o.values[0], o.values[0]];\r
+                               }\r
+                       } else {\r
+                               this.range = $('<div></div>');\r
+                       }\r
+\r
+                       this.range\r
+                               .appendTo(this.element)\r
+                               .addClass("ui-slider-range");\r
+\r
+                       if (o.range == "min" || o.range == "max") {\r
+                               this.range.addClass("ui-slider-range-" + o.range);\r
+                       }\r
+\r
+                       // note: this isn't the most fittingly semantic framework class for this element,\r
+                       // but worked best visually with a variety of themes\r
+                       this.range.addClass("ui-widget-header");\r
+\r
+               }\r
+\r
+               if ($(".ui-slider-handle", this.element).length == 0)\r
+                       $('<a href="#"></a>')\r
+                               .appendTo(this.element)\r
+                               .addClass("ui-slider-handle");\r
+\r
+               if (o.values && o.values.length) {\r
+                       while ($(".ui-slider-handle", this.element).length < o.values.length)\r
+                               $('<a href="#"></a>')\r
+                                       .appendTo(this.element)\r
+                                       .addClass("ui-slider-handle");\r
+               }\r
+\r
+               this.handles = $(".ui-slider-handle", this.element)\r
+                       .addClass("ui-state-default"\r
+                               + " ui-corner-all");\r
+\r
+               this.handle = this.handles.eq(0);\r
+\r
+               this.handles.add(this.range).filter("a")\r
+                       .click(function(event) {\r
+                               event.preventDefault();\r
+                       })\r
+                       .hover(function() {\r
+                               if (!o.disabled) {\r
+                                       $(this).addClass('ui-state-hover');\r
+                               }\r
+                       }, function() {\r
+                               $(this).removeClass('ui-state-hover');\r
+                       })\r
+                       .focus(function() {\r
+                               if (!o.disabled) {\r
+                                       $(".ui-slider .ui-state-focus").removeClass('ui-state-focus'); $(this).addClass('ui-state-focus');\r
+                               } else {\r
+                                       $(this).blur();\r
+                               }\r
+                       })\r
+                       .blur(function() {\r
+                               $(this).removeClass('ui-state-focus');\r
+                       });\r
+\r
+               this.handles.each(function(i) {\r
+                       $(this).data("index.ui-slider-handle", i);\r
+               });\r
+\r
+               this.handles.keydown(function(event) {\r
+\r
+                       var ret = true;\r
+\r
+                       var index = $(this).data("index.ui-slider-handle");\r
+\r
+                       if (self.options.disabled)\r
+                               return;\r
+\r
+                       switch (event.keyCode) {\r
+                               case $.ui.keyCode.HOME:\r
+                               case $.ui.keyCode.END:\r
+                               case $.ui.keyCode.UP:\r
+                               case $.ui.keyCode.RIGHT:\r
+                               case $.ui.keyCode.DOWN:\r
+                               case $.ui.keyCode.LEFT:\r
+                                       ret = false;\r
+                                       if (!self._keySliding) {\r
+                                               self._keySliding = true;\r
+                                               $(this).addClass("ui-state-active");\r
+                                               self._start(event, index);\r
+                                       }\r
+                                       break;\r
+                       }\r
+\r
+                       var curVal, newVal, step = self._step();\r
+                       if (self.options.values && self.options.values.length) {\r
+                               curVal = newVal = self.values(index);\r
+                       } else {\r
+                               curVal = newVal = self.value();\r
+                       }\r
+\r
+                       switch (event.keyCode) {\r
+                               case $.ui.keyCode.HOME:\r
+                                       newVal = self._valueMin();\r
+                                       break;\r
+                               case $.ui.keyCode.END:\r
+                                       newVal = self._valueMax();\r
+                                       break;\r
+                               case $.ui.keyCode.UP:\r
+                               case $.ui.keyCode.RIGHT:\r
+                                       if(curVal == self._valueMax()) return;\r
+                                       newVal = curVal + step;\r
+                                       break;\r
+                               case $.ui.keyCode.DOWN:\r
+                               case $.ui.keyCode.LEFT:\r
+                                       if(curVal == self._valueMin()) return;\r
+                                       newVal = curVal - step;\r
+                                       break;\r
+                       }\r
+\r
+                       self._slide(event, index, newVal);\r
+\r
+                       return ret;\r
+\r
+               }).keyup(function(event) {\r
+\r
+                       var index = $(this).data("index.ui-slider-handle");\r
+\r
+                       if (self._keySliding) {\r
+                               self._stop(event, index);\r
+                               self._change(event, index);\r
+                               self._keySliding = false;\r
+                               $(this).removeClass("ui-state-active");\r
+                       }\r
+\r
+               });\r
+\r
+               this._refreshValue();\r
+\r
+       },\r
+\r
+       destroy: function() {\r
+\r
+               this.handles.remove();\r
+               this.range.remove();\r
+\r
+               this.element\r
+                       .removeClass("ui-slider"\r
+                               + " ui-slider-horizontal"\r
+                               + " ui-slider-vertical"\r
+                               + " ui-slider-disabled"\r
+                               + " ui-widget"\r
+                               + " ui-widget-content"\r
+                               + " ui-corner-all")\r
+                       .removeData("slider")\r
+                       .unbind(".slider");\r
+\r
+               this._mouseDestroy();\r
+\r
+       },\r
+\r
+       _mouseCapture: function(event) {\r
+\r
+               var o = this.options;\r
+\r
+               if (o.disabled)\r
+                       return false;\r
+\r
+               this.elementSize = {\r
+                       width: this.element.outerWidth(),\r
+                       height: this.element.outerHeight()\r
+               };\r
+               this.elementOffset = this.element.offset();\r
+\r
+               var position = { x: event.pageX, y: event.pageY };\r
+               var normValue = this._normValueFromMouse(position);\r
+\r
+               var distance = this._valueMax() - this._valueMin() + 1, closestHandle;\r
+               var self = this, index;\r
+               this.handles.each(function(i) {\r
+                       var thisDistance = Math.abs(normValue - self.values(i));\r
+                       if (distance > thisDistance) {\r
+                               distance = thisDistance;\r
+                               closestHandle = $(this);\r
+                               index = i;\r
+                       }\r
+               });\r
+\r
+               // workaround for bug #3736 (if both handles of a range are at 0,\r
+               // the first is always used as the one with least distance,\r
+               // and moving it is obviously prevented by preventing negative ranges)\r
+               if(o.range == true && this.values(1) == o.min) {\r
+                       closestHandle = $(this.handles[++index]);\r
+               }\r
+\r
+               this._start(event, index);\r
+\r
+               self._handleIndex = index;\r
+\r
+               closestHandle\r
+                       .addClass("ui-state-active")\r
+                       .focus();\r
+               \r
+               var offset = closestHandle.offset();\r
+               var mouseOverHandle = !$(event.target).parents().andSelf().is('.ui-slider-handle');\r
+               this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {\r
+                       left: event.pageX - offset.left - (closestHandle.width() / 2),\r
+                       top: event.pageY - offset.top\r
+                               - (closestHandle.height() / 2)\r
+                               - (parseInt(closestHandle.css('borderTopWidth'),10) || 0)\r
+                               - (parseInt(closestHandle.css('borderBottomWidth'),10) || 0)\r
+                               + (parseInt(closestHandle.css('marginTop'),10) || 0)\r
+               };\r
+\r
+               normValue = this._normValueFromMouse(position);\r
+               this._slide(event, index, normValue);\r
+               return true;\r
+\r
+       },\r
+\r
+       _mouseStart: function(event) {\r
+               return true;\r
+       },\r
+\r
+       _mouseDrag: function(event) {\r
+\r
+               var position = { x: event.pageX, y: event.pageY };\r
+               var normValue = this._normValueFromMouse(position);\r
+               \r
+               this._slide(event, this._handleIndex, normValue);\r
+\r
+               return false;\r
+\r
+       },\r
+\r
+       _mouseStop: function(event) {\r
+\r
+               this.handles.removeClass("ui-state-active");\r
+               this._stop(event, this._handleIndex);\r
+               this._change(event, this._handleIndex);\r
+               this._handleIndex = null;\r
+               this._clickOffset = null;\r
+\r
+               return false;\r
+\r
+       },\r
+       \r
+       _detectOrientation: function() {\r
+               this.orientation = this.options.orientation == 'vertical' ? 'vertical' : 'horizontal';\r
+       },\r
+\r
+       _normValueFromMouse: function(position) {\r
+\r
+               var pixelTotal, pixelMouse;\r
+               if ('horizontal' == this.orientation) {\r
+                       pixelTotal = this.elementSize.width;\r
+                       pixelMouse = position.x - this.elementOffset.left - (this._clickOffset ? this._clickOffset.left : 0);\r
+               } else {\r
+                       pixelTotal = this.elementSize.height;\r
+                       pixelMouse = position.y - this.elementOffset.top - (this._clickOffset ? this._clickOffset.top : 0);\r
+               }\r
+\r
+               var percentMouse = (pixelMouse / pixelTotal);\r
+               if (percentMouse > 1) percentMouse = 1;\r
+               if (percentMouse < 0) percentMouse = 0;\r
+               if ('vertical' == this.orientation)\r
+                       percentMouse = 1 - percentMouse;\r
+\r
+               var valueTotal = this._valueMax() - this._valueMin(),\r
+                       valueMouse = percentMouse * valueTotal,\r
+                       valueMouseModStep = valueMouse % this.options.step,\r
+                       normValue = this._valueMin() + valueMouse - valueMouseModStep;\r
+\r
+               if (valueMouseModStep > (this.options.step / 2))\r
+                       normValue += this.options.step;\r
+\r
+               // Since JavaScript has problems with large floats, round\r
+               // the final value to 5 digits after the decimal point (see #4124)\r
+               return parseFloat(normValue.toFixed(5));\r
+\r
+       },\r
+\r
+       _start: function(event, index) {\r
+               var uiHash = {\r
+                       handle: this.handles[index],\r
+                       value: this.value()\r
+               };\r
+               if (this.options.values && this.options.values.length) {\r
+                       uiHash.value = this.values(index);\r
+                       uiHash.values = this.values();\r
+               }\r
+               this._trigger("start", event, uiHash);\r
+       },\r
+\r
+       _slide: function(event, index, newVal) {\r
+\r
+               var handle = this.handles[index];\r
+\r
+               if (this.options.values && this.options.values.length) {\r
+\r
+                       var otherVal = this.values(index ? 0 : 1);\r
+\r
+                       if ((this.options.values.length == 2 && this.options.range === true) && \r
+                               ((index == 0 && newVal > otherVal) || (index == 1 && newVal < otherVal))){\r
+                               newVal = otherVal;\r
+                       }\r
+\r
+                       if (newVal != this.values(index)) {\r
+                               var newValues = this.values();\r
+                               newValues[index] = newVal;\r
+                               // A slide can be canceled by returning false from the slide callback\r
+                               var allowed = this._trigger("slide", event, {\r
+                                       handle: this.handles[index],\r
+                                       value: newVal,\r
+                                       values: newValues\r
+                               });\r
+                               var otherVal = this.values(index ? 0 : 1);\r
+                               if (allowed !== false) {\r
+                                       this.values(index, newVal, ( event.type == 'mousedown' && this.options.animate ), true);\r
+                               }\r
+                       }\r
+\r
+               } else {\r
+\r
+                       if (newVal != this.value()) {\r
+                               // A slide can be canceled by returning false from the slide callback\r
+                               var allowed = this._trigger("slide", event, {\r
+                                       handle: this.handles[index],\r
+                                       value: newVal\r
+                               });\r
+                               if (allowed !== false) {\r
+                                       this._setData('value', newVal, ( event.type == 'mousedown' && this.options.animate ));\r
+                               }\r
+                                       \r
+                       }\r
+\r
+               }\r
+\r
+       },\r
+\r
+       _stop: function(event, index) {\r
+               var uiHash = {\r
+                       handle: this.handles[index],\r
+                       value: this.value()\r
+               };\r
+               if (this.options.values && this.options.values.length) {\r
+                       uiHash.value = this.values(index);\r
+                       uiHash.values = this.values();\r
+               }\r
+               this._trigger("stop", event, uiHash);\r
+       },\r
+\r
+       _change: function(event, index) {\r
+               var uiHash = {\r
+                       handle: this.handles[index],\r
+                       value: this.value()\r
+               };\r
+               if (this.options.values && this.options.values.length) {\r
+                       uiHash.value = this.values(index);\r
+                       uiHash.values = this.values();\r
+               }\r
+               this._trigger("change", event, uiHash);\r
+       },\r
+\r
+       value: function(newValue) {\r
+\r
+               if (arguments.length) {\r
+                       this._setData("value", newValue);\r
+                       this._change(null, 0);\r
+               }\r
+\r
+               return this._value();\r
+\r
+       },\r
+\r
+       values: function(index, newValue, animated, noPropagation) {\r
+\r
+               if (arguments.length > 1) {\r
+                       this.options.values[index] = newValue;\r
+                       this._refreshValue(animated);\r
+                       if(!noPropagation) this._change(null, index);\r
+               }\r
+\r
+               if (arguments.length) {\r
+                       if (this.options.values && this.options.values.length) {\r
+                               return this._values(index);\r
+                       } else {\r
+                               return this.value();\r
+                       }\r
+               } else {\r
+                       return this._values();\r
+               }\r
+\r
+       },\r
+\r
+       _setData: function(key, value, animated) {\r
+\r
+               $.widget.prototype._setData.apply(this, arguments);\r
+\r
+               switch (key) {\r
+                       case 'disabled':\r
+                               if (value) {\r
+                                       this.handles.filter(".ui-state-focus").blur();\r
+                                       this.handles.removeClass("ui-state-hover");\r
+                                       this.handles.attr("disabled", "disabled");\r
+                               } else {\r
+                                       this.handles.removeAttr("disabled");\r
+                               }\r
+                       case 'orientation':\r
+\r
+                               this._detectOrientation();\r
+                               \r
+                               this.element\r
+                                       .removeClass("ui-slider-horizontal ui-slider-vertical")\r
+                                       .addClass("ui-slider-" + this.orientation);\r
+                               this._refreshValue(animated);\r
+                               break;\r
+                       case 'value':\r
+                               this._refreshValue(animated);\r
+                               break;\r
+               }\r
+\r
+       },\r
+\r
+       _step: function() {\r
+               var step = this.options.step;\r
+               return step;\r
+       },\r
+\r
+       _value: function() {\r
+\r
+               var val = this.options.value;\r
+               if (val < this._valueMin()) val = this._valueMin();\r
+               if (val > this._valueMax()) val = this._valueMax();\r
+\r
+               return val;\r
+\r
+       },\r
+\r
+       _values: function(index) {\r
+\r
+               if (arguments.length) {\r
+                       var val = this.options.values[index];\r
+                       if (val < this._valueMin()) val = this._valueMin();\r
+                       if (val > this._valueMax()) val = this._valueMax();\r
+\r
+                       return val;\r
+               } else {\r
+                       return this.options.values;\r
+               }\r
+\r
+       },\r
+\r
+       _valueMin: function() {\r
+               var valueMin = this.options.min;\r
+               return valueMin;\r
+       },\r
+\r
+       _valueMax: function() {\r
+               var valueMax = this.options.max;\r
+               return valueMax;\r
+       },\r
+\r
+       _refreshValue: function(animate) {\r
+\r
+               var oRange = this.options.range, o = this.options, self = this;\r
+\r
+               if (this.options.values && this.options.values.length) {\r
+                       var vp0, vp1;\r
+                       this.handles.each(function(i, j) {\r
+                               var valPercent = (self.values(i) - self._valueMin()) / (self._valueMax() - self._valueMin()) * 100;\r
+                               var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%';\r
+                               $(this).stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate);\r
+                               if (self.options.range === true) {\r
+                                       if (self.orientation == 'horizontal') {\r
+                                               (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ left: valPercent + '%' }, o.animate);\r
+                                               (i == 1) && self.range[animate ? 'animate' : 'css']({ width: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate });\r
+                                       } else {\r
+                                               (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ bottom: (valPercent) + '%' }, o.animate);\r
+                                               (i == 1) && self.range[animate ? 'animate' : 'css']({ height: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate });\r
+                                       }\r
+                               }\r
+                               lastValPercent = valPercent;\r
+                       });\r
+               } else {\r
+                       var value = this.value(),\r
+                               valueMin = this._valueMin(),\r
+                               valueMax = this._valueMax(),\r
+                               valPercent = valueMax != valueMin\r
+                                       ? (value - valueMin) / (valueMax - valueMin) * 100\r
+                                       : 0;\r
+                       var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%';\r
+                       this.handle.stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate);\r
+\r
+                       (oRange == "min") && (this.orientation == "horizontal") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ width: valPercent + '%' }, o.animate);\r
+                       (oRange == "max") && (this.orientation == "horizontal") && this.range[animate ? 'animate' : 'css']({ width: (100 - valPercent) + '%' }, { queue: false, duration: o.animate });\r
+                       (oRange == "min") && (this.orientation == "vertical") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ height: valPercent + '%' }, o.animate);\r
+                       (oRange == "max") && (this.orientation == "vertical") && this.range[animate ? 'animate' : 'css']({ height: (100 - valPercent) + '%' }, { queue: false, duration: o.animate });\r
+               }\r
+\r
+       }\r
+       \r
+}));\r
+\r
+$.extend($.ui.slider, {\r
+       getter: "value values",\r
+       version: "1.7.2",\r
+       eventPrefix: "slide",\r
+       defaults: {\r
+               animate: false,\r
+               delay: 0,\r
+               distance: 0,\r
+               max: 100,\r
+               min: 0,\r
+               orientation: 'horizontal',\r
+               range: false,\r
+               step: 1,\r
+               value: 0,\r
+               values: null\r
+       }\r
+});\r
+\r
+})(jQuery);\r
diff --git a/mods/atutor_opencaps/opencaps/js/json/json2.js b/mods/atutor_opencaps/opencaps/js/json/json2.js
new file mode 100755 (executable)
index 0000000..7ae5032
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+    http://www.JSON.org/json2.js
+    2009-06-29
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the object holding the key.
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+*/
+
+/*jslint evil: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+var JSON = JSON || {};
+
+(function () {
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf()) ?
+                   this.getUTCFullYear()   + '-' +
+                 f(this.getUTCMonth() + 1) + '-' +
+                 f(this.getUTCDate())      + 'T' +
+                 f(this.getUTCHours())     + ':' +
+                 f(this.getUTCMinutes())   + ':' +
+                 f(this.getUTCSeconds())   + 'Z' : null;
+        };
+
+        String.prototype.toJSON =
+        Number.prototype.toJSON =
+        Boolean.prototype.toJSON = function (key) {
+            return this.valueOf();
+        };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// 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.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ?
+            '"' + string.replace(escapable, function (a) {
+                var c = meta[a];
+                return typeof c === 'string' ? c :
+                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+            }) + '"' :
+            '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0 ? '[]' :
+                    gap ? '[\n' + gap +
+                            partial.join(',\n' + gap) + '\n' +
+                                mind + ']' :
+                          '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    k = rep[i];
+                    if (typeof k === 'string') {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0 ? '{}' :
+                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+                        mind + '}' : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                     typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function' ?
+                    walk({'': j}, '') : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());
diff --git a/mods/atutor_opencaps/opencaps/js/preview.js b/mods/atutor_opencaps/opencaps/js/preview.js
new file mode 100755 (executable)
index 0000000..a560491
--- /dev/null
@@ -0,0 +1,86 @@
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+var layout = 0;\r
+\r
+$(document).ready(function () {\r
+       $.get("include/workflow.php", { task: 'get_json' }, function(json) {\r
+               if (json) {\r
+                       proj = JSON.parse(json);                        \r
+                       startPreview();\r
+                }\r
+       });     \r
+});\r
+\r
+function startPreview() {\r
+       $("#preview-tab").addClass('current');\r
+       layout = proj.layout;\r
+       if (layout == undefined)\r
+               layout = 0;\r
+       \r
+       //set selected layout   \r
+       $('input[name="layout"]')[layout].checked = true;\r
+       \r
+       embedPreview();\r
+       \r
+}\r
+\r
+function saveLayout() {\r
+\r
+       for(var i=0; i<document.forms[0].layout.length; i++) {\r
+               if (document.forms[0].layout[i].checked == true ) {\r
+                       proj.layout = document.forms[0].layout[i].value;\r
+                       break;\r
+               }\r
+       }\r
+       \r
+       json = JSON.stringify(proj);\r
+       $.get("include/workflow.php", { task: 'save_json', json:json, pid:proj.id }, function(data) {           \r
+               startPreview();\r
+       });\r
+}\r
+\r
\r
+function QTStatus() {\r
+       var status = movieObj.GetPluginStatus();\r
+\r
+       if (status == "Complete") {\r
+               window.clearInterval(QTinterval);\r
+               setDisplay();\r
+       }\r
+}\r
+\r
+function embedPreview() {\r
+       if (proj.media_width <= 0) {\r
+               layout = 2;\r
+               proj.media_width = 250;\r
+               $('input[name="layout"]')[layout].checked = true;\r
+       }\r
+       \r
+       //preview on the server creates the qttext and smil files\r
+       $.get("include/workflow.php", { task:'preview', layout: layout }, function(obj_height) {\r
+               \r
+               if (obj_height) {                       \r
+                       smil_loc = "projects/"+proj.id+"/smil_"+layout+".mov";\r
+       \r
+                       //embed smil file\r
+                       var embed = '<object width="'+(parseInt(proj.media_width)+80)+'" height="'+obj_height+'" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0" id="mymovie">';\r
+                       embed += '<param name="src" value="'+smil_loc+'" /><param name="enablejavascript" value="true" />';\r
+                       embed += '<param name="postdomevents" value="true" /><param name="autoplay" value="false" />';\r
+                       embed += '<param name="cache" value="false" />';\r
+                       embed += '<embed src="'+smil_loc+'" width="'+(parseInt(proj.media_width)+80)+'" height="'+obj_height+'" cache="false" pluginspage="http://www.apple.com/quicktime/download/" name="mymovie" enablejavascript="true" id="mymovie_embed" postdomevents="true" autoplay="false" /></object>';\r
+                       $("#movie-container").html(embed);                      \r
+               }                       \r
+       });     \r
+       \r
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/settings.js b/mods/atutor_opencaps/opencaps/js/settings.js
new file mode 100755 (executable)
index 0000000..276180d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+$(document).ready(function () {
+       $("#settings-tab").addClass('current');
+       hide_all();
+});
+
+
+function hide_all() {
+       $("#edit-name").hide();
+       $("#edit-caps").hide();
+       $("#edit-media").hide();
+       $("#edit-perms").hide();        
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/start.js b/mods/atutor_opencaps/opencaps/js/start.js
new file mode 100755 (executable)
index 0000000..ea12520
--- /dev/null
@@ -0,0 +1,155 @@
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+$(document).ready(function () {\r
+       $("#start-entry").hide();\r
+       $("#open-entry").hide();        \r
+               \r
+       //create start tabs, local and remote   \r
+       $.get("include/workflow.php", { task: 'get_tabs' }, function(data) {\r
+               $("#start-tabs").html(data);    \r
+               $("#home").addClass('current');\r
+       });     \r
+       \r
+       if(document.location.search.substring(1, 5) == 'page')\r
+               startOpen();    \r
+       else if (document.location.search.substring(1, 7) == 'submit')\r
+               startNew();\r
+               \r
+});\r
+\r
+\r
+function startNew() {\r
+       $("#open-entry").hide();\r
+       $("#start-entry").show();\r
+}\r
+function startOpen() {\r
+       $("#start-entry").hide();\r
+       \r
+       if (document.location.search != '') {\r
+               $.get("include/workflow.php", { task: 'print_projs', page: document.location.search.substring(6) }, function(data){             \r
+                       $("#projects").html(data);      \r
+               });\r
+       } else {\r
+               $.get("include/workflow.php", { task: 'print_projs' }, function(data){          \r
+                       $("#projects").html(data);      \r
+               });\r
+       }\r
+       \r
+       $("#open-entry").show();        \r
+}      \r
+\r
+\r
+/*\r
+ * start project\r
+ */\r
+/*function processNew() {      \r
+               \r
+       $.get("include/workflow.php", { task:'new_proj', name:name, media_url:media_url, media_file:media_file, captions:captions }, function(data){\r
+               if (!data) {\r
+                       window.location = "editor.php";\r
+               } else {\r
+                       alert(data);\r
+               }\r
+       });     \r
+\r
+}*/\r
+\r
+function validateNewForm() {\r
+       var myform = document.forms[0];\r
+       var errs = '';\r
+       \r
+       if (myform.projname.value == '') {\r
+               errs = 'Project name cannot be empty.\n';\r
+       } else {\r
+               var projname = myform.projname.value;\r
+       }\r
+       \r
+       if ((myform.media_url.value == '' || myform.media_url.value == 'http://') && myform.media_file.value == '') {\r
+               errs += 'Video file cannot be empty.\n';\r
+       }\r
+       \r
+       if (errs != '') {\r
+               alert(errs);\r
+               startNew();\r
+               if (projname) \r
+                       myform.projname.value = projname;       \r
+               return false;\r
+       } else {\r
+               document.forms[0].submit();\r
+               //return true;\r
+       }\r
+}      \r
+\r
+\r
+function processOpen() {       \r
+       var myform = document.forms[1];\r
+\r
+       //get chosen project id\r
+       chosen = myform.proj.value;\r
+\r
+       projlen = myform.proj.length;  //if array       \r
+       for (i = 0; i<projlen; i++) {\r
+               if (myform.proj[i].checked) {\r
+                       chosen = myform.proj[i].value;\r
+               }\r
+       }       \r
+       \r
+       //open project\r
+       $.get("include/workflow.php", { task: 'open_proj', pid: chosen }, function(data){               \r
+               if (!data) {\r
+                       window.location = "editor.php";\r
+               } else {\r
+                       alert(data);\r
+               }\r
+       });\r
+}\r
+\r
+function validateOpenForm() {\r
+       var myform = document.forms[1];\r
+       var errs = '';\r
+       var chosen = null;\r
+       \r
+       //make sure a project was selected\r
+       chosen = myform.proj.value;\r
+\r
+       projlen = myform.proj.length;  //if array\r
+       \r
+               for (i = 0; i <projlen; i++) {\r
+               if (myform.proj[i].checked) {\r
+                       chosen = myform.proj[i].value;\r
+               }\r
+       }       \r
+       \r
+       if (chosen == null) \r
+               errs += 'You must choose a project to open.\n';\r
+\r
+       if (errs != '') {\r
+               alert(errs);\r
+               startOpen();            \r
+               return false;\r
+       } else {\r
+               return true;\r
+       }\r
+}      \r
+\r
+function confirmDelete(proj_id, name) {\r
+       if (confirm("Are you sure you want to delete the project '"+name+"'?")) {\r
+               $.get("include/workflow.php", { task:'proj_delete', pid: proj_id }, function(data){\r
+                       if (data) {\r
+                               alert(data);\r
+                       } \r
+               });\r
+               startOpen();\r
+       }\r
+}      
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/start_remote.js b/mods/atutor_opencaps/opencaps/js/start_remote.js
new file mode 100755 (executable)
index 0000000..91a2eb0
--- /dev/null
@@ -0,0 +1,99 @@
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+$(document).ready(function () {\r
+       var rid = window.location.search.substring(3,4);\r
+       var page = window.location.search.substring(10);\r
+       \r
+       if (page == '')\r
+               page = 1;\r
+\r
+       //create start tabs, local and remote   \r
+       $.get("include/workflow.php", { task: 'get_tabs' }, function(data) {\r
+               $("#start-tabs").html(data);    \r
+               $("#remote-"+rid).addClass('current');\r
+       });     \r
+       \r
+       $.get("include/workflow.php", { task: 'print_projs_remote', rid: rid, page: page }, function(data){             \r
+               $("#projects").html(data);      \r
+       });\r
+       \r
+});\r
+\r
+\r
+function validateOpenForm() {\r
+       var myform = document.forms[0];\r
+       var errs = '';\r
+       var chosen = null;\r
+       \r
+       //make sure a project was selected\r
+       chosen = myform.proj.value;\r
+\r
+       projlen = myform.proj.length;  //if array\r
+       \r
+               for (i = 0; i <projlen; i++) {\r
+               if (myform.proj[i].checked) {\r
+                       chosen = myform.proj[i].value;\r
+               }\r
+       }       \r
+       \r
+       if (chosen == null) \r
+               errs += 'You must choose a project to open.\n';\r
+\r
+       if (errs != '') {\r
+               alert(errs);\r
+               return false;\r
+       } else {\r
+               return true;\r
+       }\r
+}\r
+\r
+function processOpenRemote() { \r
+       var myform = document.forms[0];\r
+\r
+       //get chosen project id\r
+       chosen = myform.proj.value;\r
+\r
+       projlen = myform.proj.length;  //if array       \r
+       for (i = 0; i<projlen; i++) {\r
+               if (myform.proj[i].checked) {\r
+                       chosen = myform.proj[i].value;\r
+               }\r
+       }       \r
+       \r
+       //open project\r
+       $.get("include/workflow.php", { task: 'open_proj_remote', pid: chosen  }, function(data){               \r
+               if (!data) {\r
+                       window.location = "editor.php";\r
+               } else {\r
+                       alert(data);\r
+               }\r
+       });\r
+}\r
+\r
+\r
+/*for(var i=0; i<document.forms[1].pkg_url.length; i++) {\r
+if (document.forms[1].pkg_url[i].checked == true ) {\r
+       var pkg_url = document.forms[1].pkg_url[i].value;\r
+       break;\r
+}\r
+\r
+var pkg_url = document.forms[1].pkg_url.value;\r
+\r
+$.get("include/workflow.php", { task:'open_proj_pkg', xml:pkg_url }, function(data){\r
+if (!data) {\r
+       window.location = "editor.php";\r
+} else {\r
+       alert(data);\r
+}\r
+});    }*/
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/js/utils.js b/mods/atutor_opencaps/opencaps/js/utils.js
new file mode 100755 (executable)
index 0000000..20bfea2
--- /dev/null
@@ -0,0 +1,182 @@
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+\r
+function loadProject() {\r
+       $.get("include/workflow.php", { task: 'get_json' }, function(json){\r
+               alert(json);\r
+\r
+               if (json) {\r
+                       proj = JSON.parse(json);\r
+                }\r
+       });\r
+}\r
+\r
+/*************************************** listeners */\r
+function myAddListener(obj, evt, handler, captures) {\r
+       if (document.addEventListener) \r
+               obj.addEventListener(evt, handler, captures);\r
+       else\r
+               obj.attachEvent('on' + evt, handler);\r
+}\r
+function RegisterListener(eventName, objID, embedID, listenerFcn) {\r
+       var obj = document.getElementById(objID);\r
+       if ( !obj )\r
+               obj = document.getElementById(embedID);\r
+       if ( obj )\r
+               myAddListener(obj, eventName, listenerFcn, false);\r
+}\r
+\r
+/*************************************** utils */\r
+function sortNumber(a, b) {\r
+       return a - b;\r
+}\r
+\r
+function calcTime(time) {\r
+       var numhours = 0;\r
+       var nummins = 0;\r
+       var numsecs = 0;\r
+       var nummils = 0;\r
+               \r
+       var t = time/movieObj.GetTimeScale();  \r
+\r
+       if (t > onehr) {\r
+               numhours = parseInt(t/onehr);\r
+               t = t-(numhours*onehr);\r
+       }\r
+       if (t > onemin) {\r
+               nummins = parseInt(t/onemin);\r
+               t = t-(nummins*onemin);\r
+       }\r
+\r
+       //converts xx.xxxxxxxxxxx... to xxxxx since js doesn't round to a decimal\r
+       t = Math.round(t*1000)+1;\r
+\r
+       /*if (t > 0)\r
+               t = t+1;*/\r
+\r
+       var t2 = new String(t);\r
+       if (t<1000) { //less than a sec\r
+               numsecs = 0;\r
+               nummils = t;\r
+       } else if (t<10000) { //less than 10 secs\r
+               numsecs = t2.substr(0,1);\r
+               nummils = t2.substr(1);\r
+       } else {\r
+               numsecs = t2.substr(0,2);\r
+               nummils = t2.substr(2);\r
+       }\r
+\r
+       nummils = nummils + "000";\r
+       nummils = nummils.substr(0,3);\r
+\r
+       return padDigits(numhours,2) + ':' + padDigits(nummins, 2) + ':' + padDigits(numsecs, 2) + '.' + nummils;\r
+}\r
+function getFormattedTime(gt) {\r
+       var total = gt/movieObj.GetTimeScale();\r
+\r
+       var gms = Math.round(total * 1000) % 1000;\r
+       \r
+       total = Math.floor(total);\r
+       \r
+       var gs = total % 60;\r
+       total = Math.floor(total / 60); \r
+       \r
+       var gm = total % 60;\r
+       gh = Math.floor(total / 60);    \r
+       \r
+       var code = padDigits(gh, 2) + ":" + padDigits(gm, 2) + ":" + padDigits(gs, 2) + "." + padDigits(gms, 3);\r
+       return code;\r
+}\r
+\r
+function getMilliseconds(ft) {\r
+       var t = ft.split(':');\r
+       \r
+       //convert hours, minutes, seconds all to milliseconds and add\r
+       var millis = (t[0]*60*60*1000) + (t[1]*60*1000) + (t[2]*1000);\r
+\r
+       //millis = millis*(movieObj.GetTimeScale());\r
+       \r
+       return Math.round(millis);\r
+}\r
+\r
+\r
+function getFormattedTime2(total) {\r
+\r
+       var milli = total % 1000;\r
+       var sec = Math.floor(total/1000);       \r
+       var min = 0;\r
+       var hr = 0;\r
+       \r
+       if (sec > 59) {\r
+               var bigsec = sec;\r
+               sec = bigsec % 60;\r
+               min = Math.floor(bigsec / 60);\r
+               \r
+               if (min > 59) {\r
+                       bigmin = min\r
+                       min = bigmin % 60;\r
+                       hr = Math.floor(bigmin / 60);\r
+               }\r
+       } \r
+       \r
+       return padDigits(hr, 2) + ":" + padDigits(min, 2) + ":" + padDigits(sec, 2) + "." + padDigits(milli, 3);        \r
+}\r
+\r
+function getClipDuration(tin, tout) {  \r
+       tin = getMilliseconds(tin);\r
+       tout= getMilliseconds(tout);\r
+       \r
+       var total = tout-tin;   \r
+       return getFormattedTime2(total);        \r
+}\r
+\r
+function addMilli(t) {\r
+       t = getMilliseconds(t) + 1;\r
+       return getFormattedTime2(t);\r
+}\r
+\r
+function subMilli(t) {\r
+       t = getMilliseconds(t) - 1;\r
+       return getFormattedTime2(t);\r
+}\r
+\r
+function roundNum(n) {\r
+       return Math.round(n * 1000) / 1000;\r
+}\r
+\r
+//adds missing zeros before number if ness\r
+function padDigits(n, totalDigits) { \r
+       n = n.toString(); \r
+       var pd = ''; \r
+       if (totalDigits > n.length)     { \r
+               for (i=0; i < (totalDigits-n.length); i++) { \r
+                       pd += '0'; \r
+               } \r
+       } \r
+       return pd + n.toString(); \r
+} \r
+\r
+/*function inASpace() {\r
+       if ( ($("#clip-name").text() == "Space after Clip "+ curClip) || ($("#clip-name").text() == "Space before Clip "+ (curClip+1))) \r
+               return true;\r
+       else \r
+               return false;\r
+}*/\r
+\r
+function inAClip() {\r
+       if ( $("#clip-name").text() == "Clip "+ curClip ) \r
+               return true;\r
+       else \r
+               return false;\r
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/license.txt b/mods/atutor_opencaps/opencaps/license.txt
new file mode 100755 (executable)
index 0000000..6b11dea
--- /dev/null
@@ -0,0 +1,76 @@
+OpenCaps is available under the terms of the Educational Community License, Version 2.0. All modules are Copyright 2007 University of Toronto except where noted otherwise in the code itself, or if the modules reside in a separate directory, they may contain explicit declarations of copyright in both the LICENSE file in the directory in which they reside and in the code itself. No external contributions are allowed under licenses which are fundamentally incompatible with the ECL license that OpenCaps is distributed under.\r
+\r
+The text of the ECL license is reproduced below. It is also available at http://www.opensource.org/licenses/ecl2.php\r
+\r
+Educational Community License, Version 2.0\r
+*************************************\r
+Copyright 2007 University of Toronto\r
+\r
+Educational Community License, Version 2.0, April 2007\r
+\r
+The Educational Community License version 2.0 ("ECL") consists of the Apache 2.0 license, modified to change the scope of the patent grant in section 3 to be specific to the needs of the education communities using this license. The original Apache 2.0 license can be found at: http://www.apache.org/licenses/LICENSE-2.0\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, and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\r
+\r
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.\r
+\r
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.\r
+\r
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.\r
+\r
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).\r
+\r
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\r
+\r
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.\r
+\r
+2. Grant of Copyright License.\r
+\r
+Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.\r
+\r
+3. Grant of Patent License.\r
+\r
+Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. Any patent license granted hereby with respect to contributions by an individual employed by an institution or organization is limited to patent claims where the individual that is the author of the Work is also the inventor of the patent claims licensed, and where the organization or institution has the right to grant such license under applicable grant and research funding agreements. No other express or implied licenses are granted.\r
+\r
+4. Redistribution.\r
+\r
+You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:\r
+\r
+   1. You must give any other recipients of the Work or Derivative Works a copy of this License; and\r
+   2. You must cause any modified files to carry prominent notices stating that You changed the files; and\r
+   3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and\r
+   4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.\r
+\r
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.\r
+\r
+5. Submission of Contributions.\r
+\r
+Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.\r
+\r
+6. Trademarks.\r
+\r
+This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+7. Disclaimer of Warranty.\r
+\r
+Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.\r
+\r
+8. Limitation of Liability.\r
+\r
+In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.\r
+\r
+9. Accepting Warranty or Additional Liability.\r
+\r
+While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.\r
+\r
+END OF TERMS AND CONDITIONS FOR ECL 2.0
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/loadmedia.php b/mods/atutor_opencaps/opencaps/loadmedia.php
new file mode 100755 (executable)
index 0000000..2b004b9
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2010 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+define('INCLUDE_PATH', 'include/');
+
+require(INCLUDE_PATH.'vitals.inc.php');
+
+
+$file = $_GET['loc'];
+
+if (isset($_SESSION['rid'])) {
+       $uri = explode($remote_systems[$_SESSION["rid"]]['url'], $file);
+       $uri = $uri[1];
+       $file = matterhornAuth($_SESSION["rid"], $uri, "media");
+}
+
+header('Pragma: public');
+header('Expires: 0');
+header('Cache-Control: must-revalidate, post-check=0, pre-check');
+header('Cache-Control: private', false);
+header('Content-Type: video/quicktime');
+header('Content-Transfer-Encoding: binary');
+header('Content-Length: '.filesize($file));
+
+readfile($file);
+exit;
+
+
+
+
+
+
+
+
+
+/*
+
+loadMedia(urldecode($_GET['loc']));
+
+function loadMedia($loc) {
+       global $remote_systems;
+                       
+       //if matterhorn
+       if (isset($_SESSION["rid"])) {
+               $uri = explode($remote_systems[$_SESSION["rid"]]['url'], $loc);
+               $uri = $uri[1];
+               return matterhornAuth($rid, $uri, "media");
+       
+       } else {
+               return readfile($loc);
+       }
+}*/
+
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/login.php b/mods/atutor_opencaps/opencaps/login.php
new file mode 100755 (executable)
index 0000000..aec57a3
--- /dev/null
@@ -0,0 +1,60 @@
+<?php \r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+require('include/vitals.inc.php');\r
+\r
+if (isset($_POST['submit'])) {\r
+       \r
+       $this_user->login($_POST['login'], $_POST['password']);\r
+\r
+}\r
+\r
+include('include/basic_header.inc.php');\r
+?>\r
+<style>\r
+       body { background-color:white; }\r
+</style>\r
+       <script language="JavaScript" src="../jscripts/sha-1factory.js" type="text/javascript"></script>\r
+\r
+       <script language="JavaScript" type="text/javascript">\r
+       //<!--\r
+         function crypt_sha1() {\r
+               document.form.password_hidden.value = hex_sha1(document.form.password.value + "<?php echo $_SESSION['token']; ?>");\r
+               document.form.password.value = "";\r
+               return true;\r
+         }\r
+        //-->\r
+       </script>       \r
+       <h2>Login</h2>\r
+\r
+       <p>To start a new captioning project or to return to an ongoing project, please login below. If you are new here, quickly <a href="register.php">register</a> with us!</p>\r
+       \r
+       \r
+       <form action="login.php" method="post" id="form">\r
+       \r
+               <h1 style="float:left; margin-left:10px;"><img src="images/logo_sm.png" alt="Capscribe logo" /></h1>\r
+       \r
+               <dl class="col-list" style="width:33%; margin-left:auto; margin-right:auto;">\r
+                       <dt><label for="login">Login:</label></dt> \r
+                               <dd><input name="login" type="text" id="login" value="" /></dd>\r
+                       <dt><label for="pswd">Password:</label></dt> \r
+                               <dd><input name="password" type="password" id="pswd" value="" /></dd>\r
+               </dl>\r
+               <div style="text-align:right">\r
+                       <input type="submit" name="submit" value="Submit" class="button" style="width:5em; margin-right:10px;" />\r
+               </div>\r
+       </form>\r
+\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/logout.php b/mods/atutor_opencaps/opencaps/logout.php
new file mode 100755 (executable)
index 0000000..777b50c
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+define('INCLUDE_PATH', 'include/');
+require(INCLUDE_PATH.'vitals.inc.php');
+
+unset($_SESSION['login']);
+unset($_SESSION['valid_user']);
+unset($_SESSION['mid']);
+unset($_SESSION['username']);
+
+unset($_SESSION['is_admin']);
+unset($_SESSION['errors']);
+unset($_SESSION['notices']);
+
+$_SESSION['feedback'][] = 'Successfully logged out.';
+
+header('Location: index.php');
+exit;
+
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/preview.php b/mods/atutor_opencaps/opencaps/preview.php
new file mode 100755 (executable)
index 0000000..79700d8
--- /dev/null
@@ -0,0 +1,45 @@
+<?php \r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+define('INCLUDE_PATH', 'include/');\r
+require(INCLUDE_PATH.'vitals.inc.php');\r
+require(INCLUDE_PATH.'header.inc.php'); ?>\r
+\r
+<script language="javascript" type="text/javascript" src="js/preview.js"></script>\r
+       \r
+<div id="content">\r
+       <div id="movie-container" style="margin-top:10px;padding-bottom:5em;"> \r
+       </div>\r
+       \r
+       <div id="info-container">\r
+               <!-- div id="submenubar">\r
+                       <ul>\r
+                               <li><a id="preset-tab" href="#" onClick="displayPreset();">Preset</a></li>\r
+                               <li><a id="custom-tab" href="#" onClick="displayCustom()">Custom</a></li>\r
+                       </ul>\r
+               </div -->\r
+               \r
+               <div id="layout" style="padding:5px; border-top:2px solid #ccc;">       \r
+                       <h3 style="font-size:small; margin:0px;margin-bottom:5px;">Layout Presets</h3>\r
+                       <form method="post" id="form" action="javascript:saveLayout();">\r
+                               <label><input type="radio" name="layout" value="0" /> Caption below</label><br />\r
+                               <label><input type="radio" name="layout" value="1" /> Caption on bottom</label><br />\r
+                               <label><input type="radio" name="layout" value="2" /> Caption only (audio podcast)</label><br /><br />                  \r
+                               <div style="text-align:right"><input type="submit" name="submit" value="Apply" /></div>\r
+                       </form>\r
+               </div>\r
+       </div>\r
+\r
+       </div>\r
+<?php require(INCLUDE_PATH.'footer.inc.php'); ?>\r
diff --git a/mods/atutor_opencaps/opencaps/projects/12-d0679f0984ba38ffc572d0d9718091d37059d5b6/opencaps.json b/mods/atutor_opencaps/opencaps/projects/12-d0679f0984ba38ffc572d0d9718091d37059d5b6/opencaps.json
new file mode 100755 (executable)
index 0000000..2f8a98a
--- /dev/null
@@ -0,0 +1 @@
+{"id":"12-d0679f0984ba38ffc572d0d9718091d37059d5b6","name":"ttttttttttt","media_loc":"http://localhost/php/_myphp/__phpOO/ATutor_Devel/_at2/ATutor/content/1/antoOC/movie1.mov","media_height":"182","media_width":"287","duration":"00:00:26.693","caption_loc":null,"clip_collection":{"clips":[],"global_caption_styles":[]},"layout":null,"owner":{"id":"99999","username":"guest","name":null,"preferences":[],"valid":false}}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/projects/3-d0679f0984ba38ffc572d0d9718091d37059d5b6/opencaps.json b/mods/atutor_opencaps/opencaps/projects/3-d0679f0984ba38ffc572d0d9718091d37059d5b6/opencaps.json
new file mode 100755 (executable)
index 0000000..a1efe74
--- /dev/null
@@ -0,0 +1 @@
+{"id":"3-d0679f0984ba38ffc572d0d9718091d37059d5b6","name":"sdfsdf","media_loc":"http://localhost/php/_myphp/__phpOO/ATutor_Devel/_at2/ATutor/content/1/ram40.mov","media_height":"150","media_width":"272","duration":"00:03:03.125","caption_loc":null,"clip_collection":{"clips":[{"inTime":"00:00:00.000","outTime":"00:00:23.196","duration":"00:00:23.196","inTimeMilli":0,"outTimeMilli":23196,"durationMilli":23196,"caption_text":"ok lang is oku000alove yoy php.flash","captionStyles":[],"name":"Clip 1"},{"inTime":"00:00:29.594","outTime":"00:01:40.218","duration":"00:01:10.624","inTimeMilli":29594,"outTimeMilli":100218,"durationMilli":70624,"caption_text":"adfsdafsda","captionStyles":[],"name":"Clip 2"},{"inTime":"00:01:46.299","outTime":"00:02:06.786","duration":"00:00:20.487","inTimeMilli":106299,"outTimeMilli":126786,"durationMilli":20487,"caption_text":"afdsfs","captionStyles":[],"name":"Clip 3"}],"global_caption_styles":[]},"layout":null,"owner":{"id":"99999","username":"guest","name":null,"preferences":[],"valid":false}}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/projects/index.html b/mods/atutor_opencaps/opencaps/projects/index.html
new file mode 100755 (executable)
index 0000000..6a23616
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\r
+<title></title>\r
+</head>\r
+<body>\r
+\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/projects/layouts/smil_0.mov b/mods/atutor_opencaps/opencaps/projects/layouts/smil_0.mov
new file mode 100755 (executable)
index 0000000..ad73615
--- /dev/null
@@ -0,0 +1 @@
+SMILtext\r<smil xmlns:qt="http://www.apple.com/quicktime/resources/smilextensions" qt:autoplay="false" qt:time-slider="true" qt:chapter-mode="all" >\r   <head>\r         <layout type="text/css">\r                       [region="captionregion"] {background-color:black; }\r            </layout>\r\r             <layout>\r                       <root-layout id="Main" width="%rootwidth%" height="%rootheight%" background-color="#000000" />\r                 <region id="movieregion" width="%width%" height="%height%" left="0" top="2" fit="Fill" z-index="1" background-color="#000000" />\r                       <region id="captionregion" width="%capwidth%" height="%capheight%" left="5" top="%captop%" fit="Meet" z-index="0" background-color="#000000" />\r                </layout>\r      </head>\r        <body>\r         <par begin="00:00:00.00" dur="%duration%">\r                     <video src="%video%" id="video1" region="movieregion" dur="%duration%" />\r                      <textstream src="captions.txt" id="text1" region="captionregion" dur="%duration%" />\r           </par>\r </body>\r</smil>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/projects/layouts/smil_1.mov b/mods/atutor_opencaps/opencaps/projects/layouts/smil_1.mov
new file mode 100755 (executable)
index 0000000..8578865
--- /dev/null
@@ -0,0 +1 @@
+SMILtext\r<smil xmlns:qt="http://www.apple.com/quicktime/resources/smilextensions" qt:autoplay="false" qt:time-slider="true" qt:chapter-mode="all" >\r   <head>\r         <layout>\r                       <root-layout id="Main" width="%rootwidth%" height="%rootheight%" background-color="#000000" />\r                 <region id="movieregion" width="%width%" height="%height%" left="0" top="2" fit="Fill" z-index="0" />\r                  <region id="captionregion" width="%capwidth%" height="%capheight%" left="5" top="%captop%" fit="Meet" z-index="1" />\r           </layout>\r      </head>\r        <body>\r         <seq>\r                  <par>\r                          <video src="%video%" id="video1" region="movieregion" dur="%duration%" begin="00:00:00.00" end="%duration%" />\r                         <textstream src="captions.txt" id="text1" region="captionregion" qt:composite-mode="transparent-color;#000000"  begin="00:00:00.000" dur="%duration%" align="center" />\r                        </par>\r         </seq>\r </body>\r</smil>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/projects/layouts/smil_2.mov b/mods/atutor_opencaps/opencaps/projects/layouts/smil_2.mov
new file mode 100755 (executable)
index 0000000..6bd2012
--- /dev/null
@@ -0,0 +1 @@
+SMILtext\r<smil xmlns:qt="http://www.apple.com/quicktime/resources/smilextensions" qt:autoplay="false" qt:time-slider="true" qt:chapter-mode="all" >\r   <head>\r         <layout>\r                       <root-layout id="Main" width="%rootwidth%" height="%rootheight%" background-color="#000000" />\r                 <region id="movieregion" width="0" height="0" left="41" top="2" fit="Fill" z-index="1" />\r                      <region id="captionregion" width="%capwidth%" height="%capheight%" left="5" top="%captop%" fit="Meet" z-index="0" />\r           </layout>\r      </head>\r        <body>\r         <seq>\r                  <par>\r                          <video src="%video%" id="video1" region="movieregion" dur="%duration%" begin="00:00:00.00" end="%duration%" />\r                         <textstream src="captions.txt" id="text1" region="captionregion" qt:composite-mode="transparent-color;#000000"  begin="00:00:00.000" dur="%duration%" />\r                       </par>\r         </seq>\r </body>\r</smil>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/projects/opencaps.json b/mods/atutor_opencaps/opencaps/projects/opencaps.json
new file mode 100755 (executable)
index 0000000..0e4bc21
--- /dev/null
@@ -0,0 +1 @@
+{"id":"3-d0679f0984ba38ffc572d0d9718091d37059d5b6","name":"sdfsdf","media_loc":"http://localhost/php/_myphp/__phpOO/ATutor_Devel/_at2/ATutor/content/1/ram40.mov","media_height":"165","media_width":"283","duration":"00:03:03.125","caption_loc":null,"clip_collection":{"clips":[{"inTime":"00:00:00.000","outTime":"00:00:23.196","duration":"00:00:23.196","inTimeMilli":0,"outTimeMilli":23196,"durationMilli":23196,"caption_text":"ok lang is ok","captionStyles":[]},{"inTime":"00:00:29.594","outTime":"00:01:40.218","duration":"00:01:10.624","inTimeMilli":29594,"outTimeMilli":100218,"durationMilli":70624,"caption_text":"adfsdafsda","captionStyles":[]},{"inTime":"00:01:46.299","outTime":"00:02:06.786","duration":"00:00:20.487","inTimeMilli":106299,"outTimeMilli":126786,"durationMilli":20487,"caption_text":"afdsfs","captionStyles":[]}],"global_caption_styles":[]},"layout":null,"owner":{"id":"99999","username":"guest","name":null,"preferences":[],"valid":false}}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/projects/player_template.php b/mods/atutor_opencaps/opencaps/projects/player_template.php
new file mode 100755 (executable)
index 0000000..1dc333d
--- /dev/null
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+<title>Capscribe Movies</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+<style type="text/css">
+       body {
+               background-color: #FFFFFF;
+               text-align:center;
+       }
+       
+       #movie-commands {
+               list-style:none;
+               margin: 0px 0px 0px -30px;
+               font-weight: bold;
+               padding:0px;
+       }
+       #movie-commands li {
+               display:inline;
+               padding: 5px;
+       }
+</style>
+
+<script language="JavaScript" type="text/javascript">
+function stepback() {
+       var time = document.movie1.GetTime();
+       
+       if (time<5000)
+               document.movie1.Rewind();
+       else
+               document.movie1.SetTime(time-5000);
+}
+
+//adds missing zeros before number if ness
+function padDigits(n, totalDigits) { 
+       n = n.toString(); 
+       var pd = ''; 
+       if (totalDigits > n.length)     { 
+               for (i=0; i < (totalDigits-n.length); i++) { 
+                       pd += '0'; 
+               } 
+       } 
+       return pd + n.toString(); 
+} 
+
+function getFormattedTime(gt) {
+       var total = gt/document.movie1.GetTimeScale();
+
+       var gms = Math.round(total * 1000) % 1000;
+       
+       total = Math.floor(total);
+       
+       var gs = total % 60;
+       total = Math.floor(total / 60); 
+       
+       var gm = total % 60;
+       gh = Math.floor(total / 60);    
+       
+       var code = padDigits(gh, 2) + ":" + padDigits(gm, 2) + ":" + padDigits(gs, 2) + "." + padDigits(gms, 3);
+       return code;
+}
+
+
+function gettime() {
+       document.movie1.Stop();
+       var time = document.movie1.GetTime();
+       alert("The current time is " + getFormattedTime(document.movie1.GetTime()));
+}
+
+</script>
+
+</head>
+
+
+<body>
+
+<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" width="%width%" height="%height%" id="movie1">
+       <param name="src" value="smil.mov">
+       <param name="enablejavascript" value="true">
+       <param name="autoplay" value="false">
+       <param name="bgcolor" value="#000000">
+       <param name="controller" value="true">
+       
+       <embed src="smil.mov" width="%width%" height="%height%" pluginspage="http://www.apple.com/quicktime/download/" name="movie1" enablejavascript="true" id="movie1_embed" postdomevents="true" autoplay="false" controller="true" />
+</object>
+
+<div style="margin-top:1px; background: #a9a9a9">
+       <ul id="movie-commands">
+               <li><a href="#" onclick="javascript:document.movie1.Play();">Play</a></li>
+               <li><a href="#" onclick="javascript:document.movie1.Stop();">Stop</a></li>      
+       
+               <li><a href="#" onclick="javascript:gettime()">Get Movie Time</a></li>  
+               
+               <li><a href="#" onclick="javascript:document.movie1.Rewind();">Rewind</a></li>
+               <li><a href="#" onclick="stepback();">Step Back</a></li>
+               <li><a href="#" onclick="javascript:document.movie1.SetTime(document.movie1.GetTime()+5000);">Step Ahead</a></li>
+       
+       
+       </ul>   
+</div>
+       
+
+</body>
+</html>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/register.php b/mods/atutor_opencaps/opencaps/register.php
new file mode 100755 (executable)
index 0000000..aee8144
--- /dev/null
@@ -0,0 +1,125 @@
+<?php \r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+require('include/vitals.inc.php');\r
+\r
+if (isset($_POST['newuser']) && $_POST['newuser']=="Register") {       \r
+\r
+       $email = $addslashes($_POST['email']);\r
+       $login = $addslashes($_POST['login']);\r
+\r
+       $result = @mysql_query("SELECT * FROM members WHERE email='$email'",$db);\r
+       if (@mysql_num_rows($result) != 0) {\r
+               $_SESSION['errors'][] = 'Email address already in use. Try the Password Reminder.';\r
+       }\r
+\r
+       $result = @mysql_query("SELECT * FROM members WHERE login='$login'",$db);\r
+       if (@mysql_num_rows($result) != 0) {\r
+               $_SESSION['errors'][] = 'Login name already exists.';\r
+       } \r
+\r
+       if (!isset($_SESSION['errors'])) {\r
+               $realname       = $addslashes(trim($_POST['realname']));\r
+               $email      = $addslashes(trim($_POST['email']));\r
+               $login          = $addslashes(trim($_POST['login']));\r
+               $password       = $addslashes(trim($_POST['password']));\r
+\r
+\r
+               $sql = "INSERT INTO members VALUES (NULL, '$login', '$password', '$realname', '$email', NOW())";\r
+               $result = @mysql_query($sql, $this_db->db);\r
+\r
+               if (!$result) {\r
+                       $_SESSION['errors'][] = 'Database error - user not added.';\r
+               } else {\r
+                       //send email to registrant\r
+       \r
+                       $_SESSION['feedback'][] = 'Registration successful. Please login.';\r
+                       header('Location: index.php');\r
+                       exit;\r
+               }\r
+       }\r
+}\r
+\r
+require('include/basic_header.inc.php'); ?>\r
+\r
+<script type="text/javascript">\r
+<!--\r
+       function validateRegForm() {\r
+               var myform = document.forms[0];\r
+               var errs = '';\r
+\r
+               if (myform.realname.value == '') {\r
+                       errs = 'Name cannot be empty.\n';\r
+               } else {\r
+                       var realname = myform.realname.value;\r
+               }\r
+               \r
+               var at = myform.email.value.indexOf("@");\r
+               var dot = myform.email.value.lastIndexOf(".");\r
+               \r
+               if (myform.email.value == '') {\r
+                       errs += 'Email cannot be empty.\n';\r
+               } else if ( (at==-1 || dot==-1) || (dot<at) || (dot-at == 1) ) {\r
+                       errs += 'Incorrect email format.\n';\r
+               } else {\r
+                       var email = myform.email.value;\r
+               }\r
+               \r
+               if (myform.login.value == '') {\r
+                       errs += 'Login cannot be empty.\n';\r
+               } else {\r
+                       var login = myform.login.value;\r
+               }\r
+               \r
+               if (myform.password.value == '' || myform.password2.value == '' || myform.password.value != myform.password2.value) {\r
+                       errs += 'Passwords cannot be empty and must match.\n';\r
+               } else {\r
+                       var password = myform.password.value;\r
+               }               \r
+               \r
+               if (errs != '') {\r
+                       alert(errs);\r
+                       return false;\r
+               } else {\r
+                       return true;\r
+               }\r
+       }\r
+\r
+//-->\r
+</script>\r
+       \r
+       <h2>Register</h2>\r
+       <p>Create a new account with OpenCaps.</p>\r
+\r
+       <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" id="form" style="background-color:white;" onSubmit="javascript: return validateRegForm();">            \r
+               \r
+               <dl class="col-list" style="width:33%; margin-left:auto; margin-right:auto;">\r
+                       <dt><label for="realname">Name:</label></dt> \r
+                               <dd><input name="realname" type="text" id="realname" value="<?php echo $_POST['realname']; ?>" /></dd>\r
+                       <dt><label for="email">Email:</label></dt> \r
+                               <dd><input name="email" type="text" id="email" value="<?php echo $_POST['email']; ?>" /><br /><br /></dd>\r
+       \r
+                       <dt><label for="login">Login:</label></dt> \r
+                               <dd><input name="login" type="text" id="login" value="<?php echo $_POST['login']; ?>" /></dd>\r
+                       <dt><label for="pswd">Password:</label></dt> \r
+                               <dd><input name="password" type="password" id="pswd" value="<?php echo $_POST['password']; ?>" /></dd>\r
+                       <dt><label for="pswd">Password Again:</label></dt> \r
+                               <dd><input name="password2" type="password" id="pswd2" value="<?php echo $_POST['password2']; ?>" /></dd>\r
+               </dl>\r
+               <div style='text-align:right; margin-right:10px;'><input type="submit" name="newuser" value="Register" class="button" style="width:5em;" /> <input type="button" name="cancel" value="Cancel" class="button" style="width:5em;" onClick="javascript:history.back(1);" /> </div>\r
+       </form>\r
+</div>\r
+\r
+</body>\r
+</html>\r
diff --git a/mods/atutor_opencaps/opencaps/scripts/install.sh b/mods/atutor_opencaps/opencaps/scripts/install.sh
new file mode 100755 (executable)
index 0000000..d3c2e25
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# apache, php5, mysql5
+echo "============================"
+echo "==Installing Apache, PHP, and MySql=="
+echo "============================"
+sudo apt-get -y update
+sudo apt-get -y install apache2 php5 curl libcurl3 libcurl3-dev php5-curl mysql-server php5-mysql #user enters mysql password for root
+sudo /etc/init.d/apache2 restart
+
+# opencaps
+echo "============================"
+echo "==Installing OpenCaps=="
+echo "============================"
+echo "Creating database - please enter your mysql root password"
+mysqladmin create opencaps -u root -p                                  
+cd /var/www/
+sudo wget http://opencaps.atrc.utoronto.ca/releases/opencaps.tar.gz
+sudo tar -xvzf opencaps.tar.gz
+
+cd opencaps
+sudo cp install/config_template.php include/config.inc.php
+sudo chmod 777 conversion_service/imported
+sudo chmod 777 projects
+echo "Installing database tables - please enter your mysql root password"
+sudo mysql opencaps -u root -p  < install/oc_schema.sql                
+sudo /etc/init.d/mysql start
+
+# edit opencaps config
+
+# add mysql info
+echo "**** Please enter your mysql root password for the OpenCaps configuration file"
+currentstate=`stty -g`
+stty -echo
+read pass
+stty $currentstate                                                                                     
+sed -i "s/password/$pass/" include/config.inc.php
+
+# add matterhorn info
+MY_IP=`ifconfig | grep "inet addr:" | grep -v 127.0.0.1 | awk '{print $2}' | cut -d':' -f2`
+sed -i 's/?>/\$remote_systems[0][url]="http:\/\/'${MY_IP}':8080";\n?>/' include/config.inc.php
+sed -i 's/?>/\$remote_systems[0][name]="Matterhorn";\n?>/' include/config.inc.php
+
+echo "**** OpenCaps is installed and available at $MY_IP/opencaps"
diff --git a/mods/atutor_opencaps/opencaps/scripts/install_remote_only.sh b/mods/atutor_opencaps/opencaps/scripts/install_remote_only.sh
new file mode 100755 (executable)
index 0000000..72e02ba
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# apache, php5, mysql5
+echo "============================"
+echo "==Installing Apache, PHP=="
+echo "============================"
+sudo apt-get -y update
+sudo apt-get -y install apache2 php5 curl libcurl3 libcurl3-dev php5-curl
+sudo /etc/init.d/apache2 restart
+
+# opencaps
+echo "============================"
+echo "==Installing OpenCaps=="
+echo "============================"                   
+cd /var/www/
+sudo wget http://opencaps.atrc.utoronto.ca/releases/opencaps.tar.gz
+sudo tar -xvzf opencaps.tar.gz
+#sudo gzip -dc opencaps.tar.gz | tar xvzf -
+
+cd opencaps
+sudo cp install/config_template.php include/config.inc.php
+sudo chmod 777 conversion_service/imported
+sudo chmod 777 projects
+
+# disable local access in config
+sudo sed -i "s/\'DISABLE_LOCAL\',      \tfalse/\'DISABLE_LOCAL\',\ttrue/g" include/config.inc.php
+
+# add matterhorn info to config
+MY_IP=`ifconfig | grep "inet addr:" | grep -v 127.0.0.1 | awk '{print $2}' | cut -d':' -f2`
+sudo sed -i 's/?>/\$remote_systems[0][url]="http:\/\/'${MY_IP}':8080";\n?>/' include/config.inc.php
+sudo sed -i 's/?>/\$remote_systems[0][name]="Matterhorn";\n?>/' include/config.inc.php
+sudo sed -i 's/?>/\$remote_systems[0][username]="";\n?>/' include/config.inc.php
+sudo sed -i 's/?>/\$remote_systems[0][password]="";\n?>/' include/config.inc.php
+
+echo "**** OpenCaps is installed and available at $MY_IP/opencaps"
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/settings.php b/mods/atutor_opencaps/opencaps/settings.php
new file mode 100755 (executable)
index 0000000..8ef685a
--- /dev/null
@@ -0,0 +1,79 @@
+<?php 
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+define('INCLUDE_PATH', 'include/');
+require(INCLUDE_PATH.'vitals.inc.php');
+
+if (isset($_POST['submit-name'])) {
+       $this_proj->editName($_POST['name']);
+} if (isset($_POST['submit-caps'])) {
+       $this_proj->importCaptions($_FILES['caption_file']);
+}
+
+
+require(INCLUDE_PATH.'header.inc.php'); 
+
+?>
+
+<script language="javascript" type="text/javascript" src="js/settings.js"></script>
+
+<div id="content">
+
+       <h3>Project Settings</h3>
+       <p>Edit your project's settings here.</p>
+       
+       <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" id="form" enctype="multipart/form-data">
+
+               <h4>Project Name</h4>
+               <p><?php echo $this_proj->name; ?> 
+               <?php if (!isset($_SESSION['rid'])) { ?> (<a href="#" onclick="javascript:hide_all();$('#edit-name').show();">Edit</a>)</p> <?php } ?>
+                
+               <div id="edit-name">
+                       New project name: <input type="input" name="name" value="" /> <input type="submit" class='button' style='width:6em;' name="submit-name" value="Submit" />
+               </div>
+               
+               <h4>Captions</h4> 
+               <p><a href="#" onclick="javascript:hide_all();$('#edit-caps').show();">Import caption file</a></p>
+               
+               <div id="edit-caps">
+                       <p>Uploading a new caption file will delete all existing captions. Make sure to backup your project (<a href="export.php">Export</a> Json file) before doing this.</p>
+                       Caption File: <input type="file" name="caption_file" /> <input type="submit" name="submit-caps" class='button' style='width:6em;' value="Submit" />
+               </div>
+       
+               <!-- h4>Media File</h4> 
+               <p><?php if (substr($this_proj->media_loc,0, 7) == "http://") echo $this_proj->media_loc; else echo end(explode("/", $this_proj->media_loc)); ?> (<a href="#" onclick="javascript:hide_all();$('#edit-media').show();">Edit</a>)</p -->
+               
+               <div id="edit-media">
+                       <p>Coming soon.<br />
+                       Upload a new version of your media. The duration of the new media file must match that of the existing media.</p>
+                       <!--  input type="file" name="media_file" /> <input type="submit" name="submit-media" class='button' style='width:6em;' value="Submit" / -->                    
+               </div>
+                       
+               <!-- h4>Permissions</h4> 
+               
+               <p>People who can edit this project: You (<a href="#" onclick="javascript:hide_all();$('#edit-perms').show();">Edit</a>) </p>
+               
+               <div id="edit-perms">
+                       <p>Coming soon.<br />
+                       Permissions will allow for collaborative editing by letting you give other users access to your project.</p>
+                       
+                       <select name="collab" size="4" multiple="multiple">
+                       </select>
+                       <input type="submit" name="submit-perms" class='button' style='width:6em;' value="Submit" />    
+               </div -->
+               
+       
+       </form>
+</div>
+<?php require(INCLUDE_PATH.'footer.inc.php'); ?>
diff --git a/mods/atutor_opencaps/opencaps/start.php b/mods/atutor_opencaps/opencaps/start.php
new file mode 100755 (executable)
index 0000000..9f9e2db
--- /dev/null
@@ -0,0 +1,155 @@
+<?php \r
+/*\r
+ * OpenCaps\r
+ * http://opencaps.atrc.utoronto.ca\r
+ * \r
+ * Copyright 2009 Heidi Hazelton\r
+ * Adaptive Technology Resource Centre, University of Toronto\r
+ * \r
+ * Licensed under the Educational Community License (ECL), Version 2.0. \r
+ * You may not use this file except in compliance with this License.\r
+ * http://www.opensource.org/licenses/ecl2.php\r
+ * \r
+ */\r
+\r
+define('INCLUDE_PATH', 'include/');\r
+require(INCLUDE_PATH.'vitals.inc.php');\r
+\r
+unset($_SESSION['pid']);\r
+\r
+if (DISABLE_LOCAL && isset($systems[0]['url'])) {\r
+       header("Location:start_remote.php?r=0");\r
+       exit;\r
+} else if (DISABLE_LOCAL) {\r
+       $_SESSION['errors'][] = "Your administrator has disabled local captioning and no remote systems have been configured.";\r
+       include(INCLUDE_PATH.'basic_header.inc.php'); \r
+       include(INCLUDE_PATH.'footer.inc.php'); \r
+       exit;\r
+}\r
+\r
+if (isset($_POST['submit_login'])) {   \r
+       $this_user->login($_POST['login'], $_POST['password']);\r
+} \r
+\r
+//valid post\r
+if (isset($_GET['submit']) && $_GET['submit'] && empty($_POST)) {\r
+       $_SESSION['errors'][] = "Can't create project. If you uploaded a file, it may be too large.";\r
+       \r
+//file size    \r
+} else if (isset($_POST['submit_new']) && ($_FILES["media_file"]["error"] == UPLOAD_ERR_INI_SIZE || $_FILES["media_file"]["error"] == UPLOAD_ERR_FORM_SIZE)) { \r
+    $_SESSION['errors'][] = "Can't create project. If you uploaded a file, it may be too large.";\r
+    \r
+} else if (isset($_POST['submit_new'])) {\r
+       $this_proj = new project();\r
+                               \r
+       //valid URL\r
+       if (isset($_POST['media_url']) && !empty($_POST['media_url']) && $_POST['media_url']!="http://") {\r
+               $this_ext = explode(".", $_POST['media_url']);\r
+               $this_ext = end($this_ext);\r
+               \r
+               if (!file_get_contents($_POST['media_url']) || !in_array($this_ext, $supported_ext) ) {\r
+                       $_SESSION['errors'][] = "Invalid URL. Make sure the URL is correct and that the media file is a supported format.";                     \r
+               } else {\r
+                       $this_proj->createNew($addslashes($_POST['projname']), $_POST['media_url'], $_FILES['caption_file']);\r
+               }\r
+       }\r
+       \r
+       //valid file upload\r
+       else if (!empty($_FILES['media_file'])) {\r
+               $this_ext = explode(".", $_FILES['media_file']['name']);\r
+               $this_ext = end($this_ext);             \r
+       \r
+               if (!in_array($this_ext, $supported_ext) ) {\r
+                       $_SESSION['errors'][] = "Incorrect upload format.";                     \r
+               } else {                                                \r
+                       $pid = $this_proj->createNew($addslashes($_POST['projname']), $_FILES['media_file'], $_FILES['caption_file']);\r
+               }\r
+       } \r
+       \r
+       if (empty($_SESSION['errors'])) \r
+               header("Location:editor.php");\r
+}\r
+\r
+if (intval(ini_get('upload_max_filesize')) < MAX_FILE_SIZE/1048576)\r
+       $max = intval(ini_get('upload_max_filesize'));\r
+else\r
+       $max = MAX_FILE_SIZE/1048576;\r
+\r
+include(INCLUDE_PATH.'basic_header.inc.php'); \r
+\r
+unset($_SESSION['rid']);\r
+\r
+if ($_SESSION['mid'] == "99999")\r
+       unset($_SESSION['mid']);\r
+       \r
+?>\r
+\r
+<script language="JavaScript" src="js/start.js" type="text/javascript"></script>\r
+\r
+<h1 style="margin-top:10px;"><img src="images/logo.png" alt="OpenCaps - a free, online caption editor" title="OpenCaps - a free, online caption editor" style="margin-top:7px;" /></h1>\r
+<p>Start Captioning!</p>\r
+\r
+<div id="start-tabs"></div>\r
+<div id="start-container">     \r
+       <?php if (!$_SESSION['mid'] || !isset($_SESSION['valid_user']) || !$_SESSION['valid_user']) { ?>\r
+       <h2>Login</h2>\r
+\r
+       <p>To start a new captioning project or to return to an ongoing project, please login below. If you are new here, quickly <a href="register.php">register</a> with us!</p>\r
+       \r
+       <form action="start.php" method="post" id="form" >      \r
+               <dl class="col-list" style="width:33%; margin-left:auto; margin-right:auto;">\r
+                       <dt><label for="login">Login:</label></dt> \r
+                               <dd><input name="login" type="text" id="login" value="" /></dd>\r
+                       <dt><label for="pswd">Password:</label></dt> \r
+                               <dd><input name="password" type="password" id="pswd" value="" /></dd>\r
+               </dl>\r
+               <div style="text-align:right">\r
+                       <input type="submit" name="submit_login" value="Submit" class="button" style="width:5em; margin-right:10px;" />\r
+               </div>\r
+       </form>\r
+       <?php } else {?>\r
+       <div>\r
+               <h2 style="font-weight:bold">New Project</h2>\r
+               <p>Begin adding captions to a new video.</p>\r
+               \r
+               <img src="images/asterisk_yellow.png" alt="asterisk" /> <a href="#" onclick="javascript:startNew();" style="margin-top:30px;">Start New Project</a>\r
+               <form action="start.php?submit=1" method="post" id="form_new" enctype="multipart/form-data" onsubmit="javascript: return validateNewForm();">\r
+                       <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo MAX_FILE_SIZE; ?>" />\r
+               \r
+                       <div id="start-entry">\r
+                       \r
+                       <em>Project Name</em><br /> <input type='text' name='projname' style="width:200px;" value="<?php echo $this_proj->name; ?>" /><br /><br />\r
+       \r
+                       <em>Video File</em><br />\r
+                       URL: <input type="text" name="media_url" value="<?php echo isset($_POST['media_url']) ? $_POST['media_url'] : 'http://'; ?>" style="width:200px;" /><br />\r
+                       <strong>or</strong><br />\r
+                       Upload: <input type='file' name='media_file' style="width:250px;" /><br /><br />  \r
+                       <span style="font-size:smaller;">Max upload size: <?php echo $max; ?>Mb.<br /> \r
+                       Supported formats: <?php echo implode(', ', $supported_ext); ?>.</span><br /><br />\r
+                       \r
+                       <em>Caption file (optional)</em><br />\r
+                       <input type="file" name="caption_file" style="width:200px;" /><br />\r
+                       <span style="font-size:smaller;">Supported formats: QTtext, DFXP, SubRip, OpenCaps-JSON.</span>\r
+       \r
+                       <div style='text-align:right;'><input type='submit' class='button' style='width:6em;margin-top:5px;' name='submit_new' value='Submit' /></div>          \r
+                       </div>          \r
+               </form>\r
+               <br style="clear:both" />\r
+       </div>\r
+       <div>\r
+               <h2 style="font-weight:bold">Open Existing Project</h2>\r
+               <p>Continue working on a project.</p>\r
+               <img src="images/asterisk_yellow.png" alt="asterisk" />  <a href="#" onclick="javascript:startOpen();" style="margin-top:30px;">Open Project</a>\r
+       \r
+               <form action="javascript:processOpen();" method="post" id="form_open" enctype="multipart/form-data" onsubmit="javascript: return validateOpenForm();">\r
+                       <div id="open-entry">\r
+                               <div id="projects"></div>                                       \r
+                       </div>\r
+               </form>\r
+       </div>\r
+       <?php } ?>\r
+       <br style="clear:both" />\r
+</div>\r
+\r
+</body>\r
+</html>\r
diff --git a/mods/atutor_opencaps/opencaps/start_remote.php b/mods/atutor_opencaps/opencaps/start_remote.php
new file mode 100755 (executable)
index 0000000..d08140c
--- /dev/null
@@ -0,0 +1,64 @@
+<?php 
+/*
+ * OpenCaps
+ * http://opencaps.atrc.utoronto.ca
+ * 
+ * Copyright 2009 Heidi Hazelton
+ * Adaptive Technology Resource Centre, University of Toronto
+ * 
+ * Licensed under the Educational Community License (ECL), Version 2.0. 
+ * You may not use this file except in compliance with this License.
+ * http://www.opensource.org/licenses/ecl2.php
+ * 
+ */
+
+define('INCLUDE_PATH', 'include/');
+
+require(INCLUDE_PATH.'vitals.inc.php');
+
+if (!isset($_SESSION['mid']))
+       $_SESSION['mid'] = '99999'; //guest for remote
+
+
+if (!isset($systems[$_GET['r']]['url'])) {
+       
+       if (ACTIVE_SYSTEM) {
+               header("Location:start_remote.php?r=".ACTIVE_SYSTEM);
+               exit;
+       } 
+       
+       $_SESSION['errors'][] = "No remote systems have been configured. Go to the <a href='start.php'>start</a> page.";        
+       include(INCLUDE_PATH.'basic_header.inc.php'); 
+       include(INCLUDE_PATH.'footer.inc.php'); 
+       exit;
+} 
+
+if (!isset($_SESSION['mid']))
+       $_SESSION['mid'] = '99999'; //guest for remote
+
+       
+require('include/basic_header.inc.php'); 
+
+?>
+<script language="JavaScript" src="js/start_remote.js" type="text/javascript"></script>
+
+<h1 style="margin-top:10px;"><img src="images/logo.png" alt="OpenCaps - a free, online caption editor" title="OpenCaps - a free, online caption editor" style="margin-top:7px;" /></h1>
+
+<p>Start captioning! Please select a project to work on:</p>
+
+<div id="start-tabs"></div>
+<div id="start-container">     
+       <div>
+               <h2 style="font-weight:bold">Open Project</h2>
+               <p>Add captions to a remote project.</p>
+                       
+               <form action="javascript:processOpenRemote();" method="post" id="form_open" enctype="multipart/form-data" onsubmit="javascript: return validateOpenForm();">
+                       <div id="projects"></div>
+               </form>
+               
+       <br style="clear:both" /></div>
+       
+</div>
+
+</body>
+</html>
diff --git a/mods/atutor_opencaps/opencaps/styles.css b/mods/atutor_opencaps/opencaps/styles.css
new file mode 100755 (executable)
index 0000000..e8b24af
--- /dev/null
@@ -0,0 +1,459 @@
+/* capscribe styles */\r
+html,body{\r
+       height:100%;\r
+       width:100%;\r
+}\r
+\r
+body {\r
+       height:100%;\r
+       width:100%;\r
+       \r
+       font-family: Helevetica, Arial, sans-serif;\r
+       font-size: 75%;\r
+       background-color: #dce5f3;\r
+       padding:0px;\r
+       margin:0px;\r
+}\r
+img {\r
+       border:0px;\r
+}\r
+\r
+h1 {\r
+       display:inline;\r
+       margin:0px;\r
+       margin-right:20px;\r
+       padding-left:10px;\r
+}\r
+\r
+h3 {\r
+       color: #394e6f;\r
+}      \r
+\r
+h4 {\r
+       display:inline;\r
+       height:1em;\r
+}\r
+\r
+#container {\r
+       margin:0px auto 0px auto;\r
+       padding:0px;\r
+       min-width:580px;\r
+       \r
+       min-height: 97%;\r
+       position: relative;\r
+       height: auto !important;\r
+       height:97%;     \r
+       background-color: white;\r
+       width:780px;\r
+       border-left:2px solid #ccc;\r
+       border-right:2px solid #ccc;\r
+       border-bottom:2px solid #ccc;\r
+       \r
+}\r
+\r
+#header {\r
+       background-color: #eaeffb; /* #eaeffb  #e2f7f7 */\r
+       padding-bottom:5px;\r
+}\r
+\r
+#menubar {\r
+       background-color: #b5c3d9;\r
+       padding-top:3em;\r
+       padding-bottom:3px;\r
+       font-weight:bold;\r
+       font-size:110%;\r
+       /*background-image:url('images/menubar_left.png');\r
+       background-repeat: no-repeat;   */\r
+       margin-bottom:5px;\r
+}\r
+\r
+#menubar ul {\r
+       margin:0px;\r
+       display:inline; \r
+       text-align:center;\r
+}\r
+#menubar ul li {\r
+       display:inline;\r
+       list-style:none;\r
+}\r
+\r
+#menubar a:link, #menubar a:visited {\r
+       color: black;\r
+       padding-left:10px;\r
+       padding-right:10px;\r
+       text-decoration:none;\r
+}\r
+\r
+#menubar a:hover, #menubar a:focus {\r
+       padding:3px 10px 3px 10px;\r
+       width:5em;\r
+       background-color: #dce3f7;\r
+       color: black;\r
+       text-decoration:none;\r
+}\r
+#menubar .current a:link, #menubar .current a:visited {\r
+       padding:3px 10px 4px 10px;\r
+       width:5em;\r
+       background-color: white;\r
+       color: black;\r
+       text-decoration:none;\r
+}\r
+\r
+#menubar input {\r
+       padding:0px;\r
+       margin:0px;\r
+       margin-top:2px;\r
+       margin-right:3px;\r
+}\r
+\r
+/* sub menu bar */\r
+\r
+#submenubar {\r
+       padding-top:5px;\r
+       padding-bottom:3px;\r
+       font-weight:bold;\r
+       /*background-image:url('images/menubar_left.png');\r
+       background-repeat: no-repeat;   */\r
+}\r
+\r
+#submenubar ul {\r
+       margin:0px;\r
+       margin-left:-30px;\r
+       display:inline;\r
+}\r
+#submenubar ul li {\r
+       display:inline;\r
+       list-style:none;\r
+}\r
+\r
+#submenubar a:link, #submenubar a:visited {\r
+       color: black;\r
+       background-color:#dce3f7;\r
+       padding:3px 10px 4px 10px;\r
+}\r
+\r
+#submenubar a:hover, #submenubar a:focus {\r
+       padding:3px 10px 4px 10px;\r
+       width:5em;\r
+       background-color: #ccc;\r
+       color: black;\r
+}\r
+#submenubar .current a:link, #submenubar .current a:visited {\r
+       padding:3px 10px 4px 10px;\r
+       width:5em;\r
+       background-color: #2f51b3;\r
+       color: white;\r
+}\r
+\r
+#submenubar input {\r
+       padding:0px;\r
+       margin:0px;\r
+       margin-top:2px;\r
+       margin-right:3px;\r
+}\r
+\r
+#info-tab {\r
+       overflow: auto;         \r
+       border: 1px solid #ccc;\r
+       height:450px;\r
+}\r
+\r
+#layout {\r
+       border: 1px solid #ccc;\r
+       border-top: 5px solid #2f51b3;\r
+       margin-top:-1px;\r
+}\r
+\r
+h1 {\r
+       margin-top:3px;\r
+       margin-bottom:3px;\r
+       font-size:110%;\r
+}              \r
+\r
+h2 {\r
+       margin-top:3px;\r
+       margin-bottom:3px;\r
+       font-size:110%;\r
+}      \r
+\r
+dt {\r
+       font-weight:bold;\r
+}\r
+\r
+\r
+#content {\r
+       padding-left: 10px;\r
+       padding-right: 10px;    \r
+}\r
+\r
+/* left movie area */\r
+#movie-container {\r
+       margin: 5px 0px 0px 5px;\r
+       float:left;\r
+       text-align:center;\r
+       vertical-align: text-top;\r
+       width:70%;\r
+       padding-bottom:3em;\r
+}\r
+\r
+#themovie {\r
+       padding:5px;\r
+       width:340px;    \r
+}\r
+\r
+#movie_status {\r
+       width:340px;\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+       padding-top:10px;\r
+}\r
+\r
+/* movie controls */\r
+#movie-controls {\r
+       clear:both;\r
+       padding-left:5px;\r
+       padding-right:5px;\r
+       margin:5px;\r
+       width:340px;\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+\r
+}\r
+\r
+#m_timeline {\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+       margin-bottom:5px;\r
+}\r
+\r
+#last-saved {\r
+       font-size:smaller;\r
+}\r
+\r
+/* clip controls */\r
+#clip-controls {\r
+       margin-top:5px;\r
+       background-color: #eaeaea;\r
+       border:1px solid #ccc;\r
+       padding:5px;\r
+       text-align:center;\r
+       width:57%;\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+}\r
+\r
+#clip-info {\r
+       float:left;\r
+}\r
+\r
+#clip-buttons {\r
+       margin-top:1.5em;       \r
+}\r
+\r
+#clip-timeline {\r
+       margin-top:5px;\r
+       margin-left: auto; \r
+       margin-right: auto;\r
+       width:150px;\r
+}\r
+\r
+#make-clip {\r
+       float:right; \r
+       margin-top:45px; \r
+       margin-right:20px;\r
+}      \r
+\r
+/* captions */\r
+#captions {\r
+       text-align:center;\r
+       width:51%;\r
+       margin-left:auto;\r
+       margin-right:auto;      \r
+       margin-top:10px;\r
+}\r
+\r
+#captions textarea {\r
+       width:100%;\r
+       border: 1px solid #ccc;\r
+}\r
+\r
+/* right clip info area */\r
+#info-container {\r
+       margin-left:71%;\r
+       line-height:145%;\r
+}\r
+.clip {\r
+       background-color: #f4f6fc;\r
+       padding:5px;\r
+       border-bottom: 1px solid #ccc;\r
+}\r
+\r
+.clip-title {\r
+       text-decoration: underline;\r
+       font-weight:bold;\r
+       padding-bottom:10px;\r
+}\r
+\r
+.space {\r
+       background-color:#fffff8;\r
+       padding:5px;\r
+       border-bottom: 1px solid #ccc;\r
+}\r
+\r
+\r
+\r
+/* footer */\r
+#footer {\r
+       font-size: x-small;\r
+       text-align:center;\r
+\r
+       clear: both;\r
+       width:780px;\r
+       position: absolute;\r
+       bottom: 0 !important;\r
+       height:1.5em;\r
+}\r
+\r
+#duration, #current-time, #source-file, #clip-time, #clip-duration {\r
+       display:inline;\r
+}\r
+\r
+.button {\r
+       border:1px solid black;\r
+       padding-top:3px;\r
+       padding-bottom:3px;     \r
+       margin:0px;\r
+       width:3em;\r
+}\r
+\r
+\r
+\r
+/* skins sliders */\r
+\r
+.ui-slider { \r
+       width: 100%; \r
+       height: 23px; \r
+       position: relative; \r
+       background-repeat: repeat-x; \r
+       background-position: center center; \r
+}\r
+.ui-slider-handle { position: absolute; z-index: 0; height: 23px; width: 12px; top: 0px; left: 0px; background-image: url(images/slider-handle.gif);  }\r
+\r
+/*.ui-slider-handle-ghost { \r
+       position: absolute; \r
+       z-index: 1; \r
+       height: 23px; \r
+       width: 12px; \r
+       top: 0px; \r
+       left: 0px; \r
+       background-image: url(images/slider-handle.gif);  \r
+       opacity: 0.1;\r
+}*/\r
+\r
+\r
+/*.ui-slider-handle-active, .ui-slider-handle-ghost-active { border: 1px dotted black;  }\r
+.ui-slider-disabled .ui-slider-handle { opacity: 0.5; filter: alpha(opacity=50); }*/\r
+.ui-slider-range { position: absolute; background: #50A029; opacity: 0.3; filter: alpha(opacity=30); width: 100%; height: 100%; }\r
+\r
+/* Default slider backgrounds */\r
+.ui-slider, .ui-slider-1 { background-image: url(images/slider-bg-2.png); }\r
+.ui-slider-2 { background-image: url(images/slider-bg-2.png); }\r
+.ui-slider-clip { background-image: url(images/middlebar.png); }\r
+\r
+/*.ui-slider-ghost { background-image: none; }*/\r
+\r
+\r
+/* links */\r
+a:link, a:visited {\r
+       color: black;\r
+}\r
+a:hover, a:focus {\r
+       color:red;\r
+}\r
+\r
+\r
+\r
+\r
+li.choice {\r
+       height:19em;\r
+       padding:5px;\r
+       width: 12.25em;\r
+       background-color: #fffff8;\r
+       border: 1px solid #969696;\r
+       text-align:center;\r
+       float:left;\r
+       margin-right:15px;\r
+       margin-bottom:5px;\r
+       list-style:none;\r
+}\r
+\r
+.choice-info {\r
+       height:17em;\r
+}\r
+\r
+\r
+/* msgs */\r
+\r
+div.error {\r
+       width:80%;\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+       background-color: #F4E0E0;\r
+       border: 1px solid #A64040;\r
+       padding:10px;\r
+       margin:10px;\r
+}\r
+\r
+div.feedback {\r
+       width:80%;\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+       background-color: #D4ECD1;\r
+       border: 1px solid #4CA640;\r
+       padding:10px;\r
+       margin:10px;\r
+}\r
+\r
+div.notice {\r
+       width:80%;\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+       background-color: #f3edf6;\r
+       border: 1px solid #9977a8;\r
+       padding:10px;\r
+       margin:10px;\r
+}\r
+\r
+/* export */\r
+ul#export-list {\r
+       list-style: none;       \r
+}\r
+\r
+ul#export-list li {\r
+       padding-top:3px;\r
+       padding-bottom:5px;     \r
+}\r
+\r
+ul#export-list a {\r
+       font-weight:bold;\r
+}\r
+\r
+\r
+/* editor */\r
+#in-info {\r
+       float:left; \r
+       text-align:left; \r
+}\r
+\r
+#out-info {\r
+       float:right; \r
+       text-align:right;\r
+}\r
+\r
+/* settings */\r
+\r
+#edit-name, #edit-caps, #edit-media, #edit-perms {\r
+       margin-bottom: 20px;\r
+       padding:5px;\r
+       background-color: #dce5f3;\r
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/styles_ff.css b/mods/atutor_opencaps/opencaps/styles_ff.css
new file mode 100755 (executable)
index 0000000..3c65757
--- /dev/null
@@ -0,0 +1,5 @@
+/* Styles for Firefox on Windows */\r
+\r
+#make-clip {\r
+       margin-right:5px;\r
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/styles_ie.css b/mods/atutor_opencaps/opencaps/styles_ie.css
new file mode 100755 (executable)
index 0000000..4b87901
--- /dev/null
@@ -0,0 +1,34 @@
+/* Styles for IE on Windows */\r
+\r
+#start-tabs ul {       \r
+       margin-left: 0px;\r
+}\r
+\r
+#start-container form {\r
+       margin-left:-30px;\r
+}\r
+\r
+.col-list {\r
+       margin-bottom: 10px;\r
+}\r
+\r
+img {\r
+       height:auto;\r
+       width:auto;\r
+}\r
+\r
+/* editor */\r
+\r
+#make-clip {\r
+       margin-right:5px;\r
+}\r
+\r
+#in-info {\r
+       width:6em;\r
+       margin-top:-1em;\r
+}\r
+\r
+#out-info {\r
+       margin-top:-1em;        \r
+       width:6em;\r
+}
\ No newline at end of file
diff --git a/mods/atutor_opencaps/opencaps/styles_public.css b/mods/atutor_opencaps/opencaps/styles_public.css
new file mode 100755 (executable)
index 0000000..7a93afe
--- /dev/null
@@ -0,0 +1,109 @@
+/* Styles for start public pages */\r
+\r
+body {\r
+       width:50em;\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+       line-height:150%;\r
+       margin-top:5px; \r
+}\r
+\r
+#start-container {\r
+       background-color: white;\r
+       margin-top:-1px;\r
+       padding:10px;\r
+}      \r
+\r
+a:link, a:visited {\r
+       color: #143aa8;\r
+}\r
+\r
+a:hover {\r
+       text-decoration:underline;\r
+}\r
+\r
+#footer {\r
+       width:50em;\r
+       margin-left:auto;\r
+       margin-right:auto;\r
+}\r
+\r
+h1 {\r
+       margin-left:0px;\r
+       padding:0px;\r
+}\r
+h2 {\r
+       padding:0px;\r
+       margin-left:0px;\r
+       margin-bottom:10px;\r
+       margin-top:0px;\r
+}\r
+\r
+form {\r
+       padding: 10px;\r
+}\r
+\r
+ul#start {     \r
+       margin-left:-40px; \r
+       margin-bottom:20px;\r
+       list-style:none;\r
+}\r
+\r
+ul#start li {\r
+       background-color: white;\r
+       clear:both;\r
+       margin-bottom:1em;\r
+       padding:5px;\r
+}\r
+\r
+#start-tabs {\r
+       padding-top:5px;\r
+       padding-bottom:3px;\r
+       font-weight:bold;\r
+}\r
+\r
+#start-tabs ul {\r
+       margin:0px;\r
+       margin-left:-30px;\r
+       display:inline;\r
+}\r
+#start-tabs ul li {\r
+       display:inline;\r
+       list-style:none;\r
+       margin-right:5px;\r
+}\r
+\r
+#start-tabs a:link, #start-tabs a:visited {\r
+       color: black;\r
+       background-color:#efefef;\r
+       padding:3px 10px 4px 10px;\r
+}\r
+\r
+#start-tabs a:hover {\r
+       padding:3px 10px 4px 10px;\r
+       width:5em;\r
+       background-color: #ccc;\r
+       color: black;\r
+}\r
+#start-tabs .current a:link, #start-tabs .current a:visited {\r
+       padding:3px 10px 4px 10px;\r
+       width:5em;\r
+       background-color: white;\r
+}\r
+\r
+#start-tabs input {\r
+       padding:0px;\r
+       margin:0px;\r
+       margin-top:2px;\r
+       margin-right:3px;\r
+}\r
+\r
+ul.proj-list {\r
+       list-style:none;\r
+       margin:0px;\r
+       padding:0px;\r
+}      \r
+\r
+ul.proj-list li {\r
+       padding-top:2px;\r
+       padding-bottom:2px;     \r
diff --git a/mods/atutor_opencaps/player.php b/mods/atutor_opencaps/player.php
new file mode 100755 (executable)
index 0000000..209ee22
--- /dev/null
@@ -0,0 +1,144 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+define('AT_INCLUDE_PATH', '../../include/');\r
+require (AT_INCLUDE_PATH.'vitals.inc.php');\r
+\r
+//\r
+// load ATutor-OpenCaps Module Vitals \r
+include_once('include/vitals.inc.php');\r
+\r
+\r
+$mediaFile ='';\r
+$captionFile = '';\r
+$width = '320';\r
+$height = '240';\r
+\r
+if (isset($_GET['mediaFile']) && $_GET['mediaFile']!='')\r
+{\r
+       $mediaFile = $_GET['mediaFile'];\r
+       \r
+       if (isset($_GET['captionFile']) && $_GET['captionFile']!='')\r
+       {\r
+               $captionFile = $_GET['captionFile'];\r
+       }\r
+       \r
+       if (isset($_GET['width']) && $_GET['width']!='')\r
+       {\r
+               $width = $_GET['width'];\r
+       }\r
+       \r
+       if (isset($_GET['height']) && $_GET['height']!='')\r
+       {\r
+               $height = $_GET['height'];\r
+       }\r
+}\r
+\r
+?>\r
+<html>\r
+<head>\r
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">\r
+       <script type="text/javascript" src="<?php echo AT_BASE_HREF ?>mods/AtOpenCaps/flowplayer/flowplayer-3.2.2.min.js"></script>\r
+       <link rel="stylesheet" type="text/css" href="<?php echo AT_BASE_HREF ?>mods/AtOpenCaps/module.css">\r
+       <title>AT Media Player</title>\r
+</head>\r
+<body>\r
+\r
+<div id="ATOC_playerPreview" align="center" style="width: <?php echo $width ?>;height: <?php echo $height ?>;">\r
+<?php\r
+$playerEmbed = '\r
+<a id="ATmediaPlayer">\r
+       <img src="'.AT_BASE_HREF.'mods/AtOpenCaps/images/poster.jpg"\r
+       style="opacity: 1.0; " />\r
+</a>\r
+\r
+<script language="JavaScript">\r
+\r
+$f("ATmediaPlayer", "'.AT_BASE_HREF.'mods/AtOpenCaps/flowplayer/flowplayer-3.2.2.swf", \r
+{\r
+\r
+               ';\r
+       \r
+$playerEmbed .= "\r
+\r
+       clip: \r
+       {\r
+               url: '".$mediaFile."',\r
+               \r
+\r
+               // this is the Timed Text file with captions info\r
+               captionUrl: '".$captionFile."'\r
+       },\r
+       plugins:  \r
+       {\r
+\r
+               captions: {\r
+                       url: '".AT_BASE_HREF."mods/AtOpenCaps/flowplayer/flowplayer.captions-3.2.1.swf',\r
+\r
+                       // pointer to a content plugin (see below)\r
+                       captionTarget: 'content'\r
+               },\r
+\r
+               // configure a content plugin to look good for our purpose\r
+               content: {\r
+                       url:'".AT_BASE_HREF."mods/AtOpenCaps/flowplayer/flowplayer.content-3.2.0.swf',\r
+                       bottom: 25,\r
+                       width: '80%',\r
+                       height: 60,\r
+                       backgroundColor: 'transparent',\r
+                       backgroundGradient: 'low',\r
+                       //borderRadius: 1,\r
+                       border: 0,\r
+                       textDecoration: 'outline',\r
+\r
+                       style: {\r
+                           'body': {\r
+                               fontSize: '22',\r
+                               fontFamily: 'Arial',\r
+                               textAlign: 'center',\r
+                               color: '#FFFFFF'\r
+                           }\r
+                   }\r
+               }\r
+       }\r
+});\r
+\r
+</script>\r
+"; // end stript\r
+\r
+echo $playerEmbed;\r
+?>\r
+\r
+<?php\r
+\r
+?>\r
+</div>\r
+<div id="ATOC_preview_code">\r
+<h3><?php echo _AT('atoc_htmlCode'); ?>:</h3>\r
+       <form name="playerCode" id="playerCode" method="post" action="">\r
+         <textarea name="flowPlayerCode" cols="40" rows="5" id="flowPlayerCode">\r
+\r
+<script type="text/javascript" src="<?php echo AT_BASE_HREF ?>mods/AtOpenCaps/flowplayer/flowplayer-3.2.2.min.js"></script>\r
+<div align="center" style="width: <?php echo $width ?>;height: <?php echo $height ?>;">\r
+<?php\r
+echo $playerEmbed;\r
+?>\r
+</div>\r
+         </textarea>\r
+       </form>\r
+</div>\r
+\r
+</body>\r
+</html>\r
+\r
+       
\ No newline at end of file
diff --git a/mods/atutor_opencaps/service.php b/mods/atutor_opencaps/service.php
new file mode 100755 (executable)
index 0000000..31d67e5
--- /dev/null
@@ -0,0 +1,100 @@
+<?php\r
+/****************************************************************/\r
+/* Atutor-OpenCaps Module                                              \r
+/****************************************************************/\r
+/* Copyright (c) 2010                           \r
+/* Written by Antonio Gamba                                            \r
+/* Adaptive Technology Resource Centre / University of Toronto\r
+/*\r
+/* This program is free software. You can redistribute it and/or\r
+/* modify it under the terms of the GNU General Public License\r
+/* as published by the Free Software Foundation.\r
+/****************************************************************/\r
+\r
+// At vitals \r
+include_once('../../include/config.inc.php');\r
+include_once('../../include/lib/mysql_connect.inc.php');\r
+\r
+// load ATutor-OpenCaps Module Vitals \r
+include_once('include/vitals.inc.php');\r
+\r
+\r
+//echo '<br/>AT_CONTENT_DIR: '.AT_CONTENT_DIR;\r
+//echo '<br/>AT_BASE_HREF: '.AT_BASE_HREF;\r
+\r
+// check if is GET or POST requet\r
+\r
+// initialize vars\r
+$method = '';\r
+$action = '';\r
+$projectId = '';\r
+$captionData = '';\r
+\r
+if($ocAtSettings['atWebPath'] == '')\r
+{\r
+       $atWebPath_replace = str_replace('mods/AtOpenCaps/service.php','',$_SERVER['SCRIPT_NAME']);\r
+       $ocAtSettings['atWebPath'] = 'http://'.$_SERVER['HTTP_HOST'].''.$atWebPath_replace;\r
+}\r
+\r
+if (isset($_GET['action']) && $_GET['action'] !='')\r
+{\r
+       $action = $_GET['action'];\r
+       \r
+               if (isset($_GET['id']) && $_GET['id'] !='')\r
+               {\r
+               $projectId = $_GET['id'];\r
+               }\r
+} \r
+\r
+if (isset($_POST['action']) && $_POST['action'] !='')\r
+{\r
+       $action = $_POST['action'];\r
+       \r
+               if (isset($_POST['id']) && $_POST['id'] !='')\r
+               {\r
+               $projectId = $_POST['id'];\r
+               }\r
+} \r
+\r
+// Get media data and return JSon\r
+\r
+if ($action=='getMedia' && $projectId !='')\r
+{\r
+       $myProjectManager = new ATOCProjectManager();\r
+       \r
+       $activeProjectJson = $myProjectManager->_getProjecDataJson($projectId,$ocAtSettings['atWebPath']);\r
+       echo $activeProjectJson;\r
+       \r
+       // start OC Json class\r
+} else if ($action=='getMedia') {\r
+       echo "Invalid request";\r
+       \r
+} \r
+\r
+\r
+// save caption data\r
+\r
+if ($action=='putCaps' && $projectId != '' &&  isset($_POST['cc']) && $_POST['cc']!='')\r
+{\r
+       $captionData = $_POST['cc'];\r
+       \r
+       if(isset($_POST['width']))\r
+       {\r
+               $theWidth = $_POST['width'];\r
+       } else {\r
+               $theWidth = '';\r
+       }\r
+       if(isset($_POST['height']))\r
+       {\r
+               $theHeight = $_POST['height'];\r
+       } else {\r
+               $theHeight = '';\r
+       }\r
+       $myProjectManager = new ATOCProjectManager();\r
+\r
+       $saveMSG = $myProjectManager->_saveCaptionData($projectId,$captionData,$theWidth,$theHeight);\r
+\r
+       //echo $saveMSG;\r
+\r
+} \r
+?>
\ No newline at end of file
diff --git a/mods/atutor_opencaps/service_test.php b/mods/atutor_opencaps/service_test.php
new file mode 100755 (executable)
index 0000000..7a6b7bf
--- /dev/null
@@ -0,0 +1,53 @@
+<?php\r
+\r
+// include AT vitals\r
+define('AT_INCLUDE_PATH', '../../include/');\r
+require (AT_INCLUDE_PATH.'vitals.inc.php');\r
+authenticate(AT_PRIV_OPEN_CAPS);\r
+\r
+// load ATutor-OpenCaps Module Vitals \r
+include_once('include/vitals.inc.php');\r
+\r
+\r
+echo '<br/>AT_CONTENT_DIR: '.AT_CONTENT_DIR;\r
+echo '<br/>AT_BASE_HREF: '.AT_BASE_HREF;\r
+\r
+?>\r
+\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<title>Untitled Document</title>\r
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />\r
+</head>\r
+\r
+<body>\r
+<p>Test Service</p>\r
+<h1>getMedia: $_GET</h1>\r
+<p><a href="<?php echo AT_BASE_HREF; ?>/mods/AtOpenCaps/service.php?id=1&action=getMedia">/mods/AtOpenCaps/service.php?id=1&amp;action=getMedia</a></p>\r
+<p>&nbsp;</p>\r
+<h1>putCaps: $_POST</h1>\r
+<form name="form1" id="form1" method="post" action="<?php echo AT_BASE_HREF; ?>/mods/AtOpenCaps/service.php">\r
+  <p>Id: \r
+    <input name="id" type="text" id="id" value="1" />\r
+  </p>\r
+  <p> action: \r
+    <input name="action" type="text" id="action" value="putCaps" />\r
+  </p>\r
+      <p>\r
+      <strong>Width:</strong> <input name="width" id="width" value="320" type="text" size="4"/>\r
+       <strong>Height:</strong> <input name="height" id="height" value="240" type="text" size="4"/>\r
+      </p>\r
+\r
+  <p> cc: <br />\r
+    <textarea name="cc" cols="60" rows="10" id="cc">Some data so save in the caption file\r
+uno more line</textarea>\r
+  </p>\r
+  <p>\r
+    <input type="submit" name="Submit" value="Save Data" />\r
+  </p>\r
+</form>\r
+<p>&nbsp;</p>\r
+</body>\r
+</html>\r
+\r