incubator-cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bfede...@apache.org
Subject [25/50] [abbrv] Moved console-proxy into services
Date Wed, 13 Feb 2013 22:04:21 GMT
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/4869f0ca/services/console-proxy/server/js/ajaxviewer.js
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/js/ajaxviewer.js b/services/console-proxy/server/js/ajaxviewer.js
new file mode 100644
index 0000000..e95615d
--- /dev/null
+++ b/services/console-proxy/server/js/ajaxviewer.js
@@ -0,0 +1,1444 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+ 
+  http://www.apache.org/licenses/LICENSE-2.0
+ 
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+var g_logger;
+
+/////////////////////////////////////////////////////////////////////////////
+// class StringBuilder
+//
+function StringBuilder(initStr) {
+    this.strings = new Array("");
+    this.append(initStr);
+}
+
+StringBuilder.prototype = {
+	append : function (str) {
+	    if (str) {
+	        this.strings.push(str);
+	    }
+	    return this;
+	},
+	
+	clear : function() {
+	    this.strings.length = 1;
+	    return this;
+	},
+	
+	toString: function() {
+	    return this.strings.join("");
+	}
+};
+
+
+function getCurrentLanguage() {
+	if(acceptLanguages) {
+		var tokens = acceptLanguages.split(',');
+		if(tokens.length > 0)
+			return tokens[0];
+		
+		return "en-us";
+	} else {
+		return "en-us";
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// class KeyboardMapper
+//
+function KeyboardMapper() {
+	this.mappedInput = [];
+	this.jsX11KeysymMap = [];
+	this.jsKeyPressX11KeysymMap = [];
+}
+
+//
+// RAW keyboard
+// 		Primarily translates KeyDown/KeyUp event, either as is (if there is no mapping entry)
+// 		or through mapped result.
+//
+// 		For KeyPress event, it translates it only if there exist a mapping entry
+// 		in jsX11KeysymMap map and the entry meets the condition
+// 
+// COOKED keyboard
+//		Primarily translates KeyPress event, either as is or through mapped result
+//		It translates KeyDown/KeyUp only there exists a mapping entry, or if there
+//		is no mapping entry, translate when certain modifier key is pressed (i.e., 
+//		CTRL or ALT key
+//
+// Mapping entry types
+//		direct		:	will be directly mapped into the entry value with the same event type
+//		boolean		:	only valid for jsX11KeysymMap, existence of this type, no matter true or false
+//						in value, corresponding KeyDown/KeyUp event will be masked
+//		array		:	contains a set of conditional mapping entry
+//		
+// Conditional mapping entry
+//
+//		{ 
+//			type: <event type>, code: <mapped key code>, modifiers: <modifiers>,
+//		  	shift : <shift state match condition>,		-- match on shift state
+//			guestos : <guest os match condition>,		-- match on guestos type
+//			browser: <browser type match condition>,	-- match on browser
+//			browserVersion: <brower version match condition>	-- match on browser version
+//		}
+//
+KeyboardMapper.KEYBOARD_TYPE_RAW = 0;
+KeyboardMapper.KEYBOARD_TYPE_COOKED = 1;
+
+KeyboardMapper.prototype = {
+		
+	setKeyboardType : function(keyboardType) {
+		this.keyboardType = keyboardType;
+		
+		if(keyboardType == KeyboardMapper.KEYBOARD_TYPE_RAW) {
+			// intialize keyboard mapping for RAW keyboard
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_CAPSLOCK] 		= AjaxViewer.X11_KEY_CAPSLOCK;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_BACKSPACE] 		= AjaxViewer.X11_KEY_BACKSPACE;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_TAB]			= AjaxViewer.X11_KEY_TAB;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ENTER] 			= AjaxViewer.X11_KEY_ENTER;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ESCAPE] 			= AjaxViewer.X11_KEY_ESCAPE;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_INSERT] 			= AjaxViewer.X11_KEY_INSERT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DELETE] 			= AjaxViewer.X11_KEY_DELETE;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_HOME] 			= AjaxViewer.X11_KEY_HOME;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_END] 			= AjaxViewer.X11_KEY_END;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_PAGEUP] 			= AjaxViewer.X11_KEY_PAGEUP;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_PAGEDOWN] 		= AjaxViewer.X11_KEY_PAGEDOWN;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_LEFT] 			= AjaxViewer.X11_KEY_LEFT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_UP] 			= AjaxViewer.X11_KEY_UP;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_RIGHT] 			= AjaxViewer.X11_KEY_RIGHT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DOWN] 			= AjaxViewer.X11_KEY_DOWN;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F1] 				= AjaxViewer.X11_KEY_F1;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F2] 				= AjaxViewer.X11_KEY_F2;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F3] 				= AjaxViewer.X11_KEY_F3;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F4] 				= AjaxViewer.X11_KEY_F4;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F5] 				= AjaxViewer.X11_KEY_F5;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F6] 				= AjaxViewer.X11_KEY_F6;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F7] 				= AjaxViewer.X11_KEY_F7;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F8] 				= AjaxViewer.X11_KEY_F8;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F9] 				= AjaxViewer.X11_KEY_F9;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F10] 				= AjaxViewer.X11_KEY_F10;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F11] 				= AjaxViewer.X11_KEY_F11;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F12] 				= AjaxViewer.X11_KEY_F12;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_SHIFT] 			= AjaxViewer.X11_KEY_SHIFT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_CTRL] 			= AjaxViewer.X11_KEY_CTRL;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ALT] 				= AjaxViewer.X11_KEY_ALT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_GRAVE_ACCENT] 	= AjaxViewer.X11_KEY_GRAVE_ACCENT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_SUBSTRACT] 		= AjaxViewer.X11_KEY_SUBSTRACT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ADD] 				= AjaxViewer.X11_KEY_ADD;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_OPEN_BRACKET] 	= AjaxViewer.X11_KEY_OPEN_BRACKET;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_CLOSE_BRACKET] 	= AjaxViewer.X11_KEY_CLOSE_BRACKET;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_BACK_SLASH] 		= AjaxViewer.X11_KEY_BACK_SLASH;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_SINGLE_QUOTE] 	= AjaxViewer.X11_KEY_SINGLE_QUOTE;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_COMMA] 			= AjaxViewer.X11_KEY_COMMA;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_PERIOD] 			= AjaxViewer.X11_KEY_PERIOD;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_FORWARD_SLASH] 	= AjaxViewer.X11_KEY_FORWARD_SLASH;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DASH] 			= AjaxViewer.X11_KEY_DASH;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_SEMI_COLON] 		= AjaxViewer.X11_KEY_SEMI_COLON;
+
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD0] 			= AjaxViewer.X11_KEY_NUMPAD0;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD1] 			= AjaxViewer.X11_KEY_NUMPAD1;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD2] 			= AjaxViewer.X11_KEY_NUMPAD2;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD3] 			= AjaxViewer.X11_KEY_NUMPAD3;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD4] 			= AjaxViewer.X11_KEY_NUMPAD4;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD5] 			= AjaxViewer.X11_KEY_NUMPAD5;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD6] 			= AjaxViewer.X11_KEY_NUMPAD6;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD7] 			= AjaxViewer.X11_KEY_NUMPAD7;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD8] 			= AjaxViewer.X11_KEY_NUMPAD8;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD9] 			= AjaxViewer.X11_KEY_NUMPAD9;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DECIMAL_POINT] 	= AjaxViewer.X11_KEY_DECIMAL_POINT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DIVIDE] 			= AjaxViewer.X11_KEY_DIVIDE;
+			
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_MULTIPLY] = [
+			    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0 },
+			    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ASTERISK, modifiers: 0 },
+			    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ASTERISK, modifiers: 0 },
+			    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0 }
+			];
+			
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ADD] = false;
+			this.jsKeyPressX11KeysymMap = [];
+			this.jsKeyPressX11KeysymMap[61] = [
+			    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
+			    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false }
+			];
+			this.jsKeyPressX11KeysymMap[43] = [
+			    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
+			    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
+			    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
+			    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
+			    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: true },
+			    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: true }
+			];
+		} else {
+			// initialize mapping for COOKED keyboard
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_CAPSLOCK] 		= AjaxViewer.X11_KEY_CAPSLOCK;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_BACKSPACE] 		= AjaxViewer.X11_KEY_BACKSPACE;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_TAB] 				= AjaxViewer.X11_KEY_TAB;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ENTER] 			= AjaxViewer.X11_KEY_ENTER;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ESCAPE] 			= AjaxViewer.X11_KEY_ESCAPE;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_INSERT] 			= AjaxViewer.X11_KEY_INSERT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DELETE] 			= AjaxViewer.X11_KEY_DELETE;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_HOME] 			= AjaxViewer.X11_KEY_HOME;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_END] 				= AjaxViewer.X11_KEY_END;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_PAGEUP] 			= AjaxViewer.X11_KEY_PAGEUP;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_PAGEDOWN] 		= AjaxViewer.X11_KEY_PAGEDOWN;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_LEFT] 			= AjaxViewer.X11_KEY_LEFT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_UP] 				= AjaxViewer.X11_KEY_UP;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_RIGHT] 			= AjaxViewer.X11_KEY_RIGHT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DOWN] 			= AjaxViewer.X11_KEY_DOWN;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F1] 				= AjaxViewer.X11_KEY_F1;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F2] 				= AjaxViewer.X11_KEY_F2;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F3] 				= AjaxViewer.X11_KEY_F3;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F4] 				= AjaxViewer.X11_KEY_F4;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F5] 				= AjaxViewer.X11_KEY_F5;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F6] 				= AjaxViewer.X11_KEY_F6;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F7] 				= AjaxViewer.X11_KEY_F7;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F8] 				= AjaxViewer.X11_KEY_F8;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F9] 				= AjaxViewer.X11_KEY_F9;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F10] 				= AjaxViewer.X11_KEY_F10;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F11] 				= AjaxViewer.X11_KEY_F11;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_F12] 				= AjaxViewer.X11_KEY_F12;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_SHIFT] 			= AjaxViewer.X11_KEY_SHIFT;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_CTRL] 			= AjaxViewer.X11_KEY_CTRL;
+			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ALT] 				= AjaxViewer.X11_KEY_ALT;
+		}
+	},
+	RawkeyboardInputHandler : function(eventType, code, modifiers, guestos, browser, browserVersion) {
+		if(eventType == AjaxViewer.KEY_DOWN || eventType == AjaxViewer.KEY_UP) {
+			
+			// special handling for Alt + Ctrl + Ins, convert it into Alt-Ctrl-Del
+			if(code == AjaxViewer.JS_KEY_INSERT) {
+				if((modifiers & AjaxViewer.ALT_KEY_MASK) != 0 && (modifiers & AjaxViewer.CTRL_KEY_MASK) != 0) {
+					this.mappedInput.push({type : eventType, code: 0xffff, modifiers: modifiers});
+					return;
+				}
+			}
+			
+			var X11Keysym = code;
+			if(this.jsX11KeysymMap[code] != undefined) {
+				X11Keysym = this.jsX11KeysymMap[code];
+				if(typeof this.jsX11KeysymMap[code] == "boolean") {
+					return;
+				} else if($.isArray(X11Keysym)) {
+					for(var i = 0; i < X11Keysym.length; i++) {
+					// How to set the guestos, browser, version value??? add later
+						if(this.isConditionalEntryMatched(eventType, code, modifiers, X11Keysym[i], guestos, browser, browserVersion)) {
+							this.mappedInput.push(X11Keysym[i]);
+						}
+					}
+				} else {
+					this.mappedInput.push({type : eventType, code: X11Keysym, modifiers: modifiers});
+				}
+			} else {
+				this.mappedInput.push({type : eventType, code: X11Keysym, modifiers: modifiers});
+			}
+
+			// special handling for ALT/CTRL key
+			if(eventType == AjaxViewer.KEY_UP && (code == AjaxViewer.JS_KEY_ALT || code == code == AjaxViewer.JS_KEY_CTRL))
+				this.mappedInput.push({type : eventType, code: this.jsX11KeysymMap[code], modifiers: modifiers});
+			
+		} else if(eventType == AjaxViewer.KEY_PRESS) {
+			var X11Keysym = code;
+			X11Keysym = this.jsKeyPressX11KeysymMap[code];
+			if(X11Keysym) {
+				if($.isArray(X11Keysym)) {
+					for(var i = 0; i < X11Keysym.length; i++) {
+						if(this.isConditionalEntryMatched(eventType, code, modifiers, X11Keysym[i], guestos, browser))
+							this.mappedInput.push(X11Keysym[i]);
+					}
+				} else {
+					this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: X11Keysym, modifiers: modifiers});
+					this.mappedInput.push({type : AjaxViewer.KEY_UP, code: X11Keysym, modifiers: modifiers});
+				}
+			}
+		}
+	},
+	
+	CookedKeyboardInputHandler : function(eventType, code, modifiers, guestos, browser, browserVersion) {
+		if(eventType == AjaxViewer.KEY_DOWN || eventType == AjaxViewer.KEY_UP) {
+			
+			// special handling for Alt + Ctrl + Ins, convert it into Alt-Ctrl-Del
+			if(code == AjaxViewer.JS_KEY_INSERT) {
+				if((modifiers & AjaxViewer.ALT_KEY_MASK) != 0 && (modifiers & AjaxViewer.CTRL_KEY_MASK) != 0) {
+					this.mappedInput.push({type : eventType, code: 0xffff, modifiers: modifiers});
+					return;
+				}
+			}
+			
+			var X11Keysym = code;
+			if(this.jsX11KeysymMap[code] != undefined) {
+				X11Keysym = this.jsX11KeysymMap[code];
+				if(typeof this.jsX11KeysymMap[code] == "boolean") {
+					return;
+				} else if($.isArray(X11Keysym)) {
+					for(var i = 0; i < X11Keysym.length; i++) {
+						if(this.isConditionalEntryMatched(eventType, code, modifiers, X11Keysym[i], guestos, browser, browserVersion)) {
+							this.mappedInput.push(X11Keysym[i]);
+						}
+					}
+				} else {
+					this.mappedInput.push({type : eventType, code: X11Keysym, modifiers: modifiers});
+				}
+			} else {
+				if((modifiers & (AjaxViewer.CTRL_KEY_MASK | AjaxViewer.ALT_KEY_MASK)) != 0) {
+					this.mappedInput.push({type : eventType, code: X11Keysym, modifiers: modifiers});
+				}
+			}
+
+			// special handling for ALT/CTRL key
+			if(eventType == AjaxViewer.KEY_UP && (code == AjaxViewer.JS_KEY_ALT || code == code == AjaxViewer.JS_KEY_CTRL))
+				this.mappedInput.push({type : eventType, code: this.jsX11KeysymMap[code], modifiers: modifiers});
+			
+		} else if(eventType == AjaxViewer.KEY_PRESS) {
+			// special handling for * and + key on number pad
+			if(code == AjaxViewer.JS_NUMPAD_MULTIPLY) {
+				this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: modifiers});
+				this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: 42, modifiers: modifiers});
+				this.mappedInput.push({type : AjaxViewer.KEY_UP, code: 42, modifiers: modifiers});
+				this.mappedInput.push({type : AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: modifiers});
+				return;
+			}
+			
+			if(code == AjaxViewer.JS_NUMPAD_PLUS) {
+				this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: modifiers});
+				this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: 43, modifiers: modifiers});
+				this.mappedInput.push({type : AjaxViewer.KEY_UP, code: 43, modifiers: modifiers});
+				this.mappedInput.push({type : AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: modifiers});
+				return;
+			}
+			
+			// ENTER/BACKSPACE key should already have been sent through KEY DOWN/KEY UP event
+			if(code == AjaxViewer.JS_KEY_ENTER || code == AjaxViewer.JS_KEY_BACKSPACE)
+				return;
+
+			if(code > 0) {
+				var X11Keysym = code;
+				X11Keysym = this.jsKeyPressX11KeysymMap[code];
+				if(X11Keysym) {
+					if($.isArray(X11Keysym)) {
+						for(var i = 0; i < X11Keysym.length; i++) {
+							if(this.isConditionalEntryMatched(eventType, code, modifiers, X11Keysym[i], guestos, browser))
+								this.mappedInput.push(X11Keysym[i]);
+						}
+					} else {
+						this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: X11Keysym, modifiers: modifiers});
+						this.mappedInput.push({type : AjaxViewer.KEY_UP, code: X11Keysym, modifiers: modifiers});
+					}
+				} else {
+					// if there is no mappting entry, use the JS keypress code directly
+					this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: code, modifiers: modifiers});
+					this.mappedInput.push({type : AjaxViewer.KEY_UP, code: code, modifiers: modifiers});
+				}
+			}
+		}
+	},
+	
+	inputFeed : function(eventType, code, modifiers, guestos, browser, browserVersion) {
+		if(this.keyboardType == KeyboardMapper.KEYBOARD_TYPE_RAW)
+			this.RawkeyboardInputHandler(eventType, code, modifiers, guestos, browser, browserVersion);
+		else
+			this.CookedKeyboardInputHandler(eventType, code, modifiers, guestos, browser, browserVersion);
+	},
+	
+	getMappedInput : function() {
+		var mappedInput = this.mappedInput;
+		this.mappedInput = [];
+		return mappedInput;
+	},
+	
+	isConditionalEntryMatched : function(eventType, code, modifiers, entry, guestos, browser, browserVersion) {
+		if(eventType == AjaxViewer.KEY_DOWN || eventType == AjaxViewer.KEY_UP) {
+			// for KeyDown/KeyUp events, we require that the type in entry should match with
+			// the real input
+			if(entry.type != eventType)
+				return false;
+		}
+		
+		// check conditional match
+		if(entry.shift != undefined) {
+			var shift = ((modifiers & AjaxViewer.SHIFT_KEY_MASK) != 0 ? true : false); 
+			if(entry.shift ^ shift)
+				return false;
+		}
+		
+		if(entry.guestos != undefined) {
+			if(entry.guestos != guestos)
+				return false;
+		}
+		
+		if(entry.browser != undefined) {
+			if(entry.browser != browser)
+				return false;
+		}
+		
+		if(entry.browserVersion != undefined) {
+			if(entry.browserVersion != browserVersion)
+				return false;
+		}
+		
+		return true;
+	},
+	
+	isModifierInput : function(code) {
+		return $.inArray(code, [AjaxViewer.ALT_KEY_MASK, AjaxViewer.SHIFT_KEY_MASK, AjaxViewer.CTRL_KEY_MASK, AjaxViewer.META_KEY_MASK]) >= 0;
+	}
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// class AjaxViewer
+//
+function AjaxViewer(panelId, imageUrl, updateUrl, tileMap, width, height, tileWidth, tileHeight) {
+	// logging is disabled by default so that it won't have negative impact on performance
+	// however, a back door key-sequence can trigger to open the logger window, it is designed to help
+	// trouble-shooting
+	g_logger = new Logger();
+	
+	// g_logger.enable(true);
+	// g_logger.open();
+	
+	var ajaxViewer = this;
+	this.imageLoaded = false;
+	this.fullImage = true;
+	this.imgUrl = imageUrl;
+	this.img = new Image();
+	$(this.img).attr('src', imageUrl).load(function() {
+		ajaxViewer.imageLoaded = true;
+	});
+	
+	this.updateUrl = updateUrl;
+	this.tileMap = tileMap;
+	this.dirty = true;
+	this.width = width;
+	this.height = height;
+	this.tileWidth = tileWidth;
+	this.tileHeight = tileHeight;
+	this.maxTileZIndex = 1;
+	
+	this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_ENGLISH;
+	this.keyboardMappers = [];
+	
+	this.timer = 0;
+	this.eventQueue = [];
+	this.sendingEventInProgress = false;
+	
+	this.lastClickEvent = { x: 0, y: 0, button: 0, modifiers: 0, time: new Date().getTime() };
+	
+	if(window.onStatusNotify == undefined)
+		window.onStatusNotify = function(status) {};
+	
+	this.panel = this.generateCanvas(panelId, width, height, tileWidth, tileHeight);
+//	this.setupKeyboardTranslationle();
+	this.setupKeyboardTranslationTable(this.keyboardMappers);
+	this.setupUIController();
+}
+
+// client event types
+AjaxViewer.MOUSE_MOVE = 1;
+AjaxViewer.MOUSE_DOWN = 2;
+AjaxViewer.MOUSE_UP = 3;
+AjaxViewer.KEY_PRESS = 4;
+AjaxViewer.KEY_DOWN = 5;
+AjaxViewer.KEY_UP = 6;
+AjaxViewer.EVENT_BAG = 7;
+AjaxViewer.MOUSE_DBLCLK = 8;
+
+// use java AWT key modifier masks 
+AjaxViewer.SHIFT_KEY_MASK = 64;
+AjaxViewer.CTRL_KEY_MASK = 128;
+AjaxViewer.META_KEY_MASK = 256;
+AjaxViewer.ALT_KEY_MASK = 512;
+AjaxViewer.LEFT_SHIFT_MASK = 1024;
+AjaxViewer.LEFT_CTRL_MASK = 2048;
+AjaxViewer.LEFT_ALT_MASK = 4096;
+
+AjaxViewer.EVENT_QUEUE_MOUSE_EVENT = 1;
+AjaxViewer.EVENT_QUEUE_KEYBOARD_EVENT = 2;
+
+AjaxViewer.STATUS_RECEIVING = 1;
+AjaxViewer.STATUS_RECEIVED = 2;
+AjaxViewer.STATUS_SENDING = 3;
+AjaxViewer.STATUS_SENT = 4;
+
+AjaxViewer.KEYBOARD_TYPE_ENGLISH = "us";
+AjaxViewer.KEYBOARD_TYPE_JAPANESE = "jp";
+
+AjaxViewer.JS_KEY_BACKSPACE = 8;
+AjaxViewer.JS_KEY_TAB = 9;
+AjaxViewer.JS_KEY_ENTER = 13;
+AjaxViewer.JS_KEY_SHIFT = 16;
+AjaxViewer.JS_KEY_CTRL = 17;
+AjaxViewer.JS_KEY_ALT = 18;
+AjaxViewer.JS_KEY_PAUSE = 19;
+AjaxViewer.JS_KEY_CAPSLOCK = 20;
+AjaxViewer.JS_KEY_ESCAPE = 27;
+AjaxViewer.JS_KEY_PAGEUP = 33;
+AjaxViewer.JS_KEY_PAGEDOWN = 34;
+AjaxViewer.JS_KEY_END = 35;
+AjaxViewer.JS_KEY_HOME = 36;
+AjaxViewer.JS_KEY_LEFT = 37;
+AjaxViewer.JS_KEY_UP = 38;
+AjaxViewer.JS_KEY_RIGHT = 39;
+AjaxViewer.JS_KEY_DOWN = 40;
+AjaxViewer.JS_KEY_INSERT = 45;
+AjaxViewer.JS_KEY_DELETE = 46;
+AjaxViewer.JS_KEY_LEFT_WINDOW_KEY = 91;
+AjaxViewer.JS_KEY_RIGHT_WINDOW_KEY = 92;
+AjaxViewer.JS_KEY_SELECT_KEY = 93;
+AjaxViewer.JS_KEY_NUMPAD0 = 96;
+AjaxViewer.JS_KEY_NUMPAD1 = 97;
+AjaxViewer.JS_KEY_NUMPAD2 = 98;
+AjaxViewer.JS_KEY_NUMPAD3 = 99;
+AjaxViewer.JS_KEY_NUMPAD4 = 100;
+AjaxViewer.JS_KEY_NUMPAD5 = 101;
+AjaxViewer.JS_KEY_NUMPAD6 = 102;
+AjaxViewer.JS_KEY_NUMPAD7 = 103;
+AjaxViewer.JS_KEY_NUMPAD8 = 104;
+AjaxViewer.JS_KEY_NUMPAD9 = 105;
+AjaxViewer.JS_KEY_MULTIPLY = 106;
+AjaxViewer.JS_KEY_ADD = 107;
+AjaxViewer.JS_KEY_SUBSTRACT = 109;
+AjaxViewer.JS_KEY_DECIMAL_POINT = 110;
+AjaxViewer.JS_KEY_DIVIDE = 111;
+AjaxViewer.JS_KEY_F1 = 112;
+AjaxViewer.JS_KEY_F2 = 113;
+AjaxViewer.JS_KEY_F3 = 114;
+AjaxViewer.JS_KEY_F4 = 115;
+AjaxViewer.JS_KEY_F5 = 116;
+AjaxViewer.JS_KEY_F6 = 117;
+AjaxViewer.JS_KEY_F7 = 118;
+AjaxViewer.JS_KEY_F8 = 119;
+AjaxViewer.JS_KEY_F9 = 120;
+AjaxViewer.JS_KEY_F10 = 121;
+AjaxViewer.JS_KEY_F11 = 122;
+AjaxViewer.JS_KEY_F12 = 123;
+AjaxViewer.JS_KEY_NUMLOCK = 144;
+AjaxViewer.JS_KEY_SCROLLLOCK = 145;
+AjaxViewer.JS_KEY_SEMI_COLON = 186;			// ;
+AjaxViewer.JS_KEY_EQUAL_SIGN = 187;			// =
+AjaxViewer.JS_KEY_COMMA = 188;				// ,
+AjaxViewer.JS_KEY_DASH = 189;				// -
+AjaxViewer.JS_KEY_PERIOD = 190;				// .
+AjaxViewer.JS_KEY_FORWARD_SLASH = 191;		// /
+AjaxViewer.JS_KEY_GRAVE_ACCENT = 192;		// `				
+AjaxViewer.JS_KEY_OPEN_BRACKET = 219;		// [
+AjaxViewer.JS_KEY_BACK_SLASH = 220;			// \
+AjaxViewer.JS_KEY_CLOSE_BRACKET = 221;		// ]
+AjaxViewer.JS_KEY_SINGLE_QUOTE = 222;		// '
+AjaxViewer.JS_NUMPAD_PLUS = 43;
+AjaxViewer.JS_NUMPAD_MULTIPLY = 42;
+AjaxViewer.JS_KEY_NUM8 = 56;
+
+// keycode from Japanese keyboard
+AjaxViewer.JS_KEY_JP_COLON = 222;			// :* on JP keyboard
+AjaxViewer.JS_KEY_JP_CLOSE_BRACKET = 220;	// [{ on JP keyboard
+AjaxViewer.JS_KEY_JP_AT_SIGN = 219;			// @` on JP keyboard
+AjaxViewer.JS_KEY_JP_OPEN_BRACKET = 221;	// [{ on JP keyboard
+AjaxViewer.JS_KEY_JP_BACK_SLASH = 193;		// \| on JP keyboard
+AjaxViewer.JS_KEY_JP_YEN_MARK = 255;
+
+AjaxViewer.JS_KEY_JP_EQUAL = 109;			// -= ON JP keyboard
+AjaxViewer.JS_KEY_JP_ACUTE = 107;			// ^~ on JP keyboard
+
+// X11 keysym definitions
+AjaxViewer.X11_KEY_CAPSLOCK = 0xffe5;
+AjaxViewer.X11_KEY_BACKSPACE = 0xff08;
+AjaxViewer.X11_KEY_TAB = 0xff09;
+AjaxViewer.X11_KEY_ENTER = 0xff0d;
+AjaxViewer.X11_KEY_ESCAPE = 0xff1b;
+AjaxViewer.X11_KEY_INSERT = 0xff63;
+AjaxViewer.X11_KEY_DELETE = 0xffff;
+AjaxViewer.X11_KEY_HOME = 0xff50;
+AjaxViewer.X11_KEY_END = 0xff57;
+AjaxViewer.X11_KEY_PAGEUP = 0xff55;
+AjaxViewer.X11_KEY_PAGEDOWN = 0xff56;
+AjaxViewer.X11_KEY_LEFT = 0xff51;
+AjaxViewer.X11_KEY_UP = 0xff52;
+AjaxViewer.X11_KEY_RIGHT = 0xff53;
+AjaxViewer.X11_KEY_DOWN = 0xff54;
+AjaxViewer.X11_KEY_F1 = 0xffbe;
+AjaxViewer.X11_KEY_F2 = 0xffbf;
+AjaxViewer.X11_KEY_F3 = 0xffc0;
+AjaxViewer.X11_KEY_F4 = 0xffc1;
+AjaxViewer.X11_KEY_F5 = 0xffc2;
+AjaxViewer.X11_KEY_F6 = 0xffc3;
+AjaxViewer.X11_KEY_F7 = 0xffc4;
+AjaxViewer.X11_KEY_F8 = 0xffc5;
+AjaxViewer.X11_KEY_F9 = 0xffc6;
+AjaxViewer.X11_KEY_F10 = 0xffc7;
+AjaxViewer.X11_KEY_F11 = 0xffc8;
+AjaxViewer.X11_KEY_F12 = 0xffc9;
+AjaxViewer.X11_KEY_SHIFT = 0xffe1;
+AjaxViewer.X11_KEY_CTRL = 0xffe3;
+AjaxViewer.X11_KEY_ALT = 0xffe9;
+AjaxViewer.X11_KEY_GRAVE_ACCENT = 0x60;
+AjaxViewer.X11_KEY_SUBSTRACT = 0x2d;
+AjaxViewer.X11_KEY_ADD = 0x2b;
+AjaxViewer.X11_KEY_OPEN_BRACKET = 0x5b;
+AjaxViewer.X11_KEY_CLOSE_BRACKET = 0x5d;
+AjaxViewer.X11_KEY_BACK_SLASH = 0x7c;
+AjaxViewer.X11_KEY_REVERSE_SOLIUS = 0x5c;			// another back slash (back slash on JP keyboard)
+AjaxViewer.X11_KEY_SINGLE_QUOTE = 0x22;
+AjaxViewer.X11_KEY_COMMA = 0x3c;
+AjaxViewer.X11_KEY_PERIOD = 0x3e;
+AjaxViewer.X11_KEY_FORWARD_SLASH = 0x3f;
+AjaxViewer.X11_KEY_DASH = 0x2d;
+AjaxViewer.X11_KEY_COLON = 0x3a;
+AjaxViewer.X11_KEY_SEMI_COLON = 0x3b;
+AjaxViewer.X11_KEY_NUMPAD0 = 0x30;
+AjaxViewer.X11_KEY_NUMPAD1 = 0x31;
+AjaxViewer.X11_KEY_NUMPAD2 = 0x32;
+AjaxViewer.X11_KEY_NUMPAD3 = 0x33;
+AjaxViewer.X11_KEY_NUMPAD4 = 0x34;
+AjaxViewer.X11_KEY_NUMPAD5 = 0x35;
+AjaxViewer.X11_KEY_NUMPAD6 = 0x36;
+AjaxViewer.X11_KEY_NUMPAD7 = 0x37;
+AjaxViewer.X11_KEY_NUMPAD8 = 0x38;
+AjaxViewer.X11_KEY_NUMPAD9 = 0x39;
+AjaxViewer.X11_KEY_DECIMAL_POINT = 0x2e;
+AjaxViewer.X11_KEY_DIVIDE = 0x3f;
+AjaxViewer.X11_KEY_TILDE = 0x7e;				// ~
+AjaxViewer.X11_KEY_CIRCUMFLEX_ACCENT = 0x5e;	// ^
+AjaxViewer.X11_KEY_YEN_MARK = 0xa5;				// Japanese YEN mark
+AjaxViewer.X11_KEY_ASTERISK = 0x2a;
+
+AjaxViewer.getEventName = function(type) {
+	switch(type) {
+	case AjaxViewer.MOUSE_MOVE :
+		return "MOUSE_MOVE";
+		
+	case AjaxViewer.MOUSE_DOWN :
+		return "MOUSE_DOWN";
+		
+	case AjaxViewer.MOUSE_UP :
+		return "MOUSE_UP";
+		
+	case AjaxViewer.KEY_PRESS :
+		return "KEY_PRESS";
+		
+	case AjaxViewer.KEY_DOWN :
+		return "KEY_DOWN";
+		
+	case AjaxViewer.KEY_UP :
+		return "KEY_UP";
+		
+	case AjaxViewer.EVENT_BAG :
+		return "EVENT_BAG";
+		
+	case AjaxViewer.MOUSE_DBLCLK :
+		return "MOUSE_DBLCLK";
+	}
+	
+	return "N/A";
+};
+
+AjaxViewer.prototype = {
+	setDirty: function(value) {
+		this.dirty = value;
+	},
+	
+	isDirty: function() {
+		return this.dirty;
+	},
+	
+	isImageLoaded: function() {
+		return this.imageLoaded;
+	},
+	
+	refresh: function(imageUrl, tileMap, fullImage) {
+		var ajaxViewer = this;
+		var img = $(this.img); 
+		this.fullImage = fullImage;
+		this.imgUrl=imageUrl;
+
+		img.attr('src', imageUrl).load(function() {
+			ajaxViewer.imageLoaded = true;
+		});
+		this.tileMap = tileMap;
+	},
+	
+	resize: function(panelId, width, height, tileWidth, tileHeight) {
+		$(".canvas_tile", document.body).each(function() {
+			$(this).remove();
+		});
+		$("table", $("#" + panelId)).remove();
+		
+		this.width = width;
+		this.height = height;
+		this.tileWidth = tileWidth;
+		this.tileHeight = tileHeight;
+		this.panel = this.generateCanvas(panelId, width, height, tileWidth, tileHeight);
+	},
+	
+	start: function() {
+		var ajaxViewer = this;
+		this.timer = setInterval(function() { ajaxViewer.heartbeat(); }, 50);
+		
+		$(document).bind("ajaxError", function(event, XMLHttpRequest, ajaxOptions, thrownError) {
+			ajaxViewer.onAjaxError(event, XMLHttpRequest, ajaxOptions, thrownError);
+		});
+		
+		this.eventQueue = [];	// reset event queue
+		this.sendingEventInProgress = false;
+		ajaxViewer.installMouseHook();
+		ajaxViewer.installKeyboardHook();
+
+		$(window).bind("resize", function() {
+			ajaxViewer.onWindowResize();
+		});
+	},
+	
+	stop: function() {
+		clearInterval(this.timer);
+		this.deleteCanvas();
+
+		this.uninstallMouseHook();
+		this.uninstallKeyboardHook();	
+		this.eventQueue = [];
+		this.sendingEventInProgress = false;
+
+		$(document).unbind("ajaxError");
+		$(window).unbind("resize");
+	},
+	
+	sendMouseEvent: function(event, x, y, whichButton, modifiers) {
+		this.eventQueue.push({
+			type: AjaxViewer.EVENT_QUEUE_MOUSE_EVENT,
+			event: event,
+			x: x,
+			y: y,
+			code: whichButton,
+			modifiers: modifiers
+		});
+		this.checkEventQueue();
+	},
+//NEW  insert the keyboard tables file here
+// ajaxKeys.js
+
+	setupKeyboardTranslationTable : function() {
+		this.keyboardMappers = [];
+		
+		var mapper = new KeyboardMapper();
+		this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_ENGLISH] = mapper;
+		mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_COOKED);
+
+		mapper = new KeyboardMapper();
+		this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_JAPANESE] = mapper;
+		mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_RAW);
+
+		// JP keyboard plugged in a English host OS
+/*		
+		mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_COLON] = AjaxViewer.X11_KEY_COLON;
+		mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_CLOSE_BRACKET] = AjaxViewer.X11_KEY_CLOSE_BRACKET;
+		mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_AT_SIGN] = AjaxViewer.X11_KEY_GRAVE_ACCENT;
+		mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_OPEN_BRACKET] = AjaxViewer.X11_KEY_OPEN_BRACKET;
+		mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_BACK_SLASH] = AjaxViewer.X11_KEY_REVERSE_SOLIUS;		// X11 REVERSE SOLIDUS
+		mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_YEN_MARK] = AjaxViewer.X11_KEY_YEN_MARK;				// X11 YEN SIGN
+		mapper.jsKeyPressX11KeysymMap[61] = [
+    	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_CIRCUMFLEX_ACCENT, modifiers: 0 },
+    	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_CIRCUMFLEX_ACCENT, modifiers: 0 },
+    	];
+		
+		mapper.jsKeyPressX11KeysymMap[43] = [
+    	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
+    	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
+    	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
+    	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
+    	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_TILDE, modifiers: 0, shift: true },
+    	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_TILDE, modifiers: 0, shift: true }
+        ];
+*/
+
+/* Old
+		// JP keyboard plugged in a Japanese host OS
+		mapper.jsX11KeysymMap[222] = AjaxViewer.X11_KEY_CIRCUMFLEX_ACCENT;
+		mapper.jsX11KeysymMap[220] = AjaxViewer.X11_KEY_YEN_MARK;
+		mapper.jsX11KeysymMap[219] = AjaxViewer.X11_KEY_OPEN_BRACKET;
+		mapper.jsX11KeysymMap[221] = AjaxViewer.X11_KEY_CLOSE_BRACKET;
+		mapper.jsX11KeysymMap[59] = AjaxViewer.X11_KEY_COLON;					// Firefox
+		mapper.jsX11KeysymMap[186] = AjaxViewer.X11_KEY_COLON;					// Chrome
+		mapper.jsX11KeysymMap[226] = AjaxViewer.X11_KEY_REVERSE_SOLIUS;			// \| key left to right SHIFT on JP keyboard
+		mapper.jsX11KeysymMap[240] = [
+      	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_CAPSLOCK, modifiers: 0 },
+    	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_CAPSLOCK, modifiers: 0 },
+    	];
+			
+		// for keycode 107, keypress 59
+		mapper.jsKeyPressX11KeysymMap[59] = [
+    	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SEMI_COLON, modifiers: 0 },
+    	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SEMI_COLON, modifiers: 0 },
+    	];
+		
+		// for keycode 107, keypress 43
+		mapper.jsKeyPressX11KeysymMap[43] = [
+     	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
+    	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
+    	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
+    	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
+       	    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: true },
+       	    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: true },
+        ];
+
+*/
+	// create the mapping table based on the tables input
+	if (keyboardTables != undefined	) {
+
+	    for(var i = 0; i < keyboardTables.length; i++) {
+		var mappingTbl = keyboardTables[i];
+                var mappings = mappingTbl.mappingTable;
+		var x11Maps = mappings.X11;
+		for (var j = 0; j < x11Maps.length; j++) {
+			var code = x11Maps[j].keycode;
+			var mappedEntry = x11Maps[j].entry;
+			mapper.jsX11KeysymMap[code] = mappedEntry;
+		}
+		var keyPressMaps = mappings.keyPress;
+		for (var j = 0; j < keyPressMaps.length; j++) {
+			var code = keyPressMaps[j].keycode;
+			var mappedEntry = keyPressMaps[j].entry;
+			mapper.jsKeyPressX11KeysymMap[code] = mappedEntry;
+		}
+
+	    }
+	}
+
+	}, // end of the setupKeyboardTranslationTable function
+	
+	getCurrentKeyboardMapper : function() {
+		return this.keyboardMappers[this.currentKeyboard];
+	},
+	
+	setupUIController : function() {
+		var ajaxViewer = this;
+		var pullDownElement = $("#toolbar").find(".pulldown");
+		pullDownElement.hover(
+			function(e) {
+				var subMenu = pullDownElement.find("ul");
+				var offset = subMenu.parent().offset();
+				subMenu.css("left", offset.left);
+			
+				$("li.current").removeClass("current");
+				$("li:has(a[cmd$=" + ajaxViewer.currentKeyboard + "])", subMenu).addClass("current");
+				subMenu.css("z-index", "" + ajaxViewer.maxTileZIndex + 1).show();
+				return false;
+			},
+			
+			function(e) {
+				pullDownElement.find("ul").hide();
+				return false;
+			}
+		);
+
+		$("[cmd]", "#toolbar").each(function(i, val) {
+			$(val).click(function(e) {
+				var cmd = $(e.target).attr("cmd");
+				if(cmd)
+					ajaxViewer.onCommand(cmd); 
+				else {
+					var cmdLink = $(e.target).closest("a");
+					
+					if(cmdLink.attr("cmd")) {
+						var cmd = cmdLink.attr("cmd");
+						ajaxViewer.onCommand(cmd);
+					}
+				}
+			});
+		});
+	},
+	
+	onCommand : function(cmd) {
+		if(cmd == "keyboard_jp") {
+			$("#toolbar").find(".pulldown").find("ul").hide();
+			this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_JAPANESE;
+		} else if(cmd == "keyboard_us") {
+			$("#toolbar").find(".pulldown").find("ul").hide();
+			this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_ENGLISH;
+		} else if(cmd == "sendCtrlAltDel") {
+			this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffe9, 0);		// X11 Alt
+			this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffe3, 0);		// X11 Ctrl
+			this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffff, 0);		// X11 Del
+			this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xffff, 0);
+			this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xffe3, 0);
+			this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xffe9, 0);
+		} else if(cmd == "sendCtrlEsc") {
+			this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffe3, 0);		// X11 Ctrl
+			this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xff1b, 0);		// X11 ESC
+			this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xff1b, 0);
+			this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xffe3, 0);
+		} else if(cmd == "toggle_logwin") {
+			if(!g_logger.isOpen()) {
+				g_logger.enable(true);
+				g_logger.open();
+				g_logger.log(Logger.LEVEL_SYS, "Accept languages: " + acceptLanguages + ", current language: " + getCurrentLanguage());
+			} else {
+				g_logger.close();
+			}
+		}
+	},
+	
+	sendKeyboardEvent: function(event, code, modifiers) {
+		// back door to open logger window - CTRL-ATL-SHIFT+SPACE
+		if(code == 32 && 
+			(modifiers & AjaxViewer.SHIFT_KEY_MASK | AjaxViewer.CTRL_KEY_MASK | AjaxViewer.ALT_KEY_MASK) == (AjaxViewer.SHIFT_KEY_MASK | AjaxViewer.CTRL_KEY_MASK | AjaxViewer.ALT_KEY_MASK)) {
+			
+			if(!g_logger.isOpen()) {
+				g_logger.enable(true);
+				g_logger.open();
+				g_logger.log(Logger.LEVEL_SYS, "Accept languages: " + acceptLanguages + ", current language: " + getCurrentLanguage());
+			} else {
+				g_logger.close();
+			}
+		}
+			
+		var len;
+		g_logger.log(Logger.LEVEL_INFO, "Keyboard event: " + AjaxViewer.getEventName(event) + ", code: " + code + ", modifiers: " + modifiers + ', char: ' + String.fromCharCode(code));
+		this.eventQueue.push({
+			type: AjaxViewer.EVENT_QUEUE_KEYBOARD_EVENT,
+			event: event,
+			code: code,
+			modifiers: modifiers
+		});
+
+		if(event != AjaxViewer.KEY_DOWN)
+			this.checkEventQueue();
+	},
+	
+	aggregateEvents: function() {
+		var ajaxViewer = this;
+		var aggratedQueue = [];
+		
+		var aggregating = false;
+		var mouseX;
+		var mouseY;
+		$.each(ajaxViewer.eventQueue, function(index, item) {
+			if(item.type != AjaxViewer.EVENT_QUEUE_MOUSE_EVENT) {
+				aggratedQueue.push(item);
+			} else {
+				if(!aggregating) {
+					if(item.event == AjaxViewer.MOUSE_MOVE) {
+						aggregating = true;
+						mouseX = item.x;
+						mouseY = item.y;
+					} else {
+						aggratedQueue.push(item);
+					}
+				} else {
+					if(item.event == AjaxViewer.MOUSE_MOVE) {
+						// continue to aggregate mouse move event
+						mouseX = item.x;
+						mouseY = item.y;
+					} else {
+						aggratedQueue.push({
+							type: AjaxViewer.EVENT_QUEUE_MOUSE_EVENT,
+							event: AjaxViewer.MOUSE_MOVE,
+							x: mouseX,
+							y: mouseY,
+							code: 0,
+							modifiers: 0
+						});
+						aggregating = false;
+						
+						aggratedQueue.push(item);
+					}
+				}
+			}
+		});
+		
+		if(aggregating) {
+			aggratedQueue.push({
+				type: AjaxViewer.EVENT_QUEUE_MOUSE_EVENT,
+				event: AjaxViewer.MOUSE_MOVE,
+				x: mouseX,
+				y: mouseY,
+				code: 0,
+				modifiers: 0
+			});
+		}
+		
+		this.eventQueue = aggratedQueue; 
+	},
+	
+	checkEventQueue: function() {
+		var ajaxViewer = this;
+		
+		if(!this.sendingEventInProgress && this.eventQueue.length > 0) {
+			var sb = new StringBuilder();
+			sb.append(""+this.eventQueue.length).append("|");
+			$.each(this.eventQueue, function() {
+				var item = this;
+				if(item.type == AjaxViewer.EVENT_QUEUE_MOUSE_EVENT) {
+					sb.append(""+item.type).append("|");
+					sb.append(""+item.event).append("|");
+					sb.append(""+item.x).append("|");
+					sb.append(""+item.y).append("|");
+					sb.append(""+item.code).append("|");
+					sb.append(""+item.modifiers).append("|");
+				} else {
+					sb.append(""+item.type).append("|");
+					sb.append(""+item.event).append("|");
+					sb.append(""+item.code).append("|");
+					sb.append(""+item.modifiers).append("|");
+				}
+			});
+			this.eventQueue.length = 0;
+			
+			var url = ajaxViewer.updateUrl + "&event=" + AjaxViewer.EVENT_BAG;
+			
+			g_logger.log(Logger.LEVEL_TRACE, "Posting client event " + sb.toString() + "...");
+			
+			ajaxViewer.sendingEventInProgress = true;
+			window.onStatusNotify(AjaxViewer.STATUS_SENDING);
+			$.post(url, {data: sb.toString()}, function(data, textStatus) {
+				g_logger.log(Logger.LEVEL_TRACE, "Client event " + sb.toString() + " is posted");
+				
+				ajaxViewer.sendingEventInProgress = false;
+				window.onStatusNotify(AjaxViewer.STATUS_SENT);
+				
+				ajaxViewer.checkUpdate();
+			}, 'html');
+		}
+	},
+	
+	onAjaxError: function(event, XMLHttpRequest, ajaxOptions, thrownError) {
+		if(window.onClientError != undefined && jQuery.isFunction(window.onClientError)) {
+			window.onClientError();
+		}
+	},
+	
+	onWindowResize: function() {
+		var offset = this.panel.offset();
+		
+		var row = $('tr:first', this.panel);
+		var cell = $('td:first', row);
+		var tile = this.getTile(cell, 'tile');
+		
+		var tileOffset = tile.offset();
+		var deltaX = offset.left - tileOffset.left;
+		var deltaY = offset.top - tileOffset.top;
+		
+		if(deltaX != 0 || deltaY != 0) {
+			$(".canvas_tile").each(function() {
+				var offsetFrom = $(this).offset();
+				$(this).css('left', offsetFrom.left + deltaX).css('top', offsetFrom.top + deltaY);
+			});
+		}
+	},
+	
+	deleteCanvas: function() {
+		$('.canvas_tile', $(document.body)).each(function() {
+			$(this).remove();
+		});
+	},
+	
+	generateCanvas: function(wrapperDivId, width, height, tileWidth, tileHeight) {
+		var canvasParent = $('#' + wrapperDivId);
+		canvasParent.width(width);
+		canvasParent.height(height);
+		
+		if(window.onCanvasSizeChange != undefined && jQuery.isFunction(window.onCanvasSizeChange))
+			window.onCanvasSizeChange(width, height);
+		
+		var tableDef = '<table cellpadding="0px" cellspacing="0px">\r\n';
+		var i = 0;
+		var j = 0;
+		for(i = 0; i < Math.ceil((height + tileHeight - 1) / tileHeight); i++) {
+			var rowHeight = Math.min(height - i*tileHeight, tileHeight);
+			tableDef += '<tr style="height:' + rowHeight + 'px">\r\n';
+			
+			for(j = 0; j < Math.ceil((width + tileWidth - 1) / tileWidth); j++) {
+				var colWidth = Math.min(width - j*tileWidth, tileWidth);
+				tableDef += '<td width="' + colWidth + 'px"></td>\r\n';
+			}
+			tableDef += '</tr>\r\n';
+		}
+		tableDef += '</table>\r\n';
+		
+		return $(tableDef).appendTo(canvasParent);
+	},
+	
+	getTile: function(cell, name) {
+		var clonedDiv = cell.data(name);
+		if(!clonedDiv) {
+			var offset = cell.offset();
+			var divDef = "<div class=\"canvas_tile\" style=\"z-index:1;position:absolute;overflow:hidden;width:" + cell.width() + "px;height:" 
+				+ cell.height() + "px;left:" + offset.left + "px;top:" + offset.top+"px\"></div>";
+			
+			clonedDiv = $(divDef).appendTo($(document.body));
+			cell.data(name, clonedDiv);
+		}
+		
+		return clonedDiv;
+	},
+	
+	initCell: function(cell) {
+		if(!cell.data("init")) {
+			cell.data("init", true);
+			
+			cell.data("current", 0);
+			this.getTile(cell, "tile2");
+			this.getTile(cell, "tile");
+		}
+	},
+	
+	displayCell: function(cell, bg) {
+		var div;
+		var divPrev;
+		if(!cell.data("current")) {
+			cell.data("current", 1);
+			
+			divPrev = this.getTile(cell, "tile");
+			div = this.getTile(cell, "tile2");
+		} else {
+			cell.data("current", 0);
+			divPrev = this.getTile(cell, "tile2");
+			div = this.getTile(cell, "tile");
+		}
+		
+		var zIndex = parseInt(divPrev.css("z-index")) + 1;
+		this.maxTileZIndex = Math.max(this.maxTileZIndex, zIndex);
+		div.css("z-index", zIndex);
+		div.css("background", bg);
+	},
+	
+	updateTile: function() {
+		if(this.dirty) {
+			var ajaxViewer = this;
+			var tileWidth = this.tileWidth;
+			var tileHeight = this.tileHeight;
+			var imgUrl = this.imgUrl;
+			var panel = this.panel;
+			
+			if(this.fullImage) {
+				$.each(this.tileMap, function() {
+					var i = $(this)[0];
+					var j = $(this)[1];
+					var row = $("TR:eq("+i+")", panel);
+					var cell = $("TD:eq("+j+")", row);
+					var attr = "url(" + imgUrl + ") -"+j*tileWidth+"px -"+i*tileHeight + "px";
+					
+					ajaxViewer.initCell(cell);
+					ajaxViewer.displayCell(cell, attr);
+				});
+			} else {
+				$.each(this.tileMap, function(index) {
+					var i = $(this)[0];
+					var j = $(this)[1];
+					var offset = index*tileWidth;
+					var attr = "url(" + imgUrl + ") no-repeat -"+offset+"px 0px";
+					var row = $("TR:eq("+i+")", panel);
+					var cell = $("TD:eq("+j+")", row);
+					
+					ajaxViewer.initCell(cell);
+					ajaxViewer.displayCell(cell, attr);
+				});
+			}
+			
+			this.dirty = false;
+		}
+	},
+	
+	heartbeat: function() {
+		this.checkEventQueue();
+		this.checkUpdate();
+	},
+	
+	checkUpdate: function() {
+		if(!this.isDirty())
+			return;
+		
+		if(this.isImageLoaded()) {
+			this.updateTile();
+			var url = this.updateUrl;
+			var ajaxViewer = this;
+
+			window.onStatusNotify(AjaxViewer.STATUS_RECEIVING);
+			$.getScript(url, function(data, textStatus) {
+				if(/^<html>/.test(data)) {
+					ajaxViewer.stop();
+					$(document.body).html(data);
+				} else {
+					eval(data);
+					ajaxViewer.setDirty(true);
+					window.onStatusNotify(AjaxViewer.STATUS_RECEIVED);
+					
+					ajaxViewer.checkUpdate();
+				}
+			});
+		} 
+	},
+	
+	ptInPanel: function(pageX, pageY) {
+		var mainPanel = this.panel;
+		
+		var offset = mainPanel.offset();
+		var x = pageX - offset.left;
+		var y = pageY - offset.top;
+		
+		if(x < 0 || y < 0 || x > mainPanel.width() - 1 || y > mainPanel.height() - 1)
+			return false;
+		return true;
+	},
+	
+	pageToPanel: function(pageX, pageY) {
+		var mainPanel = this.panel;
+		
+		var offset = mainPanel.offset();
+		var x = pageX - offset.left;
+		var y = pageY - offset.top;
+		
+		if(x < 0)
+			x = 0;
+		if(x > mainPanel.width() - 1)
+			x = mainPanel.width() - 1;
+		
+		if(y < 0)
+			y = 0;
+		if(y > mainPanel.height() - 1)
+			y = mainPanel.height() - 1;
+		
+		return { x: Math.ceil(x), y: Math.ceil(y) };
+	},
+	
+	installMouseHook: function() {
+		var ajaxViewer = this;
+		var target = $(document.body);
+		
+		target.mousemove(function(e) {
+			if(!ajaxViewer.ptInPanel(e.pageX, e.pageY))
+				return true;
+			
+			var pt = ajaxViewer.pageToPanel(e.pageX, e.pageY);  
+			ajaxViewer.onMouseMove(pt.x, pt.y);
+			
+			e.stopPropagation();
+			return false;
+		});
+		
+		target.mousedown(function(e) {
+			ajaxViewer.panel.parent().focus();
+			
+			if(!ajaxViewer.ptInPanel(e.pageX, e.pageY))
+				return true;
+			
+			var modifiers = ajaxViewer.getKeyModifiers(e);
+			var whichButton = e.button;
+			
+			var pt = ajaxViewer.pageToPanel(e.pageX, e.pageY);  
+			ajaxViewer.onMouseDown(pt.x, pt.y, whichButton, modifiers);
+			
+			e.stopPropagation();
+			return false;
+		});
+		
+		target.mouseup(function(e) {
+			if(!ajaxViewer.ptInPanel(e.pageX, e.pageY))
+				return true;
+			
+			var modifiers = ajaxViewer.getKeyModifiers(e);
+			var whichButton = e.button;
+			
+			var pt = ajaxViewer.pageToPanel(e.pageX, e.pageY);  
+
+			ajaxViewer.onMouseUp(pt.x, pt.y, whichButton, modifiers);
+			e.stopPropagation();
+			return false;
+		});
+		
+		// disable browser right-click context menu
+		target.bind("contextmenu", function() { return false; });
+	},
+	
+	uninstallMouseHook : function() {
+		var target = $(document);
+		target.unbind("mousemove");
+		target.unbind("mousedown");
+		target.unbind("mouseup");
+		target.unbind("contextmenu");
+	},
+	
+	requiresDefaultKeyProcess : function(e) {
+		switch(e.which) {
+		case 8 :		// backspace
+		case 9 :		// TAB
+		case 19 :		// PAUSE/BREAK
+		case 20 :		// CAPSLOCK
+		case 27 :		// ESCAPE
+		case 16 :		// SHIFT key
+		case 17 :		// CTRL key
+		case 18 :		// ALT key
+		case 33 :		// PGUP
+		case 34 :		// PGDN
+		case 35 :		// END
+		case 36 :		// HOME
+		case 37 :		// LEFT
+		case 38 :		// UP
+		case 39 :		// RIGHT
+		case 40 :		// DOWN
+			return false;
+		}
+		
+		if(this.getKeyModifiers(e) == AjaxViewer.SHIFT_KEY_MASK)
+			return true;
+		
+		if(this.getKeyModifiers(e) != 0)
+			return false;
+		
+		return true;
+	},
+	
+	installKeyboardHook: function() {
+		var ajaxViewer = this;
+		var target = $(document);
+
+		target.keypress(function(e) {
+			ajaxViewer.onKeyPress(e.which, ajaxViewer.getKeyModifiers(e));
+
+			e.stopPropagation();
+			if(ajaxViewer.requiresDefaultKeyProcess(e))
+				return true;
+			
+			e.preventDefault();
+			return false;
+		});
+		
+		target.keydown(function(e) {
+			ajaxViewer.onKeyDown(e.which, ajaxViewer.getKeyModifiers(e));
+			
+			e.stopPropagation();
+			if(ajaxViewer.requiresDefaultKeyProcess(e))
+				return true;
+			
+			e.preventDefault();
+			return false;
+		});
+		
+		target.keyup(function(e) {
+			ajaxViewer.onKeyUp(e.which, ajaxViewer.getKeyModifiers(e));
+
+			e.stopPropagation();
+			if(ajaxViewer.requiresDefaultKeyProcess(e))
+				return true;
+			
+			e.preventDefault();
+			return false;
+		});
+	},
+	
+	uninstallKeyboardHook : function() {
+		var target = $(document);
+		target.unbind("keypress");
+		target.unbind("keydown");
+		target.unbind("keyup");
+	},
+	
+	onMouseMove: function(x, y) {
+		this.sendMouseEvent(AjaxViewer.MOUSE_MOVE, x, y, 0, 0);
+	},
+	
+	onMouseDown: function(x, y, whichButton, modifiers) {
+		this.sendMouseEvent(AjaxViewer.MOUSE_DOWN, x, y, whichButton, modifiers);
+	},
+	
+	onMouseUp: function(x, y, whichButton, modifiers) {
+		this.sendMouseEvent(AjaxViewer.MOUSE_UP, x, y, whichButton, modifiers);
+		
+		var curTick = new Date().getTime();
+		if(this.lastClickEvent.time && (curTick - this.lastClickEvent.time < 300)) {
+			this.onMouseDblClick(this.lastClickEvent.x, this.lastClickEvent.y, 
+				this.lastClickEvent.button, this.lastClickEvent.modifiers);
+		}
+		
+		this.lastClickEvent.x = x;
+		this.lastClickEvent.y = y;
+		this.lastClickEvent.button = whichButton;
+		this.lastClickEvent.modifiers = modifiers;
+		this.lastClickEvent.time = curTick;
+	},
+	
+	onMouseDblClick: function(x, y, whichButton, modifiers) {
+		this.sendMouseEvent(AjaxViewer.MOUSE_DBLCLK, x, y, whichButton, modifiers);
+	},
+	
+	onKeyPress: function(code, modifiers) {
+		g_logger.log(Logger.LEVEL_WARN, "RAW KEYBOARD EVENT. KEY-PRESS: " + code + ", modifers: " + modifiers);
+		
+		this.dispatchKeyboardInput(AjaxViewer.KEY_PRESS, code, modifiers);
+	},
+	
+	onKeyDown: function(code, modifiers) {
+		g_logger.log(Logger.LEVEL_WARN, "RAW KEYBOARD EVENT. KEY-DOWN: " + code + ", modifers: " + modifiers);
+		
+		this.dispatchKeyboardInput(AjaxViewer.KEY_DOWN, code, modifiers);
+	},
+	
+	onKeyUp: function(code, modifiers) {
+		g_logger.log(Logger.LEVEL_WARN, "RAW KEYBOARD EVENT. KEY-UP: " + code + ", modifers: " + modifiers);
+		
+		this.dispatchKeyboardInput(AjaxViewer.KEY_UP, code, modifiers);
+	},
+	
+	dispatchKeyboardInput : function(event, code, modifiers) {
+		var keyboardMapper = ajaxViewer.getCurrentKeyboardMapper();
+		keyboardMapper.inputFeed(event, code, modifiers, this.guestos, $.browser, $.browser.version);
+		this.dispatchMappedKeyboardInput(keyboardMapper.getMappedInput());
+	},
+	
+	dispatchMappedKeyboardInput : function(mappedInput) {
+		for(var i = 0; i < mappedInput.length; i++) {
+			switch(mappedInput[i].type) {
+			case AjaxViewer.KEY_DOWN :
+				this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, mappedInput[i].code, mappedInput[i].modifiers);
+				break;
+				
+			case AjaxViewer.KEY_UP :
+				this.sendKeyboardEvent(AjaxViewer.KEY_UP, mappedInput[i].code, mappedInput[i].modifiers);
+				break;
+				
+			case AjaxViewer.KEY_PRESS :
+				this.sendKeyboardEvent(AjaxViewer.KEY_PRESS, mappedInput[i].code, mappedInput[i].modifiers);
+				break;
+			}
+		}
+	},
+	
+	getKeyModifiers: function(e) {
+		var modifiers = 0;
+		if(e.altKey)
+			modifiers |= AjaxViewer.ALT_KEY_MASK;
+		
+		if(e.altLeft)
+			modifiers |= AjaxViewer.LEFT_ALT_MASK;
+		
+		if(e.ctrlKey)
+			modifiers |= AjaxViewer.CTRL_KEY_MASK;
+		
+		if(e.ctrlLeft)
+			modifiers |=  AjaxViewer.LEFT_CTRL_MASK;
+		
+		if(e.shiftKey)
+			modifiers |=  AjaxViewer.SHIFT_KEY_MASK;
+		
+		if(e.shiftLeft)
+			modifiers |= AjaxViewer.LEFT_SHIFT_MASK;
+		
+		if(e.metaKey)
+			modifiers |= AjaxViewer.META_KEY_MASK;
+		
+		return modifiers;
+	}
+};
+

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/4869f0ca/services/console-proxy/server/js/cloud.logger.js
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/js/cloud.logger.js b/services/console-proxy/server/js/cloud.logger.js
new file mode 100644
index 0000000..751627e
--- /dev/null
+++ b/services/console-proxy/server/js/cloud.logger.js
@@ -0,0 +1,338 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+ 
+  http://www.apache.org/licenses/LICENSE-2.0
+ 
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+// Version: 1.9.1.152
+
+//
+// Javascript logger utility
+// Author
+//		Kelven Yang
+//		2/25/2010
+//
+
+function Logger() {
+	this.bDockEnabled = true;
+	
+	this.logWin = null;
+	this.logger = null;
+	this.header = null;
+	
+	this.bEnabled = true;
+	this.level = 0;
+	
+	this.bMoving = false;
+	this.offsetStart = {left: 0, top: 0};
+	this.ptStart = {x: 0, y: 0};
+}
+
+Logger.DEFAULT_WIN_HEIGHT = 500;
+Logger.LEVEL_TRACE = 0;
+Logger.LEVEL_DEBUG = 1;
+Logger.LEVEL_INFO = 2;
+Logger.LEVEL_WARN = 3;
+Logger.LEVEL_ERROR = 4;
+Logger.LEVEL_FATAL = 5;
+Logger.LEVEL_SYS = 100;
+
+Logger.prototype = {
+	
+	open: function() {
+		if(this.logWin) {
+			this.logWin.show();
+			
+			this.log(Logger.LEVEL_SYS, "Logger is open in browser: " + this.objectToString($.browser));
+			return;
+		}
+		
+		var logger = this;
+		var logWinMarkup = [ 
+				'<div class="logwin">',
+				'<div class="logwin_title">',
+					'<div class="logwin_title_actionbox">',
+		        		'<a class="logwin_playbutton" href="#" cmd="1"></a>', 
+		        		'<a class="logwin_stopbutton" href="#" cmd="2"></a>',
+		        		'<a class="logwin_clrbutton" href="#" cmd="3"></a>',
+		        		'<form action="#">',
+						'<select class="select" id="template_type">',
+		                  '<option value="0">TRACE</option>',
+		                  '<option value="1">DEBUG</option>',
+		                  '<option value="2">INFO</option>',
+		                  '<option value="3">WARN</option>',
+		                  '<option value="4">ERROR</option>',
+		                  '<option value="5">FATAL</option>',
+		         		'</select>',
+		         		'</form>',
+		            '</div>',
+		            '<div class="logwin_title_rgtactionbox">',
+			        	'<a class="logwin_minimizebutton" href="#" cmd="4"></a>',
+			            '<a class="logwin_shrinkbutton" href="#" cmd="5"></a>',
+		            '</div>',
+				'</div>',
+				'<div class="logwin_content"></div>',
+				'</div>'
+		    ].join('');
+		
+		this.logWin = $(logWinMarkup).appendTo(document.body);
+		this.header = $('.logwin_title:first', this.logWin);
+		this.logger = $('.logwin_content:first', this.logWin);
+
+		$(".logwin_title", this.logWin).mousedown(function(e) {
+			if($(e.target).attr('cmd'))
+				return true;
+			
+			if(!logger.bMoving) {
+				logger.bMoving = true;
+				logger.offsetStart = logger.logWin.offset();
+				logger.ptStart = {x: e.pageX, y: e.pageY};
+				
+				$(document).bind("mousemove", function(e) {
+					if(logger.bMoving) {
+						logger.enableDocking(false);
+						
+						var logWinNewLeft = logger.offsetStart.left + e.pageX - logger.ptStart.x;
+						var logWinNewTop = logger.offsetStart.top + e.pageY - logger.ptStart.y;
+						
+						logger.logWin.css("left", logWinNewLeft + "px").css("top", logWinNewTop + "px");
+					}
+					return false; 
+				});
+
+				$(document).bind("mouseup", function(e) {
+					if(logger.bMoving) {
+						logger.bMoving = false;
+						$(document).unbind("mousemove", arguments.callee.name);
+						$(document).unbind("mouseup", arguments.callee.name);
+						
+						return false;
+					}
+					return true;
+				});
+			}
+			
+			// prevent default handling
+			return false;
+		}).dblclick(function(e) {
+			logger.expand(!logger.isExpanded());
+		});
+		
+		this.logWin.click(function(e) {
+			if($(e.target).attr('cmd')) {
+				switch($(e.target).attr('cmd')) {
+				case '1' :
+					logger.enable(true);
+					break;
+					
+				case '2' :
+					logger.enable(false);
+					break;
+					
+				case '3' :
+					logger.clear();
+					break;
+					
+				case '4' :
+					logger.enableDocking(true);
+					logger.dockIn();
+					break;
+					
+				case '5' :
+					logger.expand(!logger.isExpanded());
+					break;
+					
+				default :
+					break;
+				}
+			}
+		});
+		
+		$("#template_type", this.logWin).change(function(e) {
+			logger.setLevel(parseInt($(this).val()));
+		});
+		
+		this.logWin.css("left", (($(document.body).width() - this.logWin.width()) / 2) + "px");
+		this.dockIn();
+		
+		this.log(Logger.LEVEL_SYS, "Logger is open in browser: " + this.objectToString($.browser));
+	},
+	
+	close: function() {
+		if(this.logWin)
+			this.logWin.hide();
+	},
+	
+	isOpen: function() {
+		if(this.logWin)
+			return this.logWin.is(":visible");
+		return false;
+	},
+	
+	dockIn: function() {
+		var logger = this;
+		var offset = this.logWin.offset();
+		var bottom = offset.top + this.logWin.height();
+		var delta = bottom - 2;
+		
+		this.logWin.animate({top: (offset.top - delta) + "px"}, 200, 
+			function() {
+				logger.logWin.unbind("mouseleave");
+				logger.logWin.bind("mouseenter", function(e) {
+					if(logger.bDockEnabled)
+						logger.dockOut();
+				});
+			} 
+		);
+	},
+	
+	dockOut: function() {
+		var logger = this;
+		this.logWin.animate({top: "0px"}, 200, 
+			function() {
+				logger.logWin.unbind("mouseenter");
+				logger.logWin.bind("mouseleave", function(e) {
+					if(logger.bDockEnabled) {
+						var xPosInLogWin = e.pageX - logger.logWin.offset().left;
+						var yPosInLogWin = e.pageY - logger.logWin.offset().top;
+						
+						if(xPosInLogWin < 0 || yPosInLogWin < 0 || 
+							xPosInLogWin > logger.logWin.width() || yPosInLogWin > logger.logWin.height()) {
+							logger.dockIn();
+						}
+					}
+				});
+			}
+		);
+	},
+	
+	enableDocking: function(bEnable) {
+		this.bDockEnabled = bEnable;
+	},
+	
+	log: function(level, message) {
+		// Note : LEVEL_SYS message will always be logged
+		if(this.logger && (level == Logger.LEVEL_SYS || this.bEnabled && level >= this.level)) {
+			var curTime = new Date();
+			var curTimeString = [
+			    '', curTime.getMonth(),
+			    '/', curTime.getDate(),
+			    '/', curTime.getYear(),
+			    ' ',
+				curTime.getHours(),
+				':', curTime.getMinutes(),
+				":", curTime.getSeconds(),
+				".", curTime.getMilliseconds()].join('');
+			
+			this.logger.append(this.getLevelDisplayString(level) + " - " + curTimeString + " - " + message + '<br>');
+		}
+	},
+	
+	clear: function() {
+		if(this.logger) {
+			this.logger.empty();
+			this.log(Logger.LEVEL_SYS, "Logger is cleared");
+		}
+	},
+	
+	setLevel: function(level) {
+		this.level = level;
+		
+		this.log(Logger.LEVEL_SYS, "Set logger trace level to " + this.getLevelDisplayString(level));
+	},
+	
+	enable: function(bEnabled) {
+		this.bEnabled = bEnabled;
+		
+		if(bEnabled)
+			this.log(Logger.LEVEL_SYS, "Logger is enabled");
+		else
+			this.log(Logger.LEVEL_SYS, "Logger is disabled");
+	},
+	
+	expand: function(bExpand) {
+		if(bExpand) {
+			this.logWin.height(Logger.DEFAULT_WIN_HEIGHT);
+			this.logger.height(Logger.DEFAULT_WIN_HEIGHT - this.header.height());
+		} else {
+			this.logWin.height(this.header.height());
+			this.logger.height(0);
+		}
+	},
+	
+	isExpanded: function() {
+		return this.logWin.height() > this.header.height();
+	},
+	
+	getLevelDisplayString: function(level) {
+		switch(level) {
+		case Logger.LEVEL_TRACE :
+			return "TRACE";
+			
+		case Logger.LEVEL_DEBUG :
+			return "DEBUG";
+			
+		case Logger.LEVEL_INFO :
+			return "INFO";
+			
+		case Logger.LEVEL_WARN :
+			return "WARN";
+			
+		case Logger.LEVEL_ERROR :
+			return "ERROR";
+			
+		case Logger.LEVEL_FATAL :
+			return "FATAL";
+			
+		case Logger.LEVEL_SYS :
+			return "SYSINFO";
+		}
+		
+		return "LEVEL " + level;
+	},
+	
+	// this is a util function which actually can be put elsewhere instead of in this class
+	objectToString : function(object) {
+		if(object) {
+			if(object instanceof Object) {
+				var sb = ['{' ];
+				
+				$.each(object, function(name, val) {
+					sb.push('' + name + ': ');
+					
+					if(val instanceof Object) {
+						sb.push(this.objectToString(val));
+					} else {
+						sb.push('' + val);
+					}
+					
+					sb.push(',');
+				});
+				
+				if(sb[sb.length - 1] == ',' )
+					sb.length = sb.length - 1;
+				
+				sb.push('}');
+				return sb.join("");
+			} else {
+				return '' + object;
+			}
+		} else {
+			return 'N/A';
+		}
+	}
+};
+

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/4869f0ca/services/console-proxy/server/js/handler.js
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/js/handler.js b/services/console-proxy/server/js/handler.js
new file mode 100644
index 0000000..d22ff07
--- /dev/null
+++ b/services/console-proxy/server/js/handler.js
@@ -0,0 +1,72 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+ 
+  http://www.apache.org/licenses/LICENSE-2.0
+ 
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+//
+// Callback handlers for AJAX viewer
+// Author
+//		Kelven Yang
+//		11/18/2009
+//
+function onKickoff() {
+	ajaxViewer.stop();
+	$('#toolbar').remove();
+	$('#main_panel').html('<p>This session is terminated because a session for the same VM has been created elsewhere.</p>');
+}
+
+function onDisconnect() {
+	ajaxViewer.stop();
+	$('#toolbar').remove();
+	$('#main_panel').html('<p>This session is terminated as the machine you are accessing has terminated the connection.</p>');
+}
+
+function onClientError() {
+	ajaxViewer.stop();
+	$('#toolbar').remove();
+	$('#main_panel').html('<p>Client communication error, please retry later.</p>');
+}
+
+function onCanvasSizeChange(width, height) {
+	$('#toolbar').width(width);
+}
+
+function onStatusNotify(status) {
+	if(status == ajaxViewer.STATUS_SENDING || status == ajaxViewer.STATUS_RECEIVING)
+		$('#light').removeClass('dark').addClass('bright');
+	else
+		$('#light').removeClass('bright').addClass('dark');
+}
+
+function sendCtrlAltDel() {
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 45, ajaxViewer.CTRL_KEY | ajaxViewer.ALT_KEY);
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 45, ajaxViewer.CTRL_KEY | ajaxViewer.ALT_KEY);
+}
+
+function sendCtrlEsc() {
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 17, 0);
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 27, ajaxViewer.CTRL_KEY);
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 27, ajaxViewer.CTRL_KEY);
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 17, 0);
+}
+
+function sendAltTab() {
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 18, 0);
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_DOWN, 9, ajaxViewer.ALT_KEY);
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 9, ajaxViewer.ALT_KEY);
+	ajaxViewer.sendKeyboardEvent(ajaxViewer.KEY_UP, 18, 0);
+}


Mime
View raw message