# This patch file was generated by NetBeans IDE
# This patch can be applied using context Tools: Apply Diff Patch action on respective folder.
# It uses platform neutral UTF-8 encoding.
# Above lines and this line are ignored by the patching process.
Index: moodle/blocks/community/renderer.php
--- moodle/blocks/community/renderer.php Base (1.11)
+++ moodle/blocks/community/renderer.php Locally Modified (Based On 1.11)
@@ -30,11 +30,6 @@
  */
 class block_community_renderer extends plugin_renderer_base {
 
-    public function __construct(moodle_page $page, $target) {
-        parent::__construct($page, $target);
-        $this->page->requires->css('/lib/gallery/assets/skins/sam/gallery-lightbox-skin.css');
-    }
-
     /**
      * Display a list of courses
      * @param array $courses
@@ -49,22 +44,20 @@
         $table = new html_table();
 
 
-        $table->head = array(get_string('coursename', 'block_community'),
-
+        $table->head = array(
+            get_string('coursename', 'block_community'),
             get_string('coursedesc', 'block_community'),
              get_string('screenshots', 'block_community'),
             get_string('courselang', 'block_community'),
-            get_string('operation', 'block_community'));
-
+            get_string('operation', 'block_community')
+        );
         $table->align = array('center', 'left', 'center', 'left', 'center');
         $table->size = array('20%', '45%', '5%', '5%', '5%');
 
 
 
         if (empty($courses)) {
-            if (isset($courses)) {
                 $renderedhtml .= get_string('nocourse', 'block_community');
-            }
         } else {
 
             $table->width = '100%';
@@ -167,40 +160,21 @@
                 // add a row to the table
                 $screenshothtml = '';
                 if (!empty($course->screenshotsids)) {
-
-                    //include gallery lightbox js
-                    $this->page->requires->js('/lib/gallery/gallery-lightbox-min.js');
-
+                    $images = array();
+                    $baseurl = new moodle_url($huburl.'/local/hub/webservice/download.php', array('courseid' => $course->id, 'filetype' => HUB_SCREENSHOT_FILE_TYPE));
                     for ($i = 1; $i <= $course->screenshotsids; $i = $i + 1) {
-                        if ($i == 1) {
-                            $params = array('courseid' => $course->id,
-                                'filetype' => HUB_SCREENSHOT_FILE_TYPE, 'screenshotnumber' => $i);
-                            $imgurl = new moodle_url($huburl . "/local/hub/webservice/download.php", $params);
-                        } else {
-                            //empty image
-                            $imgurl = new moodle_url($CFG->wwwroot . "/pix/spacer.gif");
+                        $params['screenshotnumber'] = $i;
+                        $images[] = array(
+                            'thumburl' => new moodle_url($baseurl, array('screenshotnumber' => $i)),
+                            'imageurl' => new moodle_url($baseurl, array('screenshotnumber' => $i, 'imagewidth' => 'original')),
+                            'title' => $course->fullname,
+                            'alt' => $course->fullname
+                        );
                         }
-                        $ascreenshothtml = html_writer::empty_tag('img', array('src' => $imgurl, 'alt' => $course->fullname));
-                        $originalparams = array('courseid' => $course->id,
-                            'filetype' => HUB_SCREENSHOT_FILE_TYPE, 'screenshotnumber' => $i, 'imagewidth' => 'original');
-                        $originalimgurl = new moodle_url($huburl . "/local/hub/webservice/download.php", $originalparams);
-                        $screenshothtml .= html_writer::tag('a', $ascreenshothtml,
-                                        array('rel' => 'lightbox[' . $course->shortname . ']', 'title' => $course->fullname,
-                                            'href' => $originalimgurl));
+                    $screenshothtml = $this->output->render(new image_gallery($images, $course->shortname));
                     }
-
-                    // run the JS
-                    $js = "Y.use(\"gallery-lightbox\", function (Y) { Y.Lightbox.init(); });";
-                    $this->page->requires->js_init_code($js, true);
+                $table->data[] = array($coursenamehtml, $deschtml, $screenshothtml, $language, $addbuttonhtml);
                 }
-
-                $cells = array($coursenamehtml, $deschtml, $screenshothtml, $language, $addbuttonhtml);
-
-
-                $row = new html_table_row($cells);
-
-                $table->data[] = $row;
-            }
             $renderedhtml .= html_writer::table($table);
         }
         return $renderedhtml;
Index: moodle/blocks/community/styles.css
--- moodle/blocks/community/styles.css Base (1.2)
+++ moodle/blocks/community/styles.css Locally Modified (Based On 1.2)
@@ -24,3 +24,6 @@
 #page-blocks-community-communitycourse .additionaldesc {font-size: 80%; color: #aa6666;}
 #page-blocks-community-communitycourse .additionaladmindesc {font-size: 80%; color: #6666ff;}
 #page-blocks-community-communitycourse .blockdescription {font-size: 80%; color: #555555;}
+
+.path-blocks-community .image_gallery a.imagelink {display:none;}
+.path-blocks-community .image_gallery a#imagelink1 {display:inline;}
\ No newline at end of file
Index: moodle/lib/gallery/assets/gallery-lightbox-core.css
--- moodle/lib/gallery/assets/gallery-lightbox-core.css Base (1.1)
+++ moodle/lib/gallery/assets/gallery-lightbox-core.css Locally Deleted
@@ -1 +0,0 @@
-/* NEED TO SEPARATE SKINS APPROPRIATELY. */
Index: moodle/lib/gallery/assets/skins/sam/closelabel.gif
MIME: application/octet-stream; encoding: Base64; length: -1

Index: moodle/lib/gallery/assets/skins/sam/gallery-lightbox-skin.css
--- moodle/lib/gallery/assets/skins/sam/gallery-lightbox-skin.css Base (1.2)
+++ moodle/lib/gallery/assets/skins/sam/gallery-lightbox-skin.css Locally Deleted
@@ -1,83 +0,0 @@
-#lightbox {
-	position: absolute;
-	left: 0;
-	width: 100%;
-	z-index: 100;
-	text-align: center;
-	line-height: 0;
-}
-#lightbox img { width: auto; height: auto; }
-#lightbox a img { border: none; }
-
-#outerImageContainer {
-	position: relative;
-	background-color: #fff;
-	width: 250px;
-	height: 250px;
-	margin: 0 auto;
-}
-#imageContainer { padding: 10px; }
-
-#loading {
-	position: absolute;
-	top: 40%;
-	left: 0%;
-	height: 25%;
-	background: url(loading.gif) no-repeat top center;
-	width: 100%;
-	text-align: center;
-	line-height: 0;
-}
-#hoverNav {
-	position: absolute;
-	top: 0;
-	left: 0;
-	height: 100%;
-	width: 100%;
-	z-index: 10;
-}
-#imageContainer > #hoverNav { left: 0; }
-#hoverNav a { outline: none; }
-
-#prevLink, #nextLink {
-	width: 49%;
-	height: 100%;
-	background-image: url(data:image/gif;base64,AAAA);
-	/* Trick IE into showing hover */ display: block;
-}
-#prevLink { left: 0; float: left; }
-#nextLink { right: 0; float: right; }
-#prevLink:hover, #prevLink:visited:hover { background: url(prevlabel.gif) left 15% no-repeat; }
-#nextLink:hover, #nextLink:visited:hover { background: url(nextlabel.gif) right 15% no-repeat; }
-
-#imageDataContainer {
-	font: 10px Verdana, Helvetica, sans-serif;
-	background-color: #fff;
-	margin: 0 auto;
-	line-height: 1.4em;
-	overflow: auto;
-	width: 100%;
-}
-
-#imageData { padding:0 10px; color: #666; }
-#imageData #imageDetails { width: 70%; float: left; text-align: left; }	
-#imageData #caption { font-weight: bold; }
-#imageData #numberDisplay { display: block; clear: left; padding-bottom: 1.0em; }			
-#imageData #bottomNavClose {
-	width: 66px;
-	height:22px;
-	background: url(closelabel.gif) no-repeat;
-	float: right;
-	padding-bottom: 0.7em;
-	outline: none;
-}
-
-#overlay {
-	position: absolute;
-	top: 0;
-	left: 0;
-	z-index: 90;
-	width: 100%;
-	height: 500px;
-	background-color: #000;
-}
Index: moodle/lib/gallery/assets/skins/sam/gallery-lightbox.css
--- moodle/lib/gallery/assets/skins/sam/gallery-lightbox.css Base (1.1)
+++ moodle/lib/gallery/assets/skins/sam/gallery-lightbox.css Locally Deleted
@@ -1 +0,0 @@
-#lightbox{position:absolute;left:0;width:100%;z-index:100;text-align:center;line-height:0;}#lightbox img{width:auto;height:auto;}#lightbox a img{border:none;}#outerImageContainer{position:relative;background-color:#fff;width:250px;height:250px;margin:0 auto;}#imageContainer{padding:10px;}#loading{position:absolute;top:40%;left:0;height:25%;background:url(loading.gif) no-repeat top center;width:100%;text-align:center;line-height:0;}#hoverNav{position:absolute;top:0;left:0;height:100%;width:100%;z-index:10;}#imageContainer>#hoverNav{left:0;}#hoverNav a{outline:none;}#prevLink,#nextLink{width:49%;height:100%;background-image:url(data:image/gif;base64,AAAA);display:block;}#prevLink{left:0;float:left;}#nextLink{right:0;float:right;}#prevLink:hover,#prevLink:visited:hover{background:url(prevlabel.gif) left 15% no-repeat;}#nextLink:hover,#nextLink:visited:hover{background:url(nextlabel.gif) right 15% no-repeat;}#imageDataContainer{font:10px Verdana,Helvetica,sans-serif;background-color:#fff;margin:0 auto;line-height:1.4em;overflow:auto;width:100%;}#imageData{padding:0 10px;color:#666;}#imageData #imageDetails{width:70%;float:left;text-align:left;}#imageData #caption{font-weight:bold;}#imageData #numberDisplay{display:block;clear:left;padding-bottom:1.0em;}#imageData #bottomNavClose{width:66px;height:22px;background:url(closelabel.gif) no-repeat;float:right;padding-bottom:.7em;outline:none;}#overlay{position:absolute;top:0;left:0;z-index:90;width:100%;height:500px;background-color:#000;}
Index: moodle/lib/gallery/assets/skins/sam/loading.gif
MIME: application/octet-stream; encoding: Base64; length: -1

Index: moodle/lib/gallery/assets/skins/sam/nextlabel.gif
MIME: application/octet-stream; encoding: Base64; length: -1

Index: moodle/lib/gallery/assets/skins/sam/prevlabel.gif
MIME: application/octet-stream; encoding: Base64; length: -1

Index: moodle/lib/gallery/gallery-lightbox-debug.js
--- moodle/lib/gallery/gallery-lightbox-debug.js Base (1.1)
+++ moodle/lib/gallery/gallery-lightbox-debug.js Locally Deleted
@@ -1,733 +0,0 @@
-YUI.add('gallery-lightbox', function(Y) {
-
-	/**
-	 * Inspired by the original Lightbox, this is a port to YUI.
-	 * See Lokesh Dhakar's original at http://www.huddletogether.com/projects/lightbox2/.
-	 * Currently supports everything that module supports with plans to integrate
-	 * additional functionality (i.e. non-images, slideshow mode, etc.) coming soon.
-	 * 
-	 * @module gallery-lightbox
-	 */
-	
-	var L = Y.Lang,
-		Node = Y.Node,
-		
-		PX = "px",
-		
-		CLICK = "click",
-		
-		ANIM = "anim",
-		ACTIVE_IMAGE = "activeImage",
-		IMAGE_ARRAY = "imageArray",
-		OVERLAY_OPACITY = "overlayOpacity",
-		OVERLAY_DURATION = "overlayDuration",
-		
-		LIGHTBOX = "lightbox",
-		OVERLAY = "overlay",
-		PREV_LINK = "prevLink",
-		NEXT_LINK = "nextLink",
-		HOVER_NAV = "hoverNav",
-	
-		// global lightbox instance
-		lightboxInstance = null;
-	
-	/**** BEGIN EXTENDING THE NODE CLASS ****/
-	
-	// Add a few helper methods to the Node class that hopefully will be added
-	// in a future release of the Node class.  They simplify showing/hiding a given node
-	// by manipulating its "display" style.
-	
-	Y.mix(
-		Node.prototype, {
-			/**
-		     * Display a node.
-		     *
-		     * @method show
-		     * @chainable
-		     */
-			show: function () {
-				this.setStyle("display", "");
-				return this;
-			},
-			
-			/**
-		     * Hide a node.
-		     *
-		     * @method hide
-		     * @chainable
-		     */
-			hide: function () {
-				this.setStyle("display", "none");
-				return this;
-			},
-			
-			/**
-		     * Check is a node is being shown. Specifically not called "visible"
-		     * so as not to confuse it with the visibility property.
-		     *
-		     * @method displayed
-		     * @return boolean
-		     */
-			displayed: function() {
-				return this.getStyle("display") != "none";
-			},
-			
-			/**
-		     * Toggle the display of an element.
-		     *
-		     * @method toggle
-		     * @chainable
-		     */
-			toggle: function() {
-				this[this.displayed() ? "hide" : "show"]();
-				return this;
-			}
-		}
-	);
-
-	/**** END EXTENDING THE NODE CLASS ****/
-
-	/**
-	 * The Lightbox class provides the functionality for displaying
-	 * images in a panel above an overlay.  It automatically binds to
-	 * all anchor tags determined by the "selector" attribute.  It supports
-	 * grouping images together to produce a slideshow like effect.
-	 *
-	 * @class Lightbox
-	 * @constructor
-	 * @extends Base
-	 * @uses Node
-	 * @uses Anim
-	 *
-	 * @param config {Object} object with configuration property name/value pairs
-	 */
-	var LB = function (config) {
-		LB.superclass.constructor.apply(this, arguments);
-	};
-	
-	/**
-     * The identity of the widget.
-     *
-     * @property Lightbox.NAME
-     * @type String
-     * @static
-     */
-	LB.NAME = LIGHTBOX;
-	
-	/**
-     * Static property used to define the default attribute configuration of
-     * the Widget.
-     *
-     * @property Lightbox.ATTRS
-     * @type Object
-     * @protected
-     * @static
-     */
-	LB.ATTRS = {
-		/**
-         * The selector to determine which anchors should be bound to the Lightbox
-         * instance.  If an anchor element is bound to Lightbox, it's content will
-         * be displayed in a modal panel rather than on a separate page.
-         *
-         * @attribute selector
-         * @type String
-         * @default &quot;a[rel^=lightbox]&quot;
-         */
-		selector: {
-			value: "a[rel^=lightbox]",
-			validator: L.isString
-		},
-		
-		/**
-         * The width of the border surrounding the displayed content.  This is used during
-         * resize operations.
-         *
-         * @attribute borderWidth
-         * @type Number
-         * @default 10
-         */
-		borderWidth: {
-			value: 10,
-			validator: L.isNumber
-		},
-		
-		/**
-         * The amount of time (in seconds) for the overlay to take to appear when the
-         * Lightbox is displayed.
-         *
-         * @attribute overlayDuration
-         * @type Number
-         * @default 0.2
-         */
-		overlayDuration: {
-			value: 0.2,
-			validator: L.isNumber
-		},
-		
-		/**
-         * The opacity of the overlay element once it is displayed.  This value is used
-         * during animation so that the overlay appears to be eased in.
-         *
-         * @attribute overlayOpacity
-         * @type Number
-         * @default 0.8
-         */
-		overlayOpacity: {
-			value: 0.8,
-			validator: L.isNumber
-		},
-		
-		/**
-         * The amount of time (in seconds) each reisze animation should take.  This is used
-         * specifically during Lightbox height and width resize transformations.
-         *
-         * @attribute resizeDuration
-         * @type Number
-         * @default 0.5
-         */
-		resizeDuration: {
-			value: 0.5,
-			validator: L.isNumber
-		},
-		
-		/**
-         * Whether or the Lighbox module should use animation when displaying, changing images,
-         * and hiding.  If set to false, the values of attributes that control animation settings
-         * are ignored.
-         *
-         * @attribute anim
-         * @type boolean
-         * @default !L.isUndefined(Y.Anim)
-         */
-		anim: {
-			value: !L.isUndefined(Y.Anim),
-			validator: L.isBoolean
-		},
-		
-		/**
-         * A managed array of images that Lightbox can currently cycle through. The size of this array
-         * is defined by the number of images in a particular image group.  This array determines
-         * whether or not there are next and previous options. It's initialized when an image
-         * is clicked on.
-         *
-         * @attribute imageArray
-         * @type Array
-         */
-		imageArray: {
-			validator: L.isArray
-		},
-		
-		/**
-         * The index of the currently displayed image in the "imageArray."
-         *
-         * @attribute activeImage
-         * @type Number
-         */
-		activeImage: {
-			validator: L.isNumber
-		},
-		
-		/**
-         * Set of strings to be used when displaying content.  These can be customized
-         * (i.e. for internationalization) if necessary.
-         *
-         * @attribute strings
-         * @type Object
-         */
-		strings: {
-			value : {
-				labelImage: "Image",
-				labelOf: "of"
-			}
-		}
-	};
-	
-	Y.extend(LB, Y.Base, {
-		/**
-	     * Construction logic executed during Lightbox instantiation. This
-	     * builds and inserts the markup necessary for the Lightbox to function
-	     * as well as binds all of the elements to the necessary events to make
-	     * the Lightbox functional.
-	     *
-	     * @method initializer
-	     * @param config (Object) set of configuration name/value pairs
-	     * @protected
-	     */
-		initializer: function (config) {
-			// Code inserts html at the bottom of the page that looks similar to this:
-	        //
-	        //  <div id="overlay"></div>
-	        //  <div id="lightbox">
-	        //      <div id="outerImageContainer">
-	        //          <div id="imageContainer">
-	        //              <img id="lightboxImage">
-	        //              <div style="" id="hoverNav">
-	        //                  <a href="#" id="prevLink"></a>
-	        //                  <a href="#" id="nextLink"></a>
-	        //              </div>
-	        //              <div id="loading"></div>
-	        //          </div>
-	        //      </div>
-	        //      <div id="imageDataContainer">
-	        //          <div id="imageData">
-	        //              <div id="imageDetails">
-	        //                  <span id="caption"></span>
-	        //                  <span id="numberDisplay"></span>
-	        //              </div>
-	        //              <div id="bottomNav">
-	        //                  <a href="#" id="bottomNavClose"></a>
-	        //              </div>
-	        //          </div>
-	        //      </div>
-	        //  </div>
-
-	        var objBody = Y.one(document.body),
-				create = Node.create;
-
-			objBody.append(create('<div id="overlay"></div>'));
-		
-	        objBody.append(create('<div id="lightbox"></div>')
-				.append(create('<div id="outerImageContainer"></div>')
-					.append(create('<div id="imageContainer"></div>')
-						.append(create('<img id="lightboxImage" />'))
-						.append(create('<div id="hoverNav"></div>')
-							.append(create('<a id="prevLink" href="#"></a>'))
-							.append(create('<a id="nextLink" href="#"></a>'))
-						)
-						.append(create('<div id="loading"></div>'))
-					)
-				)
-				.append(create('<div id="imageDataContainer"></div>')
-					.append(create('<div id="imageData"></div>')
-						.append(create('<div id="imageDetails"></div>')
-							.append(create('<span id="caption"></span>'))
-							.append(create('<span id="numberDisplay"></span>'))
-						)
-						.append(create('<div id="bottomNav"></div>')
-							.append(create('<a id="bottomNavClose" href="#"></a>'))
-						)
-					)
-				)
-			);
-			
-			this._bindStartListener();
-			
-			Y.one("#overlay").hide().on(CLICK, function () { this.end(); }, this);
-			Y.one("#lightbox").hide().on(CLICK, function (evt) {
-				if (evt.currentTarget.get("id") === LIGHTBOX) {
-					this.end();
-				}
-			}, this);
-			
-			var size = (this.get(ANIM) ? 250 : 1) + PX;
-			
-			Y.one("#outerImageContainer").setStyles({ width: size, height: size });
-			Y.one("#prevLink").on(CLICK, function (evt) { evt.halt(); this._changeImage(this.get(ACTIVE_IMAGE) - 1); }, this);
-			Y.one("#nextLink").on(CLICK, function (evt) { evt.halt(); this._changeImage(this.get(ACTIVE_IMAGE) + 1); }, this);
-			Y.one("#bottomNavClose").on(CLICK, function (evt) { evt.halt(); this.end(); }, this);
-			
-			L.later(0, this, function () {
-				var ids = "overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading " + 
-                	"imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose";
-            	
-				Y.Array.each(ids.split(" "), function (element, index, array) {
-					this.addAttr(element, { value: Y.one("#" + element) });
-				}, this);
-			});
-		},
-		
-		/**
-	     * Display overlay and Lightbox.  If image is part of a set, it
-	     * adds those images to an array so that a user can navigate between them.
-	     *
-	     * @method start
-	     * @param selectedLink { Y.Node } the node whose content should be displayed
-	     * @protected
-	     */
-		start: function (selectedLink) {
-			Y.all("select, object, embed").each(function() {
-				this.setStyle("visibility", "hidden");
-			});
-			
-			// Stretch overlap to fill page and fade in
-			var overlay = this.get(OVERLAY).setStyles({ height: Y.DOM.docHeight() + PX, width: Y.DOM.docWidth() + PX }).show();
-			if (this.get(ANIM)) {
-				var anim = new Y.Anim({
-					node: overlay,
-					from: { opacity: 0 },
-					to: { opacity: this.get(OVERLAY_OPACITY) },
-					duration: this.get(OVERLAY_DURATION)
-				});
-				anim.run();
-			} else {
-				overlay.setStyle("opacity", this.get(OVERLAY_OPACITY));
-			}
-			
-			var imageArray = [],
-				imageNum = 0;
-			
-			if (selectedLink.get("rel") === LIGHTBOX) {
-				// If image is NOT part of a set, add single image to imageArray
-				imageArray.push([selectedLink.get("href"), selectedLink.get("title")]);
-			} else {
-				// If image is part of a set...
-				Y.all(selectedLink.get("tagName") + '[href][rel="' + selectedLink.get("rel") + '"]').each(function () {
-					imageArray.push([this.get("href"), this.get("title")]);
-				});
-				
-				while (imageArray[imageNum][0] !== selectedLink.get("href")) { imageNum++; }
-			}
-			
-			this.set(IMAGE_ARRAY, imageArray);
-			
-			var lightboxTop = Y.DOM.docScrollY() + (Y.DOM.winHeight() / 10),
-				lightboxLeft = Y.DOM.docScrollX();
-			this.get(LIGHTBOX).setStyles({ display: "", top: lightboxTop + PX, left: lightboxLeft + PX });
-			
-			this._changeImage(imageNum);
-		},
-		
-		/**
-	     * Hide the overlay and Lightbox and unbind any event listeners.
-	     *
-	     * @method end
-	     * @protected
-	     */
-		end: function () {
-			this._disableKeyboardNav();
-			this.get(LIGHTBOX).hide();
-			
-			var overlay = this.get(OVERLAY);
-			
-			if (this.get(ANIM)) {
-				var anim = new Y.Anim({
-					node: overlay,
-					from: { opacity: this.get(OVERLAY_OPACITY) },
-					to: { opacity: 0 },
-					duration: this.get(OVERLAY_DURATION)
-				});
-				anim.on("end", function () { overlay.hide(); });
-				anim.run();
-			} else {
-				overlay.setStyles({ opacity: 0 }).hide();
-			}
-			
-			Y.all("select, object, embed").each(function() {
-				this.setStyle("visibility", "visible");
-			});
-		},
-		
-		/**
-	     * Helper method responsible for binding listener to the page to process
-	     * lightbox anchors and images.
-	     *
-	     * @method _bindStartListener
-	     * @private
-	     */
-		_bindStartListener: function () {
-			Y.delegate(CLICK, Y.bind(function (evt) {
-				evt.halt();
-				this.start(evt.currentTarget);
-			}, this), document.body, this.get("selector"));
-		},
-		
-		/**
-	     * Display the selected index by first showing a loading screen, preloading it
-	     * and displaying it once it has been loaded.
-	     *
-	     * @method _changeImage
-	     * @param imageNum { Number } the index of the image to be displayed
-	     * @private
-	     */
-		_changeImage: function (imageNum) {
-			this.set(ACTIVE_IMAGE, imageNum);
-			
-			// Hide elements during transition
-			if (this.get(ANIM)) {
-				this.get("loading").show();
-			}
-			this.get("lightboxImage").hide();
-			this.get(HOVER_NAV).hide();
-			this.get(PREV_LINK).hide();
-			this.get(NEXT_LINK).hide();
-			
-			// Hack: Opera9 doesn't support something in scriptaculous opacity and appear fx
-			// TODO: Do I need this since we are using YUI? Is this a scriptaculous/Opera
-			// bug, or just Opera bug?
-			this.get("imageDataContainer").setStyle("opacity", 0.0001);
-			this.get("numberDisplay").hide();
-			
-			var imagePreloader = new Image();
-			
-			// Once image is preloaded, resize image container
-			imagePreloader.onload = Y.bind(function () {
-				this.get("lightboxImage").set("src", this.get(IMAGE_ARRAY)[imageNum][0]);
-				this._resizeImageContainer(imagePreloader.width, imagePreloader.height);
-			}, this);
-			imagePreloader.src = this.get(IMAGE_ARRAY)[imageNum][0];
-		},
-		
-		/**
-	     * Resize the image container so it is large enough to display the entire image.
-	     * Once this is complete it will delegate to another method to actually display the image.
-	     *
-	     * @method _resizeImageContainer
-	     * @param imgWidth { Number } image width
-	     * @param imgWidth { Number } image height
-	     * @private
-	     */
-		_resizeImageContainer: function (imgWidth, imgHeight) {
-			// Get current width and height
-			var outerImageContainer = this.get("outerImageContainer"),
-				widthCurrent = outerImageContainer.get("offsetWidth"),
-				heightCurrent = outerImageContainer.get("offsetHeight"),
-			
-			// Get new width and height
-				widthNew = imgWidth + this.get("borderWidth") * 2,
-				heightNew = imgHeight + this.get("borderWidth") * 2,
-				
-			// calculate size difference between new and old image
-				wDiff = widthCurrent - widthNew,
-				hDiff = heightCurrent - heightNew,
-				
-				afterResize = Y.bind(function () {
-					this.get(PREV_LINK).setStyles({ height: imgHeight + PX });
-					this.get(NEXT_LINK).setStyles({ height: imgHeight + PX });
-					this.get("imageDataContainer").setStyles({ width: widthNew + PX });
-					
-					this._showImage();
-				}, this);
-			
-			if (wDiff !== 0 || hDiff !== 0) {
-				if (this.get(ANIM)) {
-					var resizeDuration = this.get("resizeDuration"),
-					
-					anim = new Y.Anim({
-						node: outerImageContainer,
-						from: { width: widthCurrent + PX },
-						to: { width: widthNew + PX },
-						duration: resizeDuration
-					}),
-					
-					onEnd = function () {
-						anim.getEvent("end").detach(onEnd);
-						this.setAttrs({
-							from: { height: heightCurrent + PX },
-							to: { height: heightNew + PX },
-							duration: resizeDuration
-						});
-						this.on("end", afterResize);
-						this.run();
-					};
-					
-					anim.on("end", onEnd);
-					
-					anim.run();
-				} else {
-					outerImageContainer.setStyles({ width: widthNew + PX, height: heightNew + PX});
-					L.later(0, this, afterResize);
-				}
-			} else {
-				// If new and old image are the same size, and no scaling is necessary,
-				// do a quick pause to prevent image flicker.
-				L.later(100, this, afterResize);
-			}
-		},
-		
-		/**
-	     * Display the currently loaded image and then try to preload any neighboring images.
-	     *
-	     * @method _showImage
-	     * @private
-	     */
-		_showImage: function () {
-			this.get("loading").hide();
-			
-			var lightBoxImage = this.get("lightboxImage");
-			
-			if (this.get(ANIM)) {
-				
-				var startOpacity = lightBoxImage.getStyle("display") === "none" ? 0 : lightBoxImage.getStyle("opacity") || 0,
-					anim = new Y.Anim({
-						node: lightBoxImage,
-						from: { opacity: startOpacity },
-						to: { opacity: 1 }
-					});
-	
-				anim.on("end", this._updateDetails, this);
-		
-				lightBoxImage.setStyle("opacity", startOpacity).show();
-				anim.run();
-			} else {
-				lightBoxImage.setStyle("opacity", 1).show();
-				this._updateDetails();
-			}
-			
-			this._preloadNeighborImages();
-		},
-		
-		/**
-	     * Use the title of the image as a caption and display information
-	     * about the current image and it's location in an image set (if applicable).
-	     *
-	     * @method _updateDetails
-	     * @private
-	     */
-		_updateDetails: function () {
-			
-			var imageArray = this.get(IMAGE_ARRAY),
-				activeImage = this.get(ACTIVE_IMAGE),
-				caption = imageArray[activeImage][1];
-			
-			// If caption is not null
-			if (caption !== "") {
-				this.get("caption").setContent(caption).show();
-			}
-			
-			// If image is part of a set display "Image x of x"
-			if (imageArray.length > 1) {
-				this.get("numberDisplay").setContent(this.get("strings.labelImage") + " " + (activeImage + 1) + " " + this.get("strings.labelOf") + "  " + imageArray.length).show();
-			}
-			
-			var imageDataContainer = this.get("imageDataContainer");
-			
-			if (this.get(ANIM)) {
-				
-				var startOpacity = imageDataContainer.getStyle("display") === "none" ? 0 : imageDataContainer.getStyle("opacity") || 0,
-					anim = new Y.Anim({
-						node: imageDataContainer,
-						from: { opacity: startOpacity },
-						to: { opacity: 1 },
-						duration: this.get("resizeDuration")
-					});
-		
-				anim.on("end", function () {
-					// Update overlay size and update nav
-					this.get(OVERLAY).setStyle("height", Y.DOM.docHeight() + PX);
-					this._updateNav();
-				}, this);
-		
-				imageDataContainer.setStyle("opacity", startOpacity).show();
-				anim.run();
-			} else {
-				
-				imageDataContainer.setStyle("opacity", 1).show();
-				this.get(OVERLAY).setStyle("height", Y.DOM.docHeight() + PX);
-				this._updateNav();
-			}
-		},
-		
-		/**
-	     * Update the navigation elements to display forward and/or backward
-	     * links if they're appropriate.
-	     *
-	     * @method _updateNav
-	     * @private
-	     */
-		_updateNav: function () {
-			var activeImage = this.get(ACTIVE_IMAGE);
-			
-			this.get(HOVER_NAV).show();
-			
-			// If not first image in set, display previous image button
-			if (activeImage > 0) {
-				this.get(PREV_LINK).show();
-			}
-			
-			// If not first image in set, display previous image button
-			if (activeImage < (this.get(IMAGE_ARRAY).length - 1)) {
-				this.get(NEXT_LINK).show();
-			}
-			
-			this._enableKeyboardNav();
-		},
-		
-		/**
-	     * Enable keyboard shortcuts for closing Lightbox or switching images.
-	     *
-	     * @method _enableKeyboardNav
-	     * @private
-	     */
-		_enableKeyboardNav: function () {
-			Y.get(document.body).on("keydown", this._keyboardAction, this);
-		},
-		
-		/**
-	     * Disable keyboard shortcuts for closing Lightbox or switching images.
-	     *
-	     * @method _disableKeyboardNav
-	     * @private
-	     */
-		_disableKeyboardNav: function () {
-			Y.get(document.body).unsubscribe("keydown", this._keyboardAction);
-		},
-		
-		/**
-	     * Handle key strokes to allow for users to close Lightbox or switch images.
-	     *
-	     * @method _keyboardAction
-	     * @private
-	     */
-		_keyboardAction: function (evt) {
-			var keyCode = evt.keyCode,
-				escapeKey = 27,
-				key = String.fromCharCode(keyCode).toLowerCase();
-			
-			if (key.match(/x|o|c/) || (keyCode === escapeKey)) { // close lightbox
-				this.end();
-			} else if ((key === 'p') || (keyCode === 37)) { // Display the previous image
-				if (this.get(ACTIVE_IMAGE) !== 0) {
-					this._disableKeyboardNav();
-					this._changeImage(this.get(ACTIVE_IMAGE) - 1);
-				}
-			} else if ((key === 'n') || (keyCode === 39)) { // Display the next image
-				if (this.get(ACTIVE_IMAGE) !== (this.get(IMAGE_ARRAY).length - 1)) {
-					this._disableKeyboardNav();
-					this._changeImage(this.get(ACTIVE_IMAGE) + 1);
-				}
-			}
-		},
-		
-		/**
-	     * Preload images that are adjacent to the current image, if they exist,
-	     * to reduce waiting time.
-	     *
-	     * @method _preloadNeighborImages
-	     * @private
-	     */
-		_preloadNeighborImages: function () {
-			var activeImage = this.get(ACTIVE_IMAGE),
-				imageArray = this.get(IMAGE_ARRAY),
-				preloadNextImage, preloadPrevImage;
-			
-			if (imageArray.length > activeImage + 1) {
-				preloadNextImage = new Image();
-				preloadNextImage.src = imageArray[activeImage + 1][0];
-			}
-			
-			if (activeImage > 0) {
-				preloadPrevImage = new Image();
-				preloadPrevImage.src = imageArray[activeImage - 1][0];
-			}
-		}
-	});
-	
-	Y.Lightbox = {
-		/**
-		 * This method returns the single, global LightBox instance.  Upon creation,
-		 * the Lightbox instance attaches itself to the page and is ready to be used.
-		 * 
-		 * @method init
-		 * @return { Lightbox } global instance
-		 * @static
-		 */
-		init: function(config) {
-			if (lightboxInstance === null) {
-				lightboxInstance = new LB(config);
-			}
-			return lightboxInstance;
-		}
-	};
-
-
-}, '@VERSION@' ,{requires:['base','node','anim']});
Index: moodle/lib/gallery/gallery-lightbox-min.js
--- moodle/lib/gallery/gallery-lightbox-min.js Base (1.1)
+++ moodle/lib/gallery/gallery-lightbox-min.js Locally Deleted
@@ -1,2 +0,0 @@
-YUI.add("gallery-lightbox",function(B){var N=B.Lang,J=B.Node,F="px",K="click",E="anim",D="activeImage",P="imageArray",O="overlayOpacity",H="overlayDuration",G="lightbox",Q="overlay",R="prevLink",A="nextLink",I="hoverNav",C=null;B.mix(J.prototype,{show:function(){this.setStyle("display","");return this;},hide:function(){this.setStyle("display","none");return this;},displayed:function(){return this.getStyle("display")!="none";},toggle:function(){this[this.displayed()?"hide":"show"]();return this;}});var M=function(L){M.superclass.constructor.apply(this,arguments);};M.NAME=G;M.ATTRS={selector:{value:"a[rel^=lightbox]",validator:N.isString},borderWidth:{value:10,validator:N.isNumber},overlayDuration:{value:0.2,validator:N.isNumber},overlayOpacity:{value:0.8,validator:N.isNumber},resizeDuration:{value:0.5,validator:N.isNumber},anim:{value:!N.isUndefined(B.Anim),validator:N.isBoolean},imageArray:{validator:N.isArray},activeImage:{validator:N.isNumber},strings:{value:{labelImage:"Image",labelOf:"of"}}};B.extend(M,B.Base,{initializer:function(L){var U=B.one(document.body),T=J.create;U.append(T('<div id="overlay"></div>'));U.append(T('<div id="lightbox"></div>').append(T('<div id="outerImageContainer"></div>').append(T('<div id="imageContainer"></div>').append(T('<img id="lightboxImage" />')).append(T('<div id="hoverNav"></div>').append(T('<a id="prevLink" href="#"></a>')).append(T('<a id="nextLink" href="#"></a>'))).append(T('<div id="loading"></div>')))).append(T('<div id="imageDataContainer"></div>').append(T('<div id="imageData"></div>').append(T('<div id="imageDetails"></div>').append(T('<span id="caption"></span>')).append(T('<span id="numberDisplay"></span>'))).append(T('<div id="bottomNav"></div>').append(T('<a id="bottomNavClose" href="#"></a>'))))));this._bindStartListener();B.one("#overlay").hide().on(K,function(){this.end();},this);B.one("#lightbox").hide().on(K,function(V){if(V.currentTarget.get("id")===G){this.end();}},this);var S=(this.get(E)?250:1)+F;B.one("#outerImageContainer").setStyles({width:S,height:S});B.one("#prevLink").on(K,function(V){V.halt();this._changeImage(this.get(D)-1);},this);B.one("#nextLink").on(K,function(V){V.halt();this._changeImage(this.get(D)+1);},this);B.one("#bottomNavClose").on(K,function(V){V.halt();this.end();},this);N.later(0,this,function(){var V="overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading "+"imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose";B.Array.each(V.split(" "),function(X,W,Y){this.addAttr(X,{value:B.one("#"+X)});},this);});},start:function(W){B.all("select, object, embed").each(function(){this.setStyle("visibility","hidden");});var S=this.get(Q).setStyles({height:B.DOM.docHeight()+F,width:B.DOM.docWidth()+F}).show();if(this.get(E)){var V=new B.Anim({node:S,from:{opacity:0},to:{opacity:this.get(O)},duration:this.get(H)});V.run();}else{S.setStyle("opacity",this.get(O));}var U=[],L=0;if(W.get("rel")===G){U.push([W.get("href"),W.get("title")]);}else{B.all(W.get("tagName")+'[href][rel="'+W.get("rel")+'"]').each(function(){U.push([this.get("href"),this.get("title")]);});while(U[L][0]!==W.get("href")){L++;}}this.set(P,U);var X=B.DOM.docScrollY()+(B.DOM.winHeight()/10),T=B.DOM.docScrollX();this.get(G).setStyles({display:"",top:X+F,left:T+F});this._changeImage(L);},end:function(){this._disableKeyboardNav();this.get(G).hide();var L=this.get(Q);if(this.get(E)){var S=new B.Anim({node:L,from:{opacity:this.get(O)},to:{opacity:0},duration:this.get(H)});S.on("end",function(){L.hide();});S.run();}else{L.setStyles({opacity:0}).hide();}B.all("select, object, embed").each(function(){this.setStyle("visibility","visible");});},_bindStartListener:function(){B.delegate(K,B.bind(function(L){L.halt();this.start(L.currentTarget);},this),document.body,this.get("selector"));},_changeImage:function(S){this.set(D,S);if(this.get(E)){this.get("loading").show();}this.get("lightboxImage").hide();this.get(I).hide();this.get(R).hide();this.get(A).hide();this.get("imageDataContainer").setStyle("opacity",0.0001);this.get("numberDisplay").hide();var L=new Image();L.onload=B.bind(function(){this.get("lightboxImage").set("src",this.get(P)[S][0]);this._resizeImageContainer(L.width,L.height);},this);L.src=this.get(P)[S][0];},_resizeImageContainer:function(X,Y){var U=this.get("outerImageContainer"),a=U.get("offsetWidth"),W=U.get("offsetHeight"),Z=X+this.get("borderWidth")*2,c=Y+this.get("borderWidth")*2,b=a-Z,T=W-c,d=B.bind(function(){this.get(R).setStyles({height:Y+F});this.get(A).setStyles({height:Y+F});this.get("imageDataContainer").setStyles({width:Z+F});this._showImage();},this);if(b!==0||T!==0){if(this.get(E)){var S=this.get("resizeDuration"),V=new B.Anim({node:U,from:{width:a+F},to:{width:Z+F},duration:S}),L=function(){V.getEvent("end").detach(L);this.setAttrs({from:{height:W+F},to:{height:c+F},duration:S});this.on("end",d);this.run();};V.on("end",L);V.run();}else{U.setStyles({width:Z+F,height:c+F});N.later(0,this,d);}}else{N.later(100,this,d);}},_showImage:function(){this.get("loading").hide();var T=this.get("lightboxImage");if(this.get(E)){var L=T.getStyle("display")==="none"?0:T.getStyle("opacity")||0,S=new B.Anim({node:T,from:{opacity:L},to:{opacity:1}});S.on("end",this._updateDetails,this);T.setStyle("opacity",L).show();S.run();}else{T.setStyle("opacity",1).show();this._updateDetails();}this._preloadNeighborImages();},_updateDetails:function(){var W=this.get(P),U=this.get(D),L=W[U][1];if(L!==""){this.get("caption").setContent(L).show();}if(W.length>1){this.get("numberDisplay").setContent(this.get("strings.labelImage")+" "+(U+1)+" "+this.get("strings.labelOf")+"  "+W.length).show();}var S=this.get("imageDataContainer");if(this.get(E)){var T=S.getStyle("display")==="none"?0:S.getStyle("opacity")||0,V=new B.Anim({node:S,from:{opacity:T},to:{opacity:1},duration:this.get("resizeDuration")});V.on("end",function(){this.get(Q).setStyle("height",B.DOM.docHeight()+F);this._updateNav();},this);
-S.setStyle("opacity",T).show();V.run();}else{S.setStyle("opacity",1).show();this.get(Q).setStyle("height",B.DOM.docHeight()+F);this._updateNav();}},_updateNav:function(){var L=this.get(D);this.get(I).show();if(L>0){this.get(R).show();}if(L<(this.get(P).length-1)){this.get(A).show();}this._enableKeyboardNav();},_enableKeyboardNav:function(){B.get(document.body).on("keydown",this._keyboardAction,this);},_disableKeyboardNav:function(){B.get(document.body).unsubscribe("keydown",this._keyboardAction);},_keyboardAction:function(S){var U=S.keyCode,L=27,T=String.fromCharCode(U).toLowerCase();if(T.match(/x|o|c/)||(U===L)){this.end();}else{if((T==="p")||(U===37)){if(this.get(D)!==0){this._disableKeyboardNav();this._changeImage(this.get(D)-1);}}else{if((T==="n")||(U===39)){if(this.get(D)!==(this.get(P).length-1)){this._disableKeyboardNav();this._changeImage(this.get(D)+1);}}}}},_preloadNeighborImages:function(){var S=this.get(D),U=this.get(P),L,T;if(U.length>S+1){L=new Image();L.src=U[S+1][0];}if(S>0){T=new Image();T.src=U[S-1][0];}}});B.Lightbox={init:function(L){if(C===null){C=new M(L);}return C;}};},"@VERSION@",{requires:["base","node","anim"]});
Index: moodle/lib/gallery/gallery-lightbox.js
--- moodle/lib/gallery/gallery-lightbox.js Base (1.1)
+++ moodle/lib/gallery/gallery-lightbox.js Locally Deleted
@@ -1,733 +0,0 @@
-YUI.add('gallery-lightbox', function(Y) {
-
-	/**
-	 * Inspired by the original Lightbox, this is a port to YUI.
-	 * See Lokesh Dhakar's original at http://www.huddletogether.com/projects/lightbox2/.
-	 * Currently supports everything that module supports with plans to integrate
-	 * additional functionality (i.e. non-images, slideshow mode, etc.) coming soon.
-	 * 
-	 * @module gallery-lightbox
-	 */
-	
-	var L = Y.Lang,
-		Node = Y.Node,
-		
-		PX = "px",
-		
-		CLICK = "click",
-		
-		ANIM = "anim",
-		ACTIVE_IMAGE = "activeImage",
-		IMAGE_ARRAY = "imageArray",
-		OVERLAY_OPACITY = "overlayOpacity",
-		OVERLAY_DURATION = "overlayDuration",
-		
-		LIGHTBOX = "lightbox",
-		OVERLAY = "overlay",
-		PREV_LINK = "prevLink",
-		NEXT_LINK = "nextLink",
-		HOVER_NAV = "hoverNav",
-	
-		// global lightbox instance
-		lightboxInstance = null;
-	
-	/**** BEGIN EXTENDING THE NODE CLASS ****/
-	
-	// Add a few helper methods to the Node class that hopefully will be added
-	// in a future release of the Node class.  They simplify showing/hiding a given node
-	// by manipulating its "display" style.
-	
-	Y.mix(
-		Node.prototype, {
-			/**
-		     * Display a node.
-		     *
-		     * @method show
-		     * @chainable
-		     */
-			show: function () {
-				this.setStyle("display", "");
-				return this;
-			},
-			
-			/**
-		     * Hide a node.
-		     *
-		     * @method hide
-		     * @chainable
-		     */
-			hide: function () {
-				this.setStyle("display", "none");
-				return this;
-			},
-			
-			/**
-		     * Check is a node is being shown. Specifically not called "visible"
-		     * so as not to confuse it with the visibility property.
-		     *
-		     * @method displayed
-		     * @return boolean
-		     */
-			displayed: function() {
-				return this.getStyle("display") != "none";
-			},
-			
-			/**
-		     * Toggle the display of an element.
-		     *
-		     * @method toggle
-		     * @chainable
-		     */
-			toggle: function() {
-				this[this.displayed() ? "hide" : "show"]();
-				return this;
-			}
-		}
-	);
-
-	/**** END EXTENDING THE NODE CLASS ****/
-
-	/**
-	 * The Lightbox class provides the functionality for displaying
-	 * images in a panel above an overlay.  It automatically binds to
-	 * all anchor tags determined by the "selector" attribute.  It supports
-	 * grouping images together to produce a slideshow like effect.
-	 *
-	 * @class Lightbox
-	 * @constructor
-	 * @extends Base
-	 * @uses Node
-	 * @uses Anim
-	 *
-	 * @param config {Object} object with configuration property name/value pairs
-	 */
-	var LB = function (config) {
-		LB.superclass.constructor.apply(this, arguments);
-	};
-	
-	/**
-     * The identity of the widget.
-     *
-     * @property Lightbox.NAME
-     * @type String
-     * @static
-     */
-	LB.NAME = LIGHTBOX;
-	
-	/**
-     * Static property used to define the default attribute configuration of
-     * the Widget.
-     *
-     * @property Lightbox.ATTRS
-     * @type Object
-     * @protected
-     * @static
-     */
-	LB.ATTRS = {
-		/**
-         * The selector to determine which anchors should be bound to the Lightbox
-         * instance.  If an anchor element is bound to Lightbox, it's content will
-         * be displayed in a modal panel rather than on a separate page.
-         *
-         * @attribute selector
-         * @type String
-         * @default &quot;a[rel^=lightbox]&quot;
-         */
-		selector: {
-			value: "a[rel^=lightbox]",
-			validator: L.isString
-		},
-		
-		/**
-         * The width of the border surrounding the displayed content.  This is used during
-         * resize operations.
-         *
-         * @attribute borderWidth
-         * @type Number
-         * @default 10
-         */
-		borderWidth: {
-			value: 10,
-			validator: L.isNumber
-		},
-		
-		/**
-         * The amount of time (in seconds) for the overlay to take to appear when the
-         * Lightbox is displayed.
-         *
-         * @attribute overlayDuration
-         * @type Number
-         * @default 0.2
-         */
-		overlayDuration: {
-			value: 0.2,
-			validator: L.isNumber
-		},
-		
-		/**
-         * The opacity of the overlay element once it is displayed.  This value is used
-         * during animation so that the overlay appears to be eased in.
-         *
-         * @attribute overlayOpacity
-         * @type Number
-         * @default 0.8
-         */
-		overlayOpacity: {
-			value: 0.8,
-			validator: L.isNumber
-		},
-		
-		/**
-         * The amount of time (in seconds) each reisze animation should take.  This is used
-         * specifically during Lightbox height and width resize transformations.
-         *
-         * @attribute resizeDuration
-         * @type Number
-         * @default 0.5
-         */
-		resizeDuration: {
-			value: 0.5,
-			validator: L.isNumber
-		},
-		
-		/**
-         * Whether or the Lighbox module should use animation when displaying, changing images,
-         * and hiding.  If set to false, the values of attributes that control animation settings
-         * are ignored.
-         *
-         * @attribute anim
-         * @type boolean
-         * @default !L.isUndefined(Y.Anim)
-         */
-		anim: {
-			value: !L.isUndefined(Y.Anim),
-			validator: L.isBoolean
-		},
-		
-		/**
-         * A managed array of images that Lightbox can currently cycle through. The size of this array
-         * is defined by the number of images in a particular image group.  This array determines
-         * whether or not there are next and previous options. It's initialized when an image
-         * is clicked on.
-         *
-         * @attribute imageArray
-         * @type Array
-         */
-		imageArray: {
-			validator: L.isArray
-		},
-		
-		/**
-         * The index of the currently displayed image in the "imageArray."
-         *
-         * @attribute activeImage
-         * @type Number
-         */
-		activeImage: {
-			validator: L.isNumber
-		},
-		
-		/**
-         * Set of strings to be used when displaying content.  These can be customized
-         * (i.e. for internationalization) if necessary.
-         *
-         * @attribute strings
-         * @type Object
-         */
-		strings: {
-			value : {
-				labelImage: "Image",
-				labelOf: "of"
-			}
-		}
-	};
-	
-	Y.extend(LB, Y.Base, {
-		/**
-	     * Construction logic executed during Lightbox instantiation. This
-	     * builds and inserts the markup necessary for the Lightbox to function
-	     * as well as binds all of the elements to the necessary events to make
-	     * the Lightbox functional.
-	     *
-	     * @method initializer
-	     * @param config (Object) set of configuration name/value pairs
-	     * @protected
-	     */
-		initializer: function (config) {
-			// Code inserts html at the bottom of the page that looks similar to this:
-	        //
-	        //  <div id="overlay"></div>
-	        //  <div id="lightbox">
-	        //      <div id="outerImageContainer">
-	        //          <div id="imageContainer">
-	        //              <img id="lightboxImage">
-	        //              <div style="" id="hoverNav">
-	        //                  <a href="#" id="prevLink"></a>
-	        //                  <a href="#" id="nextLink"></a>
-	        //              </div>
-	        //              <div id="loading"></div>
-	        //          </div>
-	        //      </div>
-	        //      <div id="imageDataContainer">
-	        //          <div id="imageData">
-	        //              <div id="imageDetails">
-	        //                  <span id="caption"></span>
-	        //                  <span id="numberDisplay"></span>
-	        //              </div>
-	        //              <div id="bottomNav">
-	        //                  <a href="#" id="bottomNavClose"></a>
-	        //              </div>
-	        //          </div>
-	        //      </div>
-	        //  </div>
-
-	        var objBody = Y.one(document.body),
-				create = Node.create;
-
-			objBody.append(create('<div id="overlay"></div>'));
-		
-	        objBody.append(create('<div id="lightbox"></div>')
-				.append(create('<div id="outerImageContainer"></div>')
-					.append(create('<div id="imageContainer"></div>')
-						.append(create('<img id="lightboxImage" />'))
-						.append(create('<div id="hoverNav"></div>')
-							.append(create('<a id="prevLink" href="#"></a>'))
-							.append(create('<a id="nextLink" href="#"></a>'))
-						)
-						.append(create('<div id="loading"></div>'))
-					)
-				)
-				.append(create('<div id="imageDataContainer"></div>')
-					.append(create('<div id="imageData"></div>')
-						.append(create('<div id="imageDetails"></div>')
-							.append(create('<span id="caption"></span>'))
-							.append(create('<span id="numberDisplay"></span>'))
-						)
-						.append(create('<div id="bottomNav"></div>')
-							.append(create('<a id="bottomNavClose" href="#"></a>'))
-						)
-					)
-				)
-			);
-			
-			this._bindStartListener();
-			
-			Y.one("#overlay").hide().on(CLICK, function () { this.end(); }, this);
-			Y.one("#lightbox").hide().on(CLICK, function (evt) {
-				if (evt.currentTarget.get("id") === LIGHTBOX) {
-					this.end();
-				}
-			}, this);
-			
-			var size = (this.get(ANIM) ? 250 : 1) + PX;
-			
-			Y.one("#outerImageContainer").setStyles({ width: size, height: size });
-			Y.one("#prevLink").on(CLICK, function (evt) { evt.halt(); this._changeImage(this.get(ACTIVE_IMAGE) - 1); }, this);
-			Y.one("#nextLink").on(CLICK, function (evt) { evt.halt(); this._changeImage(this.get(ACTIVE_IMAGE) + 1); }, this);
-			Y.one("#bottomNavClose").on(CLICK, function (evt) { evt.halt(); this.end(); }, this);
-			
-			L.later(0, this, function () {
-				var ids = "overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading " + 
-                	"imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose";
-            	
-				Y.Array.each(ids.split(" "), function (element, index, array) {
-					this.addAttr(element, { value: Y.one("#" + element) });
-				}, this);
-			});
-		},
-		
-		/**
-	     * Display overlay and Lightbox.  If image is part of a set, it
-	     * adds those images to an array so that a user can navigate between them.
-	     *
-	     * @method start
-	     * @param selectedLink { Y.Node } the node whose content should be displayed
-	     * @protected
-	     */
-		start: function (selectedLink) {
-			Y.all("select, object, embed").each(function() {
-				this.setStyle("visibility", "hidden");
-			});
-			
-			// Stretch overlap to fill page and fade in
-			var overlay = this.get(OVERLAY).setStyles({ height: Y.DOM.docHeight() + PX, width: Y.DOM.docWidth() + PX }).show();
-			if (this.get(ANIM)) {
-				var anim = new Y.Anim({
-					node: overlay,
-					from: { opacity: 0 },
-					to: { opacity: this.get(OVERLAY_OPACITY) },
-					duration: this.get(OVERLAY_DURATION)
-				});
-				anim.run();
-			} else {
-				overlay.setStyle("opacity", this.get(OVERLAY_OPACITY));
-			}
-			
-			var imageArray = [],
-				imageNum = 0;
-			
-			if (selectedLink.get("rel") === LIGHTBOX) {
-				// If image is NOT part of a set, add single image to imageArray
-				imageArray.push([selectedLink.get("href"), selectedLink.get("title")]);
-			} else {
-				// If image is part of a set...
-				Y.all(selectedLink.get("tagName") + '[href][rel="' + selectedLink.get("rel") + '"]').each(function () {
-					imageArray.push([this.get("href"), this.get("title")]);
-				});
-				
-				while (imageArray[imageNum][0] !== selectedLink.get("href")) { imageNum++; }
-			}
-			
-			this.set(IMAGE_ARRAY, imageArray);
-			
-			var lightboxTop = Y.DOM.docScrollY() + (Y.DOM.winHeight() / 10),
-				lightboxLeft = Y.DOM.docScrollX();
-			this.get(LIGHTBOX).setStyles({ display: "", top: lightboxTop + PX, left: lightboxLeft + PX });
-			
-			this._changeImage(imageNum);
-		},
-		
-		/**
-	     * Hide the overlay and Lightbox and unbind any event listeners.
-	     *
-	     * @method end
-	     * @protected
-	     */
-		end: function () {
-			this._disableKeyboardNav();
-			this.get(LIGHTBOX).hide();
-			
-			var overlay = this.get(OVERLAY);
-			
-			if (this.get(ANIM)) {
-				var anim = new Y.Anim({
-					node: overlay,
-					from: { opacity: this.get(OVERLAY_OPACITY) },
-					to: { opacity: 0 },
-					duration: this.get(OVERLAY_DURATION)
-				});
-				anim.on("end", function () { overlay.hide(); });
-				anim.run();
-			} else {
-				overlay.setStyles({ opacity: 0 }).hide();
-			}
-			
-			Y.all("select, object, embed").each(function() {
-				this.setStyle("visibility", "visible");
-			});
-		},
-		
-		/**
-	     * Helper method responsible for binding listener to the page to process
-	     * lightbox anchors and images.
-	     *
-	     * @method _bindStartListener
-	     * @private
-	     */
-		_bindStartListener: function () {
-			Y.delegate(CLICK, Y.bind(function (evt) {
-				evt.halt();
-				this.start(evt.currentTarget);
-			}, this), document.body, this.get("selector"));
-		},
-		
-		/**
-	     * Display the selected index by first showing a loading screen, preloading it
-	     * and displaying it once it has been loaded.
-	     *
-	     * @method _changeImage
-	     * @param imageNum { Number } the index of the image to be displayed
-	     * @private
-	     */
-		_changeImage: function (imageNum) {
-			this.set(ACTIVE_IMAGE, imageNum);
-			
-			// Hide elements during transition
-			if (this.get(ANIM)) {
-				this.get("loading").show();
-			}
-			this.get("lightboxImage").hide();
-			this.get(HOVER_NAV).hide();
-			this.get(PREV_LINK).hide();
-			this.get(NEXT_LINK).hide();
-			
-			// Hack: Opera9 doesn't support something in scriptaculous opacity and appear fx
-			// TODO: Do I need this since we are using YUI? Is this a scriptaculous/Opera
-			// bug, or just Opera bug?
-			this.get("imageDataContainer").setStyle("opacity", 0.0001);
-			this.get("numberDisplay").hide();
-			
-			var imagePreloader = new Image();
-			
-			// Once image is preloaded, resize image container
-			imagePreloader.onload = Y.bind(function () {
-				this.get("lightboxImage").set("src", this.get(IMAGE_ARRAY)[imageNum][0]);
-				this._resizeImageContainer(imagePreloader.width, imagePreloader.height);
-			}, this);
-			imagePreloader.src = this.get(IMAGE_ARRAY)[imageNum][0];
-		},
-		
-		/**
-	     * Resize the image container so it is large enough to display the entire image.
-	     * Once this is complete it will delegate to another method to actually display the image.
-	     *
-	     * @method _resizeImageContainer
-	     * @param imgWidth { Number } image width
-	     * @param imgWidth { Number } image height
-	     * @private
-	     */
-		_resizeImageContainer: function (imgWidth, imgHeight) {
-			// Get current width and height
-			var outerImageContainer = this.get("outerImageContainer"),
-				widthCurrent = outerImageContainer.get("offsetWidth"),
-				heightCurrent = outerImageContainer.get("offsetHeight"),
-			
-			// Get new width and height
-				widthNew = imgWidth + this.get("borderWidth") * 2,
-				heightNew = imgHeight + this.get("borderWidth") * 2,
-				
-			// calculate size difference between new and old image
-				wDiff = widthCurrent - widthNew,
-				hDiff = heightCurrent - heightNew,
-				
-				afterResize = Y.bind(function () {
-					this.get(PREV_LINK).setStyles({ height: imgHeight + PX });
-					this.get(NEXT_LINK).setStyles({ height: imgHeight + PX });
-					this.get("imageDataContainer").setStyles({ width: widthNew + PX });
-					
-					this._showImage();
-				}, this);
-			
-			if (wDiff !== 0 || hDiff !== 0) {
-				if (this.get(ANIM)) {
-					var resizeDuration = this.get("resizeDuration"),
-					
-					anim = new Y.Anim({
-						node: outerImageContainer,
-						from: { width: widthCurrent + PX },
-						to: { width: widthNew + PX },
-						duration: resizeDuration
-					}),
-					
-					onEnd = function () {
-						anim.getEvent("end").detach(onEnd);
-						this.setAttrs({
-							from: { height: heightCurrent + PX },
-							to: { height: heightNew + PX },
-							duration: resizeDuration
-						});
-						this.on("end", afterResize);
-						this.run();
-					};
-					
-					anim.on("end", onEnd);
-					
-					anim.run();
-				} else {
-					outerImageContainer.setStyles({ width: widthNew + PX, height: heightNew + PX});
-					L.later(0, this, afterResize);
-				}
-			} else {
-				// If new and old image are the same size, and no scaling is necessary,
-				// do a quick pause to prevent image flicker.
-				L.later(100, this, afterResize);
-			}
-		},
-		
-		/**
-	     * Display the currently loaded image and then try to preload any neighboring images.
-	     *
-	     * @method _showImage
-	     * @private
-	     */
-		_showImage: function () {
-			this.get("loading").hide();
-			
-			var lightBoxImage = this.get("lightboxImage");
-			
-			if (this.get(ANIM)) {
-				
-				var startOpacity = lightBoxImage.getStyle("display") === "none" ? 0 : lightBoxImage.getStyle("opacity") || 0,
-					anim = new Y.Anim({
-						node: lightBoxImage,
-						from: { opacity: startOpacity },
-						to: { opacity: 1 }
-					});
-	
-				anim.on("end", this._updateDetails, this);
-		
-				lightBoxImage.setStyle("opacity", startOpacity).show();
-				anim.run();
-			} else {
-				lightBoxImage.setStyle("opacity", 1).show();
-				this._updateDetails();
-			}
-			
-			this._preloadNeighborImages();
-		},
-		
-		/**
-	     * Use the title of the image as a caption and display information
-	     * about the current image and it's location in an image set (if applicable).
-	     *
-	     * @method _updateDetails
-	     * @private
-	     */
-		_updateDetails: function () {
-			
-			var imageArray = this.get(IMAGE_ARRAY),
-				activeImage = this.get(ACTIVE_IMAGE),
-				caption = imageArray[activeImage][1];
-			
-			// If caption is not null
-			if (caption !== "") {
-				this.get("caption").setContent(caption).show();
-			}
-			
-			// If image is part of a set display "Image x of x"
-			if (imageArray.length > 1) {
-				this.get("numberDisplay").setContent(this.get("strings.labelImage") + " " + (activeImage + 1) + " " + this.get("strings.labelOf") + "  " + imageArray.length).show();
-			}
-			
-			var imageDataContainer = this.get("imageDataContainer");
-			
-			if (this.get(ANIM)) {
-				
-				var startOpacity = imageDataContainer.getStyle("display") === "none" ? 0 : imageDataContainer.getStyle("opacity") || 0,
-					anim = new Y.Anim({
-						node: imageDataContainer,
-						from: { opacity: startOpacity },
-						to: { opacity: 1 },
-						duration: this.get("resizeDuration")
-					});
-		
-				anim.on("end", function () {
-					// Update overlay size and update nav
-					this.get(OVERLAY).setStyle("height", Y.DOM.docHeight() + PX);
-					this._updateNav();
-				}, this);
-		
-				imageDataContainer.setStyle("opacity", startOpacity).show();
-				anim.run();
-			} else {
-				
-				imageDataContainer.setStyle("opacity", 1).show();
-				this.get(OVERLAY).setStyle("height", Y.DOM.docHeight() + PX);
-				this._updateNav();
-			}
-		},
-		
-		/**
-	     * Update the navigation elements to display forward and/or backward
-	     * links if they're appropriate.
-	     *
-	     * @method _updateNav
-	     * @private
-	     */
-		_updateNav: function () {
-			var activeImage = this.get(ACTIVE_IMAGE);
-			
-			this.get(HOVER_NAV).show();
-			
-			// If not first image in set, display previous image button
-			if (activeImage > 0) {
-				this.get(PREV_LINK).show();
-			}
-			
-			// If not first image in set, display previous image button
-			if (activeImage < (this.get(IMAGE_ARRAY).length - 1)) {
-				this.get(NEXT_LINK).show();
-			}
-			
-			this._enableKeyboardNav();
-		},
-		
-		/**
-	     * Enable keyboard shortcuts for closing Lightbox or switching images.
-	     *
-	     * @method _enableKeyboardNav
-	     * @private
-	     */
-		_enableKeyboardNav: function () {
-			Y.get(document.body).on("keydown", this._keyboardAction, this);
-		},
-		
-		/**
-	     * Disable keyboard shortcuts for closing Lightbox or switching images.
-	     *
-	     * @method _disableKeyboardNav
-	     * @private
-	     */
-		_disableKeyboardNav: function () {
-			Y.get(document.body).unsubscribe("keydown", this._keyboardAction);
-		},
-		
-		/**
-	     * Handle key strokes to allow for users to close Lightbox or switch images.
-	     *
-	     * @method _keyboardAction
-	     * @private
-	     */
-		_keyboardAction: function (evt) {
-			var keyCode = evt.keyCode,
-				escapeKey = 27,
-				key = String.fromCharCode(keyCode).toLowerCase();
-			
-			if (key.match(/x|o|c/) || (keyCode === escapeKey)) { // close lightbox
-				this.end();
-			} else if ((key === 'p') || (keyCode === 37)) { // Display the previous image
-				if (this.get(ACTIVE_IMAGE) !== 0) {
-					this._disableKeyboardNav();
-					this._changeImage(this.get(ACTIVE_IMAGE) - 1);
-				}
-			} else if ((key === 'n') || (keyCode === 39)) { // Display the next image
-				if (this.get(ACTIVE_IMAGE) !== (this.get(IMAGE_ARRAY).length - 1)) {
-					this._disableKeyboardNav();
-					this._changeImage(this.get(ACTIVE_IMAGE) + 1);
-				}
-			}
-		},
-		
-		/**
-	     * Preload images that are adjacent to the current image, if they exist,
-	     * to reduce waiting time.
-	     *
-	     * @method _preloadNeighborImages
-	     * @private
-	     */
-		_preloadNeighborImages: function () {
-			var activeImage = this.get(ACTIVE_IMAGE),
-				imageArray = this.get(IMAGE_ARRAY),
-				preloadNextImage, preloadPrevImage;
-			
-			if (imageArray.length > activeImage + 1) {
-				preloadNextImage = new Image();
-				preloadNextImage.src = imageArray[activeImage + 1][0];
-			}
-			
-			if (activeImage > 0) {
-				preloadPrevImage = new Image();
-				preloadPrevImage.src = imageArray[activeImage - 1][0];
-			}
-		}
-	});
-	
-	Y.Lightbox = {
-		/**
-		 * This method returns the single, global LightBox instance.  Upon creation,
-		 * the Lightbox instance attaches itself to the page and is ready to be used.
-		 * 
-		 * @method init
-		 * @return { Lightbox } global instance
-		 * @static
-		 */
-		init: function(config) {
-			if (lightboxInstance === null) {
-				lightboxInstance = new LB(config);
-			}
-			return lightboxInstance;
-		}
-	};
-
-
-}, '@VERSION@' ,{requires:['base','node','anim']});
Index: moodle/lib/javascript-static.js
--- moodle/lib/javascript-static.js Base (1.155)
+++ moodle/lib/javascript-static.js Locally Modified (Based On 1.155)
@@ -10,8 +10,12 @@
         M.yui.loader.modules[modname] = modules[modname];
     }
 };
+/**
+ * The gallery version to use when loading YUI modules from the gallery.
+ * Will be changed every time when using local galleries.
+ */
+M.yui.galleryversion = '2010.04.21-21-51';
 
-
\ No newline at end of file
 /**
  * Various utility functions
  */
Index: moodle/lib/outputcomponents.php
--- moodle/lib/outputcomponents.php Base (1.128)
+++ moodle/lib/outputcomponents.php Locally Modified (Based On 1.128)
@@ -2379,3 +2379,93 @@
         return ($itema > $itemb) ? +1 : -1;
     }
 }
+
+/**
+ * Image gallery component
+ *
+ * This is the image gallery component that can be used to display several images
+ * and if JavaScript is enabled uses the gallery-lightbox YUI module to display
+ * them within a lightbox with appropriate controls and such.
+ *
+ * Lib / YUI Module location: lib/gallery/20100601/
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class image_gallery implements renderable {
+
+    /**
+     * Used to ensure we only initialise the lightbox once... it is shared
+     * @var bool
+     */
+    protected static $jsinit = false;
+    /**
+     * An array of images
+     * @var array
+     */
+    public $images = array();
+    /**
+     * The grouping to apply in the lightbox
+     * @var string
+     */
+    public $grouping = null;
+
+    /**
+     * Constructs an image gallery component
+     * @param array $images
+     * @param string $grouping
+     */
+    public function __construct(array $images=null, $grouping=null) {
+        $this->grouping = $grouping;
+        if (is_array($images)) {
+            foreach ($images as $image) {
+                $image = (array)$image;
+                if (!array_key_exists('imageurl', $image)) {
+                    throw new coding_exception('Image gallery images must specify a url for every image');
+                }
+                if (!array_key_exists('thumburl', $image)) {
+                    throw new coding_exception('Image gallery images must specify a url for every image');
+                }
+                if (!array_key_exists('title', $image)) {
+                    throw new coding_exception('Image gallery images must specify a title for every image');
+                }
+                if (!array_key_exists('alt', $image)) {
+                    $image['alt'] = null;
+                }
+                if (!array_key_exists('attributes', $image)) {
+                    $image['attributes'] = null;
+                }
+                $this->add_image($image['thumburl'], $image['imageurl'], $image['title'], $image['alt'], $image['attributes']);
+            }
+        }
+    }
+    /**
+     * Adds an image to the gallery
+     *
+     * @param moodle_url|string $thumburl
+     * @param moodle_url|string $imageurl
+     * @param string $title
+     * @param string $alt
+     * @param array $attributes
+     */
+    public function add_image($thumburl, $imageurl, $title, $alt=null, array $attributes=null) {
+        $image = new stdClass;
+        $image->link = array('id'=>'imagelink'.(count($this->images)+1), 'class'=>'imagelink');
+        $image->thumb = array('id'=>'imagethumb'.(count($this->images)+1), 'class'=>'imagethumb');
+        if (is_array($attributes)) {
+            $image->link = $attributes;
+        }
+        $image->link['href'] = new moodle_url($imageurl);
+        $image->link['title'] = $title;
+        $image->link['rel'] = 'lightbox';
+        if ($this->grouping !== null) {
+            $image->link['rel'] .= "[{$this->grouping}]";
+        }
+        
+        $image->thumb['src'] = new moodle_url($thumburl);
+        $image->thumb['alt'] = $alt;
+        
+        $this->images[] = $image;
+    }
+}
\ No newline at end of file
Index: moodle/lib/outputrenderers.php
--- moodle/lib/outputrenderers.php Base (1.211)
+++ moodle/lib/outputrenderers.php Locally Modified (Based On 1.211)
@@ -2599,7 +2599,26 @@
         // Return the sub menu
         return $content;
     }
+
+    /**
+     * Renders the image_gallery component and initialises its JavaScript
+     *
+     * @param image_gallery $imagegallery
+     * @return string
+     */
+    protected function render_image_gallery(image_gallery $imagegallery) {
+        $this->page->requires->js_gallery_module(array('gallery-lightbox','gallery-lightbox-skin'), '2010.04.08-12-35', 'Y.Lightbox.init');
+        if (count($imagegallery->images) == 0) {
+            return '';
 }
+        $content = html_writer::start_tag('div', array('class'=>'image_gallery'));
+        foreach ($imagegallery->images as $image) {
+            $content .= html_writer::tag('a', html_writer::empty_tag('img', $image->thumb), $image->link);
+        }
+        $content .= html_writer::end_tag('div');
+        return $content;
+    }
+}
 
 
 /// RENDERERS
Index: moodle/lib/outputrequirementslib.php
--- moodle/lib/outputrequirementslib.php Base (1.34)
+++ moodle/lib/outputrequirementslib.php Locally Modified (Based On 1.34)
@@ -150,6 +150,26 @@
         $this->M_yui_loader->filter       = ($this->yui3loader->filter == YUI_DEBUG) ? 'debug' : '';
         $this->M_yui_loader->insertBefore = 'firstthemesheet';
         $this->M_yui_loader->modules      = array();
+        if (empty($CFG->useexternalyui) || true) {
+            $this->M_yui_loader->groups = array(
+                'local' => array(
+                    'name' => 'gallery',
+                    'base' => $CFG->wwwroot.'/lib/yui/gallery/',
+                    'comboBase' => $this->yui3loader->comboBase,
+                    'combine' => $this->yui3loader->combine,
+                    'filter' => $this->M_yui_loader->filter,
+                    'ext' => false,
+                    'root' => 'gallery/',
+                    'patterns' => array(
+                        'gallery-' => array(
+                            'group' => 'gallery',
+                            'configFn' => '@GALLERYCONFIGFN@',
+                        ),
+                        'root' => 'gallery'
+                    ),
+                )
+            );
+        }
         $this->add_yui2_modules(); // adds loading info for all YUI2 modules
         $this->js_module($this->find_module('core_filepicker'));
         $this->js_module($this->find_module('core_dock'));
@@ -566,6 +586,40 @@
     }
 
     /**
+     * Adds a call to make use of a YUI gallery module.
+     *
+     * This function adds code to the page footer that will tell a YUI instance to
+     * use the requested gallery module(s) and then call the desired function.
+     *
+     * @todo Once YUI support loading skins from the gallery the if to use
+     * external yui libs should be fixed so that it calls;
+     *
+     * @param string|array $modules One or more gallery modules to require
+     * @param string $version
+     * @param string $function
+     * @param array $arguments
+     * @param bool $ondomready
+     */
+    public function js_gallery_module($modules, $version, $function, array $arguments = null, $ondomready = false) {
+        global $CFG;
+        if (!is_array($modules)) {
+            $modules = array($modules);
+        }
+        if (empty($CFG->useexternalyui) || true) {
+            // We need to set the M.yui.galleryversion to the correct version
+            $jscode = 'M.yui.galleryversion='.json_encode($version).';';
+        } else {
+            // Set Y's config.gallery to the version
+            $jscode = 'Y.config.gallery='.json_encode($version).';';
+        }
+        $jscode .= 'Y.use('.join(',', array_map('json_encode', $modules)).',function() {'.js_writer::function_call($function, $arguments).'})';
+        if ($ondomready) {
+            $jscode = "Y.on('domready', function() { $jscode });";
+        }
+        $this->jsinitcode[] = $jscode;
+    }
+
+    /**
      * Ensure that the specified JavaScript function is called from an inline script
      * from page footer.
      *
@@ -875,7 +929,8 @@
         // note: in JavaScript just use "YUI(M.yui.loader).use('overlay', function(Y) { .... });"
         // this needs to be done before including any other script
         $js = "var M = {}; M.yui = {}; ";
-        $js .= js_writer::set_variable('M.yui.loader', $this->M_yui_loader, false) . "\n";
+        $js .= "var galleryConfigFn = function(me) {var p = me.path,v=M.yui.galleryversion,f;if(/-skin/.test(me.name)) {me.type = 'css';var p = p.replace(/\-skin/, '').replace(/\.js/, '.css').split('/'), f = p.pop().replace(/\-skin(\-(min|debug))/, '');p.splice(p.length,0,v,'assets','skins','sam', f);} else {var p = p.split('/'), f = p.pop();p.splice(p.length,0,v, f);};me.path = p.join('/');}; ";
+        $js .= str_replace('"@GALLERYCONFIGFN@"', 'galleryConfigFn', js_writer::set_variable('M.yui.loader', $this->M_yui_loader, false) . "\n");
         $js .= js_writer::set_variable('M.cfg', $this->M_cfg, false);
         $output .= html_writer::script($js);
 
Index: moodle/lib/thirdpartylibs.xml
--- moodle/lib/thirdpartylibs.xml Base (1.19)
+++ moodle/lib/thirdpartylibs.xml Locally Modified (Based On 1.19)
@@ -50,6 +50,13 @@
     <licenseversion>2.1+</licenseversion>
   </library>
   <library>
+      <location>gallery</location>
+      <name>Gallery Lightbox</name>
+      <license>BSD</license>
+      <version>2010060100</version>
+      <licenseversion></licenseversion>
+  </library>
+  <library>
     <location>geoip</location>
     <name>GeoIP</name>
     <license>LGPL</license>
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/gallery-lightbox-core.css
--- moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/gallery-lightbox-core.css No Base Revision
+++ moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/gallery-lightbox-core.css Locally New
@@ -0,0 +1 @@
+/* NEED TO SEPARATE SKINS APPROPRIATELY. */
\ No newline at end of file
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/closelabel.gif
MIME: application/octet-stream; encoding: Base64; length: 979
R0lGODlhQgAWAOYAAMDAwMHBwZ2dnVlZWdLS0oODg6+vr/X19eTk5FBQULi4
uIyMjJSUlFRUVFZWVtzc3FJSUsnJyVFRUVhYWFVVVezs7FNTU/b29v39/erq
6vr6+qampldXV6KiokxMTE9PT2ZmZvf3993d3czMzGBgYHt7e6Ghofz8/PDw
8N7e3mxsbLW1tfv7+5WVlc3NzcrKynh4eOvr60tLS+Dg4F9fX7m5ud/f37S0
tIaGhnBwcGNjY+Xl5ZKSkoiIiKmpqW5ubpeXl29vb9XV1Y6Oju3t7WVlZXZ2
dpiYmG1tbXx8fO/v7+fn57GxsbOzs/Hx8Xl5eVpaWmRkZE1NTXNzc2dnZ5aW
loeHh+Pj405OTmlpadvb23p6ev////7+/gAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAA
LAAAAABCABYAAAf/gFyCg4SFhoeIiYqLjI2Oj4xdkpOUlZaXl5BcJ42Ynp+Y
kZJcLEdCXJZcIwIaqKCvoKJdIUAeUSKuXYIuNB5VF5QVWgiwXQjDlwdaWrqL
o00yAxZFWq6qJA0DHj6SBAtb4AsEXQBbzJUABeBbBQCUCusFL1wB6+uDoxlb
HwMJVDaCRtCwMAALDhRdImxZEEFLhAIGyJmrZGALAwJaCDDYElGigYwbLtDj
GKBkAHz5SiQY0EDFDBfYBkixEgJVgQIHJuWUeE4Sgi0CKgmYOJSSoHoPDhmt
UIIfBSTYJiToIbKLli3uLJXrybPSVQVdKirYeXRLUkOVuMRIAmGAAw4D/yAM
qSlp6yW7k4paAtqlgrotGxCUbSGgsAKURlEYoTBgQoMOrSbhRTcx75ZLfLsc
APDN7EjChhFP4qIkCGOWDHRNIoD1bmVJ8MZRYp1VMseRZwulnTElGwUHcU1g
cHXg5k5jOSdbzWyZmOZJQHErHZ1ChQRpWUA4mAChw3BJChk6LLBgM0cA6JlV
vJhxI9iw7DdsOVnPgMkARARRB3E9AYwrLziwnQTCueJNPOOUY09W6ayzQG0N
gnPYSPZ4Zo0IIEAARQIlZCBIDQJOIEEHJ1ByjHOvnHjJMjlFwsUDOqzkXwyo
CLKCBBxwIMMNxfSYijNcOMEABB9s4aFRK1iQQDAOIvjo5CjO6MICD09UkAuU
TPyww5VPwiILFxpUdQkGS3DZ5SuyNOOJfmf6mGaPgQAAOw==
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/gallery-lightbox-skin.css
--- moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/gallery-lightbox-skin.css No Base Revision
+++ moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/gallery-lightbox-skin.css Locally New
@@ -0,0 +1,83 @@
+#lightbox {
+	position: absolute;
+	left: 0;
+	width: 100%;
+	z-index: 100;
+	text-align: center;
+	line-height: 0;
+}
+#lightbox img { width: auto; height: auto; }
+#lightbox a img { border: none; }
+
+#outerImageContainer {
+	position: relative;
+	background-color: #fff;
+	width: 250px;
+	height: 250px;
+	margin: 0 auto;
+}
+#imageContainer { padding: 10px; }
+
+#loading {
+	position: absolute;
+	top: 40%;
+	left: 0%;
+	height: 25%;
+	background: url(loading.gif) no-repeat top center;
+	width: 100%;
+	text-align: center;
+	line-height: 0;
+}
+#hoverNav {
+	position: absolute;
+	top: 0;
+	left: 0;
+	height: 100%;
+	width: 100%;
+	z-index: 10;
+}
+#imageContainer > #hoverNav { left: 0; }
+#hoverNav a { outline: none; }
+
+#prevLink, #nextLink {
+	width: 49%;
+	height: 100%;
+	background-image: url(data:image/gif;base64,AAAA);
+	/* Trick IE into showing hover */ display: block;
+}
+#prevLink { left: 0; float: left; }
+#nextLink { right: 0; float: right; }
+#prevLink:hover, #prevLink:visited:hover { background: url(prevlabel.gif) left 15% no-repeat; }
+#nextLink:hover, #nextLink:visited:hover { background: url(nextlabel.gif) right 15% no-repeat; }
+
+#imageDataContainer {
+	font: 10px Verdana, Helvetica, sans-serif;
+	background-color: #fff;
+	margin: 0 auto;
+	line-height: 1.4em;
+	overflow: auto;
+	width: 100%;
+}
+
+#imageData { padding:0 10px; color: #666; }
+#imageData #imageDetails { width: 70%; float: left; text-align: left; }	
+#imageData #caption { font-weight: bold; }
+#imageData #numberDisplay { display: block; clear: left; padding-bottom: 1.0em; }			
+#imageData #bottomNavClose {
+	width: 66px;
+	height:22px;
+	background: url(closelabel.gif) no-repeat;
+	float: right;
+	padding-bottom: 0.7em;
+	outline: none;
+}
+
+#overlay {
+	position: absolute;
+	top: 0;
+	left: 0;
+	z-index: 90;
+	width: 100%;
+	height: 500px;
+	background-color: #000;
+}
\ No newline at end of file
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/gallery-lightbox.css
--- moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/gallery-lightbox.css No Base Revision
+++ moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/gallery-lightbox.css Locally New
@@ -0,0 +1 @@
+#lightbox{position:absolute;left:0;width:100%;z-index:100;text-align:center;line-height:0;}#lightbox img{width:auto;height:auto;}#lightbox a img{border:none;}#outerImageContainer{position:relative;background-color:#fff;width:250px;height:250px;margin:0 auto;}#imageContainer{padding:10px;}#loading{position:absolute;top:40%;left:0;height:25%;background:url(loading.gif) no-repeat top center;width:100%;text-align:center;line-height:0;}#hoverNav{position:absolute;top:0;left:0;height:100%;width:100%;z-index:10;}#imageContainer>#hoverNav{left:0;}#hoverNav a{outline:none;}#prevLink,#nextLink{width:49%;height:100%;background-image:url(data:image/gif;base64,AAAA);display:block;}#prevLink{left:0;float:left;}#nextLink{right:0;float:right;}#prevLink:hover,#prevLink:visited:hover{background:url(prevlabel.gif) left 15% no-repeat;}#nextLink:hover,#nextLink:visited:hover{background:url(nextlabel.gif) right 15% no-repeat;}#imageDataContainer{font:10px Verdana,Helvetica,sans-serif;background-color:#fff;margin:0 auto;line-height:1.4em;overflow:auto;width:100%;}#imageData{padding:0 10px;color:#666;}#imageData #imageDetails{width:70%;float:left;text-align:left;}#imageData #caption{font-weight:bold;}#imageData #numberDisplay{display:block;clear:left;padding-bottom:1.0em;}#imageData #bottomNavClose{width:66px;height:22px;background:url(closelabel.gif) no-repeat;float:right;padding-bottom:.7em;outline:none;}#overlay{position:absolute;top:0;left:0;z-index:90;width:100%;height:500px;background-color:#000;}
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/loading.gif
MIME: application/octet-stream; encoding: Base64; length: 2767
R0lGODlhIAAgAPcAAP///7Ozs/v7+9bW1uHh4fLy8rq6uoGBgTQ0NAEBARsb
G8TExJeXl/39/VRUVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgAAACwA
AAAAIAAgAAAI+gABCBxIkOCCAwsKKlzIcOCBhwUJFGiocICBgg8PEBzAkSLB
Ag8DEMw4sADHAR5HPkQpkKTAkwRSDjTwkIFDiAAInJRJkMHDiwBcwuQ5cMAB
nxMfOsi5c6DOATFfMmCQcGCAnwp1ljwJdeCCqVNZGq3akGvHnmCnRvVodu3G
tDZTPnW78CsDlnJ5EgBKtC9RsxxNLjBAuHBfwBwLK+Yr8+QCmAMGL/ZLWSZd
ipcZzvW4OaXZiQpNcuUJuGBpzHifclyruuvLy6oJdmbq+uVqAE1PgiYqWuzZ
2Idv4z47vLbcpsWdIvcsPHlR4szxOneamWEBussrZzVOMSAAIfkEBQoAAAAs
AAAAABgAEgAACIAAAQgcSLAggAEGEypkAIAhQQMLFEZUOJDBgQMJGWgs6FDg
gosYDWrsmBCkgYQLNhLsaAAkxYYMJhIkAFJmxoYEBFps6FIgAQMGEFZUWbBl
ToEDgAI9SoCB0JdIlUIsADXhT6lVFSY9mVVhgaddw3odQLYs2KpmzYolUHZB
WbEBAQAh+QQFCgAAACwBAAAAHQAOAAAIiQABCBxIcOAABgUTKlwoEGHCAQwH
EoBIkIFFggEiEjRggGJDAA4BUAzJkKMBAgMthiSpcYDJlApZMlzAceTFAiBF
FsSpkIBJnAgRGvg40MCBA0MHDEA5kGYAj00JLjh69KRSpTwLDI14kOpRg1cJ
MNXo9QBUkVfPLjR6IGNPpWM1MoibUKxGjQEBACH5BAUKAAAALAcAAAAZABEA
AAiBAAEIHAiAgAGCCBMqBLDAwAKEDxcWIIDQgEWCDDIuHDCg4sWBGjdyLDDQ
4kGQDCImJMCxo0CTAheEXAigJUUAMAkwALCTpkCbOD/OROjyJ8ebBAf0rLk0
4QCkCpHuDOCTZs+mVSHGzOrTAEmuYMMmPEC27AGVYM2aFQuArAOzCwICACH5
BAUKAAAALA4AAAASABgAAAiCAAEsIACgoMGDCAcsQAhgAEGGAhcsNLjAgAGI
EScCIGDxIkSJGjsOwAiy4ICOGDMCKNDx4UeJDQMY0CiQAYOUBgoctMmAJkab
AICmDBr05tCdRo8edKm0adOkKW9KdXrAIIORTpsaYHrUwIEDAah+/eoT4gAG
Yw9AxZnWo9IAZAEEBAAh+QQFCgAAACwOAAAAEgAeAAAImQABDCgAoKDBgwgF
DkjIsOCAhwcHLFjQ8OFCgxMvJrRoUCLFihALTvzIkCOAkQ0dhswY0YABAgwJ
aCTg0qXGhgtqGiDZUOfLlB1tAkU4cKhRowySKhUIlAEAp1Cdplya9KjVgwSt
fjRw1SCDmw0JBDg4lqGBAzAFVm3I4IDbgwacggVAwO0BnkDPvrVql+vRAXav
2s161CXDgAAh+QQFCgAAACwPAAEAEQAfAAAIjAABCBwIgEABgggTDhiQsGGB
hQ0jLiQQkSCBhQwrCrwIUePGjgM5ehSIcQDFihwxaiyZUSPHkyMJwBxJE6GB
mzgXaMTJ00DFngZ01hxKcwADBkI9Hj1ac+nShjpbCjyaVKBPpgN1MhB4oCuA
gyQjdj1AEGvCsQO3VkRLk+1UtWcPOFDY0K3HBQeqagwIACH5BAUKAAAALAgA
DgAYABIAAAh9AAEIHEiwIIABCBMOKGCw4UCFCh06TLggIQGJGDNiHKAxowED
HDsa/EjyosiBBRaQNLBA5AAGJgmsDHnwgIGGDAwO+GgSAIMDB3ISJMCgKMYF
QA+YFApgAVOHSW86LNpyZFKCT30aNZi0KsasAq9iPVDQa1mpA3OCPUmzY0AA
IfkEBQoAAAAsAgASAB0ADgAACIkAAQgcSLCgQQAEDhIkwEChQQIDBiQ8aODA
AQMOCUbcWECjxY8ZNW6MKJDBxwMMBmQkgHHgSJYnWyZcYHCAAQM0B0JUWfFA
AII/AWBkQBRAgZsGJj4sqBJAQ6dQAdi8GXLgU4JFBS642bRqVKhXWVINWbQr
0asAtrasihatS6UOu2IN6pXt2owBAQAh+QQFCgAAACwAAA8AGQARAAAIgAAX
HBhI8ACAgwgTKjxYsODChwkFEnQwEKLFixgxFjCQseOCjg8ZgIQYIGEAAhgH
QGTAQOXBlgsJDJiZ0CVHhCxFAjDAE4DMmQUSBlXIEiHPmz9dWmT5cWfPgzMH
oHy4oKjRp1BpLk14tKbWhVav3kQ4FWJThAsMnB2p0EDZhAEBACH5BAUKAAAA
LAEACAARABgAAAh3AAccOGAAgMGDCA8aGDhwQcKHABgOZDAAIsIFEg9YTBhg
YMGNHEGKHEmypMmTKDcuYMCgJEuWIF++BLmyJcICHx+ydHhwgQEDFQcINUgg
IYGfBgoAEFoRItKmTCEOQHow6kOkRQ1aTfizqdahDwl4/ToWpFgAAQEAIfkE
BQoAAAAsAAACAA4AHQAACIoAAQgcCGCBAYIIBx44wCAhwoUHBjgcGADiRIUL
D15cYJFgQ4IQP3qUCIDAgQAEUYokMHHAR5ETFwiUeRFAAY01WzLYyROmwJ49
E7rcCYBnzqMISV4cYMCAUoQEmkp1aFDqggJCrQ4kMACrwKhOCQ4Yy1Kg14EF
xg4o61At24Rcx9ZUm1NuzgJvAwIAOw==
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/nextlabel.gif
MIME: application/octet-stream; encoding: Base64; length: 1252
R0lGODlhPwAgAPeDAP39/enp6UdHR6mpqY+Pj+bm5tDQ0MLCwuzs7O/v76qq
qvHx8fb29vr6+v7+/lxcXPf39+3t7WdnZ2VlZV9fX0lJSc3Nze7u7ltbW/v7
+7y8vKampurq6qenp3BwcPDw8FpaWoCAgLGxsWNjY2BgYPn5+ejo6ExMTFRU
VE5OTqOjo9LS0mJiYufn52hoaI6OjldXV2FhYVFRUaioqNXV1d/f38HBwfz8
/Pj4+JGRkbS0tF1dXd7e3oODg3p6eoGBgfLy8mZmZoKCgs/Pz1JSUllZWaur
q4WFhW1tbWRkZOLi4srKylZWVqSkpLW1tbKysre3t0VFRV5eXqKiovPz88vL
y8bGxmtra3V1dcjIyJqamlVVVXh4eIiIiEhISHd3d9jY2I2Njbq6upmZmeDg
4G5ubktLS9bW1tzc3FNTU6WlpWpqap2dnU9PT66urr6+voyMjE1NTYaGhuTk
5OHh4dfX16ysrOvr68PDw0JCQlhYWH5+fnNzc3l5eZubm+Pj42xsbPT09P//
/zMzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAACH5BAEAAIMALAAAAAA/ACAAAAj/AAcNEkSwoMGD
CBMqXMgQ4cCGECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKEECsDLDQsEb
NkQICuREwYCbHZTQaOKSIAIFeOaoGGDEjYIOOiB4BECgQgweBBvseSDIBAsU
E0aM2GGhxRUMZAQ5IHCiigEYIzAQIUHiy4KlOVCkOIJDUIMQUgQFeNAjggkT
LZQuiQPHQZYUWhyUKMCBTYUVHDgAWErARZg2OgRl+EFBL4gXCcekeeKhTAKD
RgQECMl0TQEuRf4I4qw3BhIFalTYYUAQQh8ZIFYcHCCgAGsCEnDU2SIHgpDO
AZJg4OMBSYi3ggD08LKjxvDixyUAwXEw5YSCLiT0PjiSIAICBJMFiSCygYUP
IAaJG1eJ/IMgBoA8MEEQnuWAEA96hCAIFBV0kB94/EngnyBDMCGDC3pRgIUG
HIpBRwlCwICGXT6gAEZB+rH2wgQTCuJHBQQGMMEJAtSYxwYimLFBQTQU4QF2
M0SxH0hUJBCfZgicBkB7FzQZAQML3HGkIAsEkAFBDCBwQ0pcVtTAEAaEKaYB
FnjXJUQl2HDAmmwe8MYZZ8Yp55x01mnnnQo9hCdEAu0JUUAAOw==
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/assets/skins/sam/prevlabel.gif
MIME: application/octet-stream; encoding: Base64; length: 1264
R0lGODlhPwAgAPeJANzc3P39/fb29rq6utra2v7+/ltbW8HBwfX19fz8/F5e
Xk1NTV9fX/r6+uDg4NXV1djY2ICAgGBgYFFRUVRUVEpKSt3d3eLi4tnZ2cDA
wOPj4/n5+cLCwsPDw/Dw8PLy8ru7u6CgoN/f34ODg0JCQktLS11dXVpaWnJy
cmpqar6+vpCQkJSUlMzMzPj4+KSkpFJSUmVlZcbGxsTExGxsbIGBgba2tuXl
5WNjY3BwcHZ2dmZmZufn5+vr687OztfX18rKysnJyejo6FxcXFBQUKGhoY2N
jZubm3h4eHt7e5iYmN7e3tPT00BAQLi4uEdHR39/f3p6evPz89bW1qenp+bm
5k9PT3d3d2RkZEhISHl5eby8vPT09HR0dG9vb62traOjo/v7+66urr+/v25u
bmFhYWlpadTU1I6OjrW1tb29vaKiourq6p2dnbm5uVVVVZqamqampvHx8ff3
96qqqtDQ0IyMjMjIyKioqKurq2JiYoaGhklJSVhYWLOzs+Hh4UFBQXFxcc/P
z8vLy3Nzc+/v71dXV+7u7v///zMzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAACH5BAEAAIkALAAAAAA/ACAAAAj/ABEJHEiwoMGD
CBMqNJgo0cKHECM+dCixosWLGDNq3Mixo8ePIEOKHEmypMmTKFNubOBjTAYO
U1wIJJAhg4oWQgR+6HCg5wEOPAbJKDBwQ5A7IhHUmMCgaRIHiIrAUKCgTIw8
iCwYMGTgxAkFddBMADCQgAkjIgVA8SLgQ5oSdhKsMQBgg4UcfX5osLJCBIS/
BQ4sCDEQTwUfaSMQSoCowAkdUl4ouCEwDhEOVRZQKeghBQ0EiBBcCUQ0pIAI
OTwgsJHFSAAwBrZgUINDgoMLFEaocOOkA2M4FIAgYlIBxEgBI4iYGCIBCQZE
L2DEGEIBxQxEAAyYMLMDx4gGiDAszVCCSIkEHsdr7Ogw48ccgUUMAPlSYoBA
ABNYaBCx5ELpJGQ4gAULjCXWhUEhMNBDAjro8QF2C9BxkAwL7CGBICSdhgJ4
BIWgwAWIgFBCG1lNsMIDKJ5xiECF0FBBFAFkqEUKHA50xBsiIMIFEnwE8QcF
T5AgZBN+CFTAEYCIUVIAGjhQ2kBsACATIj08IMQGABCgpZYeDCQHBKCpJOZF
NxAAwJlonhnjmA+1YMMAcMY5AAhhsPlQAQHkqaeedvbp55+ABiqonxQNulBD
AQEAOw==
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox-debug.js
--- moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox-debug.js No Base Revision
+++ moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox-debug.js Locally New
@@ -0,0 +1,733 @@
+YUI.add('gallery-lightbox', function(Y) {
+
+	/**
+	 * Inspired by the original Lightbox, this is a port to YUI.
+	 * See Lokesh Dhakar's original at http://www.huddletogether.com/projects/lightbox2/.
+	 * Currently supports everything that module supports with plans to integrate
+	 * additional functionality (i.e. non-images, slideshow mode, etc.) coming soon.
+	 * 
+	 * @module gallery-lightbox
+	 */
+	
+	var L = Y.Lang,
+		Node = Y.Node,
+		
+		PX = "px",
+		
+		CLICK = "click",
+		
+		ANIM = "anim",
+		ACTIVE_IMAGE = "activeImage",
+		IMAGE_ARRAY = "imageArray",
+		OVERLAY_OPACITY = "overlayOpacity",
+		OVERLAY_DURATION = "overlayDuration",
+		
+		LIGHTBOX = "lightbox",
+		OVERLAY = "overlay",
+		PREV_LINK = "prevLink",
+		NEXT_LINK = "nextLink",
+		HOVER_NAV = "hoverNav",
+	
+		// global lightbox instance
+		lightboxInstance = null;
+	
+	/**** BEGIN EXTENDING THE NODE CLASS ****/
+	
+	// Add a few helper methods to the Node class that hopefully will be added
+	// in a future release of the Node class.  They simplify showing/hiding a given node
+	// by manipulating its "display" style.
+	
+	Y.mix(
+		Node.prototype, {
+			/**
+		     * Display a node.
+		     *
+		     * @method show
+		     * @chainable
+		     */
+			show: function () {
+				this.setStyle("display", "");
+				return this;
+			},
+			
+			/**
+		     * Hide a node.
+		     *
+		     * @method hide
+		     * @chainable
+		     */
+			hide: function () {
+				this.setStyle("display", "none");
+				return this;
+			},
+			
+			/**
+		     * Check is a node is being shown. Specifically not called "visible"
+		     * so as not to confuse it with the visibility property.
+		     *
+		     * @method displayed
+		     * @return boolean
+		     */
+			displayed: function() {
+				return this.getStyle("display") != "none";
+			},
+			
+			/**
+		     * Toggle the display of an element.
+		     *
+		     * @method toggle
+		     * @chainable
+		     */
+			toggle: function() {
+				this[this.displayed() ? "hide" : "show"]();
+				return this;
+			}
+		}
+	);
+
+	/**** END EXTENDING THE NODE CLASS ****/
+
+	/**
+	 * The Lightbox class provides the functionality for displaying
+	 * images in a panel above an overlay.  It automatically binds to
+	 * all anchor tags determined by the "selector" attribute.  It supports
+	 * grouping images together to produce a slideshow like effect.
+	 *
+	 * @class Lightbox
+	 * @constructor
+	 * @extends Base
+	 * @uses Node
+	 * @uses Anim
+	 *
+	 * @param config {Object} object with configuration property name/value pairs
+	 */
+	var LB = function (config) {
+		LB.superclass.constructor.apply(this, arguments);
+	};
+	
+	/**
+     * The identity of the widget.
+     *
+     * @property Lightbox.NAME
+     * @type String
+     * @static
+     */
+	LB.NAME = LIGHTBOX;
+	
+	/**
+     * Static property used to define the default attribute configuration of
+     * the Widget.
+     *
+     * @property Lightbox.ATTRS
+     * @type Object
+     * @protected
+     * @static
+     */
+	LB.ATTRS = {
+		/**
+         * The selector to determine which anchors should be bound to the Lightbox
+         * instance.  If an anchor element is bound to Lightbox, it's content will
+         * be displayed in a modal panel rather than on a separate page.
+         *
+         * @attribute selector
+         * @type String
+         * @default &quot;a[rel^=lightbox]&quot;
+         */
+		selector: {
+			value: "a[rel^=lightbox]",
+			validator: L.isString
+		},
+		
+		/**
+         * The width of the border surrounding the displayed content.  This is used during
+         * resize operations.
+         *
+         * @attribute borderWidth
+         * @type Number
+         * @default 10
+         */
+		borderWidth: {
+			value: 10,
+			validator: L.isNumber
+		},
+		
+		/**
+         * The amount of time (in seconds) for the overlay to take to appear when the
+         * Lightbox is displayed.
+         *
+         * @attribute overlayDuration
+         * @type Number
+         * @default 0.2
+         */
+		overlayDuration: {
+			value: 0.2,
+			validator: L.isNumber
+		},
+		
+		/**
+         * The opacity of the overlay element once it is displayed.  This value is used
+         * during animation so that the overlay appears to be eased in.
+         *
+         * @attribute overlayOpacity
+         * @type Number
+         * @default 0.8
+         */
+		overlayOpacity: {
+			value: 0.8,
+			validator: L.isNumber
+		},
+		
+		/**
+         * The amount of time (in seconds) each reisze animation should take.  This is used
+         * specifically during Lightbox height and width resize transformations.
+         *
+         * @attribute resizeDuration
+         * @type Number
+         * @default 0.5
+         */
+		resizeDuration: {
+			value: 0.5,
+			validator: L.isNumber
+		},
+		
+		/**
+         * Whether or the Lighbox module should use animation when displaying, changing images,
+         * and hiding.  If set to false, the values of attributes that control animation settings
+         * are ignored.
+         *
+         * @attribute anim
+         * @type boolean
+         * @default !L.isUndefined(Y.Anim)
+         */
+		anim: {
+			value: !L.isUndefined(Y.Anim),
+			validator: L.isBoolean
+		},
+		
+		/**
+         * A managed array of images that Lightbox can currently cycle through. The size of this array
+         * is defined by the number of images in a particular image group.  This array determines
+         * whether or not there are next and previous options. It's initialized when an image
+         * is clicked on.
+         *
+         * @attribute imageArray
+         * @type Array
+         */
+		imageArray: {
+			validator: L.isArray
+		},
+		
+		/**
+         * The index of the currently displayed image in the "imageArray."
+         *
+         * @attribute activeImage
+         * @type Number
+         */
+		activeImage: {
+			validator: L.isNumber
+		},
+		
+		/**
+         * Set of strings to be used when displaying content.  These can be customized
+         * (i.e. for internationalization) if necessary.
+         *
+         * @attribute strings
+         * @type Object
+         */
+		strings: {
+			value : {
+				labelImage: "Image",
+				labelOf: "of"
+			}
+		}
+	};
+	
+	Y.extend(LB, Y.Base, {
+		/**
+	     * Construction logic executed during Lightbox instantiation. This
+	     * builds and inserts the markup necessary for the Lightbox to function
+	     * as well as binds all of the elements to the necessary events to make
+	     * the Lightbox functional.
+	     *
+	     * @method initializer
+	     * @param config (Object) set of configuration name/value pairs
+	     * @protected
+	     */
+		initializer: function (config) {
+			// Code inserts html at the bottom of the page that looks similar to this:
+	        //
+	        //  <div id="overlay"></div>
+	        //  <div id="lightbox">
+	        //      <div id="outerImageContainer">
+	        //          <div id="imageContainer">
+	        //              <img id="lightboxImage">
+	        //              <div style="" id="hoverNav">
+	        //                  <a href="#" id="prevLink"></a>
+	        //                  <a href="#" id="nextLink"></a>
+	        //              </div>
+	        //              <div id="loading"></div>
+	        //          </div>
+	        //      </div>
+	        //      <div id="imageDataContainer">
+	        //          <div id="imageData">
+	        //              <div id="imageDetails">
+	        //                  <span id="caption"></span>
+	        //                  <span id="numberDisplay"></span>
+	        //              </div>
+	        //              <div id="bottomNav">
+	        //                  <a href="#" id="bottomNavClose"></a>
+	        //              </div>
+	        //          </div>
+	        //      </div>
+	        //  </div>
+
+	        var objBody = Y.one(document.body),
+				create = Node.create;
+
+			objBody.append(create('<div id="overlay"></div>'));
+		
+	        objBody.append(create('<div id="lightbox"></div>')
+				.append(create('<div id="outerImageContainer"></div>')
+					.append(create('<div id="imageContainer"></div>')
+						.append(create('<img id="lightboxImage" />'))
+						.append(create('<div id="hoverNav"></div>')
+							.append(create('<a id="prevLink" href="#"></a>'))
+							.append(create('<a id="nextLink" href="#"></a>'))
+						)
+						.append(create('<div id="loading"></div>'))
+					)
+				)
+				.append(create('<div id="imageDataContainer"></div>')
+					.append(create('<div id="imageData"></div>')
+						.append(create('<div id="imageDetails"></div>')
+							.append(create('<span id="caption"></span>'))
+							.append(create('<span id="numberDisplay"></span>'))
+						)
+						.append(create('<div id="bottomNav"></div>')
+							.append(create('<a id="bottomNavClose" href="#"></a>'))
+						)
+					)
+				)
+			);
+			
+			this._bindStartListener();
+			
+			Y.one("#overlay").hide().on(CLICK, function () { this.end(); }, this);
+			Y.one("#lightbox").hide().on(CLICK, function (evt) {
+				if (evt.currentTarget.get("id") === LIGHTBOX) {
+					this.end();
+				}
+			}, this);
+			
+			var size = (this.get(ANIM) ? 250 : 1) + PX;
+			
+			Y.one("#outerImageContainer").setStyles({ width: size, height: size });
+			Y.one("#prevLink").on(CLICK, function (evt) { evt.halt(); this._changeImage(this.get(ACTIVE_IMAGE) - 1); }, this);
+			Y.one("#nextLink").on(CLICK, function (evt) { evt.halt(); this._changeImage(this.get(ACTIVE_IMAGE) + 1); }, this);
+			Y.one("#bottomNavClose").on(CLICK, function (evt) { evt.halt(); this.end(); }, this);
+			
+			L.later(0, this, function () {
+				var ids = "overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading " + 
+                	"imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose";
+            	
+				Y.Array.each(ids.split(" "), function (element, index, array) {
+					this.addAttr(element, { value: Y.one("#" + element) });
+				}, this);
+			});
+		},
+		
+		/**
+	     * Display overlay and Lightbox.  If image is part of a set, it
+	     * adds those images to an array so that a user can navigate between them.
+	     *
+	     * @method start
+	     * @param selectedLink { Y.Node } the node whose content should be displayed
+	     * @protected
+	     */
+		start: function (selectedLink) {
+			Y.all("select, object, embed").each(function() {
+				this.setStyle("visibility", "hidden");
+			});
+			
+			// Stretch overlap to fill page and fade in
+			var overlay = this.get(OVERLAY).setStyles({ height: Y.DOM.docHeight() + PX, width: Y.DOM.docWidth() + PX }).show();
+			if (this.get(ANIM)) {
+				var anim = new Y.Anim({
+					node: overlay,
+					from: { opacity: 0 },
+					to: { opacity: this.get(OVERLAY_OPACITY) },
+					duration: this.get(OVERLAY_DURATION)
+				});
+				anim.run();
+			} else {
+				overlay.setStyle("opacity", this.get(OVERLAY_OPACITY));
+			}
+			
+			var imageArray = [],
+				imageNum = 0;
+			
+			if (selectedLink.get("rel") === LIGHTBOX) {
+				// If image is NOT part of a set, add single image to imageArray
+				imageArray.push([selectedLink.get("href"), selectedLink.get("title")]);
+			} else {
+				// If image is part of a set...
+				Y.all(selectedLink.get("tagName") + '[href][rel="' + selectedLink.get("rel") + '"]').each(function () {
+					imageArray.push([this.get("href"), this.get("title")]);
+				});
+				
+				while (imageArray[imageNum][0] !== selectedLink.get("href")) { imageNum++; }
+			}
+			
+			this.set(IMAGE_ARRAY, imageArray);
+			
+			var lightboxTop = Y.DOM.docScrollY() + (Y.DOM.winHeight() / 10),
+				lightboxLeft = Y.DOM.docScrollX();
+			this.get(LIGHTBOX).setStyles({ display: "", top: lightboxTop + PX, left: lightboxLeft + PX });
+			
+			this._changeImage(imageNum);
+		},
+		
+		/**
+	     * Hide the overlay and Lightbox and unbind any event listeners.
+	     *
+	     * @method end
+	     * @protected
+	     */
+		end: function () {
+			this._disableKeyboardNav();
+			this.get(LIGHTBOX).hide();
+			
+			var overlay = this.get(OVERLAY);
+			
+			if (this.get(ANIM)) {
+				var anim = new Y.Anim({
+					node: overlay,
+					from: { opacity: this.get(OVERLAY_OPACITY) },
+					to: { opacity: 0 },
+					duration: this.get(OVERLAY_DURATION)
+				});
+				anim.on("end", function () { overlay.hide(); });
+				anim.run();
+			} else {
+				overlay.setStyles({ opacity: 0 }).hide();
+			}
+			
+			Y.all("select, object, embed").each(function() {
+				this.setStyle("visibility", "visible");
+			});
+		},
+		
+		/**
+	     * Helper method responsible for binding listener to the page to process
+	     * lightbox anchors and images.
+	     *
+	     * @method _bindStartListener
+	     * @private
+	     */
+		_bindStartListener: function () {
+			Y.delegate(CLICK, Y.bind(function (evt) {
+				evt.halt();
+				this.start(evt.currentTarget);
+			}, this), document.body, this.get("selector"));
+		},
+		
+		/**
+	     * Display the selected index by first showing a loading screen, preloading it
+	     * and displaying it once it has been loaded.
+	     *
+	     * @method _changeImage
+	     * @param imageNum { Number } the index of the image to be displayed
+	     * @private
+	     */
+		_changeImage: function (imageNum) {
+			this.set(ACTIVE_IMAGE, imageNum);
+			
+			// Hide elements during transition
+			if (this.get(ANIM)) {
+				this.get("loading").show();
+			}
+			this.get("lightboxImage").hide();
+			this.get(HOVER_NAV).hide();
+			this.get(PREV_LINK).hide();
+			this.get(NEXT_LINK).hide();
+			
+			// Hack: Opera9 doesn't support something in scriptaculous opacity and appear fx
+			// TODO: Do I need this since we are using YUI? Is this a scriptaculous/Opera
+			// bug, or just Opera bug?
+			this.get("imageDataContainer").setStyle("opacity", 0.0001);
+			this.get("numberDisplay").hide();
+			
+			var imagePreloader = new Image();
+			
+			// Once image is preloaded, resize image container
+			imagePreloader.onload = Y.bind(function () {
+				this.get("lightboxImage").set("src", this.get(IMAGE_ARRAY)[imageNum][0]);
+				this._resizeImageContainer(imagePreloader.width, imagePreloader.height);
+			}, this);
+			imagePreloader.src = this.get(IMAGE_ARRAY)[imageNum][0];
+		},
+		
+		/**
+	     * Resize the image container so it is large enough to display the entire image.
+	     * Once this is complete it will delegate to another method to actually display the image.
+	     *
+	     * @method _resizeImageContainer
+	     * @param imgWidth { Number } image width
+	     * @param imgWidth { Number } image height
+	     * @private
+	     */
+		_resizeImageContainer: function (imgWidth, imgHeight) {
+			// Get current width and height
+			var outerImageContainer = this.get("outerImageContainer"),
+				widthCurrent = outerImageContainer.get("offsetWidth"),
+				heightCurrent = outerImageContainer.get("offsetHeight"),
+			
+			// Get new width and height
+				widthNew = imgWidth + this.get("borderWidth") * 2,
+				heightNew = imgHeight + this.get("borderWidth") * 2,
+				
+			// calculate size difference between new and old image
+				wDiff = widthCurrent - widthNew,
+				hDiff = heightCurrent - heightNew,
+				
+				afterResize = Y.bind(function () {
+					this.get(PREV_LINK).setStyles({ height: imgHeight + PX });
+					this.get(NEXT_LINK).setStyles({ height: imgHeight + PX });
+					this.get("imageDataContainer").setStyles({ width: widthNew + PX });
+					
+					this._showImage();
+				}, this);
+			
+			if (wDiff !== 0 || hDiff !== 0) {
+				if (this.get(ANIM)) {
+					var resizeDuration = this.get("resizeDuration"),
+					
+					anim = new Y.Anim({
+						node: outerImageContainer,
+						from: { width: widthCurrent + PX },
+						to: { width: widthNew + PX },
+						duration: resizeDuration
+					}),
+					
+					onEnd = function () {
+						anim.getEvent("end").detach(onEnd);
+						this.setAttrs({
+							from: { height: heightCurrent + PX },
+							to: { height: heightNew + PX },
+							duration: resizeDuration
+						});
+						this.on("end", afterResize);
+						this.run();
+					};
+					
+					anim.on("end", onEnd);
+					
+					anim.run();
+				} else {
+					outerImageContainer.setStyles({ width: widthNew + PX, height: heightNew + PX});
+					L.later(0, this, afterResize);
+				}
+			} else {
+				// If new and old image are the same size, and no scaling is necessary,
+				// do a quick pause to prevent image flicker.
+				L.later(100, this, afterResize);
+			}
+		},
+		
+		/**
+	     * Display the currently loaded image and then try to preload any neighboring images.
+	     *
+	     * @method _showImage
+	     * @private
+	     */
+		_showImage: function () {
+			this.get("loading").hide();
+			
+			var lightBoxImage = this.get("lightboxImage");
+			
+			if (this.get(ANIM)) {
+				
+				var startOpacity = lightBoxImage.getStyle("display") === "none" ? 0 : lightBoxImage.getStyle("opacity") || 0,
+					anim = new Y.Anim({
+						node: lightBoxImage,
+						from: { opacity: startOpacity },
+						to: { opacity: 1 }
+					});
+	
+				anim.on("end", this._updateDetails, this);
+		
+				lightBoxImage.setStyle("opacity", startOpacity).show();
+				anim.run();
+			} else {
+				lightBoxImage.setStyle("opacity", 1).show();
+				this._updateDetails();
+			}
+			
+			this._preloadNeighborImages();
+		},
+		
+		/**
+	     * Use the title of the image as a caption and display information
+	     * about the current image and it's location in an image set (if applicable).
+	     *
+	     * @method _updateDetails
+	     * @private
+	     */
+		_updateDetails: function () {
+			
+			var imageArray = this.get(IMAGE_ARRAY),
+				activeImage = this.get(ACTIVE_IMAGE),
+				caption = imageArray[activeImage][1];
+			
+			// If caption is not null
+			if (caption !== "") {
+				this.get("caption").setContent(caption).show();
+			}
+			
+			// If image is part of a set display "Image x of x"
+			if (imageArray.length > 1) {
+				this.get("numberDisplay").setContent(this.get("strings.labelImage") + " " + (activeImage + 1) + " " + this.get("strings.labelOf") + "  " + imageArray.length).show();
+			}
+			
+			var imageDataContainer = this.get("imageDataContainer");
+			
+			if (this.get(ANIM)) {
+				
+				var startOpacity = imageDataContainer.getStyle("display") === "none" ? 0 : imageDataContainer.getStyle("opacity") || 0,
+					anim = new Y.Anim({
+						node: imageDataContainer,
+						from: { opacity: startOpacity },
+						to: { opacity: 1 },
+						duration: this.get("resizeDuration")
+					});
+		
+				anim.on("end", function () {
+					// Update overlay size and update nav
+					this.get(OVERLAY).setStyle("height", Y.DOM.docHeight() + PX);
+					this._updateNav();
+				}, this);
+		
+				imageDataContainer.setStyle("opacity", startOpacity).show();
+				anim.run();
+			} else {
+				
+				imageDataContainer.setStyle("opacity", 1).show();
+				this.get(OVERLAY).setStyle("height", Y.DOM.docHeight() + PX);
+				this._updateNav();
+			}
+		},
+		
+		/**
+	     * Update the navigation elements to display forward and/or backward
+	     * links if they're appropriate.
+	     *
+	     * @method _updateNav
+	     * @private
+	     */
+		_updateNav: function () {
+			var activeImage = this.get(ACTIVE_IMAGE);
+			
+			this.get(HOVER_NAV).show();
+			
+			// If not first image in set, display previous image button
+			if (activeImage > 0) {
+				this.get(PREV_LINK).show();
+			}
+			
+			// If not first image in set, display previous image button
+			if (activeImage < (this.get(IMAGE_ARRAY).length - 1)) {
+				this.get(NEXT_LINK).show();
+			}
+			
+			this._enableKeyboardNav();
+		},
+		
+		/**
+	     * Enable keyboard shortcuts for closing Lightbox or switching images.
+	     *
+	     * @method _enableKeyboardNav
+	     * @private
+	     */
+		_enableKeyboardNav: function () {
+			Y.get(document.body).on("keydown", this._keyboardAction, this);
+		},
+		
+		/**
+	     * Disable keyboard shortcuts for closing Lightbox or switching images.
+	     *
+	     * @method _disableKeyboardNav
+	     * @private
+	     */
+		_disableKeyboardNav: function () {
+			Y.get(document.body).unsubscribe("keydown", this._keyboardAction);
+		},
+		
+		/**
+	     * Handle key strokes to allow for users to close Lightbox or switch images.
+	     *
+	     * @method _keyboardAction
+	     * @private
+	     */
+		_keyboardAction: function (evt) {
+			var keyCode = evt.keyCode,
+				escapeKey = 27,
+				key = String.fromCharCode(keyCode).toLowerCase();
+			
+			if (key.match(/x|o|c/) || (keyCode === escapeKey)) { // close lightbox
+				this.end();
+			} else if ((key === 'p') || (keyCode === 37)) { // Display the previous image
+				if (this.get(ACTIVE_IMAGE) !== 0) {
+					this._disableKeyboardNav();
+					this._changeImage(this.get(ACTIVE_IMAGE) - 1);
+				}
+			} else if ((key === 'n') || (keyCode === 39)) { // Display the next image
+				if (this.get(ACTIVE_IMAGE) !== (this.get(IMAGE_ARRAY).length - 1)) {
+					this._disableKeyboardNav();
+					this._changeImage(this.get(ACTIVE_IMAGE) + 1);
+				}
+			}
+		},
+		
+		/**
+	     * Preload images that are adjacent to the current image, if they exist,
+	     * to reduce waiting time.
+	     *
+	     * @method _preloadNeighborImages
+	     * @private
+	     */
+		_preloadNeighborImages: function () {
+			var activeImage = this.get(ACTIVE_IMAGE),
+				imageArray = this.get(IMAGE_ARRAY),
+				preloadNextImage, preloadPrevImage;
+			
+			if (imageArray.length > activeImage + 1) {
+				preloadNextImage = new Image();
+				preloadNextImage.src = imageArray[activeImage + 1][0];
+			}
+			
+			if (activeImage > 0) {
+				preloadPrevImage = new Image();
+				preloadPrevImage.src = imageArray[activeImage - 1][0];
+			}
+		}
+	});
+	
+	Y.Lightbox = {
+		/**
+		 * This method returns the single, global LightBox instance.  Upon creation,
+		 * the Lightbox instance attaches itself to the page and is ready to be used.
+		 * 
+		 * @method init
+		 * @return { Lightbox } global instance
+		 * @static
+		 */
+		init: function(config) {
+			if (lightboxInstance === null) {
+				lightboxInstance = new LB(config);
+			}
+			return lightboxInstance;
+		}
+	};
+
+
+}, '@VERSION@' ,{requires:['base','node','anim']});
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox-min.js
--- moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox-min.js No Base Revision
+++ moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox-min.js Locally New
@@ -0,0 +1,2 @@
+YUI.add("gallery-lightbox",function(B){var N=B.Lang,J=B.Node,F="px",K="click",E="anim",D="activeImage",P="imageArray",O="overlayOpacity",H="overlayDuration",G="lightbox",Q="overlay",R="prevLink",A="nextLink",I="hoverNav",C=null;B.mix(J.prototype,{show:function(){this.setStyle("display","");return this;},hide:function(){this.setStyle("display","none");return this;},displayed:function(){return this.getStyle("display")!="none";},toggle:function(){this[this.displayed()?"hide":"show"]();return this;}});var M=function(L){M.superclass.constructor.apply(this,arguments);};M.NAME=G;M.ATTRS={selector:{value:"a[rel^=lightbox]",validator:N.isString},borderWidth:{value:10,validator:N.isNumber},overlayDuration:{value:0.2,validator:N.isNumber},overlayOpacity:{value:0.8,validator:N.isNumber},resizeDuration:{value:0.5,validator:N.isNumber},anim:{value:!N.isUndefined(B.Anim),validator:N.isBoolean},imageArray:{validator:N.isArray},activeImage:{validator:N.isNumber},strings:{value:{labelImage:"Image",labelOf:"of"}}};B.extend(M,B.Base,{initializer:function(L){var U=B.one(document.body),T=J.create;U.append(T('<div id="overlay"></div>'));U.append(T('<div id="lightbox"></div>').append(T('<div id="outerImageContainer"></div>').append(T('<div id="imageContainer"></div>').append(T('<img id="lightboxImage" />')).append(T('<div id="hoverNav"></div>').append(T('<a id="prevLink" href="#"></a>')).append(T('<a id="nextLink" href="#"></a>'))).append(T('<div id="loading"></div>')))).append(T('<div id="imageDataContainer"></div>').append(T('<div id="imageData"></div>').append(T('<div id="imageDetails"></div>').append(T('<span id="caption"></span>')).append(T('<span id="numberDisplay"></span>'))).append(T('<div id="bottomNav"></div>').append(T('<a id="bottomNavClose" href="#"></a>'))))));this._bindStartListener();B.one("#overlay").hide().on(K,function(){this.end();},this);B.one("#lightbox").hide().on(K,function(V){if(V.currentTarget.get("id")===G){this.end();}},this);var S=(this.get(E)?250:1)+F;B.one("#outerImageContainer").setStyles({width:S,height:S});B.one("#prevLink").on(K,function(V){V.halt();this._changeImage(this.get(D)-1);},this);B.one("#nextLink").on(K,function(V){V.halt();this._changeImage(this.get(D)+1);},this);B.one("#bottomNavClose").on(K,function(V){V.halt();this.end();},this);N.later(0,this,function(){var V="overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading "+"imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose";B.Array.each(V.split(" "),function(X,W,Y){this.addAttr(X,{value:B.one("#"+X)});},this);});},start:function(W){B.all("select, object, embed").each(function(){this.setStyle("visibility","hidden");});var S=this.get(Q).setStyles({height:B.DOM.docHeight()+F,width:B.DOM.docWidth()+F}).show();if(this.get(E)){var V=new B.Anim({node:S,from:{opacity:0},to:{opacity:this.get(O)},duration:this.get(H)});V.run();}else{S.setStyle("opacity",this.get(O));}var U=[],L=0;if(W.get("rel")===G){U.push([W.get("href"),W.get("title")]);}else{B.all(W.get("tagName")+'[href][rel="'+W.get("rel")+'"]').each(function(){U.push([this.get("href"),this.get("title")]);});while(U[L][0]!==W.get("href")){L++;}}this.set(P,U);var X=B.DOM.docScrollY()+(B.DOM.winHeight()/10),T=B.DOM.docScrollX();this.get(G).setStyles({display:"",top:X+F,left:T+F});this._changeImage(L);},end:function(){this._disableKeyboardNav();this.get(G).hide();var L=this.get(Q);if(this.get(E)){var S=new B.Anim({node:L,from:{opacity:this.get(O)},to:{opacity:0},duration:this.get(H)});S.on("end",function(){L.hide();});S.run();}else{L.setStyles({opacity:0}).hide();}B.all("select, object, embed").each(function(){this.setStyle("visibility","visible");});},_bindStartListener:function(){B.delegate(K,B.bind(function(L){L.halt();this.start(L.currentTarget);},this),document.body,this.get("selector"));},_changeImage:function(S){this.set(D,S);if(this.get(E)){this.get("loading").show();}this.get("lightboxImage").hide();this.get(I).hide();this.get(R).hide();this.get(A).hide();this.get("imageDataContainer").setStyle("opacity",0.0001);this.get("numberDisplay").hide();var L=new Image();L.onload=B.bind(function(){this.get("lightboxImage").set("src",this.get(P)[S][0]);this._resizeImageContainer(L.width,L.height);},this);L.src=this.get(P)[S][0];},_resizeImageContainer:function(X,Y){var U=this.get("outerImageContainer"),a=U.get("offsetWidth"),W=U.get("offsetHeight"),Z=X+this.get("borderWidth")*2,c=Y+this.get("borderWidth")*2,b=a-Z,T=W-c,d=B.bind(function(){this.get(R).setStyles({height:Y+F});this.get(A).setStyles({height:Y+F});this.get("imageDataContainer").setStyles({width:Z+F});this._showImage();},this);if(b!==0||T!==0){if(this.get(E)){var S=this.get("resizeDuration"),V=new B.Anim({node:U,from:{width:a+F},to:{width:Z+F},duration:S}),L=function(){V.getEvent("end").detach(L);this.setAttrs({from:{height:W+F},to:{height:c+F},duration:S});this.on("end",d);this.run();};V.on("end",L);V.run();}else{U.setStyles({width:Z+F,height:c+F});N.later(0,this,d);}}else{N.later(100,this,d);}},_showImage:function(){this.get("loading").hide();var T=this.get("lightboxImage");if(this.get(E)){var L=T.getStyle("display")==="none"?0:T.getStyle("opacity")||0,S=new B.Anim({node:T,from:{opacity:L},to:{opacity:1}});S.on("end",this._updateDetails,this);T.setStyle("opacity",L).show();S.run();}else{T.setStyle("opacity",1).show();this._updateDetails();}this._preloadNeighborImages();},_updateDetails:function(){var W=this.get(P),U=this.get(D),L=W[U][1];if(L!==""){this.get("caption").setContent(L).show();}if(W.length>1){this.get("numberDisplay").setContent(this.get("strings.labelImage")+" "+(U+1)+" "+this.get("strings.labelOf")+"  "+W.length).show();}var S=this.get("imageDataContainer");if(this.get(E)){var T=S.getStyle("display")==="none"?0:S.getStyle("opacity")||0,V=new B.Anim({node:S,from:{opacity:T},to:{opacity:1},duration:this.get("resizeDuration")});V.on("end",function(){this.get(Q).setStyle("height",B.DOM.docHeight()+F);this._updateNav();},this);
+S.setStyle("opacity",T).show();V.run();}else{S.setStyle("opacity",1).show();this.get(Q).setStyle("height",B.DOM.docHeight()+F);this._updateNav();}},_updateNav:function(){var L=this.get(D);this.get(I).show();if(L>0){this.get(R).show();}if(L<(this.get(P).length-1)){this.get(A).show();}this._enableKeyboardNav();},_enableKeyboardNav:function(){B.get(document.body).on("keydown",this._keyboardAction,this);},_disableKeyboardNav:function(){B.get(document.body).unsubscribe("keydown",this._keyboardAction);},_keyboardAction:function(S){var U=S.keyCode,L=27,T=String.fromCharCode(U).toLowerCase();if(T.match(/x|o|c/)||(U===L)){this.end();}else{if((T==="p")||(U===37)){if(this.get(D)!==0){this._disableKeyboardNav();this._changeImage(this.get(D)-1);}}else{if((T==="n")||(U===39)){if(this.get(D)!==(this.get(P).length-1)){this._disableKeyboardNav();this._changeImage(this.get(D)+1);}}}}},_preloadNeighborImages:function(){var S=this.get(D),U=this.get(P),L,T;if(U.length>S+1){L=new Image();L.src=U[S+1][0];}if(S>0){T=new Image();T.src=U[S-1][0];}}});B.Lightbox={init:function(L){if(C===null){C=new M(L);}return C;}};},"@VERSION@",{requires:["base","node","anim"]});
\ No newline at end of file
Index: moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox.js
--- moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox.js No Base Revision
+++ moodle/lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/gallery-lightbox.js Locally New
@@ -0,0 +1,733 @@
+YUI.add('gallery-lightbox', function(Y) {
+
+	/**
+	 * Inspired by the original Lightbox, this is a port to YUI.
+	 * See Lokesh Dhakar's original at http://www.huddletogether.com/projects/lightbox2/.
+	 * Currently supports everything that module supports with plans to integrate
+	 * additional functionality (i.e. non-images, slideshow mode, etc.) coming soon.
+	 * 
+	 * @module gallery-lightbox
+	 */
+	
+	var L = Y.Lang,
+		Node = Y.Node,
+		
+		PX = "px",
+		
+		CLICK = "click",
+		
+		ANIM = "anim",
+		ACTIVE_IMAGE = "activeImage",
+		IMAGE_ARRAY = "imageArray",
+		OVERLAY_OPACITY = "overlayOpacity",
+		OVERLAY_DURATION = "overlayDuration",
+		
+		LIGHTBOX = "lightbox",
+		OVERLAY = "overlay",
+		PREV_LINK = "prevLink",
+		NEXT_LINK = "nextLink",
+		HOVER_NAV = "hoverNav",
+	
+		// global lightbox instance
+		lightboxInstance = null;
+	
+	/**** BEGIN EXTENDING THE NODE CLASS ****/
+	
+	// Add a few helper methods to the Node class that hopefully will be added
+	// in a future release of the Node class.  They simplify showing/hiding a given node
+	// by manipulating its "display" style.
+	
+	Y.mix(
+		Node.prototype, {
+			/**
+		     * Display a node.
+		     *
+		     * @method show
+		     * @chainable
+		     */
+			show: function () {
+				this.setStyle("display", "");
+				return this;
+			},
+			
+			/**
+		     * Hide a node.
+		     *
+		     * @method hide
+		     * @chainable
+		     */
+			hide: function () {
+				this.setStyle("display", "none");
+				return this;
+			},
+			
+			/**
+		     * Check is a node is being shown. Specifically not called "visible"
+		     * so as not to confuse it with the visibility property.
+		     *
+		     * @method displayed
+		     * @return boolean
+		     */
+			displayed: function() {
+				return this.getStyle("display") != "none";
+			},
+			
+			/**
+		     * Toggle the display of an element.
+		     *
+		     * @method toggle
+		     * @chainable
+		     */
+			toggle: function() {
+				this[this.displayed() ? "hide" : "show"]();
+				return this;
+			}
+		}
+	);
+
+	/**** END EXTENDING THE NODE CLASS ****/
+
+	/**
+	 * The Lightbox class provides the functionality for displaying
+	 * images in a panel above an overlay.  It automatically binds to
+	 * all anchor tags determined by the "selector" attribute.  It supports
+	 * grouping images together to produce a slideshow like effect.
+	 *
+	 * @class Lightbox
+	 * @constructor
+	 * @extends Base
+	 * @uses Node
+	 * @uses Anim
+	 *
+	 * @param config {Object} object with configuration property name/value pairs
+	 */
+	var LB = function (config) {
+		LB.superclass.constructor.apply(this, arguments);
+	};
+	
+	/**
+     * The identity of the widget.
+     *
+     * @property Lightbox.NAME
+     * @type String
+     * @static
+     */
+	LB.NAME = LIGHTBOX;
+	
+	/**
+     * Static property used to define the default attribute configuration of
+     * the Widget.
+     *
+     * @property Lightbox.ATTRS
+     * @type Object
+     * @protected
+     * @static
+     */
+	LB.ATTRS = {
+		/**
+         * The selector to determine which anchors should be bound to the Lightbox
+         * instance.  If an anchor element is bound to Lightbox, it's content will
+         * be displayed in a modal panel rather than on a separate page.
+         *
+         * @attribute selector
+         * @type String
+         * @default &quot;a[rel^=lightbox]&quot;
+         */
+		selector: {
+			value: "a[rel^=lightbox]",
+			validator: L.isString
+		},
+		
+		/**
+         * The width of the border surrounding the displayed content.  This is used during
+         * resize operations.
+         *
+         * @attribute borderWidth
+         * @type Number
+         * @default 10
+         */
+		borderWidth: {
+			value: 10,
+			validator: L.isNumber
+		},
+		
+		/**
+         * The amount of time (in seconds) for the overlay to take to appear when the
+         * Lightbox is displayed.
+         *
+         * @attribute overlayDuration
+         * @type Number
+         * @default 0.2
+         */
+		overlayDuration: {
+			value: 0.2,
+			validator: L.isNumber
+		},
+		
+		/**
+         * The opacity of the overlay element once it is displayed.  This value is used
+         * during animation so that the overlay appears to be eased in.
+         *
+         * @attribute overlayOpacity
+         * @type Number
+         * @default 0.8
+         */
+		overlayOpacity: {
+			value: 0.8,
+			validator: L.isNumber
+		},
+		
+		/**
+         * The amount of time (in seconds) each reisze animation should take.  This is used
+         * specifically during Lightbox height and width resize transformations.
+         *
+         * @attribute resizeDuration
+         * @type Number
+         * @default 0.5
+         */
+		resizeDuration: {
+			value: 0.5,
+			validator: L.isNumber
+		},
+		
+		/**
+         * Whether or the Lighbox module should use animation when displaying, changing images,
+         * and hiding.  If set to false, the values of attributes that control animation settings
+         * are ignored.
+         *
+         * @attribute anim
+         * @type boolean
+         * @default !L.isUndefined(Y.Anim)
+         */
+		anim: {
+			value: !L.isUndefined(Y.Anim),
+			validator: L.isBoolean
+		},
+		
+		/**
+         * A managed array of images that Lightbox can currently cycle through. The size of this array
+         * is defined by the number of images in a particular image group.  This array determines
+         * whether or not there are next and previous options. It's initialized when an image
+         * is clicked on.
+         *
+         * @attribute imageArray
+         * @type Array
+         */
+		imageArray: {
+			validator: L.isArray
+		},
+		
+		/**
+         * The index of the currently displayed image in the "imageArray."
+         *
+         * @attribute activeImage
+         * @type Number
+         */
+		activeImage: {
+			validator: L.isNumber
+		},
+		
+		/**
+         * Set of strings to be used when displaying content.  These can be customized
+         * (i.e. for internationalization) if necessary.
+         *
+         * @attribute strings
+         * @type Object
+         */
+		strings: {
+			value : {
+				labelImage: "Image",
+				labelOf: "of"
+			}
+		}
+	};
+	
+	Y.extend(LB, Y.Base, {
+		/**
+	     * Construction logic executed during Lightbox instantiation. This
+	     * builds and inserts the markup necessary for the Lightbox to function
+	     * as well as binds all of the elements to the necessary events to make
+	     * the Lightbox functional.
+	     *
+	     * @method initializer
+	     * @param config (Object) set of configuration name/value pairs
+	     * @protected
+	     */
+		initializer: function (config) {
+			// Code inserts html at the bottom of the page that looks similar to this:
+	        //
+	        //  <div id="overlay"></div>
+	        //  <div id="lightbox">
+	        //      <div id="outerImageContainer">
+	        //          <div id="imageContainer">
+	        //              <img id="lightboxImage">
+	        //              <div style="" id="hoverNav">
+	        //                  <a href="#" id="prevLink"></a>
+	        //                  <a href="#" id="nextLink"></a>
+	        //              </div>
+	        //              <div id="loading"></div>
+	        //          </div>
+	        //      </div>
+	        //      <div id="imageDataContainer">
+	        //          <div id="imageData">
+	        //              <div id="imageDetails">
+	        //                  <span id="caption"></span>
+	        //                  <span id="numberDisplay"></span>
+	        //              </div>
+	        //              <div id="bottomNav">
+	        //                  <a href="#" id="bottomNavClose"></a>
+	        //              </div>
+	        //          </div>
+	        //      </div>
+	        //  </div>
+
+	        var objBody = Y.one(document.body),
+				create = Node.create;
+
+			objBody.append(create('<div id="overlay"></div>'));
+		
+	        objBody.append(create('<div id="lightbox"></div>')
+				.append(create('<div id="outerImageContainer"></div>')
+					.append(create('<div id="imageContainer"></div>')
+						.append(create('<img id="lightboxImage" />'))
+						.append(create('<div id="hoverNav"></div>')
+							.append(create('<a id="prevLink" href="#"></a>'))
+							.append(create('<a id="nextLink" href="#"></a>'))
+						)
+						.append(create('<div id="loading"></div>'))
+					)
+				)
+				.append(create('<div id="imageDataContainer"></div>')
+					.append(create('<div id="imageData"></div>')
+						.append(create('<div id="imageDetails"></div>')
+							.append(create('<span id="caption"></span>'))
+							.append(create('<span id="numberDisplay"></span>'))
+						)
+						.append(create('<div id="bottomNav"></div>')
+							.append(create('<a id="bottomNavClose" href="#"></a>'))
+						)
+					)
+				)
+			);
+			
+			this._bindStartListener();
+			
+			Y.one("#overlay").hide().on(CLICK, function () { this.end(); }, this);
+			Y.one("#lightbox").hide().on(CLICK, function (evt) {
+				if (evt.currentTarget.get("id") === LIGHTBOX) {
+					this.end();
+				}
+			}, this);
+			
+			var size = (this.get(ANIM) ? 250 : 1) + PX;
+			
+			Y.one("#outerImageContainer").setStyles({ width: size, height: size });
+			Y.one("#prevLink").on(CLICK, function (evt) { evt.halt(); this._changeImage(this.get(ACTIVE_IMAGE) - 1); }, this);
+			Y.one("#nextLink").on(CLICK, function (evt) { evt.halt(); this._changeImage(this.get(ACTIVE_IMAGE) + 1); }, this);
+			Y.one("#bottomNavClose").on(CLICK, function (evt) { evt.halt(); this.end(); }, this);
+			
+			L.later(0, this, function () {
+				var ids = "overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading " + 
+                	"imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose";
+            	
+				Y.Array.each(ids.split(" "), function (element, index, array) {
+					this.addAttr(element, { value: Y.one("#" + element) });
+				}, this);
+			});
+		},
+		
+		/**
+	     * Display overlay and Lightbox.  If image is part of a set, it
+	     * adds those images to an array so that a user can navigate between them.
+	     *
+	     * @method start
+	     * @param selectedLink { Y.Node } the node whose content should be displayed
+	     * @protected
+	     */
+		start: function (selectedLink) {
+			Y.all("select, object, embed").each(function() {
+				this.setStyle("visibility", "hidden");
+			});
+			
+			// Stretch overlap to fill page and fade in
+			var overlay = this.get(OVERLAY).setStyles({ height: Y.DOM.docHeight() + PX, width: Y.DOM.docWidth() + PX }).show();
+			if (this.get(ANIM)) {
+				var anim = new Y.Anim({
+					node: overlay,
+					from: { opacity: 0 },
+					to: { opacity: this.get(OVERLAY_OPACITY) },
+					duration: this.get(OVERLAY_DURATION)
+				});
+				anim.run();
+			} else {
+				overlay.setStyle("opacity", this.get(OVERLAY_OPACITY));
+			}
+			
+			var imageArray = [],
+				imageNum = 0;
+			
+			if (selectedLink.get("rel") === LIGHTBOX) {
+				// If image is NOT part of a set, add single image to imageArray
+				imageArray.push([selectedLink.get("href"), selectedLink.get("title")]);
+			} else {
+				// If image is part of a set...
+				Y.all(selectedLink.get("tagName") + '[href][rel="' + selectedLink.get("rel") + '"]').each(function () {
+					imageArray.push([this.get("href"), this.get("title")]);
+				});
+				
+				while (imageArray[imageNum][0] !== selectedLink.get("href")) { imageNum++; }
+			}
+			
+			this.set(IMAGE_ARRAY, imageArray);
+			
+			var lightboxTop = Y.DOM.docScrollY() + (Y.DOM.winHeight() / 10),
+				lightboxLeft = Y.DOM.docScrollX();
+			this.get(LIGHTBOX).setStyles({ display: "", top: lightboxTop + PX, left: lightboxLeft + PX });
+			
+			this._changeImage(imageNum);
+		},
+		
+		/**
+	     * Hide the overlay and Lightbox and unbind any event listeners.
+	     *
+	     * @method end
+	     * @protected
+	     */
+		end: function () {
+			this._disableKeyboardNav();
+			this.get(LIGHTBOX).hide();
+			
+			var overlay = this.get(OVERLAY);
+			
+			if (this.get(ANIM)) {
+				var anim = new Y.Anim({
+					node: overlay,
+					from: { opacity: this.get(OVERLAY_OPACITY) },
+					to: { opacity: 0 },
+					duration: this.get(OVERLAY_DURATION)
+				});
+				anim.on("end", function () { overlay.hide(); });
+				anim.run();
+			} else {
+				overlay.setStyles({ opacity: 0 }).hide();
+			}
+			
+			Y.all("select, object, embed").each(function() {
+				this.setStyle("visibility", "visible");
+			});
+		},
+		
+		/**
+	     * Helper method responsible for binding listener to the page to process
+	     * lightbox anchors and images.
+	     *
+	     * @method _bindStartListener
+	     * @private
+	     */
+		_bindStartListener: function () {
+			Y.delegate(CLICK, Y.bind(function (evt) {
+				evt.halt();
+				this.start(evt.currentTarget);
+			}, this), document.body, this.get("selector"));
+		},
+		
+		/**
+	     * Display the selected index by first showing a loading screen, preloading it
+	     * and displaying it once it has been loaded.
+	     *
+	     * @method _changeImage
+	     * @param imageNum { Number } the index of the image to be displayed
+	     * @private
+	     */
+		_changeImage: function (imageNum) {
+			this.set(ACTIVE_IMAGE, imageNum);
+			
+			// Hide elements during transition
+			if (this.get(ANIM)) {
+				this.get("loading").show();
+			}
+			this.get("lightboxImage").hide();
+			this.get(HOVER_NAV).hide();
+			this.get(PREV_LINK).hide();
+			this.get(NEXT_LINK).hide();
+			
+			// Hack: Opera9 doesn't support something in scriptaculous opacity and appear fx
+			// TODO: Do I need this since we are using YUI? Is this a scriptaculous/Opera
+			// bug, or just Opera bug?
+			this.get("imageDataContainer").setStyle("opacity", 0.0001);
+			this.get("numberDisplay").hide();
+			
+			var imagePreloader = new Image();
+			
+			// Once image is preloaded, resize image container
+			imagePreloader.onload = Y.bind(function () {
+				this.get("lightboxImage").set("src", this.get(IMAGE_ARRAY)[imageNum][0]);
+				this._resizeImageContainer(imagePreloader.width, imagePreloader.height);
+			}, this);
+			imagePreloader.src = this.get(IMAGE_ARRAY)[imageNum][0];
+		},
+		
+		/**
+	     * Resize the image container so it is large enough to display the entire image.
+	     * Once this is complete it will delegate to another method to actually display the image.
+	     *
+	     * @method _resizeImageContainer
+	     * @param imgWidth { Number } image width
+	     * @param imgWidth { Number } image height
+	     * @private
+	     */
+		_resizeImageContainer: function (imgWidth, imgHeight) {
+			// Get current width and height
+			var outerImageContainer = this.get("outerImageContainer"),
+				widthCurrent = outerImageContainer.get("offsetWidth"),
+				heightCurrent = outerImageContainer.get("offsetHeight"),
+			
+			// Get new width and height
+				widthNew = imgWidth + this.get("borderWidth") * 2,
+				heightNew = imgHeight + this.get("borderWidth") * 2,
+				
+			// calculate size difference between new and old image
+				wDiff = widthCurrent - widthNew,
+				hDiff = heightCurrent - heightNew,
+				
+				afterResize = Y.bind(function () {
+					this.get(PREV_LINK).setStyles({ height: imgHeight + PX });
+					this.get(NEXT_LINK).setStyles({ height: imgHeight + PX });
+					this.get("imageDataContainer").setStyles({ width: widthNew + PX });
+					
+					this._showImage();
+				}, this);
+			
+			if (wDiff !== 0 || hDiff !== 0) {
+				if (this.get(ANIM)) {
+					var resizeDuration = this.get("resizeDuration"),
+					
+					anim = new Y.Anim({
+						node: outerImageContainer,
+						from: { width: widthCurrent + PX },
+						to: { width: widthNew + PX },
+						duration: resizeDuration
+					}),
+					
+					onEnd = function () {
+						anim.getEvent("end").detach(onEnd);
+						this.setAttrs({
+							from: { height: heightCurrent + PX },
+							to: { height: heightNew + PX },
+							duration: resizeDuration
+						});
+						this.on("end", afterResize);
+						this.run();
+					};
+					
+					anim.on("end", onEnd);
+					
+					anim.run();
+				} else {
+					outerImageContainer.setStyles({ width: widthNew + PX, height: heightNew + PX});
+					L.later(0, this, afterResize);
+				}
+			} else {
+				// If new and old image are the same size, and no scaling is necessary,
+				// do a quick pause to prevent image flicker.
+				L.later(100, this, afterResize);
+			}
+		},
+		
+		/**
+	     * Display the currently loaded image and then try to preload any neighboring images.
+	     *
+	     * @method _showImage
+	     * @private
+	     */
+		_showImage: function () {
+			this.get("loading").hide();
+			
+			var lightBoxImage = this.get("lightboxImage");
+			
+			if (this.get(ANIM)) {
+				
+				var startOpacity = lightBoxImage.getStyle("display") === "none" ? 0 : lightBoxImage.getStyle("opacity") || 0,
+					anim = new Y.Anim({
+						node: lightBoxImage,
+						from: { opacity: startOpacity },
+						to: { opacity: 1 }
+					});
+	
+				anim.on("end", this._updateDetails, this);
+		
+				lightBoxImage.setStyle("opacity", startOpacity).show();
+				anim.run();
+			} else {
+				lightBoxImage.setStyle("opacity", 1).show();
+				this._updateDetails();
+			}
+			
+			this._preloadNeighborImages();
+		},
+		
+		/**
+	     * Use the title of the image as a caption and display information
+	     * about the current image and it's location in an image set (if applicable).
+	     *
+	     * @method _updateDetails
+	     * @private
+	     */
+		_updateDetails: function () {
+			
+			var imageArray = this.get(IMAGE_ARRAY),
+				activeImage = this.get(ACTIVE_IMAGE),
+				caption = imageArray[activeImage][1];
+			
+			// If caption is not null
+			if (caption !== "") {
+				this.get("caption").setContent(caption).show();
+			}
+			
+			// If image is part of a set display "Image x of x"
+			if (imageArray.length > 1) {
+				this.get("numberDisplay").setContent(this.get("strings.labelImage") + " " + (activeImage + 1) + " " + this.get("strings.labelOf") + "  " + imageArray.length).show();
+			}
+			
+			var imageDataContainer = this.get("imageDataContainer");
+			
+			if (this.get(ANIM)) {
+				
+				var startOpacity = imageDataContainer.getStyle("display") === "none" ? 0 : imageDataContainer.getStyle("opacity") || 0,
+					anim = new Y.Anim({
+						node: imageDataContainer,
+						from: { opacity: startOpacity },
+						to: { opacity: 1 },
+						duration: this.get("resizeDuration")
+					});
+		
+				anim.on("end", function () {
+					// Update overlay size and update nav
+					this.get(OVERLAY).setStyle("height", Y.DOM.docHeight() + PX);
+					this._updateNav();
+				}, this);
+		
+				imageDataContainer.setStyle("opacity", startOpacity).show();
+				anim.run();
+			} else {
+				
+				imageDataContainer.setStyle("opacity", 1).show();
+				this.get(OVERLAY).setStyle("height", Y.DOM.docHeight() + PX);
+				this._updateNav();
+			}
+		},
+		
+		/**
+	     * Update the navigation elements to display forward and/or backward
+	     * links if they're appropriate.
+	     *
+	     * @method _updateNav
+	     * @private
+	     */
+		_updateNav: function () {
+			var activeImage = this.get(ACTIVE_IMAGE);
+			
+			this.get(HOVER_NAV).show();
+			
+			// If not first image in set, display previous image button
+			if (activeImage > 0) {
+				this.get(PREV_LINK).show();
+			}
+			
+			// If not first image in set, display previous image button
+			if (activeImage < (this.get(IMAGE_ARRAY).length - 1)) {
+				this.get(NEXT_LINK).show();
+			}
+			
+			this._enableKeyboardNav();
+		},
+		
+		/**
+	     * Enable keyboard shortcuts for closing Lightbox or switching images.
+	     *
+	     * @method _enableKeyboardNav
+	     * @private
+	     */
+		_enableKeyboardNav: function () {
+			Y.get(document.body).on("keydown", this._keyboardAction, this);
+		},
+		
+		/**
+	     * Disable keyboard shortcuts for closing Lightbox or switching images.
+	     *
+	     * @method _disableKeyboardNav
+	     * @private
+	     */
+		_disableKeyboardNav: function () {
+			Y.get(document.body).unsubscribe("keydown", this._keyboardAction);
+		},
+		
+		/**
+	     * Handle key strokes to allow for users to close Lightbox or switch images.
+	     *
+	     * @method _keyboardAction
+	     * @private
+	     */
+		_keyboardAction: function (evt) {
+			var keyCode = evt.keyCode,
+				escapeKey = 27,
+				key = String.fromCharCode(keyCode).toLowerCase();
+			
+			if (key.match(/x|o|c/) || (keyCode === escapeKey)) { // close lightbox
+				this.end();
+			} else if ((key === 'p') || (keyCode === 37)) { // Display the previous image
+				if (this.get(ACTIVE_IMAGE) !== 0) {
+					this._disableKeyboardNav();
+					this._changeImage(this.get(ACTIVE_IMAGE) - 1);
+				}
+			} else if ((key === 'n') || (keyCode === 39)) { // Display the next image
+				if (this.get(ACTIVE_IMAGE) !== (this.get(IMAGE_ARRAY).length - 1)) {
+					this._disableKeyboardNav();
+					this._changeImage(this.get(ACTIVE_IMAGE) + 1);
+				}
+			}
+		},
+		
+		/**
+	     * Preload images that are adjacent to the current image, if they exist,
+	     * to reduce waiting time.
+	     *
+	     * @method _preloadNeighborImages
+	     * @private
+	     */
+		_preloadNeighborImages: function () {
+			var activeImage = this.get(ACTIVE_IMAGE),
+				imageArray = this.get(IMAGE_ARRAY),
+				preloadNextImage, preloadPrevImage;
+			
+			if (imageArray.length > activeImage + 1) {
+				preloadNextImage = new Image();
+				preloadNextImage.src = imageArray[activeImage + 1][0];
+			}
+			
+			if (activeImage > 0) {
+				preloadPrevImage = new Image();
+				preloadPrevImage.src = imageArray[activeImage - 1][0];
+			}
+		}
+	});
+	
+	Y.Lightbox = {
+		/**
+		 * This method returns the single, global LightBox instance.  Upon creation,
+		 * the Lightbox instance attaches itself to the page and is ready to be used.
+		 * 
+		 * @method init
+		 * @return { Lightbox } global instance
+		 * @static
+		 */
+		init: function(config) {
+			if (lightboxInstance === null) {
+				lightboxInstance = new LB(config);
+			}
+			return lightboxInstance;
+		}
+	};
+
+
+}, '@VERSION@' ,{requires:['base','node','anim']});
Index: moodle/lib/yui/gallery/gallery-lightbox/license.txt
--- moodle/lib/yui/gallery/gallery-lightbox/license.txt No Base Revision
+++ moodle/lib/yui/gallery/gallery-lightbox/license.txt Locally New
@@ -0,0 +1,31 @@
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+
+Redistribution and use of this software in source and binary forms, with or
+without modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its contributors may be used
+  to endorse or promote products derived from this software without specific
+  prior written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+http://developer.yahoo.net/yui/license.html
Index: moodle/lib/yui/gallery/gallery-lightbox/readme_moodle.txt
--- moodle/lib/yui/gallery/gallery-lightbox/readme_moodle.txt No Base Revision
+++ moodle/lib/yui/gallery/gallery-lightbox/readme_moodle.txt Locally New
@@ -0,0 +1,25 @@
+Description of import of gallery-lightbox YUI3 module.
+
+Author:
+    Andrew Bialecki
+
+Gallery url:
+    http://yuilibrary.com/gallery/show/lightbox
+
+License:
+    YUI BSD http://developer.yahoo.com/yui/license.html
+
+Available from:
+    http://projects.sophomoredev.com/yui-gallery-lightbox
+
+Downloaded from:
+    http://github.com/downloads/bialecki/yui3-gallery/gallery-lightbox.zip
+
+Information:
+    A port of the lightbox 2 project [http://www.huddletogether.com/projects/lightbox2/]
+
+
+1\ Version gallery-2010.04.08-12-35
+   * Copied downloaded files to lib/yui/gallery/gallery-lightbox/2010.04.08-12-35/.
+   * Did not make any changes to downloaded files.
+   * Integrated into Moodle via image_gallery component in lib/outputcomponents.php.
\ No newline at end of file
Index: moodle/theme/yui_combo.php
--- moodle/theme/yui_combo.php Base (1.7)
+++ moodle/theme/yui_combo.php Locally Modified (Based On 1.7)
@@ -58,7 +58,7 @@
         continue;
     }
     $version = $bits[0];
-    if ($version != $CFG->yui3version and $version != $CFG->yui2version) {
+    if ($version != $CFG->yui3version and $version != $CFG->yui2version and $version != 'gallery') {
         $content .= "\n// Wrong yui version $part!\n";
         continue;
     }
@@ -70,9 +70,14 @@
     $filecontent = file_get_contents($contentfile);
 
     if ($mimetype === 'text/css') {
+        if ($version == 'gallery') {
+            // search for all images in gallery module CSS and serve them through the yui_image.php script
+            $filecontent = preg_replace('/([a-z_-]+)\.(png|gif)/', 'yui_image.php?file='.$version.'/'.$bits[1].'/'.$bits[2].'/$1.$2', $filecontent);
+        } else {
         // search for all images in yui2 CSS and serve them through the yui_image.php script
         $filecontent = preg_replace('/([a-z_-]+)\.(png|gif)/', 'yui_image.php?file='.$version.'/$1.$2', $filecontent);
     }
+    }
 
     $content .= $filecontent;
 }
Index: moodle/theme/yui_image.php
--- moodle/theme/yui_image.php Base (1.4)
+++ moodle/theme/yui_image.php Locally Modified (Based On 1.4)
@@ -31,15 +31,18 @@
 $path = min_optional_param('file', '', 'SAFEPATH');
 
 $parts = explode('/', $path);
-if (count($parts) != 2) {
-    yui_image_not_found();
-}
-list($version, $image) = $parts;
+$version = array_shift($parts);
 
+if ($version =='gallery' && count($parts)==3) {
+    list($module, $version, $image) = $parts;
+    $imagepath = "$CFG->dirroot/lib/yui/gallery/$module/$version/assets/skins/sam/$image";
+} else if (count($parts) == 1 && ($version == $CFG->yui3version || $version == $CFG->yui2version)) {
+    list($image) = $parts;
 if ($version == $CFG->yui3version) {
     $imagepath = "$CFG->dirroot/lib/yui/$CFG->yui3version/build/assets/skins/sam/$image";
-} else if ($version == $CFG->yui2version) {
+    } else  {
     $imagepath = "$CFG->dirroot/lib/yui/$CFG->yui2version/build/assets/skins/sam/$image";
+    }
 } else {
     yui_image_not_found();
 }
