Merge branch 'master' of ssh://git.eclipse.org/gitroot/orion/org.eclipse.orion.client
diff --git a/bundles/org.eclipse.orion.client.core/web/navigate/table.js b/bundles/org.eclipse.orion.client.core/web/navigate/table.js
index 9787087..9fe724d 100644
--- a/bundles/org.eclipse.orion.client.core/web/navigate/table.js
+++ b/bundles/org.eclipse.orion.client.core/web/navigate/table.js
@@ -127,10 +127,11 @@
 		commandService.registerCommandContribution("selectionTools", "eclipse.deleteFile", 5, "orion.selectionGroup", false, new mCommands.CommandKeyBinding(46, false, false, false, false, "explorer-tree", "Navigator")); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
 		commandService.registerCommandContribution("selectionTools", "eclipse.compareWithEachOther", 6, "orion.selectionGroup"); 
 		commandService.registerCommandContribution("selectionTools", "eclipse.compareWith", 7, "orion.selectionGroup"); 
-		commandService.registerCommandContribution("selectionTools", "orion.import", 1, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-		commandService.registerCommandContribution("selectionTools", "eclipse.downloadFile", 2, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-		commandService.registerCommandContribution("selectionTools", "orion.importSFTP", 3, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-		commandService.registerCommandContribution("selectionTools", "eclipse.exportSFTPCommand", 4, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+		commandService.registerCommandContribution("selectionTools", "orion.importZipURL", 1, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+		commandService.registerCommandContribution("selectionTools", "orion.import", 2, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+		commandService.registerCommandContribution("selectionTools", "eclipse.downloadFile", 3, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+		commandService.registerCommandContribution("selectionTools", "orion.importSFTP", 4, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+		commandService.registerCommandContribution("selectionTools", "eclipse.exportSFTPCommand", 5, "orion.selectionGroup/orion.importExportGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
 			
 		mFileCommands.createAndPlaceFileCommandsExtension(serviceRegistry, commandService, explorer, "pageActions", "selectionTools", "orion.selectionGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
 
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/commonHTMLFragments.js b/bundles/org.eclipse.orion.client.core/web/orion/commonHTMLFragments.js
index 63bb63a..fe10062 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/commonHTMLFragments.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/commonHTMLFragments.js
@@ -32,8 +32,10 @@
 			'<div class="layoutRight">' + //$NON-NLS-0$
 				'<div id="globalActions" class="spacingLeft layoutLeft"></div>' + //$NON-NLS-0$
 				'<div id="relatedLinks" class="spacingLeft layoutLeft" style="padding-top:1px;"></div>' + //$NON-NLS-0$
-				'<input type="text" id="search" placeholder="'+messages['Search']+'" title="'+messages['Type a keyword or wild card to search in root']+'" class="layoutLeft spacingLeft searchbox" role="search">' + //$NON-NLS-2$ //$NON-NLS-0$
-				'<div id="searchOptions" class="layoutLeft" style="padding-top:1px;"></div>' + //$NON-NLS-0$
+				'<input type="text" id="search" autocomplete="off" list= "searchCompletion" placeholder="'+messages['Search']+'" title="'+messages['Type a keyword or wild card to search in root']+'" class="layoutLeft spacingLeft searchbox" role="search">' + //$NON-NLS-2$ //$NON-NLS-0$
+				 '<datalist id="searchCompletion">' +
+				 '</datalist>' +				
+    			'<div id="searchOptions" class="layoutLeft" style="padding-top:1px;"></div>' + //$NON-NLS-0$
 				// '<div id="userInfo" style= "display:none;" class="layoutLeft primaryNav"></div>' + //$NON-NLS-0$
 				'<div id="userMenu" class="spacingLeft layoutLeft"></div>' + //$NON-NLS-0$
 			'</div>' + //$NON-NLS-0$
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/fileCommands.js b/bundles/org.eclipse.orion.client.core/web/orion/fileCommands.js
index 5c65eb3..a43aa9d 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/fileCommands.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/fileCommands.js
@@ -614,21 +614,28 @@
 				return item.Directory && !mUtil.isAtRoot(item.Location);}});
 	
 		commandService.addCommand(newFolderCommand);
-		
-	
+
+		var zipURLParameters = new mCommands.ParametersDescription([new mCommands.CommandParameter('url', 'url', messages['File URL:'], 'URL'), new mCommands.CommandParameter('unzip', 'boolean', 'Unzip file:', false)]); //$NON-NLS-1$ //$NON-NLS-0$
+
 		var importZipURLCommand = new mCommands.Command({
-			name: "Import a Zip",
-			tooltip: "Import a zip file from a URL and unzip the content",
+			name: "Import from HTTP...",
+			tooltip: "Copy a file from a URL and optionally unzip it",
 			id: "orion.importZipURL", //$NON-NLS-0$
+			parameters: zipURLParameters,
 			callback: function(data) {
-				var item = forceSingleItem(data.items);
-				// this is a temporary hack until we implement import from zip, for now use the old code
-				// that canned content.  Totally fake.
-				var files = ["index.html", "hello.css", "hello.js"]; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-				for (var i=0; i<files.length;  i++) {
-					fileClient.createFile(item.Location, files[i]).then(function(newFileMetadata) {
-						mUtil.saveFileContents(fileClient, newFileMetadata, {sourceLocation: window.location.protocol + "//" + window.location.host+"/examples/contentTemplates/helloWorld/"+newFileMetadata.Name}); //$NON-NLS-0$
-					}, errorHandler);
+				var targetFolder = forceSingleItem(data.items);
+				var sourceURL = data.parameters && data.parameters.valueFor("url"); //$NON-NLS-0$
+				if (targetFolder && sourceURL) {
+					var importURL = targetFolder.ImportLocation+"?source="+sourceURL; //$NON-NLS-0$
+					var expandZip = data.parameters  && data.parameters.valueFor("unzip"); //$NON-NLS-0$
+					var optionHeader = expandZip ? "" : "raw"; //$NON-NLS-1$ //$NON-NLS-0$
+					var deferred = fileClient.remoteImport(importURL, {"OptionHeader":optionHeader}); //$NON-NLS-0$
+					progress.showWhile(deferred, messages["Importing from "] + sourceURL).then(
+						dojo.hitch(explorer, function() {
+							this.changedItem(this.treeRoot, true);
+						}),
+						errorHandler
+					);//refresh the root
 				}
 			},
 			visibleWhen: function(item) {
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/globalCommands.js b/bundles/org.eclipse.orion.client.core/web/orion/globalCommands.js
index 413a9d1..36f802a 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/globalCommands.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/globalCommands.js
@@ -13,9 +13,9 @@
 /*browser:true*/
 
 define(['i18n!orion/nls/messages', 'require', 'dojo', 'dijit', 'orion/commonHTMLFragments', 'orion/commands', 'orion/parameterCollectors', 
-	'orion/extensionCommands', 'orion/util', 'orion/textview/keyBinding', 'orion/breadcrumbs', 'orion/splitter', 'orion/favorites', 'orion/contentTypes', 'orion/URITemplate', 'orion/PageUtil', 'orion/widgets/themes/container/ThemeSheetWriter',
+	'orion/extensionCommands', 'orion/util', 'orion/textview/keyBinding', 'orion/breadcrumbs', 'orion/splitter', 'orion/favorites', 'orion/contentTypes', 'orion/URITemplate', 'orion/PageUtil', 'orion/widgets/themes/container/ThemeSheetWriter', 'orion/searchUtils',
 	'dojo/DeferredList', 'dijit/Menu', 'dijit/MenuItem', 'dijit/form/DropDownButton', 'orion/widgets/OpenResourceDialog', 'orion/widgets/LoginDialog', 'orion/widgets/UserMenu', 'orion/widgets/UserMenuDropDown'], 
-        function(messages, require, dojo, dijit, commonHTML, mCommands, mParameterCollectors, mExtensionCommands, mUtil, mKeyBinding, mBreadcrumbs, mSplitter, mFavorites, mContentTypes, URITemplate, PageUtil, ThemeSheetWriter){
+        function(messages, require, dojo, dijit, commonHTML, mCommands, mParameterCollectors, mExtensionCommands, mUtil, mKeyBinding, mBreadcrumbs, mSplitter, mFavorites, mContentTypes, URITemplate, PageUtil, ThemeSheetWriter, mSearchUtils){
 
 	/**
 	 * This class contains static utility methods. It is not intended to be instantiated.
@@ -249,28 +249,20 @@
 		}	
 	}
 	
-	function _populateSavedSearchMenu(serviceRegistry, commandService, menu) {
-		// see http://bugs.dojotoolkit.org/ticket/10296
-		menu.focusedChild = null;
-		dojo.forEach(menu.getChildren(), function(child) {
-			menu.removeChild(child);
-			child.destroy();
+	function _addSearchPopUp(mainMenu, popUpLabel, serviceRegistry, type, makeLabelFunc){
+		var choicesMenu = new dijit.Menu({
+			style: "display: none;" //$NON-NLS-0$
 		});
-
-		serviceRegistry.getService("orion.core.preference").getPreferences("/window/favorites").then(function(prefs) {  //$NON-NLS-1$ //$NON-NLS-0$
-			var i;
-			var searches = prefs.get("search"); //$NON-NLS-0$
-			if (typeof searches === "string") { //$NON-NLS-0$
-				searches = JSON.parse(searches);
-			}
-			if (searches) {
-				for (i in searches) {
-					menu.addChild(new mCommands.CommandMenuItem({
-						 label: "<a href='"+require.toUrl("search/search.html") +  "#" + searches[i].query + "'>" + searches[i].name+"</a>", //$NON-NLS-4$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-						 hasLink: true
-					}));
-				}
-			}
+		var popup = new dijit.PopupMenuItem({
+			label: popUpLabel,
+			popup: choicesMenu
+		});
+		mainMenu.addChild(popup);
+		dojo.connect(mainMenu, "_openPopup", popup, function(event) { //$NON-NLS-0$
+			mSearchUtils.populateSearchMenu(serviceRegistry, choicesMenu, type, function(theSearch){
+				return makeLabelFunc(theSearch);
+				//)"<a href='"+require.toUrl("search/search.html") +  "#" + theSearch.query + "'>" + theSearch.name+"</a>"; //$NON-NLS-4$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+			});
 		});
 	}
 		
@@ -293,17 +285,17 @@
 			}
 		}));
 		newMenu.addChild(new dijit.MenuSeparator());
-		var choicesMenu = new dijit.Menu({
-			style: "display: none;" //$NON-NLS-0$
+		
+		//Add the saved searches as popups
+		_addSearchPopUp(newMenu,  messages["Saved searches"], serviceRegistry, "search", function(theSearch){
+			return "<a href='"+require.toUrl("search/search.html") +  "#" + theSearch.query + "'>" + theSearch.name+"</a>"; //$NON-NLS-4$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
 		});
-		var popup = new dijit.PopupMenuItem({
-			label: messages["Saved searches"],
-			popup: choicesMenu
+		//Add the recent searches as popups
+		_addSearchPopUp(newMenu,  messages["Recent searches"], serviceRegistry, "recentSearch", function(theSearch){
+			var query = searcher.createSearchQuery(theSearch.name);
+			return "<a href='"+require.toUrl("search/search.html") +  "#" + query + "'>" + theSearch.name+"</a>"; //$NON-NLS-4$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
 		});
-		newMenu.addChild(popup);
-		dojo.connect(newMenu, "_openPopup", popup, function(event) { //$NON-NLS-0$
-			_populateSavedSearchMenu(serviceRegistry, commandService, choicesMenu);
-		});
+		
 		var menuButton = new orion.widgets.UserMenuDropDown({
 			label : "",
 			id : "searchOptionsDropDown", //$NON-NLS-0$
@@ -784,6 +776,7 @@
 			if (e.charOrCode === dojo.keys.ENTER) {
 				if (searcher) {
 					if (searchField.value.length > 0) {
+						mSearchUtils.addRecentSearch(serviceRegistry, searchField.value);
 						var query = searcher.createSearchQuery(searchField.value);
 						window.location = require.toUrl("search/search.html") + "#"+query; //$NON-NLS-1$ //$NON-NLS-0$
 					}
@@ -792,6 +785,18 @@
 				}
 			}
 		});
+		dojo.connect(searchField, "onfocus", function(e){ //$NON-NLS-0$
+			var searchCompletion =  dojo.byId("searchCompletion");
+			dojo.empty(searchCompletion);
+			mSearchUtils.getSearches(serviceRegistry, "recentSearch", function(searches){//$NON-NLS-0$
+				var i;
+				for (i in searches) {
+					var option = document.createElement('option');
+					option.value = searches[i].name;
+					searchCompletion.appendChild(option);
+				}
+			});
+		});
 		_addSearchOptions(serviceRegistry, commandService, searcher);
 		// layout behavior.  Special handling for pages that use dijit for interior layout.
 		var dijitLayout = dojo.query(".dijitManagesLayout")[0]; //$NON-NLS-0$
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/nls/root/messages.js b/bundles/org.eclipse.orion.client.core/web/orion/nls/root/messages.js
index ba56d0f..53ec296 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/nls/root/messages.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/nls/root/messages.js
@@ -77,5 +77,6 @@
 	"Submit" : "Submit",
 	"More" : "More",
 	"Saved searches" : "Saved searches",
+	"Recent searches" : "Recent searches",
 	"Regular expression" : "Regular expression" 
 });
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/outliner.js b/bundles/org.eclipse.orion.client.core/web/orion/outliner.js
index 125ada3..9d6f806 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/outliner.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/outliner.js
@@ -84,11 +84,11 @@
 	OutlineExplorer.prototype = mExplorer.Explorer.prototype;	
 	OutlineExplorer.prototype.constructor = OutlineExplorer;
 	
-	function OutlineModel(items) {
+	function OutlineModel(items, rootId) {
 		this.items = items;
 		this.root = {children: items};
+		this.root.outlinerId = rootId;
 		this.idItemMap = {};
-		this.specialIds = [];
 	}
 	OutlineModel.prototype.constructor = OutlineModel;
 	
@@ -100,23 +100,19 @@
 	};
 	
 	OutlineModel.prototype.getId = function(/* item */ item){
-		// first see if we have already generated an id because of a special case (duplicates)
-		// We hope this list remains relatively small, or we should consider a different implementation
-		// for mapping items back to their id.
-		for (var i=0; i<this.specialIds.length; i++) {
-			if (this.specialIds[i].item === item) {
-				return this.specialIds[i].id;
-			}
+		// Do we have a cached id?
+		if (item.outlinerId) {
+			return item.outlinerId;
 		}
-		// Generate an id.  This code is assuming that generating an id for an item is faster than if we kept an array
-		// of all id/item combinations.  Since these id's are used in the DOM, we strip out characters that shouldn't be in a DOM id.
+		// Generate an id.  Since these id's are used in the DOM, we strip out characters that shouldn't be in a DOM id.
 		var id = item.label.replace(/[\\\/\.\:\-\_]/g, "");
-		// We might have duplicate id's if the outline items are duplicated.  Check for this case and use a timestamp in lieu
-		// of the generated id.
-		if (this.idItemMap[id] && this.idItemMap[id]!== item) {
+		// We might have duplicate id's if the outline items are duplicated, or if we happen to have another dom id using
+		// this name.  Check for this case and use a timestamp in lieu of the generated id.
+		if ((this.idItemMap[id] && this.idItemMap[id]!== item) ||
+			dojo.byId(id)) {// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=389760
 			id = new Date().getTime().toString();
 			this.idItemMap[id] = item;
-			this.specialIds.push({id: id, item: item});
+			item.outlinerId = id;
 		} else {
 			this.idItemMap[id] = item;
 		}
@@ -134,6 +130,16 @@
 			onComplete([]);
 		}
 	};
+	
+	OutlineModel.prototype.doExpansions = function(tree) {
+		// for now, just expand the first level of the model
+		// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=389547
+		for (var i=0; i < this.root.children.length; i++) {
+			if (this.root.children[i].children) {
+				tree.expand(this.root.children[i]);
+			}
+		}
+	};
 
 
 
@@ -211,14 +217,10 @@
 			dojo.empty(contentNode);
 			outlineModel = outlineModel instanceof Array ? outlineModel : [outlineModel];
 			if (outlineModel) {
+				var treeModel = new OutlineModel(outlineModel);
 				this.explorer = new OutlineExplorer(this._serviceRegistry, this._selectionService, title);
-				this.explorer.createTree("outlineSectionContent", new OutlineModel(outlineModel), {selectionPolicy: "cursorOnly", setFocus: false}); //$NON-NLS-1$ //$NON-NLS-0$
-				// expand the first level of the model
-				for (var i=0; i < outlineModel.length; i++) {
-					if (outlineModel[i].children) {
-						this.explorer.myTree.expand(outlineModel[i]);
-					}
-				}
+				this.explorer.createTree("outlineSectionContent", treeModel, {selectionPolicy: "cursorOnly", setFocus: false}); //$NON-NLS-1$ //$NON-NLS-0$
+				treeModel.doExpansions(this.explorer.myTree);
 			}
 		},
 		_menuCallback: function() {
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/searchUtils.js b/bundles/org.eclipse.orion.client.core/web/orion/searchUtils.js
index b31ac59..d438bf0 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/searchUtils.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/searchUtils.js
@@ -10,7 +10,7 @@
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 
-define(['require', 'dojo', 'orion/editor/regex', 'orion/util'], function(require, dojo, mRegex, mUtil) {
+define(['require', 'dojo', 'orion/editor/regex', 'orion/util', 'orion/commands'], function(require, dojo, mRegex, mUtil, mCommands) {
 
 var orion = orion || {};
 
@@ -520,6 +520,76 @@
 	var tail = keepTailSlash ? 0: 1;
 	return filePath.substring(0, filePath.length-fileName.length-tail);
 };
-	
+
+var MAX_RECENT_SEARCH_NUMBER = 20;
+
+orion.searchUtils._storeRecentSearch = function(serviceRegistry, searches){
+	serviceRegistry.getService("orion.core.preference").getPreferences("/window/favorites").then(function(prefs) {  //$NON-NLS-1$ //$NON-NLS-0$
+		prefs.put("recentSearch", searches); //$NON-NLS-0$
+	});
+};
+
+orion.searchUtils.addRecentSearch = function(serviceRegistry, searchName){
+	if(typeof searchName !== "string" || !searchName ){
+		return;
+	}
+	serviceRegistry.getService("orion.core.preference").getPreferences("/window/favorites").then(function(prefs) {  //$NON-NLS-1$ //$NON-NLS-0$
+		var i;
+		var searches = prefs.get("recentSearch"); //$NON-NLS-0$
+		if (typeof searches === "string") { //$NON-NLS-0$
+			searches = JSON.parse(searches);
+		}
+		if (searches) {
+			var i;
+			for (i in searches) {
+				if (searches[i].name === searchName) {
+					return;
+				}
+			}
+			if(searches.length >= MAX_RECENT_SEARCH_NUMBER){
+				var len = searches.length;
+				searches.splice(MAX_RECENT_SEARCH_NUMBER-1, len-MAX_RECENT_SEARCH_NUMBER+1);
+			}
+		} else {
+			searches = [];
+		}
+		searches.splice(0,0,{ "name": searchName});//$NON-NLS-1$
+		orion.searchUtils._storeRecentSearch(serviceRegistry, searches);
+		//prefs.put("recentSearch", searches); //$NON-NLS-0$
+	});
+};
+
+orion.searchUtils.populateSearchMenu = function(serviceRegistry, choicesMenu, type, makeLabelFunc) {
+	// see http://bugs.dojotoolkit.org/ticket/10296
+	choicesMenu.focusedChild = null;
+	dojo.forEach(choicesMenu.getChildren(), function(child) {
+		choicesMenu.removeChild(child);
+		child.destroy();
+	});
+	orion.searchUtils.getSearches(serviceRegistry, type, function(searches){
+		if (searches) {
+			for (i in searches) {
+				choicesMenu.addChild(new mCommands.CommandMenuItem({
+					 label: makeLabelFunc(searches[i]),
+					 hasLink: true
+				}));
+			}
+		}
+	});
+};
+
+orion.searchUtils.getSearches = function(serviceRegistry, type, callback){
+	serviceRegistry.getService("orion.core.preference").getPreferences("/window/favorites").then(function(prefs) {  //$NON-NLS-1$ //$NON-NLS-0$
+		var i;
+		var searches = prefs.get(type); //$NON-NLS-0$
+		if (typeof searches === "string") { //$NON-NLS-0$
+			searches = JSON.parse(searches);
+		}
+		if (searches && callback) {
+			callback(searches);
+		}
+	});
+};
+
 return orion.searchUtils;
 });
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/sites/nls/root/messages.js b/bundles/org.eclipse.orion.client.core/web/orion/sites/nls/root/messages.js
index ce00d42..d4630ef 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/sites/nls/root/messages.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/sites/nls/root/messages.js
@@ -25,7 +25,7 @@
 	"Save the site configuration": "Save the site configuration",
 	"Choose folder&#8230;": "Choose folder&#8230;",
 	"Choose Orion Source Folder": "Choose Orion Source Folder",
-	"Select the folder where you checked out the ${0} repository:": "Select the folder where you checked out the ${0} repository:",
+	"SelectRepoSourceFolder": "Select the folder where you checked out the ${0} repository:",
 	"Loading...": "Loading...",
 	"Add": "Add",
 	"Add a directory mapping to the site configuration": "Add a directory mapping to the site configuration",
@@ -66,5 +66,6 @@
 	"Optional; used to determine the URL where a started site can be accessed." : "Optional; used to determine the URL where a started site can be accessed.",
 	"Changes you make here won't affect the running site." : "Changes you make here won't affect the running site.",
 	"Stopped" : "Stopped",
-	"Started at " : "Started at "
+	"Started at " : "Started at ",
+	"EnterPortNumber": "Enter the HTTP port number that the Orion server is running on (default is ${0}):"
 });
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/treetable.js b/bundles/org.eclipse.orion.client.core/web/orion/treetable.js
index bcd3f3d..58844cb 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/treetable.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/treetable.js
@@ -75,16 +75,16 @@
 			
 			// Generate the table
 			this._root = this._treeModel.getRoot(function (root) {
-				if (this._showRoot) {
+				if (tree._showRoot) {
 					root._depth = 0;
-					this._generate([root], 0);
+					tree._generate([root], 0);
 				}
 				else {
 					tree._treeModel.getChildren(root, function(children) {
 						tree._generate(children, 0);
 					});
 				}
-			}.bind(this));
+			});
 		},
 		
 		_generate: function(children, indentLevel) {
@@ -104,7 +104,7 @@
 		},
 		
 		_generateChildren: function(children, indentLevel, referenceNode, position) {
-			for (var i in children) {
+			for (var i=0; i<children.length; i++) {
 				var row = document.createElement(this._tableRowElement); //$NON-NLS-0$
 				row.id = this._treeModel.getId(children[i]);
 				row._depth = indentLevel;
@@ -221,7 +221,7 @@
 					tree._generateChildren(children, row._depth+1, row, "after"); //$NON-NLS-0$
 					tree._rowsChanged();
 					if (postExpandFunc) {
-						postExpandFunc.apply(this, args);
+						postExpandFunc.apply(tree, args);
 					}
 				});
 			}
@@ -251,7 +251,7 @@
 					}
 				}
 			});
-			for (var i in toRemove) {
+			for (var i=0; i<toRemove.length; i++) {
 				//table.removeChild(toRemove[i]); // IE barfs on this
 				var child = toRemove[i];
 				child.parentNode.removeChild(child);
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/widgets/DirectoryPrompterDialog.js b/bundles/org.eclipse.orion.client.core/web/orion/widgets/DirectoryPrompterDialog.js
index a1c9537..df9414e 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/widgets/DirectoryPrompterDialog.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/widgets/DirectoryPrompterDialog.js
@@ -39,11 +39,10 @@
 		}}
 	 */
 	 
-	dojo.declare("orion.widgets.DirectoryPrompterDialog", [ dijit.Dialog, orion.widgets._OrionDialogMixin ], { //$NON-NLS-0$
+	var DirectoryPrompterDialog = dojo.declare("orion.widgets.DirectoryPrompterDialog", [ dijit.Dialog, orion.widgets._OrionDialogMixin ], { //$NON-NLS-0$
 		widgetsInTemplate : true,
 		templateString : dojo.cache('orion', 'widgets/templates/DirectoryPrompterDialog.html'), //$NON-NLS-1$ //$NON-NLS-0$
 		constructor : function() {
-			this.inherited(arguments);
 			this.options = arguments[0] || {};
 		},
 		
@@ -83,4 +82,5 @@
 			}.bind(this));
 		}
 	});
+	return DirectoryPrompterDialog;
 });
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/widgets/SiteEditor.js b/bundles/org.eclipse.orion.client.core/web/orion/widgets/SiteEditor.js
index 0d42c0b..198af7a 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/widgets/SiteEditor.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/widgets/SiteEditor.js
@@ -9,13 +9,67 @@
  * Contributors: IBM Corporation - initial API and implementation

  ******************************************************************************/

 /*global define orion*/

-/*jslint browser:true */

+/*jslint browser:true sub:true*/

 

-define(['i18n!orion/sites/nls/messages', 'require', 'dojo', 'dijit', 'orion/commands', 'orion/section', 'orion/sites/siteMappingsTable',

-		'orion/widgets/DirectoryPrompterDialog', 'text!orion/widgets/templates/SiteEditor.html',

-		'dojo/DeferredList', 'dijit/layout/ContentPane', 'dijit/Tooltip', 'dijit/_Templated',

-		'dijit/form/Form', 'dijit/form/TextBox', 'dijit/form/ValidationTextBox'],

-		function(messages, require, dojo, dijit, mCommands, mSection, mSiteMappingsTable) {

+define(['i18n!orion/sites/nls/messages', 'i18n!orion/widgets/nls/messages', 'require', 'dojo', 'dijit', 'orion/commands', 'orion/section',

+	'orion/sites/siteMappingsTable', 'orion/i18nUtil', 'orion/widgets/DirectoryPrompterDialog', 'dijit/Dialog',

+	'orion/widgets/_OrionDialogMixin',

+	'text!orion/widgets/templates/SiteEditor.html',

+	'dojo/DeferredList', 'dijit/layout/ContentPane', 'dijit/Tooltip', 'dijit/_Templated',

+	'dijit/form/Form', 'dijit/form/TextBox', 'dijit/form/ValidationTextBox'],

+	function(messages, widgetsMessages, require, dojo, dijit, mCommands, mSection, mSiteMappingsTable, i18nUtil, DirectoryPrompterDialog,

+		Dialog, _OrionDialogMixin) {

+

+var ConvertToSelfHostingDialog = dojo.declare("orion.widgets.ConvertToSelfHostDialog", [Dialog, _OrionDialogMixin], {

+	DEFAULT_PORT: 8080,

+	widgetsInTemplate: true,

+	templateString: dojo.cache('orion', 'widgets/templates/ConvertToSelfHostingDialog.html'), //$NON-NLS-1$ //$NON-NLS-0$

+

+	constructor: function(options) {

+		this.options = options || {};

+	},

+	postMixInProperties: function() {

+		this.options.title = messages['Convert to Self-Hosting']; //$NON-NLS-1$

+		this.message = i18nUtil.formatMessage(messages["SelectRepoSourceFolder"], ["<b>org.eclipse.orion.client</b>"]); //$NON-NLS-1$ //$NON-NLS-0$

+		this.browseMessage = widgetsMessages['Browse...']; //$NON-NLS-1$

+		this.portMessage = i18nUtil.formatMessage(messages["EnterPortNumber"], this.DEFAULT_PORT); //$NON-NLS-1$

+		this.inherited(arguments);

+	},

+	postCreate: function() {

+		this.inherited(arguments);

+		dojo.connect(this.browseButton, 'click', function() { //$NON-NLS-1$

+			var dialog = new DirectoryPrompterDialog({

+				title: messages["Choose Orion Source Folder"], //$NON-NLS-1$

+				serviceRegistry: this.serviceRegistry,

+				fileClient: this.fileClient,

+				func: this.onFolderChosen.bind(this)

+			});

+			dialog.startup();

+			dialog.show();

+		}.bind(this));

+		dojo.connect(this.port, 'onchange', function() { //$NON-NLS-1$

+			this.portNumber = parseInt(this.port.value, 10);

+			this.validate();

+		}.bind(this));

+		this.portNumber = this.port.value = this.DEFAULT_PORT;

+		this.validate();

+	},

+	onFolderChosen: function(folder) {

+		this.folder = folder;

+		this.folderText.textContent = folder ? folder.Name : ''; //$NON-NLS-1$

+		this.validate();

+	},

+	validate: function() {

+		var isValid = (this.folder && !isNaN(this.portNumber) && this.portNumber > 0);

+		this.okButton.set('disabled', !isValid); //$NON-NLS-1$

+	},

+	execute: function() {

+		this.onHide();

+		if (typeof this.options.func === 'function') { //$NON-NLS-1$

+			this.options.func(this.folder, this.portNumber);

+		}

+	}

+});

 

 var AUTOSAVE_INTERVAL = 8000;

 var ROOT = "/"; //$NON-NLS-0$

@@ -25,7 +79,7 @@
  * @class Editor for an individual site configuration.

  * @param {Object} options Options bag for creating the widget.

  */

-dojo.declare("orion.widgets.SiteEditor", [dijit.layout.ContentPane, dijit._Templated], { //$NON-NLS-0$

+var SiteEditor = dojo.declare("orion.widgets.SiteEditor", [dijit.layout.ContentPane, dijit._Templated], { //$NON-NLS-0$

 	widgetsInTemplate: true,

 	templateString: dojo.cache('orion', 'widgets/templates/SiteEditor.html'), //$NON-NLS-1$ //$NON-NLS-0$

 

@@ -169,7 +223,7 @@
 			name: messages["Choose folder&#8230;"],

 			imageClass: "core-sprite-folder", //$NON-NLS-0$

 			callback: dojo.hitch(this, function() {

-				var dialog = new orion.widgets.DirectoryPrompterDialog({

+				var dialog = new DirectoryPrompterDialog({

 					serviceRegistry: this.serviceRegistry,

 					fileClient: this.fileClient,

 					func: dojo.hitch(this, function(folder) {

@@ -188,24 +242,22 @@
 	},

 

 	// Special feature for setting up self-hosting

-	// TODO ideally this command would be defined entirely by a plugin. It is here because of the DirectoryPrompter dependency

+	// TODO ideally this logic would be defined entirely by a plugin. It is here because of the dialog (UI) dependency

 	convertToSelfHostedSite: function(items, userData) {

-		var dialog = new orion.widgets.DirectoryPrompterDialog({

+		var self = this;

+		var dialog = new ConvertToSelfHostingDialog({

 			serviceRegistry: this.serviceRegistry,

 			fileClient: this.fileClient,

-			func: dojo.hitch(this, function(folder) {

-				if (folder) {

-					var self = this;

-					this._siteClient.convertToSelfHosting(this.getSiteConfiguration(), folder.Location).then(

-						function(updatedSite) {

-							self.mappings.deleteAllMappings();

-							self.mappings.addMappings(updatedSite.Mappings);

-							self.save();

-						});

-				}

-			}),

-			title: messages["Choose Orion Source Folder"],

-			message: dojo.string.substitute(messages["Select the folder where you checked out the ${0} repository:"], ["<b>org.eclipse.orion.client</b>"])}); //$NON-NLS-1$

+			siteClient: this._siteClient,

+			func: function(folder, port) {

+				self._siteClient.convertToSelfHosting(self.getSiteConfiguration(), folder.Location, port).then(

+					function(updatedSite) {

+						self.mappings.deleteAllMappings();

+						self.mappings.addMappings(updatedSite.Mappings);

+						self.save();

+					});

+			}

+		});

 		dialog.startup();

 		dialog.show();

 	},

@@ -444,4 +496,5 @@
 	onError: function(deferred) {

 	}

 });

+	return SiteEditor;

 });

diff --git a/bundles/org.eclipse.orion.client.core/web/orion/widgets/_OrionDialogMixin.js b/bundles/org.eclipse.orion.client.core/web/orion/widgets/_OrionDialogMixin.js
index e326bd0..6b7fc0c 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/widgets/_OrionDialogMixin.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/widgets/_OrionDialogMixin.js
@@ -17,7 +17,7 @@
 
 define(['i18n!orion/widgets/nls/messages', 'dojo', 'dijit'], function(messages, dojo, dijit) {
 
-dojo.declare("orion.widgets._OrionDialogMixin", null, { //$NON-NLS-0$
+var _OrionDialogMixin = dojo.declare("orion.widgets._OrionDialogMixin", null, { //$NON-NLS-0$
 	postMixInProperties : function() {
 		this.inherited(arguments);
 		this.title = this.options.title || messages["Information Needed"];
@@ -48,5 +48,5 @@
 		}), this.duration);   
 	}
 });
-
+	return _OrionDialogMixin;
 });
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/widgets/templates/ConvertToSelfHostingDialog.html b/bundles/org.eclipse.orion.client.core/web/orion/widgets/templates/ConvertToSelfHostingDialog.html
new file mode 100644
index 0000000..e70582d
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.core/web/orion/widgets/templates/ConvertToSelfHostingDialog.html
@@ -0,0 +1,65 @@
+<div class="dijitDialog" tabindex="-1" waiRole="dialog" waiState="labelledby-${id}_title">
+	<div data-dojo-attach-point="titleBar" class="dijitDialogTitleBar">
+		<span data-dojo-attach-point="titleNode" class="dijitDialogTitle" id="${id}_title"></span>
+		<span data-dojo-attach-point="closeButtonNode" class="dijitDialogCloseIcon" dojoAttachEvent="onclick: onCancel" title="${buttonCancel}">
+			<span data-dojo-attach-point="closeText" class="closeText" title="${buttonCancel}">x</span>
+		</span>
+	</div>
+	<style>
+	.form {
+		width: auto;
+		list-style-type: none; 
+		padding: 0; 
+		margin: 0;
+		-webkit-padding-start: 0;
+		-webkit-margin-before: 0;
+	}
+	.form li {
+		margin: 0;
+	}
+	.msg {
+		clear: both;
+		width: 25em;
+	}
+	.pad1 { padding: 8px 0 0 0; }
+	.pad2 { padding: 20px 0 0 0; }
+	.field {
+		float: left;
+		width: 6em;
+	}
+	.col { float: left; }
+	.okButton {
+		float: right;
+		clear: both;
+	}
+	</style>
+	<div data-dojo-attach-point="containerNode" class="dijitDialogPaneContent">
+		<!-- Actual content here -->
+		<ul class="form">
+			<li class="msg">
+				<div>${message}</div>
+			</li>
+			<li class="pad1">
+				<div class="col">
+					<button data-dojo-attach-point="browseButton" id="${id}_browseButton"
+						class="commandButton">${browseMessage}</button>
+					<span data-dojo-attach-point="folderText"></span>
+				</div>
+			</li>
+			<li class="msg pad2">
+				<div>${portMessage}</div>
+			</li>
+			<li class="pad1">
+				<input class="field" data-dojo-attach-point="port" id="${id}_port" type="number" />
+			</li>
+			<li class="msg">
+				<button data-dojo-attach-point="okButton" 
+					data-dojo-type="dijit.form.Button"
+					value="OK"
+					data-dojo-props="class:'okButton', type: 'submit'">
+				${buttonOk}
+				</button>
+			</li>
+		</ul>
+	</div> <!-- content pane -->
+</div>
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/widgets/themes/editor/ThemeData.js b/bundles/org.eclipse.orion.client.core/web/orion/widgets/themes/editor/ThemeData.js
index 2918a2f..14ab253 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/widgets/themes/editor/ThemeData.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/widgets/themes/editor/ThemeData.js
@@ -46,7 +46,7 @@
 			orion.annotationRuler = 'white'; 

 			orion.background = 'white';

 			orion.comment = 'green';

-			orion.keyword = 'darkRed';

+			orion.keyword = '#7f0055';

 			orion.text = '#333';

 			orion.string = 'blue';

 			orion.overviewRuler = 'white';

@@ -86,7 +86,6 @@
 			blue.lineNumberEven = '#333';

 			blue.lineNumber = '#333';

 			

-			

 			this.styles.push( blue );

 			

 			var ambience = new StyleSet();

@@ -103,9 +102,40 @@
 			ambience.lineNumberEven = 'black';

 			ambience.lineNumber = 'black';

 			

-			

 			this.styles.push( ambience );

 			

+			var tierra = new StyleSet();

+			

+			tierra.name = 'tierra';

+			tierra.annotationRuler = 'moccasin'; 

+			tierra.background = 'lemonchiffon';

+			tierra.comment = 'darkseagreen';

+			tierra.keyword = 'darkred';

+			tierra.text = 'darkseagreen';

+			tierra.string = 'orangered';

+			tierra.overviewRuler = 'moccasin';

+			tierra.lineNumberOdd = 'chocolate';

+			tierra.lineNumberEven = 'chocolate';

+			tierra.lineNumber = 'chocolate';

+			

+			this.styles.push( tierra );

+			

+			var nimbus = new StyleSet();

+			

+			nimbus.name = 'nimbus';

+			nimbus.annotationRuler = '#444'; 

+			nimbus.background = 'dimgray';

+			nimbus.comment = 'darkseagreen';

+			nimbus.keyword = 'darkorange';

+			nimbus.text = 'white';

+			nimbus.string = 'cornflowerblue';

+			nimbus.overviewRuler = '#444';

+			nimbus.lineNumberOdd = '#aaa';

+			nimbus.lineNumberEven = '#aaa';

+			nimbus.lineNumber = '#aaa';

+			

+			this.styles.push( nimbus );

+			

 		}

 		

 		function getStyles(){

diff --git a/bundles/org.eclipse.orion.client.core/web/plugins/site/siteServiceImpl.js b/bundles/org.eclipse.orion.client.core/web/plugins/site/siteServiceImpl.js
index ea4fd57..c276b83 100644
--- a/bundles/org.eclipse.orion.client.core/web/plugins/site/siteServiceImpl.js
+++ b/bundles/org.eclipse.orion.client.core/web/plugins/site/siteServiceImpl.js
@@ -91,9 +91,8 @@
 			return this.projects[workspaceId];
 		};
 	}
-	function getSelfHostingMappings(basePath) {
-		// TODO: prompt for port? It is not detectable from client side if proxy is used
-		var hostPrefix = "http://localhost" + ":" + "8080" + makeHostRelative(getContext());
+	function getSelfHostingMappings(basePath, port) {
+		var hostPrefix = "http://localhost" + ":" + port + makeHostRelative(getContext());
 		return [
 			["/", basePath + "/bundles/org.eclipse.orion.client.core/web/index.html"],
 			["/", basePath + "/bundles/org.eclipse.orion.client.core/web"],
@@ -312,9 +311,9 @@
 				});
 			});
 		},
-		convertToSelfHosting: function(site, selfHostfileLocation) {
+		convertToSelfHosting: function(site, selfHostfileLocation, port) {
 			var internalPath = this.toInternalForm(selfHostfileLocation);
-			var mappings = getSelfHostingMappings(internalPath);
+			var mappings = getSelfHostingMappings(internalPath, port);
 			site.Mappings = mappings;
 			return site;
 		},