docs: function generateBanner(parentId, serviceRegistry, commandRegistry, prefsService, searcher, handler, /* optional */ editor, closeSplitter, fileClient) {
  		serviceRegistry.registerService("orion.metrics", {
  			/** @callback */
  			logEvent: function(category, action, label, value) {
  			},
  			logTiming: function(timingCategory, timingVar, timingValue, timingLabel) {
  				if (timingCategory === "page" && timingVar === "complete") {
  					var pageLoader = require.defined("orion/splash") && require("orion/splash").getPageLoader();
  					if (pageLoader) pageLoader.takeDown();
  				}
  				if (localStorage.consoleMetrics) {
  					window.console.log(timingCategory + " " + timingVar + " " + timingValue + " " + timingLabel);
  				}
  			},
  			/** @callback */
  			pageLoad: function(href, page, title, args) {
  			}
  		}, {});
  		var metrics = new mMetrics.Metrics(serviceRegistry);
  		prefsService.addChangeListener(function(name, value) {
  			if (value.length < METRICS_MAXLENGTH && name.indexOf("/git/credentials/") !== 0) { //$NON-NLS-0$
  				metrics.logEvent("preferenceChange", name, value); //$NON-NLS-0$
  			}
  		});
  		window.addEventListener("error", function(e) {
  			var index = e.filename.lastIndexOf("/");
  			var filename = e.filename.substring(index + 1);
  			if (filename) {
  				var errorString = e.message + " (" + filename + ": " + e.lineno + (e.colno ? ", " + e.colno : "") + ")"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
  				metrics.logEvent("runtime", "uncaughtError", errorString); //$NON-NLS-1$ //$NON-NLS-0$
  			} else {
  				errorString = e.message + " (" + e.filename + ": " + e.lineno + (e.colno ? ", " + e.colno : "") + ")"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
  				metrics.logEvent("runtime", "uncaughtErrorUnknownFile", errorString); //$NON-NLS-1$ //$NON-NLS-0$
  			}
  
  			if (e.error) {
  				var stackString = e.error.stack.replace(new RegExp(window.location.origin, "g"), "");
  				metrics.logEvent("runtime", "uncaughtErrorStack", stackString); //$NON-NLS-1$ //$NON-NLS-0$
  			}
  		});
  
  		var themeVal = localStorage.getItem("pageTheme");
  		if (themeVal && typeof themeVal === "string" || themeVal instanceof String && themeVal.length > 0) {
  			themeVal.split(" ").forEach(function(clazz) {
  				if (!document.body.classList.contains(clazz)) {
  					document.body.classList.add(clazz);
  				}
  			});
  		}
  		
  		// forward the preference service on to the command registry
  		commandRegistry.setServiceRegistry(serviceRegistry);
  
  		new mThemePreferences.ThemePreferences(prefsService, new mThemeData.ThemeData(serviceRegistry)).apply();
  
  		var parent = lib.node(parentId);
  
  		if (!parent) {
  			throw i18nUtil.formatMessage("could not find banner parent, id was ${0}", parentId);
  		}
  		// place the HTML fragment for the header.
  		new Banner().create(parent);
  		
  		// TODO not entirely happy with this. Dynamic behavior that couldn't be in the html template, maybe it could be
  		// dynamically bound in a better way like we do with NLS strings
  		var home = lib.node("home"); //$NON-NLS-0$
  		if (home) {
  			home.href = require.toUrl("edit/edit.html"); //$NON-NLS-0$
  			home.setAttribute("aria-label", messages['Orion Home']); //$NON-NLS-1$ //$NON-NLS-0$
  		}
  
  		var toolbar = lib.node("pageToolbar"); //$NON-NLS-0$
  		if (toolbar) {
  			toolbar.setAttribute("aria-label", messages.toolbar); //$NON-NLS-1$
  			toolbar.classList.add("toolbarLayout"); //$NON-NLS-0$
  			toolbar.innerHTML = ToolbarTemplate + commonHTML.slideoutHTMLFragment("mainToolbar"); //$NON-NLS-0$
  		}
  		var closeNotification = lib.node("closeNotifications"); //$NON-NLS-0$
  		if (closeNotification) {
  			closeNotification.setAttribute("aria-label", messages['Close notification']); //$NON-NLS-1$ //$NON-NLS-0$
  		}
  
  		//Hack for FF17 Bug#415176
  		if (util.isFirefox <= 17) {
  			var staticBanner = lib.node("staticBanner"); //$NON-NLS-0$
  			if (staticBanner) {
  				staticBanner.style.width = "100%"; //$NON-NLS-0$
  				staticBanner.style.MozBoxSizing = "border-box"; //$NON-NLS-0$
  			}
  		}
  
  		var footer = lib.node("footer"); //$NON-NLS-0$
  		if (footer && FooterTemplate) {
  			footer.innerHTML = FooterTemplate;
  			// do the i18n string substitutions
  			lib.processTextNodes(footer, messages);
  			var sideMenuNode = lib.node("sideMenu"); //$NON-NLS-0$
  			if (sideMenuNode) {
  				sideMenuNode.classList.add("content-fixedHeight-withFooter");
  			}
  			var content = lib.$(".content-fixedHeight"); //$NON-NLS-0$
  			if (content) {
  				content.classList.add("content-fixedHeight-withFooter");
  			}
  			footer.classList.add("footer-visible");
  		}
  
  		// Set up a custom parameter collector that slides out of adjacent tool areas.
  		commandRegistry.setParameterCollector(new mParameterCollectors.CommandParameterCollector(getToolbarElements, layoutToolbarElements));
  
  		document.addEventListener("keydown", function (e) {
  			if (e.keyCode === lib.KEY.ESCAPE) {
  				var statusService = serviceRegistry.getService("orion.page.message"); //$NON-NLS-0$
  				if (statusService) {
  					statusService.setProgressMessage("");
  				}
  			}
  		}, false);
  
  		customGlobalCommands.generateNavigationMenu.apply(this, arguments);
  		customGlobalCommands.afterGenerateNavigationMenu.apply(this, arguments);
  
  		// generate primary nav links.
  		var categoriesPromise = PageLinks.getCategoriesInfo(serviceRegistry);
  		var pageLinksPromise = PageLinks.getPageLinksInfo(serviceRegistry, "orion.page.link");
  		Deferred.all([ categoriesPromise, pageLinksPromise ]).then(function(results) {
  			if (this.sideMenu) {
  				var categoriesInfo = results[0], pageLinksInfo = results[1];
  				this.sideMenu.setCategories(categoriesInfo);
  				this.sideMenu.setPageLinks(pageLinksInfo);
  
  				// Now we have enough to show the sidemenu with its close-to-final layout
  				this.sideMenu.render();
  			}
  		}.bind(this));
  
  		// hook up split behavior - the splitter widget and the associated global command/key bindings.
  		var splitNode = lib.$(".split"); //$NON-NLS-0$
  		if (splitNode) {
  			var side = lib.$(".sidePanelLayout"); //$NON-NLS-0$
  			var main = lib.$(".mainPanelLayout"); //$NON-NLS-0$
  			if (side && main) {
  				mainSplitter = {
  					side: side,
  					main: main
  				};
  				mainSplitter.splitter = new mSplitter.Splitter({
  					node: splitNode,
  					sidePanel: side,
  					mainPanel: main,
  					toggle: true,
  					closeByDefault: closeSplitter
  				});
  				var toggleSidePanelCommand = new mCommands.Command({
  					name: messages["Toggle Side Panel"],
  					tooltip: messages["Open or close the side panel"],
  					id: "orion.toggleSidePane", //$NON-NLS-0$
  					callback: function () {
  						mainSplitter.splitter.toggleSidePanel();
  					}
  				});
  				commandRegistry.addCommand(toggleSidePanelCommand);
  				commandRegistry.registerCommandContribution("pageActions", "orion.toggleSidePane", 1, null, true, new KeyBinding.KeyBinding('l', util.isMac ? false : true, true, false, util.isMac ? true : false)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
  			}
  		}
  
  		// Assemble global commands, those that could be available from any page due to header content or common key bindings.
  
  		// open resource
  		var showingResourceDialog = false;
  		var openResourceDialog = function (searcher, serviceRegistry, commandRegistry) {
  			if (showingResourceDialog) {
  				return;
  			}
  			var progress = serviceRegistry.getService("orion.page.progress"); //$NON-NLS-0$
  			var prefs = serviceRegistry.getService("orion.core.preference"); //$NON-NLS-0$
  			var dialog = new openResource.OpenResourceDialog({
  				searcher: searcher,
  				progress: progress,
  				prefService: prefs,
  				serviceRegistry: serviceRegistry,
  				commandRegistry: commandRegistry,
  				searchRenderer: searcher.defaultRenderer,
  				onHide: function () {
  					showingResourceDialog = false;
  				}
  			});
  			window.setTimeout(function () {
  				showingResourceDialog = true;
  				dialog.show();
  			}, 0);
  		};
  
  		var openResourceCommand = new mCommands.Command({
  			name: messages["FindFile"],
  			tooltip: messages["ChooseFileOpenEditor"],
  			id: "orion.openResource", //$NON-NLS-0$
  			callback: function (data) {
  				openResourceDialog(searcher, serviceRegistry, commandRegistry);
  			}
  		});
  
  		commandRegistry.addCommand(openResourceCommand);
  		commandRegistry.registerCommandContribution("globalActions", "orion.openResource", 100, null, true, new KeyBinding.KeyBinding('f', true, true)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
  		var noBanner = false;
  		var toggleBannerFunc = function () {
  			if (noBanner) {
  				return false;
  			}
  			var header = lib.node("banner"); //$NON-NLS-0$
  			var footer = lib.node("footer"); //$NON-NLS-0$
  			var sideMenuNode = lib.node("sideMenu"); //$NON-NLS-0$
  			var content = lib.$(".content-fixedHeight"); //$NON-NLS-0$
  			var maximized = header.classList.contains("banner-maximized"); //$NON-NLS-0$
  			if (maximized) {
  				header.classList.remove("banner-maximized"); //$NON-NLS-0$
  				footer.classList.remove("footer-maximized"); //$NON-NLS-0$
  				content.classList.remove("content-fixedHeight-maximized"); //$NON-NLS-0$
  				if (sideMenuNode) {
  					sideMenuNode.classList.remove("sideMenu-maximized"); //$NON-NLS-0$
  				}
  			} else {
  				header.classList.add("banner-maximized"); //$NON-NLS-0$
  				footer.classList.add("footer-maximized"); //$NON-NLS-0$
  				content.classList.add("content-fixedHeight-maximized"); //$NON-NLS-0$
  				if (sideMenuNode) {
  					sideMenuNode.classList.add("sideMenu-maximized"); //$NON-NLS-0$
  				}
  			}
  			getGlobalEventTarget().dispatchEvent({type: "toggleTrim", maximized: !maximized}); //$NON-NLS-0$
  			return true;
  		};
  
  
  		var noTrim = window.orionNoTrim || localStorage.orionNoTrim || false;
  		if (noTrim) {
  			toggleBannerFunc();
  			noBanner = true;
  			if (noTrim !== "bannerOnly") this.sideMenu.hide();
  		} else {
  			// Toggle trim command
  			var toggleBanner = new mCommands.Command({
  				name: messages["Toggle Banner and Footer"],
  				tooltip: messages["HideShowBannerFooter"],
  				id: "orion.toggleTrim", //$NON-NLS-0$
  				callback: toggleBannerFunc
  			});
  			commandRegistry.addCommand(toggleBanner);
  			commandRegistry.registerCommandContribution("globalActions", "orion.toggleTrim", 100, null, true, new KeyBinding.KeyBinding("m", true, true)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
  
  			// Open configuration page, Ctrl+Shift+F1
  			var configDetailsCommand = new mCommands.Command({
  				name: messages["System Configuration Details"],
  				tooltip: messages["System Config Tooltip"],
  				id: "orion.configDetailsPage", //$NON-NLS-0$
  				hrefCallback: function () {
  					return require.toUrl("about/about.html"); //$NON-NLS-0$
  				}
  			});
  
  			commandRegistry.addCommand(configDetailsCommand);
  			commandRegistry.registerCommandContribution("globalActions", "orion.configDetailsPage", 100, null, true, new KeyBinding.KeyBinding(112, true, true, true)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
  
  			// Background Operations Page, Ctrl+Shift+O
  			var operationsCommand = new mCommands.Command({
  				name: messages["Background Operations"],
  				tooltip: messages["Background Operations Tooltip"],
  				id: "orion.backgroundOperations", //$NON-NLS-0$
  				hrefCallback: function () {
  					return require.toUrl("operations/list.html"); //$NON-NLS-0$
  				}
  			});
  
  			commandRegistry.addCommand(operationsCommand);
  			commandRegistry.registerCommandContribution("globalActions", "orion.backgroundOperations", 100, null, true, new KeyBinding.KeyBinding('o', true, true)); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
  
  			var showTooltipCommand = new mCommands.Command({
  				name: editMessages.showTooltip,
  				tooltip: editMessages.showTooltipTooltip,
  				id: "orion.edit.showTooltip", //$NON-NLS-0$
  				visibleWhen: /** @callback */ function(items, data) {
  					return true;
  				},
  				callback: function() {
  					var domFocus = document.activeElement, label, tooltip;
  					if (this.editor && this.editor._domNode.contains(domFocus)) {
  						var editor = this.editor;
  						tooltip = editor.getTooltip();
  						var tv = editor.getTextView();
  						var offset = tv.getCaretOffset();
  						var pos = tv.getLocationAtOffset(offset);
  						tooltip.show({
  							x: pos.x,
  							y: pos.y,
  							getTooltipInfo: function() {
  								return editor._getTooltipInfo(this.x, this.y);
  							}
  						}, false, true);
  					} else if (domFocus.commandTooltip || domFocus.tooltip) {
  						tooltip = domFocus.commandTooltip ? domFocus.commandTooltip : domFocus.tooltip;
  						tooltip._showByKB = true;
  						tooltip.show(0);
  					} else if (domFocus.id && (label = document.querySelector("label[for=" + domFocus.id.replace(/./g, "\\.") + "]")) && label.tooltip) {
  						tooltip = label.tooltip;
  						tooltip._showByKB = true;
  						tooltip.show(0);
  					}
  				}
  			});
  			commandRegistry.addCommand(showTooltipCommand);
  			commandRegistry.registerCommandContribution("globalActions" , "orion.edit.showTooltip", 1, null, true, new KeyBinding.KeyBinding(112, false, true), null, this);//$NON-NLS-1$
  
  			var focusNextSplitter = new mCommands.Command({
  				name: messages.nextSplitter,
  				tooltip: messages.nextSplitterTooltip,
  				id: "orion.focusSplitter", //$NON-NLS-0$
  				visibleWhen: /** @callback */ function(items, data) {
  					return true;
  				},
  				callback: function() {
  					var curFocus = document.activeElement;
  					
  					var items = lib.$$array(".split", document.body, true); //$NON-NLS-0$
  					if (items.length > 0) {
  						var theSplitter = items[0];
  						
  						// Filter out invisible splitters
  						for (var j = 0; j < items.length; j++) {
  							if (!items[j].offsetParent) {
  								items.slice(items[j], 1);
  							}
  						}
  							
  						for (var i = 0; i < items.length; i++) {
  							var splitter = items[i];
  							// If a splitter is the current focus then we choose the next one..
  							if (splitter === curFocus) {
  								if (i < items.length-1) {
  									theSplitter = items[i+1];
  									break;
  								}
  							}
  						}
  						
  						theSplitter.tabIndex = "0"; // Allow the splitter to take focus
  						theSplitter.focus();
  					}
  				}
  			});
  			commandRegistry.addCommand(focusNextSplitter);
  			commandRegistry.registerCommandContribution("globalActions" , "orion.focusSplitter", 1, null, true, new KeyBinding.KeyBinding(190, true, true), null, this);//$NON-NLS-1$
  
  			// Key assist
  			keyAssist = new mKeyAssist.KeyAssistPanel({
  				commandRegistry: commandRegistry
  			});
  			var keyAssistCommand = mKeyAssist.createCommand(keyAssist, "globalActions", commandRegistry);
  
  			renderGlobalCommands(commandRegistry);
  
  			generateUserInfo(serviceRegistry, keyAssistCommand.callback, prefsService);
  		}
  
  
  		// now that footer containing progress pane is added
  		startProgressService(serviceRegistry);
  
  		// check for commands in the hash
  		window.addEventListener("hashchange", function () {
  			commandRegistry.processURL(window.location.href);
  		}, false);
  		
  	    // System Editor
  		if (util.isElectron) {
  			serviceRegistry.registerService("orion.navigate.command", {
  				run: function(item) {
  					prefsService.get("/workspace").then(function(prefs) {
  						var workspaceDir = prefs.currentWorkspace.replace(/\\/g, "/");
  						window.__electron.shell.openItem(workspaceDir+item[0].Location.slice(5)); // slice off '/file'
  					});
  				}
  			}, {
  				name: messages["Orion System Editor"],
  				id: "orion.system.editor",
  				tooltip: messages["System Editor Tooltip"]
  			});
  		}
  
  		return customGlobalCommands.afterGenerateBanner.apply(this, arguments);
  	}