My IT and development musings.

+menu-


  • Category Archives Development
  • Openfire 3.7.1 authenticating with an Active Directory global catalog server

    As in my previous post for 3.7.0 (link), I’ve created a patch for Openfire to authenticate against the entire global catalog. The actual changes and even the line numbers are identical:

    Index: LdapManager.java
    ===================================================================
    --- LdapManager.java    (revision 1)
    +++ LdapManager.java    (revision 2)
    @@ -622,7 +622,11 @@
                * the secure connection has been established. */
                if (!(startTlsEnabled && !sslEnabled)) {
                    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    +           if (baseDN == null || baseDN.trim().isEmpty()) {
    +               env.put(Context.SECURITY_PRINCIPAL, userDN);
    +           } else {
                    env.put(Context.SECURITY_PRINCIPAL, userDN + "," + baseDN);
    +           }
                    env.put(Context.SECURITY_CREDENTIALS, password);
                } else {
                    if (followReferrals)
    

    This has been up and stable for several months now with no issues.

    To download the compiled openfire.jar, please click here.


  • Home Xeon server

    For several years I ran a Win2008 x64 home file server on an Asus Intel Atom ITX motherboard (see previous post), and then added a few Linux VMs on top of it with VMware Server. While functional, this was less than ideal for development work or any experiments I wanted to run. I was crippled by the processor’s lack of virtualization features, could only create 32-bit VMs, the web UI sucked, and more…

    In building a new server, I wanted a Xeon processor and wouldn’t take no for an answer. I also wanted all of the must-have features available from Intel (quad core, HT, VT-x, VT-d) but didn’t want to bother with a video card, so I went for the lowest processor where I could get all of these features: Xeon E3-1230. In hindsight I would have opted for the E3-1235 had I known better at the time, but more on that later.

    There was a lot of fretting over 8GB of RAM vs. 16GB, both of which were supported for this motherboard and processor. In the end, 8GB won simply due to price and for a home server I really didn’t expect to truly need more than 8GB of memory.

    I wanted to stick with my existing ITX case so I hunted a long while for a viable motherboard from a reputable manufacturer. After reading more product specifications than I care to talk about I settled on the Intel S1200KP server board. This wasn’t a 100% perfect choice for my VMware virtualization plans, but it was close. The secondary NIC (Intel 82579LM) is not yet officially supported, though there are ongoing threads with 3rd party solutions here and there. I’m also a bit disappointed at the lack of eSATA and no USB3 support.

    So, as a gift to myself, I assembled the following:

    • Chenbro ES30068 mini-ITX chassis (Newegg)
    • Intel S1200KP server motherboard (Intel)
      • 2 x SATA2 ports
      • 2 x SATA3 ports
      • 2 x DDR3 1066/1333 MHz DIMMs
      • 2 x Gigabit NICs (82574L, 82579LM)
    • Intel Xeon E3-1230 processor (Intel)
      • Quad core, 3.2 GHz
      • vPro, Hyper-Hhreading, VT-x, VT-d
    • Crucial Memory, 8GB kit (4GB x 2) of DDR3 1333 MHz PC3-10600 (Crucial)
    • Western Digital VelociRaptor 150GB 10,000 RPM hard drive (WD)
    • Western Digital Caviar Black 1TB 7,200 RPM hard drive (WD)
    • Western Digital Green 2TB hard drive (WD)
    • VMware vSphere Hypervisor 5.0 (VMware)

    While the motherboard does have a PCIe slot, the case doesn’t have any expansion slots so I was forced to build the machine and install the OS with the motherboard lying on the kitchen table with a cheap PCIe video card installed. What is important to note is that the BIOS has an option to beep when no video card is detected; with this feature disabled, the server boots quietly into VMware every time. With this feature enabled (the default), the BIOS will beep several times but will continue to boot the operating system anyway.

    Looking back, I would have opted to spend the extra money for the Xeon E3-1235 with built-in GPU just for the convenience factor of not needing to install a video card when errors occur, but that’s neither here nor there. I know the E3-1230 draws less power because there is no GPU and I’m going to keep pretending to myself that I’m saving real money every month on my electrical utility bill.

    I also would like to upgrade to a nice PCIe SSD or SATA3 600GB VelociRaptor. The hard drives included in this build are leftovers from previous systems and not my choice picks, but the price was impeccable.

    So far though things are working well and I’m able to run everything I [reasonably] want to run. If I were to include Microsoft Exchange or some other individually very heavy application I think I would be in trouble with only 8GB.

    esxi

    Further reading on this project: Article updated 2012-05-02


  • GeoRSS + user presence data + Google Maps API = killer app?

    Alright, so, I have:

    Where is the killer app with this data?


  • Openfire 3.7.0 authenticating with an Active Directory global catalog server

    After more time than I care to admit, I have figured out what exactly is required to get my Openfire 3.7.0 instance to authenticate and pull users from a full Active Directory domain forest.

    • company.local
      • northamerica.company.local
      • europe.company.local
      • asiapacific.company.local

    I pointed Openfire at a domain controller in company.local with the global catalog server role and made the following changes to LdapManager:

    Index: LdapManager.java
    ===================================================================
    --- LdapManager.java  (revision 2)
    +++ LdapManager.java  (revision 3)
    @@ -622,7 +622,11 @@
    				* the secure connection has been established. */
    				if (!(startTlsEnabled && !sslEnabled)) {
    					env.put(Context.SECURITY_AUTHENTICATION, "simple");
    -					env.put(Context.SECURITY_PRINCIPAL, userDN + "," + baseDN);
    +					if (baseDN == null || baseDN.trim().isEmpty()) {
    +						env.put(Context.SECURITY_PRINCIPAL, userDN);
    +					} else {
    +						env.put(Context.SECURITY_PRINCIPAL, userDN + "," + baseDN);
    +					}
    					env.put(Context.SECURITY_CREDENTIALS, password);
    				} else {
    					if (followReferrals)
    

    System properties:

    • ldap.adminDN = openfire@company.local
    • ldap.autoFollowAliasReferrals = false
    • ldap.autoFollowReferrals = false
    • ldap.baseDN =
    • ldap.encloseDN = true
    • ldap.host = 10.0.0.10
    • ldap.port = 3268
    • xmpp.domain = company.local

    Please note that a global catalog server communicates on TWO different ports:

       389:  global catalog server responds as a domain controller in its natural domain
       3268: global catalog server responds as a global catalog server

    While this is in place and working, it requires that the ldap.basedn variable be set to blank or null, a situation the installer is not impressed with.

    Now, PLEASE NOTE that this will still not pass the tests during the installation phase. I installed Openfire 3.7.0 using the global catalog server’s domain, got it all working on that singular domain, and then performed the above patch.

    I hope this is useful to someone in the future.


  • … aaaaaannnddd we’re back!

    My misguided effort to keep my web server patched let to a minor WordPress vs PHP 5.3 clash. I think we’re good now.

    In other news I need to start posting more. I’ve begun diving into CodeIgnitor, CakePHP, Zend, and other PHP frameworks. Up until now I’ve always created my own but I’m getting tired of giving up my hard work to my present employer.


  • Prototyping JavaScript objects functionally using jQuery and JSON

    Making JavaScript act like a full-featured object oriented language takes some effort, typically more than I care to put forward. The process of manually typing out the prototyping of a JavaScript object has never been a favor task of mine.

    function foo(args) {
    	// Constructor
    };
    foo.prototype.myFunction (args) {
    	// Do something cool.
    };
    foo.prototype.myOtherFunction () {
    	// Something less than cool but neat.
    };
    var box = new foo();
    

    I find that code to be hard to read and a waste of time to write. What if the objects could be instantiated just a little closer other object oriented languages, something like:

    $.declare(
    	'window.foo',
    	{
    		constructor: function (args) {
    			//
    		},
    		myFunction: function myFunction() {
    			//
    		},
    		myOtherFunction: function myOtherFunction() {
    			//
    		}
    	},
    	undefined // not required but included for example purposes
    );
    var box = new foo();
    

    A bit simpler? Now, what about extending foo to include additional features? I want to be able to take foo as a base and extend it much like how PHP handles classes. How does this look?

    $.declare(
    	'window.fooImproved',
    	{
    		myOtherOtherFunction: function myOtherOtherFunction() {
    			//
    		}
    	},
    	window.foo
    );
    var boxImproved = new fooImproved();
    

    foo() and fooImproved() are completely independent classes (objects), with fooImproved taking all of foo’s properties and extending it with the additional myOtherOtherFunction() function. Now what’s really fun is inheritance with the addition of overloading functions.

    Let’s take fooImproved() and make fooReallyImproved, complete with a new myFunction() with some other functionality.

    $.declare(
    	'window.fooReallyImproved',
    	{
    		myFunction: function myFunction() {
    			// Do something incredible
    			this.inherited(arguments);
    			// Finish up
    		}
    	},
    	window.fooImproved
    );
    

    The really neat feature about this.inherited() is that it can be called from any function to access the parent class’ features; if that same function exists in a parent class, the parent function is executed. this.inherited() can be called recursively all the way back to the base object.

    So what is $.declare and how does it work?

    $.extend({
    	/**
    	 * Creates a pseudo-class object.
    	 * @param mixClass Either a string-based object name (with or without dot notation) or an object
    	 * @param objProperties JavaScript object containing the features to be included in the new class
    	 * @param objParentClass Optional parent class to inherit from.
    	 * @return object
    	 */
    	declare: function declare(strDeclaredClass, objProperties, objParentClass) {
    		// Establish defaults
    		objProperties = objProperties || {};
    		objParentClass = objParentClass || null;
    		// Use an anonymizer to generate a clean constructor (and prototype)
    		var obj = (function () {
    			return $.extend(
    				// Generic base constructor used by all objects
    				function constructor(args) {
    					// Make a unique copy of each variable in the class; prevents shared
    					// value strangeness between objects of the same inheritance.
    					for (var strLabel in this) {
    						if (!$.isFunction(this[strLabel])) {
    							this[strLabel] = $.extend(
    								true,
    								this[strLabel] instanceof Array
    									? []
    									: {},
    								this[strLabel],
    								strLabel === 'args'
    									? (args || {})
    									: undefined
    							);
    						}
    					}
    					this._constructor(args);
    				},
    				{
    					// Add functionality to our object for referencing the parent class
    					extend: function (properties) {
    						for (var intArg = 0; intArg < arguments.length; intArg++) {
    							for (var strLabel in arguments[intArg]) {
    								var objFunction;
    								if ($.isFunction(objFunction = arguments[intArg][strLabel]) && !0[strLabel]) {
    									objFunction.name = strLabel;
    									objFunction._inherited = (
    										this.prototype[strLabel] &&
    										$.isFunction(this.prototype[strLabel])
    									)
    										? this.prototype[strLabel]
    										: null;
    								}
    							}
    							this.prototype = $.extend(
    								true,
    								this.prototype,
    								arguments[intArg]
    							);
    						}
    					},
    					// Fresh prototype
    					prototype: {}
    				}
    			);
    		})();
    		// Duplicate prototype functions and properties
    		obj.prototype = $.extend(
    			true,
    			obj.prototype,
    			// Duplicate the prototype of the parent class as a starting point for building the new class
    			(objParentClass) ? objParentClass.prototype : {},
    			{
    				// Note the name of the class being created
    				declaredClass: strDeclaredClass.toString(),
    				// Parent class, solely for debug purposes
    				parentClass: (objParentClass) ? objParentClass.prototype.declaredClass : null,
    				// The _constructor is the constructor provided for the object,
    				//	and is called by the generic constructor declared above.
    				_constructor: $.extend(
    					(objProperties.constructor.toString().indexOf('[native code]') < 0)
    						// Use the provided constructor
    						?	objProperties.constructor
    						// No constructor provided; attempt to execute our parent's constructor
    						:	function constructor(args) {
    								this.inherited(arguments);
    							},
    					{
    						// Provide the ability to call the inherited constructor
    						_inherited: (objParentClass) ? objParentClass.prototype._constructor : null
    					}
    				),
    				inherited: function inherited(objOriginalArguments) {
    					if ($.isFunction(objOriginalArguments.callee._inherited)) {
    						objOriginalArguments.callee._inherited.apply(this,arguments);
    					} else if (
    						objOriginalArguments.callee.name &&
    						objOriginalArguments.callee.name != '_constructor' &&
    						objOriginalArguments.callee.name != 'constructor'
    					) {
    						console.error(this,"::",objOriginalArguments.callee.name," doesn't have an inherited function.");
    					}
    				},
    				toString: function toString() {
    					return this.declaredClass.toString();
    				}
    			}
    		);
    		// Extend with passed properties
    		obj.extend(objProperties);
    		// Store the class
    		return $.setObject(strDeclaredClass, obj);
    	}
    });
    

    Note: the $.declare does rely upon jquery-getobject for the $.setObject() functionality. (thanks,Marcus Dalgren, for pointing out that I neglected mentioning this)

    Many thanks to:


  • Simple (single file) PHP image gallery

    I’ve always had a few pet-peeves with the readily available open source image galleries, namely that they are bulky and complex in many situations. They have some great features and they do well for many people, but for some (me) they’re just overkill.

    A while back I set out to create a very simple web image gallery which would be contained in a single PHP file, and what I came up with has been in use for a while at http://images.johngauthier.com. There are a few configurable options, but for the most part it’s plug-and-play to have yourself a gallery:

    <?php
    class gallery {
    	/* ***** ADJUSTABLE GLOBAL VARIABLES ***** */
    	private $_strTitle = "John G. Gauthier's Gallery";	// Title for the gallery.
    	private $_intThumbSize = 200; 						// Maximum width and height in pixels.
    	private $_intThumbMargin = 3;						// Number of pixels between the thumbnail and the border.
    	private $_strThumbDir = "_thumbs/";				// MUST end in '/', eg: "_thumbs/";
    	/* *************************************** */
    	/* DO NOT MODIFY THE CODE BELOW THIS POINT */
    	/* *************************************** */
    	private $_timeStart = 0;
    	public function __construct() {
    		$this->_timeStart = microtime(true);
    		define('DS', DIRECTORY_SEPARATOR);
    		define('URL_ENTIRE', $this->fetchEntireURL());
    		define('URL_BASE', $this->fetchBaseURL());
    		$this->checkRootViewAttempt();
    		$this->checkClearThumbnailRequest();
    		// If the thumbnail directory doesn't exist, create it.
    		$strSubDirectory = (isset($_GET['d']))
    			? "{$_GET['d']}/"
    			: "";
    		if (!is_dir($this->_strThumbDir . $strSubDirectory)) {
    			mkdir ($this->_strThumbDir . $strSubDirectory, 0755, true);
    		}
    		$this->generateHeader();
    		$this->buildAll($strSubDirectory);
    		$this->generateFooter();
    	}
    	/*
    	 * Loops through every directory, then every file, in the target folder and creates the necessary HTML structures.
    	 */
    	private function buildAll($strSubDirectory) {
    		// Cycle through the contents of the folder, splitting the results into an array of directories (to be listed first) and an array of files (to be shown second)
    		$fhDir = dir(getcwd() . DS . $strSubDirectory);
    		while ($strItem = $fhDir->read()) {
    			if (is_dir(getcwd() . DS . $strSubDirectory . DS . $strItem)) {
    				// Check that this is a valid directory to include
    				if ((($strItem != ".") && ($strItem != "..") && (substr($strItem,0,1) != '_')) || ($strItem == ".." && $strSubDirectory != "")) {
    					$arrDirs[count($arrDirs)] = $strItem;
    				}
    			} else if (!ereg(".php",strtolower($strItem)) && !ereg("thumbs.db",strtolower($strItem))) {
    				$arrFiles[count($arrFiles)] = $strItem;
    			}
    		}
    		$fhDir->close();
    		if (is_array($arrDirs))  sort($arrDirs);
    		if (is_array($arrFiles)) sort($arrFiles);
    		for ($i = 0; $i < count($arrDirs); $i++) {
    			echo($this->buildDivForDir($strSubDirectory . $arrDirs[$i]));
    		}
    		for ($i = 0; $i < count($arrFiles); $i++) {
    			/* Determine what kind of thumbnail we need to build. */
    			if (ereg(".jpg",strtolower($arrFiles[$i])) ||
    				ereg(".tif",strtolower($arrFiles[$i])) ||
    				ereg(".gif",strtolower($arrFiles[$i])) ||
    				ereg(".png",strtolower($arrFiles[$i])))
    			{
    				echo($this->buildDivForImage($strSubDirectory . $arrFiles[$i]));
    			} else {
    				echo($this->buildDivForOther($strSubDirectory . $arrFiles[$i]));
    			}
    		}
    	}
    	/*
    	 * Build a div for a directory.
    	 */
    	private function buildDivForDir($strFilename) {
    		// build a user-friendly file name.
    		$strName = str_replace($_GET['d'], "", $strFilename);
    		// if we are in the root directory, preface the name with '/' for readability.
    		if ($_GET['d']=="") {
    			$strName="/$strName";
    		}
    		// If the root is our parent, point at the base URL.
    		$strURL = URL_BASE;
    		if (strpos($strFilename,"..")>0) {
    			// Replace name for clarification for non-DOS fluent folk.
    			$strName = "Return to parent directory...";
    			// Handle depth issues.
    			// If we are deeper than one child, build the new URL.
    			if ($strFilename != "..") {
    				// Remove '/..' from the filename
    				$strURL .= "?d=".substr($strFilename, 0, -3);
    				// Remove one directory layer from the right
    				$strURL = substr($strURL, 0, strrpos($strURL, "/"));
    			}
    		// Subdirectories
    		} else {
    			$strURL .= "?d={$strFilename}";
    		}
    		// Build the div to encapsulate the text.
    		return "		<div class=\"outer\"><div class=\"front\" onclick=\"location.href='{$strURL}'\">{$strName}</div></div>\n";
    	}
    	/*
    	 * Build a div for an image.
    	 */
    	private function buildDivForImage($strFilename) {
    		// Build the div statement with thumbnail, with the div itself being a hyperlink to the full image
    		return "		<div class=\"outer\"><div class=\"front\" onclick=\"location.href='{$strFilename}'\"><img style=\"border:0;\" src=\"{$this->buildThumb($strFilename)}\" alt=\"{$strFilename}\" title=\"{$this->formatFilename($strFilename)}\"></div></div>\n";
    	}
    	/*
    	 * Build a div for a viewable/navigatable object other than a jpg image.
    	 */
    	private function buildDivForOther($strFilename) {
    		// Build the div to encapsulate the text.
    		return "		<div class=\"outer\"><div class=\"front\" onclick=\"location.href='{$strFilename}'\">{$this->formatFilename($strFilename)}</div></div>\n";
    	}
    	/*
    	 * Construct a thumbnail image for an image file.
    	 */
    	private function buildThumb($strFilename) {
    		$strThumbFilename = $this->_strThumbDir . substr($strFilename,0,(strlen($strFilename) - 4)) . substr($strFilename,(strlen($strFilename) - 4));
    		// $arrDim[0] = width of the image in pixels.
    		// $arrDim[1] = height of the image in pixels.
    		// $arrDim[2] = flag indicating the type of the image:
    		//    1 = GIF
    		//    2 = JPG
    		//    3 = PNG
    		//    4 = SWF
    		//    5 = PSD
    		//    6 = BMP
    		//    7 = TIFF(intel byte order)
    		//    8 = TIFF(motorola byte order)
    		//    9 = JPC
    		//   10 = JP2
    		//   11 = JPX
    		//   12 = JB2
    		//   13 = SWC
    		//   14 = IFF
    		// If the thumb exists AND it's the same size as what we're after, bail because we're done.
    		if (file_exists($strThumbFilename)) {
    			$arrThumbDim = getimagesize($strThumbFilename);
    			if ($arrThumbDim[0] == $this->_intThumbSize || $arrThumbDim[1] == $this->_intThumbSize) {
    				return $strThumbFilename;
    			}
    		}
    		$arrDim = getimagesize($strFilename);
    		// Get new sizes
    		$intOrigRatio = $arrDim[0] / $arrDim[1];
    		$intNewWidth = $this->_intThumbSize;
    		$intNewHeight = $this->_intThumbSize;
    		// Build new height, width
    		if ($intNewWidth/$intNewHeight > $intOrigRatio) {
    			$intNewWidth = $intNewHeight * $intOrigRatio;
    		} else {
    			$intNewHeight = $intNewWidth / $intOrigRatio;
    		}
    		// Load
    		switch($arrDim[2]) {
    			case 1: $objSource = imagecreatefromgif($strFilename); break;
    			case 2: $objSource = imagecreatefromjpeg($strFilename); break;
    			case 3: $objSource = imagecreatefrompng($strFilename); break;
    		}
    		if ($intNewWidth >= $arrDim[0] || $intNewHeight >= $arrDim[1]) {
    			$intNewWidth = $arrDim[0];
    			$intNewHeight = $arrDim[1];
    		}
    		// Resize
    		$objThumb = imagecreatetruecolor($this->_intThumbSize, $this->_intThumbSize);
    		imagefill($objThumb, 0, 0, imagecolorallocate($objThumb, 255, 255, 255));
    		imagecopyresized($objThumb, $objSource, 0, 0, 0, 0, $intNewWidth, $intNewHeight, $arrDim[0], $arrDim[1]);
    		// Save the thumbnail image
    		switch($arrDim[2]) {
    			case 1: imagegif($objThumb, $strThumbFilename); break;
    			case 2: imagejpeg($objThumb, $strThumbFilename); break;
    			case 3: imagepng($objThumb, $strThumbFilename); break;
    		}
    		// Clean up.
    		imagedestroy($objSource);
    		imagedestroy($objThumb);
    		// Provide the parent function with the thumbnail file name.
    		return $strThumbFilename;
    	}
    	/*
    	 * Block attempts to view root file system.
    	 *		Prevents a security exploit by ignoring all syntaxes for viewing a directory higher than web root.
    	 */
    	private function checkRootViewAttempt() {
    		if ((substr($_GET['d'],0,1)=='.') || (substr($_GET['d'],0,1)=='/') || (substr($_GET['d'],0,1)=='\\')) {
    			header("location: " . URL_BASE);
    			exit();
    		}
    	}
    	/*
    	 * Destroys all thumbnails in a given directory.
    	 *		If there is a problem with a thumbnail, the user has the ability to clear the thumbnails and cause them to be rebuilt on the next page load.
    	 */
    	private function checkClearThumbnailRequest() {
    		// Per user request, clear existing thumbnails.
    		if (isset($_GET['r'])) {
    			$this->removeDirectory(getcwd() . DS . substr($this->_strThumbDir,0,-1) . DS . (isset($_GET['d']) ? $_GET['d'] : ""));
    			header("location: " . URL_BASE);
    			exit();
    		}
    	}
    	/*
    	 * Build a user-friendly file name.
    	 */
    	private function formatFilename($strFilename) {
    		return str_replace("/", "", str_replace($_GET['d'], "", $strFilename));
    	}
    	private function generateFooter() {
    ?>
    		<div class="clear"></div>
    		<div class="w3c">
    			<a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-html401-blue" alt="Valid HTML 4.01 Strict" height="31" width="88" style="border:0;"></a>
    		</div>
    		<div class="elapse">
    			Page built in <?php echo(microtime(true) - $this->_timeStart); ?> seconds.<br>
    			<i><a href="<?php echo(URL_ENTIRE . (isset($_GET['d']) ? "&amp;" : "?")); ?>r=1">Click here to rebuild the thumbnails above.</a></i>
    		</div>
    		<div class="clear"></div>
    	</body>
    </html>
    <?php
    	}
    	private function generateHeader() {
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    	<head>
    		<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    		<style type="text/css">
    			body {
    				margin: 0px;
    				padding: 0px;
    			}
    			div.title {
    				font-size: 14px;
    				font-weight: bold;
    				margin: 9px;
    			}
    			div.outer {
    				border: 1px solid #000;
    				float: left;
    				height: <?php echo($this->_intThumbSize + $this->_intThumbMargin*2); ?>px;
    				margin: 5px;
    				width: <?php echo($this->_intThumbSize + $this->_intThumbMargin*2); ?>px;
    			}
    			div.front {
    				background-color: #FFF;
    				cursor: pointer;
    				height: <?php echo($this->_intThumbSize); ?>px;
    				margin: <?php echo($this->_intThumbMargin); ?>px;
    				width: <?php echo($this->_intThumbSize); ?>px;
    			}
    			div.clear {
    				clear: both;
    			}
    			div.w3c {
    				float: left;
    				margin: 5px 10px;
    			}
    			div.elapse {
    				float: right;
    				font-size: 12px;
    				margin-right: 2px;
    				text-align: right;
    			}
    		</style>
    		<title><?php echo($this->_strTitle); ?></title>
    	</head>
    	<body>
    		<div class="title">
    			<a href="<?php echo(URL_BASE); ?>"><?php echo($this->_strTitle); ?></a><?php echo((($_GET['d']) ? " - {$_GET['d']}" : "")); ?>
    		</div>
    <?php
    	}
    	/*
    	 * Determine index.php's location in the site.
    	 *		This will be used later to assemble hyperlinks and to prevent
    	 *		navigation any higher up the tree than the starting point.
    	 *
    	 */
    	private function fetchBaseURL() {
    		// If our current URL contains a '?' then it and any PHP variables need to be pruned.
    		return substr(URL_ENTIRE, 0, strpos(URL_ENTIRE, strstr(URL_ENTIRE,'?') ? '?' : 'index.php'));
    	}
    	/*
    	 * Return the entire URL.
    	 */
    	private function fetchEntireURL() {
    		$s = empty($_SERVER["HTTPS"])
    			? ""
    			: ($_SERVER["HTTPS"] == "on")
    				? "s"
    				: "";
    	    $protocol = substr(strtolower($_SERVER["SERVER_PROTOCOL"]), 0, strpos(strtolower($_SERVER["SERVER_PROTOCOL"]), "/")).$s;
    	    $port = ($_SERVER["SERVER_PORT"] == "80")
    	    	? ""
    	    	: (":".$_SERVER["SERVER_PORT"]);
    		// Build the URL to return.
    		$strURL = "{$protocol}://{$_SERVER["SERVER_NAME"]}{$port}{$_SERVER["REQUEST_URI"]}";
    		if (!strstr($strURL,"index.php") && !strstr($strURL,'?')) {
    			$strURL = "{$strURL}index.php";
    		}
    		return $strURL;
    	}
    	private function removeDirectory($strPath) {
            foreach(scandir($strPath) as $strFile){
                if ($strFile !== '.' && $strFile !== '..'){
                    if (is_dir($strPath.'/'.$strFile)){
                        if (count(glob($strPath.'/'.$strFile.'/*')) > 0){
                            $this->removeDirectory($strPath.'/'.$strFile);
                        } else {
                            rmdir($strPath.'/'.$strFile);
                        }
                    } else {
                        unlink($strPath.'/'.$strFile);
                    }
                }
            }
            rmdir($strPath);
    	}
    };
    new gallery();