Kimchi-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
May 2014
- 13 participants
- 93 discussions
I'd like to talk about how to discover Kimchi peers.
Now I just talk about discover a peer in a same network here.
I will use a local multicast subnetwork address
<http://en.wikipedia.org/wiki/Multicast_address#Local_subnetwork> to
find peers in one network.
Choose 224.0.0.132 as the kimchi multicast address, and 8000 as the port.
For cross network that need the router support multicast, so I give up
discover a peer cross network.
I will let user add the remote peers manully.
In the whole system all peers are equal. There will not be a center
discover service.
We will define two kinds of multicast message Notify and Search.
the format as follow.
# ____________________________________________
# | head | message body | tail |
# |___________________|_________________|______|
# |sizeof(messageBody)| json message | EOL |
# |___________________|_________________|______|
the flow of discover Kimchi peers:
1. one host multicast a "search" message. in this message it tell
himself information, and ask others tell their information.
Like this:
{"search": {"domain": "kimchi-host1", "IP": "192.168.0.3", "httpport":
"8000", "httpsport": "8001"}}
this means "hello, I'm a kimchi host, this is my information, can
you tell me who you are?"
2. others received a search will response an "notify" message.
Like this:
{"notify": {"domain": "kimchi-host1", "IP": "192.168.0.3",
"httpport": "8000", "httpsport": "8001"}}
this tells others that "hi, I'm a kimchi host, I'm alive and this
is my information"
o (user) 1 is "search"
/\ --------> 2 is "notify"
| 1 _____ ________________
kimchi-host1 ------2-<---| DB |<----2-----|multicast listen |<--2--
| |____| |_______________|
|
----------------------1-------------------------------> |
|
_____ |_____
| |
| switch |
| |
|___________|
o (user) |
/\ --------- -----------------------------2----------------------- --->|
| | _____ ________________ |
kimchi-host3 ------1<---| DB |<---1------|multicast listen |<---1--|
|____| |_______________|
we need to discuss:
1. should we support beat heart?
every kimchi host will send periodic notify to tell others himself
information?
2. should we support a "quit" message?
"quit" message tell other peers, that this kimchi quit normally. others
can remove this from peers list.
But the kimchi can not send "quit" when aborting abnormally.
3. Do we store the local peers information in DB?
we can collection the local peers and send them immediately when user
need to discover the peers.
We will extend to support remote peers, these information need to be
stored in DB.
--
Thanks and best regards!
Sheldon Feng(???)<shaohef(a)linux.vnet.ibm.com>
IBM Linux Technology Center
3
8
A good usability practice is to leave the focus on the first editable
field on a form. That way, the user can start typing immediately what
they want without having to use the mouse to click on the
input element.
Explicitely request focus to every form's first field. Some input
elements did not have an ID; in those cases, the IDs were also added
to the HTML code.
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.guest_add_main.js | 1 +
ui/js/src/kimchi.guest_edit_main.js | 1 +
ui/js/src/kimchi.report_add_main.js | 1 +
ui/js/src/kimchi.repository_add_main.js | 1 +
ui/js/src/kimchi.repository_edit_main.js | 1 +
ui/js/src/kimchi.storagepool_add_main.js | 1 +
ui/js/src/kimchi.template_edit_main.js | 2 ++
ui/pages/guest-add.html.tmpl | 2 +-
ui/pages/repository-add.html.tmpl | 2 +-
9 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/ui/js/src/kimchi.guest_add_main.js b/ui/js/src/kimchi.guest_add_main.js
index 2113099..0a4f5e6 100644
--- a/ui/js/src/kimchi.guest_add_main.js
+++ b/ui/js/src/kimchi.guest_add_main.js
@@ -77,6 +77,7 @@ kimchi.guest_add_main = function() {
$('#form-vm-add').on('submit', addGuest);
$('#vm-doAdd').on('click', addGuest);
+ $('#guest-add-id-textbox').focus();
showTemplates();
};
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 0236e2d..3588dcc 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -225,4 +225,5 @@ kimchi.guest_edit_main = function() {
$(guestEditForm).on('submit', submitForm);
$(saveButton).on('click', submitForm);
+ $('#guest-edit-id-textbox').focus();
};
diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js
index 8759c2b..f7f1b4b 100644
--- a/ui/js/src/kimchi.report_add_main.js
+++ b/ui/js/src/kimchi.report_add_main.js
@@ -43,4 +43,5 @@ kimchi.report_add_main = function() {
addReportForm.on('submit', submitForm);
submitButton.on('click', submitForm);
+ nameTextbox.focus();
};
diff --git a/ui/js/src/kimchi.repository_add_main.js b/ui/js/src/kimchi.repository_add_main.js
index 5dc84e5..4ee7a62 100644
--- a/ui/js/src/kimchi.repository_add_main.js
+++ b/ui/js/src/kimchi.repository_add_main.js
@@ -97,4 +97,5 @@ kimchi.repository_add_main = function() {
};
$(addForm).on('submit', addRepository);
+ $('#repo_id').focus();
};
diff --git a/ui/js/src/kimchi.repository_edit_main.js b/ui/js/src/kimchi.repository_edit_main.js
index 26d6c66..0b562ee 100644
--- a/ui/js/src/kimchi.repository_edit_main.js
+++ b/ui/js/src/kimchi.repository_edit_main.js
@@ -72,4 +72,5 @@ kimchi.repository_edit_main = function() {
$(editForm).on('submit', editRepository);
$(saveButton).on('click', editRepository);
+ $('#repository-edit-name-textbox').focus();
};
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..d37a37d 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -20,6 +20,7 @@ kimchi.storagepool_add_main = function() {
kimchi.initStorageAddPage();
$('#form-pool-add').on('submit', kimchi.addPool);
$('#pool-doAdd').on('click', kimchi.addPool);
+ $('#poolId').focus();
};
kimchi.initStorageAddPage = function() {
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index f0f4718..a0e9e28 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -177,4 +177,6 @@ kimchi.template_edit_main = function() {
kimchi.message.error(err.responseJSON.reason);
});
});
+
+ $('#template-edit-id-textbox').focus();
};
diff --git a/ui/pages/guest-add.html.tmpl b/ui/pages/guest-add.html.tmpl
index 84a1994..e478b2e 100644
--- a/ui/pages/guest-add.html.tmpl
+++ b/ui/pages/guest-add.html.tmpl
@@ -37,7 +37,7 @@
<p class="text-help">
$_("The name used to identify the virtual machine. If omitted, a name will be chosen based on the template used.")
</p>
- <input type="text" class="text" style="width: 300px" name="name">
+ <input type="text" class="text" style="width: 300px" name="name" id="guest-add-id-textbox">
</div>
</section>
<section class="form-section">
diff --git a/ui/pages/repository-add.html.tmpl b/ui/pages/repository-add.html.tmpl
index 05b4de9..9a8a037 100644
--- a/ui/pages/repository-add.html.tmpl
+++ b/ui/pages/repository-add.html.tmpl
@@ -39,7 +39,7 @@
$_("Single word, unique identifier for the repository.")
</p>
<div class="textbox-wrapper">
- <input type="text" class="text" name="repo_id" />
+ <input type="text" class="text" name="repo_id" id="repo_id" />
</div>
</div>
</div>
--
1.9.0
2
2
[PATCHv2] Issue#348: Add loading icon when nfs mount is in progress
by lvroyce@linux.vnet.ibm.com 10 Jun '14
by lvroyce@linux.vnet.ibm.com 10 Jun '14
10 Jun '14
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
v1>v2, Improve feedback msg according to Hongliang's comments.
Add loading icon to indicate nfs mount in progress,
when error or normal response returns,
close create window.
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.storagepool_add_main.js | 2 ++
ui/pages/storagepool-add.html.tmpl | 6 ++++++
2 files changed, 8 insertions(+)
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..6b77bd8 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -198,6 +198,7 @@ kimchi.validateNfsForm = function () {
kimchi.message.error.code('KCHPOOL6005E');
return false;
}
+ $('#nfs-mount-loading').removeClass('hidden');
return true;
};
@@ -295,6 +296,7 @@ kimchi.addPool = function(event) {
kimchi.window.close();
}, function(err) {
kimchi.message.error(err.responseJSON.reason);
+ kimchi.window.close();
});
}
}
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 977db66..b033b36 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -91,6 +91,12 @@
</ul>
</div>
</div>
+ <div class="hidden" id="nfs-mount-loading">
+ <p class="text-help">
+ $_("Trying to mount NFS export path. It may take several seconds.")
+ <img src = "../images/theme-default/loading.gif" />
+ </p>
+ </div>
</div>
</section>
</div>
--
1.8.3.2
6
7
Finished align vlan fields. Redesigned the pattern of the label positions
V3 -> V4:
Address to Hongliang Wang: Assigned "for" attribute for label to associate it with text box accordingly
V2 -> V3:
Address to Hongliang Wang: Have the additional margin place removed.
v1 -> v2:
Address to Hongliang Wang: Have the unrelated lines removed & Have the display format changed from table to div.
Address to Yuxin Huo: Have the unused IDs removed.
Signed-off-by: Wen Wang <wenwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/network.css | 21 ++++++++++++++++-----
ui/js/src/kimchi.network.js | 8 ++++----
ui/pages/tabs/network.html.tmpl | 34 +++++++++++++++++++++-------------
3 files changed, 41 insertions(+), 22 deletions(-)
diff --git a/ui/css/theme-default/network.css b/ui/css/theme-default/network.css
index 67f2aa2..176b277 100644
--- a/ui/css/theme-default/network.css
+++ b/ui/css/theme-default/network.css
@@ -209,19 +209,30 @@
vertical-align: top;
}
-.network-config .destination {
- margin-left: 28px;
+.bridge-option-column {
+ display: inline-block;
+ margin-left: 56px;
+ vertical-align: middle;
+}
+
+.bridge-option-column > div {
+ height: 25px;
+ line-height: 25px;
}
-.network-config .VLAN {
- margin-left: 28px;
+.bridge-option-column select {
+ height: 26px;
}
-.network-config .VLAN input[type="text"] {
+.bridge-option-column input[type="text"] {
height: 25px;
width: 60px;
}
+#labelNetworkVlanID {
+ margin-left: 26px;
+}
+
.network-config .input-hint-icon {
margin: -1px 1px 0 0;
display: inline-block;
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index 7a331be..ca6d29b 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -275,13 +275,14 @@ kimchi.enableBridgeOptions = function(enable) {
$("#networkVlanID").prop("disabled", true);
$("#networkVlanID").val("");
$("#networkInterface").val("");
- $("#bridge-options").slideUp(100);
+ $("#bridgeOptions").slideUp(100);
} else if (!$("#networkInterface").val()){
$("#networkInterface").prop("selectedIndex", 0);
- $("#bridge-options").slideDown(100);
+ $("#bridgeOptions").slideDown(100);
}
};
+
kimchi.setDefaultNetworkType = function(isInterfaceAvail) {
$("#networkTypeBri").prop("checked", isInterfaceAvail);
$("#networkTypeBri").prop("disabled", !isInterfaceAvail);
@@ -289,7 +290,7 @@ kimchi.setDefaultNetworkType = function(isInterfaceAvail) {
if (!isInterfaceAvail) {
kimchi.enableBridgeOptions(false);
} else {
- $("#bridge-options").slideDown(100);
+ $("#bridgeOptions").slideDown(100);
}
};
@@ -318,7 +319,6 @@ kimchi.cleanNetworkDialog = function() {
$("#networkVlanID").prop("disabled", true);
$("#enableVlan").prop("checked", false);
};
-
kimchi.setupNetworkFormEvent = function() {
$("#networkName").on("keyup", function(event) {
$("#networkName").toggleClass("invalid-field", !$("#networkName").val().match(/^[a-zA-Z0-9_]+$/));
diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl
index e49b257..aedf7e8 100644
--- a/ui/pages/tabs/network.html.tmpl
+++ b/ui/pages/tabs/network.html.tmpl
@@ -46,7 +46,7 @@
<div class="section-container">
<div class="section-header">1. $_("Network Name")</div>
<div class="section-content">
- <input type="text" id="networkName">
+ <input type="text" id="networkName" />
<div class="input-hint">
<span class="ui-icon ui-icon-info input-hint-icon"></span>
<span class="input-hint-text">$_("Alphanumeric and '_' characters only.")</span>
@@ -57,27 +57,35 @@
<div class="section-header">2. $_("Network Type")</div>
<div class="section-content">
<div class="input-container">
- <input type="radio" id="networkTypeIso" name="networkType" value="isolated">
+ <input type="radio" id="networkTypeIso" name="networkType" value="isolated" />
<label for="networkTypeIso">$_("Isolated: no physical network connection")</label>
</div>
<div class="input-container">
- <input type="radio" id="networkTypeNat" name="networkType" value="nat">
+ <input type="radio" id="networkTypeNat" name="networkType" value="nat" />
<label for="networkTypeNat">$_("NAT: outbound physical network connection only")</label>
</div>
<div class="input-container">
- <input type="radio" id="networkTypeBri" name="networkType" value="bridged">
+ <input type="radio" id="networkTypeBri" name="networkType" value="bridged" />
<label for="networkTypeBri">$_("Bridged: Virtual machines are connected to physical network directly")</label>
</div>
- <div id="bridge-options">
- <div class="destination">
- <label for="networkInterface">$_("Destination"): </label>
- <select id="networkInterface"></select>
+ <div id="bridgeOptions">
+ <div class="bridge-option-column">
+ <div>
+ <label for="networkInterface">$_("Destination"): </label>
+ </div>
+ <div>
+ <select id="networkInterface"></select>
+ </div>
</div>
- <div class="VLAN">
- <label for="enableVlan">$_("Enable VLAN"): </label>
- <input id="enableVlan" type="checkbox" value=""/>
- <label for="networkVlanID">$_("VLAN ID"): </label>
- <input type="text" id="networkVlanID" disabled>
+ <div class="bridge-option-column">
+ <div>
+ <input id="enableVlan" type="checkbox" value="" />
+ <label for="enableVlan">$_("Enable VLAN"): </label>
+ </div>
+ <div>
+ <label for="networkVlanID" id="labelNetworkVlanID">$_("VLAN ID"): </label>
+ <input type="text" id="networkVlanID" disabled />
+ </div>
</div>
</div>
</div>
--
1.9.1
6
15
[PATCH 1/2] List iSCSI server for initiator while creating iSCSI Pool
by shaohef@linux.vnet.ibm.com 09 Jun '14
by shaohef@linux.vnet.ibm.com 09 Jun '14
09 Jun '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
The server should be already used in an existed iSCSI Pool.
Test this patch by:
$ curl -k -u shhfeng:123456 -H "Content-Type: application/json" \
> -H "Accept: application/json" \
> http://localhost:8000/storageservers?_target_type=iscsi
[
{
"host":"127.0.0.1"
}
]
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 2 +-
src/kimchi/model/storagepools.py | 4 +++-
src/kimchi/model/storageservers.py | 3 +--
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index 76c94ab..05a5866 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -416,7 +416,7 @@
"_target_type": {
"description": "List storage servers of given type",
"type": "string",
- "pattern": "^netfs$"
+ "pattern": "^netfs|iscsi$"
}
},
"additionalProperties": false,
diff --git a/src/kimchi/model/storagepools.py b/src/kimchi/model/storagepools.py
index c0f2c58..c699fc6 100644
--- a/src/kimchi/model/storagepools.py
+++ b/src/kimchi/model/storagepools.py
@@ -37,9 +37,11 @@ POOL_STATE_MAP = {0: 'inactive',
4: 'inaccessible'}
# Types of pools supported
-# FIXME: Addd 'iscsi'
STORAGE_SOURCES = {'netfs': {'addr': '/pool/source/host/@name',
'path': '/pool/source/dir/@path'},
+ 'iscsi': {'addr': '/pool/source/host/@name',
+ 'port': '/pool/source/host/@port',
+ 'path': '/pool/source/device/@path'},
'scsi': {'adapter_type': '/pool/source/adapter/@type',
'adapter_name': '/pool/source/adapter/@name',
'wwnn': '/pool/source/adapter/@wwnn',
diff --git a/src/kimchi/model/storageservers.py b/src/kimchi/model/storageservers.py
index c9dfb25..6259b92 100644
--- a/src/kimchi/model/storageservers.py
+++ b/src/kimchi/model/storageservers.py
@@ -21,8 +21,7 @@ from kimchi.exception import NotFoundError
from kimchi.model.storagepools import StoragePoolModel, StoragePoolsModel
# Types of remote storage servers supported
-# FIXME: Add iscsi?
-STORAGE_SERVERS = ['netfs']
+STORAGE_SERVERS = ['netfs', 'iscsi']
class StorageServersModel(object):
--
1.9.3
4
5
09 Jun '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
V2 -> V3:
change "enable-plugins" to "enable-sample"
remove nls
improve the Portuguese translation.
V1 -> V2:
The improvement concept here is to directly generate JSON on the server
and assign it to the i18n variable, rather than inserting nodes into the DOM.
Plugins would use a plugin1.i18n= structure to keep plugin strings from
colliding with each other, or with the kimchi variables.
ShaoHe Feng (6):
Update root.py to make Cheetah render the JSON template.
Update the i18n tmpl to produce JSON
Add JS API for fetching i18n JSON
Issue #342: load i18n.html of the plugin
add an optional to toggle the sample plugin
generate the translation files for plugins/sample
Zhou Zheng Sheng (1):
Add Minimal UI Page for the Sample Plugin
configure.ac | 11 +++
plugins/sample/Makefile.am | 26 ++++-
plugins/sample/__init__.py | 3 +-
plugins/sample/config.status | 1 +
plugins/sample/po/LINGUAS | 1 +
plugins/sample/po/Makefile.in.in | 1 +
plugins/sample/po/Makevars | 1 +
plugins/sample/po/POTFILES.in | 2 +
plugins/sample/po/en_US.po | 21 ++++
plugins/sample/po/gen-pot | 1 +
plugins/sample/po/pt_BR.po | 24 +++++
plugins/sample/po/zh_CN.po | 24 +++++
plugins/sample/sample.conf | 7 --
plugins/sample/sample.conf.in | 12 +++
plugins/sample/ui/config/tab-ext.xml | 8 +-
plugins/sample/ui/pages/i18n.json.tmpl | 9 ++
plugins/sample/ui/pages/tab.html.tmpl | 6 ++
src/kimchi/root.py | 5 +
src/kimchi/template.py | 34 ++++---
ui/js/src/kimchi.api.js | 18 +++-
ui/js/src/kimchi.main.js | 24 ++++-
ui/pages/i18n.html.tmpl | 176 ---------------------------------
ui/pages/i18n.json.tmpl | 163 ++++++++++++++++++++++++++++++
23 files changed, 367 insertions(+), 211 deletions(-)
create mode 120000 plugins/sample/config.status
create mode 120000 plugins/sample/po/LINGUAS
create mode 120000 plugins/sample/po/Makefile.in.in
create mode 120000 plugins/sample/po/Makevars
create mode 100644 plugins/sample/po/POTFILES.in
create mode 100644 plugins/sample/po/en_US.po
create mode 120000 plugins/sample/po/gen-pot
create mode 100644 plugins/sample/po/pt_BR.po
create mode 100644 plugins/sample/po/zh_CN.po
delete mode 100644 plugins/sample/sample.conf
create mode 100644 plugins/sample/sample.conf.in
create mode 100644 plugins/sample/ui/pages/i18n.json.tmpl
create mode 100644 plugins/sample/ui/pages/tab.html.tmpl
delete mode 100644 ui/pages/i18n.html.tmpl
create mode 100644 ui/pages/i18n.json.tmpl
--
1.9.0
2
8
Keep consistent with interface setup tab.
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/guest-edit.css | 92 ++++++++++---------------------------
ui/js/src/kimchi.guest_edit_main.js | 23 ++++++++--
ui/pages/guest-edit.html.tmpl | 39 ++++++++--------
3 files changed, 63 insertions(+), 91 deletions(-)
diff --git a/ui/css/theme-default/guest-edit.css b/ui/css/theme-default/guest-edit.css
index 36f7f75..52c53eb 100644
--- a/ui/css/theme-default/guest-edit.css
+++ b/ui/css/theme-default/guest-edit.css
@@ -89,74 +89,7 @@
width: 400px;
}
-.guest-edit-cdrom-button {
- background: url("../images/theme-default/guest-icon-sprite.png") no-repeat left top transparent;
- border: none;
- height: 25px;
- vertical-align: middle;
- width: 25px;
-}
-
-.guest-edit-cdrom-button.attach {
- margin: 15px 0 0 521px;
-}
-
-.guest-edit-cdrom-button.attach:hover {
- background-position: 0 -27px;
-}
-
-.guest-edit-cdrom-button.attach:focus {
- background-position: 0 -54px;
-}
-
-.guest-edit-cdrom-button.attach:active {
- background-position: 0 -81px;
-}
-
-.guest-edit-cdrom-button.attach[disabled] {
- background-position: 0 -108px;
-}
-
-.guest-edit-cdrom-button.replace {
- background-position: -27px 0;
-}
-
-.guest-edit-cdrom-button.replace:hover {
- background-position: -27px -27px;
-}
-
-.guest-edit-cdrom-button.replace:focus {
- background-position: -27px -54px;
-}
-
-.guest-edit-cdrom-button.replace:active {
- background-position: -27px -81px;
-}
-
-.guest-edit-cdrom-button.replace[disabled] {
- background-position: -27px -108px;
-}
-
-.guest-edit-cdrom-button.detach {
- background-position: -54px 0;
-}
-
-.guest-edit-cdrom-button.detach:hover {
- background-position: -54px -27px;
-}
-
-.guest-edit-cdrom-button.detach:focus {
- background-position: -54px -54px;
-}
-
-.guest-edit-cdrom-button.detach:active {
- background-position: -54px -81px;
-}
-
-.guest-edit-cdrom-button.detach[disabled] {
- background-position: -54px -108px;
-}
-
+#form-guest-edit-storage .header,
.guest-edit-interface .header {
margin-bottom: 8px;
padding-bottom: 2px;
@@ -165,33 +98,56 @@
overflow: hidden;
}
+#form-guest-edit-storage .body .item,
.guest-edit-interface .body .item {
margin: 5px 0;
}
+#form-guest-edit-storage .cell,
.guest-edit-interface .cell {
display: inline-block;
width: 250px;
}
+#form-guest-edit-storage .cell.dev {
+ width: 60px;
+}
+
+#form-guest-edit-storage .cell.path {
+ width: 440px;
+}
+
+#form-guest-edit-storage .cell.path input {
+ box-sizing: border-box;
+ width: 100%;
+}
+
.guest-edit-interface .body select {
width: 180px;
padding: 0px;
}
+#form-guest-edit-storage .action-area,
.guest-edit-interface .action-area {
float: right;
}
+#form-guest-edit-storage .action-area {
+ line-height: 24px;
+}
+
+#form-guest-edit-storage button,
.guest-edit-interface button {
width: 20px;
height: 20px;
}
+#form-guest-edit-storage .header button,
.guest-edit-interface .header button {
margin-bottom: 1px;
}
+#form-guest-edit-storage .body button:not(:last-child),
.guest-edit-interface .body button:not(:last-child) {
margin-right: 2px;
}
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 0236e2d..ba5fef5 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -36,7 +36,7 @@ kimchi.guest_edit_main = function() {
kimchi.listVMStorages({
vm: kimchi.selectedGuest
}, function(storages) {
- var container = $('#guest-edit-cdrom-row-container');
+ var container = $('#form-guest-edit-storage .body');
$(container).empty();
$.each(storages, function(index, storage) {
@@ -53,9 +53,19 @@ kimchi.guest_edit_main = function() {
};
$('input[type="text"][name="cdrom"]', container).on('click', replaceCDROM);
- $('.replace', container).on('click', replaceCDROM);
+ $('.replace', container).button({
+ icons: {
+ primary: 'ui-icon-pencil'
+ },
+ text: false
+ }).click(replaceCDROM);
- $('.detach', container).on('click', function(e) {
+ $('.detach', container).button({
+ icons: {
+ primary: 'ui-icon-trash'
+ },
+ text: false
+ }).click(function(e) {
e.preventDefault();
var settings = {
title : i18n['KCHAPI6004M'],
@@ -172,7 +182,12 @@ kimchi.guest_edit_main = function() {
refreshCDROMs();
- $('#guest-edit-attach-cdrom-button').on('click', function(event) {
+ $('#guest-edit-attach-cdrom-button').button({
+ icons: {
+ primary: "ui-icon-plusthick"
+ },
+ text: false
+ }).click(function(event) {
event.preventDefault();
kimchi.window.open("guest-storage-add.html");
});
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 96d907e..3b7291a 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -94,15 +94,12 @@
</fieldset>
</form>
<form id="form-guest-edit-storage">
- <fieldset class="guest-edit-fieldset">
- <div id="guest-edit-cdrom-row-container" class="guest-edit-cdrom-row-container"></div>
- <div>
- <button id="guest-edit-attach-cdrom-button"
- class="guest-edit-cdrom-button attach"
- title='$_("Attach")'>
- </button>
- </div>
- </fieldset>
+ <div class="header">
+ <span class="cell">$_("Device")</span>
+ <span class="cell">$_("Path")</span>
+ <button id="guest-edit-attach-cdrom-button" class="action-area attach"></button>
+ </div>
+ <div class="body"></div>
</form>
<form id="form-guest-edit-interface" class="guest-edit-interface">
<div class="header">
@@ -123,14 +120,16 @@
</footer>
</div>
<script id="cdrom-row-tmpl" type="text/html">
- <div>
- <div class="guest-edit-wrapper-label">
+ <div class="item" id="cdrom-{dev}">
+ <span class="cell dev">
<label for="cdrom-{dev}">{dev}</label>
- </div>
- <div class="guest-edit-wrapper-controls">
+ </span>
+ <span class="cell path">
<input id="cdrom-{dev}" name="cdrom" type="text"
data-vm="{vm}" data-dev="{dev}"
value="{path}" readonly="readonly" />
+ </span>
+ <span class="action-area">
<button class="guest-edit-cdrom-button replace"
data-vm="{vm}" data-dev="{dev}"
title='$_("Replace")'>
@@ -139,7 +138,7 @@
data-vm="{vm}" data-dev="{dev}"
title='$_("Detach")'>
</button>
- </div>
+ </span>
</div>
</script>
<script id="interface-tmpl" type="text/html">
@@ -160,19 +159,21 @@
<div>
</script>
<script id="disk-row-tmpl" type="text/html">
- <div>
- <div class="guest-edit-wrapper-label">
+ <div class="item" id="cdrom-{dev}">
+ <span class="cell dev">
<label for="disk-{dev}">{dev}</label>
- </div>
- <div class="guest-edit-wrapper-controls">
+ </span>
+ <span class="cell path">
<input id="disk-{dev}" name="disk" type="text"
data-vm="{vm}" data-dev="{dev}"
value="{path}" readonly="readonly" />
+ </span>
+ <span class="action-area">
<button class="guest-edit-cdrom-button detach"
data-vm="{vm}" data-dev="{dev}"
title="$_("Detach")">
</button>
- </div>
+ </span>
</div>
</script>
<script type="text/javascript">
--
1.8.1.4
2
5
Enable debug report rename feature in this patch set.
v1 -> v2:
2a) Retrieved the Right Generated Time for Debug Report
(Wen Wang's comment)
2b) Sorted debug reports by Generated Time Descendingly
(Wen Wang's comment)
2c) Enabled Form Fields after Request Processed
(Yuxin's comment)
Hongliang Wang (8):
Debug Report Rename: Update API.json
Debug Report Rename: Update API.md
Debug Report Rename: Implement Back-end
Debug Report: Use Generated Time instead of Most Changed Time
Debug Report: Sort Reports by Generated Time Descendingly
Debug Report Rename UI: Add API in kimchi.api.js
Debug Report Rename UI: Add Rename Page
Debug Report Rename UI: Enable Rename in Host Tab
docs/API.md | 3 ++
src/kimchi/API.json | 11 +++++++
src/kimchi/control/debugreports.py | 8 ++++-
src/kimchi/model/debugreports.py | 15 +++++++++-
ui/css/theme-default/report-rename.css | 22 ++++++++++++++
ui/js/src/kimchi.api.js | 12 ++++++++
ui/js/src/kimchi.host.js | 12 ++++++++
ui/js/src/kimchi.report_rename_main.js | 41 ++++++++++++++++++++++++++
ui/pages/report-rename.html.tmpl | 53 ++++++++++++++++++++++++++++++++++
9 files changed, 175 insertions(+), 2 deletions(-)
create mode 100644 ui/css/theme-default/report-rename.css
create mode 100644 ui/js/src/kimchi.report_rename_main.js
create mode 100644 ui/pages/report-rename.html.tmpl
--
1.8.1.4
5
22
From: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
Due to the timeout period to see if the NFS pool is
online, the Storage tab may look irresponsible and
the user might believe that the UI/kimchi is frozen.
Inserting the loading icon+text in this tab to show that
the UI is responsive, just waiting for an answer from the
server.
Signed-off-by: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.storage_main.js | 2 ++
ui/pages/tabs/storage.html.tmpl | 8 +++++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js
index 6052510..74e6892 100644
--- a/ui/js/src/kimchi.storage_main.js
+++ b/ui/js/src/kimchi.storage_main.js
@@ -17,6 +17,7 @@
*/
kimchi.doListStoragePools = function() {
kimchi.listStoragePools(function(result) {
+ $('#storagepoolsLoading').addClass('hidden');
var storageHtml = $('#storageTmpl').html();
if (result && result.length) {
var listHtml = '';
@@ -34,6 +35,7 @@ kimchi.doListStoragePools = function() {
$('#storagepoolsList').html('');
}
}, function(err) {
+ $('#storagepoolsLoading').addClass('hidden');
kimchi.message.error(err.responseJSON.reason);
});
diff --git a/ui/pages/tabs/storage.html.tmpl b/ui/pages/tabs/storage.html.tmpl
index c3a992e..e837599 100644
--- a/ui/pages/tabs/storage.html.tmpl
+++ b/ui/pages/tabs/storage.html.tmpl
@@ -40,7 +40,13 @@
<li class="title-actions">$_("Actions")</li>
</div>
<ul id="storagepoolsList" class="list-storage empty-when-logged-off"></ul>
-</div>
+ <div id="storagepoolsLoading">
+ <div class="grid-loading">
+ <div class="grid-loading-icon"></div>
+ <div class="grid-loading-text">$_("loading")</div>
+ </div>
+ </div>
+ </div>
<script id="storageTmpl" type="html/text">
<li id="{name}">
<div class="storage-li in" data-name="{name}" data-stat="{state}">
--
1.8.3.1
3
3
05 Jun '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
commit c53b3eab just fix volume name in StorageVolumeModel.
reproduce this bug:
1. create a iso pool
2. put a iso with name αβγ.iso in it
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
src/kimchi/model/storagevolumes.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py
index d58fd0b..fd7e24d 100644
--- a/src/kimchi/model/storagevolumes.py
+++ b/src/kimchi/model/storagevolumes.py
@@ -239,7 +239,7 @@ class IsoVolumesModel(object):
continue
for volume in volumes:
- res = self.storagevolume.lookup(pool_name, volume)
+ res = self.storagevolume.lookup(pool_name, volume.decode("utf-8"))
if res['format'] == 'iso':
res['name'] = '%s' % volume
iso_volumes.append(res)
--
1.9.3
2
1
Crístian Viana (3):
Add missing closing quote in HTML code
Use the verb "Create" in all create operations
Use action verb as the main button's label
po/en_US.po | 11 ++++-------
po/kimchi.pot | 7 ++-----
po/pt_BR.po | 11 ++++-------
po/zh_CN.po | 11 ++++-------
ui/js/src/kimchi.guest_edit_main.js | 8 ++++----
ui/js/src/kimchi.repository_edit_main.js | 6 +++---
ui/js/src/kimchi.template_edit_main.js | 2 +-
ui/pages/guest-edit.html.tmpl | 4 ++--
ui/pages/repository-edit.html.tmpl | 4 ++--
ui/pages/storagepool-add.html.tmpl | 2 +-
ui/pages/template-add.html.tmpl | 2 +-
ui/pages/template-edit.html.tmpl | 2 +-
12 files changed, 29 insertions(+), 41 deletions(-)
--
1.9.0
4
8
[PATCH] use LibvirtConnection instead of libivrt open directily to to get connection
by shaohef@linux.vnet.ibm.com 05 Jun '14
by shaohef@linux.vnet.ibm.com 05 Jun '14
05 Jun '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
On my F20, the kimchi can not start. It report:
$ sudo PYTHONPATH=src ./src/kimchid
*** Running feature tests ***
[21/May/2014:19:41:48] ENGINE Error in 'start' listener <bound method
CapabilitiesModel._set_capabilities of
<kimchi.model.config.CapabilitiesModel object at 0x314ac10>>
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/cherrypy/process/wspbus.py",
line 197, in publish
output.append(listener(*args, **kwargs))
File "/home/shhfeng/work/workdir/kimchi/src/kimchi/model/config.py",
line 69, in _set_capabilities
self.metadata_support = FeatureTests.has_metadata_support()
File "/home/shhfeng/work/workdir/kimchi/src/kimchi/featuretests.py",
line 197, in has_metadata_support
conn = libvirt.open('qemu:///system')
File "/usr/lib64/python2.7/site-packages/libvirt.py", line 247, in
open
if ret is None:raise libvirtError('virConnectOpen() failed')
libvirtError: Failed to connect socket to
'/var/run/libvirt/libvirt-sock': Connection refused
[21/May/2014:19:41:48] ENGINE Shutting down due to error in start
listener:
[21/May/2014:19:41:48] ENGINE Bus STOPPING
Now use LibvirtConnection to get connection, kimchi can work well.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
src/kimchi/featuretests.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/kimchi/featuretests.py b/src/kimchi/featuretests.py
index 5192361..df833e1 100644
--- a/src/kimchi/featuretests.py
+++ b/src/kimchi/featuretests.py
@@ -28,6 +28,7 @@
from lxml.builder import E
+from kimchi.model.libvirtconnection import LibvirtConnection
from kimchi.rollbackcontext import RollbackContext
from kimchi.utils import kimchi_log
@@ -104,7 +105,7 @@ def libvirt_supports_iso_stream(protocol):
conn = None
try:
FeatureTests.disable_screen_error_logging()
- conn = libvirt.open('qemu:///system')
+ conn = LibvirtConnection('qemu:///system').get()
dom = conn.defineXML(xml)
dom.undefine()
return True
@@ -122,7 +123,7 @@ def _get_xml():
xml = ET.tostring(obj)
return xml
try:
- conn = libvirt.open('qemu:///system')
+ conn = LibvirtConnection('qemu:///system').get()
FeatureTests.disable_screen_error_logging()
conn.findStoragePoolSources('netfs', _get_xml(), 0)
except libvirt.libvirtError as e:
@@ -174,7 +175,7 @@ def qemu_iso_stream_dns():
def libvirt_support_fc_host():
try:
FeatureTests.disable_screen_error_logging()
- conn = libvirt.open('qemu:///system')
+ conn = LibvirtConnection('qemu:///system').get()
pool = None
pool = conn.storagePoolDefineXML(SCSI_FC_XML, 0)
except libvirt.libvirtError as e:
@@ -194,7 +195,7 @@ def has_metadata_support():
with RollbackContext() as rollback:
FeatureTests.disable_screen_error_logging()
rollback.prependDefer(FeatureTests.enable_screen_error_logging)
- conn = libvirt.open('qemu:///system')
+ conn = LibvirtConnection('qemu:///system').get()
rollback.prependDefer(conn.close)
dom = conn.defineXML(SIMPLE_VM_XML)
rollback.prependDefer(dom.undefine)
--
1.9.0
5
4
vnc_auto.html has 2 meta tags for X-UA-Compatible preventing the IE mode from taking effect. Combine them so they are both effective.
Signed-off-by: Adam King <rak(a)linux.vnet.ibm.com>
---
ui/pages/vnc_auto.html.tmpl | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/ui/pages/vnc_auto.html.tmpl b/ui/pages/vnc_auto.html.tmpl
index f295019..bd96d60 100644
--- a/ui/pages/vnc_auto.html.tmpl
+++ b/ui/pages/vnc_auto.html.tmpl
@@ -12,8 +12,7 @@
-->
<head>
<title>noVNC</title>
- <meta http-equiv="X-UA-Compatible" content="chrome=1">
- <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+ <meta http-equiv="X-UA-Compatible" content="chrome=1, IE=Edge">
<link rel="stylesheet" href="$href("/css/novnc/base.css")" title="plain">
<script type='text/javascript'>
var INCLUDE_URI = "/js/novnc/";
--
1.9.0
4
4
05 Jun '14
1. Refactor code.
2. Put focus on log-in button instead of password box when browser
automatically fill in log-in form.
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.login_window.js | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/ui/js/src/kimchi.login_window.js b/ui/js/src/kimchi.login_window.js
index 9c06a50..c562159 100644
--- a/ui/js/src/kimchi.login_window.js
+++ b/ui/js/src/kimchi.login_window.js
@@ -50,6 +50,9 @@ kimchi.login_main = function() {
return true;
};
+ var userNameBox = $('#username');
+ var passwordBox = $('#password');
+ var loginButton = $('#btn-login');
var placeCursor = function(id) {
if (id && $('#' + id).size() > 0) {
$('#' + id).focus();
@@ -57,10 +60,10 @@ kimchi.login_main = function() {
}
var userName = kimchi.user.getUserName();
- userName && $('#username').val(userName);
+ userName && !userNameBox.val() && userNameBox.val(userName);
+ var password = passwordBox.val();
- var nodeToFocus = ! $('#username').val() ? $('#username') :
- (! $('#password').val() ? $('#password') : $('#btn-login'));
+ var nodeToFocus = !userName ? userNameBox : !password ? passwordBox : loginButton;
$(nodeToFocus).focus();
};
@@ -71,13 +74,13 @@ kimchi.login_main = function() {
return false;
}
- $('#btn-login').text(i18n['KCHAUTH6002M']).prop('disabled', true);
+ loginButton.text(i18n['KCHAUTH6002M']).prop('disabled', true);
- var userName = $('#username').val();
+ var userName = userNameBox.val();
userName && kimchi.user.setUserName(userName);
var settings = {
username: userName,
- password: $("#password").val()
+ password: passwordBox.val()
};
kimchi.login(settings, function() {
@@ -121,5 +124,5 @@ kimchi.login_main = function() {
$('#form-login').on('submit', login);
- placeCursor();
+ setTimeout(placeCursor, 0);
};
--
1.8.1.4
2
1
The libvirt function "metadata" always displays an error message when
the VM does not have a metadata section in its XML descriptor. Kimchi
refreshes the VM information every few seconds and a lot of error output
is printed on the console. The real exception can still be logged by the
"try/except" block, so the error itself is not being silenced, only its
output.
Even though this patch has no relation to feature tests, the functions which
enable/disable the libvirt error messages are located inside the class
FeatureTests so we need to import them.
Silence the metadata error output when trying to read the metadata
information from a VM.
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
src/kimchi/model/utils.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/kimchi/model/utils.py b/src/kimchi/model/utils.py
index a94c7f8..c9ab1d4 100644
--- a/src/kimchi/model/utils.py
+++ b/src/kimchi/model/utils.py
@@ -19,6 +19,7 @@
import re
from kimchi.exception import OperationFailed
+from kimchi.featuretests import FeatureTests
from kimchi.model.config import CapabilitiesModel
import libvirt
from lxml import etree
@@ -84,6 +85,7 @@ def _kimchi_set_metadata_node(dom, node):
def libvirt_get_kimchi_metadata_node(dom, mode="current"):
+ FeatureTests.disable_screen_error_logging()
try:
xml = dom.metadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT,
KIMCHI_META_URL,
@@ -91,6 +93,8 @@ def libvirt_get_kimchi_metadata_node(dom, mode="current"):
return etree.fromstring(xml)
except libvirt.libvirtError:
return None
+ finally:
+ FeatureTests.enable_screen_error_logging()
def set_metadata_node(dom, node, mode="all"):
--
1.9.0
3
2
Last commit was reverted because it failed for Ubuntu system.
Added it back and made it work for Ubuntu with this patch.
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/host.css | 24 ++++++++++++++++++++++++
ui/js/src/kimchi.host.js | 8 ++++----
2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/ui/css/theme-default/host.css b/ui/css/theme-default/host.css
index 6a1a308..dc7fccf 100644
--- a/ui/css/theme-default/host.css
+++ b/ui/css/theme-default/host.css
@@ -258,4 +258,28 @@
height: 200px;
width: 850px;
}
+
+.host-panel #repositories-grid .repository-id {
+ width: 120px;
+}
+
+.host-panel #repositories-grid .repository-name {
+ width: 640px;
+}
+
+.host-panel #repositories-grid .repository-enabled {
+ width: 92px;
+}
+
+.host-panel #repositories-grid .repository-baseurl.deb {
+ width: 400px;
+}
+
+.host-panel #repositories-grid .repository-enabled.deb {
+ width: 100px;
+}
+
+.host-panel #repositories-grid .repository-gpgcheck.deb {
+ width: 150px;
+}
/* End of Repository */
diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js
index 4c94fc1..3b0adec 100644
--- a/ui/js/src/kimchi.host.js
+++ b/ui/js/src/kimchi.host.js
@@ -47,19 +47,19 @@ kimchi.host_main = function() {
name: 'baseurl',
label: i18n['KCHREPO6006M'],
makeTitle: true,
- 'class': 'repository-baseurl'
+ 'class': 'repository-baseurl deb'
}, {
name: 'enabled',
label: i18n['KCHREPO6009M'],
- 'class': 'repository-enabled'
+ 'class': 'repository-enabled deb'
}, {
name: 'config[dist]',
label: "dist",
- 'class': 'repository-gpgcheck'
+ 'class': 'repository-gpgcheck deb'
}, {
name: 'config[comps]',
label: "comps",
- 'class': 'repository-gpgcheck'
+ 'class': 'repository-gpgcheck deb'
}];
}
else {
--
1.8.1.4
2
1
[PATCH] Issue #100: do not delete the VM when storage volume not found
by shaohef@linux.vnet.ibm.com 05 Jun '14
by shaohef@linux.vnet.ibm.com 05 Jun '14
05 Jun '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
The VM may not be in a certain pool for some reasons.
Or the pool may not be active for some reasons.
We do not allow to delete this VM in this case.
And report the detail message to user.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
---
src/kimchi/model/vms.py | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py
index 17bda04..3201fdd 100644
--- a/src/kimchi/model/vms.py
+++ b/src/kimchi/model/vms.py
@@ -426,14 +426,25 @@ class VMModel(object):
if info['state'] == 'running':
self.poweroff(name)
+ vols = []
+ for path in paths:
+ try:
+ vols.append(conn.storageVolLookupByPath(path))
+ except libvirt.libvirtError as e:
+ if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
+ raise OperationFailed(
+ "KCHVM0021E",
+ {'name': name, 'err': e.get_error_message()})
+ else:
+ raise
+
try:
dom.undefine()
except libvirt.libvirtError as e:
raise OperationFailed("KCHVM0021E",
{'name': name, 'err': e.get_error_message()})
- for path in paths:
- vol = conn.storageVolLookupByPath(path)
+ for vol in vols:
pool = vol.storagePoolLookupByVolume()
xml = pool.XMLDesc(0)
pool_type = xmlutils.xpath_get_text(xml, "/pool/@type")[0]
--
1.9.0
2
1
Long text in some languages of login button is truncated. Fix it in this patch.
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/login-window.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/css/theme-default/login-window.css b/ui/css/theme-default/login-window.css
index 8a21090..f4ad5f8 100644
--- a/ui/css/theme-default/login-window.css
+++ b/ui/css/theme-default/login-window.css
@@ -69,7 +69,7 @@
#login-window .login-panel button {
font-size: 18px;
height: 40px;
- width: 160px;
+ min-width: 160px;
float: right;
}
--
1.8.1.4
4
3
03 Jun '14
The storage pool type list does not have a left padding like the
other combo boxes in Kimchi, bringing the text very close to the UI
component's border.
The SCSI device list on the same window has the same alignment problem.
Apply a common CSS class to the combo boxes so they look like the other
objects in the application.
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
ui/pages/storagepool-add.html.tmpl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 977db66..ba85e6e 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -44,7 +44,7 @@
<div class="storage-type-wrapper-controls">
<div id="poolTypeId">
<input id="poolTypeInputId" name="type" type="hidden" value="dir"/>
- <span id="pool-type-label"></span><span class="arrow"></span>
+ <span id="pool-type-label" class="text"></span><span class="arrow"></span>
<div>
<ul id="storagePool-list">
</ul>
@@ -142,7 +142,7 @@
<div class="storage-type-wrapper-controls">
<div id="scsiAdapter">
<input type="hidden"/>
- <span></span><span class="arrow"></span>
+ <span class="text"></span><span class="arrow"></span>
<div><ul></ul></div>
</div>
</div>
--
1.9.0
4
3
Only one of the modal dialogs in Kimchi has a "Cancel" button along with
the form submit button. That button layout is inconsistent with the rest of
the application and it provides the same functionality as the "X" button
present at the top of every dialog.
Remove the button "Cancel" from the dialog "Edit template".
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.template_edit_main.js | 4 ----
ui/pages/template-edit.html.tmpl | 1 -
2 files changed, 5 deletions(-)
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index f0f4718..9ff8bcc 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -104,10 +104,6 @@ kimchi.template_edit_main = function() {
});
});
- $('#tmpl-edit-button-cancel').on('click', function() {
- kimchi.window.close();
- });
-
$('#template-edit-storagePool').change(function() {
storagepool = $(this).val();
var storageArray = storagepool.split("/");
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 434d938..8a4f0e4 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -141,7 +141,6 @@
</div>
<footer>
<div class="btn-group">
- <a id="tmpl-edit-button-cancel" class="btn-normal" href="javascript:void(0);"><span class="text">$_("Cancel")</span></a>
<a id="tmpl-edit-button-save" class="btn-normal" href="javascript:void(0);"><span class="text">$_("Save")</span></a>
</div>
</footer>
--
1.9.0
4
4
The README should indicate that Kimchi now supports FF 24 ESR which was released late in 2013.
Signed-off-by: Adam King <rak(a)linux.vnet.ibm.com>
---
docs/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/README.md b/docs/README.md
index 63ac760..c658637 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -14,7 +14,7 @@ Desktop Browser Support:
-----------------------
* **Internet Explorer:** IE9+
* **Chrome:** Current-1 version
-* **Firefox:** Current-1 version Firefox 17ESR
+* **Firefox:** Current-1 version Firefox 24ESR
* **Safari:** Current-1 version
* **Opera:** Current-1 version
--
1.9.0
5
4
The schema checker needs to report an error message when the disk size
is less than 1GB. Currently this message is missing, so it reports an
KeyError. This patch adds the error message.
How to trigger this bug:
1. In Web UI, create a template as usual.
2. Edit the template, define the disk size as 0.5.
v2:
v1 adds the error to "disks", but the error is not raised against it.
v2 correctly adds the error message to the "size" constraint.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 6 ++++--
src/kimchi/i18n.py | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index b9d371a..76c94ab 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -379,7 +379,8 @@
"size": {
"description": "Size (GB) of the disk",
"type": "number",
- "minimum": 1
+ "minimum": 1,
+ "error": "KCHTMPL0022E"
}
}
},
@@ -549,7 +550,8 @@
"size": {
"description": "Size (GB) of the disk",
"type": "number",
- "minimum": 1
+ "minimum": 1,
+ "error": "KCHTMPL0022E"
}
}
},
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 25b703f..e105e50 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -119,6 +119,7 @@ messages = {
"KCHTMPL0019E": _("The volume: %(volume)s in not in storage pool %(pool)s"),
"KCHTMPL0020E": _("Unable to create template due error: %(err)s"),
"KCHTMPL0021E": _("Unable to delete template due error: %(err)s"),
+ "KCHTMPL0022E": _("Disk size must be greater than 1GB."),
"KCHPOOL0001E": _("Storage pool %(name)s already exists"),
"KCHPOOL0002E": _("Storage pool %(name)s does not exist"),
--
1.9.0
3
3
Previously it was 'Power off Confirmation', this patch changes it to 'VM
Delete Confirmation'.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.guest_main.js | 2 +-
ui/pages/i18n.html.tmpl | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js
index 510e7f9..ea36d62 100644
--- a/ui/js/src/kimchi.guest_main.js
+++ b/ui/js/src/kimchi.guest_main.js
@@ -108,7 +108,7 @@ kimchi.vmdelete = function(event) {
var vm = $(this).closest('li[name=guest]');
var vm_id=vm.attr("id");
var settings = {
- title : i18n['KCHVM6002M'],
+ title : i18n['KCHVM6008M'],
content : i18n['KCHVM6001M'],
confirm : i18n['KCHAPI6002M'],
cancel : i18n['KCHAPI6003M']
diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl
index 98da828..7194792 100644
--- a/ui/pages/i18n.html.tmpl
+++ b/ui/pages/i18n.html.tmpl
@@ -134,6 +134,7 @@ var i18n = {
" the guest OS shutdown. Would you like to continue?")",
'KCHVM6006M': "$_("Shut Down Confirmation")",
'KCHVM6007M': "$_("Note the guest OS may ignore this request. Would you like to continue?")",
+ 'KCHVM6008M': "$_("VM Delete Confirmation")",
'KCHVMCD6001M': "$_("This CDROM will be detached permanently and you can re-attach it. Continue to detach it?")",
'KCHVMCD6002M': "$_("Attach")",
--
1.9.0
5
4
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
the layout is wrong in firefox, fix it.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
ui/css/theme-default/host.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/css/theme-default/host.css b/ui/css/theme-default/host.css
index 6a1a308..ed28d25 100644
--- a/ui/css/theme-default/host.css
+++ b/ui/css/theme-default/host.css
@@ -117,7 +117,7 @@
.host-panel .info-container {
padding-top: 16px;
- width: 892px;
+ width: 890px;
}
.host-panel .section-header {
--
1.9.0
2
1
[PATCH] Exception: fix exception details when not specified
by lvroyce@linux.vnet.ibm.com 03 Jun '14
by lvroyce@linux.vnet.ibm.com 03 Jun '14
03 Jun '14
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Not every validation error needs to translate for user,
we define user interested errors,
other developer interested error should report directly by schema validator,
and handled by developer directly.
fix exception handling for this situation.
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/control/utils.py | 6 ++++--
src/kimchi/exception.py | 2 +-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py
index 5e63816..a67f627 100644
--- a/src/kimchi/control/utils.py
+++ b/src/kimchi/control/utils.py
@@ -98,8 +98,10 @@ def validate_params(params, instance, action):
try:
validator.validate(request)
except ValidationError, e:
- raise InvalidParameter(e.schema['error'], {'value': str(e.instance)})
-
+ if e.schema.get('error'):
+ raise InvalidParameter(e.schema['error'], {'value': str(e.instance)})
+ else:
+ raise InvalidParameter(e.message)
class UrlSubNode(object):
diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py
index fcf60cc..5a292e0 100644
--- a/src/kimchi/exception.py
+++ b/src/kimchi/exception.py
@@ -62,7 +62,7 @@ class KimchiException(Exception):
# itself to a unicode string.
args[key] = unicode(value)
- return unicode(translation.gettext(text), 'utf-8') % args
+ return translation.gettext(text).encode('utf-8') % args
class NotFoundError(KimchiException):
--
1.8.3.2
5
7
The function listDeepScanIsos is not being used in the Kimchi code. It
was replaced by stepListDeepScanIsos.
---
ui/js/src/kimchi.api.js | 24 ------------------------
1 file changed, 24 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 7d85fdf..5f3bf00 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -481,30 +481,6 @@ var kimchi = {
return deepScanHandler;
},
- listDeepScanIsos : function(suc, err) {
- var isoPool = 'iso' + new Date().getTime();
- kimchi.createStoragePool({
- name : isoPool,
- type : 'kimchi-iso',
- path : '/'
- }, function(result) {
- var taskId = result.task_id;
- function monitorTask() {
- kimchi.getTask(taskId, function(result) {
- var status = result.status;
- if (status === "finished") {
- kimchi.listStorageVolumes(isoPool, suc, err);
- } else if (status === "running") {
- setTimeout(monitorTask, 50);
- } else if (status === "failed") {
- err(result.message);
- }
- }, err);
- }
- monitorTask();
- }, err);
- },
-
getTask : function(taskId, suc, err) {
kimchi.requestJSON({
url : kimchi.url + 'tasks/' + encodeURIComponent(taskId),
--
1.9.0
5
4
This function was designed to substitute variables in HTML template strings originally
so it was named as kimchi.template, and it can be used in other scenarios, e.g. we use
it when we load plugins we have a unified URL for plugin XML files:
/plugins/{plugin}/ui/config/tab-ext.xml
and after we have the plugins list, we can easily generate the corresponding URLs like
/plugins/pluginA/ui/config/tab-ext.xml,
/plugins/pluginB/ui/config/tab-ext.xml.
by list ['pluginA', 'pluginB'].
Though it is sometimes misunderstood to be related with VM templates.
Renamed it in this patch.
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.grid.js | 2 +-
ui/js/src/kimchi.guest_add_main.js | 2 +-
ui/js/src/kimchi.guest_edit_main.js | 4 +--
ui/js/src/kimchi.guest_media_main.js | 2 +-
ui/js/src/kimchi.host.js | 2 +-
ui/js/src/kimchi.main.js | 2 +-
ui/js/src/kimchi.network.js | 2 +-
ui/js/src/kimchi.storage_main.js | 4 +--
ui/js/src/kimchi.storagepool_add_main.js | 2 +-
ui/js/src/kimchi.substitute.js | 45 ++++++++++++++++++++++++++++++++
ui/js/src/kimchi.template.js | 45 --------------------------------
ui/js/src/kimchi.template_add_main.js | 4 +--
ui/js/src/kimchi.template_edit_main.js | 2 +-
ui/js/src/kimchi.template_main.js | 2 +-
14 files changed, 60 insertions(+), 60 deletions(-)
create mode 100644 ui/js/src/kimchi.substitute.js
delete mode 100644 ui/js/src/kimchi.template.js
diff --git a/ui/js/src/kimchi.grid.js b/ui/js/src/kimchi.grid.js
index 055f487..2c70969 100644
--- a/ui/js/src/kimchi.grid.js
+++ b/ui/js/src/kimchi.grid.js
@@ -375,7 +375,7 @@ kimchi.widget.Grid.prototype = (function() {
var container = $('#' + containerID);
var gridID = this['opts']['id'];
var rowSelection = this['opts']['rowSelection'] || 'single';
- var domNode = $(kimchi.template(htmlStr, {
+ var domNode = $(kimchi.substitute(htmlStr, {
id: gridID,
loading: i18n['KCHGRD6001M'],
message: i18n['KCHGRD6002M'],
diff --git a/ui/js/src/kimchi.guest_add_main.js b/ui/js/src/kimchi.guest_add_main.js
index 2113099..eefd59a 100644
--- a/ui/js/src/kimchi.guest_add_main.js
+++ b/ui/js/src/kimchi.guest_add_main.js
@@ -25,7 +25,7 @@ kimchi.guest_add_main = function() {
var html = '';
var tmpl = $('#tmpl-template').html();
$.each(result, function(index, value) {
- html += kimchi.template(tmpl, value);
+ html += kimchi.substitute(tmpl, value);
});
$('#templateTile').html(html);
return;
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 0236e2d..90dcb32 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -42,7 +42,7 @@ kimchi.guest_edit_main = function() {
$.each(storages, function(index, storage) {
storage['vm'] = kimchi.selectedGuest;
rowHTML = $('#' + storage['type'] + '-row-tmpl').html();
- var templated = kimchi.template(rowHTML, storage);
+ var templated = kimchi.substitute(rowHTML, storage);
container.append(templated);
});
@@ -96,7 +96,7 @@ kimchi.guest_edit_main = function() {
$(".action-area", item).toggleClass("hide");
};
var addItem = function(data) {
- var itemNode = $.parseHTML(kimchi.template($('#interface-tmpl').html(),data));
+ var itemNode = $.parseHTML(kimchi.substitute($('#interface-tmpl').html(),data));
$(".body", "#form-guest-edit-interface").append(itemNode);
$("select", itemNode).append(networkOptions);
if(data.network!==""){
diff --git a/ui/js/src/kimchi.guest_media_main.js b/ui/js/src/kimchi.guest_media_main.js
index 02009ec..d6dee2e 100644
--- a/ui/js/src/kimchi.guest_media_main.js
+++ b/ui/js/src/kimchi.guest_media_main.js
@@ -28,7 +28,7 @@ kimchi.guest_media_main = function() {
$.each(storages, function(index, storage) {
storage['vm'] = kimchi.selectedGuest;
- var templated = kimchi.template(rowHTML, storage);
+ var templated = kimchi.substitute(rowHTML, storage);
container.append(templated);
});
diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js
index 4c94fc1..ee59a7e 100644
--- a/ui/js/src/kimchi.host.js
+++ b/ui/js/src/kimchi.host.js
@@ -485,7 +485,7 @@ kimchi.host_main = function() {
data['memory'] = kimchi.formatMeasurement(data['memory'], {
fixed: 2
});
- var templated = kimchi.template(htmlTmpl, data);
+ var templated = kimchi.substitute(htmlTmpl, data);
$('#host-content-container').html(templated);
initPage();
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js
index 86fed5b..184029d 100644
--- a/ui/js/src/kimchi.main.js
+++ b/ui/js/src/kimchi.main.js
@@ -69,7 +69,7 @@ kimchi.main = function() {
var tabs = retrieveTabs(tabConfigUrl);
kimchi.listPlugins(function(plugins) {
$(plugins).each(function(i, p) {
- var url = kimchi.template(pluginConfigUrl, {
+ var url = kimchi.substitute(pluginConfigUrl, {
plugin: p
});
tabs.push.apply(tabs, retrieveTabs(url));
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index ca6d29b..875bc08 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -63,7 +63,7 @@ kimchi.getNetworkItemHtml = function(network) {
}
var disable_in_use = network.in_use ? "ui-state-disabled" : "";
- var networkItem = kimchi.template($('#networkItem').html(), {
+ var networkItem = kimchi.substitute($('#networkItem').html(), {
name : network.name,
state : network.state,
type : network.type,
diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js
index 6052510..1493124 100644
--- a/ui/js/src/kimchi.storage_main.js
+++ b/ui/js/src/kimchi.storage_main.js
@@ -25,7 +25,7 @@ kimchi.doListStoragePools = function() {
value.capacity = kimchi.changetoProperUnit(value.capacity,1);
value.allocated = kimchi.changetoProperUnit(value.allocated,1);
if ('kimchi-iso' !== value.type) {
- listHtml += kimchi.template(storageHtml, value);
+ listHtml += kimchi.substitute(storageHtml, value);
}
});
$('#storagepoolsList').html(listHtml);
@@ -172,7 +172,7 @@ kimchi.doListVolumes = function(poolObj) {
value.poolname = poolObj.data('name');
value.capacity = kimchi.changetoProperUnit(value.capacity,1);
value.allocation = kimchi.changetoProperUnit(value.allocation,1);
- listHtml += kimchi.template(volumeHtml, value);
+ listHtml += kimchi.substitute(volumeHtml, value);
});
volumeDiv.html(listHtml);
} else {
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..050aa90 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -30,7 +30,7 @@ kimchi.initStorageAddPage = function() {
valid_types = ['part', 'disk', 'mpath'];
$.each(data, function(index, value) {
if (valid_types.indexOf(value.type) != -1) {
- listHtml += kimchi.template(deviceHtml, value);
+ listHtml += kimchi.substitute(deviceHtml, value);
}
});
$('.host-partition').html(listHtml);
diff --git a/ui/js/src/kimchi.substitute.js b/ui/js/src/kimchi.substitute.js
new file mode 100644
index 0000000..27ca8ed
--- /dev/null
+++ b/ui/js/src/kimchi.substitute.js
@@ -0,0 +1,45 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Licensed 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.
+ */
+kimchi.substitute = function(templatedStr, data, tag) {
+ tag = tag || /\{([^\}]+)\}/g;
+
+ var escapeHtml = function(html) {
+ return String(html)
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ };
+
+ return templatedStr.replace(tag, function(matchResult, express) {
+ var propertyArray = express.split('!');
+ var defaultValue = propertyArray[1] || '';
+ propertyArray = propertyArray[0].split('.');
+ var value = data, i = 0, l = propertyArray.length, property;
+ for (; i < l; i++) {
+ property = propertyArray[i];
+ if (value) {
+ value = value[property];
+ } else {
+ break;
+ }
+ }
+ return escapeHtml((value || value === 0) ? value : defaultValue);
+ });
+};
diff --git a/ui/js/src/kimchi.template.js b/ui/js/src/kimchi.template.js
deleted file mode 100644
index 082269f..0000000
--- a/ui/js/src/kimchi.template.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Project Kimchi
- *
- * Copyright IBM, Corp. 2013
- *
- * Licensed 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.
- */
-kimchi.template = function(templateStr, data, tag) {
- tag = tag || /\{([^\}]+)\}/g;
-
- var escapeHtml = function(html) {
- return String(html)
- .replace(/&/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/"/g, '"')
- .replace(/'/g, ''');
- };
-
- return templateStr.replace(tag, function(matchResult, express) {
- var propertyArray = express.split('!');
- var defaultValue = propertyArray[1] || '';
- propertyArray = propertyArray[0].split('.');
- var value = data, i = 0, l = propertyArray.length, property;
- for (; i < l; i++) {
- property = propertyArray[i];
- if (value) {
- value = value[property];
- } else {
- break;
- }
- }
- return escapeHtml((value || value === 0) ? value : defaultValue);
- });
-};
diff --git a/ui/js/src/kimchi.template_add_main.js b/ui/js/src/kimchi.template_add_main.js
index dbb3952..e9adbac 100644
--- a/ui/js/src/kimchi.template_add_main.js
+++ b/ui/js/src/kimchi.template_add_main.js
@@ -152,7 +152,7 @@ kimchi.template_add_main = function() {
volume.isoId = isoId;
volume.capacity = kimchi.changetoProperUnit(volume.capacity, 1);
kimchi.isoInfo[isoId] = volume;
- html += kimchi.template(template, volume);
+ html += kimchi.substitute(template, volume);
}
});
$('#list-local-iso').append(html);
@@ -266,7 +266,7 @@ kimchi.template_add_main = function() {
if (!kimchi.isoInfo[isoId]) {
volume.isoId = isoId;
kimchi.isoInfo[isoId] = volume;
- html += kimchi.template(template, volume);
+ html += kimchi.substitute(template, volume);
}
});
$('#list-remote-iso').html(html);
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index 9ff8bcc..cffc685 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -87,7 +87,7 @@ kimchi.template_edit_main = function() {
var html = '';
var tmpl = $('#tmpl-network').html();
$.each(result, function(index, network) {
- html += kimchi.template(tmpl, network);
+ html += kimchi.substitute(tmpl, network);
});
$('#template-edit-network-list').html(html).show();
if(template.networks && template.networks.length > 0) {
diff --git a/ui/js/src/kimchi.template_main.js b/ui/js/src/kimchi.template_main.js
index 160ecc8..b90e3f3 100644
--- a/ui/js/src/kimchi.template_main.js
+++ b/ui/js/src/kimchi.template_main.js
@@ -22,7 +22,7 @@ kimchi.doListTemplates = function() {
var listHtml = '';
var templateHtml = $('#templateTmpl').html();
$.each(result, function(index, value) {
- listHtml += kimchi.template(templateHtml, value);
+ listHtml += kimchi.substitute(templateHtml, value);
});
$('#templateList').html(listHtml);
kimchi.templateBindClick();
--
1.8.1.4
3
3
[PATCH] model.host: avoid redundant libvirt lookupByName API invocation
by Zhou Zheng Sheng 03 Jun '14
by Zhou Zheng Sheng 03 Jun '14
03 Jun '14
In HostModel._get_vms_list_by_state(), it gets a list of domain objects
and extracts the names, then it traverses the names and calls
lookupByName(name) to get domain objects. This is redundant because it
has a list of domain object already.
This patch fixes the problem.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/model/host.py | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py
index e9ac487..5844f4b 100644
--- a/src/kimchi/model/host.py
+++ b/src/kimchi/model/host.py
@@ -104,15 +104,9 @@ class HostModel(object):
def _get_vms_list_by_state(self, state):
conn = self.conn.get()
- names = [dom.name().decode('utf-8') for dom in conn.listAllDomains(0)]
-
- ret_list = []
- for name in names:
- dom = conn.lookupByName(name.encode("utf-8"))
- info = dom.info()
- if (DOM_STATE_MAP[info[0]]) == state:
- ret_list.append(name)
- return ret_list
+ return [dom.name().decode('utf-8')
+ for dom in conn.listAllDomains(0)
+ if (DOM_STATE_MAP[dom.info()[0]]) == state]
class HostStatsModel(object):
--
1.9.3
4
3
03 Jun '14
Libvirt accepts iso files with names that do not end with '.iso'
extension. Also, Kimchi discovers ISOs stored in storagepools by the
file format, it does not care about file name.
This patch removes the .iso checking from API.json schema, then files
ending with '.iso.1', '.iso.bkp' or any other, can be used.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index b9d371a..44a1439 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -361,7 +361,7 @@
"cdrom": {
"description": "Path for cdrom",
"type": "string",
- "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$",
+ "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$",
"required": true,
"error": "KCHTMPL0014E"
},
@@ -532,7 +532,7 @@
"cdrom": {
"description": "Path for cdrom",
"type": "string",
- "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$",
+ "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$",
"error": "KCHTMPL0014E"
},
"disks": {
--
1.9.0
3
4
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
this page is used for the session timeout or first login.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
Signed-off-by: Yu Xin Huo <huoyuxin(a)linux.vnet.ibm.com>
---
ui/images/progressing.gif | Bin 0 -> 1152 bytes
ui/pages/login.html.tmpl | 247 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 247 insertions(+)
create mode 100644 ui/images/progressing.gif
create mode 100644 ui/pages/login.html.tmpl
diff --git a/ui/images/progressing.gif b/ui/images/progressing.gif
new file mode 100644
index 0000000000000000000000000000000000000000..6552d41d9d4c874091bb51931c6adf64a95e8bd0
GIT binary patch
literal 1152
zcmZ?wbhEHb6k!ly*v!E2|NsBHckiA#b7s?~O&uK_IXO9@p`oUxrgCy}4A_9;e{Mh5
zkYH!W09PYD17=2`8pWS1oFWVy3_2k7AY&O=+5}E^`WY^hIhD@I;2`qkhUamCHs#2?
zD{Sl5ddqAu;o;E8n07H&VTOd$9w+z3Od8dz)1OOlg@hfQ?6P6gg)Nhut~h8s_iHy|
zTx?f<DfNuF4qs+in1T70o7P)P87f1<g5(0~t-`bz%`;<c7;R*Hby&0+Cd*D$nyx)7
zxH>hoEs9-2GEYbl<TO?^r*$AZO&~F#<dR{_!xK!0-EtLPZ*p|yWoF`%>SmZA?aQ<9
zUT3kA$h=8X2{%vLaEeZ2FfFvxHCy+@)2xTXXx&nW19L8~I4mhFCLSR*N5YUN_g8RC
zxvG$d3rC2Yoni>Hr8Z+mk+UtMt&Fyriq3S|nYyz*lh|s_)v7fmBnyPWjzbSOeSwpn
ztM^*GK3gr@WX{W=;H4@s$Eix`o#&Z+UC|vq;?Mm$*qz>q{MpOLKD$V>lW^GM@gRp<
zTfqAxmTMW#NQtz1Ow(GUENaLTnG@~OSSl%)a-~@^*=_L^Wu6LazRZG$dI^iu%U-z%
zg<00g*_8=1ySk){v9Pk(*~<9qvQD2qQDdsojG1{NY_a__TQemj7eK-u-Fqm>f>utm
zWMS=L&jJU059@Suul#8<RCK0juuU^pO9X~|9`=wYHdzoCYCehQmh?GGSt;IO&EY61
z^|cU^WKC}pQa3GC)^bS)J5HFrADAqr$@=Tg_KIeUMR6Q@nr+9QW_y9zNsLj!T)@YO
zmFW>EN`0IXPrZ>S5M3ptD%hrTMQhc8T>+_g4tF#}E)IMpc<k8J3C>bEce!tTI4V-^
zEEL|{;B8wW%<SUK!k*>CY&#hksVX{CWv466RGb|aXRcN%49rjY*aHrnWY;d4a(eT<
sn9_<U58lHODbH9KGQC;#6@s@G?AG7t-SQycLr1Fr#FC=U9tH+$0KoWQ9smFU
literal 0
HcmV?d00001
diff --git a/ui/pages/login.html.tmpl b/ui/pages/login.html.tmpl
new file mode 100644
index 0000000..e7afbb3
--- /dev/null
+++ b/ui/pages/login.html.tmpl
@@ -0,0 +1,247 @@
+#*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2014
+ *
+ * Licensed 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.
+ *#
+#unicode UTF-8
+#import gettext
+#from kimchi.cachebust import href
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent _ = t.gettext
+#silent _t = t.gettext
+#from kimchi.config import get_version
+<!DOCTYPE html>
+<html lang="$lang.lang[0]">
+<head>
+<meta charset="UTF-8">
+<title>Kimchi</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+
+<style type="text/css">
+.login {
+ font-family: Arial;
+ margin: 0px;
+}
+
+.login input.invalid-field {
+ border-color: #C85305 !important;
+}
+
+.login .header {
+ background: none repeat scroll 0 0 #353D40;
+ border-bottom: 3px solid #008ABF;
+ border-top: 0 none;
+ box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
+ height: 50px;
+ color: #F8F8F8;
+ font-size: 13px;
+ font-weight: 700;
+ font-family: Helvetica;
+ overflow: hidden;
+}
+
+.login .header .lang {
+ float: right;
+ margin-right: 20px;
+ margin-top: 14px;
+}
+
+.login .header .lang select {
+ vertical-align: middle;
+}
+
+.login .content-pane {
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 200px;
+ width: 260px;
+}
+
+.login .content-pane .trademark {
+ margin-bottom: 30px;
+}
+
+.login .content-pane .trademark .logo {
+ background: url("../images/logo.ico") no-repeat scroll center center transparent;
+ display: inline-block;
+ height: 25px;
+ width: 25px;
+ margin-left: -4px;
+ margin-right: 5px;
+ vertical-align: middle;
+}
+
+.login .content-pane .trademark .name {
+ vertical-align: middle;
+ padding-top: 2px;
+ font-weight: bold;
+ font-size: 18px;
+}
+
+.login .content-pane .trademark .version {
+ vertical-align: middle;
+ padding-top: 6px;
+ font-size: 13px;
+ padding-left: 6px;
+}
+
+.login .content-pane .message-area .item {
+ font-size: 12px;
+ margin-bottom: 30px;
+ margin-top: 30px;
+ height: 20px;
+}
+
+.login .content-pane .message-area .text {
+ color: #C85305;
+}
+
+.login .progress-indicator .progress-icon {
+ margin-right: 3px;
+ vertical-align: middle;
+ width: 15px;
+ height: 15px;
+}
+
+.login .progress-indicator .progress-text {
+ vertical-align: middle;
+ padding-top: 2px;
+}
+
+.login .content-pane .hint {
+ margin-bottom: 10px;
+ font-size: 14px;
+}
+
+.login .content-pane .field-area {
+ overflow: hidden;
+}
+
+.login .content-pane .field-area .text-field {
+ width: 240px;
+ padding: 5px 7px;
+ margin-bottom: 5px;
+ border: 1px solid #BABABA;
+ border-radius: 1px;
+}
+
+.login .button {
+ margin-top: 20px;
+ background: -moz-linear-gradient(center top , #1783BF 0%, #0C4C88 100%) repeat scroll 0 0 transparent;
+ border-color: #666666 #666666 #555555;
+ border-image: none;
+ border-radius: 5px 5px 5px 5px;
+ border-style: solid;
+ border-width: 1px;
+ color: #DDDDDD;
+ cursor: pointer;
+ font-weight: bolder;
+ padding: 5px 10px;
+ float: right;
+}
+</style>
+
+<script>
+
+function validateForm() {
+ var user = document.forms["login"]["username"];
+ var pass = document.forms["login"]["password"];
+ var validateField = function(field){
+ field.className = "text-field";
+ var isValid = field.value && field.value.trim()!="" ? true : false;
+ if(!isValid) field.className += " invalid-field";
+ return isValid;
+ };
+ var isValid = validateField(user);
+ isValid = validateField(pass) && isValid;
+ if(isValid)
+ document.getElementById("messWait").style.display = "";
+ return isValid;
+}
+
+function getCookie(cname) {
+ var name = cname + "=";
+ var ca = document.cookie.split(';');
+ for(var i=0; i<ca.length; i++) {
+ var c = ca[i].trim();
+ if (c.indexOf(name)==0) return c.substring(name.length,c.length);
+ }
+ return null;
+}
+
+function setCookie(cname,cvalue,exdays) {
+ var d = new Date();
+ d.setTime(d.getTime()+(exdays*24*60*60*1000));
+ var expires = "expires="+d.toGMTString();
+ document.cookie = cname + "=" + cvalue + "; " + expires;
+}
+
+function init() {
+ var defaultLang = 'en_US';
+ var clientLang = document.getElementById('userLang').value;
+ var persistLang = getCookie('kimchiLang');
+ document.getElementById("userLang").value = persistLang || clientLang || defaultLang;
+/*
+ var url = window.location.href;
+ if(url.indexOf("wrongUserPass")!=-1)
+ document.getElementById("messUserPass").style.display = "";
+ if(url.indexOf("sessionTimeout")!=-1)
+ document.getElementById("messSession").style.display = "";
+*/
+}
+
+function changeLang() {
+ var lang = document.getElementById('userLang').value;
+ setCookie('kimchiLang', lang, 365);
+ window.location.reload();
+}
+
+</script>
+</head>
+<body class="login" onload="init()">
+
+<div class="header">
+ <div class="lang">
+ <label>$_("Language"):</label>
+ <select id="userLang" onchange="changeLang()">
+ <option value="en_US">English (US)</option>
+ <option value="zh_CN">中文(简体)</option>
+ <option value="pt_BR">Português (Brasil)</option>
+ </select>
+ </div>
+</div>
+<div class="content-pane">
+ <div class="trademark"><span class="logo"></span><span class="name">Kimchi</span><span class="version">1.2</span></div>
+ <div class="message-area">
+ <div id="messUserPass" class="item text" style="display: none;">$_("User Name or password is incorrect.")</div>
+ <div id="messSession" class="item text" style="display: none;">$_("Session timeout, please re-login.")</div>
+ <div id="messWait" class="item progress-indicator" style="display: none;">
+ <img src="images/progressing.gif" class="progress-icon"><span class="progress-text">$_("Processing")...</span>
+ </div>
+ </div>
+ <div class="hint">$_("Sign in with your linux account")</div>
+ <div class="field-area">
+ <form name="login" action="/login?next=$getVar('data.next', '/')" method="POST" onsubmit="return validateForm()">
+ <input type="hidden" name="next" value="$getVar('data.next', '/')">
+ <input type="text" name="username" placeholder="$_("User Name")" class="text-field" autofocus>
+ <input type="password" name="password" placeholder="$_("Password")" class="text-field">
+ <input type="submit" value="$_("Sign In")" class="button">
+ </form>
+ </div>
+</div>
+
+</body>
+</html>
--
1.9.3
3
5
[PATCH] Issue #296 [enhance]kimchi UI should not waiting while generating reports
by Wen Wang 02 Jun '14
by Wen Wang 02 Jun '14
02 Jun '14
1) Removed the dialogue window when generating a debug report.
2) Designed an animation bar indicate user there is a report generating
during the generating progress.
3) Disable the buttons' functions in debug report area when generating a new
report in case there might be any conflict. Meanwhile user can operate
on other parts of Kimchi.
4) Enable all buttonss' functions in debug report area after generating
progress.
---
ui/css/theme-default/host.css | 22 +++++++++++++++++++++
ui/js/src/kimchi.report_add_main.js | 38 ++++++++++++++++++++++++++++++++-----
2 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/ui/css/theme-default/host.css b/ui/css/theme-default/host.css
index 6a1a308..c684c0a 100644
--- a/ui/css/theme-default/host.css
+++ b/ui/css/theme-default/host.css
@@ -219,6 +219,28 @@
width: 200px;
}
+#id-generate-bar {
+ text-align: center;
+ vertical-align: middle;
+}
+
+#id-generate-panel {
+ vertical-align: middle;
+ margin: 0 auto;
+ text-align: center;
+ height: 20px;
+ width: 250px;
+ color: #fff;
+ border: 1px solid #ccc;
+ background-color: #5af;
+}
+
+#id-generating {
+ font-color: #fff;
+ background: #5af url(../../images/theme-default/loading.gif) 7px
+ center no-repeat;
+ padding-left: 26px;
+}
/* End of Debug Report */
/* Software Updates */
diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js
index 8759c2b..1e5df89 100644
--- a/ui/js/src/kimchi.report_add_main.js
+++ b/ui/js/src/kimchi.report_add_main.js
@@ -1,4 +1,5 @@
kimchi.report_add_main = function() {
+ var reportGridID = 'available-reports-grid';
var addReportForm = $('#form-report-add');
var submitButton = $('#button-report-add');
var nameTextbox = $('input[name="name"]', addReportForm);
@@ -13,12 +14,39 @@ kimchi.report_add_main = function() {
return false;
}
var formData = addReportForm.serializeObject();
- submitButton
- .text(i18n['KCHDR6007M'])
- .prop('disabled', true);
- nameTextbox.prop('disabled', true);
+ kimchi.window.close();
+ var reportGrid = null;
+ $('#' + reportGridID + '-generate-button').prop('disabled',true);
+ $('#' + reportGridID + '-remove-button').prop('disabled',true);
+ $('#' + reportGridID + '-download-button').prop('disabled',true);
+ $('#' + reportGridID + '-rename-button').prop('disabled',true);
+ $('#available-reports-grid').find('.grid-body').find('table').find('tr').click(function() {
+ $('#' + reportGridID + '-remove-button').prop('disabled',true);
+ $('#' + reportGridID + '-download-button').prop('disabled',true);
+ $('#' + reportGridID + '-rename-button').prop('disabled',true);
+ });
+ var len = $('#available-reports-grid').find('.grid-frozen-body-view').find('tr').length + 1;
+ $('#available-reports-grid').find('.grid-frozen-body-view').find('table').append('<tr id="temp-row-col1"><td>' + len + '</td></tr>');
+ $('#available-reports-grid').find('.grid-body-view').find('table').append('<tr id="temp-row-col2"><td id="id-generate-bar"; colspan="2"></td></tr>');
+ var textboxValue = $('#report-name-textbox').val();
+ if (textboxValue != "") {
+ if (textboxValue.length <= 15) {
+ $('#id-generate-bar').append('<div id="id-generate-panel"></div>');
+ $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue +'" ' + i18n['KCHDR6007M'] + '</span></label>');
+ }
+ else {
+ $('#id-generate-bar').append('<div id="id-generate-panel"></div>');
+ $('#id-generate-panel').append('<label id="id-generating"><span>' + '"' + textboxValue.substring(0,13) +'..." ' + i18n['KCHDR6007M'] + '</span></label>');
+ }
+ }
+ else {
+ $('#id-generate-bar').append('<div id="id-generate-panel"></div>');
+ $('#id-generate-panel').append('<label id="id-generating"><span>' + i18n['KCHDR6007M'] + '</span></label>');
+ }
kimchi.createReport(formData, function(result) {
- kimchi.window.close();
+ $('#temp-row-col1').remove();
+ $('#temp-row-col2').remove();
+ $('#' + reportGridID + '-generate-button').prop('disabled',false);
kimchi.topic('kimchi/debugReportAdded').publish({
result: result
});
--
1.9.1
4
4
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Royce Lv (2):
disk attachment: fix ref_cnt to prevent double attach
disk attachment: limit ref_cnt check to disk attachment
src/kimchi/model/vmstorages.py | 31 ++++++++++++++++++++++++++++++-
tests/test_model.py | 1 +
2 files changed, 31 insertions(+), 1 deletion(-)
--
1.8.3.2
2
4
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Depend on exception fix patchset.
v3>v4, delete json schema change.(Shaohe's comments)
v2>v3, fixed loading info cannot display when reopen,
also correct i18n for Chinese.(Yuxin's comments)
v1>v2, Added error msg and loading info for pool extend.(Aline's comments)
Royce Lv (2):
StoragePool Edit: Add Disk to Logical Pool
Update po file
po/zh_CN.po | 5 +++-
ui/js/src/kimchi.api.js | 12 ++++++++
ui/js/src/kimchi.storage_main.js | 47 ++++++++++++++++++++++++++++++++
ui/js/src/kimchi.storagepool_add_main.js | 2 +-
ui/pages/i18n.html.tmpl | 1 +
ui/pages/tabs/storage.html.tmpl | 15 ++++++++++
6 files changed, 80 insertions(+), 2 deletions(-)
--
1.8.3.2
2
5
[PATCH] Issue#348: Add loading icon when nfs mount is in progress
by lvroyce@linux.vnet.ibm.com 29 May '14
by lvroyce@linux.vnet.ibm.com 29 May '14
29 May '14
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Add loading icon to indicate nfs mount in progress,
when error or normal response returns,
close create window.
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.storagepool_add_main.js | 2 ++
ui/pages/storagepool-add.html.tmpl | 6 ++++++
2 files changed, 8 insertions(+)
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..6b77bd8 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -198,6 +198,7 @@ kimchi.validateNfsForm = function () {
kimchi.message.error.code('KCHPOOL6005E');
return false;
}
+ $('#nfs-mount-loading').removeClass('hidden');
return true;
};
@@ -295,6 +296,7 @@ kimchi.addPool = function(event) {
kimchi.window.close();
}, function(err) {
kimchi.message.error(err.responseJSON.reason);
+ kimchi.window.close();
});
}
}
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 977db66..b0bc36d 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -91,6 +91,12 @@
</ul>
</div>
</div>
+ <div class="hidden" id="nfs-mount-loading">
+ <p class="text-help">
+ $_("Server trying mount nfs export path...")
+ <img src = "../images/theme-default/loading.gif" />
+ </p>
+ </div>
</div>
</section>
</div>
--
1.8.3.2
5
5
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Pyflakes and pep8 dependencies need to be added so that pyflakes
check can be performed properly.
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
---
contrib/DEBIAN/control.in | 2 ++
contrib/kimchi.spec.fedora.in | 2 ++
contrib/kimchi.spec.suse.in | 2 ++
3 files changed, 6 insertions(+)
diff --git a/contrib/DEBIAN/control.in b/contrib/DEBIAN/control.in
index aac1a24..581601b 100644
--- a/contrib/DEBIAN/control.in
+++ b/contrib/DEBIAN/control.in
@@ -25,6 +25,8 @@ Depends: python-cherrypy3 (>= 3.2.0),
firewalld,
nginx
Build-Depends: libxslt,
+ pep8,
+ pyflakes,
python-libxml2
Maintainer: Aline Manera <alinefm(a)br.ibm.com>
Description: Kimchi web server
diff --git a/contrib/kimchi.spec.fedora.in b/contrib/kimchi.spec.fedora.in
index 2d4699b..9f62e05 100644
--- a/contrib/kimchi.spec.fedora.in
+++ b/contrib/kimchi.spec.fedora.in
@@ -32,6 +32,8 @@ Requires: nginx
Requires: iscsi-initiator-utils
BuildRequires: libxslt
BuildRequires: libxml2-python
+BuildRequires: python-pep8
+BuildRequires: pyflakes
%if 0%{?rhel} == 6
Requires: python-ordereddict
diff --git a/contrib/kimchi.spec.suse.in b/contrib/kimchi.spec.suse.in
index 165f566..36d6b0a 100644
--- a/contrib/kimchi.spec.suse.in
+++ b/contrib/kimchi.spec.suse.in
@@ -28,6 +28,8 @@ Requires: nginx
Requires: open-iscsi
BuildRequires: libxslt-tools
BuildRequires: python-libxml2
+BuildRequires: python-pyflakes
+BuildRequires: python-pep8
%if 0%{?sles_version} == 11
Requires: python-ordereddict
--
1.8.3.2
2
1
From: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
Due to the timeout period to see if the NFS pool is
online, the Storage tab may look irresponsible and
the user might believe that the UI/kimchi is frozen.
Inserting the loading icon+text in this tab to show that
the UI is responsive, just waiting for an answer from the
server.
Signed-off-by: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.storage_main.js | 2 ++
ui/pages/tabs/storage.html.tmpl | 8 +++++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js
index 6052510..74e6892 100644
--- a/ui/js/src/kimchi.storage_main.js
+++ b/ui/js/src/kimchi.storage_main.js
@@ -17,6 +17,7 @@
*/
kimchi.doListStoragePools = function() {
kimchi.listStoragePools(function(result) {
+ $('#storagepoolsLoading').addClass('hidden');
var storageHtml = $('#storageTmpl').html();
if (result && result.length) {
var listHtml = '';
@@ -34,6 +35,7 @@ kimchi.doListStoragePools = function() {
$('#storagepoolsList').html('');
}
}, function(err) {
+ $('#storagepoolsLoading').addClass('hidden');
kimchi.message.error(err.responseJSON.reason);
});
diff --git a/ui/pages/tabs/storage.html.tmpl b/ui/pages/tabs/storage.html.tmpl
index c3a992e..84372c1 100644
--- a/ui/pages/tabs/storage.html.tmpl
+++ b/ui/pages/tabs/storage.html.tmpl
@@ -40,7 +40,13 @@
<li class="title-actions">$_("Actions")</li>
</div>
<ul id="storagepoolsList" class="list-storage empty-when-logged-off"></ul>
-</div>
+ <div id="storagepoolsLoading">
+ <div class="grid-loading">
+ <div class="grid-loading-icon"></div>
+ <div class="grid-loading-text">$_("loading")</div>
+ </div>
+ </div>
+ </div>
<script id="storageTmpl" type="html/text">
<li id="{name}">
<div class="storage-li in" data-name="{name}" data-stat="{state}">
--
1.8.3.1
3
2
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
v2>v3, fixed loading info cannot display when reopen,
also correct i18n for Chinese.
v1>v2, Added error msg and loading info for pool extend.(Aline's comments)
Royce Lv (3):
StoragePool Edit: Add Disk to Logical Pool
StoragePool Edit: Update json schema
Update po file
po/zh_CN.po | 5 +++-
src/kimchi/API.json | 3 +-
ui/js/src/kimchi.api.js | 12 ++++++++
ui/js/src/kimchi.storage_main.js | 47 ++++++++++++++++++++++++++++++++
ui/js/src/kimchi.storagepool_add_main.js | 2 +-
ui/pages/i18n.html.tmpl | 1 +
ui/pages/tabs/storage.html.tmpl | 15 ++++++++++
7 files changed, 82 insertions(+), 3 deletions(-)
--
1.8.3.2
3
5
27 May '14
Libvirt accepts iso files with names that do not end with '.iso'
extension. Also, Kimchi discovers ISOs stored in storagepools by the
file format, it does not care about file name.
This patch removes the .iso checking from API.json schema, then files
ending with '.iso.1', '.iso.bkp' or any other, can be used.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index b9d371a..44a1439 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -361,7 +361,7 @@
"cdrom": {
"description": "Path for cdrom",
"type": "string",
- "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$",
+ "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$",
"required": true,
"error": "KCHTMPL0014E"
},
@@ -532,7 +532,7 @@
"cdrom": {
"description": "Path for cdrom",
"type": "string",
- "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$",
+ "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$",
"error": "KCHTMPL0014E"
},
"disks": {
--
1.9.0
4
5
27 May '14
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
v1>v2, add loading icon before disk query finished
and display mesg when no partition is available.
Add storage pool extend dialog and choose proper disk for extension.
Signed-off-by: Yu Xin Huo <huoyuxin(a)linux.vnet.ibm.com>
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.api.js | 12 +++++++++
ui/js/src/kimchi.storage_main.js | 46 ++++++++++++++++++++++++++++++++
ui/js/src/kimchi.storagepool_add_main.js | 2 +-
ui/pages/i18n.html.tmpl | 1 +
ui/pages/tabs/storage.html.tmpl | 15 +++++++++++
5 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 3c6765c..d30bf10 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -208,6 +208,18 @@ var kimchi = {
}).done(suc).fail(err);
},
+ updateStoragePool : function(name, content, suc, err) {
+ $.ajax({
+ url : kimchi.url + "storagepools/" + encodeURIComponent(name),
+ type : 'PUT',
+ contentType : 'application/json',
+ dataType : 'json',
+ data : JSON.stringify(content)
+ }).done(suc).fail(err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ });
+ },
+
startVM : function(vm, suc, err) {
kimchi.requestJSON({
url : kimchi.url + 'vms/' + encodeURIComponent(vm) + '/start',
diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js
index 6052510..ef3d8f5 100644
--- a/ui/js/src/kimchi.storage_main.js
+++ b/ui/js/src/kimchi.storage_main.js
@@ -24,6 +24,7 @@ kimchi.doListStoragePools = function() {
value.usage = parseInt(value.allocated / value.capacity * 100) || 0;
value.capacity = kimchi.changetoProperUnit(value.capacity,1);
value.allocated = kimchi.changetoProperUnit(value.allocated,1);
+ value.enableExt = value.type==="logical" ? "" : "hide-content";
if ('kimchi-iso' !== value.type) {
listHtml += kimchi.template(storageHtml, value);
}
@@ -138,6 +139,11 @@ kimchi.storageBindClick = function() {
}
});
+ $('.pool-extend').on('click', function() {
+ $("#logicalPoolExtend").dialog("option", "poolName", $(this).data('name'));
+ $("#logicalPoolExtend").dialog("open");
+ });
+
$('#volume-doAdd').on('click', function() {
kimchi.window.open('storagevolume-add.html');
});
@@ -187,11 +193,51 @@ kimchi.doListVolumes = function(poolObj) {
});
}
+kimchi.initLogicalPoolExtend = function() {
+ $("#logicalPoolExtend").dialog({
+ autoOpen : false,
+ modal : true,
+ width : 600,
+ resizable : false,
+ closeText: "X",
+ open : function(){
+ $(".ui-dialog-titlebar-close", $("#logicalPoolExtend").parent()).removeAttr("title");
+ kimchi.listHostPartitions(function(data) {
+ if (data.length > 0) {
+ $('.host-partition', '#logicalPoolExtend').html('');
+ for(var i=0;i<data.length;i++){
+ if (data[i].type === 'part' || data[i].type === 'disk') {
+ $('.host-partition', '#logicalPoolExtend').append(kimchi.template($('#logicalPoolExtendTmpl').html(), data[i]));
+ }
+ }
+ } else {
+ $('.host-partition').html(i18n['KCHPOOL6011M']);
+ $('.host-partition').addClass('text-help');
+ }
+ });
+ },
+ beforeClose : function() { $('.host-partition', '#logicalPoolExtend').empty(); },
+ buttons : [{
+ class: "ui-button-primary",
+ text: i18n.KCHAPI6007M,
+ click: function(){
+ var devicePaths = [];
+ $("input[type='checkbox']:checked", "#logicalPoolExtend").each(function(){
+ devicePaths.push($(this).prop('value'));
+ })
+ kimchi.updateStoragePool($("#logicalPoolExtend").dialog("option", "poolName"),{disks: devicePaths});
+ $(this).dialog("close");
+ }
+ }]
+ });
+}
+
kimchi.storage_main = function() {
$('#storage-pool-add').on('click', function() {
kimchi.window.open('storagepool-add.html');
});
kimchi.doListStoragePools();
+ kimchi.initLogicalPoolExtend();
}
kimchi.changeArrow = function(obj) {
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..bc57601 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -33,7 +33,7 @@ kimchi.initStorageAddPage = function() {
listHtml += kimchi.template(deviceHtml, value);
}
});
- $('.host-partition').html(listHtml);
+ $('.host-partition', '#form-pool-add').html(listHtml);
} else {
$('.host-partition').html(i18n['KCHPOOL6011M']);
$('.host-partition').addClass('text-help');
diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl
index 98da828..f7977c8 100644
--- a/ui/pages/i18n.html.tmpl
+++ b/ui/pages/i18n.html.tmpl
@@ -58,6 +58,7 @@ var i18n = {
'KCHAPI6004M': "$_("Confirm")",
'KCHAPI6005M': "$_("Create")",
'KCHAPI6006M': "$_("Warning")",
+ 'KCHAPI6007M': "$_("Save")",
'KCHGRD6001M': "$_("Loading...")",
'KCHGRD6002M': "$_("An error occurs while checking for packages update.")",
diff --git a/ui/pages/tabs/storage.html.tmpl b/ui/pages/tabs/storage.html.tmpl
index c3a992e..76d2e07 100644
--- a/ui/pages/tabs/storage.html.tmpl
+++ b/ui/pages/tabs/storage.html.tmpl
@@ -41,6 +41,14 @@
</div>
<ul id="storagepoolsList" class="list-storage empty-when-logged-off"></ul>
</div>
+<div id="logicalPoolExtend" title="$_("Device path")">
+ <div class="host-partition">
+ <p class="text-help">
+ $_("Looking for available partitions ...")
+ <img src = "../images/theme-default/loading.gif" />
+ </p>
+ </div>
+</div>
<script id="storageTmpl" type="html/text">
<li id="{name}">
<div class="storage-li in" data-name="{name}" data-stat="{state}">
@@ -74,6 +82,7 @@
<div class="popover actionsheet right-side" style="width: 250px">
<button class="button-big pool-deactivate" data-stat="{state}" data-name="{name}" data-persistent="{persistent}"><span class="text">$_("Deactivate")</span></button>
<button class="button-big pool-activate" data-stat="{state}" data-name="{name}"><span class="text">$_("Activate")</span></button>
+ <button class="button-big pool-extend {enableExt}" data-stat="{state}" data-name="{name}"><span class="text">$_("Extend")</span></button>
<button class="button-big red pool-delete" data-stat="{state}" data-name="{name}"><span class="text">$_("Undefine")</span></button>
</div>
</div>
@@ -107,6 +116,12 @@
</div>
</div>
</script>
+<script id="logicalPoolExtendTmpl" type="html/text">
+ <div>
+ <input type="checkbox" value="{path}" name="devices">
+ <label for="{name}">{path}</label>
+ </div>
+</script>
<script>
kimchi.storage_main();
</script>
--
1.8.3.2
4
3
This function was designed to substitute variables in HTML template strings originally
so it was named as kimchi.template, and it can be used in other scenarios, e.g. we use
it when we load plugins we have a unified URL for plugin XML files:
/plugins/{plugin}/ui/config/tab-ext.xml
and after we have the plugins list, we can easily generate the corresponding URLs like
/plugins/pluginA/ui/config/tab-ext.xml,
/plugins/pluginB/ui/config/tab-ext.xml.
by list ['pluginA', 'pluginB'].
Though it is sometimes misunderstood to be related with VM templates.
Renamed it in this patch.
v1 -> v2:
2a) Configurated git to use "rename" instead of "remove"&"create"
(Thanks to Sheldon & Zheng Sheng's help)
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.grid.js | 2 +-
ui/js/src/kimchi.guest_add_main.js | 2 +-
ui/js/src/kimchi.guest_edit_main.js | 4 ++--
ui/js/src/kimchi.guest_media_main.js | 2 +-
ui/js/src/kimchi.host.js | 2 +-
ui/js/src/kimchi.main.js | 2 +-
ui/js/src/kimchi.network.js | 2 +-
ui/js/src/kimchi.storage_main.js | 4 ++--
ui/js/src/kimchi.storagepool_add_main.js | 2 +-
ui/js/src/{kimchi.template.js => kimchi.substitute.js} | 2 +-
ui/js/src/kimchi.template_add_main.js | 4 ++--
ui/js/src/kimchi.template_edit_main.js | 2 +-
ui/js/src/kimchi.template_main.js | 2 +-
13 files changed, 16 insertions(+), 16 deletions(-)
rename ui/js/src/{kimchi.template.js => kimchi.substitute.js} (96%)
diff --git a/ui/js/src/kimchi.grid.js b/ui/js/src/kimchi.grid.js
index 055f487..2c70969 100644
--- a/ui/js/src/kimchi.grid.js
+++ b/ui/js/src/kimchi.grid.js
@@ -375,7 +375,7 @@ kimchi.widget.Grid.prototype = (function() {
var container = $('#' + containerID);
var gridID = this['opts']['id'];
var rowSelection = this['opts']['rowSelection'] || 'single';
- var domNode = $(kimchi.template(htmlStr, {
+ var domNode = $(kimchi.substitute(htmlStr, {
id: gridID,
loading: i18n['KCHGRD6001M'],
message: i18n['KCHGRD6002M'],
diff --git a/ui/js/src/kimchi.guest_add_main.js b/ui/js/src/kimchi.guest_add_main.js
index 2113099..eefd59a 100644
--- a/ui/js/src/kimchi.guest_add_main.js
+++ b/ui/js/src/kimchi.guest_add_main.js
@@ -25,7 +25,7 @@ kimchi.guest_add_main = function() {
var html = '';
var tmpl = $('#tmpl-template').html();
$.each(result, function(index, value) {
- html += kimchi.template(tmpl, value);
+ html += kimchi.substitute(tmpl, value);
});
$('#templateTile').html(html);
return;
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 0236e2d..90dcb32 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -42,7 +42,7 @@ kimchi.guest_edit_main = function() {
$.each(storages, function(index, storage) {
storage['vm'] = kimchi.selectedGuest;
rowHTML = $('#' + storage['type'] + '-row-tmpl').html();
- var templated = kimchi.template(rowHTML, storage);
+ var templated = kimchi.substitute(rowHTML, storage);
container.append(templated);
});
@@ -96,7 +96,7 @@ kimchi.guest_edit_main = function() {
$(".action-area", item).toggleClass("hide");
};
var addItem = function(data) {
- var itemNode = $.parseHTML(kimchi.template($('#interface-tmpl').html(),data));
+ var itemNode = $.parseHTML(kimchi.substitute($('#interface-tmpl').html(),data));
$(".body", "#form-guest-edit-interface").append(itemNode);
$("select", itemNode).append(networkOptions);
if(data.network!==""){
diff --git a/ui/js/src/kimchi.guest_media_main.js b/ui/js/src/kimchi.guest_media_main.js
index 02009ec..d6dee2e 100644
--- a/ui/js/src/kimchi.guest_media_main.js
+++ b/ui/js/src/kimchi.guest_media_main.js
@@ -28,7 +28,7 @@ kimchi.guest_media_main = function() {
$.each(storages, function(index, storage) {
storage['vm'] = kimchi.selectedGuest;
- var templated = kimchi.template(rowHTML, storage);
+ var templated = kimchi.substitute(rowHTML, storage);
container.append(templated);
});
diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js
index 4c94fc1..ee59a7e 100644
--- a/ui/js/src/kimchi.host.js
+++ b/ui/js/src/kimchi.host.js
@@ -485,7 +485,7 @@ kimchi.host_main = function() {
data['memory'] = kimchi.formatMeasurement(data['memory'], {
fixed: 2
});
- var templated = kimchi.template(htmlTmpl, data);
+ var templated = kimchi.substitute(htmlTmpl, data);
$('#host-content-container').html(templated);
initPage();
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js
index 86fed5b..184029d 100644
--- a/ui/js/src/kimchi.main.js
+++ b/ui/js/src/kimchi.main.js
@@ -69,7 +69,7 @@ kimchi.main = function() {
var tabs = retrieveTabs(tabConfigUrl);
kimchi.listPlugins(function(plugins) {
$(plugins).each(function(i, p) {
- var url = kimchi.template(pluginConfigUrl, {
+ var url = kimchi.substitute(pluginConfigUrl, {
plugin: p
});
tabs.push.apply(tabs, retrieveTabs(url));
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index ca6d29b..875bc08 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -63,7 +63,7 @@ kimchi.getNetworkItemHtml = function(network) {
}
var disable_in_use = network.in_use ? "ui-state-disabled" : "";
- var networkItem = kimchi.template($('#networkItem').html(), {
+ var networkItem = kimchi.substitute($('#networkItem').html(), {
name : network.name,
state : network.state,
type : network.type,
diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js
index 6052510..1493124 100644
--- a/ui/js/src/kimchi.storage_main.js
+++ b/ui/js/src/kimchi.storage_main.js
@@ -25,7 +25,7 @@ kimchi.doListStoragePools = function() {
value.capacity = kimchi.changetoProperUnit(value.capacity,1);
value.allocated = kimchi.changetoProperUnit(value.allocated,1);
if ('kimchi-iso' !== value.type) {
- listHtml += kimchi.template(storageHtml, value);
+ listHtml += kimchi.substitute(storageHtml, value);
}
});
$('#storagepoolsList').html(listHtml);
@@ -172,7 +172,7 @@ kimchi.doListVolumes = function(poolObj) {
value.poolname = poolObj.data('name');
value.capacity = kimchi.changetoProperUnit(value.capacity,1);
value.allocation = kimchi.changetoProperUnit(value.allocation,1);
- listHtml += kimchi.template(volumeHtml, value);
+ listHtml += kimchi.substitute(volumeHtml, value);
});
volumeDiv.html(listHtml);
} else {
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..050aa90 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -30,7 +30,7 @@ kimchi.initStorageAddPage = function() {
valid_types = ['part', 'disk', 'mpath'];
$.each(data, function(index, value) {
if (valid_types.indexOf(value.type) != -1) {
- listHtml += kimchi.template(deviceHtml, value);
+ listHtml += kimchi.substitute(deviceHtml, value);
}
});
$('.host-partition').html(listHtml);
diff --git a/ui/js/src/kimchi.template.js b/ui/js/src/kimchi.substitute.js
similarity index 96%
rename from ui/js/src/kimchi.template.js
rename to ui/js/src/kimchi.substitute.js
index 082269f..9d4dff6 100644
--- a/ui/js/src/kimchi.template.js
+++ b/ui/js/src/kimchi.substitute.js
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-kimchi.template = function(templateStr, data, tag) {
+kimchi.substitute = function(templateStr, data, tag) {
tag = tag || /\{([^\}]+)\}/g;
var escapeHtml = function(html) {
diff --git a/ui/js/src/kimchi.template_add_main.js b/ui/js/src/kimchi.template_add_main.js
index dbb3952..e9adbac 100644
--- a/ui/js/src/kimchi.template_add_main.js
+++ b/ui/js/src/kimchi.template_add_main.js
@@ -152,7 +152,7 @@ kimchi.template_add_main = function() {
volume.isoId = isoId;
volume.capacity = kimchi.changetoProperUnit(volume.capacity, 1);
kimchi.isoInfo[isoId] = volume;
- html += kimchi.template(template, volume);
+ html += kimchi.substitute(template, volume);
}
});
$('#list-local-iso').append(html);
@@ -266,7 +266,7 @@ kimchi.template_add_main = function() {
if (!kimchi.isoInfo[isoId]) {
volume.isoId = isoId;
kimchi.isoInfo[isoId] = volume;
- html += kimchi.template(template, volume);
+ html += kimchi.substitute(template, volume);
}
});
$('#list-remote-iso').html(html);
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index 9ff8bcc..cffc685 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -87,7 +87,7 @@ kimchi.template_edit_main = function() {
var html = '';
var tmpl = $('#tmpl-network').html();
$.each(result, function(index, network) {
- html += kimchi.template(tmpl, network);
+ html += kimchi.substitute(tmpl, network);
});
$('#template-edit-network-list').html(html).show();
if(template.networks && template.networks.length > 0) {
diff --git a/ui/js/src/kimchi.template_main.js b/ui/js/src/kimchi.template_main.js
index 160ecc8..b90e3f3 100644
--- a/ui/js/src/kimchi.template_main.js
+++ b/ui/js/src/kimchi.template_main.js
@@ -22,7 +22,7 @@ kimchi.doListTemplates = function() {
var listHtml = '';
var templateHtml = $('#templateTmpl').html();
$.each(result, function(index, value) {
- listHtml += kimchi.template(templateHtml, value);
+ listHtml += kimchi.substitute(templateHtml, value);
});
$('#templateList').html(listHtml);
kimchi.templateBindClick();
--
1.8.1.4
2
1
[PATCH] Add /var/spool/cron to default host configuration backup paths
by Zhou Zheng Sheng 27 May '14
by Zhou Zheng Sheng 27 May '14
27 May '14
/var/spool/cron contains user cron jobs and ".cron.hostname". It should
be included in the default backup.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
plugins/ginger/ginger.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/ginger/ginger.conf b/plugins/ginger/ginger.conf
index dbb2aa2..d6dce1d 100644
--- a/plugins/ginger/ginger.conf
+++ b/plugins/ginger/ginger.conf
@@ -4,7 +4,7 @@ plugin_class = "Ginger"
uri = "/plugins/ginger"
[backup]
-default_include = ['/etc', ]
+default_include = ['/etc', '/var/spool/cron']
default_exclude = ['/etc/init.d', '/etc/rc.d', '/etc/rc?.d', ]
[/]
--
1.9.0
1
1
Hi,
This patch series is to enable Kimchi to assign hos devices directly to
a VM, thus greately improve VM performance. Currently we support assigning
PCI device, USB device and SCSI LUN. For example, we can assign an NIC
to VM to improve guest network throughput, or passthrough a USB camera
to enable the guest OS to record video.
Host devices form a tree. We can assign most of the devices in the tree
to VM. By assigning a device, all the devices in its sub-tree are also
assigned. It might not make sense to assign a USB controller, because
the host may be using one of the devices connected to the controller.
Instead, Kimchi just presents the "leaf" devices to assign to guest.
In recent Linux kernel and KVM, it is able to recognize the IOMMU group
of a PCI device. The "leaf" PCI devices in the same IOMMU group should
be assigned and dismissed together. The IOMMU group is the actual
smallest isolation granularity of the PCI devices.
The first patch is to list all host devices information. It's useful on
its own to show host devices information.
The second patch is to list all eligible host devices to assign, as well
as the "affected" devices in the same IOMMU group.
The third patch creates a sub-collection "hostdevs" to the VM resource,
and deals with assigning and dismissing devices.
The fourth patch adds a sub-collection "vm_holders" to the host device
resource. It's to list all VMs that are holding the device.
I'll update API and unit test once everyone is happy with the interface
and logic.
v4:
Add new sub-collection to host device to list the VMs holding the device.
v3:
Fix a small naming error introduced by rebase.
v2:
Handle the devices in VM's sub-collection "hostdevs".
v1:
Handle the devices in VM template.
Zhou Zheng Sheng (4):
Host device passthrough: List all types of host devices
Host device passthrough: List eligible device to passthrough
Host device passthrough: Directly assign and dissmis host device from
VM
Host device passthrough: List VMs that are holding a host device
docs/API.md | 11 +-
src/kimchi/control/host.py | 16 ++
src/kimchi/control/vm/hostdevs.py | 44 ++++++
src/kimchi/featuretests.py | 10 +-
src/kimchi/hostdev.py | 263 +++++++++++++++++++++++++++++++
src/kimchi/i18n.py | 7 +
src/kimchi/mockmodel.py | 7 +-
src/kimchi/model/config.py | 2 +
src/kimchi/model/host.py | 53 +++++--
src/kimchi/model/libvirtstoragepool.py | 18 +--
src/kimchi/model/vmhostdevs.py | 277 +++++++++++++++++++++++++++++++++
src/kimchi/rollbackcontext.py | 3 +
src/kimchi/xmlutils.py | 26 +++-
tests/test_rest.py | 6 +-
tests/test_storagepool.py | 7 +-
15 files changed, 711 insertions(+), 39 deletions(-)
create mode 100644 src/kimchi/control/vm/hostdevs.py
create mode 100644 src/kimchi/hostdev.py
create mode 100644 src/kimchi/model/vmhostdevs.py
--
1.9.0
1
4
[PATCHv3] Exception: fix exception details when not specified
by lvroyce@linux.vnet.ibm.com 27 May '14
by lvroyce@linux.vnet.ibm.com 27 May '14
27 May '14
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
v2>v3, Because kimchi exception used unicode as msg, convert it to str
to make unicode encode work.
v1>v2, Add a new type of error to cover general schema validation error.
(per Sheldon's comments)
Not every validation error needs to translate for user,
we define user interested errors,
other developer interested error should report directly by schema validator,
and handled by developer directly.
fix exception handling for this situation.
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Signed-off-by: Zheng Sheng Zhou <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/control/utils.py | 6 ++++--
src/kimchi/i18n.py | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py
index 5e63816..081bb81 100644
--- a/src/kimchi/control/utils.py
+++ b/src/kimchi/control/utils.py
@@ -98,8 +98,10 @@ def validate_params(params, instance, action):
try:
validator.validate(request)
except ValidationError, e:
- raise InvalidParameter(e.schema['error'], {'value': str(e.instance)})
-
+ if e.schema.get('error'):
+ raise InvalidParameter(e.schema['error'], {'value': str(e.instance)})
+ else:
+ raise InvalidParameter("KCHAPI0008E", {"err": str(e.message)})
class UrlSubNode(object):
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 25b703f..4ed13fe 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -30,6 +30,7 @@ messages = {
"KCHAPI0005E": _("Create is not allowed for %(resource)s"),
"KCHAPI0006E": _("Unable to parse JSON request"),
"KCHAPI0007E": _("This API only supports JSON"),
+ "KCHAPI0008E": _("Parameters does not match requirement in schema: %(err)s"),
"KCHASYNC0001E": _("Datastore is not initiated in the model object."),
"KCHASYNC0002E": _("Unable to start task due error: %(err)s"),
--
1.8.3.2
3
2
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
ticket support for guest
ShaoHe Feng (4):
update API.md
ticket in backend: add a set ticket action for VM resource
support ticket in UI.
set the password for spice and VNC page.
docs/API.md | 4 ++++
src/kimchi/control/vms.py | 1 +
src/kimchi/model/vms.py | 28 ++++++++++++++++++++++++++++
ui/js/src/kimchi.api.js | 33 ++++++++++++++++++++++++++++++++-
ui/pages/spice.html.tmpl | 3 ++-
ui/pages/websockify/console.html | 5 +++++
6 files changed, 72 insertions(+), 2 deletions(-)
--
1.9.0
9
26
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Fix for ref_cnt for disk attachment.
Royce Lv (2):
disk attachment: fix ref_cnt to prevent double attach
disk attachment: avoid checking cdrom ref_cnt
src/kimchi/model/vmstorages.py | 31 ++++++++++++++++++++++++++++++-
tests/test_model.py | 1 +
2 files changed, 31 insertions(+), 1 deletion(-)
--
1.8.3.2
3
8
Hi,
There is a problem while creating a new template with local isos.
If some iso is stored inside an active storagepool, then kimchi is going
to show it for selection.
Kimchi looks for any file, with any name, but of type "iso" -
IsoVolumesModel:get_list() in
src/kimchi/model/storagevolumes.py.
So, isos rename like ubuntu.iso.1 or even teste.exe will be shown to user.
Error happens if user selects one of them, because the JSON schema
restricts file names to
ends with ".iso".
According to my tests, Libvirt accepts any name, since the file is ISO
type. So, I would like to
propose to remove the ".iso" checking in the JSON schema.
This is not going to break anything in UI.
Problems would happen if user tries to create a template using the API
directly and gives a file
that is not an ISO. In this case, a error will be returned by libvirt
and triggered to user.
Patch is quite simple. Any objection ?
Rodrigo Trujillo
1
1
[PATCH V2] Issue#361:Bugfix as disable the action button content when creating network
by Wen Wang 23 May '14
by Wen Wang 23 May '14
23 May '14
Bugfix that disabled the content display of the action button for an exsiting
network when creating a new network.
V1 -> V2
Accroding to Hongliang Wang, fix the bug that tabs keep shown when there
exists more than one network.
---
ui/js/src/kimchi.network.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index ca6d29b..8c037e5 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -165,11 +165,13 @@ kimchi.addNetworkActions = function(network) {
icons : {
secondary : "action-button-icon"
}
- }).click(function() {
+ }).click(function(event) {
+ event.stopPropagation();
+ $("*").find(".menu-container", "#" + network.name).toggle(false);
$(".menu-container", "#" + network.name).toggle();
window.scrollBy(0, 150);
});
- $(".menu-container", "#" + network.name).mouseleave(function() {
+ $(document).click(function(event) {
$(".menu-container", "#" + network.name).toggle(false);
});
};
--
1.9.1
2
1
Hi,
This patch series is to enable Kimchi to assign hos devices directly to
a VM, thus greately improve VM performance. Currently we support assigning
PCI device, USB device and SCSI LUN. For example, we can assign an NIC
to VM to improve guest network throughput, or passthrough a USB camera
to enable the guest OS to record video.
Host devices form a tree. We can assign most of the devices in the tree
to VM. By assigning a device, all the devices in its sub-tree are also
assigned. It might not make sense to assign a USB controller, because
the host may be using one of the devices connected to the controller.
Instead, Kimchi just presents the "leaf" devices to assign to guest.
In recent Linux kernel and KVM, it is able to recognize the IOMMU group
of a PCI device. The "leaf" PCI devices in the same IOMMU group should
be assigned and dismissed together. The IOMMU group is the actual
smallest isolation granularity of the PCI devices.
The first patch is to list all host devices information. It's useful on
its own to show host devices information.
The second patch is to list all eligible host devices to assign, as well
as the "affected" devices in the same IOMMU group.
The third patch creates a sub-collection "hostdevs" to the VM resource,
and deals with assigning and dismissing devices.
I'll update API and unit test once everyone is happy with the interface
and logic.
v1:
Handle the devices in VM template.
v2:
Handle the devices in VM's sub-collection "hostdevs".
v3:
Fix a small naming error introduced by rebase.
Zhou Zheng Sheng (3):
PCI passthrough: list all types of host devices
PCI passthrough: list eligible device to passthrough
PCI passthrough: Directly assign and dissmis host device from VM
docs/API.md | 11 +-
src/kimchi/control/host.py | 9 ++
src/kimchi/control/vm/hostdevs.py | 44 ++++++
src/kimchi/featuretests.py | 10 +-
src/kimchi/hostdev.py | 266 +++++++++++++++++++++++++++++++++
src/kimchi/i18n.py | 7 +
src/kimchi/mockmodel.py | 7 +-
src/kimchi/model/config.py | 2 +
src/kimchi/model/host.py | 32 ++--
src/kimchi/model/libvirtstoragepool.py | 18 +--
src/kimchi/model/vmhostdevs.py | 259 ++++++++++++++++++++++++++++++++
src/kimchi/rollbackcontext.py | 3 +
src/kimchi/xmlutils.py | 26 +++-
tests/test_rest.py | 6 +-
tests/test_storagepool.py | 7 +-
15 files changed, 668 insertions(+), 39 deletions(-)
create mode 100644 src/kimchi/control/vm/hostdevs.py
create mode 100644 src/kimchi/hostdev.py
create mode 100644 src/kimchi/model/vmhostdevs.py
--
1.9.0
2
7
23 May '14
Most forms contain fields that must be filled before they are submitted.
Some of them submit the missing data and display an error message when
something goes wrong, and some of them do not allow the user to submit
them if some data is missing.
Make the forms behavior consistent by enabling their buttons only
when the required data is entered.
Internally, the page tags all required fields with the class "required"
and whenever any of their values change, they are checke. If any
required field is empty, the submit button becomses disabled; otherwise,
it becomes enabled.
Fix GitHub issue #317 ("Inconsistent button status when adding or
creating new resources").
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
ui/css/theme-default/login-window.css | 4 --
ui/js/src/kimchi.guest_edit_main.js | 15 +++++++
ui/js/src/kimchi.login_window.js | 36 +++++++--------
ui/js/src/kimchi.storagepool_add_main.js | 75 +++++++++++++++++++++++---------
ui/js/src/kimchi.template_edit_main.js | 20 +++++++++
ui/pages/guest-edit.html.tmpl | 6 +--
ui/pages/i18n.html.tmpl | 6 ---
ui/pages/login-window.html.tmpl | 8 ++--
ui/pages/storagepool-add.html.tmpl | 6 +--
ui/pages/template-edit.html.tmpl | 8 ++--
10 files changed, 117 insertions(+), 67 deletions(-)
diff --git a/ui/css/theme-default/login-window.css b/ui/css/theme-default/login-window.css
index 8a21090..d021be6 100644
--- a/ui/css/theme-default/login-window.css
+++ b/ui/css/theme-default/login-window.css
@@ -62,10 +62,6 @@
width: 290px;
}
-#login-window .login-panel .msg-required {
- color: red;
-}
-
#login-window .login-panel button {
font-size: 18px;
height: 40px;
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 0236e2d..bb4ee51 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -202,6 +202,21 @@ kimchi.guest_edit_main = function() {
kimchi.retrieveVM(kimchi.selectedGuest, initContent);
+ var updateSubmitButtonStatus = function() {
+ var valid = true;
+ guestEditForm.find('input.required').each(function(index, field) {
+ if (field.value === '') {
+ valid = false;
+ return;
+ }
+ });
+
+ saveButton.prop('disabled', !valid);
+ };
+
+ guestEditForm.find('input.required').on('input propertychange',
+ updateSubmitButtonStatus);
+
var submitForm = function(event) {
$(saveButton).prop('disabled', true);
var data=$('#form-guest-edit-general').serializeObject();
diff --git a/ui/js/src/kimchi.login_window.js b/ui/js/src/kimchi.login_window.js
index 9c06a50..52394a5 100644
--- a/ui/js/src/kimchi.login_window.js
+++ b/ui/js/src/kimchi.login_window.js
@@ -30,26 +30,25 @@ kimchi.login_main = function() {
$(opt).prop('selected', selectedLanguage === k);
}
+ var updateSubmitButtonStatus = function() {
+ var valid = true;
+ $('#form-login').find('input.required').each(function(index, field) {
+ if (field.value === '') {
+ valid = false;
+ return;
+ }
+ });
+
+ $('#btn-login').prop('disabled', !valid);
+ }
+
+ $('#form-login').find('input.required').on('input propertychange',
+ updateSubmitButtonStatus);
+
$('#language').on('change', function() {
kimchi.topic('languageChanged').publish($(this).val());
});
- var validateNonEmpty = function(idsArray) {
- for(var i = 0; i < idsArray.length; i++) {
- var id = idsArray[i];
- if (!$('#' + id).val()) {
- $('#' + id + '-msg').text(i18n['KCHAUTH6002E']);
- placeCursor(id);
- return false;
- }
- else {
- $('#' + id + '-msg').empty();
- }
- }
-
- return true;
- };
-
var placeCursor = function(id) {
if (id && $('#' + id).size() > 0) {
$('#' + id).focus();
@@ -66,11 +65,6 @@ kimchi.login_main = function() {
};
var login = function(event) {
-
- if (!validateNonEmpty(['username', 'password'])) {
- return false;
- }
-
$('#btn-login').text(i18n['KCHAUTH6002M']).prop('disabled', true);
var userName = $('#username').val();
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..5356985 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -122,6 +122,18 @@ kimchi.initStorageAddPage = function() {
});
});
+ var updateSubmitButtonStatus = function() {
+ var valid = true;
+ $('#form-pool-add').find('input.required').each(function(index, field) {
+ if (field.value === '') {
+ valid = false;
+ return;
+ }
+ });
+
+ $('#pool-doAdd').prop('disabled', !valid);
+ };
+
$('#poolTypeInputId').change(function() {
var poolObject = {'dir': ".path-section", 'netfs': '.nfs-section',
'iscsi': '.iscsi-section', 'scsi': '.scsi-section',
@@ -134,7 +146,49 @@ kimchi.initStorageAddPage = function() {
$(value).addClass('tmpl-html');
}
});
+
+ switch (selectType) {
+ case 'dir':
+ $('#pathId').addClass('required');
+
+ $('#nfsserverId').removeClass('required');
+ $('#nfspathId').removeClass('required');
+ $('#iscsiserverId').removeClass('required');
+ break;
+ case 'netfs':
+ $('#nfsserverId').addClass('required');
+ $('#nfspathId').addClass('required');
+
+ $('#pathId').removeClass('required');
+ $('#iscsiserverId').removeClass('required');
+ break;
+ case 'iscsi':
+ $('#iscsiserverId').addClass('required');
+
+ $('#pathId').removeClass('required');
+ $('#nfsserverId').removeClass('required');
+ $('#nfspathId').removeClass('required');
+ break;
+ case 'scsi':
+ $('#pathId').removeClass('required');
+ $('#nfsserverId').removeClass('required');
+ $('#nfspathId').removeClass('required');
+ $('#iscsiserverId').removeClass('required');
+ break;
+ case 'logical':
+ $('#pathId').removeClass('required');
+ $('#nfsserverId').removeClass('required');
+ $('#nfspathId').removeClass('required');
+ $('#iscsiserverId').removeClass('required');
+ break;
+ }
+
+ updateSubmitButtonStatus();
});
+
+ $('#form-pool-add').find('input').on('input propertychange',
+ updateSubmitButtonStatus);
+
$('#authId').click(function() {
if ($(this).prop("checked")) {
$('.authenticationfield').removeClass('tmpl-html');
@@ -150,10 +204,6 @@ kimchi.initStorageAddPage = function() {
kimchi.validateForm = function() {
var name = $('#poolId').val();
var poolType = $("#poolTypeInputId").val();
- if ('' === name) {
- kimchi.message.error.code('KCHPOOL6001E');
- return false;
- }
if (name.indexOf("/")!=-1) {
kimchi.message.error.code('KCHPOOL6004E');
return false;
@@ -173,10 +223,6 @@ kimchi.validateForm = function() {
kimchi.validateDirForm = function () {
var path = $('#pathId').val();
- if ('' === path) {
- kimchi.message.error.code('KCHPOOL6002E');
- return false;
- }
if (!/(^\/.*)$/.test(path)) {
kimchi.message.error.code('KCHAPI6003E');
return false;
@@ -190,10 +236,6 @@ kimchi.validateNfsForm = function () {
if (!kimchi.validateServer(nfsserver)) {
return false;
}
- if ('' === nfspath) {
- kimchi.message.error.code('KCHPOOL6003E');
- return false;
- }
if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(nfspath)) {
kimchi.message.error.code('KCHPOOL6005E');
return false;
@@ -203,22 +245,13 @@ kimchi.validateNfsForm = function () {
kimchi.validateIscsiForm = function() {
var iscsiServer = $('#iscsiserverId').val();
- var iscsiTarget = $('#iscsiTargetId').val();
if (!kimchi.validateServer(iscsiServer)) {
return false;
}
- if ('' === iscsiTarget) {
- kimchi.message.error.code('KCHPOOL6007E');
- return false;
- }
return true;
};
kimchi.validateServer = function(serverField) {
- if ('' === serverField) {
- kimchi.message.error.code('KCHPOOL6008E');
- return false;
- }
if(!kimchi.isServer(serverField)) {
kimchi.message.error.code('KCHPOOL6009E');
return false;
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index f0f4718..e552bf9 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -104,6 +104,26 @@ kimchi.template_edit_main = function() {
});
});
+ var updateSubmitButtonStatus = function() {
+ var valid = true;
+ templateEditForm.find('input.required').each(function(index, field) {
+ if (field.value === '') {
+ valid = false;
+ return;
+ }
+ });
+
+ if (valid) {
+ $('#tmpl-edit-button-save').removeAttr('disabled');
+ }
+ else {
+ $('#tmpl-edit-button-save').attr('disabled', 'disabled');
+ }
+ };
+
+ templateEditForm.find('input.required').on('input propertychange',
+ updateSubmitButtonStatus);
+
$('#tmpl-edit-button-cancel').on('click', function() {
kimchi.window.close();
});
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 96d907e..d35ad7a 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -49,7 +49,7 @@
</div>
<div class="guest-edit-wrapper-controls">
<input id="guest-edit-id-textbox"
- name="name" type="text" />
+ name="name" type="text" class="required" />
</div>
</div>
<div>
@@ -62,7 +62,7 @@
<input
id="guest-edit-cores-textbox"
name="cpus"
- type="text" />
+ type="text" class="required" />
</div>
</div>
<div>
@@ -74,7 +74,7 @@
<div class="guest-edit-wrapper-controls">
<input id="guest-edit-memory-textbox"
name="memory"
- type="text" />
+ type="text" class="required" />
</div>
</div>
<div>
diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl
index 98da828..814825f 100644
--- a/ui/pages/i18n.html.tmpl
+++ b/ui/pages/i18n.html.tmpl
@@ -33,7 +33,6 @@
<script>
var i18n = {
'KCHAUTH6001E': "$_("The username or password you entered is incorrect. Please try again.")",
- 'KCHAUTH6002E': "$_("This field is required.")",
'KCHAUTH6001M': "$_("Log in")",
'KCHAUTH6002M': "$_("Logging in...")",
@@ -158,14 +157,9 @@ var i18n = {
'KCHPOOL6004M': "$_("SCSI Fibre Channel")",
'KCHPOOL6005M': "$_("No SCSI adapters found.")",
- 'KCHPOOL6001E': "$_("The storage pool name can not be blank.")",
- 'KCHPOOL6002E': "$_("The storage pool path can not be blank.")",
- 'KCHPOOL6003E': "$_("NFS server mount path can not be blank.")",
'KCHPOOL6004E': "$_("Invalid storage pool name. It should not contain '/'.")",
'KCHPOOL6005E': "$_("Invalid NFS mount path.")",
'KCHPOOL6006E': "$_("No logical device selected.")",
- 'KCHPOOL6007E': "$_("The iSCSI target can not be blank.")",
- 'KCHPOOL6008E': "$_("Server name can not be blank.")",
'KCHPOOL6009E': "$_("This is not a valid Server Name or IP. please, modify it.")",
'KCHPOOL6010M': "$_("Looking for available partitions ...")",
'KCHPOOL6011M': "$_("No available partitions found.")",
diff --git a/ui/pages/login-window.html.tmpl b/ui/pages/login-window.html.tmpl
index 3e451c4..1cd9e83 100644
--- a/ui/pages/login-window.html.tmpl
+++ b/ui/pages/login-window.html.tmpl
@@ -34,15 +34,13 @@
<div class="content login-panel">
<form id="form-login" action="/login" method="POST">
<div class="row">
- <input type="text" id="username" name="username" required="required" placeholder="$_("User Name")" />
- <div id="username-msg" class="msg-required"></div>
+ <input type="text" id="username" name="username" class="required" placeholder="$_("User Name")" />
</div>
<div class="row">
- <input type="password" id="password" name="password" required="required" placeholder="$_("Password")" />
- <div id="password-msg" class="msg-required"></div>
+ <input type="password" id="password" name="password" class="required" placeholder="$_("Password")" />
</div>
<div class="row">
- <button id="btn-login" class="btn-normal">$_("Log in")</button>
+ <button id="btn-login" class="btn-normal" disabled="true">$_("Log in")</button>
</div>
</form>
</div>
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 977db66..6ce1343 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -36,7 +36,7 @@
<p class="text-help">
$_("The name used to identify the storage pools, and it should not be empty.")
</p>
- <input id="poolId" required="required" type="text" class="text storage-base-input-width" name="name">
+ <input id="poolId" type="text" class="text storage-base-input-width required" name="name">
</div>
</section>
<section class="form-section">
@@ -60,7 +60,7 @@
$_("The path of the Storage Pool. Each Storage Pool must have a unique path.")</p>
<p class="text-help">
$_("Kimchi will try to create the directory when it does not already exist in your system.")</p>
- <input id="pathId" type="text" class="text storage-base-input-width">
+ <input id="pathId" type="text" class="text storage-base-input-width required">
</div>
<div class="clear"></div>
</section>
@@ -152,7 +152,7 @@
</div>
<footer>
<div class="btn-group">
- <button id="pool-doAdd" class="btn-normal">
+ <button id="pool-doAdd" class="btn-normal" disabled="disabled">
<span class="text">$_("Create")</span>
</button>
</div>
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 434d938..46b7058 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -36,7 +36,7 @@
<label for="template-edit-id-textbox">$_("Name")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-id-textbox" name="name" type="text" />
+ <input id="template-edit-id-textbox" name="name" type="text" class="required" />
</div>
</div>
<div>
@@ -60,7 +60,7 @@
<label for="template-edit-cpu-textbox">$_("CPU Number")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-cpu-textbox" name="cpus" type="text" />
+ <input id="template-edit-cpu-textbox" name="cpus" type="text" class="required" />
</div>
</div>
<div>
@@ -68,7 +68,7 @@
<label for="template-edit-memory-textbox">$_("Memory")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-memory-textbox" name="memory" type="text" />
+ <input id="template-edit-memory-textbox" name="memory" type="text" class="required" />
</div>
</div>
<div>
@@ -76,7 +76,7 @@
<label for="template-edit-disk-textbox">$_("Disk (GB)")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-disk-textbox" name="disks" type="text" />
+ <input id="template-edit-disk-textbox" name="disks" type="text" class="required" />
</div>
</div>
</fieldset>
--
1.9.0
3
7
Hi all,
I was looking over patches today and wished that there was better
context for the changed lines. Specifically, I wanted a function name
instead of just the class name.
I finally came across this e-mail [1] from someone at Red Hat:
"""
Hello,
I'm sure you're aware of hunk header lines in patches:
@@ -24,5 +24,5 @@ class SomeClass(object):
It's possible to configure which source line Git selects for the hunk
header. By default it uses non-indented lines. A "python" regexp, which
selects functions, classes and methods, is already included in Git; you
just have to enable it. I also use custom regexps for ldifs and API.txt:
$ cat ~/.gitattributes # (Or .git/info/attributes for project-specific
config)
*.py diff=python
API.txt diff=apitxt
*.ldif diff=ldif
*.update diff=ldif
$ git config -l # set with e.g. `git config --global key="value"`
...
core.attributesfile=~/.gitattributes
diff.apitxt.xfuncname=^command: .*
diff.ldif.xfuncname=^dn:.*
Enjoy your Friday!
--
Petr³
"""
We can also define our own, as per:
http://stackoverflow.com/questions/2783086/how-does-git-diff-generate-hunk-…
I put *.py diff=python into my kimchi project's .git/info/attributes
file, and I like these diffs a lot better.
For example (using a really old branch I should have deleted while ago!
):
@@ -37,7 +37,6 @@ class AsyncTask(object):
self.status = 'running'
self.message = 'OK'
self._save_helper()
- self._cp_request = cherrypy.serving.request
self.thread = threading.Thread(target=self._run_helper,
args=(opaque, self._status_cb))
self.thread.setDaemon(True)
@@ -37,7 +37,6 @@ class AsyncTask(object):
self.status = 'running'
self.message = 'OK'
self._save_helper()
- self._cp_request = cherrypy.serving.request
self.thread = threading.Thread(target=self._run_helper,
args=(opaque, self._status_cb))
self.thread.setDaemon(True)
@@ -60,17 +59,13 @@ class AsyncTask(object):
obj = {}
for attr in ('id', 'target_uri', 'message', 'status'):
obj[attr] = getattr(self, attr)
- try:
- with self.objstore as session:
- session.store('task', self.id, obj)
- except Exception as e:
- raise OperationFailed('KCHASYNC0002E', {'err': e.message})
+ with self.objstore as session:
+ session.store('task', self.id, obj)
def _run_helper(self, opaque, cb):
- cherrypy.serving.request = self._cp_request
try:
changes to:
diff --git a/src/kimchi/asynctask.py b/src/kimchi/asynctask.py
index e2d2dcf..8f0d96c 100644
--- a/src/kimchi/asynctask.py
+++ b/src/kimchi/asynctask.py
@@ -37,7 +37,6 @@ def __init__(self, id, target_uri, fn, objstore,
opaque=None):
self.status = 'running'
self.message = 'OK'
self._save_helper()
- self._cp_request = cherrypy.serving.request
self.thread = threading.Thread(target=self._run_helper,
args=(opaque, self._status_cb))
self.thread.setDaemon(True)
@@ -60,17 +59,13 @@ def _save_helper(self):
obj = {}
for attr in ('id', 'target_uri', 'message', 'status'):
obj[attr] = getattr(self, attr)
- try:
- with self.objstore as session:
- session.store('task', self.id, obj)
- except Exception as e:
- raise OperationFailed('KCHASYNC0002E', {'err': e.message})
+ with self.objstore as session:
So now you can see the function that the code is in, not the
larger-scope (the class).
I thought I would share, in case any one else wanted to use this.
Maybe we could even add a .gitattributes file to kimchi if others think
it's a good idea to enforce some project-specific conventions.
Happy coding!
- Christy
[1]
http://www.redhat.com/archives/freeipa-devel/2013-April/msg00381.html
2
2
22 May '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
V1 -> V2:
The improvement concept here is to directly generate JSON on the server
and assign it to the i18n variable, rather than inserting nodes into the DOM.
Plugins would use a plugin1.i18n= structure to keep plugin strings from
colliding with each other, or with the kimchi variables.
ShaoHe Feng (5):
Update root.py to make Cheetah render the JSON template.
Update the i18n tmpl to produce JSON
Add JS API for fetching i18n JSON
add an optional to toggle the sample plugin
generate the translation files for plugins/sample
Zhou Zheng Sheng (2):
Add Minimal UI Page for the Sample Plugin
Issue #342: load i18n.html of the plugin
configure.ac | 11 +++
plugins/sample/Makefile.am | 25 ++++-
plugins/sample/__init__.py | 3 +-
plugins/sample/config.status | 1 +
plugins/sample/po/LINGUAS | 1 +
plugins/sample/po/Makefile.in.in | 1 +
plugins/sample/po/Makevars | 1 +
plugins/sample/po/POTFILES.in | 2 +
plugins/sample/po/en_US.po | 21 ++++
plugins/sample/po/gen-pot | 1 +
plugins/sample/po/pt_BR.po | 24 +++++
plugins/sample/po/zh_CN.po | 24 +++++
plugins/sample/sample.conf | 7 --
plugins/sample/sample.conf.in | 12 +++
plugins/sample/ui/config/tab-ext.xml | 9 +-
plugins/sample/ui/pages/i18n.json.tmpl | 9 ++
plugins/sample/ui/pages/tab.html.tmpl | 6 ++
src/kimchi/root.py | 5 +
src/kimchi/template.py | 34 ++++---
ui/js/src/kimchi.api.js | 18 +++-
ui/js/src/kimchi.main.js | 24 ++++-
ui/pages/i18n.html.tmpl | 176 ---------------------------------
ui/pages/i18n.json.tmpl | 163 ++++++++++++++++++++++++++++++
23 files changed, 368 insertions(+), 210 deletions(-)
create mode 120000 plugins/sample/config.status
create mode 120000 plugins/sample/po/LINGUAS
create mode 120000 plugins/sample/po/Makefile.in.in
create mode 120000 plugins/sample/po/Makevars
create mode 100644 plugins/sample/po/POTFILES.in
create mode 100644 plugins/sample/po/en_US.po
create mode 120000 plugins/sample/po/gen-pot
create mode 100644 plugins/sample/po/pt_BR.po
create mode 100644 plugins/sample/po/zh_CN.po
delete mode 100644 plugins/sample/sample.conf
create mode 100644 plugins/sample/sample.conf.in
create mode 100644 plugins/sample/ui/pages/i18n.json.tmpl
create mode 100644 plugins/sample/ui/pages/tab.html.tmpl
delete mode 100644 ui/pages/i18n.html.tmpl
create mode 100644 ui/pages/i18n.json.tmpl
--
1.9.0
5
27
Enable debug report rename feature in this patch set.
Hongliang Wang (6):
Debug Report Rename: Update API.json
Debug Report Rename: Update API.md
Debug Report Rename: Implement Back-end
Debug Report Rename UI: Add API in kimchi.api.js
Debug Report Rename UI: Add Rename Page
Debug Report Rename UI: Enable Rename in Host Tab
docs/API.md | 3 ++
src/kimchi/API.json | 11 +++++++
src/kimchi/control/debugreports.py | 4 ++-
src/kimchi/model/debugreports.py | 13 +++++++++
ui/css/theme-default/report-rename.css | 22 ++++++++++++++
ui/js/src/kimchi.api.js | 12 ++++++++
ui/js/src/kimchi.host.js | 12 ++++++++
ui/js/src/kimchi.report_rename_main.js | 39 +++++++++++++++++++++++++
ui/pages/report-rename.html.tmpl | 53 ++++++++++++++++++++++++++++++++++
9 files changed, 168 insertions(+), 1 deletion(-)
create mode 100644 ui/css/theme-default/report-rename.css
create mode 100644 ui/js/src/kimchi.report_rename_main.js
create mode 100644 ui/pages/report-rename.html.tmpl
--
1.8.1.4
4
15
Hi,
This patch series is to enable Kimchi to assign hos devices directly to
a VM, thus greately improve VM performance. Currently we support assigning
PCI device, USB device and SCSI LUN. For example, we can assign an NIC
to VM to improve guest network throughput, or passthrough a USB camera
to enable the guest OS to record video.
Host devices form a tree. We can assign most of the devices in the tree
to VM. By assigning a device, all the devices in its sub-tree are also
assigned. It might not make sense to assign a USB controller, because
the host may be using one of the devices connected to the controller.
Instead, Kimchi just presents the "leaf" devices to assign to guest.
In recent Linux kernel and KVM, it is able to recognize the IOMMU group
of a PCI device. The "leaf" PCI devices in the same IOMMU group should
be assigned and dismissed together. The IOMMU group is the actual
smallest isolation granularity of the PCI devices.
The first patch is to list all host devices information. It's useful on
its own to show host devices information.
The second patch is to list all eligible host devices to assign, as well
as the "affected" devices in the same IOMMU group.
The third patch creates a sub-collection "hostdevs" to the VM resource,
and deals with assigning and dismissing devices.
I'll update API and unit test once everyone is happy with the interface
and logic.
Zhou Zheng Sheng (3):
PCI passthrough: list all types of host devices
PCI passthrough: list eligible device to passthrough
PCI passthrough: Directly assign and dissmis host device from VM
docs/API.md | 11 +-
src/kimchi/control/host.py | 9 ++
src/kimchi/control/vm/hostdevs.py | 44 ++++++
src/kimchi/featuretests.py | 10 +-
src/kimchi/hostdev.py | 266 +++++++++++++++++++++++++++++++++
src/kimchi/i18n.py | 7 +
src/kimchi/mockmodel.py | 7 +-
src/kimchi/model/config.py | 2 +
src/kimchi/model/host.py | 32 ++--
src/kimchi/model/libvirtstoragepool.py | 18 +--
src/kimchi/model/vmhostdevs.py | 259 ++++++++++++++++++++++++++++++++
src/kimchi/rollbackcontext.py | 3 +
src/kimchi/xmlutils.py | 26 +++-
tests/test_rest.py | 6 +-
tests/test_storagepool.py | 7 +-
15 files changed, 668 insertions(+), 39 deletions(-)
create mode 100644 src/kimchi/control/vm/hostdevs.py
create mode 100644 src/kimchi/hostdev.py
create mode 100644 src/kimchi/model/vmhostdevs.py
--
1.9.0
2
5
$ sudo PYTHONPATH=src ./src/kimchid
*** Running feature tests ***
[21/May/2014:19:41:48] ENGINE Error in 'start' listener <bound method
CapabilitiesModel._set_capabilities of
<kimchi.model.config.CapabilitiesModel object at 0x314ac10>>
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/cherrypy/process/wspbus.py",
line 197, in publish
output.append(listener(*args, **kwargs))
File "/home/shhfeng/work/workdir/kimchi/src/kimchi/model/config.py",
line 69, in _set_capabilities
self.metadata_support = FeatureTests.has_metadata_support()
File "/home/shhfeng/work/workdir/kimchi/src/kimchi/featuretests.py",
line 197, in has_metadata_support
conn = libvirt.open('qemu:///system')
File "/usr/lib64/python2.7/site-packages/libvirt.py", line 247, in open
if ret is None:raise libvirtError('virConnectOpen() failed')
libvirtError: Failed to connect socket to
'/var/run/libvirt/libvirt-sock': Connection refused
[21/May/2014:19:41:48] ENGINE Shutting down due to error in start listener:
[21/May/2014:19:41:48] ENGINE Bus STOPPING
[21/May/2014:19:41:48] ENGINE HTTP Server
cherrypy._cpwsgi_server.CPWSGIServer(('127.0.0.1', 8010)) shut down
[21/May/2014:19:41:48] ENGINE Stopped thread '_TimeoutMonitor'.
[21/May/2014:19:41:48] ENGINE Stopped thread 'Autoreloader'.
[21/May/2014:19:41:48] ENGINE Bus STOPPED
[21/May/2014:19:41:48] ENGINE Bus EXITING
[21/May/2014:19:41:48] ENGINE Bus EXITED
I do not find the root reason. but
after I use LibvirtConnection to open a libvirt connection, kimchi can
start.
+from kimchi.model.libvirtconnection import LibvirtConnection
@@ -104,7 +105,7 @@ def libvirt_supports_iso_stream(protocol):
- conn = libvirt.open('qemu:///system')
+ conn = LibvirtConnection('qemu:///system').get()
--
Thanks and best regards!
Sheldon Feng(???)<shaohef(a)linux.vnet.ibm.com>
IBM Linux Technology Center
1
0
[PATCHv2] Exception: fix exception details when not specified
by lvroyce@linux.vnet.ibm.com 21 May '14
by lvroyce@linux.vnet.ibm.com 21 May '14
21 May '14
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
v1>v2, Add a new type of error to cover general schema validation error.
(per Sheldon's comments)
Not every validation error needs to translate for user,
we define user interested errors,
other developer interested error should report directly by schema validator,
and handled by developer directly.
fix exception handling for this situation.
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Signed-off-by: Zheng Sheng Zhou <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/control/utils.py | 6 ++++--
src/kimchi/exception.py | 2 +-
src/kimchi/i18n.py | 1 +
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py
index 5e63816..611b1c0 100644
--- a/src/kimchi/control/utils.py
+++ b/src/kimchi/control/utils.py
@@ -98,8 +98,10 @@ def validate_params(params, instance, action):
try:
validator.validate(request)
except ValidationError, e:
- raise InvalidParameter(e.schema['error'], {'value': str(e.instance)})
-
+ if e.schema.get('error'):
+ raise InvalidParameter(e.schema['error'], {'value': str(e.instance)})
+ else:
+ raise InvalidParameter("KCHAPI0008E", {"err": e.message})
class UrlSubNode(object):
diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py
index fcf60cc..5a292e0 100644
--- a/src/kimchi/exception.py
+++ b/src/kimchi/exception.py
@@ -62,7 +62,7 @@ class KimchiException(Exception):
# itself to a unicode string.
args[key] = unicode(value)
- return unicode(translation.gettext(text), 'utf-8') % args
+ return translation.gettext(text).encode('utf-8') % args
class NotFoundError(KimchiException):
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 25b703f..4ed13fe 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -30,6 +30,7 @@ messages = {
"KCHAPI0005E": _("Create is not allowed for %(resource)s"),
"KCHAPI0006E": _("Unable to parse JSON request"),
"KCHAPI0007E": _("This API only supports JSON"),
+ "KCHAPI0008E": _("Parameters does not match requirement in schema: %(err)s"),
"KCHASYNC0001E": _("Datastore is not initiated in the model object."),
"KCHASYNC0002E": _("Unable to start task due error: %(err)s"),
--
1.8.3.2
1
0
According to #296, Dialogue window blocked ui when generating debug
report. I have one proposal that added a process bar showing that it's
working without blocking ui:
I have two thoughts:
1. Dynamic dots during generating process indicate it's working.
2. Dynamic background(with the blue stripe moving forward) indicating
it's working.
Your comments on this design are highly valued and very important to me.
Best regards
Wang Wen
2
2
[PATCH] Issue#361:Bugfix as disable the action button content when creating network
by Wen Wang 16 May '14
by Wen Wang 16 May '14
16 May '14
Bugfix that disabled the content display of the action button for an exsiting
network when creating a new network.
---
ui/js/src/kimchi.network.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index ca6d29b..7ff39ae 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -172,6 +172,9 @@ kimchi.addNetworkActions = function(network) {
$(".menu-container", "#" + network.name).mouseleave(function() {
$(".menu-container", "#" + network.name).toggle(false);
});
+ $("#networkAdd").on("click", function() {
+ $(".menu-container", "#" + network.name).toggle(false);
+ });
};
kimchi.initNetworkCreation = function() {
--
1.9.1
2
1
Re: [Kimchi-devel] [PATCH 3/3] Use action verb as the main button's label
by Hongliang Wang 16 May '14
by Hongliang Wang 16 May '14
16 May '14
On 05/16/2014 01:37 AM, Crístian Viana wrote:
> On 15-05-2014 00:30, Hongliang Wang wrote:
>> It's an interesting topic here.
> I agree :-) I wish we had more discussions like this here.
>> Take edit template for example. The flow is:
>> List templates =>
>> Select a template to edit by clicking the "*Edit*" Button =>
>> Edit template window is open, and user changes some fields. =>
>> Click the "*Save*" (Or "Submit") Button to save (or submit) changes.
>>
>> Notice that "Edit" means the user is about to edit the template, so
>> "Edit'" Button should trigger a pop-up window to allow user to change
>> some fields.
>> And "Save" Button is for saving user's changes to server. So I think
>> it's reasonable to use these 2 labels for these 2 different purposes.
> You're right, that's another way of labeling the buttons. But this is
> also not used in throughout Kimchi and that's what concerns me. Some
> windows have the "Save" button, some windows have the same label as
> the button which triggered it; we need a consistency. Whichever way is
> fine for me, as long as it looks consistent. I don't like the idea of
> having each dialog of the same application designed differently, even
> if subtly, which is how I feel it is now.
> I also thought about always using "Save" as the buttons' labels, as
> you said, and that sounds totally fine for me. If we think this
> approach is better, I'll use this approach on the next version of this
> patchset.
Go ahead! Either "Save" or "Submit" is fine for me.
>> Let me explain the naming rule of #guest-edit-button-save. It follows
>> name space style like Java package mechanism.
>> guest-: It's within the scope of guest page
>> edit-: It's within the scope of guest edit window
>> button-: It's a button within the scope of guest edit window
>> save: It's a button named save
>>
>> So please remain the original ID string of the button. If we will
>> introduce another button in the future, we can simply name it
>> "#guest-edit-button-newid".
> Thanks for the explanation, it makes total sense. I just blindly
> removed the "save" string from the variable name, I should have left
> "edit" instead, which is the new label I'm using.
> But, again, this variable naming rule is also not consistent
> throughout thel Kimchi code. For example, the submit button of the
> dialog "Create Storage Pool" has an id="pool-doAdd". According to this
> naming rule, it should be something like "storage-add-button-create".
> In this patch, I was just trying to remove the reference to "save",
> which was the label I removed. I agree I should have left the new
> label on the ID, "edit". But I think this is a different discussion,
> regarding coding consistency, which [definitely] needs to be addressed
> in future patches. I'll use "guest-edit-button-edit" in the next
> version of this patch to keep the style you mentioned.
Agree. The naming rules is totally not consistent because we didn't
propose one unified. I also think we need have a unified naming rule (as
well as same user experience through out Kimchi, including windows,
dialog s, buttons, operation behaviors, etc.). Maybe we need propose a
coding/designing guideline documentation for future code. If we are
planning to, I'm glad to be involved in.
1
0
Finished align vlan fields. Redesigned the pattern of the label positions
V2 -> V3:
Address to Hongliang Wang: Have the additional margin place removed.
v1 -> v2:
Address to Hongliang Wang: Have the unrelated lines removed & Have the display format changed from table to div.
Address to Yuxin Huo: Have the unused IDs removed.
Signed-off-by: Wen Wang <wenwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/network.css | 21 ++++++++++++++++-----
ui/js/src/kimchi.network.js | 8 ++++----
ui/pages/tabs/network.html.tmpl | 26 +++++++++++++++++---------
3 files changed, 37 insertions(+), 18 deletions(-)
diff --git a/ui/css/theme-default/network.css b/ui/css/theme-default/network.css
index 67f2aa2..176b277 100644
--- a/ui/css/theme-default/network.css
+++ b/ui/css/theme-default/network.css
@@ -209,19 +209,30 @@
vertical-align: top;
}
-.network-config .destination {
- margin-left: 28px;
+.bridge-option-column {
+ display: inline-block;
+ margin-left: 56px;
+ vertical-align: middle;
+}
+
+.bridge-option-column > div {
+ height: 25px;
+ line-height: 25px;
}
-.network-config .VLAN {
- margin-left: 28px;
+.bridge-option-column select {
+ height: 26px;
}
-.network-config .VLAN input[type="text"] {
+.bridge-option-column input[type="text"] {
height: 25px;
width: 60px;
}
+#labelNetworkVlanID {
+ margin-left: 26px;
+}
+
.network-config .input-hint-icon {
margin: -1px 1px 0 0;
display: inline-block;
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index 7a331be..ca6d29b 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -275,13 +275,14 @@ kimchi.enableBridgeOptions = function(enable) {
$("#networkVlanID").prop("disabled", true);
$("#networkVlanID").val("");
$("#networkInterface").val("");
- $("#bridge-options").slideUp(100);
+ $("#bridgeOptions").slideUp(100);
} else if (!$("#networkInterface").val()){
$("#networkInterface").prop("selectedIndex", 0);
- $("#bridge-options").slideDown(100);
+ $("#bridgeOptions").slideDown(100);
}
};
+
kimchi.setDefaultNetworkType = function(isInterfaceAvail) {
$("#networkTypeBri").prop("checked", isInterfaceAvail);
$("#networkTypeBri").prop("disabled", !isInterfaceAvail);
@@ -289,7 +290,7 @@ kimchi.setDefaultNetworkType = function(isInterfaceAvail) {
if (!isInterfaceAvail) {
kimchi.enableBridgeOptions(false);
} else {
- $("#bridge-options").slideDown(100);
+ $("#bridgeOptions").slideDown(100);
}
};
@@ -318,7 +319,6 @@ kimchi.cleanNetworkDialog = function() {
$("#networkVlanID").prop("disabled", true);
$("#enableVlan").prop("checked", false);
};
-
kimchi.setupNetworkFormEvent = function() {
$("#networkName").on("keyup", function(event) {
$("#networkName").toggleClass("invalid-field", !$("#networkName").val().match(/^[a-zA-Z0-9_]+$/));
diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl
index e49b257..aacd2b6 100644
--- a/ui/pages/tabs/network.html.tmpl
+++ b/ui/pages/tabs/network.html.tmpl
@@ -68,16 +68,24 @@
<input type="radio" id="networkTypeBri" name="networkType" value="bridged">
<label for="networkTypeBri">$_("Bridged: Virtual machines are connected to physical network directly")</label>
</div>
- <div id="bridge-options">
- <div class="destination">
- <label for="networkInterface">$_("Destination"): </label>
- <select id="networkInterface"></select>
+ <div id="bridgeOptions">
+ <div class="bridge-option-column">
+ <div>
+ <label for="networkInterface">$_("Destination"): </label>
+ </div>
+ <div>
+ <select id="networkInterface"></select>
+ </div>
</div>
- <div class="VLAN">
- <label for="enableVlan">$_("Enable VLAN"): </label>
- <input id="enableVlan" type="checkbox" value=""/>
- <label for="networkVlanID">$_("VLAN ID"): </label>
- <input type="text" id="networkVlanID" disabled>
+ <div class="bridge-option-column">
+ <div>
+ <input id="enableVlan" type="checkbox" value=""/>
+ <label for="enableVlan">$_("Enable VLAN"): </label>
+ </div>
+ <div>
+ <label id="labelNetworkVlanID">$_("VLAN ID"): </label>
+ <input type="text" id="networkVlanID" disabled>
+ </div>
</div>
</div>
</div>
--
1.9.1
2
1
Finished align vlan fields. Redesigned the pattern of the label positions
v1 -> v2:
Address to Hongliang Wang: Have the unrelated lines removed & Have the display format changed from table to div.
Address to Yuxin Huo: Have the unused IDs removed.
Signed-off-by: Wen Wang <wenwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/network.css | 18 +++++++++++++++---
ui/js/src/kimchi.network.js | 8 ++++----
ui/pages/tabs/network.html.tmpl | 26 +++++++++++++++++---------
3 files changed, 36 insertions(+), 16 deletions(-)
diff --git a/ui/css/theme-default/network.css b/ui/css/theme-default/network.css
index 67f2aa2..5a06715 100644
--- a/ui/css/theme-default/network.css
+++ b/ui/css/theme-default/network.css
@@ -209,19 +209,31 @@
vertical-align: top;
}
-.network-config .destination {
+.bridge-option-column {
+ display: inline-block;
margin-left: 28px;
+ vertical-align: middle;
}
-.network-config .VLAN {
+.bridge-option-column > div {
margin-left: 28px;
+ height: 25px;
+ line-height: 25px;
+}
+
+.bridge-option-column select {
+ height: 26px;
}
-.network-config .VLAN input[type="text"] {
+.bridge-option-column input[type="text"] {
height: 25px;
width: 60px;
}
+#labelNetworkVlanID {
+ margin-left: 26px;
+}
+
.network-config .input-hint-icon {
margin: -1px 1px 0 0;
display: inline-block;
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index 7a331be..ca6d29b 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -275,13 +275,14 @@ kimchi.enableBridgeOptions = function(enable) {
$("#networkVlanID").prop("disabled", true);
$("#networkVlanID").val("");
$("#networkInterface").val("");
- $("#bridge-options").slideUp(100);
+ $("#bridgeOptions").slideUp(100);
} else if (!$("#networkInterface").val()){
$("#networkInterface").prop("selectedIndex", 0);
- $("#bridge-options").slideDown(100);
+ $("#bridgeOptions").slideDown(100);
}
};
+
kimchi.setDefaultNetworkType = function(isInterfaceAvail) {
$("#networkTypeBri").prop("checked", isInterfaceAvail);
$("#networkTypeBri").prop("disabled", !isInterfaceAvail);
@@ -289,7 +290,7 @@ kimchi.setDefaultNetworkType = function(isInterfaceAvail) {
if (!isInterfaceAvail) {
kimchi.enableBridgeOptions(false);
} else {
- $("#bridge-options").slideDown(100);
+ $("#bridgeOptions").slideDown(100);
}
};
@@ -318,7 +319,6 @@ kimchi.cleanNetworkDialog = function() {
$("#networkVlanID").prop("disabled", true);
$("#enableVlan").prop("checked", false);
};
-
kimchi.setupNetworkFormEvent = function() {
$("#networkName").on("keyup", function(event) {
$("#networkName").toggleClass("invalid-field", !$("#networkName").val().match(/^[a-zA-Z0-9_]+$/));
diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl
index e49b257..aacd2b6 100644
--- a/ui/pages/tabs/network.html.tmpl
+++ b/ui/pages/tabs/network.html.tmpl
@@ -68,16 +68,24 @@
<input type="radio" id="networkTypeBri" name="networkType" value="bridged">
<label for="networkTypeBri">$_("Bridged: Virtual machines are connected to physical network directly")</label>
</div>
- <div id="bridge-options">
- <div class="destination">
- <label for="networkInterface">$_("Destination"): </label>
- <select id="networkInterface"></select>
+ <div id="bridgeOptions">
+ <div class="bridge-option-column">
+ <div>
+ <label for="networkInterface">$_("Destination"): </label>
+ </div>
+ <div>
+ <select id="networkInterface"></select>
+ </div>
</div>
- <div class="VLAN">
- <label for="enableVlan">$_("Enable VLAN"): </label>
- <input id="enableVlan" type="checkbox" value=""/>
- <label for="networkVlanID">$_("VLAN ID"): </label>
- <input type="text" id="networkVlanID" disabled>
+ <div class="bridge-option-column">
+ <div>
+ <input id="enableVlan" type="checkbox" value=""/>
+ <label for="enableVlan">$_("Enable VLAN"): </label>
+ </div>
+ <div>
+ <label id="labelNetworkVlanID">$_("VLAN ID"): </label>
+ <input type="text" id="networkVlanID" disabled>
+ </div>
</div>
</div>
</div>
--
1.9.1
2
1
15 May '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
Apparently, in plugin code there is no way to insert new entries into
Kimchi ./ui/pages/i18n.html.tmpl, so every plugin should provide its own
i18n.html.tmpl.
each plugin provides a "plugins/plugin-name/ui/pages/i18n.html.tmpl",
and maps it to the URI "plugins/plugin-name/i18n.html". This is already
supported by the kimchi back-end. What we have to do is just to load
"plugins/plugin-name/i18n.html" in the front-end code.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.api.js | 3 ++-
ui/js/src/kimchi.main.js | 19 ++++++++++++++++++-
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 7d85fdf..d4d92d8 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -558,13 +558,14 @@ var kimchi = {
});
},
- listPlugins : function(suc, err) {
+ listPlugins : function(suc, err, async) {
kimchi.requestJSON({
url : kimchi.url + 'plugins',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend: true,
+ async: async ? async : true,
success : suc,
error : err
});
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js
index 86fed5b..82778cc 100644
--- a/ui/js/src/kimchi.main.js
+++ b/ui/js/src/kimchi.main.js
@@ -62,8 +62,19 @@ kimchi.main = function() {
return tabs;
};
+ var retrieveI18ns = function(url) {
+ $.ajax({
+ url : url,
+ async : false,
+ success : function(html) {
+ $('#main').append(html)},
+ error: function(html) {}
+ });
+ };
+
var tabConfigUrl = '/config/ui/tabs.xml';
var pluginConfigUrl = '/plugins/{plugin}/ui/config/tab-ext.xml';
+ var pluginI18nUrl = 'plugins/{plugin}/i18n.html';
var DEFAULT_HASH;
var buildTabs = function(callback) {
var tabs = retrieveTabs(tabConfigUrl);
@@ -72,6 +83,10 @@ kimchi.main = function() {
var url = kimchi.template(pluginConfigUrl, {
plugin: p
});
+ var i18nurl = kimchi.template(pluginI18nUrl, {
+ plugin: p
+ });
+ retrieveI18ns(i18nurl);
tabs.push.apply(tabs, retrieveTabs(url));
});
@@ -85,7 +100,9 @@ kimchi.main = function() {
$('#nav-menu').append(genTabs(tabs));
callback && callback();
- });
+ }, function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }, true);
};
var onLanguageChanged = function(lang) {
--
1.9.0
4
13
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Yu Xin Huo (1):
StoragePool Edit: Add Disk to Logical Pool
Royce Lv (2):
StoragePool Edit: Add Disk to Logical Pool
StoragePool Edit: Update json schema
src/kimchi/API.json | 3 ++-
ui/js/src/kimchi.api.js | 12 ++++++++++
ui/js/src/kimchi.storage_main.js | 41 ++++++++++++++++++++++++++++++++
ui/js/src/kimchi.storagepool_add_main.js | 2 +-
ui/pages/i18n.html.tmpl | 1 +
ui/pages/tabs/storage.html.tmpl | 10 ++++++++
6 files changed, 67 insertions(+), 2 deletions(-)
--
1.8.3.2
4
5
The schema checker needs to report an error message when the disk size
is less than 1GB. Currently this message is missing, so it reports an
KeyError. This patch adds the error message.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 6 ++++--
src/kimchi/i18n.py | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index b9d371a..d2a834c 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -384,7 +384,8 @@
}
},
"minItems": 1,
- "uniqueItems": true
+ "uniqueItems": true,
+ "error": "KCHTMPL0022E"
},
"storagepool": {
"description": "Location of the storage pool",
@@ -554,7 +555,8 @@
}
},
"minItems": 1,
- "uniqueItems": true
+ "uniqueItems": true,
+ "error": "KCHTMPL0022E"
},
"storagepool": {
"description": "Location of the storage pool",
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 25b703f..e105e50 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -119,6 +119,7 @@ messages = {
"KCHTMPL0019E": _("The volume: %(volume)s in not in storage pool %(pool)s"),
"KCHTMPL0020E": _("Unable to create template due error: %(err)s"),
"KCHTMPL0021E": _("Unable to delete template due error: %(err)s"),
+ "KCHTMPL0022E": _("Disk size must be greater than 1GB."),
"KCHPOOL0001E": _("Storage pool %(name)s already exists"),
"KCHPOOL0002E": _("Storage pool %(name)s does not exist"),
--
1.9.0
1
1
Signed-off-by: Adam King <rak(a)linux.vnet.ibm.com>
---
docs/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/README.md b/docs/README.md
index 63ac760..c658637 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -14,7 +14,7 @@ Desktop Browser Support:
-----------------------
* **Internet Explorer:** IE9+
* **Chrome:** Current-1 version
-* **Firefox:** Current-1 version Firefox 17ESR
+* **Firefox:** Current-1 version Firefox 24ESR
* **Safari:** Current-1 version
* **Opera:** Current-1 version
--
1.9.0
3
3
14 May '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
Apparently, in plugin code there is no way to insert new entries into
Kimchi ./ui/pages/i18n.html.tmpl, so every plugin should provide its own
i18n.html.tmpl.
each plugin provides a "plugins/plugin-name/ui/pages/i18n.html.tmpl",
and maps it to the URI "plugins/plugin-name/i18n.html". This is already
supported by the kimchi back-end. What we have to do is just to load
"plugins/plugin-name/i18n.html" in the front-end code.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.api.js | 3 ++-
ui/js/src/kimchi.main.js | 19 ++++++++++++++++++-
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 7d85fdf..d4d92d8 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -558,13 +558,14 @@ var kimchi = {
});
},
- listPlugins : function(suc, err) {
+ listPlugins : function(suc, err, async) {
kimchi.requestJSON({
url : kimchi.url + 'plugins',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend: true,
+ async: async ? async : true,
success : suc,
error : err
});
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js
index 86fed5b..82778cc 100644
--- a/ui/js/src/kimchi.main.js
+++ b/ui/js/src/kimchi.main.js
@@ -62,8 +62,19 @@ kimchi.main = function() {
return tabs;
};
+ var retrieveI18ns = function(url) {
+ $.ajax({
+ url : url,
+ async : false,
+ success : function(html) {
+ $('#main').append(html)},
+ error: function(html) {}
+ });
+ };
+
var tabConfigUrl = '/config/ui/tabs.xml';
var pluginConfigUrl = '/plugins/{plugin}/ui/config/tab-ext.xml';
+ var pluginI18nUrl = 'plugins/{plugin}/i18n.html';
var DEFAULT_HASH;
var buildTabs = function(callback) {
var tabs = retrieveTabs(tabConfigUrl);
@@ -72,6 +83,10 @@ kimchi.main = function() {
var url = kimchi.template(pluginConfigUrl, {
plugin: p
});
+ var i18nurl = kimchi.template(pluginI18nUrl, {
+ plugin: p
+ });
+ retrieveI18ns(i18nurl);
tabs.push.apply(tabs, retrieveTabs(url));
});
@@ -85,7 +100,9 @@ kimchi.main = function() {
$('#nav-menu').append(genTabs(tabs));
callback && callback();
- });
+ }, function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }, true);
};
var onLanguageChanged = function(lang) {
--
1.9.0
1
0
Finished align vlan fields. Redesigned the pattern of the label positions
Signed-off-by: Wen Wang <wenwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/network.css | 28 ++++++++++++++++++++++------
ui/js/src/kimchi.network.js | 10 +++++-----
ui/pages/tabs/network.html.tmpl | 33 ++++++++++++++++++++++-----------
3 files changed, 49 insertions(+), 22 deletions(-)
diff --git a/ui/css/theme-default/network.css b/ui/css/theme-default/network.css
index 67f2aa2..98220ab 100644
--- a/ui/css/theme-default/network.css
+++ b/ui/css/theme-default/network.css
@@ -198,7 +198,7 @@
color: #666666;
border: solid 1px;
background-color: white;
- padding: 3px 4px 3px 0;
+ padding: 3px 4px 3px 0;192.168.122.0/24
}
.network-config .input-container {
@@ -209,17 +209,33 @@
vertical-align: top;
}
-.network-config .destination {
- margin-left: 28px;
+.network-config .destination select {
+ margin-left: 48px;
+
+}
+
+.network-config .destination label {
+ vertical-align: middle;
+ margin-left: 48px;
}
-.network-config .VLAN {
- margin-left: 28px;
+.network-config .VLANID input[type="checkbox"] {
+ margin-left: 34px;
+ vertical-align: middle;
}
-.network-config .VLAN input[type="text"] {
+.network-config .VLANID label {
+ vertical-align: middle;
+}
+
+.network-config .labelVLAN label {
+ margin-left: 56px;
+ vertical-align: middle;
+}
+.network-config .labelVLAN input[type="text"] {
height: 25px;
width: 60px;
+ vertical-align: middle;
}
.network-config .input-hint-icon {
diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js
index 7a331be..cfd7338 100644
--- a/ui/js/src/kimchi.network.js
+++ b/ui/js/src/kimchi.network.js
@@ -244,6 +244,7 @@ kimchi.openNetworkDialog = function(okCallback) {
if (nics[$("#networkInterface").val()].type === "bridge") {
$("#enableVlan").prop("checked", false);
$("#enableVlan").prop("disabled", true);
+ $("#enableVlan").slideUp(100);
$("#networkVlanID").val("");
$("#networkVlanID").prop("disabled", true);
} else {
@@ -275,13 +276,14 @@ kimchi.enableBridgeOptions = function(enable) {
$("#networkVlanID").prop("disabled", true);
$("#networkVlanID").val("");
$("#networkInterface").val("");
- $("#bridge-options").slideUp(100);
+ $("#bridgeOptions").slideUp(100);
} else if (!$("#networkInterface").val()){
$("#networkInterface").prop("selectedIndex", 0);
- $("#bridge-options").slideDown(100);
+ $("#bridgeOptions").slideDown(100);
}
};
+
kimchi.setDefaultNetworkType = function(isInterfaceAvail) {
$("#networkTypeBri").prop("checked", isInterfaceAvail);
$("#networkTypeBri").prop("disabled", !isInterfaceAvail);
@@ -289,7 +291,7 @@ kimchi.setDefaultNetworkType = function(isInterfaceAvail) {
if (!isInterfaceAvail) {
kimchi.enableBridgeOptions(false);
} else {
- $("#bridge-options").slideDown(100);
+ $("#bridgeOptions").slideDown(100);
}
};
@@ -315,10 +317,8 @@ kimchi.cleanNetworkDialog = function() {
$("#networkInterface option").removeAttr("selected").find(":first").attr("selected", "selected");
$("#networkFormOk").off("click");
$("#networkFormOk").button("disable");
- $("#networkVlanID").prop("disabled", true);
$("#enableVlan").prop("checked", false);
};
-
kimchi.setupNetworkFormEvent = function() {
$("#networkName").on("keyup", function(event) {
$("#networkName").toggleClass("invalid-field", !$("#networkName").val().match(/^[a-zA-Z0-9_]+$/));
diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl
index e49b257..c9bf1d4 100644
--- a/ui/pages/tabs/network.html.tmpl
+++ b/ui/pages/tabs/network.html.tmpl
@@ -68,17 +68,28 @@
<input type="radio" id="networkTypeBri" name="networkType" value="bridged">
<label for="networkTypeBri">$_("Bridged: Virtual machines are connected to physical network directly")</label>
</div>
- <div id="bridge-options">
- <div class="destination">
- <label for="networkInterface">$_("Destination"): </label>
- <select id="networkInterface"></select>
- </div>
- <div class="VLAN">
- <label for="enableVlan">$_("Enable VLAN"): </label>
- <input id="enableVlan" type="checkbox" value=""/>
- <label for="networkVlanID">$_("VLAN ID"): </label>
- <input type="text" id="networkVlanID" disabled>
- </div>
+ <div id="bridgeOptions">
+ <table id="tableBridgeOption" >
+ <tr>
+ <td class="destination">
+ <label id="labelNetworkInterface">$_("Destination"): </label>
+ </td>
+ <td class="VLANID">
+ <input id="enableVlan" type="checkbox" value=""/>
+ <label id="labelVlanID">$_("Enable VLAN"): </label>
+ </td>
+ </tr>
+ <tr>
+ <td class="destination">
+ <select id="networkInterface"></select>
+ </td>
+ <td class="labelVLAN">
+ <label id="labelNetworkVlanID">$_("VLAN ID"): </label>
+ <input type="text" id="networkVlanID" disabled>
+ </td>
+ </tr>
+ </table>
+
</div>
</div>
</div>
--
1.9.1
3
2
[PATCH] Issue #317: disable storage pool create by default in UI
by shaohef@linux.vnet.ibm.com 14 May '14
by shaohef@linux.vnet.ibm.com 14 May '14
14 May '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
All button status of add/create pages should be consistent - it should
be disabled by default until the minimum of the required fields are
filled.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.storagepool_add_main.js | 8 ++++++++
ui/pages/storagepool-add.html.tmpl | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 86dbe7f..7bed152 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -145,6 +145,14 @@ kimchi.initStorageAddPage = function() {
$('#iscsiportId').keyup(function(event) {
$(this).toggleClass("invalid-field",!/^[0-9]+$/.test($(this).val()));
});
+ $('#form-pool-add').change(function() {
+ if (kimchi.validateForm()) {
+ $('#pool-doAdd').removeAttr('disabled');
+ } else {
+ $('#pool-doAdd').attr('disabled', 'disabled');
+ }
+
+ });
};
kimchi.validateForm = function() {
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 977db66..7406bab 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -152,7 +152,7 @@
</div>
<footer>
<div class="btn-group">
- <button id="pool-doAdd" class="btn-normal">
+ <button id="pool-doAdd" class="btn-normal" disabled="disabled">
<span class="text">$_("Create")</span>
</button>
</div>
--
1.9.0
3
2
The storage pool type list does not have a left padding like the
other combo boxes in Kimchi, bringing the text very close to the UI
component's border.
Apply a common CSS class to the combo box so it looks like the other
objects in the application.
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
ui/pages/storagepool-add.html.tmpl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 977db66..6700b56 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -44,7 +44,7 @@
<div class="storage-type-wrapper-controls">
<div id="poolTypeId">
<input id="poolTypeInputId" name="type" type="hidden" value="dir"/>
- <span id="pool-type-label"></span><span class="arrow"></span>
+ <span id="pool-type-label" class="text"></span><span class="arrow"></span>
<div>
<ul id="storagePool-list">
</ul>
--
1.9.0
1
1
13 May '14
Common UI guidelines state that there should be ellipsis on buttons or
menu items when additional information is required from the user to
perform the operation, usually via a modal window or a popup. Some
operations in Kimchi require additional input from the user (e.g.
Template > Edit) while other operations do not (e.g. Template > Clone).
Using a common guideline like this makes the UI easier to navigate, so
the user can expect a new dialog when clicking on "Template > Edit" and
no additional dialog when clicking on "Template > Clone", for example.
There is a related discussion on this link:
http://stackoverflow.com/q/637683/38333.
Append an ellipsis to buttons and menu items that require additional
user information.
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.host.js | 6 +++---
ui/pages/guest-add.html.tmpl | 2 +-
ui/pages/guest.html.tmpl | 4 ++--
ui/pages/tabs/templates.html.tmpl | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js
index 4c94fc1..9bfc844 100644
--- a/ui/js/src/kimchi.host.js
+++ b/ui/js/src/kimchi.host.js
@@ -84,7 +84,7 @@ kimchi.host_main = function() {
title: i18n['KCHREPO6003M'],
toolbarButtons: [{
id: 'repositories-grid-add-button',
- label: i18n['KCHREPO6012M'],
+ label: i18n['KCHREPO6012M'] + '…',
onClick: function(event) {
kimchi.window.open({url:'repository-add.html', class: repo_type});
}
@@ -106,7 +106,7 @@ kimchi.host_main = function() {
}
}, {
id: 'repositories-grid-edit-button',
- label: i18n['KCHREPO6013M'],
+ label: i18n['KCHREPO6013M'] + "…",
disabled: true,
onClick: function(event) {
var repository = repositoriesGrid.getSelected();
@@ -291,7 +291,7 @@ kimchi.host_main = function() {
title: i18n['KCHDR6002M'],
toolbarButtons: [{
id: reportGridID + '-generate-button',
- label: i18n['KCHDR6006M'],
+ label: i18n['KCHDR6006M'] + '…',
onClick: function(event) {
kimchi.window.open('report-add.html', {
close: function() {
diff --git a/ui/pages/guest-add.html.tmpl b/ui/pages/guest-add.html.tmpl
index 84a1994..ab80a2f 100644
--- a/ui/pages/guest-add.html.tmpl
+++ b/ui/pages/guest-add.html.tmpl
@@ -47,7 +47,7 @@
<div id="prompt-create-template" class="hidden">
<div>$_("Please create a template first.")</div>
<a id="btn-create-template" class="btn-normal" href="templates.html">
- <span class="text">$_("Create a Template")</span>
+ <span class="text">$_("Create a Template")…</span>
</a>
</div>
<div id="prompt-choose-template" class="hidden">
diff --git a/ui/pages/guest.html.tmpl b/ui/pages/guest.html.tmpl
index c7335c8..f23889f 100644
--- a/ui/pages/guest.html.tmpl
+++ b/ui/pages/guest.html.tmpl
@@ -56,8 +56,8 @@
<span class="text">$_("Actions")</span><span class="arrow"></span>
<div class="popover actionsheet right-side" style="width: 250px">
<button class="button-big shutoff-disabled" name="vm-console" ><span class="text">$_("Connect")</span></button>
- <button class="button-big shutoff-disabled" name="vm-media"><span class="text">$_("Manage Media")</span></button>
- <button class="button-big running-disabled" name="vm-edit"><span class="text">$_("Edit")</span></button>
+ <button class="button-big shutoff-disabled" name="vm-media"><span class="text">$_("Manage Media")…</span></button>
+ <button class="button-big running-disabled" name="vm-edit"><span class="text">$_("Edit")…</span></button>
<button class="button-big shutoff-hidden" name="vm-reset"><span class="text">$_("Reset")</span></button>
<button class="button-big shutoff-hidden" name="vm-shutdown"><span class="text">$_("Shut Down")</span></button>
<button class="button-big running-hidden" name="vm-start"><span class="text">$_("Start")</span></button>
diff --git a/ui/pages/tabs/templates.html.tmpl b/ui/pages/tabs/templates.html.tmpl
index 6ae6640..59f490c 100644
--- a/ui/pages/tabs/templates.html.tmpl
+++ b/ui/pages/tabs/templates.html.tmpl
@@ -42,7 +42,7 @@
<div class="btn dropdown popable" style="width: 70px">
<span class="text">$_("Actions")</span><span class="arrow"></span>
<div class="popover actionsheet right-side" style="width: 250px">
- <a class="button-big template-edit" data-template='{name}'>$_("Edit")</a>
+ <a class="button-big template-edit" data-template='{name}'>$_("Edit")…</a>
<a class="button-big template-clone" data-template='{name}'>$_("Clone")</a>
<a class="button-big red template-delete" data-template='{name}'>$_("Delete")</a>
</div>
--
1.9.0
1
0
The template update command (as well as the other ones) should return an
error message when any of its property values is empty/wrong. The error
message should describe what happened.
When leaving the disk size empty during the template update command, no
error message is returned and the server an exception is raised.
Update the API JSON file so there is an error message assigned to the
template disk property.
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 3 ++-
src/kimchi/i18n.py | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index b9d371a..92e9720 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -549,7 +549,8 @@
"size": {
"description": "Size (GB) of the disk",
"type": "number",
- "minimum": 1
+ "minimum": 1,
+ "error": "KCHTMPL0022E"
}
}
},
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 25b703f..4beb29d 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -119,6 +119,7 @@ messages = {
"KCHTMPL0019E": _("The volume: %(volume)s in not in storage pool %(pool)s"),
"KCHTMPL0020E": _("Unable to create template due error: %(err)s"),
"KCHTMPL0021E": _("Unable to delete template due error: %(err)s"),
+ "KCHTMPL0022E": _("Disk size must be an integer greater than 0"),
"KCHPOOL0001E": _("Storage pool %(name)s already exists"),
"KCHPOOL0002E": _("Storage pool %(name)s does not exist"),
--
1.9.0
1
0
From: Aline Manera <alinefm(a)br.ibm.com>
Aline Manera (2):
bug fix: Update test cases to use HTTPS
bug fix: Allow changing default ports
src/kimchi.conf.in | 3 ++
src/kimchi/config.py.in | 6 ++--
src/kimchi/proxy.py | 6 ++--
src/kimchi/server.py | 4 +--
src/kimchid.in | 17 ++++-----
tests/test_authorization.py | 5 +--
tests/test_exception.py | 24 +++++++------
tests/test_mockmodel.py | 25 ++++++++------
tests/test_plugin.py | 5 +--
tests/test_rest.py | 80 ++++++++++++++++++++++---------------------
tests/test_server.py | 7 ++--
tests/utils.py | 20 +++++------
12 files changed, 105 insertions(+), 97 deletions(-)
--
1.7.10.4
2
4
[PATCH v2] host/partitions: avoid calling disks.get_partitions_names() for each partition
by Zhou Zheng Sheng 09 May '14
by Zhou Zheng Sheng 09 May '14
09 May '14
Problem:
In PartitionModel.lookup(), it calls disks.get_partitions_names() to
verify the given partition is eligible to be used in a new logical
storage pool as follow.
if name not in disks.get_partitions_names():
raise NotFoundError(...)
When the front-end issues GET request to host/partitions, the back-end
would call get_partitions_names() for each partition. If there are many
disks and partitions in the host, get_partitions_names() takes a long
time to finish, and calling get_partitions_names() for each partition
would make the GET request timeout.
In all, the original control flow is as follow.
GET host/partitions
Partitions._get_resources()
PartitionsModel.get_list()
disks.get_partitions_names()
for each partition name:
Partition.lookup()
PartitionModel.lookup()
verify partition name in disks.get_partitions_names()
disks.get_partition_details()
The solution is to split the block device verification code out of
disks.get_partitions_names(), and put it in a new function
disks._is_available(). Now get_partitions_names() just returns
all the block devices, and disks.get_partition_details() can perform
the eligibility check by calling disks._is_available(). The original
get_partitions_names() checks eligibility for all the detected device,
so calling it for each partition is too slow. The new _is_available()
function just checks the given block device.
The New control flow is as follow.
GET host/partitions
Partitions._get_resources()
PartitionsModel.get_list()
disks.get_partitions_names()
for each partition name:
Partition.lookup()
PartitionModel.lookup()
disks.get_partition_details()
check if the block device _is_available()
v1:
Make use of the resource and model arguments to have Partitions
collection controller set a flag, so Partition model can inspect the
flag and skip the check accordingly.
v2:
v1 solution is too hack, re-write the patch by refactoring the
underlying disks model. Split the batch verification into small peices
amortized by each concrete block device.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/control/host.py | 6 +++++-
src/kimchi/disks.py | 37 +++++++++++++++++++++++--------------
src/kimchi/model/host.py | 3 ---
3 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py
index ad34919..ebf1bed 100644
--- a/src/kimchi/control/host.py
+++ b/src/kimchi/control/host.py
@@ -21,7 +21,7 @@ import cherrypy
from kimchi.control.base import Collection, Resource, SimpleCollection
from kimchi.control.utils import UrlSubNode, validate_method
-from kimchi.exception import OperationFailed
+from kimchi.exception import OperationFailed, NotFoundError
from kimchi.template import render
@@ -80,6 +80,7 @@ class Partitions(Collection):
# sorted by their path
def _get_resources(self, flag_filter):
res_list = super(Partitions, self)._get_resources(flag_filter)
+ res_list = filter(lambda x: x.info['available'], res_list)
res_list.sort(key=lambda x: x.info['path'])
return res_list
@@ -90,6 +91,9 @@ class Partition(Resource):
@property
def data(self):
+ if not self.info['available']:
+ raise NotFoundError("KCHPART0001E", {'name': self.info['name']})
+
return self.info
diff --git a/src/kimchi/disks.py b/src/kimchi/disks.py
index 842fd48..a13c753 100644
--- a/src/kimchi/disks.py
+++ b/src/kimchi/disks.py
@@ -142,7 +142,23 @@ def _get_vgname(devNodePath):
return re.findall(r"LVM2_VG_NAME='([^\']*)'", out)[0]
-def get_partitions_names():
+def _is_available(name, devtype, fstype, mountpoint, majmin):
+ devNodePath = _get_dev_node_path(majmin)
+ # Only list unmounted and unformated and leaf and (partition or disk)
+ # leaf means a partition, a disk has no partition, or a disk not held
+ # by any multipath device. Physical volume belongs to no volume group
+ # is also listed. Extended partitions should not be listed.
+ if (devtype in ['part', 'disk', 'mpath'] and
+ fstype in ['', 'LVM2_member'] and
+ mountpoint == "" and
+ _get_vgname(devNodePath) == "" and
+ _is_dev_leaf(devNodePath) and
+ not _is_dev_extended_partition(devtype, devNodePath)):
+ return True
+ return False
+
+
+def get_partitions_names(check=False):
names = set()
keys = ["NAME", "TYPE", "FSTYPE", "MOUNTPOINT", "MAJ:MIN"]
# output is on format key="value",
@@ -151,26 +167,17 @@ def get_partitions_names():
# split()[0] to avoid the second part of the name, after the
# whiteline
name = dev['name'].split()[0]
- devNodePath = _get_dev_node_path(dev['maj:min'])
- # Only list unmounted and unformated and leaf and (partition or disk)
- # leaf means a partition, a disk has no partition, or a disk not held
- # by any multipath device. Physical volume belongs to no volume group
- # is also listed. Extended partitions should not be listed.
- if not (dev['type'] in ['part', 'disk', 'mpath'] and
- dev['fstype'] in ['', 'LVM2_member'] and
- dev['mountpoint'] == "" and
- _get_vgname(devNodePath) == "" and
- _is_dev_leaf(devNodePath) and
- not _is_dev_extended_partition(dev['type'], devNodePath)):
+ if check and not _is_available(name, dev['type'], dev['fstype'],
+ dev['mountpoint'], dev['maj:min']):
continue
-
names.add(name)
return list(names)
def get_partition_details(name):
- dev_path = _get_dev_node_path(_get_dev_major_min(name))
+ majmin = _get_dev_major_min(name)
+ dev_path = _get_dev_node_path(majmin)
keys = ["TYPE", "FSTYPE", "SIZE", "MOUNTPOINT"]
try:
@@ -180,6 +187,8 @@ def get_partition_details(name):
"Error getting partition info for %s: %s", name, e)
return {}
+ dev['available'] = _is_available(name, dev['type'], dev['fstype'],
+ dev['mountpoint'], majmin)
if dev['mountpoint']:
# Sometimes the mountpoint comes with [SWAP] or other
# info which is not an actual mount point. Filtering it
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py
index 47b0aa1..e9ac487 100644
--- a/src/kimchi/model/host.py
+++ b/src/kimchi/model/host.py
@@ -245,9 +245,6 @@ class PartitionModel(object):
pass
def lookup(self, name):
- if name not in disks.get_partitions_names():
- raise NotFoundError("KCHPART0001E", {'name': name})
-
return disks.get_partition_details(name)
--
1.9.0
3
5
[PATCH 1/3] probe that libvirt support to change a live VM network source
by shaohef@linux.vnet.ibm.com 09 May '14
by shaohef@linux.vnet.ibm.com 09 May '14
09 May '14
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
This is a good feature to user, but it is not supported by low version
libvirt.
So we need to probe it.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
src/kimchi/featuretests.py | 43 ++++++++++++++++++++++++++++++++++++++++++-
src/kimchi/model/config.py | 3 +++
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/src/kimchi/featuretests.py b/src/kimchi/featuretests.py
index 5192361..6eb29f4 100644
--- a/src/kimchi/featuretests.py
+++ b/src/kimchi/featuretests.py
@@ -62,8 +62,25 @@ SIMPLE_VM_XML = """
<type arch='x86_64' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
+ <devices>
+ %s
+ </devices>
</domain>"""
+SIMPLE_NETWORK_XML = """
+<network>
+ <name>%s</name>
+</network>
+"""
+
+VM_IFACE_XML = """
+<interface type='network'>
+ <mac address='52:54:00:12:34:56'/>
+ <source network='%s'/>
+ <model type='rtl8139'/>
+</interface>
+"""
+
SCSI_FC_XML = """
<pool type='scsi'>
<name>TEST_SCSI_FC_POOL</name>
@@ -196,7 +213,7 @@ class FeatureTests(object):
rollback.prependDefer(FeatureTests.enable_screen_error_logging)
conn = libvirt.open('qemu:///system')
rollback.prependDefer(conn.close)
- dom = conn.defineXML(SIMPLE_VM_XML)
+ dom = conn.defineXML(SIMPLE_VM_XML % "")
rollback.prependDefer(dom.undefine)
try:
dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT,
@@ -206,3 +223,27 @@ class FeatureTests(object):
return True
except libvirt.libvirtError:
return False
+
+ @staticmethod
+ def change_live_vm_network():
+ with RollbackContext() as rollback:
+ FeatureTests.disable_screen_error_logging()
+ rollback.prependDefer(FeatureTests.enable_screen_error_logging)
+ conn = libvirt.open('qemu:///system')
+ rollback.prependDefer(conn.close)
+ net1_name = "isolated_test_net1"
+ net2_name = "isolated_test_net2"
+ net1 = conn.networkCreateXML(SIMPLE_NETWORK_XML % net1_name)
+ rollback.prependDefer(net1.destroy)
+ net2 = conn.networkCreateXML(SIMPLE_NETWORK_XML % net2_name)
+ rollback.prependDefer(net2.destroy)
+ iface1_xml = VM_IFACE_XML % net1_name
+ iface2_xml = VM_IFACE_XML % net2_name
+ dom = conn.createXML(SIMPLE_VM_XML % iface1_xml, flags=0)
+ rollback.prependDefer(dom.destroy)
+ try:
+ dom.updateDeviceFlags(iface2_xml,
+ libvirt.VIR_DOMAIN_AFFECT_LIVE)
+ return True
+ except libvirt.libvirtError:
+ return False
diff --git a/src/kimchi/model/config.py b/src/kimchi/model/config.py
index 0ef0855..88ab681 100644
--- a/src/kimchi/model/config.py
+++ b/src/kimchi/model/config.py
@@ -54,6 +54,7 @@ class CapabilitiesModel(object):
self.libvirt_stream_protocols = []
self.fc_host_support = False
self.metadata_support = False
+ self.change_live_vm_network = False
# Subscribe function to set host capabilities to be run when cherrypy
# server is up
@@ -67,6 +68,8 @@ class CapabilitiesModel(object):
self.nfs_target_probe = FeatureTests.libvirt_support_nfs_probe()
self.fc_host_support = FeatureTests.libvirt_support_fc_host()
self.metadata_support = FeatureTests.has_metadata_support()
+ self.change_live_vm_network = FeatureTests.change_live_vm_network()
+
self.libvirt_stream_protocols = []
for p in ['http', 'https', 'ftp', 'ftps', 'tftp']:
--
1.9.0
2
3
From: Aline Manera <alinefm(a)br.ibm.com>
In proxy.py, the config_dir was only initialized in a 'if' statement and
used outside it.
So if the SSL certificate and key were received as parameters, config_dir
was undefined.
Fix it.
Signed-off-by: Aline Manera <alinefm(a)br.ibm.com>
---
src/kimchi/proxy.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/kimchi/proxy.py b/src/kimchi/proxy.py
index 7a12bfd..1ccbbcc 100644
--- a/src/kimchi/proxy.py
+++ b/src/kimchi/proxy.py
@@ -57,9 +57,9 @@ def _create_proxy_config(p_port, k_port, p_ssl_port, cert, key):
except KeyError:
user_proxy = 'www-data'
+ config_dir = paths.conf_dir
# No certificates specified by the user
if not cert or not key:
- config_dir = paths.conf_dir
cert = '%s/kimchi-cert.pem' % config_dir
key = '%s/kimchi-key.pem' % config_dir
# create cert files if they don't exist
--
1.7.10.4
3
3
09 May '14
It was "version" instead of "disk".
v2 -> v3:
3a) Corrected id string from CDROM
(Aline's comment)
v1 -> v2:
2a) Added for attribute for version text box
(Sheldon's comment)
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/pages/template-edit.html.tmpl | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index f00e4fc..15ff25c 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -73,20 +73,20 @@
</div>
<div>
<div class="template-edit-wrapper-label">
- <label>$_("Disk (GB)")</label>
+ <label for="template-edit-disk-textbox">$_("Disk (GB)")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-version-textbox" name="disks" type="text" />
+ <input id="template-edit-disk-textbox" name="disks" type="text" />
</div>
</div>
</fieldset>
<fieldset class="template-edit-fieldset">
<div>
<div class="template-edit-wrapper-label">
- <label>$_("CDROM")</label>
+ <label for="template-edit-cdrom-textbox">$_("CDROM")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-version-textbox" name="cdrom" type="text" disabled="disabled"/>
+ <input id="template-edit-cdrom-textbox" name="cdrom" type="text" disabled="disabled"/>
</div>
</div>
<div>
--
1.8.1.4
3
2
09 May '14
It was "version" instead of "disk".
v1 -> v2:
2a) Added for attribute for version text box
(Sheldon's comment)
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/pages/template-edit.html.tmpl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index f00e4fc..3ba8315 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -73,17 +73,17 @@
</div>
<div>
<div class="template-edit-wrapper-label">
- <label>$_("Disk (GB)")</label>
+ <label for="template-edit-disk-textbox">$_("Disk (GB)")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-version-textbox" name="disks" type="text" />
+ <input id="template-edit-disk-textbox" name="disks" type="text" />
</div>
</div>
</fieldset>
<fieldset class="template-edit-fieldset">
<div>
<div class="template-edit-wrapper-label">
- <label>$_("CDROM")</label>
+ <label for="template-edit-version-textbox">$_("CDROM")</label>
</div>
<div class="template-edit-wrapper-controls">
<input id="template-edit-version-textbox" name="cdrom" type="text" disabled="disabled"/>
--
1.8.1.4
2
2
Hi all,
I reverted the commit a67fe5426e1e86cbe589a2d48c0d404f50486ec2 because
it introduces a
issue into repositories grid for Ubuntu systems.
With this patch the repositories grid in Ubuntu system (deb
repositories) only displays
one column ("Enabled"). And without it, there is any difference in UI
for yum or deb repositories.
If someone thinks it is really needed, please send a new patch that
works for both systems.
Regards,
Aline Manera
1
0
Long text will wrap in template edit window. Fix it.
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/template-edit.css | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/ui/css/theme-default/template-edit.css b/ui/css/theme-default/template-edit.css
index c827048..ad95b31 100644
--- a/ui/css/theme-default/template-edit.css
+++ b/ui/css/theme-default/template-edit.css
@@ -17,7 +17,7 @@
*/
#template-edit-window {
font-size: 13px;
- height: 420px;
+ height: 600px;
width: 1000px;
}
@@ -27,19 +27,14 @@
}
.template-edit-wrapper-label, .template-edit-wrapper-controls {
- display: inline-block;
vertical-align: top;
+ width: 470px;
}
.template-edit-wrapper-label {
- width: 150px;
- height: 38px;
- line-height: 38px;
- margin-top: 5px;
-}
-
-.template-edit-wrapper-controls {
- width: 300px;
+ height: 18px;
+ line-height: 18px;
+ margin-top: 8px;
}
.template-edit-wrapper-controls input[type="text"] {
@@ -49,16 +44,19 @@
-webkit-border-radius: 5px;
border-radius: 5px;
box-shadow: 2px 2px 2px #eee inset;
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
border-top: 1px solid #bbb;
border-left: 1px solid #bbb;
padding: 0 10px;
margin-top: 5px;
- width: 250px;
+ width: 100%;
}
.template-edit-wrapper-controls > .dropdown {
margin: 5px 0 0 1px;
- width: 250px;
+ width: 440px;
}
.template-edit-wrapper-controls input[type="text"][disabled] {
@@ -72,7 +70,7 @@
}
.template-edit-wrapper-controls .select-list-box {
- width: 272px;
+ width: 464px;
max-height: 168px;
overflow: auto;
margin-top: 5px;
--
1.8.1.4
2
1
Tabs in tab bar was set to fixed width that will cut long text in
some languages. Fix it in this patch.
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/navbar.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/css/theme-default/navbar.css b/ui/css/theme-default/navbar.css
index 020fc59..4dc4841 100644
--- a/ui/css/theme-default/navbar.css
+++ b/ui/css/theme-default/navbar.css
@@ -34,7 +34,7 @@
.nav-menu .item {
display: block;
- width: 100px;
+ min-width: 100px;
height: 48px;
line-height: 48px;
padding: 0 10px;
--
1.8.1.4
2
1
08 May '14
From: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
As described in #368, the Hosts tab wasn't appearing after
relogging (due to restarting kimchid or even when the session
expires). The issue was in the getHostStats JSON, which was
marked with the 'resend' flag, preventing the Host tab from
reloading.
This behavior is set in the kimchi.login_window.js. This flag
isn't used for any other purpose, thus its removal does not
break the refresh of the System Statistics frame in the Hosts
tab. A description of the right usage of the 'resend' tag can
be found in the header of kimchi.api.js.
Signed-off-by: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.api.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index fe56eaf..7d85fdf 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -84,7 +84,6 @@ var kimchi = {
kimchi.requestJSON({
url : kimchi.url + 'host/stats',
type : 'GET',
- resend: true,
contentType : 'application/json',
headers: {'Kimchi-Robot': 'kimchi-robot'},
dataType : 'json',
--
1.8.3.1
2
2
[PATCH] host/partitions: avoid calling disks.get_partitions_names() for each partition
by Zhou Zheng Sheng 07 May '14
by Zhou Zheng Sheng 07 May '14
07 May '14
In PartitionModel.lookup(), it calls disks.get_partitions_names() to
verify the given partition is eligible to be used in a new logical
storage pool as follow.
if name not in disks.get_partitions_names():
raise NotFoundError(...)
When the front-end issues GET request to host/partitions, the back-end
would call get_partitions_names() for each partition. If there are many
disks and partitions in the host, get_partitions_names() takes a long
time to finish, and calling get_partitions_names() for each partition
would make the GET request timeout.
This patch is to do the following.
When the partition is listed from the URI host/partitions, we should
avoid calling get_partitions_names() for each of them.
When the partition is listed from the URI host/partitions/sdaX, we
should verify sdaX is among the eligible partitions.
The solution is that we make use of the resource_args in Partitions
collection class and override the _get_resources() method. In the
_get_resources() method, it sets resource_args to "[True]", indicating
that the listed partitions are already verified and eligible, so
PartitionModel.lookup() would skip the check. When we are outside of
_get_resources() method, resource_args is set to "[False]", and
PartitionModel.lookup() enables the check.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/control/host.py | 26 +++++++++++++++++++++-----
src/kimchi/model/host.py | 4 ++--
2 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py
index ad34919..11673d5 100644
--- a/src/kimchi/control/host.py
+++ b/src/kimchi/control/host.py
@@ -17,11 +17,14 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+import threading
+
import cherrypy
from kimchi.control.base import Collection, Resource, SimpleCollection
from kimchi.control.utils import UrlSubNode, validate_method
from kimchi.exception import OperationFailed
+from kimchi.rollbackcontext import RollbackContext
from kimchi.template import render
@@ -75,18 +78,31 @@ class Partitions(Collection):
def __init__(self, model):
super(Partitions, self).__init__(model)
self.resource = Partition
+ self._reset_resource_args()
+ self._resource_args_lock = threading.Lock()
+
+ def _reset_resource_args(self):
+ self.resource_args = [False]
- # Defining get_resources in order to return list of partitions in UI
- # sorted by their path
def _get_resources(self, flag_filter):
- res_list = super(Partitions, self)._get_resources(flag_filter)
- res_list.sort(key=lambda x: x.info['path'])
+ with RollbackContext() as rollback:
+ self._resource_args_lock.acquire()
+ rollback.prependDefer(self._resource_args_lock.release)
+
+ self.resource_args = [True]
+ rollback.prependDefer(self._reset_resource_args)
+
+ # Defining get_resources in order to return list of partitions in
+ # UI sorted by their path
+ res_list = super(Partitions, self)._get_resources(flag_filter)
+ res_list.sort(key=lambda x: x.info['path'])
return res_list
class Partition(Resource):
- def __init__(self, model, id):
+ def __init__(self, model, verified, id):
super(Partition, self).__init__(model, id)
+ self.model_args = [verified] + list(self.model_args)
@property
def data(self):
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py
index 47b0aa1..ebd6f79 100644
--- a/src/kimchi/model/host.py
+++ b/src/kimchi/model/host.py
@@ -244,8 +244,8 @@ class PartitionModel(object):
def __init__(self, **kargs):
pass
- def lookup(self, name):
- if name not in disks.get_partitions_names():
+ def lookup(self, verified, name):
+ if not verified and name not in disks.get_partitions_names():
raise NotFoundError("KCHPART0001E", {'name': name})
return disks.get_partition_details(name)
--
1.9.0
2
4
07 May '14
It was "version" instead of "disk".
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/pages/template-edit.html.tmpl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index f00e4fc..7a1a6a8 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -73,10 +73,10 @@
</div>
<div>
<div class="template-edit-wrapper-label">
- <label>$_("Disk (GB)")</label>
+ <label for="template-edit-disk-textbox">$_("Disk (GB)")</label>
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-version-textbox" name="disks" type="text" />
+ <input id="template-edit-disk-textbox" name="disks" type="text" />
</div>
</div>
</fieldset>
--
1.8.1.4
2
2
so vnc & spice will work in all environments.
Adam King (1):
Set IE edge mode for VNC/Spice web pages
ui/pages/spice.html.tmpl | 3 ++-
ui/pages/vnc_auto.html.tmpl | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
--
1.9.0
2
3
[PATCH 0/8 V2] Enable Kimchi authentication in console pages and spice bug fix
by Aline Manera 06 May '14
by Aline Manera 06 May '14
06 May '14
From: Aline Manera <alinefm(a)br.ibm.com>
V1 -> V2:
- Properly add the console.html to spec files
- Use the same mechanism to accept the CA for spice console
- Fix spice issue
-------------------------------------------------------------------------------
As I commented in mailing list ([v3] Enable encryption in vm VNC console connection)
to enable Kimchi authentication in console pages those need to be provided by
Kimchi server instead of websockify web server.
I reverted the "Enable encryption in vm VNC console connection" commit, applied
"[PATCH v2] Enable encryption in vm console connection" path send by Mark and
make the changes needed to redirect user from websockify web server to Kimchi.
So noVNC page continues to be rendered by Kimchi.
With all that done, I was able to enable authentication to vnc_auto.html and
spice.html
Aline Manera (7):
Revert "Enable encryption in vm VNC console connection"
Make use of the mini Web server in the websockify
Enable Kimchi authentication in console pages
backend: Redirect 401 error to default page
UI: Redirect user to console page after logging
websockets: Disallow non-encrypted client connections
bug fix: Properly set the listen IP to SPICE console
Mark Wu (1):
Enable encryption in vm console connection
configure.ac | 9 +-
contrib/kimchi.spec.fedora.in | 14 +-
contrib/kimchi.spec.suse.in | 14 +-
src/kimchi/config.py.in | 32 +-
src/kimchi/vnc.py | 3 +-
src/nginx.conf.in | 10 +
tests/test_config.py.in | 32 +-
ui/Makefile.am | 2 +-
ui/css/Makefile.am | 2 +-
ui/css/fonts/Makefile.am | 2 +
ui/css/fonts/novnc/Makefile.am | 20 +
ui/css/fonts/novnc/Orbitron700.ttf | Bin 0 -> 38580 bytes
ui/css/fonts/novnc/Orbitron700.woff | Bin 0 -> 17472 bytes
ui/css/novnc/Makefile.am | 20 +
ui/css/novnc/base.css | 405 ++++++
ui/js/Makefile.am | 2 +-
ui/js/novnc/Makefile.am | 22 +
ui/js/novnc/base64.js | 115 ++
ui/js/novnc/des.js | 273 ++++
ui/js/novnc/display.js | 770 +++++++++++
ui/js/novnc/input.js | 1946 +++++++++++++++++++++++++++
ui/js/novnc/jsunzip.js | 676 ++++++++++
ui/js/novnc/main.js | 103 ++
ui/js/novnc/rfb.js | 1866 +++++++++++++++++++++++++
ui/js/novnc/util.js | 381 ++++++
ui/js/novnc/web-socket-js/Makefile.am | 24 +
ui/js/novnc/web-socket-js/README.txt | 109 ++
ui/js/novnc/web-socket-js/WebSocketMain.swf | Bin 0 -> 177114 bytes
ui/js/novnc/web-socket-js/swfobject.js | 4 +
ui/js/novnc/web-socket-js/web_socket.js | 391 ++++++
ui/js/novnc/websock.js | 422 ++++++
ui/js/novnc/webutil.js | 216 +++
ui/js/src/kimchi.api.js | 20 +-
ui/js/src/kimchi.login_window.js | 19 +-
ui/novnc/Makefile.am | 22 -
ui/novnc/css/Makefile.am | 20 -
ui/novnc/css/Orbitron700.ttf | Bin 38580 -> 0 bytes
ui/novnc/css/Orbitron700.woff | Bin 17472 -> 0 bytes
ui/novnc/css/base.css | 405 ------
ui/novnc/js/Makefile.am | 22 -
ui/novnc/js/base64.js | 115 --
ui/novnc/js/des.js | 273 ----
ui/novnc/js/display.js | 770 -----------
ui/novnc/js/input.js | 1946 ---------------------------
ui/novnc/js/jsunzip.js | 676 ----------
ui/novnc/js/main.js | 103 --
ui/novnc/js/rfb.js | 1866 -------------------------
ui/novnc/js/util.js | 381 ------
ui/novnc/js/web-socket-js/Makefile.am | 24 -
ui/novnc/js/web-socket-js/README.txt | 109 --
ui/novnc/js/web-socket-js/WebSocketMain.swf | Bin 177114 -> 0 bytes
ui/novnc/js/web-socket-js/swfobject.js | 4 -
ui/novnc/js/web-socket-js/web_socket.js | 391 ------
ui/novnc/js/websock.js | 422 ------
ui/novnc/js/webutil.js | 216 ---
ui/novnc/vnc.html | 43 -
ui/pages/Makefile.am | 2 +-
ui/pages/spice.html.tmpl | 4 +-
ui/pages/vnc_auto.html.tmpl | 44 +
ui/pages/websockify/Makefile.am | 20 +
ui/pages/websockify/console.html | 25 +
61 files changed, 7958 insertions(+), 7869 deletions(-)
create mode 100644 ui/css/fonts/novnc/Makefile.am
create mode 100644 ui/css/fonts/novnc/Orbitron700.ttf
create mode 100644 ui/css/fonts/novnc/Orbitron700.woff
create mode 100644 ui/css/novnc/Makefile.am
create mode 100644 ui/css/novnc/base.css
create mode 100644 ui/js/novnc/Makefile.am
create mode 100644 ui/js/novnc/base64.js
create mode 100644 ui/js/novnc/des.js
create mode 100644 ui/js/novnc/display.js
create mode 100644 ui/js/novnc/input.js
create mode 100755 ui/js/novnc/jsunzip.js
create mode 100644 ui/js/novnc/main.js
create mode 100644 ui/js/novnc/rfb.js
create mode 100644 ui/js/novnc/util.js
create mode 100644 ui/js/novnc/web-socket-js/Makefile.am
create mode 100644 ui/js/novnc/web-socket-js/README.txt
create mode 100644 ui/js/novnc/web-socket-js/WebSocketMain.swf
create mode 100644 ui/js/novnc/web-socket-js/swfobject.js
create mode 100644 ui/js/novnc/web-socket-js/web_socket.js
create mode 100644 ui/js/novnc/websock.js
create mode 100644 ui/js/novnc/webutil.js
delete mode 100644 ui/novnc/Makefile.am
delete mode 100644 ui/novnc/css/Makefile.am
delete mode 100644 ui/novnc/css/Orbitron700.ttf
delete mode 100644 ui/novnc/css/Orbitron700.woff
delete mode 100644 ui/novnc/css/base.css
delete mode 100644 ui/novnc/js/Makefile.am
delete mode 100644 ui/novnc/js/base64.js
delete mode 100644 ui/novnc/js/des.js
delete mode 100644 ui/novnc/js/display.js
delete mode 100644 ui/novnc/js/input.js
delete mode 100755 ui/novnc/js/jsunzip.js
delete mode 100644 ui/novnc/js/main.js
delete mode 100644 ui/novnc/js/rfb.js
delete mode 100644 ui/novnc/js/util.js
delete mode 100644 ui/novnc/js/web-socket-js/Makefile.am
delete mode 100644 ui/novnc/js/web-socket-js/README.txt
delete mode 100644 ui/novnc/js/web-socket-js/WebSocketMain.swf
delete mode 100644 ui/novnc/js/web-socket-js/swfobject.js
delete mode 100644 ui/novnc/js/web-socket-js/web_socket.js
delete mode 100644 ui/novnc/js/websock.js
delete mode 100644 ui/novnc/js/webutil.js
delete mode 100644 ui/novnc/vnc.html
create mode 100644 ui/pages/vnc_auto.html.tmpl
create mode 100644 ui/pages/websockify/Makefile.am
create mode 100644 ui/pages/websockify/console.html
--
1.7.10.4
2
10
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
V2 -> V3
just support to change persistent network configure.
V1 -> V2
add test case for running VM
We allow user change the interface from one network to another network
when VM is alive.
But we only support change the vm configure no matter vm is alive or not.
ShaoHe Feng (4):
vmiface update support: update API.md
vmiface update support: update model.
vmiface update support: update mockmodel
vmiface update support: update test case
docs/API.md | 8 ++++++++
src/kimchi/API.json | 17 +++++++++++++++++
src/kimchi/control/vm/ifaces.py | 1 +
src/kimchi/i18n.py | 1 +
src/kimchi/mockmodel.py | 12 ++++++++++++
src/kimchi/model/vmifaces.py | 21 +++++++++++++++++++++
tests/test_model.py | 10 ++++++++++
tests/test_rest.py | 8 ++++++++
8 files changed, 78 insertions(+)
--
1.9.0
2
5
Hi all,
I'm working on host device passthrough. A a problem troubles me: I see
in current Kimchi code, when adding a specific SCSI or iSCSI LUN, it is
added to the template but not the VM. This is counter-intuitive, because
a template is to store the common information for lots of VMs, while a
specific LUN should only be used by just one VM. It's OK for DIR, NFS
and Logical storage pool being managed by the template, because actually
the template allocates a new specific volume for a new VM, so the
specific volume goes with the specific VM but not the template. Since we
don't define a specific DIR storage volume in the template, why we
define a concrete LUN in it?
The first problem in the current design is that we can not attach a new
LUN to a VM after the VM is created.
Another problem is that we mix the "things in common" and "things
special" in template, thus we make its responsibility complex. Static
and dynamic validations are also mixed in template.
The third problem is that if we get 10 LUNs for 10 VMs, the user has to
create 10 templates at first, then create 10 VMs from the 10 templates
respectively. It's a bit tedious.
The fourth problem is that if a LUN is used by a VM, usually it should
not be used by other VMs, so it implies that by specifying a LUN in a
template, the template should only create just one VM. What's the point
to make a template that only produces one VM?
It seems a cleaner way is putting SCSI LUN handling code in VM. Firstly,
we can assign a SCSI/iSCSI storage pool to the template. When it's time
to create a VM from the template, Kimchi lists all the available LUNs in
the storage pool and the user can just pick some LUNs. The VM override
parameters are suitable to store the LUNs information. It also makes
possible to implement some mechanisms to add/remove LUNs after a VM is
created, which is a very typical user requirement.
The same problem exists in host device passthrough. For a specific
device, it should be passthrough to a specific VM but not a template.
I'd like to collect some thoughts before my device passthrough patch V2.
In which place you'd suggest me to put device passthrough information,
template or VM?
Thanks for sharing your ideas!
--
Thanks and best regards!
Zhou Zheng Sheng / 周征晟
E-mail: zhshzhou(a)linux.vnet.ibm.com
Telephone: 86-10-82454397
3
6
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
v1>v3,
Adjust html format(Aline's comments)
Fix disk view display,
Fix align problem in select menu(hongliang's comments)
Fill default value in pool and volume box(hongliang's comments)
v3>v4,
Backend changed param from path to pool/vol,
UI change with backend.
handle option with no value.(hongliang's comments)
Royce Lv (3):
Fix select menu data append
UI: Support add guest disk
Display all disk types in storage edit view
ui/css/theme-default/guest-storage-add.css | 16 ++++
ui/js/src/kimchi.guest_edit_main.js | 5 +-
ui/js/src/kimchi.guest_storage_add.main.js | 137 ++++++++++++++++++++++++-----
ui/js/widgets/select-menu.js | 4 +-
ui/pages/guest-edit.html.tmpl | 17 +++-
ui/pages/guest-storage-add.html.tmpl | 62 +++++++++++--
6 files changed, 208 insertions(+), 33 deletions(-)
--
1.8.3.2
3
6
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
Note:
This patchset depends on
[PATCH V9 7/7] write the template OS info to vm metadata.
v3>v4,
Rebase on shaohe's new metadata patchset.
v1>v3,
Choose bus type according to os info in metadata.
When adding a disk, specify a pool and vol name,
so that kimchi can chek ref_cnt to make sure no others
using that volume,
also volume format is filled to driver so that qcow2 image
will not recognized as raw.
Tested:
1. when no bus is specified,
kimchi chose 'ide' for cdrom and 'virtio' for disk
2. when bus is specified,
kimchi attach disk with specified bus.
3. ide does not support hot plug.
4. Disk size for qcow2 and raw is right.
Royce Lv (7):
Guest disks: Update doc to support manage guest disks
Guest disks: Update api definition and error reporting
Guest disks: Choose proper bus for device
Guest disks: Abstract vm disk functions
Guest disk: deals with disk attachment
Multiple pep8 fixes
Guest disks: Update testcase
docs/API.md | 12 ++--
src/kimchi/API.json | 37 +++++++---
src/kimchi/i18n.py | 28 ++++----
src/kimchi/mockmodel.py | 18 ++---
src/kimchi/model/storagevolumes.py | 9 +--
src/kimchi/model/vmstorages.py | 138 ++++++++++++++++++-------------------
src/kimchi/vmdisks.py | 58 ++++++++++++++++
tests/test_model.py | 75 ++++++++++++++++++++
8 files changed, 265 insertions(+), 110 deletions(-)
create mode 100644 src/kimchi/vmdisks.py
--
1.8.3.2
2
10
As a follow-up from the discussion here:
http://lists.ovirt.org/pipermail/kimchi-devel/2014-April/004600.html
run_command needs to be updated to return some indication
to the caller that a command did not complete. Currently,
if there is an exception (e.g. the command does not exist),
None is returned for the output, the error output, and
the return code.
msg is already created, but only printed to the log/console,
so return that as the error message. Return -1 for the rc, which
could be, depending on the command passed, an ignorable error
code. Having some indication of a problem is better than None,
though.
Signed-off-by: Christy Perez <christy(a)linux.vnet.ibm.com>
---
src/kimchi/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py
index a30dcfe..97adbf8 100644
--- a/src/kimchi/utils.py
+++ b/src/kimchi/utils.py
@@ -199,7 +199,7 @@ def run_command(cmd, timeout=None):
if proc:
return out, error, proc.returncode
else:
- return None, None, None
+ return None, msg, -1
finally:
if timer and not timeout_flag[0]:
timer.cancel()
--
1.9.0
3
2
From: Aline Manera <alinefm(a)br.ibm.com>
As I commented in mailing list ([v3] Enable encryption in vm VNC console connection)
to enable Kimchi authentication in console pages those need to be provided by
Kimchi server instead of websockify web server.
I reverted the "Enable encryption in vm VNC console connection" commit, applied
"[PATCH v2] Enable encryption in vm console connection" path send by Mark and
make the changes needed to redirect user from websockify web server to Kimchi.
So noVNC page continues to be rendered by Kimchi.
With all that done, I was able to enable authentication to vnc_auto.html and
spice.html
Aline Manera (5):
Revert "Enable encryption in vm VNC console connection"
Make use of the mini Web server in the websockify
Enable Kimchi authentication in console pages
backend: Redirect 401 error to default page
UI: Redirect user to console page after logging
Mark Wu (1):
Enable encryption in vm console connection
configure.ac | 9 +-
contrib/kimchi.spec.fedora.in | 14 +-
contrib/kimchi.spec.suse.in | 14 +-
src/kimchi/config.py.in | 32 +-
src/kimchi/vnc.py | 2 +-
src/nginx.conf.in | 15 +
tests/test_config.py.in | 32 +-
ui/Makefile.am | 2 +-
ui/css/Makefile.am | 2 +-
ui/css/fonts/Makefile.am | 2 +
ui/css/fonts/novnc/Makefile.am | 20 +
ui/css/fonts/novnc/Orbitron700.ttf | Bin 0 -> 38580 bytes
ui/css/fonts/novnc/Orbitron700.woff | Bin 0 -> 17472 bytes
ui/css/novnc/Makefile.am | 20 +
ui/css/novnc/base.css | 405 ++++++
ui/js/Makefile.am | 2 +-
ui/js/novnc/Makefile.am | 22 +
ui/js/novnc/base64.js | 115 ++
ui/js/novnc/des.js | 273 ++++
ui/js/novnc/display.js | 770 +++++++++++
ui/js/novnc/input.js | 1946 +++++++++++++++++++++++++++
ui/js/novnc/jsunzip.js | 676 ++++++++++
ui/js/novnc/main.js | 103 ++
ui/js/novnc/rfb.js | 1866 +++++++++++++++++++++++++
ui/js/novnc/util.js | 381 ++++++
ui/js/novnc/web-socket-js/Makefile.am | 24 +
ui/js/novnc/web-socket-js/README.txt | 109 ++
ui/js/novnc/web-socket-js/WebSocketMain.swf | Bin 0 -> 177114 bytes
ui/js/novnc/web-socket-js/swfobject.js | 4 +
ui/js/novnc/web-socket-js/web_socket.js | 391 ++++++
ui/js/novnc/websock.js | 422 ++++++
ui/js/novnc/webutil.js | 216 +++
ui/js/src/kimchi.api.js | 7 +-
ui/js/src/kimchi.login_window.js | 24 +-
ui/novnc/Makefile.am | 22 -
ui/novnc/css/Makefile.am | 20 -
ui/novnc/css/Orbitron700.ttf | Bin 38580 -> 0 bytes
ui/novnc/css/Orbitron700.woff | Bin 17472 -> 0 bytes
ui/novnc/css/base.css | 405 ------
ui/novnc/js/Makefile.am | 22 -
ui/novnc/js/base64.js | 115 --
ui/novnc/js/des.js | 273 ----
ui/novnc/js/display.js | 770 -----------
ui/novnc/js/input.js | 1946 ---------------------------
ui/novnc/js/jsunzip.js | 676 ----------
ui/novnc/js/main.js | 103 --
ui/novnc/js/rfb.js | 1866 -------------------------
ui/novnc/js/util.js | 381 ------
ui/novnc/js/web-socket-js/Makefile.am | 24 -
ui/novnc/js/web-socket-js/README.txt | 109 --
ui/novnc/js/web-socket-js/WebSocketMain.swf | Bin 177114 -> 0 bytes
ui/novnc/js/web-socket-js/swfobject.js | 4 -
ui/novnc/js/web-socket-js/web_socket.js | 391 ------
ui/novnc/js/websock.js | 422 ------
ui/novnc/js/webutil.js | 216 ---
ui/novnc/vnc.html | 43 -
ui/pages/Makefile.am | 2 +-
ui/pages/novnc/Makefile.am | 20 +
ui/pages/novnc/vnc_auto.html | 22 +
ui/pages/vnc_auto.html.tmpl | 44 +
60 files changed, 7955 insertions(+), 7861 deletions(-)
create mode 100644 ui/css/fonts/novnc/Makefile.am
create mode 100644 ui/css/fonts/novnc/Orbitron700.ttf
create mode 100644 ui/css/fonts/novnc/Orbitron700.woff
create mode 100644 ui/css/novnc/Makefile.am
create mode 100644 ui/css/novnc/base.css
create mode 100644 ui/js/novnc/Makefile.am
create mode 100644 ui/js/novnc/base64.js
create mode 100644 ui/js/novnc/des.js
create mode 100644 ui/js/novnc/display.js
create mode 100644 ui/js/novnc/input.js
create mode 100755 ui/js/novnc/jsunzip.js
create mode 100644 ui/js/novnc/main.js
create mode 100644 ui/js/novnc/rfb.js
create mode 100644 ui/js/novnc/util.js
create mode 100644 ui/js/novnc/web-socket-js/Makefile.am
create mode 100644 ui/js/novnc/web-socket-js/README.txt
create mode 100644 ui/js/novnc/web-socket-js/WebSocketMain.swf
create mode 100644 ui/js/novnc/web-socket-js/swfobject.js
create mode 100644 ui/js/novnc/web-socket-js/web_socket.js
create mode 100644 ui/js/novnc/websock.js
create mode 100644 ui/js/novnc/webutil.js
delete mode 100644 ui/novnc/Makefile.am
delete mode 100644 ui/novnc/css/Makefile.am
delete mode 100644 ui/novnc/css/Orbitron700.ttf
delete mode 100644 ui/novnc/css/Orbitron700.woff
delete mode 100644 ui/novnc/css/base.css
delete mode 100644 ui/novnc/js/Makefile.am
delete mode 100644 ui/novnc/js/base64.js
delete mode 100644 ui/novnc/js/des.js
delete mode 100644 ui/novnc/js/display.js
delete mode 100644 ui/novnc/js/input.js
delete mode 100755 ui/novnc/js/jsunzip.js
delete mode 100644 ui/novnc/js/main.js
delete mode 100644 ui/novnc/js/rfb.js
delete mode 100644 ui/novnc/js/util.js
delete mode 100644 ui/novnc/js/web-socket-js/Makefile.am
delete mode 100644 ui/novnc/js/web-socket-js/README.txt
delete mode 100644 ui/novnc/js/web-socket-js/WebSocketMain.swf
delete mode 100644 ui/novnc/js/web-socket-js/swfobject.js
delete mode 100644 ui/novnc/js/web-socket-js/web_socket.js
delete mode 100644 ui/novnc/js/websock.js
delete mode 100644 ui/novnc/js/webutil.js
delete mode 100644 ui/novnc/vnc.html
create mode 100644 ui/pages/novnc/Makefile.am
create mode 100644 ui/pages/novnc/vnc_auto.html
create mode 100644 ui/pages/vnc_auto.html.tmpl
--
1.7.10.4
3
16
Keep storage tab and interface tab consistent in UI style.
Signed-off-by: Hongliang Wang <hlwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/guest-edit.css | 92 ++++++++++---------------------------
ui/js/src/kimchi.guest_edit_main.js | 23 ++++++++--
ui/pages/guest-edit.html.tmpl | 29 ++++++------
3 files changed, 57 insertions(+), 87 deletions(-)
diff --git a/ui/css/theme-default/guest-edit.css b/ui/css/theme-default/guest-edit.css
index 36f7f75..52c53eb 100644
--- a/ui/css/theme-default/guest-edit.css
+++ b/ui/css/theme-default/guest-edit.css
@@ -89,74 +89,7 @@
width: 400px;
}
-.guest-edit-cdrom-button {
- background: url("../images/theme-default/guest-icon-sprite.png") no-repeat left top transparent;
- border: none;
- height: 25px;
- vertical-align: middle;
- width: 25px;
-}
-
-.guest-edit-cdrom-button.attach {
- margin: 15px 0 0 521px;
-}
-
-.guest-edit-cdrom-button.attach:hover {
- background-position: 0 -27px;
-}
-
-.guest-edit-cdrom-button.attach:focus {
- background-position: 0 -54px;
-}
-
-.guest-edit-cdrom-button.attach:active {
- background-position: 0 -81px;
-}
-
-.guest-edit-cdrom-button.attach[disabled] {
- background-position: 0 -108px;
-}
-
-.guest-edit-cdrom-button.replace {
- background-position: -27px 0;
-}
-
-.guest-edit-cdrom-button.replace:hover {
- background-position: -27px -27px;
-}
-
-.guest-edit-cdrom-button.replace:focus {
- background-position: -27px -54px;
-}
-
-.guest-edit-cdrom-button.replace:active {
- background-position: -27px -81px;
-}
-
-.guest-edit-cdrom-button.replace[disabled] {
- background-position: -27px -108px;
-}
-
-.guest-edit-cdrom-button.detach {
- background-position: -54px 0;
-}
-
-.guest-edit-cdrom-button.detach:hover {
- background-position: -54px -27px;
-}
-
-.guest-edit-cdrom-button.detach:focus {
- background-position: -54px -54px;
-}
-
-.guest-edit-cdrom-button.detach:active {
- background-position: -54px -81px;
-}
-
-.guest-edit-cdrom-button.detach[disabled] {
- background-position: -54px -108px;
-}
-
+#form-guest-edit-storage .header,
.guest-edit-interface .header {
margin-bottom: 8px;
padding-bottom: 2px;
@@ -165,33 +98,56 @@
overflow: hidden;
}
+#form-guest-edit-storage .body .item,
.guest-edit-interface .body .item {
margin: 5px 0;
}
+#form-guest-edit-storage .cell,
.guest-edit-interface .cell {
display: inline-block;
width: 250px;
}
+#form-guest-edit-storage .cell.dev {
+ width: 60px;
+}
+
+#form-guest-edit-storage .cell.path {
+ width: 440px;
+}
+
+#form-guest-edit-storage .cell.path input {
+ box-sizing: border-box;
+ width: 100%;
+}
+
.guest-edit-interface .body select {
width: 180px;
padding: 0px;
}
+#form-guest-edit-storage .action-area,
.guest-edit-interface .action-area {
float: right;
}
+#form-guest-edit-storage .action-area {
+ line-height: 24px;
+}
+
+#form-guest-edit-storage button,
.guest-edit-interface button {
width: 20px;
height: 20px;
}
+#form-guest-edit-storage .header button,
.guest-edit-interface .header button {
margin-bottom: 1px;
}
+#form-guest-edit-storage .body button:not(:last-child),
.guest-edit-interface .body button:not(:last-child) {
margin-right: 2px;
}
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 2ba6b79..6b27c78 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -38,7 +38,7 @@ kimchi.guest_edit_main = function() {
storageType: 'cdrom'
}, function(storages) {
var rowHTML = $('#cdrom-row-tmpl').html();
- var container = $('#guest-edit-cdrom-row-container');
+ var container = $('#form-guest-edit-storage .body');
$(container).empty();
$.each(storages, function(index, storage) {
@@ -54,9 +54,19 @@ kimchi.guest_edit_main = function() {
};
$('input[type="text"][name="cdrom"]', container).on('click', replaceCDROM);
- $('.replace', container).on('click', replaceCDROM);
+ $('.replace', container).button({
+ icons: {
+ primary: 'ui-icon-pencil'
+ },
+ text: false
+ }).click(replaceCDROM);
- $('.detach', container).on('click', function(e) {
+ $('.detach', container).button({
+ icons: {
+ primary: 'ui-icon-trash'
+ },
+ text: false
+ }).click(function(e) {
e.preventDefault();
var settings = {
title : i18n['KCHAPI6004M'],
@@ -173,7 +183,12 @@ kimchi.guest_edit_main = function() {
refreshCDROMs();
- $('#guest-edit-attach-cdrom-button').on('click', function(event) {
+ $('#guest-edit-attach-cdrom-button').button({
+ icons: {
+ primary: "ui-icon-plusthick"
+ },
+ text: false
+ }).click(function(event) {
event.preventDefault();
kimchi.window.open("guest-storage-add.html");
});
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 552b4c8..71164d4 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -94,15 +94,12 @@
</fieldset>
</form>
<form id="form-guest-edit-storage">
- <fieldset class="guest-edit-fieldset">
- <div id="guest-edit-cdrom-row-container" class="guest-edit-cdrom-row-container"></div>
- <div>
- <button id="guest-edit-attach-cdrom-button"
- class="guest-edit-cdrom-button attach"
- title='$_("Attach")'>
- </button>
- </div>
- </fieldset>
+ <div class="header">
+ <span class="cell">$_("Device")</span>
+ <span class="cell">$_("Path")</span>
+ <button id="guest-edit-attach-cdrom-button"class="add action-area"></button>
+ </div>
+ <div class="body"></div>
</form>
<form id="form-guest-edit-interface" class="guest-edit-interface">
<div class="header">
@@ -123,14 +120,16 @@
</footer>
</div>
<script id="cdrom-row-tmpl" type="text/html">
- <div>
- <div class="guest-edit-wrapper-label">
+ <div class="item" id="cdrom-{dev}">
+ <span class="cell dev">
<label for="cdrom-{dev}">{dev}</label>
- </div>
- <div class="guest-edit-wrapper-controls">
+ </span>
+ <span class="cell path">
<input id="cdrom-{dev}" name="cdrom" type="text"
data-vm="{vm}" data-dev="{dev}"
value="{path}" readonly="readonly" />
+ </span>
+ <span class="action-area">
<button class="guest-edit-cdrom-button replace"
data-vm="{vm}" data-dev="{dev}"
title='$_("Replace")'>
@@ -139,8 +138,8 @@
data-vm="{vm}" data-dev="{dev}"
title='$_("Detach")'>
</button>
- </div>
- </div>
+ </span>
+ <div>
</script>
<script id="interface-tmpl" type="text/html">
<div class="item" id="{mac}">
--
1.8.1.4
1
0
From: Mark Wu <wudxw(a)linux.vnet.ibm.com>
The current vm VNC console connection is unencrypted. This patch enables
encrypted vm VNC console connection. But browsers doesn't
support well for the usage self-signed certs in the ssl websocket
connection. For details, please see:
https://github.com/kanaka/websockify/wiki/Encrypted-Connections
For chrome browser, the encrypted console connection should work after
you login with ssl connection. But for firefox, it does not show a
confirmation page for the user the accept the self-signed cert when
the HTTPs connection is started from a websocket.
So this patch makes use of the Web server in the websockify. The mini
Web server in the websockify can serve static contents like html, css
and js. This patch moves all novnc related html, css, font and js files
to ui/novnc, and have the websockify serve those files. When the user
clicks the VNC icon, Kimchi brings the user to
https://host:64667/vnc.html, which is served by websockify. Then
firefox would prompt a confirmation page for the self-signed cert. After
the user accept the cert, HTTPs connection started from the websocket
would succeed.
v3:
Make use of the mini Web server in the websockify.
Signed-off-by: Mark Wu <wudxw(a)linux.vnet.ibm.com>
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
configure.ac | 8 ++++----
contrib/kimchi.spec.fedora.in | 13 +++++++------
contrib/kimchi.spec.suse.in | 13 +++++++------
src/kimchi/vnc.py | 11 +++++++++--
ui/Makefile.am | 2 +-
ui/css/Makefile.am | 2 +-
ui/css/fonts/Makefile.am | 2 --
ui/js/Makefile.am | 2 +-
ui/js/src/kimchi.api.js | 7 ++++---
ui/{css => }/novnc/Makefile.am | 8 +++++---
ui/{css/fonts/novnc => novnc/css}/Makefile.am | 4 ++--
ui/{css/fonts/novnc => novnc/css}/Orbitron700.ttf | Bin
ui/{css/fonts/novnc => novnc/css}/Orbitron700.woff | Bin
ui/{css/novnc => novnc/css}/base.css | 0
ui/{js/novnc => novnc/js}/Makefile.am | 2 +-
ui/{js/novnc => novnc/js}/base64.js | 0
ui/{js/novnc => novnc/js}/des.js | 0
ui/{js/novnc => novnc/js}/display.js | 0
ui/{js/novnc => novnc/js}/input.js | 0
ui/{js/novnc => novnc/js}/jsunzip.js | 0
ui/{js/novnc => novnc/js}/main.js | 0
ui/{js/novnc => novnc/js}/rfb.js | 0
ui/{js/novnc => novnc/js}/util.js | 0
ui/{js/novnc => novnc/js}/web-socket-js/Makefile.am | 2 +-
ui/{js/novnc => novnc/js}/web-socket-js/README.txt | 0
ui/{js/novnc => novnc/js}/web-socket-js/WebSocketMain.swf | Bin
ui/{js/novnc => novnc/js}/web-socket-js/swfobject.js | 0
ui/{js/novnc => novnc/js}/web-socket-js/web_socket.js | 0
ui/{js/novnc => novnc/js}/websock.js | 0
ui/{js/novnc => novnc/js}/webutil.js | 0
ui/{pages/vnc_auto.html.tmpl => novnc/vnc.html} | 9 ++++-----
31 files changed, 47 insertions(+), 38 deletions(-)
rename ui/{css => }/novnc/Makefile.am (82%)
rename ui/{css/fonts/novnc => novnc/css}/Makefile.am (88%)
rename ui/{css/fonts/novnc => novnc/css}/Orbitron700.ttf (100%)
rename ui/{css/fonts/novnc => novnc/css}/Orbitron700.woff (100%)
rename ui/{css/novnc => novnc/css}/base.css (100%)
rename ui/{js/novnc => novnc/js}/Makefile.am (94%)
rename ui/{js/novnc => novnc/js}/base64.js (100%)
rename ui/{js/novnc => novnc/js}/des.js (100%)
rename ui/{js/novnc => novnc/js}/display.js (100%)
rename ui/{js/novnc => novnc/js}/input.js (100%)
rename ui/{js/novnc => novnc/js}/jsunzip.js (100%)
rename ui/{js/novnc => novnc/js}/main.js (100%)
rename ui/{js/novnc => novnc/js}/rfb.js (100%)
rename ui/{js/novnc => novnc/js}/util.js (100%)
rename ui/{js/novnc => novnc/js}/web-socket-js/Makefile.am (91%)
rename ui/{js/novnc => novnc/js}/web-socket-js/README.txt (100%)
rename ui/{js/novnc => novnc/js}/web-socket-js/WebSocketMain.swf (100%)
rename ui/{js/novnc => novnc/js}/web-socket-js/swfobject.js (100%)
rename ui/{js/novnc => novnc/js}/web-socket-js/web_socket.js (100%)
rename ui/{js/novnc => novnc/js}/websock.js (100%)
rename ui/{js/novnc => novnc/js}/webutil.js (100%)
rename ui/{pages/vnc_auto.html.tmpl => novnc/vnc.html} (83%)
diff --git a/configure.ac b/configure.ac
index 7d76f97..bc3f93e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,19 +66,19 @@ AC_CONFIG_FILES([
plugins/sample/ui/config/Makefile
ui/Makefile
ui/css/Makefile
- ui/css/novnc/Makefile
ui/css/fonts/Makefile
- ui/css/fonts/novnc/Makefile
ui/images/Makefile
ui/images/theme-default/Makefile
ui/js/Makefile
- ui/js/novnc/Makefile
ui/js/spice/Makefile
- ui/js/novnc/web-socket-js/Makefile
ui/libs/Makefile
ui/libs/themes/Makefile
ui/libs/themes/base/Makefile
ui/libs/themes/base/images/Makefile
+ ui/novnc/Makefile
+ ui/novnc/css/Makefile
+ ui/novnc/js/Makefile
+ ui/novnc/js/web-socket-js/Makefile
ui/pages/Makefile
ui/pages/help/Makefile
ui/pages/help/en_US/Makefile
diff --git a/contrib/kimchi.spec.fedora.in b/contrib/kimchi.spec.fedora.in
index 104c114..dd2fba7 100644
--- a/contrib/kimchi.spec.fedora.in
+++ b/contrib/kimchi.spec.fedora.in
@@ -154,8 +154,6 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/mo/*/LC_MESSAGES/kimchi.mo
%{_datadir}/kimchi/config/ui/*.xml
%{_datadir}/kimchi/ui/css/fonts/fontawesome-webfont.*
-%{_datadir}/kimchi/ui/css/fonts/novnc/Orbitron700.*
-%{_datadir}/kimchi/ui/css/novnc/base.css
%{_datadir}/kimchi/ui/css/theme-default.min.css
%{_datadir}/kimchi/ui/images/*.png
%{_datadir}/kimchi/ui/images/*.ico
@@ -165,11 +163,7 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/ui/js/jquery-ui.js
%{_datadir}/kimchi/ui/js/jquery.min.js
%{_datadir}/kimchi/ui/js/modernizr.custom.2.6.2.min.js
-%{_datadir}/kimchi/ui/js/novnc/*.js
%{_datadir}/kimchi/ui/js/spice/*.js
-%{_datadir}/kimchi/ui/js/novnc/web-socket-js/WebSocketMain.swf
-%{_datadir}/kimchi/ui/js/novnc/web-socket-js/swfobject.js
-%{_datadir}/kimchi/ui/js/novnc/web-socket-js/web_socket.js
%{_datadir}/kimchi/ui/libs/jquery-ui-i18n.min.js
%{_datadir}/kimchi/ui/libs/jquery-ui.min.js
%{_datadir}/kimchi/ui/libs/jquery-1.10.0.min.js
@@ -177,6 +171,13 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/ui/libs/themes/base/images/*.png
%{_datadir}/kimchi/ui/libs/themes/base/images/*.gif
%{_datadir}/kimchi/ui/libs/themes/base/jquery-ui.min.css
+%{_datadir}/kimchi/ui/novnc/css/Orbitron700.*
+%{_datadir}/kimchi/ui/novnc/css/base.css
+%{_datadir}/kimchi/ui/novnc/js/*.js
+%{_datadir}/kimchi/ui/novnc/js/web-socket-js/WebSocketMain.swf
+%{_datadir}/kimchi/ui/novnc/js/web-socket-js/swfobject.js
+%{_datadir}/kimchi/ui/novnc/js/web-socket-js/web_socket.js
+%{_datadir}/kimchi/ui/novnc/vnc.html
%{_datadir}/kimchi/ui/pages/*.html.tmpl
%{_datadir}/kimchi/ui/pages/help/*/*.html
%{_datadir}/kimchi/ui/pages/tabs/*.html.tmpl
diff --git a/contrib/kimchi.spec.suse.in b/contrib/kimchi.spec.suse.in
index 7704822..73c59a0 100644
--- a/contrib/kimchi.spec.suse.in
+++ b/contrib/kimchi.spec.suse.in
@@ -76,8 +76,6 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/mo/*/LC_MESSAGES/kimchi.mo
%{_datadir}/kimchi/config/ui/*.xml
%{_datadir}/kimchi/ui/css/fonts/fontawesome-webfont.*
-%{_datadir}/kimchi/ui/css/fonts/novnc/Orbitron700.*
-%{_datadir}/kimchi/ui/css/novnc/base.css
%{_datadir}/kimchi/ui/css/theme-default.min.css
%{_datadir}/kimchi/ui/images/*.png
%{_datadir}/kimchi/ui/images/*.ico
@@ -87,11 +85,7 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/ui/js/jquery-ui.js
%{_datadir}/kimchi/ui/js/jquery.min.js
%{_datadir}/kimchi/ui/js/modernizr.custom.2.6.2.min.js
-%{_datadir}/kimchi/ui/js/novnc/*.js
%{_datadir}/kimchi/ui/js/spice/*.js
-%{_datadir}/kimchi/ui/js/novnc/web-socket-js/WebSocketMain.swf
-%{_datadir}/kimchi/ui/js/novnc/web-socket-js/swfobject.js
-%{_datadir}/kimchi/ui/js/novnc/web-socket-js/web_socket.js
%{_datadir}/kimchi/ui/libs/jquery-ui-i18n.min.js
%{_datadir}/kimchi/ui/libs/jquery-ui.min.js
%{_datadir}/kimchi/ui/libs/jquery-1.10.0.min.js
@@ -99,6 +93,13 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/ui/libs/themes/base/images/*.png
%{_datadir}/kimchi/ui/libs/themes/base/images/*.gif
%{_datadir}/kimchi/ui/libs/themes/base/jquery-ui.min.css
+%{_datadir}/kimchi/ui/novnc/css/Orbitron700.*
+%{_datadir}/kimchi/ui/novnc/css/base.css
+%{_datadir}/kimchi/ui/novnc/js/*.js
+%{_datadir}/kimchi/ui/novnc/js/web-socket-js/WebSocketMain.swf
+%{_datadir}/kimchi/ui/novnc/js/web-socket-js/swfobject.js
+%{_datadir}/kimchi/ui/novnc/js/web-socket-js/web_socket.js
+%{_datadir}/kimchi/ui/novnc/vnc.html
%{_datadir}/kimchi/ui/pages/*.html.tmpl
%{_datadir}/kimchi/ui/pages/help/*/*.html
%{_datadir}/kimchi/ui/pages/tabs/*.html.tmpl
diff --git a/src/kimchi/vnc.py b/src/kimchi/vnc.py
index 1f36e9a..61f9c15 100644
--- a/src/kimchi/vnc.py
+++ b/src/kimchi/vnc.py
@@ -23,7 +23,7 @@ import os
import subprocess
-from kimchi.config import config
+from kimchi.config import config, paths
WS_TOKENS_DIR = '/var/lib/kimchi/vnc-tokens'
@@ -36,9 +36,16 @@ def new_ws_proxy():
if e.errno == errno.EEXIST:
pass
+ cert = config.get('server', 'ssl_cert')
+ key = config.get('server', 'ssl_key')
+ if not (cert and key):
+ cert = '%s/kimchi-cert.pem' % paths.conf_dir
+ key = '%s/kimchi-key.pem' % paths.conf_dir
+
cmd = os.path.join(os.path.dirname(__file__), 'websockify.py')
args = ['python', cmd, config.get('display', 'display_proxy_port'),
- '--target-config', WS_TOKENS_DIR]
+ '--target-config', WS_TOKENS_DIR, '--cert', cert, '--key', key,
+ '--web', os.path.join(paths.ui_dir, 'novnc')]
p = subprocess.Popen(args, close_fds=True)
return p
diff --git a/ui/Makefile.am b/ui/Makefile.am
index b5366c5..4e0d57a 100644
--- a/ui/Makefile.am
+++ b/ui/Makefile.am
@@ -15,4 +15,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-SUBDIRS = css images js libs pages
+SUBDIRS = css images js libs pages novnc
diff --git a/ui/css/Makefile.am b/ui/css/Makefile.am
index db65799..0922a9d 100644
--- a/ui/css/Makefile.am
+++ b/ui/css/Makefile.am
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-SUBDIRS = novnc fonts
+SUBDIRS = fonts
EXTRA_DIST = theme-default
diff --git a/ui/css/fonts/Makefile.am b/ui/css/fonts/Makefile.am
index 63df038..d72bb6c 100644
--- a/ui/css/fonts/Makefile.am
+++ b/ui/css/fonts/Makefile.am
@@ -15,8 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-SUBDIRS = novnc
-
fontdir = $(datadir)/kimchi/ui/css/fonts
dist_font_DATA = fontawesome-webfont.*
diff --git a/ui/js/Makefile.am b/ui/js/Makefile.am
index f4d1e6b..a29c262 100644
--- a/ui/js/Makefile.am
+++ b/ui/js/Makefile.am
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-SUBDIRS = novnc spice
+SUBDIRS = spice
EXTRA_DIST = src widgets
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 1bde45c..c8c422d 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -318,7 +318,6 @@ var kimchi = {
type : 'GET',
dataType : 'json'
}).done(function(data, textStatus, xhr) {
- http_port = data['http_port'];
proxy_port = data['display_proxy_port'];
kimchi.requestJSON({
url : "/vms/" + encodeURIComponent(vm) + "/connect",
@@ -329,9 +328,10 @@ var kimchi = {
* Due to problems with web sockets and self-signed
* certificates, for now we will always redirect to http
*/
- url = 'http://' + location.hostname + ':' + http_port;
- url += "/vnc_auto.html?port=" + proxy_port;
+ url = 'https://' + location.hostname + ':' + proxy_port;
+ url += "/vnc.html?port=" + proxy_port;
url += "&path=?token=" + encodeURIComponent(vm);
+ url += '&encrypt=1'
window.open(url);
});
}).error(function() {
@@ -355,6 +355,7 @@ var kimchi = {
url = 'http://' + location.hostname + ':' + http_port;
url += "/spice.html?port=" + proxy_port + "&listen="
+ data.graphics.listen + "&token=" + encodeURIComponent(vm);
+ url += '&encrypt=1'
window.open(url);
});
}).error(function() {
diff --git a/ui/css/novnc/Makefile.am b/ui/novnc/Makefile.am
similarity index 82%
rename from ui/css/novnc/Makefile.am
rename to ui/novnc/Makefile.am
index 29703d6..d0aca93 100644
--- a/ui/css/novnc/Makefile.am
+++ b/ui/novnc/Makefile.am
@@ -1,7 +1,7 @@
#
# Kimchi
#
-# Copyright IBM, Corp. 2013
+# Copyright IBM, Corp. 2014
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-cssdir = $(datadir)/kimchi/ui/css/novnc
+SUBDIRS = css js
-dist_css_DATA = base.css
+htmldir = $(datadir)/kimchi/ui/novnc
+
+dist_html_DATA = vnc.html $(NULL)
diff --git a/ui/css/fonts/novnc/Makefile.am b/ui/novnc/css/Makefile.am
similarity index 88%
rename from ui/css/fonts/novnc/Makefile.am
rename to ui/novnc/css/Makefile.am
index 50f6050..23d178f 100644
--- a/ui/css/fonts/novnc/Makefile.am
+++ b/ui/novnc/css/Makefile.am
@@ -15,6 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-fontdir = $(datadir)/kimchi/ui/css/fonts/novnc
+cssdir = $(datadir)/kimchi/ui/novnc/css
-dist_font_DATA = Orbitron700.*
+dist_css_DATA = base.css Orbitron700.*
diff --git a/ui/css/fonts/novnc/Orbitron700.ttf b/ui/novnc/css/Orbitron700.ttf
similarity index 100%
rename from ui/css/fonts/novnc/Orbitron700.ttf
rename to ui/novnc/css/Orbitron700.ttf
diff --git a/ui/css/fonts/novnc/Orbitron700.woff b/ui/novnc/css/Orbitron700.woff
similarity index 100%
rename from ui/css/fonts/novnc/Orbitron700.woff
rename to ui/novnc/css/Orbitron700.woff
diff --git a/ui/css/novnc/base.css b/ui/novnc/css/base.css
similarity index 100%
rename from ui/css/novnc/base.css
rename to ui/novnc/css/base.css
diff --git a/ui/js/novnc/Makefile.am b/ui/novnc/js/Makefile.am
similarity index 94%
rename from ui/js/novnc/Makefile.am
rename to ui/novnc/js/Makefile.am
index fefe6af..0c22fed 100644
--- a/ui/js/novnc/Makefile.am
+++ b/ui/novnc/js/Makefile.am
@@ -17,6 +17,6 @@
SUBDIRS = web-socket-js
-jsdir = $(datadir)/kimchi/ui/js/novnc
+jsdir = $(datadir)/kimchi/ui/novnc/js
dist_js_DATA = $(wildcard *.js) $(NULL)
diff --git a/ui/js/novnc/base64.js b/ui/novnc/js/base64.js
similarity index 100%
rename from ui/js/novnc/base64.js
rename to ui/novnc/js/base64.js
diff --git a/ui/js/novnc/des.js b/ui/novnc/js/des.js
similarity index 100%
rename from ui/js/novnc/des.js
rename to ui/novnc/js/des.js
diff --git a/ui/js/novnc/display.js b/ui/novnc/js/display.js
similarity index 100%
rename from ui/js/novnc/display.js
rename to ui/novnc/js/display.js
diff --git a/ui/js/novnc/input.js b/ui/novnc/js/input.js
similarity index 100%
rename from ui/js/novnc/input.js
rename to ui/novnc/js/input.js
diff --git a/ui/js/novnc/jsunzip.js b/ui/novnc/js/jsunzip.js
similarity index 100%
rename from ui/js/novnc/jsunzip.js
rename to ui/novnc/js/jsunzip.js
diff --git a/ui/js/novnc/main.js b/ui/novnc/js/main.js
similarity index 100%
rename from ui/js/novnc/main.js
rename to ui/novnc/js/main.js
diff --git a/ui/js/novnc/rfb.js b/ui/novnc/js/rfb.js
similarity index 100%
rename from ui/js/novnc/rfb.js
rename to ui/novnc/js/rfb.js
diff --git a/ui/js/novnc/util.js b/ui/novnc/js/util.js
similarity index 100%
rename from ui/js/novnc/util.js
rename to ui/novnc/js/util.js
diff --git a/ui/js/novnc/web-socket-js/Makefile.am b/ui/novnc/js/web-socket-js/Makefile.am
similarity index 91%
rename from ui/js/novnc/web-socket-js/Makefile.am
rename to ui/novnc/js/web-socket-js/Makefile.am
index 7d685f5..26ba1c0 100644
--- a/ui/js/novnc/web-socket-js/Makefile.am
+++ b/ui/novnc/js/web-socket-js/Makefile.am
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-websocketdir = $(datadir)/kimchi/ui/js/novnc/web-socket-js
+websocketdir = $(datadir)/kimchi/ui/novnc/js/web-socket-js
dist_websocket_DATA = \
swfobject.js \
diff --git a/ui/js/novnc/web-socket-js/README.txt b/ui/novnc/js/web-socket-js/README.txt
similarity index 100%
rename from ui/js/novnc/web-socket-js/README.txt
rename to ui/novnc/js/web-socket-js/README.txt
diff --git a/ui/js/novnc/web-socket-js/WebSocketMain.swf b/ui/novnc/js/web-socket-js/WebSocketMain.swf
similarity index 100%
rename from ui/js/novnc/web-socket-js/WebSocketMain.swf
rename to ui/novnc/js/web-socket-js/WebSocketMain.swf
diff --git a/ui/js/novnc/web-socket-js/swfobject.js b/ui/novnc/js/web-socket-js/swfobject.js
similarity index 100%
rename from ui/js/novnc/web-socket-js/swfobject.js
rename to ui/novnc/js/web-socket-js/swfobject.js
diff --git a/ui/js/novnc/web-socket-js/web_socket.js b/ui/novnc/js/web-socket-js/web_socket.js
similarity index 100%
rename from ui/js/novnc/web-socket-js/web_socket.js
rename to ui/novnc/js/web-socket-js/web_socket.js
diff --git a/ui/js/novnc/websock.js b/ui/novnc/js/websock.js
similarity index 100%
rename from ui/js/novnc/websock.js
rename to ui/novnc/js/websock.js
diff --git a/ui/js/novnc/webutil.js b/ui/novnc/js/webutil.js
similarity index 100%
rename from ui/js/novnc/webutil.js
rename to ui/novnc/js/webutil.js
diff --git a/ui/pages/vnc_auto.html.tmpl b/ui/novnc/vnc.html
similarity index 83%
rename from ui/pages/vnc_auto.html.tmpl
rename to ui/novnc/vnc.html
index 0078190..1f4355c 100644
--- a/ui/pages/vnc_auto.html.tmpl
+++ b/ui/novnc/vnc.html
@@ -1,4 +1,3 @@
-#from kimchi.cachebust import href
<!DOCTYPE html>
<html>
<!--
@@ -13,15 +12,15 @@
<head>
<title>noVNC</title>
<meta http-equiv="X-UA-Compatible" content="chrome=1">
- <link rel="stylesheet" href="$href("/css/novnc/base.css")" title="plain">
+ <link rel="stylesheet" href="css/base.css" title="plain">
<script type='text/javascript'>
- var INCLUDE_URI = "/js/novnc/";
+ var INCLUDE_URI = "js/";
</script>
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
- <script src="$href("/js/novnc/util.js")"></script>
+ <script src="js/util.js"></script>
</head>
<body style="margin: 0px;">
@@ -39,6 +38,6 @@
Canvas not supported.
</canvas>
</div>
- <script src="$href("/js/novnc/main.js")"></script>
+ <script src="js/main.js"></script>
</body>
</html>
--
1.9.0
3
4
02 May '14
From: Aline Manera <alinefm(a)br.ibm.com>
This reverts commit 06238f292aaf236c456dcc50d0aea1efcbb05584.
This patch was exposing all the noVNC files and let websockify web server
render the noVNC page.
The websockify web server is limited and only renders content in a directory.
So if someone has the URL
https://host-ip:64667/vnc.html?port=64667&path=?token=my-vm&encrypt=1
he/she can access the VM console without Kimchi authentication.
The idea is let Kimchi render the noVNC page and also add authentication
to it.
Signed-off-by: Aline Manera <alinefm(a)br.ibm.com>
---
configure.ac | 8 +-
contrib/kimchi.spec.fedora.in | 13 +-
contrib/kimchi.spec.suse.in | 13 +-
src/kimchi/vnc.py | 11 +-
ui/Makefile.am | 2 +-
ui/css/Makefile.am | 2 +-
ui/css/fonts/Makefile.am | 2 +
ui/css/fonts/novnc/Makefile.am | 20 +
ui/css/fonts/novnc/Orbitron700.ttf | Bin 0 -> 38580 bytes
ui/css/fonts/novnc/Orbitron700.woff | Bin 0 -> 17472 bytes
ui/css/novnc/Makefile.am | 20 +
ui/css/novnc/base.css | 405 ++++++
ui/js/Makefile.am | 2 +-
ui/js/novnc/Makefile.am | 22 +
ui/js/novnc/base64.js | 115 ++
ui/js/novnc/des.js | 273 ++++
ui/js/novnc/display.js | 770 +++++++++++
ui/js/novnc/input.js | 1946 +++++++++++++++++++++++++++
ui/js/novnc/jsunzip.js | 676 ++++++++++
ui/js/novnc/main.js | 103 ++
ui/js/novnc/rfb.js | 1866 +++++++++++++++++++++++++
ui/js/novnc/util.js | 381 ++++++
ui/js/novnc/web-socket-js/Makefile.am | 24 +
ui/js/novnc/web-socket-js/README.txt | 109 ++
ui/js/novnc/web-socket-js/WebSocketMain.swf | Bin 0 -> 177114 bytes
ui/js/novnc/web-socket-js/swfobject.js | 4 +
ui/js/novnc/web-socket-js/web_socket.js | 391 ++++++
ui/js/novnc/websock.js | 422 ++++++
ui/js/novnc/webutil.js | 216 +++
ui/js/src/kimchi.api.js | 7 +-
ui/novnc/Makefile.am | 22 -
ui/novnc/css/Makefile.am | 20 -
ui/novnc/css/Orbitron700.ttf | Bin 38580 -> 0 bytes
ui/novnc/css/Orbitron700.woff | Bin 17472 -> 0 bytes
ui/novnc/css/base.css | 405 ------
ui/novnc/js/Makefile.am | 22 -
ui/novnc/js/base64.js | 115 --
ui/novnc/js/des.js | 273 ----
ui/novnc/js/display.js | 770 -----------
ui/novnc/js/input.js | 1946 ---------------------------
ui/novnc/js/jsunzip.js | 676 ----------
ui/novnc/js/main.js | 103 --
ui/novnc/js/rfb.js | 1866 -------------------------
ui/novnc/js/util.js | 381 ------
ui/novnc/js/web-socket-js/Makefile.am | 24 -
ui/novnc/js/web-socket-js/README.txt | 109 --
ui/novnc/js/web-socket-js/WebSocketMain.swf | Bin 177114 -> 0 bytes
ui/novnc/js/web-socket-js/swfobject.js | 4 -
ui/novnc/js/web-socket-js/web_socket.js | 391 ------
ui/novnc/js/websock.js | 422 ------
ui/novnc/js/webutil.js | 216 ---
ui/novnc/vnc.html | 43 -
ui/pages/vnc_auto.html.tmpl | 44 +
53 files changed, 7833 insertions(+), 7842 deletions(-)
create mode 100644 ui/css/fonts/novnc/Makefile.am
create mode 100644 ui/css/fonts/novnc/Orbitron700.ttf
create mode 100644 ui/css/fonts/novnc/Orbitron700.woff
create mode 100644 ui/css/novnc/Makefile.am
create mode 100644 ui/css/novnc/base.css
create mode 100644 ui/js/novnc/Makefile.am
create mode 100644 ui/js/novnc/base64.js
create mode 100644 ui/js/novnc/des.js
create mode 100644 ui/js/novnc/display.js
create mode 100644 ui/js/novnc/input.js
create mode 100755 ui/js/novnc/jsunzip.js
create mode 100644 ui/js/novnc/main.js
create mode 100644 ui/js/novnc/rfb.js
create mode 100644 ui/js/novnc/util.js
create mode 100644 ui/js/novnc/web-socket-js/Makefile.am
create mode 100644 ui/js/novnc/web-socket-js/README.txt
create mode 100644 ui/js/novnc/web-socket-js/WebSocketMain.swf
create mode 100644 ui/js/novnc/web-socket-js/swfobject.js
create mode 100644 ui/js/novnc/web-socket-js/web_socket.js
create mode 100644 ui/js/novnc/websock.js
create mode 100644 ui/js/novnc/webutil.js
delete mode 100644 ui/novnc/Makefile.am
delete mode 100644 ui/novnc/css/Makefile.am
delete mode 100644 ui/novnc/css/Orbitron700.ttf
delete mode 100644 ui/novnc/css/Orbitron700.woff
delete mode 100644 ui/novnc/css/base.css
delete mode 100644 ui/novnc/js/Makefile.am
delete mode 100644 ui/novnc/js/base64.js
delete mode 100644 ui/novnc/js/des.js
delete mode 100644 ui/novnc/js/display.js
delete mode 100644 ui/novnc/js/input.js
delete mode 100755 ui/novnc/js/jsunzip.js
delete mode 100644 ui/novnc/js/main.js
delete mode 100644 ui/novnc/js/rfb.js
delete mode 100644 ui/novnc/js/util.js
delete mode 100644 ui/novnc/js/web-socket-js/Makefile.am
delete mode 100644 ui/novnc/js/web-socket-js/README.txt
delete mode 100644 ui/novnc/js/web-socket-js/WebSocketMain.swf
delete mode 100644 ui/novnc/js/web-socket-js/swfobject.js
delete mode 100644 ui/novnc/js/web-socket-js/web_socket.js
delete mode 100644 ui/novnc/js/websock.js
delete mode 100644 ui/novnc/js/webutil.js
delete mode 100644 ui/novnc/vnc.html
create mode 100644 ui/pages/vnc_auto.html.tmpl
diff --git a/configure.ac b/configure.ac
index bc3f93e..7d76f97 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,19 +66,19 @@ AC_CONFIG_FILES([
plugins/sample/ui/config/Makefile
ui/Makefile
ui/css/Makefile
+ ui/css/novnc/Makefile
ui/css/fonts/Makefile
+ ui/css/fonts/novnc/Makefile
ui/images/Makefile
ui/images/theme-default/Makefile
ui/js/Makefile
+ ui/js/novnc/Makefile
ui/js/spice/Makefile
+ ui/js/novnc/web-socket-js/Makefile
ui/libs/Makefile
ui/libs/themes/Makefile
ui/libs/themes/base/Makefile
ui/libs/themes/base/images/Makefile
- ui/novnc/Makefile
- ui/novnc/css/Makefile
- ui/novnc/js/Makefile
- ui/novnc/js/web-socket-js/Makefile
ui/pages/Makefile
ui/pages/help/Makefile
ui/pages/help/en_US/Makefile
diff --git a/contrib/kimchi.spec.fedora.in b/contrib/kimchi.spec.fedora.in
index dd2fba7..104c114 100644
--- a/contrib/kimchi.spec.fedora.in
+++ b/contrib/kimchi.spec.fedora.in
@@ -154,6 +154,8 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/mo/*/LC_MESSAGES/kimchi.mo
%{_datadir}/kimchi/config/ui/*.xml
%{_datadir}/kimchi/ui/css/fonts/fontawesome-webfont.*
+%{_datadir}/kimchi/ui/css/fonts/novnc/Orbitron700.*
+%{_datadir}/kimchi/ui/css/novnc/base.css
%{_datadir}/kimchi/ui/css/theme-default.min.css
%{_datadir}/kimchi/ui/images/*.png
%{_datadir}/kimchi/ui/images/*.ico
@@ -163,7 +165,11 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/ui/js/jquery-ui.js
%{_datadir}/kimchi/ui/js/jquery.min.js
%{_datadir}/kimchi/ui/js/modernizr.custom.2.6.2.min.js
+%{_datadir}/kimchi/ui/js/novnc/*.js
%{_datadir}/kimchi/ui/js/spice/*.js
+%{_datadir}/kimchi/ui/js/novnc/web-socket-js/WebSocketMain.swf
+%{_datadir}/kimchi/ui/js/novnc/web-socket-js/swfobject.js
+%{_datadir}/kimchi/ui/js/novnc/web-socket-js/web_socket.js
%{_datadir}/kimchi/ui/libs/jquery-ui-i18n.min.js
%{_datadir}/kimchi/ui/libs/jquery-ui.min.js
%{_datadir}/kimchi/ui/libs/jquery-1.10.0.min.js
@@ -171,13 +177,6 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/ui/libs/themes/base/images/*.png
%{_datadir}/kimchi/ui/libs/themes/base/images/*.gif
%{_datadir}/kimchi/ui/libs/themes/base/jquery-ui.min.css
-%{_datadir}/kimchi/ui/novnc/css/Orbitron700.*
-%{_datadir}/kimchi/ui/novnc/css/base.css
-%{_datadir}/kimchi/ui/novnc/js/*.js
-%{_datadir}/kimchi/ui/novnc/js/web-socket-js/WebSocketMain.swf
-%{_datadir}/kimchi/ui/novnc/js/web-socket-js/swfobject.js
-%{_datadir}/kimchi/ui/novnc/js/web-socket-js/web_socket.js
-%{_datadir}/kimchi/ui/novnc/vnc.html
%{_datadir}/kimchi/ui/pages/*.html.tmpl
%{_datadir}/kimchi/ui/pages/help/*/*.html
%{_datadir}/kimchi/ui/pages/tabs/*.html.tmpl
diff --git a/contrib/kimchi.spec.suse.in b/contrib/kimchi.spec.suse.in
index 73c59a0..7704822 100644
--- a/contrib/kimchi.spec.suse.in
+++ b/contrib/kimchi.spec.suse.in
@@ -76,6 +76,8 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/mo/*/LC_MESSAGES/kimchi.mo
%{_datadir}/kimchi/config/ui/*.xml
%{_datadir}/kimchi/ui/css/fonts/fontawesome-webfont.*
+%{_datadir}/kimchi/ui/css/fonts/novnc/Orbitron700.*
+%{_datadir}/kimchi/ui/css/novnc/base.css
%{_datadir}/kimchi/ui/css/theme-default.min.css
%{_datadir}/kimchi/ui/images/*.png
%{_datadir}/kimchi/ui/images/*.ico
@@ -85,7 +87,11 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/ui/js/jquery-ui.js
%{_datadir}/kimchi/ui/js/jquery.min.js
%{_datadir}/kimchi/ui/js/modernizr.custom.2.6.2.min.js
+%{_datadir}/kimchi/ui/js/novnc/*.js
%{_datadir}/kimchi/ui/js/spice/*.js
+%{_datadir}/kimchi/ui/js/novnc/web-socket-js/WebSocketMain.swf
+%{_datadir}/kimchi/ui/js/novnc/web-socket-js/swfobject.js
+%{_datadir}/kimchi/ui/js/novnc/web-socket-js/web_socket.js
%{_datadir}/kimchi/ui/libs/jquery-ui-i18n.min.js
%{_datadir}/kimchi/ui/libs/jquery-ui.min.js
%{_datadir}/kimchi/ui/libs/jquery-1.10.0.min.js
@@ -93,13 +99,6 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/kimchi/ui/libs/themes/base/images/*.png
%{_datadir}/kimchi/ui/libs/themes/base/images/*.gif
%{_datadir}/kimchi/ui/libs/themes/base/jquery-ui.min.css
-%{_datadir}/kimchi/ui/novnc/css/Orbitron700.*
-%{_datadir}/kimchi/ui/novnc/css/base.css
-%{_datadir}/kimchi/ui/novnc/js/*.js
-%{_datadir}/kimchi/ui/novnc/js/web-socket-js/WebSocketMain.swf
-%{_datadir}/kimchi/ui/novnc/js/web-socket-js/swfobject.js
-%{_datadir}/kimchi/ui/novnc/js/web-socket-js/web_socket.js
-%{_datadir}/kimchi/ui/novnc/vnc.html
%{_datadir}/kimchi/ui/pages/*.html.tmpl
%{_datadir}/kimchi/ui/pages/help/*/*.html
%{_datadir}/kimchi/ui/pages/tabs/*.html.tmpl
diff --git a/src/kimchi/vnc.py b/src/kimchi/vnc.py
index 61f9c15..1f36e9a 100644
--- a/src/kimchi/vnc.py
+++ b/src/kimchi/vnc.py
@@ -23,7 +23,7 @@ import os
import subprocess
-from kimchi.config import config, paths
+from kimchi.config import config
WS_TOKENS_DIR = '/var/lib/kimchi/vnc-tokens'
@@ -36,16 +36,9 @@ def new_ws_proxy():
if e.errno == errno.EEXIST:
pass
- cert = config.get('server', 'ssl_cert')
- key = config.get('server', 'ssl_key')
- if not (cert and key):
- cert = '%s/kimchi-cert.pem' % paths.conf_dir
- key = '%s/kimchi-key.pem' % paths.conf_dir
-
cmd = os.path.join(os.path.dirname(__file__), 'websockify.py')
args = ['python', cmd, config.get('display', 'display_proxy_port'),
- '--target-config', WS_TOKENS_DIR, '--cert', cert, '--key', key,
- '--web', os.path.join(paths.ui_dir, 'novnc')]
+ '--target-config', WS_TOKENS_DIR]
p = subprocess.Popen(args, close_fds=True)
return p
diff --git a/ui/Makefile.am b/ui/Makefile.am
index 4e0d57a..b5366c5 100644
--- a/ui/Makefile.am
+++ b/ui/Makefile.am
@@ -15,4 +15,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-SUBDIRS = css images js libs pages novnc
+SUBDIRS = css images js libs pages
diff --git a/ui/css/Makefile.am b/ui/css/Makefile.am
index 0922a9d..db65799 100644
--- a/ui/css/Makefile.am
+++ b/ui/css/Makefile.am
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-SUBDIRS = fonts
+SUBDIRS = novnc fonts
EXTRA_DIST = theme-default
diff --git a/ui/css/fonts/Makefile.am b/ui/css/fonts/Makefile.am
index d72bb6c..63df038 100644
--- a/ui/css/fonts/Makefile.am
+++ b/ui/css/fonts/Makefile.am
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+SUBDIRS = novnc
+
fontdir = $(datadir)/kimchi/ui/css/fonts
dist_font_DATA = fontawesome-webfont.*
diff --git a/ui/css/fonts/novnc/Makefile.am b/ui/css/fonts/novnc/Makefile.am
new file mode 100644
index 0000000..50f6050
--- /dev/null
+++ b/ui/css/fonts/novnc/Makefile.am
@@ -0,0 +1,20 @@
+#
+# Kimchi
+#
+# Copyright IBM, Corp. 2013
+#
+# Licensed 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.
+
+fontdir = $(datadir)/kimchi/ui/css/fonts/novnc
+
+dist_font_DATA = Orbitron700.*
diff --git a/ui/css/fonts/novnc/Orbitron700.ttf b/ui/css/fonts/novnc/Orbitron700.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..e28729dc56b0662b5d2506ddfde5a368784f5755
GIT binary patch
literal 38580
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
YaN=?Mu0Qj~<BJ#F#P26F-oE1h0<?nDhX4Qo
literal 0
HcmV?d00001
diff --git a/ui/css/fonts/novnc/Orbitron700.woff b/ui/css/fonts/novnc/Orbitron700.woff
new file mode 100644
index 0000000000000000000000000000000000000000..61db630cce1c18fd78c71462d82184a32af6089a
GIT binary patch
literal 17472
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
aYg+X)x}OQee;ks?lK=p?0sn=t1dRYj;d3$o
literal 0
HcmV?d00001
diff --git a/ui/css/novnc/Makefile.am b/ui/css/novnc/Makefile.am
new file mode 100644
index 0000000..29703d6
--- /dev/null
+++ b/ui/css/novnc/Makefile.am
@@ -0,0 +1,20 @@
+#
+# Kimchi
+#
+# Copyright IBM, Corp. 2013
+#
+# Licensed 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.
+
+cssdir = $(datadir)/kimchi/ui/css/novnc
+
+dist_css_DATA = base.css
diff --git a/ui/css/novnc/base.css b/ui/css/novnc/base.css
new file mode 100644
index 0000000..89b2b57
--- /dev/null
+++ b/ui/css/novnc/base.css
@@ -0,0 +1,405 @@
+/*
+ * noVNC base CSS
+ * Copyright (C) 2012 Joel Martin
+ * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
+ * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
+ */
+
+body {
+ margin:0;
+ padding:0;
+ font-family: Helvetica;
+ /*Background image with light grey curve.*/
+ background-color:#494949;
+ background-repeat:no-repeat;
+ background-position:right bottom;
+ height:100%;
+}
+
+html {
+ height:100%;
+}
+
+#noVNC_controls ul {
+ list-style: none;
+ margin: 0px;
+ padding: 0px;
+}
+#noVNC_controls li {
+ padding-bottom:8px;
+}
+
+#noVNC_host {
+ width:150px;
+}
+#noVNC_port {
+ width: 80px;
+}
+#noVNC_password {
+ width: 150px;
+}
+#noVNC_encrypt {
+}
+#noVNC_connectTimeout {
+ width: 30px;
+}
+#noVNC_path {
+ width: 100px;
+}
+#noVNC_connect_button {
+ width: 110px;
+ float:right;
+}
+
+
+#noVNC_view_drag_button {
+ display: none;
+}
+#sendCtrlAltDelButton {
+ display: none;
+}
+#noVNC_mobile_buttons {
+ display: none;
+}
+
+.noVNC-buttons-left {
+ float: left;
+ padding-left:10px;
+ padding-top:4px;
+}
+
+.noVNC-buttons-right {
+ float:right;
+ right: 0px;
+ padding-right:10px;
+ padding-top:4px;
+}
+
+#noVNC_status_bar {
+ margin-top: 0px;
+ padding: 0px;
+}
+
+#noVNC_status_bar div {
+ font-size: 12px;
+ padding-top: 4px;
+ width:100%;
+}
+
+#noVNC_status {
+ height:20px;
+ text-align: center;
+}
+#noVNC_settings_menu {
+ margin: 3px;
+ text-align: left;
+}
+#noVNC_settings_menu ul {
+ list-style: none;
+ margin: 0px;
+ padding: 0px;
+}
+
+#noVNC_apply {
+ float:right;
+}
+
+.noVNC_status_normal {
+ background: #eee;
+}
+.noVNC_status_error {
+ background: #f44;
+}
+.noVNC_status_warn {
+ background: #ff4;
+}
+
+/* Do not set width/height for VNC_screen or VNC_canvas or incorrect
+ * scaling will occur. Canvas resizes to remote VNC settings */
+#noVNC_screen_pad {
+ margin: 0px;
+ padding: 0px;
+ height: 44px;
+}
+#noVNC_screen {
+ text-align: center;
+ display: table;
+ width:100%;
+ height:100%;
+ background-color:#313131;
+ border-bottom-right-radius: 800px 600px;
+ /*border-top-left-radius: 800px 600px;*/
+}
+
+#noVNC_container, #noVNC_canvas {
+ margin: 0px;
+ padding: 0px;
+}
+
+#noVNC_canvas {
+ left: 0px;
+}
+
+#VNC_clipboard_clear_button {
+ float:right;
+}
+#VNC_clipboard_text {
+ font-size: 11px;
+}
+
+#noVNC_clipboard_clear_button {
+ float:right;
+}
+
+/*Bubble contents divs*/
+#noVNC_settings {
+ display:none;
+ margin-top:77px;
+ right:20px;
+ position:fixed;
+}
+
+#noVNC_controls {
+ display:none;
+ margin-top:77px;
+ right:12px;
+ position:fixed;
+}
+#noVNC_controls.top:after {
+ right:15px;
+}
+
+#noVNC_description {
+ display:none;
+ position:fixed;
+
+ margin-top:77px;
+ right:20px;
+ left:20px;
+ padding:15px;
+ color:#000;
+ background:#eee; /* default background for browsers without gradient support */
+
+ border:2px solid #E0E0E0;
+ -webkit-border-radius:10px;
+ -moz-border-radius:10px;
+ border-radius:10px;
+}
+
+#noVNC_clipboard {
+ display:none;
+ margin-top:77px;
+ right:30px;
+ position:fixed;
+}
+#noVNC_clipboard.top:after {
+ right:85px;
+}
+
+#keyboardinput {
+ width:1px;
+ height:1px;
+ background-color:#fff;
+ color:#fff;
+ border:0;
+ position: relative;
+ left: -40px;
+ z-index: -1;
+}
+
+.noVNC_status_warn {
+ background-color:yellow;
+}
+
+/*
+ * Advanced Styling
+ */
+
+/* Control bar */
+#noVNC-control-bar {
+ position:fixed;
+ background: #b2bdcd; /* Old browsers */
+ background: -moz-linear-gradient(top, #b2bdcd 0%, #899cb3 49%, #7e93af 51%, #6e84a3 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2bdcd), color-stop(49%,#899cb3), color-stop(51%,#7e93af), color-stop(100%,#6e84a3)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* IE10+ */
+ background: linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* W3C */
+
+ display:block;
+ height:44px;
+ left:0;
+ top:0;
+ width:100%;
+ z-index:200;
+}
+
+.noVNC_status_button {
+ padding: 4px 4px;
+ vertical-align: middle;
+ border:1px solid #869dbc;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ background: #b2bdcd; /* Old browsers */
+ background: -moz-linear-gradient(top, #b2bdcd 0%, #899cb3 49%, #7e93af 51%, #6e84a3 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2bdcd), color-stop(49%,#899cb3), color-stop(51%,#7e93af), color-stop(100%,#6e84a3)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b2bdcd', endColorstr='#6e84a3',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* W3C */
+ /*box-shadow:inset 0.4px 0.4px 0.4px #000000;*/
+}
+
+.noVNC_status_button_selected {
+ padding: 4px 4px;
+ vertical-align: middle;
+ border:1px solid #4366a9;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ background: #779ced; /* Old browsers */
+ background: -moz-linear-gradient(top, #779ced 0%, #3970e0 49%, #2160dd 51%, #2463df 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#779ced), color-stop(49%,#3970e0), color-stop(51%,#2160dd), color-stop(100%,#2463df)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#779ced', endColorstr='#2463df',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* W3C */
+ /*box-shadow:inset 0.4px 0.4px 0.4px #000000;*/
+}
+
+
+/*Settings Bubble*/
+.triangle-right {
+ position:relative;
+ padding:15px;
+ margin:1em 0 3em;
+ color:#fff;
+ background:#fff; /* default background for browsers without gradient support */
+ /* css3 */
+ /*background:-webkit-gradient(linear, 0 0, 0 100%, from(#2e88c4), to(#075698));
+ background:-moz-linear-gradient(#2e88c4, #075698);
+ background:-o-linear-gradient(#2e88c4, #075698);
+ background:linear-gradient(#2e88c4, #075698);*/
+ -webkit-border-radius:10px;
+ -moz-border-radius:10px;
+ border-radius:10px;
+ color:#000;
+ border:2px solid #E0E0E0;
+}
+
+.triangle-right.top:after {
+ border-color: transparent #E0E0E0;
+ border-width: 20px 20px 0 0;
+ bottom: auto;
+ left: auto;
+ right: 50px;
+ top: -20px;
+}
+
+.triangle-right:after {
+ content:"";
+ position:absolute;
+ bottom:-20px; /* value = - border-top-width - border-bottom-width */
+ left:50px; /* controls horizontal position */
+ border-width:20px 0 0 20px; /* vary these values to change the angle of the vertex */
+ border-style:solid;
+ border-color:#E0E0E0 transparent;
+ /* reduce the damage in FF3.0 */
+ display:block;
+ width:0;
+}
+
+.triangle-right.top:after {
+ top:-40px; /* value = - border-top-width - border-bottom-width */
+ right:50px; /* controls horizontal position */
+ bottom:auto;
+ left:auto;
+ border-width:40px 40px 0 0; /* vary these values to change the angle of the vertex */
+ border-color:transparent #E0E0E0;
+}
+
+/*Default noVNC logo.*/
+/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
+@font-face {
+ font-family: 'Orbitron';
+ font-style: normal;
+ font-weight: 700;
+ src: local('?'), url('Orbitron700.woff') format('woff'),
+ url('Orbitron700.ttf') format('truetype');
+}
+
+#noVNC_logo {
+ margin-top: 170px;
+ margin-left: 10px;
+ color:yellow;
+ text-align:left;
+ font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
+ line-height:90%;
+ text-shadow:
+ 5px 5px 0 #000,
+ -1px -1px 0 #000,
+ 1px -1px 0 #000,
+ -1px 1px 0 #000,
+ 1px 1px 0 #000;
+}
+
+
+#noVNC_logo span{
+ color:green;
+}
+
+/* ----------------------------------------
+ * Media sizing
+ * ----------------------------------------
+ */
+
+
+.noVNC_status_button {
+ font-size: 12px;
+}
+
+#noVNC_clipboard_text {
+ width: 500px;
+}
+
+#noVNC_logo {
+ font-size: 180px;
+}
+
+@media screen and (min-width: 481px) and (max-width: 640px) {
+ .noVNC_status_button {
+ font-size: 10px;
+ }
+ #noVNC_clipboard_text {
+ width: 410px;
+ }
+ #noVNC_logo {
+ font-size: 150px;
+ }
+}
+
+@media screen and (min-width: 321px) and (max-width: 480px) {
+ .noVNC_status_button {
+ font-size: 10px;
+ }
+ #noVNC_clipboard_text {
+ width: 250px;
+ }
+ #noVNC_logo {
+ font-size: 110px;
+ }
+}
+
+@media screen and (max-width: 320px) {
+ .noVNC_status_button {
+ font-size: 9px;
+ }
+ #noVNC_clipboard_text {
+ width: 220px;
+ }
+ #noVNC_logo {
+ font-size: 90px;
+ }
+}
diff --git a/ui/js/Makefile.am b/ui/js/Makefile.am
index a29c262..f4d1e6b 100644
--- a/ui/js/Makefile.am
+++ b/ui/js/Makefile.am
@@ -15,7 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-SUBDIRS = spice
+SUBDIRS = novnc spice
EXTRA_DIST = src widgets
diff --git a/ui/js/novnc/Makefile.am b/ui/js/novnc/Makefile.am
new file mode 100644
index 0000000..fefe6af
--- /dev/null
+++ b/ui/js/novnc/Makefile.am
@@ -0,0 +1,22 @@
+#
+# Kimchi
+#
+# Copyright IBM, Corp. 2013
+#
+# Licensed 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.
+
+SUBDIRS = web-socket-js
+
+jsdir = $(datadir)/kimchi/ui/js/novnc
+
+dist_js_DATA = $(wildcard *.js) $(NULL)
diff --git a/ui/js/novnc/base64.js b/ui/js/novnc/base64.js
new file mode 100644
index 0000000..f0891ab
--- /dev/null
+++ b/ui/js/novnc/base64.js
@@ -0,0 +1,115 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools…
+
+/*jslint white: false, bitwise: false, plusplus: false */
+/*global console */
+
+var Base64 = {
+
+/* Convert data (an array of integers) to a Base64 string. */
+toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
+base64Pad : '=',
+
+encode: function (data) {
+ "use strict";
+ var result = '';
+ var toBase64Table = Base64.toBase64Table;
+ var length = data.length
+ var lengthpad = (length%3);
+ var i = 0, j = 0;
+ // Convert every three bytes to 4 ascii characters.
+ /* BEGIN LOOP */
+ for (i = 0; i < (length - 2); i += 3) {
+ result += toBase64Table[data[i] >> 2];
+ result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
+ result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
+ result += toBase64Table[data[i+2] & 0x3f];
+ }
+ /* END LOOP */
+
+ // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
+ if (lengthpad === 2) {
+ j = length - lengthpad;
+ result += toBase64Table[data[j] >> 2];
+ result += toBase64Table[((data[j] & 0x03) << 4) + (data[j+1] >> 4)];
+ result += toBase64Table[(data[j+1] & 0x0f) << 2];
+ result += toBase64Table[64];
+ } else if (lengthpad === 1) {
+ j = length - lengthpad;
+ result += toBase64Table[data[j] >> 2];
+ result += toBase64Table[(data[j] & 0x03) << 4];
+ result += toBase64Table[64];
+ result += toBase64Table[64];
+ }
+
+ return result;
+},
+
+/* Convert Base64 data to a string */
+toBinaryTable : [
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+ 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
+ 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+ -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+ 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+],
+
+decode: function (data, offset) {
+ "use strict";
+ offset = typeof(offset) !== 'undefined' ? offset : 0;
+ var toBinaryTable = Base64.toBinaryTable;
+ var base64Pad = Base64.base64Pad;
+ var result, result_length, idx, i, c, padding;
+ var leftbits = 0; // number of bits decoded, but yet to be appended
+ var leftdata = 0; // bits decoded, but yet to be appended
+ var data_length = data.indexOf('=') - offset;
+
+ if (data_length < 0) { data_length = data.length - offset; }
+
+ /* Every four characters is 3 resulting numbers */
+ result_length = (data_length >> 2) * 3 + Math.floor((data_length%4)/1.5);
+ result = new Array(result_length);
+
+ // Convert one by one.
+ /* BEGIN LOOP */
+ for (idx = 0, i = offset; i < data.length; i++) {
+ c = toBinaryTable[data.charCodeAt(i) & 0x7f];
+ padding = (data.charAt(i) === base64Pad);
+ // Skip illegal characters and whitespace
+ if (c === -1) {
+ console.error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
+ continue;
+ }
+
+ // Collect data into leftdata, update bitcount
+ leftdata = (leftdata << 6) | c;
+ leftbits += 6;
+
+ // If we have 8 or more bits, append 8 bits to the result
+ if (leftbits >= 8) {
+ leftbits -= 8;
+ // Append if not padding.
+ if (!padding) {
+ result[idx++] = (leftdata >> leftbits) & 0xff;
+ }
+ leftdata &= (1 << leftbits) - 1;
+ }
+ }
+ /* END LOOP */
+
+ // If there are any bits left, the base64 string was corrupted
+ if (leftbits) {
+ throw {name: 'Base64-Error',
+ message: 'Corrupted base64 string'};
+ }
+
+ return result;
+}
+
+}; /* End of Base64 namespace */
diff --git a/ui/js/novnc/des.js b/ui/js/novnc/des.js
new file mode 100644
index 0000000..2d207c4
--- /dev/null
+++ b/ui/js/novnc/des.js
@@ -0,0 +1,273 @@
+/*
+ * Ported from Flashlight VNC ActionScript implementation:
+ * http://www.wizhelp.com/flashlight-vnc/
+ *
+ * Full attribution follows:
+ *
+ * -------------------------------------------------------------------------
+ *
+ * This DES class has been extracted from package Acme.Crypto for use in VNC.
+ * The unnecessary odd parity code has been removed.
+ *
+ * These changes are:
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+
+ * DesCipher - the DES encryption method
+ *
+ * The meat of this code is by Dave Zimmerman <dzimm(a)widget.com>, and is:
+ *
+ * Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
+ * without fee is hereby granted, provided that this copyright notice is kept
+ * intact.
+ *
+ * WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
+ * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
+ *
+ * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
+ * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
+ * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
+ * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
+ * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+ * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
+ * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
+ * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
+ * HIGH RISK ACTIVITIES.
+ *
+ *
+ * The rest is:
+ *
+ * Copyright (C) 1996 by Jef Poskanzer <jef(a)acme.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Visit the ACME Labs Java page for up-to-date versions of this and other
+ * fine Java utilities: http://www.acme.com/java/
+ */
+
+"use strict";
+/*jslint white: false, bitwise: false, plusplus: false */
+
+function DES(passwd) {
+
+// Tables, permutations, S-boxes, etc.
+var PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
+ 25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
+ 50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
+ totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28],
+ z = 0x0, a,b,c,d,e,f, SP1,SP2,SP3,SP4,SP5,SP6,SP7,SP8,
+ keys = [];
+
+a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
+SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
+ z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
+ a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
+ c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
+a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
+SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
+ a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
+ z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
+ z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
+a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
+SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
+ b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
+ c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
+ b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
+a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
+SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
+ z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
+ b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
+ c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
+a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
+SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
+ a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
+ z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
+ c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
+a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
+SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
+ z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
+ b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
+ a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
+a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
+SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
+ b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
+ b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
+ z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
+a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
+SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
+ c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
+ a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
+ z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
+
+// Set the key.
+function setKeys(keyBlock) {
+ var i, j, l, m, n, o, pc1m = [], pcr = [], kn = [],
+ raw0, raw1, rawi, KnLi;
+
+ for (j = 0, l = 56; j < 56; ++j, l-=8) {
+ l += l<-5 ? 65 : l<-3 ? 31 : l<-1 ? 63 : l===27 ? 35 : 0; // PC1
+ m = l & 0x7;
+ pc1m[j] = ((keyBlock[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
+ }
+
+ for (i = 0; i < 16; ++i) {
+ m = i << 1;
+ n = m + 1;
+ kn[m] = kn[n] = 0;
+ for (o=28; o<59; o+=28) {
+ for (j = o-28; j < o; ++j) {
+ l = j + totrot[i];
+ if (l < o) {
+ pcr[j] = pc1m[l];
+ } else {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+ }
+ for (j = 0; j < 24; ++j) {
+ if (pcr[PC2[j]] !== 0) {
+ kn[m] |= 1<<(23-j);
+ }
+ if (pcr[PC2[j + 24]] !== 0) {
+ kn[n] |= 1<<(23-j);
+ }
+ }
+ }
+
+ // cookey
+ for (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
+ raw0 = kn[rawi++];
+ raw1 = kn[rawi++];
+ keys[KnLi] = (raw0 & 0x00fc0000) << 6;
+ keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
+ keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
+ keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
+ ++KnLi;
+ keys[KnLi] = (raw0 & 0x0003f000) << 12;
+ keys[KnLi] |= (raw0 & 0x0000003f) << 16;
+ keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
+ keys[KnLi] |= (raw1 & 0x0000003f);
+ ++KnLi;
+ }
+}
+
+// Encrypt 8 bytes of text
+function enc8(text) {
+ var i = 0, b = text.slice(), fval, keysi = 0,
+ l, r, x; // left, right, accumulator
+
+ // Squash 8 bytes to 2 ints
+ l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
+ r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
+
+ x = ((l >>> 4) ^ r) & 0x0f0f0f0f;
+ r ^= x;
+ l ^= (x << 4);
+ x = ((l >>> 16) ^ r) & 0x0000ffff;
+ r ^= x;
+ l ^= (x << 16);
+ x = ((r >>> 2) ^ l) & 0x33333333;
+ l ^= x;
+ r ^= (x << 2);
+ x = ((r >>> 8) ^ l) & 0x00ff00ff;
+ l ^= x;
+ r ^= (x << 8);
+ r = (r << 1) | ((r >>> 31) & 1);
+ x = (l ^ r) & 0xaaaaaaaa;
+ l ^= x;
+ r ^= x;
+ l = (l << 1) | ((l >>> 31) & 1);
+
+ for (i = 0; i < 8; ++i) {
+ x = (r << 28) | (r >>> 4);
+ x ^= keys[keysi++];
+ fval = SP7[x & 0x3f];
+ fval |= SP5[(x >>> 8) & 0x3f];
+ fval |= SP3[(x >>> 16) & 0x3f];
+ fval |= SP1[(x >>> 24) & 0x3f];
+ x = r ^ keys[keysi++];
+ fval |= SP8[x & 0x3f];
+ fval |= SP6[(x >>> 8) & 0x3f];
+ fval |= SP4[(x >>> 16) & 0x3f];
+ fval |= SP2[(x >>> 24) & 0x3f];
+ l ^= fval;
+ x = (l << 28) | (l >>> 4);
+ x ^= keys[keysi++];
+ fval = SP7[x & 0x3f];
+ fval |= SP5[(x >>> 8) & 0x3f];
+ fval |= SP3[(x >>> 16) & 0x3f];
+ fval |= SP1[(x >>> 24) & 0x3f];
+ x = l ^ keys[keysi++];
+ fval |= SP8[x & 0x0000003f];
+ fval |= SP6[(x >>> 8) & 0x3f];
+ fval |= SP4[(x >>> 16) & 0x3f];
+ fval |= SP2[(x >>> 24) & 0x3f];
+ r ^= fval;
+ }
+
+ r = (r << 31) | (r >>> 1);
+ x = (l ^ r) & 0xaaaaaaaa;
+ l ^= x;
+ r ^= x;
+ l = (l << 31) | (l >>> 1);
+ x = ((l >>> 8) ^ r) & 0x00ff00ff;
+ r ^= x;
+ l ^= (x << 8);
+ x = ((l >>> 2) ^ r) & 0x33333333;
+ r ^= x;
+ l ^= (x << 2);
+ x = ((r >>> 16) ^ l) & 0x0000ffff;
+ l ^= x;
+ r ^= (x << 16);
+ x = ((r >>> 4) ^ l) & 0x0f0f0f0f;
+ l ^= x;
+ r ^= (x << 4);
+
+ // Spread ints to bytes
+ x = [r, l];
+ for (i = 0; i < 8; i++) {
+ b[i] = (x[i>>>2] >>> (8*(3 - (i%4)))) % 256;
+ if (b[i] < 0) { b[i] += 256; } // unsigned
+ }
+ return b;
+}
+
+// Encrypt 16 bytes of text using passwd as key
+function encrypt(t) {
+ return enc8(t.slice(0,8)).concat(enc8(t.slice(8,16)));
+}
+
+setKeys(passwd); // Setup keys
+return {'encrypt': encrypt}; // Public interface
+
+} // function DES
diff --git a/ui/js/novnc/display.js b/ui/js/novnc/display.js
new file mode 100644
index 0000000..afddf88
--- /dev/null
+++ b/ui/js/novnc/display.js
@@ -0,0 +1,770 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2012 Joel Martin
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ */
+
+/*jslint browser: true, white: false, bitwise: false */
+/*global Util, Base64, changeCursor */
+
+function Display(defaults) {
+"use strict";
+
+var that = {}, // Public API methods
+ conf = {}, // Configuration attributes
+
+ // Private Display namespace variables
+ c_ctx = null,
+ c_forceCanvas = false,
+
+ // Queued drawing actions for in-order rendering
+ renderQ = [],
+
+ // Predefine function variables (jslint)
+ imageDataGet, rgbImageData, bgrxImageData, cmapImageData,
+ setFillColor, rescale, scan_renderQ,
+
+ // The full frame buffer (logical canvas) size
+ fb_width = 0,
+ fb_height = 0,
+ // The visible "physical canvas" viewport
+ viewport = {'x': 0, 'y': 0, 'w' : 0, 'h' : 0 },
+ cleanRect = {'x1': 0, 'y1': 0, 'x2': -1, 'y2': -1},
+
+ c_prevStyle = "",
+ tile = null,
+ tile16x16 = null,
+ tile_x = 0,
+ tile_y = 0;
+
+
+// Configuration attributes
+Util.conf_defaults(conf, that, defaults, [
+ ['target', 'wo', 'dom', null, 'Canvas element for rendering'],
+ ['context', 'ro', 'raw', null, 'Canvas 2D context for rendering (read-only)'],
+ ['logo', 'rw', 'raw', null, 'Logo to display when cleared: {"width": width, "height": height, "data": data}'],
+ ['true_color', 'rw', 'bool', true, 'Use true-color pixel data'],
+ ['colourMap', 'rw', 'arr', [], 'Colour map array (when not true-color)'],
+ ['scale', 'rw', 'float', 1.0, 'Display area scale factor 0.0 - 1.0'],
+ ['viewport', 'rw', 'bool', false, 'Use a viewport set with viewportChange()'],
+ ['width', 'rw', 'int', null, 'Display area width'],
+ ['height', 'rw', 'int', null, 'Display area height'],
+
+ ['render_mode', 'ro', 'str', '', 'Canvas rendering mode (read-only)'],
+
+ ['prefer_js', 'rw', 'str', null, 'Prefer Javascript over canvas methods'],
+ ['cursor_uri', 'rw', 'raw', null, 'Can we render cursor using data URI']
+ ]);
+
+// Override some specific getters/setters
+that.get_context = function () { return c_ctx; };
+
+that.set_scale = function(scale) { rescale(scale); };
+
+that.set_width = function (val) { that.resize(val, fb_height); };
+that.get_width = function() { return fb_width; };
+
+that.set_height = function (val) { that.resize(fb_width, val); };
+that.get_height = function() { return fb_height; };
+
+
+
+//
+// Private functions
+//
+
+// Create the public API interface
+function constructor() {
+ Util.Debug(">> Display.constructor");
+
+ var c, func, i, curDat, curSave,
+ has_imageData = false, UE = Util.Engine;
+
+ if (! conf.target) { throw("target must be set"); }
+
+ if (typeof conf.target === 'string') {
+ throw("target must be a DOM element");
+ }
+
+ c = conf.target;
+
+ if (! c.getContext) { throw("no getContext method"); }
+
+ if (! c_ctx) { c_ctx = c.getContext('2d'); }
+
+ Util.Debug("User Agent: " + navigator.userAgent);
+ if (UE.gecko) { Util.Debug("Browser: gecko " + UE.gecko); }
+ if (UE.webkit) { Util.Debug("Browser: webkit " + UE.webkit); }
+ if (UE.trident) { Util.Debug("Browser: trident " + UE.trident); }
+ if (UE.presto) { Util.Debug("Browser: presto " + UE.presto); }
+
+ that.clear();
+
+ // Check canvas features
+ if ('createImageData' in c_ctx) {
+ conf.render_mode = "canvas rendering";
+ } else {
+ throw("Canvas does not support createImageData");
+ }
+ if (conf.prefer_js === null) {
+ Util.Info("Prefering javascript operations");
+ conf.prefer_js = true;
+ }
+
+ // Initialize cached tile imageData
+ tile16x16 = c_ctx.createImageData(16, 16);
+
+ /*
+ * Determine browser support for setting the cursor via data URI
+ * scheme
+ */
+ curDat = [];
+ for (i=0; i < 8 * 8 * 4; i += 1) {
+ curDat.push(255);
+ }
+ try {
+ curSave = c.style.cursor;
+ changeCursor(conf.target, curDat, curDat, 2, 2, 8, 8);
+ if (c.style.cursor) {
+ if (conf.cursor_uri === null) {
+ conf.cursor_uri = true;
+ }
+ Util.Info("Data URI scheme cursor supported");
+ } else {
+ if (conf.cursor_uri === null) {
+ conf.cursor_uri = false;
+ }
+ Util.Warn("Data URI scheme cursor not supported");
+ }
+ c.style.cursor = curSave;
+ } catch (exc2) {
+ Util.Error("Data URI scheme cursor test exception: " + exc2);
+ conf.cursor_uri = false;
+ }
+
+ Util.Debug("<< Display.constructor");
+ return that ;
+}
+
+rescale = function(factor) {
+ var c, tp, x, y,
+ properties = ['transform', 'WebkitTransform', 'MozTransform', null];
+ c = conf.target;
+ tp = properties.shift();
+ while (tp) {
+ if (typeof c.style[tp] !== 'undefined') {
+ break;
+ }
+ tp = properties.shift();
+ }
+
+ if (tp === null) {
+ Util.Debug("No scaling support");
+ return;
+ }
+
+
+ if (typeof(factor) === "undefined") {
+ factor = conf.scale;
+ } else if (factor > 1.0) {
+ factor = 1.0;
+ } else if (factor < 0.1) {
+ factor = 0.1;
+ }
+
+ if (conf.scale === factor) {
+ //Util.Debug("Display already scaled to '" + factor + "'");
+ return;
+ }
+
+ conf.scale = factor;
+ x = c.width - c.width * factor;
+ y = c.height - c.height * factor;
+ c.style[tp] = "scale(" + conf.scale + ") translate(-" + x + "px, -" + y + "px)";
+};
+
+setFillColor = function(color) {
+ var bgr, newStyle;
+ if (conf.true_color) {
+ bgr = color;
+ } else {
+ bgr = conf.colourMap[color[0]];
+ }
+ newStyle = "rgb(" + bgr[2] + "," + bgr[1] + "," + bgr[0] + ")";
+ if (newStyle !== c_prevStyle) {
+ c_ctx.fillStyle = newStyle;
+ c_prevStyle = newStyle;
+ }
+};
+
+
+//
+// Public API interface functions
+//
+
+// Shift and/or resize the visible viewport
+that.viewportChange = function(deltaX, deltaY, width, height) {
+ var c = conf.target, v = viewport, cr = cleanRect,
+ saveImg = null, saveStyle, x1, y1, vx2, vy2, w, h;
+
+ if (!conf.viewport) {
+ Util.Debug("Setting viewport to full display region");
+ deltaX = -v.w; // Clamped later if out of bounds
+ deltaY = -v.h; // Clamped later if out of bounds
+ width = fb_width;
+ height = fb_height;
+ }
+
+ if (typeof(deltaX) === "undefined") { deltaX = 0; }
+ if (typeof(deltaY) === "undefined") { deltaY = 0; }
+ if (typeof(width) === "undefined") { width = v.w; }
+ if (typeof(height) === "undefined") { height = v.h; }
+
+ // Size change
+
+ if (width > fb_width) { width = fb_width; }
+ if (height > fb_height) { height = fb_height; }
+
+ if ((v.w !== width) || (v.h !== height)) {
+ // Change width
+ if ((width < v.w) && (cr.x2 > v.x + width -1)) {
+ cr.x2 = v.x + width - 1;
+ }
+ v.w = width;
+
+ // Change height
+ if ((height < v.h) && (cr.y2 > v.y + height -1)) {
+ cr.y2 = v.y + height - 1;
+ }
+ v.h = height;
+
+
+ if (v.w > 0 && v.h > 0 && c.width > 0 && c.height > 0) {
+ saveImg = c_ctx.getImageData(0, 0,
+ (c.width < v.w) ? c.width : v.w,
+ (c.height < v.h) ? c.height : v.h);
+ }
+
+ c.width = v.w;
+ c.height = v.h;
+
+ if (saveImg) {
+ c_ctx.putImageData(saveImg, 0, 0);
+ }
+ }
+
+ vx2 = v.x + v.w - 1;
+ vy2 = v.y + v.h - 1;
+
+
+ // Position change
+
+ if ((deltaX < 0) && ((v.x + deltaX) < 0)) {
+ deltaX = - v.x;
+ }
+ if ((vx2 + deltaX) >= fb_width) {
+ deltaX -= ((vx2 + deltaX) - fb_width + 1);
+ }
+
+ if ((v.y + deltaY) < 0) {
+ deltaY = - v.y;
+ }
+ if ((vy2 + deltaY) >= fb_height) {
+ deltaY -= ((vy2 + deltaY) - fb_height + 1);
+ }
+
+ if ((deltaX === 0) && (deltaY === 0)) {
+ //Util.Debug("skipping viewport change");
+ return;
+ }
+ Util.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY);
+
+ v.x += deltaX;
+ vx2 += deltaX;
+ v.y += deltaY;
+ vy2 += deltaY;
+
+ // Update the clean rectangle
+ if (v.x > cr.x1) {
+ cr.x1 = v.x;
+ }
+ if (vx2 < cr.x2) {
+ cr.x2 = vx2;
+ }
+ if (v.y > cr.y1) {
+ cr.y1 = v.y;
+ }
+ if (vy2 < cr.y2) {
+ cr.y2 = vy2;
+ }
+
+ if (deltaX < 0) {
+ // Shift viewport left, redraw left section
+ x1 = 0;
+ w = - deltaX;
+ } else {
+ // Shift viewport right, redraw right section
+ x1 = v.w - deltaX;
+ w = deltaX;
+ }
+ if (deltaY < 0) {
+ // Shift viewport up, redraw top section
+ y1 = 0;
+ h = - deltaY;
+ } else {
+ // Shift viewport down, redraw bottom section
+ y1 = v.h - deltaY;
+ h = deltaY;
+ }
+
+ // Copy the valid part of the viewport to the shifted location
+ saveStyle = c_ctx.fillStyle;
+ c_ctx.fillStyle = "rgb(255,255,255)";
+ if (deltaX !== 0) {
+ //that.copyImage(0, 0, -deltaX, 0, v.w, v.h);
+ //that.fillRect(x1, 0, w, v.h, [255,255,255]);
+ c_ctx.drawImage(c, 0, 0, v.w, v.h, -deltaX, 0, v.w, v.h);
+ c_ctx.fillRect(x1, 0, w, v.h);
+ }
+ if (deltaY !== 0) {
+ //that.copyImage(0, 0, 0, -deltaY, v.w, v.h);
+ //that.fillRect(0, y1, v.w, h, [255,255,255]);
+ c_ctx.drawImage(c, 0, 0, v.w, v.h, 0, -deltaY, v.w, v.h);
+ c_ctx.fillRect(0, y1, v.w, h);
+ }
+ c_ctx.fillStyle = saveStyle;
+};
+
+
+// Return a map of clean and dirty areas of the viewport and reset the
+// tracking of clean and dirty areas.
+//
+// Returns: {'cleanBox': {'x': x, 'y': y, 'w': w, 'h': h},
+// 'dirtyBoxes': [{'x': x, 'y': y, 'w': w, 'h': h}, ...]}
+that.getCleanDirtyReset = function() {
+ var v = viewport, c = cleanRect, cleanBox, dirtyBoxes = [],
+ vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1;
+
+
+ // Copy the cleanRect
+ cleanBox = {'x': c.x1, 'y': c.y1,
+ 'w': c.x2 - c.x1 + 1, 'h': c.y2 - c.y1 + 1};
+
+ if ((c.x1 >= c.x2) || (c.y1 >= c.y2)) {
+ // Whole viewport is dirty
+ dirtyBoxes.push({'x': v.x, 'y': v.y, 'w': v.w, 'h': v.h});
+ } else {
+ // Redraw dirty regions
+ if (v.x < c.x1) {
+ // left side dirty region
+ dirtyBoxes.push({'x': v.x, 'y': v.y,
+ 'w': c.x1 - v.x + 1, 'h': v.h});
+ }
+ if (vx2 > c.x2) {
+ // right side dirty region
+ dirtyBoxes.push({'x': c.x2 + 1, 'y': v.y,
+ 'w': vx2 - c.x2, 'h': v.h});
+ }
+ if (v.y < c.y1) {
+ // top/middle dirty region
+ dirtyBoxes.push({'x': c.x1, 'y': v.y,
+ 'w': c.x2 - c.x1 + 1, 'h': c.y1 - v.y});
+ }
+ if (vy2 > c.y2) {
+ // bottom/middle dirty region
+ dirtyBoxes.push({'x': c.x1, 'y': c.y2 + 1,
+ 'w': c.x2 - c.x1 + 1, 'h': vy2 - c.y2});
+ }
+ }
+
+ // Reset the cleanRect to the whole viewport
+ cleanRect = {'x1': v.x, 'y1': v.y,
+ 'x2': v.x + v.w - 1, 'y2': v.y + v.h - 1};
+
+ return {'cleanBox': cleanBox, 'dirtyBoxes': dirtyBoxes};
+};
+
+// Translate viewport coordinates to absolute coordinates
+that.absX = function(x) {
+ return x + viewport.x;
+};
+that.absY = function(y) {
+ return y + viewport.y;
+};
+
+
+that.resize = function(width, height) {
+ c_prevStyle = "";
+
+ fb_width = width;
+ fb_height = height;
+
+ rescale(conf.scale);
+ that.viewportChange();
+};
+
+that.clear = function() {
+
+ if (conf.logo) {
+ that.resize(conf.logo.width, conf.logo.height);
+ that.blitStringImage(conf.logo.data, 0, 0);
+ } else {
+ that.resize(640, 20);
+ c_ctx.clearRect(0, 0, viewport.w, viewport.h);
+ }
+
+ renderQ = [];
+
+ // No benefit over default ("source-over") in Chrome and firefox
+ //c_ctx.globalCompositeOperation = "copy";
+};
+
+that.fillRect = function(x, y, width, height, color) {
+ setFillColor(color);
+ c_ctx.fillRect(x - viewport.x, y - viewport.y, width, height);
+};
+
+that.copyImage = function(old_x, old_y, new_x, new_y, w, h) {
+ var x1 = old_x - viewport.x, y1 = old_y - viewport.y,
+ x2 = new_x - viewport.x, y2 = new_y - viewport.y;
+ c_ctx.drawImage(conf.target, x1, y1, w, h, x2, y2, w, h);
+};
+
+
+// Start updating a tile
+that.startTile = function(x, y, width, height, color) {
+ var data, bgr, red, green, blue, i;
+ tile_x = x;
+ tile_y = y;
+ if ((width === 16) && (height === 16)) {
+ tile = tile16x16;
+ } else {
+ tile = c_ctx.createImageData(width, height);
+ }
+ data = tile.data;
+ if (conf.prefer_js) {
+ if (conf.true_color) {
+ bgr = color;
+ } else {
+ bgr = conf.colourMap[color[0]];
+ }
+ red = bgr[2];
+ green = bgr[1];
+ blue = bgr[0];
+ for (i = 0; i < (width * height * 4); i+=4) {
+ data[i ] = red;
+ data[i + 1] = green;
+ data[i + 2] = blue;
+ data[i + 3] = 255;
+ }
+ } else {
+ that.fillRect(x, y, width, height, color);
+ }
+};
+
+// Update sub-rectangle of the current tile
+that.subTile = function(x, y, w, h, color) {
+ var data, p, bgr, red, green, blue, width, j, i, xend, yend;
+ if (conf.prefer_js) {
+ data = tile.data;
+ width = tile.width;
+ if (conf.true_color) {
+ bgr = color;
+ } else {
+ bgr = conf.colourMap[color[0]];
+ }
+ red = bgr[2];
+ green = bgr[1];
+ blue = bgr[0];
+ xend = x + w;
+ yend = y + h;
+ for (j = y; j < yend; j += 1) {
+ for (i = x; i < xend; i += 1) {
+ p = (i + (j * width) ) * 4;
+ data[p ] = red;
+ data[p + 1] = green;
+ data[p + 2] = blue;
+ data[p + 3] = 255;
+ }
+ }
+ } else {
+ that.fillRect(tile_x + x, tile_y + y, w, h, color);
+ }
+};
+
+// Draw the current tile to the screen
+that.finishTile = function() {
+ if (conf.prefer_js) {
+ c_ctx.putImageData(tile, tile_x - viewport.x, tile_y - viewport.y);
+ }
+ // else: No-op, if not prefer_js then already done by setSubTile
+};
+
+rgbImageData = function(x, y, vx, vy, width, height, arr, offset) {
+ var img, i, j, data;
+ /*
+ if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
+ (x - v.x + width < 0) || (y - v.y + height < 0)) {
+ // Skipping because outside of viewport
+ return;
+ }
+ */
+ img = c_ctx.createImageData(width, height);
+ data = img.data;
+ for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+3) {
+ data[i ] = arr[j ];
+ data[i + 1] = arr[j + 1];
+ data[i + 2] = arr[j + 2];
+ data[i + 3] = 255; // Set Alpha
+ }
+ c_ctx.putImageData(img, x - vx, y - vy);
+};
+
+bgrxImageData = function(x, y, vx, vy, width, height, arr, offset) {
+ var img, i, j, data;
+ /*
+ if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
+ (x - v.x + width < 0) || (y - v.y + height < 0)) {
+ // Skipping because outside of viewport
+ return;
+ }
+ */
+ img = c_ctx.createImageData(width, height);
+ data = img.data;
+ for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
+ data[i ] = arr[j + 2];
+ data[i + 1] = arr[j + 1];
+ data[i + 2] = arr[j ];
+ data[i + 3] = 255; // Set Alpha
+ }
+ c_ctx.putImageData(img, x - vx, y - vy);
+};
+
+cmapImageData = function(x, y, vx, vy, width, height, arr, offset) {
+ var img, i, j, data, bgr, cmap;
+ img = c_ctx.createImageData(width, height);
+ data = img.data;
+ cmap = conf.colourMap;
+ for (i=0, j=offset; i < (width * height * 4); i+=4, j+=1) {
+ bgr = cmap[arr[j]];
+ data[i ] = bgr[2];
+ data[i + 1] = bgr[1];
+ data[i + 2] = bgr[0];
+ data[i + 3] = 255; // Set Alpha
+ }
+ c_ctx.putImageData(img, x - vx, y - vy);
+};
+
+that.blitImage = function(x, y, width, height, arr, offset) {
+ if (conf.true_color) {
+ bgrxImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
+ } else {
+ cmapImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
+ }
+};
+
+that.blitRgbImage = function(x, y, width, height, arr, offset) {
+ if (conf.true_color) {
+ rgbImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
+ } else {
+ // prolly wrong...
+ cmapImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
+ }
+};
+
+that.blitStringImage = function(str, x, y) {
+ var img = new Image();
+ img.onload = function () {
+ c_ctx.drawImage(img, x - viewport.x, y - viewport.y);
+ };
+ img.src = str;
+};
+
+// Wrap ctx.drawImage but relative to viewport
+that.drawImage = function(img, x, y) {
+ c_ctx.drawImage(img, x - viewport.x, y - viewport.y);
+};
+
+that.renderQ_push = function(action) {
+ renderQ.push(action);
+ if (renderQ.length === 1) {
+ // If this can be rendered immediately it will be, otherwise
+ // the scanner will start polling the queue (every
+ // requestAnimationFrame interval)
+ scan_renderQ();
+ }
+};
+
+scan_renderQ = function() {
+ var a, ready = true;
+ while (ready && renderQ.length > 0) {
+ a = renderQ[0];
+ switch (a.type) {
+ case 'copy':
+ that.copyImage(a.old_x, a.old_y, a.x, a.y, a.width, a.height);
+ break;
+ case 'fill':
+ that.fillRect(a.x, a.y, a.width, a.height, a.color);
+ break;
+ case 'blit':
+ that.blitImage(a.x, a.y, a.width, a.height, a.data, 0);
+ break;
+ case 'blitRgb':
+ that.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0);
+ break;
+ case 'img':
+ if (a.img.complete) {
+ that.drawImage(a.img, a.x, a.y);
+ } else {
+ // We need to wait for this image to 'load'
+ // to keep things in-order
+ ready = false;
+ }
+ break;
+ }
+ if (ready) {
+ a = renderQ.shift();
+ }
+ }
+ if (renderQ.length > 0) {
+ requestAnimFrame(scan_renderQ);
+ }
+};
+
+
+that.changeCursor = function(pixels, mask, hotx, hoty, w, h) {
+ if (conf.cursor_uri === false) {
+ Util.Warn("changeCursor called but no cursor data URI support");
+ return;
+ }
+
+ if (conf.true_color) {
+ changeCursor(conf.target, pixels, mask, hotx, hoty, w, h);
+ } else {
+ changeCursor(conf.target, pixels, mask, hotx, hoty, w, h, conf.colourMap);
+ }
+};
+
+that.defaultCursor = function() {
+ conf.target.style.cursor = "default";
+};
+
+return constructor(); // Return the public API interface
+
+} // End of Display()
+
+
+/* Set CSS cursor property using data URI encoded cursor file */
+function changeCursor(target, pixels, mask, hotx, hoty, w0, h0, cmap) {
+ "use strict";
+ var cur = [], rgb, IHDRsz, RGBsz, ANDsz, XORsz, url, idx, alpha, x, y;
+ //Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w0: " + w0 + ", h0: " + h0);
+
+ var w = w0;
+ var h = h0;
+ if (h < w)
+ h = w; // increase h to make it square
+ else
+ w = h; // increace w to make it square
+
+ // Push multi-byte little-endian values
+ cur.push16le = function (num) {
+ this.push((num ) & 0xFF,
+ (num >> 8) & 0xFF );
+ };
+ cur.push32le = function (num) {
+ this.push((num ) & 0xFF,
+ (num >> 8) & 0xFF,
+ (num >> 16) & 0xFF,
+ (num >> 24) & 0xFF );
+ };
+
+ IHDRsz = 40;
+ RGBsz = w * h * 4;
+ XORsz = Math.ceil( (w * h) / 8.0 );
+ ANDsz = Math.ceil( (w * h) / 8.0 );
+
+ // Main header
+ cur.push16le(0); // 0: Reserved
+ cur.push16le(2); // 2: .CUR type
+ cur.push16le(1); // 4: Number of images, 1 for non-animated ico
+
+ // Cursor #1 header (ICONDIRENTRY)
+ cur.push(w); // 6: width
+ cur.push(h); // 7: height
+ cur.push(0); // 8: colors, 0 -> true-color
+ cur.push(0); // 9: reserved
+ cur.push16le(hotx); // 10: hotspot x coordinate
+ cur.push16le(hoty); // 12: hotspot y coordinate
+ cur.push32le(IHDRsz + RGBsz + XORsz + ANDsz);
+ // 14: cursor data byte size
+ cur.push32le(22); // 18: offset of cursor data in the file
+
+
+ // Cursor #1 InfoHeader (ICONIMAGE/BITMAPINFO)
+ cur.push32le(IHDRsz); // 22: Infoheader size
+ cur.push32le(w); // 26: Cursor width
+ cur.push32le(h*2); // 30: XOR+AND height
+ cur.push16le(1); // 34: number of planes
+ cur.push16le(32); // 36: bits per pixel
+ cur.push32le(0); // 38: Type of compression
+
+ cur.push32le(XORsz + ANDsz); // 43: Size of Image
+ // Gimp leaves this as 0
+
+ cur.push32le(0); // 46: reserved
+ cur.push32le(0); // 50: reserved
+ cur.push32le(0); // 54: reserved
+ cur.push32le(0); // 58: reserved
+
+ // 62: color data (RGBQUAD icColors[])
+ for (y = h-1; y >= 0; y -= 1) {
+ for (x = 0; x < w; x += 1) {
+ if (x >= w0 || y >= h0) {
+ cur.push(0); // blue
+ cur.push(0); // green
+ cur.push(0); // red
+ cur.push(0); // alpha
+ } else {
+ idx = y * Math.ceil(w0 / 8) + Math.floor(x/8);
+ alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
+ if (cmap) {
+ idx = (w0 * y) + x;
+ rgb = cmap[pixels[idx]];
+ cur.push(rgb[2]); // blue
+ cur.push(rgb[1]); // green
+ cur.push(rgb[0]); // red
+ cur.push(alpha); // alpha
+ } else {
+ idx = ((w0 * y) + x) * 4;
+ cur.push(pixels[idx + 2]); // blue
+ cur.push(pixels[idx + 1]); // green
+ cur.push(pixels[idx ]); // red
+ cur.push(alpha); // alpha
+ }
+ }
+ }
+ }
+
+ // XOR/bitmask data (BYTE icXOR[])
+ // (ignored, just needs to be right size)
+ for (y = 0; y < h; y += 1) {
+ for (x = 0; x < Math.ceil(w / 8); x += 1) {
+ cur.push(0x00);
+ }
+ }
+
+ // AND/bitmask data (BYTE icAND[])
+ // (ignored, just needs to be right size)
+ for (y = 0; y < h; y += 1) {
+ for (x = 0; x < Math.ceil(w / 8); x += 1) {
+ cur.push(0x00);
+ }
+ }
+
+ url = "data:image/x-icon;base64," + Base64.encode(cur);
+ target.style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default";
+ //Util.Debug("<< changeCursor, cur.length: " + cur.length);
+}
diff --git a/ui/js/novnc/input.js b/ui/js/novnc/input.js
new file mode 100644
index 0000000..03c5e77
--- /dev/null
+++ b/ui/js/novnc/input.js
@@ -0,0 +1,1946 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2012 Joel Martin
+ * Licensed under MPL 2.0 or any later version (see LICENSE.txt)
+ */
+
+/*jslint browser: true, white: false, bitwise: false */
+/*global window, Util */
+
+
+//
+// Keyboard event handler
+//
+
+function Keyboard(defaults) {
+"use strict";
+
+var that = {}, // Public API methods
+ conf = {}, // Configuration attributes
+
+ keyDownList = []; // List of depressed keys
+ // (even if they are happy)
+
+// Configuration attributes
+Util.conf_defaults(conf, that, defaults, [
+ ['target', 'wo', 'dom', document, 'DOM element that captures keyboard input'],
+ ['focused', 'rw', 'bool', true, 'Capture and send key events'],
+
+ ['onKeyPress', 'rw', 'func', null, 'Handler for key press/release']
+ ]);
+
+
+//
+// Private functions
+//
+
+// From the event keyCode return the keysym value for keys that need
+// to be suppressed otherwise they may trigger unintended browser
+// actions
+function getKeysymSpecial(evt) {
+ var keysym = null;
+
+ switch ( evt.keyCode ) {
+ // These generate a keyDown and keyPress in Firefox and Opera
+ case 8 : keysym = 0xFF08; break; // BACKSPACE
+ case 13 : keysym = 0xFF0D; break; // ENTER
+
+ // This generates a keyDown and keyPress in Opera
+ case 9 : keysym = 0xFF09; break; // TAB
+ default : break;
+ }
+
+ if (evt.type === 'keydown') {
+ switch ( evt.keyCode ) {
+ case 27 : keysym = 0xFF1B; break; // ESCAPE
+ case 46 : keysym = 0xFFFF; break; // DELETE
+
+ case 36 : keysym = 0xFF50; break; // HOME
+ case 35 : keysym = 0xFF57; break; // END
+ case 33 : keysym = 0xFF55; break; // PAGE_UP
+ case 34 : keysym = 0xFF56; break; // PAGE_DOWN
+ case 45 : keysym = 0xFF63; break; // INSERT
+ // '-' during keyPress
+ case 37 : keysym = 0xFF51; break; // LEFT
+ case 38 : keysym = 0xFF52; break; // UP
+ case 39 : keysym = 0xFF53; break; // RIGHT
+ case 40 : keysym = 0xFF54; break; // DOWN
+ case 16 : keysym = 0xFFE1; break; // SHIFT
+ case 17 : keysym = 0xFFE3; break; // CONTROL
+ //case 18 : keysym = 0xFFE7; break; // Left Meta (Mac Option)
+ case 18 : keysym = 0xFFE9; break; // Left ALT (Mac Command)
+
+ case 112 : keysym = 0xFFBE; break; // F1
+ case 113 : keysym = 0xFFBF; break; // F2
+ case 114 : keysym = 0xFFC0; break; // F3
+ case 115 : keysym = 0xFFC1; break; // F4
+ case 116 : keysym = 0xFFC2; break; // F5
+ case 117 : keysym = 0xFFC3; break; // F6
+ case 118 : keysym = 0xFFC4; break; // F7
+ case 119 : keysym = 0xFFC5; break; // F8
+ case 120 : keysym = 0xFFC6; break; // F9
+ case 121 : keysym = 0xFFC7; break; // F10
+ case 122 : keysym = 0xFFC8; break; // F11
+ case 123 : keysym = 0xFFC9; break; // F12
+
+ case 225 : keysym = 0xFE03; break; // AltGr
+ case 91 : keysym = 0xFFEC; break; // Super_R (Win Key)
+ case 93 : keysym = 0xFF67; break; // Menu (Win Menu)
+
+ default : break;
+ }
+ }
+
+ if ((!keysym) && (evt.ctrlKey || evt.altKey)) {
+ if ((typeof(evt.which) !== "undefined") && (evt.which > 0)) {
+ keysym = evt.which;
+ } else {
+ // IE9 always
+ // Firefox and Opera when ctrl/alt + special
+ Util.Warn("which not set, using keyCode");
+ keysym = evt.keyCode;
+ }
+
+ /* Remap symbols */
+ switch (keysym) {
+ case 186 : keysym = 59; break; // ; (IE)
+ case 187 : keysym = 61; break; // = (IE)
+ case 188 : keysym = 44; break; // , (Mozilla, IE)
+ case 109 : // - (Mozilla, Opera)
+ if (Util.Engine.gecko || Util.Engine.presto) {
+ keysym = 45; }
+ break;
+ case 173 : // - (Mozilla)
+ if (Util.Engine.gecko) {
+ keysym = 45; }
+ break;
+ case 189 : keysym = 45; break; // - (IE)
+ case 190 : keysym = 46; break; // . (Mozilla, IE)
+ case 191 : keysym = 47; break; // / (Mozilla, IE)
+ case 192 : keysym = 96; break; // ` (Mozilla, IE)
+ case 219 : keysym = 91; break; // [ (Mozilla, IE)
+ case 220 : keysym = 92; break; // \ (Mozilla, IE)
+ case 221 : keysym = 93; break; // ] (Mozilla, IE)
+ case 222 : keysym = 39; break; // ' (Mozilla, IE)
+ }
+
+ /* Remap shifted and unshifted keys */
+ if (!!evt.shiftKey) {
+ switch (keysym) {
+ case 48 : keysym = 41 ; break; // ) (shifted 0)
+ case 49 : keysym = 33 ; break; // ! (shifted 1)
+ case 50 : keysym = 64 ; break; // @ (shifted 2)
+ case 51 : keysym = 35 ; break; // # (shifted 3)
+ case 52 : keysym = 36 ; break; // $ (shifted 4)
+ case 53 : keysym = 37 ; break; // % (shifted 5)
+ case 54 : keysym = 94 ; break; // ^ (shifted 6)
+ case 55 : keysym = 38 ; break; // & (shifted 7)
+ case 56 : keysym = 42 ; break; // * (shifted 8)
+ case 57 : keysym = 40 ; break; // ( (shifted 9)
+
+ case 59 : keysym = 58 ; break; // : (shifted `)
+ case 61 : keysym = 43 ; break; // + (shifted ;)
+ case 44 : keysym = 60 ; break; // < (shifted ,)
+ case 45 : keysym = 95 ; break; // _ (shifted -)
+ case 46 : keysym = 62 ; break; // > (shifted .)
+ case 47 : keysym = 63 ; break; // ? (shifted /)
+ case 96 : keysym = 126; break; // ~ (shifted `)
+ case 91 : keysym = 123; break; // { (shifted [)
+ case 92 : keysym = 124; break; // | (shifted \)
+ case 93 : keysym = 125; break; // } (shifted ])
+ case 39 : keysym = 34 ; break; // " (shifted ')
+ }
+ } else if ((keysym >= 65) && (keysym <=90)) {
+ /* Remap unshifted A-Z */
+ keysym += 32;
+ } else if (evt.keyLocation === 3) {
+ // numpad keys
+ switch (keysym) {
+ case 96 : keysym = 48; break; // 0
+ case 97 : keysym = 49; break; // 1
+ case 98 : keysym = 50; break; // 2
+ case 99 : keysym = 51; break; // 3
+ case 100: keysym = 52; break; // 4
+ case 101: keysym = 53; break; // 5
+ case 102: keysym = 54; break; // 6
+ case 103: keysym = 55; break; // 7
+ case 104: keysym = 56; break; // 8
+ case 105: keysym = 57; break; // 9
+ case 109: keysym = 45; break; // -
+ case 110: keysym = 46; break; // .
+ case 111: keysym = 47; break; // /
+ }
+ }
+ }
+
+ return keysym;
+}
+
+/* Translate DOM keyPress event to keysym value */
+function getKeysym(evt) {
+ var keysym, msg;
+
+ if (typeof(evt.which) !== "undefined") {
+ // WebKit, Firefox, Opera
+ keysym = evt.which;
+ } else {
+ // IE9
+ Util.Warn("which not set, using keyCode");
+ keysym = evt.keyCode;
+ }
+
+ if ((keysym > 255) && (keysym < 0xFF00)) {
+ msg = "Mapping character code " + keysym;
+ // Map Unicode outside Latin 1 to X11 keysyms
+ keysym = unicodeTable[keysym];
+ if (typeof(keysym) === 'undefined') {
+ keysym = 0;
+ }
+ Util.Debug(msg + " to " + keysym);
+ }
+
+ return keysym;
+}
+
+function show_keyDownList(kind) {
+ var c;
+ var msg = "keyDownList (" + kind + "):\n";
+ for (c = 0; c < keyDownList.length; c++) {
+ msg = msg + " " + c + " - keyCode: " + keyDownList[c].keyCode +
+ " - which: " + keyDownList[c].which + "\n";
+ }
+ Util.Debug(msg);
+}
+
+function copyKeyEvent(evt) {
+ var members = ['type', 'keyCode', 'charCode', 'which',
+ 'altKey', 'ctrlKey', 'shiftKey',
+ 'keyLocation', 'keyIdentifier'], i, obj = {};
+ for (i = 0; i < members.length; i++) {
+ if (typeof(evt[members[i]]) !== "undefined") {
+ obj[members[i]] = evt[members[i]];
+ }
+ }
+ return obj;
+}
+
+function pushKeyEvent(fevt) {
+ keyDownList.push(fevt);
+}
+
+function getKeyEvent(keyCode, pop) {
+ var i, fevt = null;
+ for (i = keyDownList.length-1; i >= 0; i--) {
+ if (keyDownList[i].keyCode === keyCode) {
+ if ((typeof(pop) !== "undefined") && (pop)) {
+ fevt = keyDownList.splice(i, 1)[0];
+ } else {
+ fevt = keyDownList[i];
+ }
+ break;
+ }
+ }
+ return fevt;
+}
+
+function ignoreKeyEvent(evt) {
+ // Blarg. Some keys have a different keyCode on keyDown vs keyUp
+ if (evt.keyCode === 229) {
+ // French AZERTY keyboard dead key.
+ // Lame thing is that the respective keyUp is 219 so we can't
+ // properly ignore the keyUp event
+ return true;
+ }
+ return false;
+}
+
+
+//
+// Key Event Handling:
+//
+// There are several challenges when dealing with key events:
+// - The meaning and use of keyCode, charCode and which depends on
+// both the browser and the event type (keyDown/Up vs keyPress).
+// - We cannot automatically determine the keyboard layout
+// - The keyDown and keyUp events have a keyCode value that has not
+// been translated by modifier keys.
+// - The keyPress event has a translated (for layout and modifiers)
+// character code but the attribute containing it differs. keyCode
+// contains the translated value in WebKit (Chrome/Safari), Opera
+// 11 and IE9. charCode contains the value in WebKit and Firefox.
+// The which attribute contains the value on WebKit, Firefox and
+// Opera 11.
+// - The keyDown/Up keyCode value indicates (sort of) the physical
+// key was pressed but only for standard US layout. On a US
+// keyboard, the '-' and '_' characters are on the same key and
+// generate a keyCode value of 189. But on an AZERTY keyboard even
+// though they are different physical keys they both still
+// generate a keyCode of 189!
+// - To prevent a key event from propagating to the browser and
+// causing unwanted default actions (such as closing a tab,
+// opening a menu, shifting focus, etc) we must suppress this
+// event in both keyDown and keyPress because not all key strokes
+// generate on a keyPress event. Also, in WebKit and IE9
+// suppressing the keyDown prevents a keyPress but other browsers
+// still generated a keyPress even if keyDown is suppressed.
+//
+// For safe key events, we wait until the keyPress event before
+// reporting a key down event. For unsafe key events, we report a key
+// down event when the keyDown event fires and we suppress any further
+// actions (including keyPress).
+//
+// In order to report a key up event that matches what we reported
+// for the key down event, we keep a list of keys that are currently
+// down. When the keyDown event happens, we add the key event to the
+// list. If it is a safe key event, then we update the which attribute
+// in the most recent item on the list when we received a keyPress
+// event (keyPress should immediately follow keyDown). When we
+// received a keyUp event we search for the event on the list with
+// a matching keyCode and we report the character code using the value
+// in the 'which' attribute that was stored with that key.
+//
+
+function onKeyDown(e) {
+ if (! conf.focused) {
+ return true;
+ }
+ var fevt = null, evt = (e ? e : window.event),
+ keysym = null, suppress = false;
+ //Util.Debug("onKeyDown kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
+
+ fevt = copyKeyEvent(evt);
+
+ keysym = getKeysymSpecial(evt);
+ // Save keysym decoding for use in keyUp
+ fevt.keysym = keysym;
+ if (keysym) {
+ // If it is a key or key combination that might trigger
+ // browser behaviors or it has no corresponding keyPress
+ // event, then send it immediately
+ if (conf.onKeyPress && !ignoreKeyEvent(evt)) {
+ Util.Debug("onKeyPress down, keysym: " + keysym +
+ " (onKeyDown key: " + evt.keyCode +
+ ", which: " + evt.which + ")");
+ conf.onKeyPress(keysym, 1, evt);
+ }
+ suppress = true;
+ }
+
+ if (! ignoreKeyEvent(evt)) {
+ // Add it to the list of depressed keys
+ pushKeyEvent(fevt);
+ //show_keyDownList('down');
+ }
+
+ if (suppress) {
+ // Suppress bubbling/default actions
+ Util.stopEvent(e);
+ return false;
+ } else {
+ // Allow the event to bubble and become a keyPress event which
+ // will have the character code translated
+ return true;
+ }
+}
+
+function onKeyPress(e) {
+ if (! conf.focused) {
+ return true;
+ }
+ var evt = (e ? e : window.event),
+ kdlen = keyDownList.length, keysym = null;
+ //Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
+
+ if (((evt.which !== "undefined") && (evt.which === 0)) ||
+ (getKeysymSpecial(evt))) {
+ // Firefox and Opera generate a keyPress event even if keyDown
+ // is suppressed. But the keys we want to suppress will have
+ // either:
+ // - the which attribute set to 0
+ // - getKeysymSpecial() will identify it
+ Util.Debug("Ignoring special key in keyPress");
+ Util.stopEvent(e);
+ return false;
+ }
+
+ keysym = getKeysym(evt);
+
+ // Modify the the which attribute in the depressed keys list so
+ // that the keyUp event will be able to have the character code
+ // translation available.
+ if (kdlen > 0) {
+ keyDownList[kdlen-1].keysym = keysym;
+ } else {
+ Util.Warn("keyDownList empty when keyPress triggered");
+ }
+
+ //show_keyDownList('press');
+
+ // Send the translated keysym
+ if (conf.onKeyPress && (keysym > 0)) {
+ Util.Debug("onKeyPress down, keysym: " + keysym +
+ " (onKeyPress key: " + evt.keyCode +
+ ", which: " + evt.which + ")");
+ conf.onKeyPress(keysym, 1, evt);
+ }
+
+ // Stop keypress events just in case
+ Util.stopEvent(e);
+ return false;
+}
+
+function onKeyUp(e) {
+ if (! conf.focused) {
+ return true;
+ }
+ var fevt = null, evt = (e ? e : window.event), keysym;
+ //Util.Debug("onKeyUp kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
+
+ fevt = getKeyEvent(evt.keyCode, true);
+
+ if (fevt) {
+ keysym = fevt.keysym;
+ } else {
+ Util.Warn("Key event (keyCode = " + evt.keyCode +
+ ") not found on keyDownList");
+ keysym = 0;
+ }
+
+ //show_keyDownList('up');
+
+ if (conf.onKeyPress && (keysym > 0)) {
+ //Util.Debug("keyPress up, keysym: " + keysym +
+ // " (key: " + evt.keyCode + ", which: " + evt.which + ")");
+ Util.Debug("onKeyPress up, keysym: " + keysym +
+ " (onKeyPress key: " + evt.keyCode +
+ ", which: " + evt.which + ")");
+ conf.onKeyPress(keysym, 0, evt);
+ }
+ Util.stopEvent(e);
+ return false;
+}
+
+function allKeysUp() {
+ Util.Debug(">> Keyboard.allKeysUp");
+ if (keyDownList.length > 0) {
+ Util.Info("Releasing pressed/down keys");
+ }
+ var i, keysym, fevt = null;
+ for (i = keyDownList.length-1; i >= 0; i--) {
+ fevt = keyDownList.splice(i, 1)[0];
+ keysym = fevt.keysym;
+ if (conf.onKeyPress && (keysym > 0)) {
+ Util.Debug("allKeysUp, keysym: " + keysym +
+ " (keyCode: " + fevt.keyCode +
+ ", which: " + fevt.which + ")");
+ conf.onKeyPress(keysym, 0, fevt);
+ }
+ }
+ Util.Debug("<< Keyboard.allKeysUp");
+ return;
+}
+
+//
+// Public API interface functions
+//
+
+that.grab = function() {
+ //Util.Debug(">> Keyboard.grab");
+ var c = conf.target;
+
+ Util.addEvent(c, 'keydown', onKeyDown);
+ Util.addEvent(c, 'keyup', onKeyUp);
+ Util.addEvent(c, 'keypress', onKeyPress);
+
+ // Release (key up) if window loses focus
+ Util.addEvent(window, 'blur', allKeysUp);
+
+ //Util.Debug("<< Keyboard.grab");
+};
+
+that.ungrab = function() {
+ //Util.Debug(">> Keyboard.ungrab");
+ var c = conf.target;
+
+ Util.removeEvent(c, 'keydown', onKeyDown);
+ Util.removeEvent(c, 'keyup', onKeyUp);
+ Util.removeEvent(c, 'keypress', onKeyPress);
+ Util.removeEvent(window, 'blur', allKeysUp);
+
+ // Release (key up) all keys that are in a down state
+ allKeysUp();
+
+ //Util.Debug(">> Keyboard.ungrab");
+};
+
+return that; // Return the public API interface
+
+} // End of Keyboard()
+
+
+//
+// Mouse event handler
+//
+
+function Mouse(defaults) {
+"use strict";
+
+var that = {}, // Public API methods
+ conf = {}, // Configuration attributes
+ mouseCaptured = false;
+
+// Configuration attributes
+Util.conf_defaults(conf, that, defaults, [
+ ['target', 'ro', 'dom', document, 'DOM element that captures mouse input'],
+ ['focused', 'rw', 'bool', true, 'Capture and send mouse clicks/movement'],
+ ['scale', 'rw', 'float', 1.0, 'Viewport scale factor 0.0 - 1.0'],
+
+ ['onMouseButton', 'rw', 'func', null, 'Handler for mouse button click/release'],
+ ['onMouseMove', 'rw', 'func', null, 'Handler for mouse movement'],
+ ['touchButton', 'rw', 'int', 1, 'Button mask (1, 2, 4) for touch devices (0 means ignore clicks)']
+ ]);
+
+function captureMouse() {
+ // capturing the mouse ensures we get the mouseup event
+ if (conf.target.setCapture) {
+ conf.target.setCapture();
+ }
+
+ // some browsers give us mouseup events regardless,
+ // so if we never captured the mouse, we can disregard the event
+ mouseCaptured = true;
+}
+
+function releaseMouse() {
+ if (conf.target.releaseCapture) {
+ conf.target.releaseCapture();
+ }
+ mouseCaptured = false;
+}
+//
+// Private functions
+//
+
+function onMouseButton(e, down) {
+ var evt, pos, bmask;
+ if (! conf.focused) {
+ return true;
+ }
+ evt = (e ? e : window.event);
+ pos = Util.getEventPosition(e, conf.target, conf.scale);
+ if (e.touches || e.changedTouches) {
+ // Touch device
+ bmask = conf.touchButton;
+ // If bmask is set
+ } else if (evt.which) {
+ /* everything except IE */
+ bmask = 1 << evt.button;
+ } else {
+ /* IE including 9 */
+ bmask = (evt.button & 0x1) + // Left
+ (evt.button & 0x2) * 2 + // Right
+ (evt.button & 0x4) / 2; // Middle
+ }
+ //Util.Debug("mouse " + pos.x + "," + pos.y + " down: " + down +
+ // " bmask: " + bmask + "(evt.button: " + evt.button + ")");
+ if (bmask > 0 && conf.onMouseButton) {
+ Util.Debug("onMouseButton " + (down ? "down" : "up") +
+ ", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
+ conf.onMouseButton(pos.x, pos.y, down, bmask);
+ }
+ Util.stopEvent(e);
+ return false;
+}
+
+function onMouseDown(e) {
+ captureMouse();
+ onMouseButton(e, 1);
+}
+
+function onMouseUp(e) {
+ if (!mouseCaptured) {
+ return;
+ }
+
+ onMouseButton(e, 0);
+ releaseMouse();
+}
+
+function onMouseWheel(e) {
+ var evt, pos, bmask, wheelData;
+ if (! conf.focused) {
+ return true;
+ }
+ evt = (e ? e : window.event);
+ pos = Util.getEventPosition(e, conf.target, conf.scale);
+ wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
+ if (wheelData > 0) {
+ bmask = 1 << 3;
+ } else {
+ bmask = 1 << 4;
+ }
+ //Util.Debug('mouse scroll by ' + wheelData + ':' + pos.x + "," + pos.y);
+ if (conf.onMouseButton) {
+ conf.onMouseButton(pos.x, pos.y, 1, bmask);
+ conf.onMouseButton(pos.x, pos.y, 0, bmask);
+ }
+ Util.stopEvent(e);
+ return false;
+}
+
+function onMouseMove(e) {
+ var evt, pos;
+ if (! conf.focused) {
+ return true;
+ }
+ evt = (e ? e : window.event);
+ pos = Util.getEventPosition(e, conf.target, conf.scale);
+ //Util.Debug('mouse ' + evt.which + '/' + evt.button + ' up:' + pos.x + "," + pos.y);
+ if (conf.onMouseMove) {
+ conf.onMouseMove(pos.x, pos.y);
+ }
+ Util.stopEvent(e);
+ return false;
+}
+
+function onMouseDisable(e) {
+ var evt, pos;
+ if (! conf.focused) {
+ return true;
+ }
+ evt = (e ? e : window.event);
+ pos = Util.getEventPosition(e, conf.target, conf.scale);
+ /* Stop propagation if inside canvas area */
+ if ((pos.x >= 0) && (pos.y >= 0) &&
+ (pos.x < conf.target.offsetWidth) &&
+ (pos.y < conf.target.offsetHeight)) {
+ //Util.Debug("mouse event disabled");
+ Util.stopEvent(e);
+ return false;
+ }
+ //Util.Debug("mouse event not disabled");
+ return true;
+}
+
+//
+// Public API interface functions
+//
+
+that.grab = function() {
+ //Util.Debug(">> Mouse.grab");
+ var c = conf.target;
+
+ if ('ontouchstart' in document.documentElement) {
+ Util.addEvent(c, 'touchstart', onMouseDown);
+ Util.addEvent(window, 'touchend', onMouseUp);
+ Util.addEvent(c, 'touchend', onMouseUp);
+ Util.addEvent(c, 'touchmove', onMouseMove);
+ } else {
+ Util.addEvent(c, 'mousedown', onMouseDown);
+ Util.addEvent(window, 'mouseup', onMouseUp);
+ Util.addEvent(c, 'mouseup', onMouseUp);
+ Util.addEvent(c, 'mousemove', onMouseMove);
+ Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
+ onMouseWheel);
+ }
+
+ /* Work around right and middle click browser behaviors */
+ Util.addEvent(document, 'click', onMouseDisable);
+ Util.addEvent(document.body, 'contextmenu', onMouseDisable);
+
+ //Util.Debug("<< Mouse.grab");
+};
+
+that.ungrab = function() {
+ //Util.Debug(">> Mouse.ungrab");
+ var c = conf.target;
+
+ if ('ontouchstart' in document.documentElement) {
+ Util.removeEvent(c, 'touchstart', onMouseDown);
+ Util.removeEvent(window, 'touchend', onMouseUp);
+ Util.removeEvent(c, 'touchend', onMouseUp);
+ Util.removeEvent(c, 'touchmove', onMouseMove);
+ } else {
+ Util.removeEvent(c, 'mousedown', onMouseDown);
+ Util.removeEvent(window, 'mouseup', onMouseUp);
+ Util.removeEvent(c, 'mouseup', onMouseUp);
+ Util.removeEvent(c, 'mousemove', onMouseMove);
+ Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
+ onMouseWheel);
+ }
+
+ /* Work around right and middle click browser behaviors */
+ Util.removeEvent(document, 'click', onMouseDisable);
+ Util.removeEvent(document.body, 'contextmenu', onMouseDisable);
+
+ //Util.Debug(">> Mouse.ungrab");
+};
+
+return that; // Return the public API interface
+
+} // End of Mouse()
+
+
+/*
+ * Browser keypress to X11 keysym for Unicode characters > U+00FF
+ */
+unicodeTable = {
+ 0x0104 : 0x01a1,
+ 0x02D8 : 0x01a2,
+ 0x0141 : 0x01a3,
+ 0x013D : 0x01a5,
+ 0x015A : 0x01a6,
+ 0x0160 : 0x01a9,
+ 0x015E : 0x01aa,
+ 0x0164 : 0x01ab,
+ 0x0179 : 0x01ac,
+ 0x017D : 0x01ae,
+ 0x017B : 0x01af,
+ 0x0105 : 0x01b1,
+ 0x02DB : 0x01b2,
+ 0x0142 : 0x01b3,
+ 0x013E : 0x01b5,
+ 0x015B : 0x01b6,
+ 0x02C7 : 0x01b7,
+ 0x0161 : 0x01b9,
+ 0x015F : 0x01ba,
+ 0x0165 : 0x01bb,
+ 0x017A : 0x01bc,
+ 0x02DD : 0x01bd,
+ 0x017E : 0x01be,
+ 0x017C : 0x01bf,
+ 0x0154 : 0x01c0,
+ 0x0102 : 0x01c3,
+ 0x0139 : 0x01c5,
+ 0x0106 : 0x01c6,
+ 0x010C : 0x01c8,
+ 0x0118 : 0x01ca,
+ 0x011A : 0x01cc,
+ 0x010E : 0x01cf,
+ 0x0110 : 0x01d0,
+ 0x0143 : 0x01d1,
+ 0x0147 : 0x01d2,
+ 0x0150 : 0x01d5,
+ 0x0158 : 0x01d8,
+ 0x016E : 0x01d9,
+ 0x0170 : 0x01db,
+ 0x0162 : 0x01de,
+ 0x0155 : 0x01e0,
+ 0x0103 : 0x01e3,
+ 0x013A : 0x01e5,
+ 0x0107 : 0x01e6,
+ 0x010D : 0x01e8,
+ 0x0119 : 0x01ea,
+ 0x011B : 0x01ec,
+ 0x010F : 0x01ef,
+ 0x0111 : 0x01f0,
+ 0x0144 : 0x01f1,
+ 0x0148 : 0x01f2,
+ 0x0151 : 0x01f5,
+ 0x0171 : 0x01fb,
+ 0x0159 : 0x01f8,
+ 0x016F : 0x01f9,
+ 0x0163 : 0x01fe,
+ 0x02D9 : 0x01ff,
+ 0x0126 : 0x02a1,
+ 0x0124 : 0x02a6,
+ 0x0130 : 0x02a9,
+ 0x011E : 0x02ab,
+ 0x0134 : 0x02ac,
+ 0x0127 : 0x02b1,
+ 0x0125 : 0x02b6,
+ 0x0131 : 0x02b9,
+ 0x011F : 0x02bb,
+ 0x0135 : 0x02bc,
+ 0x010A : 0x02c5,
+ 0x0108 : 0x02c6,
+ 0x0120 : 0x02d5,
+ 0x011C : 0x02d8,
+ 0x016C : 0x02dd,
+ 0x015C : 0x02de,
+ 0x010B : 0x02e5,
+ 0x0109 : 0x02e6,
+ 0x0121 : 0x02f5,
+ 0x011D : 0x02f8,
+ 0x016D : 0x02fd,
+ 0x015D : 0x02fe,
+ 0x0138 : 0x03a2,
+ 0x0156 : 0x03a3,
+ 0x0128 : 0x03a5,
+ 0x013B : 0x03a6,
+ 0x0112 : 0x03aa,
+ 0x0122 : 0x03ab,
+ 0x0166 : 0x03ac,
+ 0x0157 : 0x03b3,
+ 0x0129 : 0x03b5,
+ 0x013C : 0x03b6,
+ 0x0113 : 0x03ba,
+ 0x0123 : 0x03bb,
+ 0x0167 : 0x03bc,
+ 0x014A : 0x03bd,
+ 0x014B : 0x03bf,
+ 0x0100 : 0x03c0,
+ 0x012E : 0x03c7,
+ 0x0116 : 0x03cc,
+ 0x012A : 0x03cf,
+ 0x0145 : 0x03d1,
+ 0x014C : 0x03d2,
+ 0x0136 : 0x03d3,
+ 0x0172 : 0x03d9,
+ 0x0168 : 0x03dd,
+ 0x016A : 0x03de,
+ 0x0101 : 0x03e0,
+ 0x012F : 0x03e7,
+ 0x0117 : 0x03ec,
+ 0x012B : 0x03ef,
+ 0x0146 : 0x03f1,
+ 0x014D : 0x03f2,
+ 0x0137 : 0x03f3,
+ 0x0173 : 0x03f9,
+ 0x0169 : 0x03fd,
+ 0x016B : 0x03fe,
+ 0x1E02 : 0x1001e02,
+ 0x1E03 : 0x1001e03,
+ 0x1E0A : 0x1001e0a,
+ 0x1E80 : 0x1001e80,
+ 0x1E82 : 0x1001e82,
+ 0x1E0B : 0x1001e0b,
+ 0x1EF2 : 0x1001ef2,
+ 0x1E1E : 0x1001e1e,
+ 0x1E1F : 0x1001e1f,
+ 0x1E40 : 0x1001e40,
+ 0x1E41 : 0x1001e41,
+ 0x1E56 : 0x1001e56,
+ 0x1E81 : 0x1001e81,
+ 0x1E57 : 0x1001e57,
+ 0x1E83 : 0x1001e83,
+ 0x1E60 : 0x1001e60,
+ 0x1EF3 : 0x1001ef3,
+ 0x1E84 : 0x1001e84,
+ 0x1E85 : 0x1001e85,
+ 0x1E61 : 0x1001e61,
+ 0x0174 : 0x1000174,
+ 0x1E6A : 0x1001e6a,
+ 0x0176 : 0x1000176,
+ 0x0175 : 0x1000175,
+ 0x1E6B : 0x1001e6b,
+ 0x0177 : 0x1000177,
+ 0x0152 : 0x13bc,
+ 0x0153 : 0x13bd,
+ 0x0178 : 0x13be,
+ 0x203E : 0x047e,
+ 0x3002 : 0x04a1,
+ 0x300C : 0x04a2,
+ 0x300D : 0x04a3,
+ 0x3001 : 0x04a4,
+ 0x30FB : 0x04a5,
+ 0x30F2 : 0x04a6,
+ 0x30A1 : 0x04a7,
+ 0x30A3 : 0x04a8,
+ 0x30A5 : 0x04a9,
+ 0x30A7 : 0x04aa,
+ 0x30A9 : 0x04ab,
+ 0x30E3 : 0x04ac,
+ 0x30E5 : 0x04ad,
+ 0x30E7 : 0x04ae,
+ 0x30C3 : 0x04af,
+ 0x30FC : 0x04b0,
+ 0x30A2 : 0x04b1,
+ 0x30A4 : 0x04b2,
+ 0x30A6 : 0x04b3,
+ 0x30A8 : 0x04b4,
+ 0x30AA : 0x04b5,
+ 0x30AB : 0x04b6,
+ 0x30AD : 0x04b7,
+ 0x30AF : 0x04b8,
+ 0x30B1 : 0x04b9,
+ 0x30B3 : 0x04ba,
+ 0x30B5 : 0x04bb,
+ 0x30B7 : 0x04bc,
+ 0x30B9 : 0x04bd,
+ 0x30BB : 0x04be,
+ 0x30BD : 0x04bf,
+ 0x30BF : 0x04c0,
+ 0x30C1 : 0x04c1,
+ 0x30C4 : 0x04c2,
+ 0x30C6 : 0x04c3,
+ 0x30C8 : 0x04c4,
+ 0x30CA : 0x04c5,
+ 0x30CB : 0x04c6,
+ 0x30CC : 0x04c7,
+ 0x30CD : 0x04c8,
+ 0x30CE : 0x04c9,
+ 0x30CF : 0x04ca,
+ 0x30D2 : 0x04cb,
+ 0x30D5 : 0x04cc,
+ 0x30D8 : 0x04cd,
+ 0x30DB : 0x04ce,
+ 0x30DE : 0x04cf,
+ 0x30DF : 0x04d0,
+ 0x30E0 : 0x04d1,
+ 0x30E1 : 0x04d2,
+ 0x30E2 : 0x04d3,
+ 0x30E4 : 0x04d4,
+ 0x30E6 : 0x04d5,
+ 0x30E8 : 0x04d6,
+ 0x30E9 : 0x04d7,
+ 0x30EA : 0x04d8,
+ 0x30EB : 0x04d9,
+ 0x30EC : 0x04da,
+ 0x30ED : 0x04db,
+ 0x30EF : 0x04dc,
+ 0x30F3 : 0x04dd,
+ 0x309B : 0x04de,
+ 0x309C : 0x04df,
+ 0x06F0 : 0x10006f0,
+ 0x06F1 : 0x10006f1,
+ 0x06F2 : 0x10006f2,
+ 0x06F3 : 0x10006f3,
+ 0x06F4 : 0x10006f4,
+ 0x06F5 : 0x10006f5,
+ 0x06F6 : 0x10006f6,
+ 0x06F7 : 0x10006f7,
+ 0x06F8 : 0x10006f8,
+ 0x06F9 : 0x10006f9,
+ 0x066A : 0x100066a,
+ 0x0670 : 0x1000670,
+ 0x0679 : 0x1000679,
+ 0x067E : 0x100067e,
+ 0x0686 : 0x1000686,
+ 0x0688 : 0x1000688,
+ 0x0691 : 0x1000691,
+ 0x060C : 0x05ac,
+ 0x06D4 : 0x10006d4,
+ 0x0660 : 0x1000660,
+ 0x0661 : 0x1000661,
+ 0x0662 : 0x1000662,
+ 0x0663 : 0x1000663,
+ 0x0664 : 0x1000664,
+ 0x0665 : 0x1000665,
+ 0x0666 : 0x1000666,
+ 0x0667 : 0x1000667,
+ 0x0668 : 0x1000668,
+ 0x0669 : 0x1000669,
+ 0x061B : 0x05bb,
+ 0x061F : 0x05bf,
+ 0x0621 : 0x05c1,
+ 0x0622 : 0x05c2,
+ 0x0623 : 0x05c3,
+ 0x0624 : 0x05c4,
+ 0x0625 : 0x05c5,
+ 0x0626 : 0x05c6,
+ 0x0627 : 0x05c7,
+ 0x0628 : 0x05c8,
+ 0x0629 : 0x05c9,
+ 0x062A : 0x05ca,
+ 0x062B : 0x05cb,
+ 0x062C : 0x05cc,
+ 0x062D : 0x05cd,
+ 0x062E : 0x05ce,
+ 0x062F : 0x05cf,
+ 0x0630 : 0x05d0,
+ 0x0631 : 0x05d1,
+ 0x0632 : 0x05d2,
+ 0x0633 : 0x05d3,
+ 0x0634 : 0x05d4,
+ 0x0635 : 0x05d5,
+ 0x0636 : 0x05d6,
+ 0x0637 : 0x05d7,
+ 0x0638 : 0x05d8,
+ 0x0639 : 0x05d9,
+ 0x063A : 0x05da,
+ 0x0640 : 0x05e0,
+ 0x0641 : 0x05e1,
+ 0x0642 : 0x05e2,
+ 0x0643 : 0x05e3,
+ 0x0644 : 0x05e4,
+ 0x0645 : 0x05e5,
+ 0x0646 : 0x05e6,
+ 0x0647 : 0x05e7,
+ 0x0648 : 0x05e8,
+ 0x0649 : 0x05e9,
+ 0x064A : 0x05ea,
+ 0x064B : 0x05eb,
+ 0x064C : 0x05ec,
+ 0x064D : 0x05ed,
+ 0x064E : 0x05ee,
+ 0x064F : 0x05ef,
+ 0x0650 : 0x05f0,
+ 0x0651 : 0x05f1,
+ 0x0652 : 0x05f2,
+ 0x0653 : 0x1000653,
+ 0x0654 : 0x1000654,
+ 0x0655 : 0x1000655,
+ 0x0698 : 0x1000698,
+ 0x06A4 : 0x10006a4,
+ 0x06A9 : 0x10006a9,
+ 0x06AF : 0x10006af,
+ 0x06BA : 0x10006ba,
+ 0x06BE : 0x10006be,
+ 0x06CC : 0x10006cc,
+ 0x06D2 : 0x10006d2,
+ 0x06C1 : 0x10006c1,
+ 0x0492 : 0x1000492,
+ 0x0493 : 0x1000493,
+ 0x0496 : 0x1000496,
+ 0x0497 : 0x1000497,
+ 0x049A : 0x100049a,
+ 0x049B : 0x100049b,
+ 0x049C : 0x100049c,
+ 0x049D : 0x100049d,
+ 0x04A2 : 0x10004a2,
+ 0x04A3 : 0x10004a3,
+ 0x04AE : 0x10004ae,
+ 0x04AF : 0x10004af,
+ 0x04B0 : 0x10004b0,
+ 0x04B1 : 0x10004b1,
+ 0x04B2 : 0x10004b2,
+ 0x04B3 : 0x10004b3,
+ 0x04B6 : 0x10004b6,
+ 0x04B7 : 0x10004b7,
+ 0x04B8 : 0x10004b8,
+ 0x04B9 : 0x10004b9,
+ 0x04BA : 0x10004ba,
+ 0x04BB : 0x10004bb,
+ 0x04D8 : 0x10004d8,
+ 0x04D9 : 0x10004d9,
+ 0x04E2 : 0x10004e2,
+ 0x04E3 : 0x10004e3,
+ 0x04E8 : 0x10004e8,
+ 0x04E9 : 0x10004e9,
+ 0x04EE : 0x10004ee,
+ 0x04EF : 0x10004ef,
+ 0x0452 : 0x06a1,
+ 0x0453 : 0x06a2,
+ 0x0451 : 0x06a3,
+ 0x0454 : 0x06a4,
+ 0x0455 : 0x06a5,
+ 0x0456 : 0x06a6,
+ 0x0457 : 0x06a7,
+ 0x0458 : 0x06a8,
+ 0x0459 : 0x06a9,
+ 0x045A : 0x06aa,
+ 0x045B : 0x06ab,
+ 0x045C : 0x06ac,
+ 0x0491 : 0x06ad,
+ 0x045E : 0x06ae,
+ 0x045F : 0x06af,
+ 0x2116 : 0x06b0,
+ 0x0402 : 0x06b1,
+ 0x0403 : 0x06b2,
+ 0x0401 : 0x06b3,
+ 0x0404 : 0x06b4,
+ 0x0405 : 0x06b5,
+ 0x0406 : 0x06b6,
+ 0x0407 : 0x06b7,
+ 0x0408 : 0x06b8,
+ 0x0409 : 0x06b9,
+ 0x040A : 0x06ba,
+ 0x040B : 0x06bb,
+ 0x040C : 0x06bc,
+ 0x0490 : 0x06bd,
+ 0x040E : 0x06be,
+ 0x040F : 0x06bf,
+ 0x044E : 0x06c0,
+ 0x0430 : 0x06c1,
+ 0x0431 : 0x06c2,
+ 0x0446 : 0x06c3,
+ 0x0434 : 0x06c4,
+ 0x0435 : 0x06c5,
+ 0x0444 : 0x06c6,
+ 0x0433 : 0x06c7,
+ 0x0445 : 0x06c8,
+ 0x0438 : 0x06c9,
+ 0x0439 : 0x06ca,
+ 0x043A : 0x06cb,
+ 0x043B : 0x06cc,
+ 0x043C : 0x06cd,
+ 0x043D : 0x06ce,
+ 0x043E : 0x06cf,
+ 0x043F : 0x06d0,
+ 0x044F : 0x06d1,
+ 0x0440 : 0x06d2,
+ 0x0441 : 0x06d3,
+ 0x0442 : 0x06d4,
+ 0x0443 : 0x06d5,
+ 0x0436 : 0x06d6,
+ 0x0432 : 0x06d7,
+ 0x044C : 0x06d8,
+ 0x044B : 0x06d9,
+ 0x0437 : 0x06da,
+ 0x0448 : 0x06db,
+ 0x044D : 0x06dc,
+ 0x0449 : 0x06dd,
+ 0x0447 : 0x06de,
+ 0x044A : 0x06df,
+ 0x042E : 0x06e0,
+ 0x0410 : 0x06e1,
+ 0x0411 : 0x06e2,
+ 0x0426 : 0x06e3,
+ 0x0414 : 0x06e4,
+ 0x0415 : 0x06e5,
+ 0x0424 : 0x06e6,
+ 0x0413 : 0x06e7,
+ 0x0425 : 0x06e8,
+ 0x0418 : 0x06e9,
+ 0x0419 : 0x06ea,
+ 0x041A : 0x06eb,
+ 0x041B : 0x06ec,
+ 0x041C : 0x06ed,
+ 0x041D : 0x06ee,
+ 0x041E : 0x06ef,
+ 0x041F : 0x06f0,
+ 0x042F : 0x06f1,
+ 0x0420 : 0x06f2,
+ 0x0421 : 0x06f3,
+ 0x0422 : 0x06f4,
+ 0x0423 : 0x06f5,
+ 0x0416 : 0x06f6,
+ 0x0412 : 0x06f7,
+ 0x042C : 0x06f8,
+ 0x042B : 0x06f9,
+ 0x0417 : 0x06fa,
+ 0x0428 : 0x06fb,
+ 0x042D : 0x06fc,
+ 0x0429 : 0x06fd,
+ 0x0427 : 0x06fe,
+ 0x042A : 0x06ff,
+ 0x0386 : 0x07a1,
+ 0x0388 : 0x07a2,
+ 0x0389 : 0x07a3,
+ 0x038A : 0x07a4,
+ 0x03AA : 0x07a5,
+ 0x038C : 0x07a7,
+ 0x038E : 0x07a8,
+ 0x03AB : 0x07a9,
+ 0x038F : 0x07ab,
+ 0x0385 : 0x07ae,
+ 0x2015 : 0x07af,
+ 0x03AC : 0x07b1,
+ 0x03AD : 0x07b2,
+ 0x03AE : 0x07b3,
+ 0x03AF : 0x07b4,
+ 0x03CA : 0x07b5,
+ 0x0390 : 0x07b6,
+ 0x03CC : 0x07b7,
+ 0x03CD : 0x07b8,
+ 0x03CB : 0x07b9,
+ 0x03B0 : 0x07ba,
+ 0x03CE : 0x07bb,
+ 0x0391 : 0x07c1,
+ 0x0392 : 0x07c2,
+ 0x0393 : 0x07c3,
+ 0x0394 : 0x07c4,
+ 0x0395 : 0x07c5,
+ 0x0396 : 0x07c6,
+ 0x0397 : 0x07c7,
+ 0x0398 : 0x07c8,
+ 0x0399 : 0x07c9,
+ 0x039A : 0x07ca,
+ 0x039B : 0x07cb,
+ 0x039C : 0x07cc,
+ 0x039D : 0x07cd,
+ 0x039E : 0x07ce,
+ 0x039F : 0x07cf,
+ 0x03A0 : 0x07d0,
+ 0x03A1 : 0x07d1,
+ 0x03A3 : 0x07d2,
+ 0x03A4 : 0x07d4,
+ 0x03A5 : 0x07d5,
+ 0x03A6 : 0x07d6,
+ 0x03A7 : 0x07d7,
+ 0x03A8 : 0x07d8,
+ 0x03A9 : 0x07d9,
+ 0x03B1 : 0x07e1,
+ 0x03B2 : 0x07e2,
+ 0x03B3 : 0x07e3,
+ 0x03B4 : 0x07e4,
+ 0x03B5 : 0x07e5,
+ 0x03B6 : 0x07e6,
+ 0x03B7 : 0x07e7,
+ 0x03B8 : 0x07e8,
+ 0x03B9 : 0x07e9,
+ 0x03BA : 0x07ea,
+ 0x03BB : 0x07eb,
+ 0x03BC : 0x07ec,
+ 0x03BD : 0x07ed,
+ 0x03BE : 0x07ee,
+ 0x03BF : 0x07ef,
+ 0x03C0 : 0x07f0,
+ 0x03C1 : 0x07f1,
+ 0x03C3 : 0x07f2,
+ 0x03C2 : 0x07f3,
+ 0x03C4 : 0x07f4,
+ 0x03C5 : 0x07f5,
+ 0x03C6 : 0x07f6,
+ 0x03C7 : 0x07f7,
+ 0x03C8 : 0x07f8,
+ 0x03C9 : 0x07f9,
+ 0x23B7 : 0x08a1,
+ 0x2320 : 0x08a4,
+ 0x2321 : 0x08a5,
+ 0x23A1 : 0x08a7,
+ 0x23A3 : 0x08a8,
+ 0x23A4 : 0x08a9,
+ 0x23A6 : 0x08aa,
+ 0x239B : 0x08ab,
+ 0x239D : 0x08ac,
+ 0x239E : 0x08ad,
+ 0x23A0 : 0x08ae,
+ 0x23A8 : 0x08af,
+ 0x23AC : 0x08b0,
+ 0x2264 : 0x08bc,
+ 0x2260 : 0x08bd,
+ 0x2265 : 0x08be,
+ 0x222B : 0x08bf,
+ 0x2234 : 0x08c0,
+ 0x221D : 0x08c1,
+ 0x221E : 0x08c2,
+ 0x2207 : 0x08c5,
+ 0x223C : 0x08c8,
+ 0x2243 : 0x08c9,
+ 0x21D4 : 0x08cd,
+ 0x21D2 : 0x08ce,
+ 0x2261 : 0x08cf,
+ //0x221A : 0x08d6,
+ 0x2282 : 0x08da,
+ 0x2283 : 0x08db,
+ 0x2229 : 0x08dc,
+ 0x222A : 0x08dd,
+ 0x2227 : 0x08de,
+ 0x2228 : 0x08df,
+ //0x2202 : 0x08ef,
+ 0x0192 : 0x08f6,
+ 0x2190 : 0x08fb,
+ 0x2191 : 0x08fc,
+ 0x2192 : 0x08fd,
+ 0x2193 : 0x08fe,
+ 0x25C6 : 0x09e0,
+ 0x2592 : 0x09e1,
+ 0x2409 : 0x09e2,
+ 0x240C : 0x09e3,
+ 0x240D : 0x09e4,
+ 0x240A : 0x09e5,
+ 0x2424 : 0x09e8,
+ 0x240B : 0x09e9,
+ 0x2518 : 0x09ea,
+ 0x2510 : 0x09eb,
+ 0x250C : 0x09ec,
+ 0x2514 : 0x09ed,
+ 0x253C : 0x09ee,
+ 0x23BA : 0x09ef,
+ 0x23BB : 0x09f0,
+ 0x2500 : 0x09f1,
+ 0x23BC : 0x09f2,
+ 0x23BD : 0x09f3,
+ 0x251C : 0x09f4,
+ 0x2524 : 0x09f5,
+ 0x2534 : 0x09f6,
+ 0x252C : 0x09f7,
+ 0x2502 : 0x09f8,
+ 0x2003 : 0x0aa1,
+ 0x2002 : 0x0aa2,
+ 0x2004 : 0x0aa3,
+ 0x2005 : 0x0aa4,
+ 0x2007 : 0x0aa5,
+ 0x2008 : 0x0aa6,
+ 0x2009 : 0x0aa7,
+ 0x200A : 0x0aa8,
+ 0x2014 : 0x0aa9,
+ 0x2013 : 0x0aaa,
+ 0x2026 : 0x0aae,
+ 0x2025 : 0x0aaf,
+ 0x2153 : 0x0ab0,
+ 0x2154 : 0x0ab1,
+ 0x2155 : 0x0ab2,
+ 0x2156 : 0x0ab3,
+ 0x2157 : 0x0ab4,
+ 0x2158 : 0x0ab5,
+ 0x2159 : 0x0ab6,
+ 0x215A : 0x0ab7,
+ 0x2105 : 0x0ab8,
+ 0x2012 : 0x0abb,
+ 0x215B : 0x0ac3,
+ 0x215C : 0x0ac4,
+ 0x215D : 0x0ac5,
+ 0x215E : 0x0ac6,
+ 0x2122 : 0x0ac9,
+ 0x2018 : 0x0ad0,
+ 0x2019 : 0x0ad1,
+ 0x201C : 0x0ad2,
+ 0x201D : 0x0ad3,
+ 0x211E : 0x0ad4,
+ 0x2032 : 0x0ad6,
+ 0x2033 : 0x0ad7,
+ 0x271D : 0x0ad9,
+ 0x2663 : 0x0aec,
+ 0x2666 : 0x0aed,
+ 0x2665 : 0x0aee,
+ 0x2720 : 0x0af0,
+ 0x2020 : 0x0af1,
+ 0x2021 : 0x0af2,
+ 0x2713 : 0x0af3,
+ 0x2717 : 0x0af4,
+ 0x266F : 0x0af5,
+ 0x266D : 0x0af6,
+ 0x2642 : 0x0af7,
+ 0x2640 : 0x0af8,
+ 0x260E : 0x0af9,
+ 0x2315 : 0x0afa,
+ 0x2117 : 0x0afb,
+ 0x2038 : 0x0afc,
+ 0x201A : 0x0afd,
+ 0x201E : 0x0afe,
+ 0x22A4 : 0x0bc2,
+ 0x230A : 0x0bc4,
+ 0x2218 : 0x0bca,
+ 0x2395 : 0x0bcc,
+ 0x22A5 : 0x0bce,
+ 0x25CB : 0x0bcf,
+ 0x2308 : 0x0bd3,
+ 0x22A3 : 0x0bdc,
+ 0x22A2 : 0x0bfc,
+ 0x2017 : 0x0cdf,
+ 0x05D0 : 0x0ce0,
+ 0x05D1 : 0x0ce1,
+ 0x05D2 : 0x0ce2,
+ 0x05D3 : 0x0ce3,
+ 0x05D4 : 0x0ce4,
+ 0x05D5 : 0x0ce5,
+ 0x05D6 : 0x0ce6,
+ 0x05D7 : 0x0ce7,
+ 0x05D8 : 0x0ce8,
+ 0x05D9 : 0x0ce9,
+ 0x05DA : 0x0cea,
+ 0x05DB : 0x0ceb,
+ 0x05DC : 0x0cec,
+ 0x05DD : 0x0ced,
+ 0x05DE : 0x0cee,
+ 0x05DF : 0x0cef,
+ 0x05E0 : 0x0cf0,
+ 0x05E1 : 0x0cf1,
+ 0x05E2 : 0x0cf2,
+ 0x05E3 : 0x0cf3,
+ 0x05E4 : 0x0cf4,
+ 0x05E5 : 0x0cf5,
+ 0x05E6 : 0x0cf6,
+ 0x05E7 : 0x0cf7,
+ 0x05E8 : 0x0cf8,
+ 0x05E9 : 0x0cf9,
+ 0x05EA : 0x0cfa,
+ 0x0E01 : 0x0da1,
+ 0x0E02 : 0x0da2,
+ 0x0E03 : 0x0da3,
+ 0x0E04 : 0x0da4,
+ 0x0E05 : 0x0da5,
+ 0x0E06 : 0x0da6,
+ 0x0E07 : 0x0da7,
+ 0x0E08 : 0x0da8,
+ 0x0E09 : 0x0da9,
+ 0x0E0A : 0x0daa,
+ 0x0E0B : 0x0dab,
+ 0x0E0C : 0x0dac,
+ 0x0E0D : 0x0dad,
+ 0x0E0E : 0x0dae,
+ 0x0E0F : 0x0daf,
+ 0x0E10 : 0x0db0,
+ 0x0E11 : 0x0db1,
+ 0x0E12 : 0x0db2,
+ 0x0E13 : 0x0db3,
+ 0x0E14 : 0x0db4,
+ 0x0E15 : 0x0db5,
+ 0x0E16 : 0x0db6,
+ 0x0E17 : 0x0db7,
+ 0x0E18 : 0x0db8,
+ 0x0E19 : 0x0db9,
+ 0x0E1A : 0x0dba,
+ 0x0E1B : 0x0dbb,
+ 0x0E1C : 0x0dbc,
+ 0x0E1D : 0x0dbd,
+ 0x0E1E : 0x0dbe,
+ 0x0E1F : 0x0dbf,
+ 0x0E20 : 0x0dc0,
+ 0x0E21 : 0x0dc1,
+ 0x0E22 : 0x0dc2,
+ 0x0E23 : 0x0dc3,
+ 0x0E24 : 0x0dc4,
+ 0x0E25 : 0x0dc5,
+ 0x0E26 : 0x0dc6,
+ 0x0E27 : 0x0dc7,
+ 0x0E28 : 0x0dc8,
+ 0x0E29 : 0x0dc9,
+ 0x0E2A : 0x0dca,
+ 0x0E2B : 0x0dcb,
+ 0x0E2C : 0x0dcc,
+ 0x0E2D : 0x0dcd,
+ 0x0E2E : 0x0dce,
+ 0x0E2F : 0x0dcf,
+ 0x0E30 : 0x0dd0,
+ 0x0E31 : 0x0dd1,
+ 0x0E32 : 0x0dd2,
+ 0x0E33 : 0x0dd3,
+ 0x0E34 : 0x0dd4,
+ 0x0E35 : 0x0dd5,
+ 0x0E36 : 0x0dd6,
+ 0x0E37 : 0x0dd7,
+ 0x0E38 : 0x0dd8,
+ 0x0E39 : 0x0dd9,
+ 0x0E3A : 0x0dda,
+ 0x0E3F : 0x0ddf,
+ 0x0E40 : 0x0de0,
+ 0x0E41 : 0x0de1,
+ 0x0E42 : 0x0de2,
+ 0x0E43 : 0x0de3,
+ 0x0E44 : 0x0de4,
+ 0x0E45 : 0x0de5,
+ 0x0E46 : 0x0de6,
+ 0x0E47 : 0x0de7,
+ 0x0E48 : 0x0de8,
+ 0x0E49 : 0x0de9,
+ 0x0E4A : 0x0dea,
+ 0x0E4B : 0x0deb,
+ 0x0E4C : 0x0dec,
+ 0x0E4D : 0x0ded,
+ 0x0E50 : 0x0df0,
+ 0x0E51 : 0x0df1,
+ 0x0E52 : 0x0df2,
+ 0x0E53 : 0x0df3,
+ 0x0E54 : 0x0df4,
+ 0x0E55 : 0x0df5,
+ 0x0E56 : 0x0df6,
+ 0x0E57 : 0x0df7,
+ 0x0E58 : 0x0df8,
+ 0x0E59 : 0x0df9,
+ 0x0587 : 0x1000587,
+ 0x0589 : 0x1000589,
+ 0x055D : 0x100055d,
+ 0x058A : 0x100058a,
+ 0x055C : 0x100055c,
+ 0x055B : 0x100055b,
+ 0x055E : 0x100055e,
+ 0x0531 : 0x1000531,
+ 0x0561 : 0x1000561,
+ 0x0532 : 0x1000532,
+ 0x0562 : 0x1000562,
+ 0x0533 : 0x1000533,
+ 0x0563 : 0x1000563,
+ 0x0534 : 0x1000534,
+ 0x0564 : 0x1000564,
+ 0x0535 : 0x1000535,
+ 0x0565 : 0x1000565,
+ 0x0536 : 0x1000536,
+ 0x0566 : 0x1000566,
+ 0x0537 : 0x1000537,
+ 0x0567 : 0x1000567,
+ 0x0538 : 0x1000538,
+ 0x0568 : 0x1000568,
+ 0x0539 : 0x1000539,
+ 0x0569 : 0x1000569,
+ 0x053A : 0x100053a,
+ 0x056A : 0x100056a,
+ 0x053B : 0x100053b,
+ 0x056B : 0x100056b,
+ 0x053C : 0x100053c,
+ 0x056C : 0x100056c,
+ 0x053D : 0x100053d,
+ 0x056D : 0x100056d,
+ 0x053E : 0x100053e,
+ 0x056E : 0x100056e,
+ 0x053F : 0x100053f,
+ 0x056F : 0x100056f,
+ 0x0540 : 0x1000540,
+ 0x0570 : 0x1000570,
+ 0x0541 : 0x1000541,
+ 0x0571 : 0x1000571,
+ 0x0542 : 0x1000542,
+ 0x0572 : 0x1000572,
+ 0x0543 : 0x1000543,
+ 0x0573 : 0x1000573,
+ 0x0544 : 0x1000544,
+ 0x0574 : 0x1000574,
+ 0x0545 : 0x1000545,
+ 0x0575 : 0x1000575,
+ 0x0546 : 0x1000546,
+ 0x0576 : 0x1000576,
+ 0x0547 : 0x1000547,
+ 0x0577 : 0x1000577,
+ 0x0548 : 0x1000548,
+ 0x0578 : 0x1000578,
+ 0x0549 : 0x1000549,
+ 0x0579 : 0x1000579,
+ 0x054A : 0x100054a,
+ 0x057A : 0x100057a,
+ 0x054B : 0x100054b,
+ 0x057B : 0x100057b,
+ 0x054C : 0x100054c,
+ 0x057C : 0x100057c,
+ 0x054D : 0x100054d,
+ 0x057D : 0x100057d,
+ 0x054E : 0x100054e,
+ 0x057E : 0x100057e,
+ 0x054F : 0x100054f,
+ 0x057F : 0x100057f,
+ 0x0550 : 0x1000550,
+ 0x0580 : 0x1000580,
+ 0x0551 : 0x1000551,
+ 0x0581 : 0x1000581,
+ 0x0552 : 0x1000552,
+ 0x0582 : 0x1000582,
+ 0x0553 : 0x1000553,
+ 0x0583 : 0x1000583,
+ 0x0554 : 0x1000554,
+ 0x0584 : 0x1000584,
+ 0x0555 : 0x1000555,
+ 0x0585 : 0x1000585,
+ 0x0556 : 0x1000556,
+ 0x0586 : 0x1000586,
+ 0x055A : 0x100055a,
+ 0x10D0 : 0x10010d0,
+ 0x10D1 : 0x10010d1,
+ 0x10D2 : 0x10010d2,
+ 0x10D3 : 0x10010d3,
+ 0x10D4 : 0x10010d4,
+ 0x10D5 : 0x10010d5,
+ 0x10D6 : 0x10010d6,
+ 0x10D7 : 0x10010d7,
+ 0x10D8 : 0x10010d8,
+ 0x10D9 : 0x10010d9,
+ 0x10DA : 0x10010da,
+ 0x10DB : 0x10010db,
+ 0x10DC : 0x10010dc,
+ 0x10DD : 0x10010dd,
+ 0x10DE : 0x10010de,
+ 0x10DF : 0x10010df,
+ 0x10E0 : 0x10010e0,
+ 0x10E1 : 0x10010e1,
+ 0x10E2 : 0x10010e2,
+ 0x10E3 : 0x10010e3,
+ 0x10E4 : 0x10010e4,
+ 0x10E5 : 0x10010e5,
+ 0x10E6 : 0x10010e6,
+ 0x10E7 : 0x10010e7,
+ 0x10E8 : 0x10010e8,
+ 0x10E9 : 0x10010e9,
+ 0x10EA : 0x10010ea,
+ 0x10EB : 0x10010eb,
+ 0x10EC : 0x10010ec,
+ 0x10ED : 0x10010ed,
+ 0x10EE : 0x10010ee,
+ 0x10EF : 0x10010ef,
+ 0x10F0 : 0x10010f0,
+ 0x10F1 : 0x10010f1,
+ 0x10F2 : 0x10010f2,
+ 0x10F3 : 0x10010f3,
+ 0x10F4 : 0x10010f4,
+ 0x10F5 : 0x10010f5,
+ 0x10F6 : 0x10010f6,
+ 0x1E8A : 0x1001e8a,
+ 0x012C : 0x100012c,
+ 0x01B5 : 0x10001b5,
+ 0x01E6 : 0x10001e6,
+ 0x01D2 : 0x10001d1,
+ 0x019F : 0x100019f,
+ 0x1E8B : 0x1001e8b,
+ 0x012D : 0x100012d,
+ 0x01B6 : 0x10001b6,
+ 0x01E7 : 0x10001e7,
+ //0x01D2 : 0x10001d2,
+ 0x0275 : 0x1000275,
+ 0x018F : 0x100018f,
+ 0x0259 : 0x1000259,
+ 0x1E36 : 0x1001e36,
+ 0x1E37 : 0x1001e37,
+ 0x1EA0 : 0x1001ea0,
+ 0x1EA1 : 0x1001ea1,
+ 0x1EA2 : 0x1001ea2,
+ 0x1EA3 : 0x1001ea3,
+ 0x1EA4 : 0x1001ea4,
+ 0x1EA5 : 0x1001ea5,
+ 0x1EA6 : 0x1001ea6,
+ 0x1EA7 : 0x1001ea7,
+ 0x1EA8 : 0x1001ea8,
+ 0x1EA9 : 0x1001ea9,
+ 0x1EAA : 0x1001eaa,
+ 0x1EAB : 0x1001eab,
+ 0x1EAC : 0x1001eac,
+ 0x1EAD : 0x1001ead,
+ 0x1EAE : 0x1001eae,
+ 0x1EAF : 0x1001eaf,
+ 0x1EB0 : 0x1001eb0,
+ 0x1EB1 : 0x1001eb1,
+ 0x1EB2 : 0x1001eb2,
+ 0x1EB3 : 0x1001eb3,
+ 0x1EB4 : 0x1001eb4,
+ 0x1EB5 : 0x1001eb5,
+ 0x1EB6 : 0x1001eb6,
+ 0x1EB7 : 0x1001eb7,
+ 0x1EB8 : 0x1001eb8,
+ 0x1EB9 : 0x1001eb9,
+ 0x1EBA : 0x1001eba,
+ 0x1EBB : 0x1001ebb,
+ 0x1EBC : 0x1001ebc,
+ 0x1EBD : 0x1001ebd,
+ 0x1EBE : 0x1001ebe,
+ 0x1EBF : 0x1001ebf,
+ 0x1EC0 : 0x1001ec0,
+ 0x1EC1 : 0x1001ec1,
+ 0x1EC2 : 0x1001ec2,
+ 0x1EC3 : 0x1001ec3,
+ 0x1EC4 : 0x1001ec4,
+ 0x1EC5 : 0x1001ec5,
+ 0x1EC6 : 0x1001ec6,
+ 0x1EC7 : 0x1001ec7,
+ 0x1EC8 : 0x1001ec8,
+ 0x1EC9 : 0x1001ec9,
+ 0x1ECA : 0x1001eca,
+ 0x1ECB : 0x1001ecb,
+ 0x1ECC : 0x1001ecc,
+ 0x1ECD : 0x1001ecd,
+ 0x1ECE : 0x1001ece,
+ 0x1ECF : 0x1001ecf,
+ 0x1ED0 : 0x1001ed0,
+ 0x1ED1 : 0x1001ed1,
+ 0x1ED2 : 0x1001ed2,
+ 0x1ED3 : 0x1001ed3,
+ 0x1ED4 : 0x1001ed4,
+ 0x1ED5 : 0x1001ed5,
+ 0x1ED6 : 0x1001ed6,
+ 0x1ED7 : 0x1001ed7,
+ 0x1ED8 : 0x1001ed8,
+ 0x1ED9 : 0x1001ed9,
+ 0x1EDA : 0x1001eda,
+ 0x1EDB : 0x1001edb,
+ 0x1EDC : 0x1001edc,
+ 0x1EDD : 0x1001edd,
+ 0x1EDE : 0x1001ede,
+ 0x1EDF : 0x1001edf,
+ 0x1EE0 : 0x1001ee0,
+ 0x1EE1 : 0x1001ee1,
+ 0x1EE2 : 0x1001ee2,
+ 0x1EE3 : 0x1001ee3,
+ 0x1EE4 : 0x1001ee4,
+ 0x1EE5 : 0x1001ee5,
+ 0x1EE6 : 0x1001ee6,
+ 0x1EE7 : 0x1001ee7,
+ 0x1EE8 : 0x1001ee8,
+ 0x1EE9 : 0x1001ee9,
+ 0x1EEA : 0x1001eea,
+ 0x1EEB : 0x1001eeb,
+ 0x1EEC : 0x1001eec,
+ 0x1EED : 0x1001eed,
+ 0x1EEE : 0x1001eee,
+ 0x1EEF : 0x1001eef,
+ 0x1EF0 : 0x1001ef0,
+ 0x1EF1 : 0x1001ef1,
+ 0x1EF4 : 0x1001ef4,
+ 0x1EF5 : 0x1001ef5,
+ 0x1EF6 : 0x1001ef6,
+ 0x1EF7 : 0x1001ef7,
+ 0x1EF8 : 0x1001ef8,
+ 0x1EF9 : 0x1001ef9,
+ 0x01A0 : 0x10001a0,
+ 0x01A1 : 0x10001a1,
+ 0x01AF : 0x10001af,
+ 0x01B0 : 0x10001b0,
+ 0x20A0 : 0x10020a0,
+ 0x20A1 : 0x10020a1,
+ 0x20A2 : 0x10020a2,
+ 0x20A3 : 0x10020a3,
+ 0x20A4 : 0x10020a4,
+ 0x20A5 : 0x10020a5,
+ 0x20A6 : 0x10020a6,
+ 0x20A7 : 0x10020a7,
+ 0x20A8 : 0x10020a8,
+ 0x20A9 : 0x10020a9,
+ 0x20AA : 0x10020aa,
+ 0x20AB : 0x10020ab,
+ 0x20AC : 0x20ac,
+ 0x2070 : 0x1002070,
+ 0x2074 : 0x1002074,
+ 0x2075 : 0x1002075,
+ 0x2076 : 0x1002076,
+ 0x2077 : 0x1002077,
+ 0x2078 : 0x1002078,
+ 0x2079 : 0x1002079,
+ 0x2080 : 0x1002080,
+ 0x2081 : 0x1002081,
+ 0x2082 : 0x1002082,
+ 0x2083 : 0x1002083,
+ 0x2084 : 0x1002084,
+ 0x2085 : 0x1002085,
+ 0x2086 : 0x1002086,
+ 0x2087 : 0x1002087,
+ 0x2088 : 0x1002088,
+ 0x2089 : 0x1002089,
+ 0x2202 : 0x1002202,
+ 0x2205 : 0x1002205,
+ 0x2208 : 0x1002208,
+ 0x2209 : 0x1002209,
+ 0x220B : 0x100220B,
+ 0x221A : 0x100221A,
+ 0x221B : 0x100221B,
+ 0x221C : 0x100221C,
+ 0x222C : 0x100222C,
+ 0x222D : 0x100222D,
+ 0x2235 : 0x1002235,
+ 0x2245 : 0x1002248,
+ 0x2247 : 0x1002247,
+ 0x2262 : 0x1002262,
+ 0x2263 : 0x1002263,
+ 0x2800 : 0x1002800,
+ 0x2801 : 0x1002801,
+ 0x2802 : 0x1002802,
+ 0x2803 : 0x1002803,
+ 0x2804 : 0x1002804,
+ 0x2805 : 0x1002805,
+ 0x2806 : 0x1002806,
+ 0x2807 : 0x1002807,
+ 0x2808 : 0x1002808,
+ 0x2809 : 0x1002809,
+ 0x280a : 0x100280a,
+ 0x280b : 0x100280b,
+ 0x280c : 0x100280c,
+ 0x280d : 0x100280d,
+ 0x280e : 0x100280e,
+ 0x280f : 0x100280f,
+ 0x2810 : 0x1002810,
+ 0x2811 : 0x1002811,
+ 0x2812 : 0x1002812,
+ 0x2813 : 0x1002813,
+ 0x2814 : 0x1002814,
+ 0x2815 : 0x1002815,
+ 0x2816 : 0x1002816,
+ 0x2817 : 0x1002817,
+ 0x2818 : 0x1002818,
+ 0x2819 : 0x1002819,
+ 0x281a : 0x100281a,
+ 0x281b : 0x100281b,
+ 0x281c : 0x100281c,
+ 0x281d : 0x100281d,
+ 0x281e : 0x100281e,
+ 0x281f : 0x100281f,
+ 0x2820 : 0x1002820,
+ 0x2821 : 0x1002821,
+ 0x2822 : 0x1002822,
+ 0x2823 : 0x1002823,
+ 0x2824 : 0x1002824,
+ 0x2825 : 0x1002825,
+ 0x2826 : 0x1002826,
+ 0x2827 : 0x1002827,
+ 0x2828 : 0x1002828,
+ 0x2829 : 0x1002829,
+ 0x282a : 0x100282a,
+ 0x282b : 0x100282b,
+ 0x282c : 0x100282c,
+ 0x282d : 0x100282d,
+ 0x282e : 0x100282e,
+ 0x282f : 0x100282f,
+ 0x2830 : 0x1002830,
+ 0x2831 : 0x1002831,
+ 0x2832 : 0x1002832,
+ 0x2833 : 0x1002833,
+ 0x2834 : 0x1002834,
+ 0x2835 : 0x1002835,
+ 0x2836 : 0x1002836,
+ 0x2837 : 0x1002837,
+ 0x2838 : 0x1002838,
+ 0x2839 : 0x1002839,
+ 0x283a : 0x100283a,
+ 0x283b : 0x100283b,
+ 0x283c : 0x100283c,
+ 0x283d : 0x100283d,
+ 0x283e : 0x100283e,
+ 0x283f : 0x100283f,
+ 0x2840 : 0x1002840,
+ 0x2841 : 0x1002841,
+ 0x2842 : 0x1002842,
+ 0x2843 : 0x1002843,
+ 0x2844 : 0x1002844,
+ 0x2845 : 0x1002845,
+ 0x2846 : 0x1002846,
+ 0x2847 : 0x1002847,
+ 0x2848 : 0x1002848,
+ 0x2849 : 0x1002849,
+ 0x284a : 0x100284a,
+ 0x284b : 0x100284b,
+ 0x284c : 0x100284c,
+ 0x284d : 0x100284d,
+ 0x284e : 0x100284e,
+ 0x284f : 0x100284f,
+ 0x2850 : 0x1002850,
+ 0x2851 : 0x1002851,
+ 0x2852 : 0x1002852,
+ 0x2853 : 0x1002853,
+ 0x2854 : 0x1002854,
+ 0x2855 : 0x1002855,
+ 0x2856 : 0x1002856,
+ 0x2857 : 0x1002857,
+ 0x2858 : 0x1002858,
+ 0x2859 : 0x1002859,
+ 0x285a : 0x100285a,
+ 0x285b : 0x100285b,
+ 0x285c : 0x100285c,
+ 0x285d : 0x100285d,
+ 0x285e : 0x100285e,
+ 0x285f : 0x100285f,
+ 0x2860 : 0x1002860,
+ 0x2861 : 0x1002861,
+ 0x2862 : 0x1002862,
+ 0x2863 : 0x1002863,
+ 0x2864 : 0x1002864,
+ 0x2865 : 0x1002865,
+ 0x2866 : 0x1002866,
+ 0x2867 : 0x1002867,
+ 0x2868 : 0x1002868,
+ 0x2869 : 0x1002869,
+ 0x286a : 0x100286a,
+ 0x286b : 0x100286b,
+ 0x286c : 0x100286c,
+ 0x286d : 0x100286d,
+ 0x286e : 0x100286e,
+ 0x286f : 0x100286f,
+ 0x2870 : 0x1002870,
+ 0x2871 : 0x1002871,
+ 0x2872 : 0x1002872,
+ 0x2873 : 0x1002873,
+ 0x2874 : 0x1002874,
+ 0x2875 : 0x1002875,
+ 0x2876 : 0x1002876,
+ 0x2877 : 0x1002877,
+ 0x2878 : 0x1002878,
+ 0x2879 : 0x1002879,
+ 0x287a : 0x100287a,
+ 0x287b : 0x100287b,
+ 0x287c : 0x100287c,
+ 0x287d : 0x100287d,
+ 0x287e : 0x100287e,
+ 0x287f : 0x100287f,
+ 0x2880 : 0x1002880,
+ 0x2881 : 0x1002881,
+ 0x2882 : 0x1002882,
+ 0x2883 : 0x1002883,
+ 0x2884 : 0x1002884,
+ 0x2885 : 0x1002885,
+ 0x2886 : 0x1002886,
+ 0x2887 : 0x1002887,
+ 0x2888 : 0x1002888,
+ 0x2889 : 0x1002889,
+ 0x288a : 0x100288a,
+ 0x288b : 0x100288b,
+ 0x288c : 0x100288c,
+ 0x288d : 0x100288d,
+ 0x288e : 0x100288e,
+ 0x288f : 0x100288f,
+ 0x2890 : 0x1002890,
+ 0x2891 : 0x1002891,
+ 0x2892 : 0x1002892,
+ 0x2893 : 0x1002893,
+ 0x2894 : 0x1002894,
+ 0x2895 : 0x1002895,
+ 0x2896 : 0x1002896,
+ 0x2897 : 0x1002897,
+ 0x2898 : 0x1002898,
+ 0x2899 : 0x1002899,
+ 0x289a : 0x100289a,
+ 0x289b : 0x100289b,
+ 0x289c : 0x100289c,
+ 0x289d : 0x100289d,
+ 0x289e : 0x100289e,
+ 0x289f : 0x100289f,
+ 0x28a0 : 0x10028a0,
+ 0x28a1 : 0x10028a1,
+ 0x28a2 : 0x10028a2,
+ 0x28a3 : 0x10028a3,
+ 0x28a4 : 0x10028a4,
+ 0x28a5 : 0x10028a5,
+ 0x28a6 : 0x10028a6,
+ 0x28a7 : 0x10028a7,
+ 0x28a8 : 0x10028a8,
+ 0x28a9 : 0x10028a9,
+ 0x28aa : 0x10028aa,
+ 0x28ab : 0x10028ab,
+ 0x28ac : 0x10028ac,
+ 0x28ad : 0x10028ad,
+ 0x28ae : 0x10028ae,
+ 0x28af : 0x10028af,
+ 0x28b0 : 0x10028b0,
+ 0x28b1 : 0x10028b1,
+ 0x28b2 : 0x10028b2,
+ 0x28b3 : 0x10028b3,
+ 0x28b4 : 0x10028b4,
+ 0x28b5 : 0x10028b5,
+ 0x28b6 : 0x10028b6,
+ 0x28b7 : 0x10028b7,
+ 0x28b8 : 0x10028b8,
+ 0x28b9 : 0x10028b9,
+ 0x28ba : 0x10028ba,
+ 0x28bb : 0x10028bb,
+ 0x28bc : 0x10028bc,
+ 0x28bd : 0x10028bd,
+ 0x28be : 0x10028be,
+ 0x28bf : 0x10028bf,
+ 0x28c0 : 0x10028c0,
+ 0x28c1 : 0x10028c1,
+ 0x28c2 : 0x10028c2,
+ 0x28c3 : 0x10028c3,
+ 0x28c4 : 0x10028c4,
+ 0x28c5 : 0x10028c5,
+ 0x28c6 : 0x10028c6,
+ 0x28c7 : 0x10028c7,
+ 0x28c8 : 0x10028c8,
+ 0x28c9 : 0x10028c9,
+ 0x28ca : 0x10028ca,
+ 0x28cb : 0x10028cb,
+ 0x28cc : 0x10028cc,
+ 0x28cd : 0x10028cd,
+ 0x28ce : 0x10028ce,
+ 0x28cf : 0x10028cf,
+ 0x28d0 : 0x10028d0,
+ 0x28d1 : 0x10028d1,
+ 0x28d2 : 0x10028d2,
+ 0x28d3 : 0x10028d3,
+ 0x28d4 : 0x10028d4,
+ 0x28d5 : 0x10028d5,
+ 0x28d6 : 0x10028d6,
+ 0x28d7 : 0x10028d7,
+ 0x28d8 : 0x10028d8,
+ 0x28d9 : 0x10028d9,
+ 0x28da : 0x10028da,
+ 0x28db : 0x10028db,
+ 0x28dc : 0x10028dc,
+ 0x28dd : 0x10028dd,
+ 0x28de : 0x10028de,
+ 0x28df : 0x10028df,
+ 0x28e0 : 0x10028e0,
+ 0x28e1 : 0x10028e1,
+ 0x28e2 : 0x10028e2,
+ 0x28e3 : 0x10028e3,
+ 0x28e4 : 0x10028e4,
+ 0x28e5 : 0x10028e5,
+ 0x28e6 : 0x10028e6,
+ 0x28e7 : 0x10028e7,
+ 0x28e8 : 0x10028e8,
+ 0x28e9 : 0x10028e9,
+ 0x28ea : 0x10028ea,
+ 0x28eb : 0x10028eb,
+ 0x28ec : 0x10028ec,
+ 0x28ed : 0x10028ed,
+ 0x28ee : 0x10028ee,
+ 0x28ef : 0x10028ef,
+ 0x28f0 : 0x10028f0,
+ 0x28f1 : 0x10028f1,
+ 0x28f2 : 0x10028f2,
+ 0x28f3 : 0x10028f3,
+ 0x28f4 : 0x10028f4,
+ 0x28f5 : 0x10028f5,
+ 0x28f6 : 0x10028f6,
+ 0x28f7 : 0x10028f7,
+ 0x28f8 : 0x10028f8,
+ 0x28f9 : 0x10028f9,
+ 0x28fa : 0x10028fa,
+ 0x28fb : 0x10028fb,
+ 0x28fc : 0x10028fc,
+ 0x28fd : 0x10028fd,
+ 0x28fe : 0x10028fe,
+ 0x28ff : 0x10028ff
+};
diff --git a/ui/js/novnc/jsunzip.js b/ui/js/novnc/jsunzip.js
new file mode 100755
index 0000000..7edcca7
--- /dev/null
+++ b/ui/js/novnc/jsunzip.js
@@ -0,0 +1,676 @@
+/*
+ * JSUnzip
+ *
+ * Copyright (c) 2011 by Erik Moller
+ * All Rights Reserved
+ *
+ * This software is provided 'as-is', without any express
+ * or implied warranty. In no event will the authors be
+ * held liable for any damages arising from the use of
+ * this software.
+ *
+ * Permission is granted to anyone to use this software
+ * for any purpose, including commercial applications,
+ * and to alter it and redistribute it freely, subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be
+ * misrepresented; you must not claim that you
+ * wrote the original software. If you use this
+ * software in a product, an acknowledgment in
+ * the product documentation would be appreciated
+ * but is not required.
+ *
+ * 2. Altered source versions must be plainly marked
+ * as such, and must not be misrepresented as
+ * being the original software.
+ *
+ * 3. This notice may not be removed or altered from
+ * any source distribution.
+ */
+
+var tinf;
+
+function JSUnzip() {
+
+ this.getInt = function(offset, size) {
+ switch (size) {
+ case 4:
+ return (this.data.charCodeAt(offset + 3) & 0xff) << 24 |
+ (this.data.charCodeAt(offset + 2) & 0xff) << 16 |
+ (this.data.charCodeAt(offset + 1) & 0xff) << 8 |
+ (this.data.charCodeAt(offset + 0) & 0xff);
+ break;
+ case 2:
+ return (this.data.charCodeAt(offset + 1) & 0xff) << 8 |
+ (this.data.charCodeAt(offset + 0) & 0xff);
+ break;
+ default:
+ return this.data.charCodeAt(offset) & 0xff;
+ break;
+ }
+ };
+
+ this.getDOSDate = function(dosdate, dostime) {
+ var day = dosdate & 0x1f;
+ var month = ((dosdate >> 5) & 0xf) - 1;
+ var year = 1980 + ((dosdate >> 9) & 0x7f)
+ var second = (dostime & 0x1f) * 2;
+ var minute = (dostime >> 5) & 0x3f;
+ hour = (dostime >> 11) & 0x1f;
+ return new Date(year, month, day, hour, minute, second);
+ }
+
+ this.open = function(data) {
+ this.data = data;
+ this.files = [];
+
+ if (this.data.length < 22)
+ return { 'status' : false, 'error' : 'Invalid data' };
+ var endOfCentralDirectory = this.data.length - 22;
+ while (endOfCentralDirectory >= 0 && this.getInt(endOfCentralDirectory, 4) != 0x06054b50)
+ --endOfCentralDirectory;
+ if (endOfCentralDirectory < 0)
+ return { 'status' : false, 'error' : 'Invalid data' };
+ if (this.getInt(endOfCentralDirectory + 4, 2) != 0 || this.getInt(endOfCentralDirectory + 6, 2) != 0)
+ return { 'status' : false, 'error' : 'No multidisk support' };
+
+ var entriesInThisDisk = this.getInt(endOfCentralDirectory + 8, 2);
+ var centralDirectoryOffset = this.getInt(endOfCentralDirectory + 16, 4);
+ var globalCommentLength = this.getInt(endOfCentralDirectory + 20, 2);
+ this.comment = this.data.slice(endOfCentralDirectory + 22, endOfCentralDirectory + 22 + globalCommentLength);
+
+ var fileOffset = centralDirectoryOffset;
+
+ for (var i = 0; i < entriesInThisDisk; ++i) {
+ if (this.getInt(fileOffset + 0, 4) != 0x02014b50)
+ return { 'status' : false, 'error' : 'Invalid data' };
+ if (this.getInt(fileOffset + 6, 2) > 20)
+ return { 'status' : false, 'error' : 'Unsupported version' };
+ if (this.getInt(fileOffset + 8, 2) & 1)
+ return { 'status' : false, 'error' : 'Encryption not implemented' };
+
+ var compressionMethod = this.getInt(fileOffset + 10, 2);
+ if (compressionMethod != 0 && compressionMethod != 8)
+ return { 'status' : false, 'error' : 'Unsupported compression method' };
+
+ var lastModFileTime = this.getInt(fileOffset + 12, 2);
+ var lastModFileDate = this.getInt(fileOffset + 14, 2);
+ var lastModifiedDate = this.getDOSDate(lastModFileDate, lastModFileTime);
+
+ var crc = this.getInt(fileOffset + 16, 4);
+ // TODO: crc
+
+ var compressedSize = this.getInt(fileOffset + 20, 4);
+ var uncompressedSize = this.getInt(fileOffset + 24, 4);
+
+ var fileNameLength = this.getInt(fileOffset + 28, 2);
+ var extraFieldLength = this.getInt(fileOffset + 30, 2);
+ var fileCommentLength = this.getInt(fileOffset + 32, 2);
+
+ var relativeOffsetOfLocalHeader = this.getInt(fileOffset + 42, 4);
+
+ var fileName = this.data.slice(fileOffset + 46, fileOffset + 46 + fileNameLength);
+ var fileComment = this.data.slice(fileOffset + 46 + fileNameLength + extraFieldLength, fileOffset + 46 + fileNameLength + extraFieldLength + fileCommentLength);
+
+ if (this.getInt(relativeOffsetOfLocalHeader + 0, 4) != 0x04034b50)
+ return { 'status' : false, 'error' : 'Invalid data' };
+ var localFileNameLength = this.getInt(relativeOffsetOfLocalHeader + 26, 2);
+ var localExtraFieldLength = this.getInt(relativeOffsetOfLocalHeader + 28, 2);
+ var localFileContent = relativeOffsetOfLocalHeader + 30 + localFileNameLength + localExtraFieldLength;
+
+ this.files[fileName] =
+ {
+ 'fileComment' : fileComment,
+ 'compressionMethod' : compressionMethod,
+ 'compressedSize' : compressedSize,
+ 'uncompressedSize' : uncompressedSize,
+ 'localFileContent' : localFileContent,
+ 'lastModifiedDate' : lastModifiedDate
+ };
+
+ fileOffset += 46 + fileNameLength + extraFieldLength + fileCommentLength;
+ }
+ return { 'status' : true }
+ };
+
+
+ this.read = function(fileName) {
+ var fileInfo = this.files[fileName];
+ if (fileInfo) {
+ if (fileInfo.compressionMethod == 8) {
+ if (!tinf) {
+ tinf = new TINF();
+ tinf.init();
+ }
+ var result = tinf.uncompress(this.data, fileInfo.localFileContent);
+ if (result.status == tinf.OK)
+ return { 'status' : true, 'data' : result.data };
+ else
+ return { 'status' : false, 'error' : result.error };
+ } else {
+ return { 'status' : true, 'data' : this.data.slice(fileInfo.localFileContent, fileInfo.localFileContent + fileInfo.uncompressedSize) };
+ }
+ }
+ return { 'status' : false, 'error' : "File '" + fileName + "' doesn't exist in zip" };
+ };
+
+};
+
+
+
+/*
+ * tinflate - tiny inflate
+ *
+ * Copyright (c) 2003 by Joergen Ibsen / Jibz
+ * All Rights Reserved
+ *
+ * http://www.ibsensoftware.com/
+ *
+ * This software is provided 'as-is', without any express
+ * or implied warranty. In no event will the authors be
+ * held liable for any damages arising from the use of
+ * this software.
+ *
+ * Permission is granted to anyone to use this software
+ * for any purpose, including commercial applications,
+ * and to alter it and redistribute it freely, subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be
+ * misrepresented; you must not claim that you
+ * wrote the original software. If you use this
+ * software in a product, an acknowledgment in
+ * the product documentation would be appreciated
+ * but is not required.
+ *
+ * 2. Altered source versions must be plainly marked
+ * as such, and must not be misrepresented as
+ * being the original software.
+ *
+ * 3. This notice may not be removed or altered from
+ * any source distribution.
+ */
+
+/*
+ * tinflate javascript port by Erik Moller in May 2011.
+ * emoller(a)opera.com
+ *
+ * read_bits() patched by mike(a)imidio.com to allow
+ * reading more then 8 bits (needed in some zlib streams)
+ */
+
+"use strict";
+
+function TINF() {
+
+this.OK = 0;
+this.DATA_ERROR = (-3);
+this.WINDOW_SIZE = 32768;
+
+/* ------------------------------ *
+ * -- internal data structures -- *
+ * ------------------------------ */
+
+this.TREE = function() {
+ this.table = new Array(16); /* table of code length counts */
+ this.trans = new Array(288); /* code -> symbol translation table */
+};
+
+this.DATA = function(that) {
+ this.source = '';
+ this.sourceIndex = 0;
+ this.tag = 0;
+ this.bitcount = 0;
+
+ this.dest = [];
+
+ this.history = [];
+
+ this.ltree = new that.TREE(); /* dynamic length/symbol tree */
+ this.dtree = new that.TREE(); /* dynamic distance tree */
+};
+
+/* --------------------------------------------------- *
+ * -- uninitialized global data (static structures) -- *
+ * --------------------------------------------------- */
+
+this.sltree = new this.TREE(); /* fixed length/symbol tree */
+this.sdtree = new this.TREE(); /* fixed distance tree */
+
+/* extra bits and base tables for length codes */
+this.length_bits = new Array(30);
+this.length_base = new Array(30);
+
+/* extra bits and base tables for distance codes */
+this.dist_bits = new Array(30);
+this.dist_base = new Array(30);
+
+/* special ordering of code length codes */
+this.clcidx = [
+ 16, 17, 18, 0, 8, 7, 9, 6,
+ 10, 5, 11, 4, 12, 3, 13, 2,
+ 14, 1, 15
+];
+
+/* ----------------------- *
+ * -- utility functions -- *
+ * ----------------------- */
+
+/* build extra bits and base tables */
+this.build_bits_base = function(bits, base, delta, first)
+{
+ var i, sum;
+
+ /* build bits table */
+ for (i = 0; i < delta; ++i) bits[i] = 0;
+ for (i = 0; i < 30 - delta; ++i) bits[i + delta] = Math.floor(i / delta);
+
+ /* build base table */
+ for (sum = first, i = 0; i < 30; ++i)
+ {
+ base[i] = sum;
+ sum += 1 << bits[i];
+ }
+}
+
+/* build the fixed huffman trees */
+this.build_fixed_trees = function(lt, dt)
+{
+ var i;
+
+ /* build fixed length tree */
+ for (i = 0; i < 7; ++i) lt.table[i] = 0;
+
+ lt.table[7] = 24;
+ lt.table[8] = 152;
+ lt.table[9] = 112;
+
+ for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i;
+ for (i = 0; i < 144; ++i) lt.trans[24 + i] = i;
+ for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i;
+ for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i;
+
+ /* build fixed distance tree */
+ for (i = 0; i < 5; ++i) dt.table[i] = 0;
+
+ dt.table[5] = 32;
+
+ for (i = 0; i < 32; ++i) dt.trans[i] = i;
+}
+
+/* given an array of code lengths, build a tree */
+this.build_tree = function(t, lengths, loffset, num)
+{
+ var offs = new Array(16);
+ var i, sum;
+
+ /* clear code length count table */
+ for (i = 0; i < 16; ++i) t.table[i] = 0;
+
+ /* scan symbol lengths, and sum code length counts */
+ for (i = 0; i < num; ++i) t.table[lengths[loffset + i]]++;
+
+ t.table[0] = 0;
+
+ /* compute offset table for distribution sort */
+ for (sum = 0, i = 0; i < 16; ++i)
+ {
+ offs[i] = sum;
+ sum += t.table[i];
+ }
+
+ /* create code->symbol translation table (symbols sorted by code) */
+ for (i = 0; i < num; ++i)
+ {
+ if (lengths[loffset + i]) t.trans[offs[lengths[loffset + i]]++] = i;
+ }
+}
+
+/* ---------------------- *
+ * -- decode functions -- *
+ * ---------------------- */
+
+/* get one bit from source stream */
+this.getbit = function(d)
+{
+ var bit;
+
+ /* check if tag is empty */
+ if (!d.bitcount--)
+ {
+ /* load next tag */
+ d.tag = d.source[d.sourceIndex++] & 0xff;
+ d.bitcount = 7;
+ }
+
+ /* shift bit out of tag */
+ bit = d.tag & 0x01;
+ d.tag >>= 1;
+
+ return bit;
+}
+
+/* read a num bit value from a stream and add base */
+function read_bits_direct(source, bitcount, tag, idx, num)
+{
+ var val = 0;
+ while (bitcount < 24) {
+ tag = tag | (source[idx++] & 0xff) << bitcount;
+ bitcount += 8;
+ }
+ val = tag & (0xffff >> (16 - num));
+ tag >>= num;
+ bitcount -= num;
+ return [bitcount, tag, idx, val];
+}
+this.read_bits = function(d, num, base)
+{
+ if (!num)
+ return base;
+
+ var ret = read_bits_direct(d.source, d.bitcount, d.tag, d.sourceIndex, num);
+ d.bitcount = ret[0];
+ d.tag = ret[1];
+ d.sourceIndex = ret[2];
+ return ret[3] + base;
+}
+
+/* given a data stream and a tree, decode a symbol */
+this.decode_symbol = function(d, t)
+{
+ while (d.bitcount < 16) {
+ d.tag = d.tag | (d.source[d.sourceIndex++] & 0xff) << d.bitcount;
+ d.bitcount += 8;
+ }
+
+ var sum = 0, cur = 0, len = 0;
+ do {
+ cur = 2 * cur + ((d.tag & (1 << len)) >> len);
+
+ ++len;
+
+ sum += t.table[len];
+ cur -= t.table[len];
+
+ } while (cur >= 0);
+
+ d.tag >>= len;
+ d.bitcount -= len;
+
+ return t.trans[sum + cur];
+}
+
+/* given a data stream, decode dynamic trees from it */
+this.decode_trees = function(d, lt, dt)
+{
+ var code_tree = new this.TREE();
+ var lengths = new Array(288+32);
+ var hlit, hdist, hclen;
+ var i, num, length;
+
+ /* get 5 bits HLIT (257-286) */
+ hlit = this.read_bits(d, 5, 257);
+
+ /* get 5 bits HDIST (1-32) */
+ hdist = this.read_bits(d, 5, 1);
+
+ /* get 4 bits HCLEN (4-19) */
+ hclen = this.read_bits(d, 4, 4);
+
+ for (i = 0; i < 19; ++i) lengths[i] = 0;
+
+ /* read code lengths for code length alphabet */
+ for (i = 0; i < hclen; ++i)
+ {
+ /* get 3 bits code length (0-7) */
+ var clen = this.read_bits(d, 3, 0);
+
+ lengths[this.clcidx[i]] = clen;
+ }
+
+ /* build code length tree */
+ this.build_tree(code_tree, lengths, 0, 19);
+
+ /* decode code lengths for the dynamic trees */
+ for (num = 0; num < hlit + hdist; )
+ {
+ var sym = this.decode_symbol(d, code_tree);
+
+ switch (sym)
+ {
+ case 16:
+ /* copy previous code length 3-6 times (read 2 bits) */
+ {
+ var prev = lengths[num - 1];
+ for (length = this.read_bits(d, 2, 3); length; --length)
+ {
+ lengths[num++] = prev;
+ }
+ }
+ break;
+ case 17:
+ /* repeat code length 0 for 3-10 times (read 3 bits) */
+ for (length = this.read_bits(d, 3, 3); length; --length)
+ {
+ lengths[num++] = 0;
+ }
+ break;
+ case 18:
+ /* repeat code length 0 for 11-138 times (read 7 bits) */
+ for (length = this.read_bits(d, 7, 11); length; --length)
+ {
+ lengths[num++] = 0;
+ }
+ break;
+ default:
+ /* values 0-15 represent the actual code lengths */
+ lengths[num++] = sym;
+ break;
+ }
+ }
+
+ /* build dynamic trees */
+ this.build_tree(lt, lengths, 0, hlit);
+ this.build_tree(dt, lengths, hlit, hdist);
+}
+
+/* ----------------------------- *
+ * -- block inflate functions -- *
+ * ----------------------------- */
+
+/* given a stream and two trees, inflate a block of data */
+this.inflate_block_data = function(d, lt, dt)
+{
+ // js optimization.
+ var ddest = d.dest;
+ var ddestlength = ddest.length;
+
+ while (1)
+ {
+ var sym = this.decode_symbol(d, lt);
+
+ /* check for end of block */
+ if (sym == 256)
+ {
+ return this.OK;
+ }
+
+ if (sym < 256)
+ {
+ ddest[ddestlength++] = sym; // ? String.fromCharCode(sym);
+ d.history.push(sym);
+ } else {
+
+ var length, dist, offs;
+ var i;
+
+ sym -= 257;
+
+ /* possibly get more bits from length code */
+ length = this.read_bits(d, this.length_bits[sym], this.length_base[sym]);
+
+ dist = this.decode_symbol(d, dt);
+
+ /* possibly get more bits from distance code */
+ offs = d.history.length - this.read_bits(d, this.dist_bits[dist], this.dist_base[dist]);
+
+ if (offs < 0)
+ throw ("Invalid zlib offset " + offs);
+
+ /* copy match */
+ for (i = offs; i < offs + length; ++i) {
+ //ddest[ddestlength++] = ddest[i];
+ ddest[ddestlength++] = d.history[i];
+ d.history.push(d.history[i]);
+ }
+ }
+ }
+}
+
+/* inflate an uncompressed block of data */
+this.inflate_uncompressed_block = function(d)
+{
+ var length, invlength;
+ var i;
+
+ if (d.bitcount > 7) {
+ var overflow = Math.floor(d.bitcount / 8);
+ d.sourceIndex -= overflow;
+ d.bitcount = 0;
+ d.tag = 0;
+ }
+
+ /* get length */
+ length = d.source[d.sourceIndex+1];
+ length = 256*length + d.source[d.sourceIndex];
+
+ /* get one's complement of length */
+ invlength = d.source[d.sourceIndex+3];
+ invlength = 256*invlength + d.source[d.sourceIndex+2];
+
+ /* check length */
+ if (length != (~invlength & 0x0000ffff)) return this.DATA_ERROR;
+
+ d.sourceIndex += 4;
+
+ /* copy block */
+ for (i = length; i; --i) {
+ d.history.push(d.source[d.sourceIndex]);
+ d.dest[d.dest.length] = d.source[d.sourceIndex++];
+ }
+
+ /* make sure we start next block on a byte boundary */
+ d.bitcount = 0;
+
+ return this.OK;
+}
+
+/* inflate a block of data compressed with fixed huffman trees */
+this.inflate_fixed_block = function(d)
+{
+ /* decode block using fixed trees */
+ return this.inflate_block_data(d, this.sltree, this.sdtree);
+}
+
+/* inflate a block of data compressed with dynamic huffman trees */
+this.inflate_dynamic_block = function(d)
+{
+ /* decode trees from stream */
+ this.decode_trees(d, d.ltree, d.dtree);
+
+ /* decode block using decoded trees */
+ return this.inflate_block_data(d, d.ltree, d.dtree);
+}
+
+/* ---------------------- *
+ * -- public functions -- *
+ * ---------------------- */
+
+/* initialize global (static) data */
+this.init = function()
+{
+ /* build fixed huffman trees */
+ this.build_fixed_trees(this.sltree, this.sdtree);
+
+ /* build extra bits and base tables */
+ this.build_bits_base(this.length_bits, this.length_base, 4, 3);
+ this.build_bits_base(this.dist_bits, this.dist_base, 2, 1);
+
+ /* fix a special case */
+ this.length_bits[28] = 0;
+ this.length_base[28] = 258;
+
+ this.reset();
+}
+
+this.reset = function()
+{
+ this.d = new this.DATA(this);
+ delete this.header;
+}
+
+/* inflate stream from source to dest */
+this.uncompress = function(source, offset)
+{
+
+ var d = this.d;
+ var bfinal;
+
+ /* initialise data */
+ d.source = source;
+ d.sourceIndex = offset;
+ d.bitcount = 0;
+
+ d.dest = [];
+
+ // Skip zlib header at start of stream
+ if (typeof this.header == 'undefined') {
+ this.header = this.read_bits(d, 16, 0);
+ /* byte 0: 0x78, 7 = 32k window size, 8 = deflate */
+ /* byte 1: check bits for header and other flags */
+ }
+
+ var blocks = 0;
+
+ do {
+
+ var btype;
+ var res;
+
+ /* read final block flag */
+ bfinal = this.getbit(d);
+
+ /* read block type (2 bits) */
+ btype = this.read_bits(d, 2, 0);
+
+ /* decompress block */
+ switch (btype)
+ {
+ case 0:
+ /* decompress uncompressed block */
+ res = this.inflate_uncompressed_block(d);
+ break;
+ case 1:
+ /* decompress block with fixed huffman trees */
+ res = this.inflate_fixed_block(d);
+ break;
+ case 2:
+ /* decompress block with dynamic huffman trees */
+ res = this.inflate_dynamic_block(d);
+ break;
+ default:
+ return { 'status' : this.DATA_ERROR };
+ }
+
+ if (res != this.OK) return { 'status' : this.DATA_ERROR };
+ blocks++;
+
+ } while (!bfinal && d.sourceIndex < d.source.length);
+
+ d.history = d.history.slice(-this.WINDOW_SIZE);
+
+ return { 'status' : this.OK, 'data' : d.dest };
+}
+
+};
diff --git a/ui/js/novnc/main.js b/ui/js/novnc/main.js
new file mode 100644
index 0000000..22037ec
--- /dev/null
+++ b/ui/js/novnc/main.js
@@ -0,0 +1,103 @@
+/* noVNC example: simple example using default UI
+ * Copyright (C) 2012 Joel Martin
+ * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
+ * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
+ *
+ * Connect parameters are provided in query string:
+ * http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
+ */
+/*jslint white: false */
+/*global window, $, Util, RFB, */
+"use strict";
+
+// Load supporting scripts
+Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
+ "input.js", "display.js", "jsunzip.js", "rfb.js"]);
+
+var rfb;
+
+function passwordRequired(rfb) {
+var msg;
+msg = '<form onsubmit="return setPassword();"';
+msg += ' style="margin-bottom: 0px">';
+msg += 'Password Required: ';
+msg += '<input type=password size=10 id="password_input" class="noVNC_status">';
+msg += '<\/form>';
+$D('noVNC_status_bar').setAttribute("class", "noVNC_status_warn");
+$D('noVNC_status').innerHTML = msg;
+}
+function onFBResize(rfb, width, height){
+window.resizeTo(width, height + 90)
+}
+function setPassword() {
+rfb.sendPassword($D('password_input').value);
+return false;
+}
+function sendCtrlAltDel() {
+rfb.sendCtrlAltDel();
+return false;
+}
+function updateState(rfb, state, oldstate, msg) {
+var s, sb, cad, level;
+s = $D('noVNC_status');
+sb = $D('noVNC_status_bar');
+cad = $D('sendCtrlAltDelButton');
+switch (state) {
+ case 'failed': level = "error"; break;
+ case 'fatal': level = "error"; break;
+ case 'normal': level = "normal"; break;
+ case 'disconnected': level = "normal"; break;
+ case 'loaded': level = "normal"; break;
+ default: level = "warn"; break;
+}
+
+if (state === "normal") { cad.disabled = false; }
+else { cad.disabled = true; }
+
+if (typeof(msg) !== 'undefined') {
+ sb.setAttribute("class", "noVNC_status_" + level);
+ s.innerHTML = msg;
+}
+}
+
+window.onscriptsload = function () {
+var host, port, password, path, token;
+
+$D('sendCtrlAltDelButton').style.display = "inline";
+$D('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
+
+WebUtil.init_logging(WebUtil.getQueryVar('logging', 'warn'));
+document.title = unescape(WebUtil.getQueryVar('title', 'noVNC'));
+// By default, use the host and port of server that served this file
+host = WebUtil.getQueryVar('host', window.location.hostname);
+port = WebUtil.getQueryVar('port', window.location.port);
+
+// If a token variable is passed in, set the parameter in a cookie.
+// This is used by nova-novncproxy.
+token = WebUtil.getQueryVar('token', null);
+if (token) {
+ WebUtil.createCookie('token', token, 1)
+}
+
+password = WebUtil.getQueryVar('password', '');
+path = WebUtil.getQueryVar('path', 'websockify');
+
+if ((!host) || (!port)) {
+ updateState('failed',
+ "Must specify host and port in URL");
+ return;
+}
+
+rfb = new RFB({'target': $D('noVNC_canvas'),
+ 'encrypt': WebUtil.getQueryVar('encrypt',
+ (window.location.protocol === "https:")),
+ 'repeaterID': WebUtil.getQueryVar('repeaterID', ''),
+ 'true_color': WebUtil.getQueryVar('true_color', true),
+ 'local_cursor': WebUtil.getQueryVar('cursor', true),
+ 'shared': WebUtil.getQueryVar('shared', true),
+ 'view_only': WebUtil.getQueryVar('view_only', false),
+ 'updateState': updateState,
+ 'onFBResize': onFBResize,
+ 'onPasswordRequired': passwordRequired});
+rfb.connect(host, port, password, path);
+};
diff --git a/ui/js/novnc/rfb.js b/ui/js/novnc/rfb.js
new file mode 100644
index 0000000..4535105
--- /dev/null
+++ b/ui/js/novnc/rfb.js
@@ -0,0 +1,1866 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2012 Joel Martin
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ *
+ * TIGHT decoder portion:
+ * (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
+ */
+
+/*jslint white: false, browser: true, bitwise: false, plusplus: false */
+/*global window, Util, Display, Keyboard, Mouse, Websock, Websock_native, Base64, DES */
+
+
+function RFB(defaults) {
+"use strict";
+
+var that = {}, // Public API methods
+ conf = {}, // Configuration attributes
+
+ // Pre-declare private functions used before definitions (jslint)
+ init_vars, updateState, fail, handle_message,
+ init_msg, normal_msg, framebufferUpdate, print_stats,
+
+ pixelFormat, clientEncodings, fbUpdateRequest, fbUpdateRequests,
+ keyEvent, pointerEvent, clientCutText,
+
+ getTightCLength, extract_data_uri,
+ keyPress, mouseButton, mouseMove,
+
+ checkEvents, // Overridable for testing
+
+
+ //
+ // Private RFB namespace variables
+ //
+ rfb_host = '',
+ rfb_port = 5900,
+ rfb_password = '',
+ rfb_path = '',
+
+ rfb_state = 'disconnected',
+ rfb_version = 0,
+ rfb_max_version= 3.8,
+ rfb_auth_scheme= '',
+
+
+ // In preference order
+ encodings = [
+ ['COPYRECT', 0x01 ],
+ ['TIGHT', 0x07 ],
+ ['TIGHT_PNG', -260 ],
+ ['HEXTILE', 0x05 ],
+ ['RRE', 0x02 ],
+ ['RAW', 0x00 ],
+ ['DesktopSize', -223 ],
+ ['Cursor', -239 ],
+
+ // Psuedo-encoding settings
+ //['JPEG_quality_lo', -32 ],
+ ['JPEG_quality_med', -26 ],
+ //['JPEG_quality_hi', -23 ],
+ //['compress_lo', -255 ],
+ ['compress_hi', -247 ],
+ ['last_rect', -224 ]
+ ],
+
+ encHandlers = {},
+ encNames = {},
+ encStats = {}, // [rectCnt, rectCntTot]
+
+ ws = null, // Websock object
+ display = null, // Display object
+ keyboard = null, // Keyboard input handler object
+ mouse = null, // Mouse input handler object
+ sendTimer = null, // Send Queue check timer
+ connTimer = null, // connection timer
+ disconnTimer = null, // disconnection timer
+ msgTimer = null, // queued handle_message timer
+
+ // Frame buffer update state
+ FBU = {
+ rects : 0,
+ subrects : 0, // RRE
+ lines : 0, // RAW
+ tiles : 0, // HEXTILE
+ bytes : 0,
+ x : 0,
+ y : 0,
+ width : 0,
+ height : 0,
+ encoding : 0,
+ subencoding : -1,
+ background : null,
+ zlibs : [] // TIGHT zlib streams
+ },
+
+ fb_Bpp = 4,
+ fb_depth = 3,
+ fb_width = 0,
+ fb_height = 0,
+ fb_name = "",
+
+ last_req_time = 0,
+ rre_chunk_sz = 100,
+
+ timing = {
+ last_fbu : 0,
+ fbu_total : 0,
+ fbu_total_cnt : 0,
+ full_fbu_total : 0,
+ full_fbu_cnt : 0,
+
+ fbu_rt_start : 0,
+ fbu_rt_total : 0,
+ fbu_rt_cnt : 0,
+ pixels : 0
+ },
+
+ test_mode = false,
+
+ def_con_timeout = Websock_native ? 2 : 5,
+
+ /* Mouse state */
+ mouse_buttonMask = 0,
+ mouse_arr = [],
+ viewportDragging = false,
+ viewportDragPos = {};
+
+// Configuration attributes
+Util.conf_defaults(conf, that, defaults, [
+ ['target', 'wo', 'dom', null, 'VNC display rendering Canvas object'],
+ ['focusContainer', 'wo', 'dom', document, 'DOM element that captures keyboard input'],
+
+ ['encrypt', 'rw', 'bool', false, 'Use TLS/SSL/wss encryption'],
+ ['true_color', 'rw', 'bool', true, 'Request true color pixel data'],
+ ['local_cursor', 'rw', 'bool', false, 'Request locally rendered cursor'],
+ ['shared', 'rw', 'bool', true, 'Request shared mode'],
+ ['view_only', 'rw', 'bool', false, 'Disable client mouse/keyboard'],
+
+ ['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'],
+ ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'],
+
+ // UltraVNC repeater ID to connect to
+ ['repeaterID', 'rw', 'str', '', 'RepeaterID to connect to'],
+
+ ['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'],
+
+ ['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'],
+ ['fbu_req_rate', 'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'],
+
+ // Callback functions
+ ['onUpdateState', 'rw', 'func', function() { },
+ 'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '],
+ ['onPasswordRequired', 'rw', 'func', function() { },
+ 'onPasswordRequired(rfb): VNC password is required '],
+ ['onClipboard', 'rw', 'func', function() { },
+ 'onClipboard(rfb, text): RFB clipboard contents received'],
+ ['onBell', 'rw', 'func', function() { },
+ 'onBell(rfb): RFB Bell message received '],
+ ['onFBUReceive', 'rw', 'func', function() { },
+ 'onFBUReceive(rfb, fbu): RFB FBU received but not yet processed '],
+ ['onFBUComplete', 'rw', 'func', function() { },
+ 'onFBUComplete(rfb, fbu): RFB FBU received and processed '],
+ ['onFBResize', 'rw', 'func', function() { },
+ 'onFBResize(rfb, width, height): frame buffer resized'],
+
+ // These callback names are deprecated
+ ['updateState', 'rw', 'func', function() { },
+ 'obsolete, use onUpdateState'],
+ ['clipboardReceive', 'rw', 'func', function() { },
+ 'obsolete, use onClipboard']
+ ]);
+
+
+// Override/add some specific configuration getters/setters
+that.set_local_cursor = function(cursor) {
+ if ((!cursor) || (cursor in {'0':1, 'no':1, 'false':1})) {
+ conf.local_cursor = false;
+ } else {
+ if (display.get_cursor_uri()) {
+ conf.local_cursor = true;
+ } else {
+ Util.Warn("Browser does not support local cursor");
+ }
+ }
+};
+
+// These are fake configuration getters
+that.get_display = function() { return display; };
+
+that.get_keyboard = function() { return keyboard; };
+
+that.get_mouse = function() { return mouse; };
+
+
+
+//
+// Setup routines
+//
+
+// Create the public API interface and initialize values that stay
+// constant across connect/disconnect
+function constructor() {
+ var i, rmode;
+ Util.Debug(">> RFB.constructor");
+
+ // Create lookup tables based encoding number
+ for (i=0; i < encodings.length; i+=1) {
+ encHandlers[encodings[i][1]] = encHandlers[encodings[i][0]];
+ encNames[encodings[i][1]] = encodings[i][0];
+ encStats[encodings[i][1]] = [0, 0];
+ }
+ // Initialize display, mouse, keyboard, and websock
+ try {
+ display = new Display({'target': conf.target});
+ } catch (exc) {
+ Util.Error("Display exception: " + exc);
+ updateState('fatal', "No working Display");
+ }
+ keyboard = new Keyboard({'target': conf.focusContainer,
+ 'onKeyPress': keyPress});
+ mouse = new Mouse({'target': conf.target,
+ 'onMouseButton': mouseButton,
+ 'onMouseMove': mouseMove});
+
+ rmode = display.get_render_mode();
+
+ ws = new Websock();
+ ws.on('message', handle_message);
+ ws.on('open', function() {
+ if (rfb_state === "connect") {
+ updateState('ProtocolVersion', "Starting VNC handshake");
+ } else {
+ fail("Got unexpected WebSockets connection");
+ }
+ });
+ ws.on('close', function(e) {
+ Util.Warn("WebSocket on-close event");
+ var msg = "";
+ if (e.code) {
+ msg = " (code: " + e.code;
+ if (e.reason) {
+ msg += ", reason: " + e.reason;
+ }
+ msg += ")";
+ }
+ if (rfb_state === 'disconnect') {
+ updateState('disconnected', 'VNC disconnected' + msg);
+ } else if (rfb_state === 'ProtocolVersion') {
+ fail('Failed to connect to server' + msg);
+ } else if (rfb_state in {'failed':1, 'disconnected':1}) {
+ Util.Error("Received onclose while disconnected" + msg);
+ } else {
+ fail('Server disconnected' + msg);
+ }
+ });
+ ws.on('error', function(e) {
+ Util.Warn("WebSocket on-error event");
+ //fail("WebSock reported an error");
+ });
+
+
+ init_vars();
+
+ /* Check web-socket-js if no builtin WebSocket support */
+ if (Websock_native) {
+ Util.Info("Using native WebSockets");
+ updateState('loaded', 'noVNC ready: native WebSockets, ' + rmode);
+ } else {
+ Util.Warn("Using web-socket-js bridge. Flash version: " +
+ Util.Flash.version);
+ if ((! Util.Flash) ||
+ (Util.Flash.version < 9)) {
+ updateState('fatal', "WebSockets or <a href='http://get.adobe.com/flashplayer'>Adobe Flash<\/a> is required");
+ } else if (document.location.href.substr(0, 7) === "file://") {
+ updateState('fatal',
+ "'file://' URL is incompatible with Adobe Flash");
+ } else {
+ updateState('loaded', 'noVNC ready: WebSockets emulation, ' + rmode);
+ }
+ }
+
+ Util.Debug("<< RFB.constructor");
+ return that; // Return the public API interface
+}
+
+function connect() {
+ Util.Debug(">> RFB.connect");
+ var uri;
+
+ if (typeof UsingSocketIO !== "undefined") {
+ uri = "http://" + rfb_host + ":" + rfb_port + "/" + rfb_path;
+ } else {
+ if (conf.encrypt) {
+ uri = "wss://";
+ } else {
+ uri = "ws://";
+ }
+ uri += rfb_host + ":" + rfb_port + "/" + rfb_path;
+ }
+ Util.Info("connecting to " + uri);
+ // TODO: make protocols a configurable
+ ws.open(uri, ['binary', 'base64']);
+
+ Util.Debug("<< RFB.connect");
+}
+
+// Initialize variables that are reset before each connection
+init_vars = function() {
+ var i;
+
+ /* Reset state */
+ ws.init();
+
+ FBU.rects = 0;
+ FBU.subrects = 0; // RRE and HEXTILE
+ FBU.lines = 0; // RAW
+ FBU.tiles = 0; // HEXTILE
+ FBU.zlibs = []; // TIGHT zlib encoders
+ mouse_buttonMask = 0;
+ mouse_arr = [];
+
+ // Clear the per connection encoding stats
+ for (i=0; i < encodings.length; i+=1) {
+ encStats[encodings[i][1]][0] = 0;
+ }
+
+ for (i=0; i < 4; i++) {
+ //FBU.zlibs[i] = new InflateStream();
+ FBU.zlibs[i] = new TINF();
+ FBU.zlibs[i].init();
+ }
+};
+
+// Print statistics
+print_stats = function() {
+ var i, s;
+ Util.Info("Encoding stats for this connection:");
+ for (i=0; i < encodings.length; i+=1) {
+ s = encStats[encodings[i][1]];
+ if ((s[0] + s[1]) > 0) {
+ Util.Info(" " + encodings[i][0] + ": " +
+ s[0] + " rects");
+ }
+ }
+ Util.Info("Encoding stats since page load:");
+ for (i=0; i < encodings.length; i+=1) {
+ s = encStats[encodings[i][1]];
+ if ((s[0] + s[1]) > 0) {
+ Util.Info(" " + encodings[i][0] + ": " +
+ s[1] + " rects");
+ }
+ }
+};
+
+//
+// Utility routines
+//
+
+
+/*
+ * Page states:
+ * loaded - page load, equivalent to disconnected
+ * disconnected - idle state
+ * connect - starting to connect (to ProtocolVersion)
+ * normal - connected
+ * disconnect - starting to disconnect
+ * failed - abnormal disconnect
+ * fatal - failed to load page, or fatal error
+ *
+ * RFB protocol initialization states:
+ * ProtocolVersion
+ * Security
+ * Authentication
+ * password - waiting for password, not part of RFB
+ * SecurityResult
+ * ClientInitialization - not triggered by server message
+ * ServerInitialization (to normal)
+ */
+updateState = function(state, statusMsg) {
+ var func, cmsg, oldstate = rfb_state;
+
+ if (state === oldstate) {
+ /* Already here, ignore */
+ Util.Debug("Already in state '" + state + "', ignoring.");
+ return;
+ }
+
+ /*
+ * These are disconnected states. A previous connect may
+ * asynchronously cause a connection so make sure we are closed.
+ */
+ if (state in {'disconnected':1, 'loaded':1, 'connect':1,
+ 'disconnect':1, 'failed':1, 'fatal':1}) {
+ if (sendTimer) {
+ clearInterval(sendTimer);
+ sendTimer = null;
+ }
+
+ if (msgTimer) {
+ clearInterval(msgTimer);
+ msgTimer = null;
+ }
+
+ if (display && display.get_context()) {
+ keyboard.ungrab();
+ mouse.ungrab();
+ display.defaultCursor();
+ if ((Util.get_logging() !== 'debug') ||
+ (state === 'loaded')) {
+ // Show noVNC logo on load and when disconnected if
+ // debug is off
+ display.clear();
+ }
+ }
+
+ ws.close();
+ }
+
+ if (oldstate === 'fatal') {
+ Util.Error("Fatal error, cannot continue");
+ }
+
+ if ((state === 'failed') || (state === 'fatal')) {
+ func = Util.Error;
+ } else {
+ func = Util.Warn;
+ }
+
+ cmsg = typeof(statusMsg) !== 'undefined' ? (" Msg: " + statusMsg) : "";
+ func("New state '" + state + "', was '" + oldstate + "'." + cmsg);
+
+ if ((oldstate === 'failed') && (state === 'disconnected')) {
+ // Do disconnect action, but stay in failed state
+ rfb_state = 'failed';
+ } else {
+ rfb_state = state;
+ }
+
+ if (connTimer && (rfb_state !== 'connect')) {
+ Util.Debug("Clearing connect timer");
+ clearInterval(connTimer);
+ connTimer = null;
+ }
+
+ if (disconnTimer && (rfb_state !== 'disconnect')) {
+ Util.Debug("Clearing disconnect timer");
+ clearInterval(disconnTimer);
+ disconnTimer = null;
+ }
+
+ switch (state) {
+ case 'normal':
+ if ((oldstate === 'disconnected') || (oldstate === 'failed')) {
+ Util.Error("Invalid transition from 'disconnected' or 'failed' to 'normal'");
+ }
+
+ break;
+
+
+ case 'connect':
+
+ connTimer = setTimeout(function () {
+ fail("Connect timeout");
+ }, conf.connectTimeout * 1000);
+
+ init_vars();
+ connect();
+
+ // WebSocket.onopen transitions to 'ProtocolVersion'
+ break;
+
+
+ case 'disconnect':
+
+ if (! test_mode) {
+ disconnTimer = setTimeout(function () {
+ fail("Disconnect timeout");
+ }, conf.disconnectTimeout * 1000);
+ }
+
+ print_stats();
+
+ // WebSocket.onclose transitions to 'disconnected'
+ break;
+
+
+ case 'failed':
+ if (oldstate === 'disconnected') {
+ Util.Error("Invalid transition from 'disconnected' to 'failed'");
+ }
+ if (oldstate === 'normal') {
+ Util.Error("Error while connected.");
+ }
+ if (oldstate === 'init') {
+ Util.Error("Error while initializing.");
+ }
+
+ // Make sure we transition to disconnected
+ setTimeout(function() { updateState('disconnected'); }, 50);
+
+ break;
+
+
+ default:
+ // No state change action to take
+
+ }
+
+ if ((oldstate === 'failed') && (state === 'disconnected')) {
+ // Leave the failed message
+ conf.updateState(that, state, oldstate); // Obsolete
+ conf.onUpdateState(that, state, oldstate);
+ } else {
+ conf.updateState(that, state, oldstate, statusMsg); // Obsolete
+ conf.onUpdateState(that, state, oldstate, statusMsg);
+ }
+};
+
+fail = function(msg) {
+ updateState('failed', msg);
+ return false;
+};
+
+handle_message = function() {
+ //Util.Debug(">> handle_message ws.rQlen(): " + ws.rQlen());
+ //Util.Debug("ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
+ if (ws.rQlen() === 0) {
+ Util.Warn("handle_message called on empty receive queue");
+ return;
+ }
+ switch (rfb_state) {
+ case 'disconnected':
+ case 'failed':
+ Util.Error("Got data while disconnected");
+ break;
+ case 'normal':
+ if (normal_msg() && ws.rQlen() > 0) {
+ // true means we can continue processing
+ // Give other events a chance to run
+ if (msgTimer === null) {
+ Util.Debug("More data to process, creating timer");
+ msgTimer = setTimeout(function () {
+ msgTimer = null;
+ handle_message();
+ }, 10);
+ } else {
+ Util.Debug("More data to process, existing timer");
+ }
+ }
+ break;
+ default:
+ init_msg();
+ break;
+ }
+};
+
+
+function genDES(password, challenge) {
+ var i, passwd = [];
+ for (i=0; i < password.length; i += 1) {
+ passwd.push(password.charCodeAt(i));
+ }
+ return (new DES(passwd)).encrypt(challenge);
+}
+
+function flushClient() {
+ if (mouse_arr.length > 0) {
+ //send(mouse_arr.concat(fbUpdateRequests()));
+ ws.send(mouse_arr);
+ setTimeout(function() {
+ ws.send(fbUpdateRequests());
+ }, 50);
+
+ mouse_arr = [];
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// overridable for testing
+checkEvents = function() {
+ var now;
+ if (rfb_state === 'normal' && !viewportDragging) {
+ if (! flushClient()) {
+ now = new Date().getTime();
+ if (now > last_req_time + conf.fbu_req_rate) {
+ last_req_time = now;
+ ws.send(fbUpdateRequests());
+ }
+ }
+ }
+ setTimeout(checkEvents, conf.check_rate);
+};
+
+keyPress = function(keysym, down) {
+ var arr;
+
+ if (conf.view_only) { return; } // View only, skip keyboard events
+
+ arr = keyEvent(keysym, down);
+ arr = arr.concat(fbUpdateRequests());
+ ws.send(arr);
+};
+
+mouseButton = function(x, y, down, bmask) {
+ if (down) {
+ mouse_buttonMask |= bmask;
+ } else {
+ mouse_buttonMask ^= bmask;
+ }
+
+ if (conf.viewportDrag) {
+ if (down && !viewportDragging) {
+ viewportDragging = true;
+ viewportDragPos = {'x': x, 'y': y};
+
+ // Skip sending mouse events
+ return;
+ } else {
+ viewportDragging = false;
+ ws.send(fbUpdateRequests()); // Force immediate redraw
+ }
+ }
+
+ if (conf.view_only) { return; } // View only, skip mouse events
+
+ mouse_arr = mouse_arr.concat(
+ pointerEvent(display.absX(x), display.absY(y)) );
+ flushClient();
+};
+
+mouseMove = function(x, y) {
+ //Util.Debug('>> mouseMove ' + x + "," + y);
+ var deltaX, deltaY;
+
+ if (viewportDragging) {
+ //deltaX = x - viewportDragPos.x; // drag viewport
+ deltaX = viewportDragPos.x - x; // drag frame buffer
+ //deltaY = y - viewportDragPos.y; // drag viewport
+ deltaY = viewportDragPos.y - y; // drag frame buffer
+ viewportDragPos = {'x': x, 'y': y};
+
+ display.viewportChange(deltaX, deltaY);
+
+ // Skip sending mouse events
+ return;
+ }
+
+ if (conf.view_only) { return; } // View only, skip mouse events
+
+ mouse_arr = mouse_arr.concat(
+ pointerEvent(display.absX(x), display.absY(y)) );
+};
+
+
+//
+// Server message handlers
+//
+
+// RFB/VNC initialisation message handler
+init_msg = function() {
+ //Util.Debug(">> init_msg [rfb_state '" + rfb_state + "']");
+
+ var strlen, reason, length, sversion, cversion, repeaterID,
+ i, types, num_types, challenge, response, bpp, depth,
+ big_endian, red_max, green_max, blue_max, red_shift,
+ green_shift, blue_shift, true_color, name_length, is_repeater;
+
+ //Util.Debug("ws.rQ (" + ws.rQlen() + ") " + ws.rQslice(0));
+ switch (rfb_state) {
+
+ case 'ProtocolVersion' :
+ if (ws.rQlen() < 12) {
+ return fail("Incomplete protocol version");
+ }
+ sversion = ws.rQshiftStr(12).substr(4,7);
+ Util.Info("Server ProtocolVersion: " + sversion);
+ is_repeater = 0;
+ switch (sversion) {
+ case "000.000": is_repeater = 1; break; // UltraVNC repeater
+ case "003.003": rfb_version = 3.3; break;
+ case "003.006": rfb_version = 3.3; break; // UltraVNC
+ case "003.889": rfb_version = 3.3; break; // Apple Remote Desktop
+ case "003.007": rfb_version = 3.7; break;
+ case "003.008": rfb_version = 3.8; break;
+ case "004.000": rfb_version = 3.8; break; // Intel AMT KVM
+ case "004.001": rfb_version = 3.8; break; // RealVNC 4.6
+ default:
+ return fail("Invalid server version " + sversion);
+ }
+ if (is_repeater) {
+ repeaterID = conf.repeaterID;
+ while (repeaterID.length < 250) {
+ repeaterID += "\0";
+ }
+ ws.send_string(repeaterID);
+ break;
+ }
+ if (rfb_version > rfb_max_version) {
+ rfb_version = rfb_max_version;
+ }
+
+ if (! test_mode) {
+ sendTimer = setInterval(function() {
+ // Send updates either at a rate of one update
+ // every 50ms, or whatever slower rate the network
+ // can handle.
+ ws.flush();
+ }, 50);
+ }
+
+ cversion = "00" + parseInt(rfb_version,10) +
+ ".00" + ((rfb_version * 10) % 10);
+ ws.send_string("RFB " + cversion + "\n");
+ updateState('Security', "Sent ProtocolVersion: " + cversion);
+ break;
+
+ case 'Security' :
+ if (rfb_version >= 3.7) {
+ // Server sends supported list, client decides
+ num_types = ws.rQshift8();
+ if (ws.rQwait("security type", num_types, 1)) { return false; }
+ if (num_types === 0) {
+ strlen = ws.rQshift32();
+ reason = ws.rQshiftStr(strlen);
+ return fail("Security failure: " + reason);
+ }
+ rfb_auth_scheme = 0;
+ types = ws.rQshiftBytes(num_types);
+ Util.Debug("Server security types: " + types);
+ for (i=0; i < types.length; i+=1) {
+ if ((types[i] > rfb_auth_scheme) && (types[i] < 3)) {
+ rfb_auth_scheme = types[i];
+ }
+ }
+ if (rfb_auth_scheme === 0) {
+ return fail("Unsupported security types: " + types);
+ }
+
+ ws.send([rfb_auth_scheme]);
+ } else {
+ // Server decides
+ if (ws.rQwait("security scheme", 4)) { return false; }
+ rfb_auth_scheme = ws.rQshift32();
+ }
+ updateState('Authentication',
+ "Authenticating using scheme: " + rfb_auth_scheme);
+ init_msg(); // Recursive fallthrough (workaround JSLint complaint)
+ break;
+
+ // Triggered by fallthough, not by server message
+ case 'Authentication' :
+ //Util.Debug("Security auth scheme: " + rfb_auth_scheme);
+ switch (rfb_auth_scheme) {
+ case 0: // connection failed
+ if (ws.rQwait("auth reason", 4)) { return false; }
+ strlen = ws.rQshift32();
+ reason = ws.rQshiftStr(strlen);
+ return fail("Auth failure: " + reason);
+ case 1: // no authentication
+ if (rfb_version >= 3.8) {
+ updateState('SecurityResult');
+ return;
+ }
+ // Fall through to ClientInitialisation
+ break;
+ case 2: // VNC authentication
+ if (rfb_password.length === 0) {
+ // Notify via both callbacks since it is kind of
+ // a RFB state change and a UI interface issue.
+ updateState('password', "Password Required");
+ conf.onPasswordRequired(that);
+ return;
+ }
+ if (ws.rQwait("auth challenge", 16)) { return false; }
+ challenge = ws.rQshiftBytes(16);
+ //Util.Debug("Password: " + rfb_password);
+ //Util.Debug("Challenge: " + challenge +
+ // " (" + challenge.length + ")");
+ response = genDES(rfb_password, challenge);
+ //Util.Debug("Response: " + response +
+ // " (" + response.length + ")");
+
+ //Util.Debug("Sending DES encrypted auth response");
+ ws.send(response);
+ updateState('SecurityResult');
+ return;
+ default:
+ fail("Unsupported auth scheme: " + rfb_auth_scheme);
+ return;
+ }
+ updateState('ClientInitialisation', "No auth required");
+ init_msg(); // Recursive fallthrough (workaround JSLint complaint)
+ break;
+
+ case 'SecurityResult' :
+ if (ws.rQwait("VNC auth response ", 4)) { return false; }
+ switch (ws.rQshift32()) {
+ case 0: // OK
+ // Fall through to ClientInitialisation
+ break;
+ case 1: // failed
+ if (rfb_version >= 3.8) {
+ length = ws.rQshift32();
+ if (ws.rQwait("SecurityResult reason", length, 8)) {
+ return false;
+ }
+ reason = ws.rQshiftStr(length);
+ fail(reason);
+ } else {
+ fail("Authentication failed");
+ }
+ return;
+ case 2: // too-many
+ return fail("Too many auth attempts");
+ }
+ updateState('ClientInitialisation', "Authentication OK");
+ init_msg(); // Recursive fallthrough (workaround JSLint complaint)
+ break;
+
+ // Triggered by fallthough, not by server message
+ case 'ClientInitialisation' :
+ ws.send([conf.shared ? 1 : 0]); // ClientInitialisation
+ updateState('ServerInitialisation', "Authentication OK");
+ break;
+
+ case 'ServerInitialisation' :
+ if (ws.rQwait("server initialization", 24)) { return false; }
+
+ /* Screen size */
+ fb_width = ws.rQshift16();
+ fb_height = ws.rQshift16();
+
+ /* PIXEL_FORMAT */
+ bpp = ws.rQshift8();
+ depth = ws.rQshift8();
+ big_endian = ws.rQshift8();
+ true_color = ws.rQshift8();
+
+ red_max = ws.rQshift16();
+ green_max = ws.rQshift16();
+ blue_max = ws.rQshift16();
+ red_shift = ws.rQshift8();
+ green_shift = ws.rQshift8();
+ blue_shift = ws.rQshift8();
+ ws.rQshiftStr(3); // padding
+
+ Util.Info("Screen: " + fb_width + "x" + fb_height +
+ ", bpp: " + bpp + ", depth: " + depth +
+ ", big_endian: " + big_endian +
+ ", true_color: " + true_color +
+ ", red_max: " + red_max +
+ ", green_max: " + green_max +
+ ", blue_max: " + blue_max +
+ ", red_shift: " + red_shift +
+ ", green_shift: " + green_shift +
+ ", blue_shift: " + blue_shift);
+
+ if (big_endian !== 0) {
+ Util.Warn("Server native endian is not little endian");
+ }
+ if (red_shift !== 16) {
+ Util.Warn("Server native red-shift is not 16");
+ }
+ if (blue_shift !== 0) {
+ Util.Warn("Server native blue-shift is not 0");
+ }
+
+ /* Connection name/title */
+ name_length = ws.rQshift32();
+ fb_name = ws.rQshiftStr(name_length);
+
+ if (conf.true_color && fb_name === "Intel(r) AMT KVM")
+ {
+ Util.Warn("Intel AMT KVM only support 8/16 bit depths. Disabling true color");
+ conf.true_color = false;
+ }
+
+ display.set_true_color(conf.true_color);
+ conf.onFBResize(that, fb_width, fb_height);
+ display.resize(fb_width, fb_height);
+ keyboard.grab();
+ mouse.grab();
+
+ if (conf.true_color) {
+ fb_Bpp = 4;
+ fb_depth = 3;
+ } else {
+ fb_Bpp = 1;
+ fb_depth = 1;
+ }
+
+ response = pixelFormat();
+ response = response.concat(clientEncodings());
+ response = response.concat(fbUpdateRequests());
+ timing.fbu_rt_start = (new Date()).getTime();
+ timing.pixels = 0;
+ ws.send(response);
+
+ /* Start pushing/polling */
+ setTimeout(checkEvents, conf.check_rate);
+
+ if (conf.encrypt) {
+ updateState('normal', "Connected (encrypted) to: " + fb_name);
+ } else {
+ updateState('normal', "Connected (unencrypted) to: " + fb_name);
+ }
+ break;
+ }
+ //Util.Debug("<< init_msg");
+};
+
+
+/* Normal RFB/VNC server message handler */
+normal_msg = function() {
+ //Util.Debug(">> normal_msg");
+
+ var ret = true, msg_type, length, text,
+ c, first_colour, num_colours, red, green, blue;
+
+ if (FBU.rects > 0) {
+ msg_type = 0;
+ } else {
+ msg_type = ws.rQshift8();
+ }
+ switch (msg_type) {
+ case 0: // FramebufferUpdate
+ ret = framebufferUpdate(); // false means need more data
+ break;
+ case 1: // SetColourMapEntries
+ Util.Debug("SetColourMapEntries");
+ ws.rQshift8(); // Padding
+ first_colour = ws.rQshift16(); // First colour
+ num_colours = ws.rQshift16();
+ if (ws.rQwait("SetColourMapEntries", num_colours*6, 6)) { return false; }
+
+ for (c=0; c < num_colours; c+=1) {
+ red = ws.rQshift16();
+ //Util.Debug("red before: " + red);
+ red = parseInt(red / 256, 10);
+ //Util.Debug("red after: " + red);
+ green = parseInt(ws.rQshift16() / 256, 10);
+ blue = parseInt(ws.rQshift16() / 256, 10);
+ display.set_colourMap([blue, green, red], first_colour + c);
+ }
+ Util.Debug("colourMap: " + display.get_colourMap());
+ Util.Info("Registered " + num_colours + " colourMap entries");
+ //Util.Debug("colourMap: " + display.get_colourMap());
+ break;
+ case 2: // Bell
+ Util.Debug("Bell");
+ conf.onBell(that);
+ break;
+ case 3: // ServerCutText
+ Util.Debug("ServerCutText");
+ if (ws.rQwait("ServerCutText header", 7, 1)) { return false; }
+ ws.rQshiftBytes(3); // Padding
+ length = ws.rQshift32();
+ if (ws.rQwait("ServerCutText", length, 8)) { return false; }
+
+ text = ws.rQshiftStr(length);
+ conf.clipboardReceive(that, text); // Obsolete
+ conf.onClipboard(that, text);
+ break;
+ default:
+ fail("Disconnected: illegal server message type " + msg_type);
+ Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30));
+ break;
+ }
+ //Util.Debug("<< normal_msg");
+ return ret;
+};
+
+framebufferUpdate = function() {
+ var now, hdr, fbu_rt_diff, ret = true;
+
+ if (FBU.rects === 0) {
+ //Util.Debug("New FBU: ws.rQslice(0,20): " + ws.rQslice(0,20));
+ if (ws.rQwait("FBU header", 3)) {
+ ws.rQunshift8(0); // FBU msg_type
+ return false;
+ }
+ ws.rQshift8(); // padding
+ FBU.rects = ws.rQshift16();
+ //Util.Debug("FramebufferUpdate, rects:" + FBU.rects);
+ FBU.bytes = 0;
+ timing.cur_fbu = 0;
+ if (timing.fbu_rt_start > 0) {
+ now = (new Date()).getTime();
+ Util.Info("First FBU latency: " + (now - timing.fbu_rt_start));
+ }
+ }
+
+ while (FBU.rects > 0) {
+ if (rfb_state !== "normal") {
+ return false;
+ }
+ if (ws.rQwait("FBU", FBU.bytes)) { return false; }
+ if (FBU.bytes === 0) {
+ if (ws.rQwait("rect header", 12)) { return false; }
+ /* New FramebufferUpdate */
+
+ hdr = ws.rQshiftBytes(12);
+ FBU.x = (hdr[0] << 8) + hdr[1];
+ FBU.y = (hdr[2] << 8) + hdr[3];
+ FBU.width = (hdr[4] << 8) + hdr[5];
+ FBU.height = (hdr[6] << 8) + hdr[7];
+ FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) +
+ (hdr[10] << 8) + hdr[11], 10);
+
+ conf.onFBUReceive(that,
+ {'x': FBU.x, 'y': FBU.y,
+ 'width': FBU.width, 'height': FBU.height,
+ 'encoding': FBU.encoding,
+ 'encodingName': encNames[FBU.encoding]});
+
+ if (encNames[FBU.encoding]) {
+ // Debug:
+ /*
+ var msg = "FramebufferUpdate rects:" + FBU.rects;
+ msg += " x: " + FBU.x + " y: " + FBU.y;
+ msg += " width: " + FBU.width + " height: " + FBU.height;
+ msg += " encoding:" + FBU.encoding;
+ msg += "(" + encNames[FBU.encoding] + ")";
+ msg += ", ws.rQlen(): " + ws.rQlen();
+ Util.Debug(msg);
+ */
+ } else {
+ fail("Disconnected: unsupported encoding " +
+ FBU.encoding);
+ return false;
+ }
+ }
+
+ timing.last_fbu = (new Date()).getTime();
+
+ ret = encHandlers[FBU.encoding]();
+
+ now = (new Date()).getTime();
+ timing.cur_fbu += (now - timing.last_fbu);
+
+ if (ret) {
+ encStats[FBU.encoding][0] += 1;
+ encStats[FBU.encoding][1] += 1;
+ timing.pixels += FBU.width * FBU.height;
+ }
+
+ if (timing.pixels >= (fb_width * fb_height)) {
+ if (((FBU.width === fb_width) &&
+ (FBU.height === fb_height)) ||
+ (timing.fbu_rt_start > 0)) {
+ timing.full_fbu_total += timing.cur_fbu;
+ timing.full_fbu_cnt += 1;
+ Util.Info("Timing of full FBU, cur: " +
+ timing.cur_fbu + ", total: " +
+ timing.full_fbu_total + ", cnt: " +
+ timing.full_fbu_cnt + ", avg: " +
+ (timing.full_fbu_total /
+ timing.full_fbu_cnt));
+ }
+ if (timing.fbu_rt_start > 0) {
+ fbu_rt_diff = now - timing.fbu_rt_start;
+ timing.fbu_rt_total += fbu_rt_diff;
+ timing.fbu_rt_cnt += 1;
+ Util.Info("full FBU round-trip, cur: " +
+ fbu_rt_diff + ", total: " +
+ timing.fbu_rt_total + ", cnt: " +
+ timing.fbu_rt_cnt + ", avg: " +
+ (timing.fbu_rt_total /
+ timing.fbu_rt_cnt));
+ timing.fbu_rt_start = 0;
+ }
+ }
+ if (! ret) {
+ return ret; // false ret means need more data
+ }
+ }
+
+ conf.onFBUComplete(that,
+ {'x': FBU.x, 'y': FBU.y,
+ 'width': FBU.width, 'height': FBU.height,
+ 'encoding': FBU.encoding,
+ 'encodingName': encNames[FBU.encoding]});
+
+ return true; // We finished this FBU
+};
+
+//
+// FramebufferUpdate encodings
+//
+
+encHandlers.RAW = function display_raw() {
+ //Util.Debug(">> display_raw (" + ws.rQlen() + " bytes)");
+
+ var cur_y, cur_height;
+
+ if (FBU.lines === 0) {
+ FBU.lines = FBU.height;
+ }
+ FBU.bytes = FBU.width * fb_Bpp; // At least a line
+ if (ws.rQwait("RAW", FBU.bytes)) { return false; }
+ cur_y = FBU.y + (FBU.height - FBU.lines);
+ cur_height = Math.min(FBU.lines,
+ Math.floor(ws.rQlen()/(FBU.width * fb_Bpp)));
+ display.blitImage(FBU.x, cur_y, FBU.width, cur_height,
+ ws.get_rQ(), ws.get_rQi());
+ ws.rQshiftBytes(FBU.width * cur_height * fb_Bpp);
+ FBU.lines -= cur_height;
+
+ if (FBU.lines > 0) {
+ FBU.bytes = FBU.width * fb_Bpp; // At least another line
+ } else {
+ FBU.rects -= 1;
+ FBU.bytes = 0;
+ }
+ //Util.Debug("<< display_raw (" + ws.rQlen() + " bytes)");
+ return true;
+};
+
+encHandlers.COPYRECT = function display_copy_rect() {
+ //Util.Debug(">> display_copy_rect");
+
+ var old_x, old_y;
+
+ if (ws.rQwait("COPYRECT", 4)) { return false; }
+ display.renderQ_push({
+ 'type': 'copy',
+ 'old_x': ws.rQshift16(),
+ 'old_y': ws.rQshift16(),
+ 'x': FBU.x,
+ 'y': FBU.y,
+ 'width': FBU.width,
+ 'height': FBU.height});
+ FBU.rects -= 1;
+ FBU.bytes = 0;
+ return true;
+};
+
+encHandlers.RRE = function display_rre() {
+ //Util.Debug(">> display_rre (" + ws.rQlen() + " bytes)");
+ var color, x, y, width, height, chunk;
+
+ if (FBU.subrects === 0) {
+ if (ws.rQwait("RRE", 4+fb_Bpp)) { return false; }
+ FBU.subrects = ws.rQshift32();
+ color = ws.rQshiftBytes(fb_Bpp); // Background
+ display.fillRect(FBU.x, FBU.y, FBU.width, FBU.height, color);
+ }
+ while ((FBU.subrects > 0) && (ws.rQlen() >= (fb_Bpp + 8))) {
+ color = ws.rQshiftBytes(fb_Bpp);
+ x = ws.rQshift16();
+ y = ws.rQshift16();
+ width = ws.rQshift16();
+ height = ws.rQshift16();
+ display.fillRect(FBU.x + x, FBU.y + y, width, height, color);
+ FBU.subrects -= 1;
+ }
+ //Util.Debug(" display_rre: rects: " + FBU.rects +
+ // ", FBU.subrects: " + FBU.subrects);
+
+ if (FBU.subrects > 0) {
+ chunk = Math.min(rre_chunk_sz, FBU.subrects);
+ FBU.bytes = (fb_Bpp + 8) * chunk;
+ } else {
+ FBU.rects -= 1;
+ FBU.bytes = 0;
+ }
+ //Util.Debug("<< display_rre, FBU.bytes: " + FBU.bytes);
+ return true;
+};
+
+encHandlers.HEXTILE = function display_hextile() {
+ //Util.Debug(">> display_hextile");
+ var subencoding, subrects, color, cur_tile,
+ tile_x, x, w, tile_y, y, h, xy, s, sx, sy, wh, sw, sh,
+ rQ = ws.get_rQ(), rQi = ws.get_rQi();
+
+ if (FBU.tiles === 0) {
+ FBU.tiles_x = Math.ceil(FBU.width/16);
+ FBU.tiles_y = Math.ceil(FBU.height/16);
+ FBU.total_tiles = FBU.tiles_x * FBU.tiles_y;
+ FBU.tiles = FBU.total_tiles;
+ }
+
+ /* FBU.bytes comes in as 1, ws.rQlen() at least 1 */
+ while (FBU.tiles > 0) {
+ FBU.bytes = 1;
+ if (ws.rQwait("HEXTILE subencoding", FBU.bytes)) { return false; }
+ subencoding = rQ[rQi]; // Peek
+ if (subencoding > 30) { // Raw
+ fail("Disconnected: illegal hextile subencoding " + subencoding);
+ //Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30));
+ return false;
+ }
+ subrects = 0;
+ cur_tile = FBU.total_tiles - FBU.tiles;
+ tile_x = cur_tile % FBU.tiles_x;
+ tile_y = Math.floor(cur_tile / FBU.tiles_x);
+ x = FBU.x + tile_x * 16;
+ y = FBU.y + tile_y * 16;
+ w = Math.min(16, (FBU.x + FBU.width) - x);
+ h = Math.min(16, (FBU.y + FBU.height) - y);
+
+ /* Figure out how much we are expecting */
+ if (subencoding & 0x01) { // Raw
+ //Util.Debug(" Raw subencoding");
+ FBU.bytes += w * h * fb_Bpp;
+ } else {
+ if (subencoding & 0x02) { // Background
+ FBU.bytes += fb_Bpp;
+ }
+ if (subencoding & 0x04) { // Foreground
+ FBU.bytes += fb_Bpp;
+ }
+ if (subencoding & 0x08) { // AnySubrects
+ FBU.bytes += 1; // Since we aren't shifting it off
+ if (ws.rQwait("hextile subrects header", FBU.bytes)) { return false; }
+ subrects = rQ[rQi + FBU.bytes-1]; // Peek
+ if (subencoding & 0x10) { // SubrectsColoured
+ FBU.bytes += subrects * (fb_Bpp + 2);
+ } else {
+ FBU.bytes += subrects * 2;
+ }
+ }
+ }
+
+ /*
+ Util.Debug(" tile:" + cur_tile + "/" + (FBU.total_tiles - 1) +
+ " (" + tile_x + "," + tile_y + ")" +
+ " [" + x + "," + y + "]@" + w + "x" + h +
+ ", subenc:" + subencoding +
+ "(last: " + FBU.lastsubencoding + "), subrects:" +
+ subrects +
+ ", ws.rQlen():" + ws.rQlen() + ", FBU.bytes:" + FBU.bytes +
+ " last:" + ws.rQslice(FBU.bytes-10, FBU.bytes) +
+ " next:" + ws.rQslice(FBU.bytes-1, FBU.bytes+10));
+ */
+ if (ws.rQwait("hextile", FBU.bytes)) { return false; }
+
+ /* We know the encoding and have a whole tile */
+ FBU.subencoding = rQ[rQi];
+ rQi += 1;
+ if (FBU.subencoding === 0) {
+ if (FBU.lastsubencoding & 0x01) {
+ /* Weird: ignore blanks after RAW */
+ Util.Debug(" Ignoring blank after RAW");
+ } else {
+ display.fillRect(x, y, w, h, FBU.background);
+ }
+ } else if (FBU.subencoding & 0x01) { // Raw
+ display.blitImage(x, y, w, h, rQ, rQi);
+ rQi += FBU.bytes - 1;
+ } else {
+ if (FBU.subencoding & 0x02) { // Background
+ FBU.background = rQ.slice(rQi, rQi + fb_Bpp);
+ rQi += fb_Bpp;
+ }
+ if (FBU.subencoding & 0x04) { // Foreground
+ FBU.foreground = rQ.slice(rQi, rQi + fb_Bpp);
+ rQi += fb_Bpp;
+ }
+
+ display.startTile(x, y, w, h, FBU.background);
+ if (FBU.subencoding & 0x08) { // AnySubrects
+ subrects = rQ[rQi];
+ rQi += 1;
+ for (s = 0; s < subrects; s += 1) {
+ if (FBU.subencoding & 0x10) { // SubrectsColoured
+ color = rQ.slice(rQi, rQi + fb_Bpp);
+ rQi += fb_Bpp;
+ } else {
+ color = FBU.foreground;
+ }
+ xy = rQ[rQi];
+ rQi += 1;
+ sx = (xy >> 4);
+ sy = (xy & 0x0f);
+
+ wh = rQ[rQi];
+ rQi += 1;
+ sw = (wh >> 4) + 1;
+ sh = (wh & 0x0f) + 1;
+
+ display.subTile(sx, sy, sw, sh, color);
+ }
+ }
+ display.finishTile();
+ }
+ ws.set_rQi(rQi);
+ FBU.lastsubencoding = FBU.subencoding;
+ FBU.bytes = 0;
+ FBU.tiles -= 1;
+ }
+
+ if (FBU.tiles === 0) {
+ FBU.rects -= 1;
+ }
+
+ //Util.Debug("<< display_hextile");
+ return true;
+};
+
+
+// Get 'compact length' header and data size
+getTightCLength = function (arr) {
+ var header = 1, data = 0;
+ data += arr[0] & 0x7f;
+ if (arr[0] & 0x80) {
+ header += 1;
+ data += (arr[1] & 0x7f) << 7;
+ if (arr[1] & 0x80) {
+ header += 1;
+ data += arr[2] << 14;
+ }
+ }
+ return [header, data];
+};
+
+function display_tight(isTightPNG) {
+ //Util.Debug(">> display_tight");
+
+ if (fb_depth === 1) {
+ fail("Tight protocol handler only implements true color mode");
+ }
+
+ var ctl, cmode, clength, color, img, data;
+ var filterId = -1, resetStreams = 0, streamId = -1;
+ var rQ = ws.get_rQ(), rQi = ws.get_rQi();
+
+ FBU.bytes = 1; // compression-control byte
+ if (ws.rQwait("TIGHT compression-control", FBU.bytes)) { return false; }
+
+ var checksum = function(data) {
+ var sum=0, i;
+ for (i=0; i<data.length;i++) {
+ sum += data[i];
+ if (sum > 65536) sum -= 65536;
+ }
+ return sum;
+ }
+
+ var decompress = function(data) {
+ for (var i=0; i<4; i++) {
+ if ((resetStreams >> i) & 1) {
+ FBU.zlibs[i].reset();
+ Util.Info("Reset zlib stream " + i);
+ }
+ }
+ var uncompressed = FBU.zlibs[streamId].uncompress(data, 0);
+ if (uncompressed.status !== 0) {
+ Util.Error("Invalid data in zlib stream");
+ }
+ //Util.Warn("Decompressed " + data.length + " to " +
+ // uncompressed.data.length + " checksums " +
+ // checksum(data) + ":" + checksum(uncompressed.data));
+
+ return uncompressed.data;
+ }
+
+ var indexedToRGB = function (data, numColors, palette, width, height) {
+ // Convert indexed (palette based) image data to RGB
+ // TODO: reduce number of calculations inside loop
+ var dest = [];
+ var x, y, b, w, w1, dp, sp;
+ if (numColors === 2) {
+ w = Math.floor((width + 7) / 8);
+ w1 = Math.floor(width / 8);
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < w1; x++) {
+ for (b = 7; b >= 0; b--) {
+ dp = (y*width + x*8 + 7-b) * 3;
+ sp = (data[y*w + x] >> b & 1) * 3;
+ dest[dp ] = palette[sp ];
+ dest[dp+1] = palette[sp+1];
+ dest[dp+2] = palette[sp+2];
+ }
+ }
+ for (b = 7; b >= 8 - width % 8; b--) {
+ dp = (y*width + x*8 + 7-b) * 3;
+ sp = (data[y*w + x] >> b & 1) * 3;
+ dest[dp ] = palette[sp ];
+ dest[dp+1] = palette[sp+1];
+ dest[dp+2] = palette[sp+2];
+ }
+ }
+ } else {
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ dp = (y*width + x) * 3;
+ sp = data[y*width + x] * 3;
+ dest[dp ] = palette[sp ];
+ dest[dp+1] = palette[sp+1];
+ dest[dp+2] = palette[sp+2];
+ }
+ }
+ }
+ return dest;
+ };
+ var handlePalette = function() {
+ var numColors = rQ[rQi + 2] + 1;
+ var paletteSize = numColors * fb_depth;
+ FBU.bytes += paletteSize;
+ if (ws.rQwait("TIGHT palette " + cmode, FBU.bytes)) { return false; }
+
+ var bpp = (numColors <= 2) ? 1 : 8;
+ var rowSize = Math.floor((FBU.width * bpp + 7) / 8);
+ var raw = false;
+ if (rowSize * FBU.height < 12) {
+ raw = true;
+ clength = [0, rowSize * FBU.height];
+ } else {
+ clength = getTightCLength(ws.rQslice(3 + paletteSize,
+ 3 + paletteSize + 3));
+ }
+ FBU.bytes += clength[0] + clength[1];
+ if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
+
+ // Shift ctl, filter id, num colors, palette entries, and clength off
+ ws.rQshiftBytes(3);
+ var palette = ws.rQshiftBytes(paletteSize);
+ ws.rQshiftBytes(clength[0]);
+
+ if (raw) {
+ data = ws.rQshiftBytes(clength[1]);
+ } else {
+ data = decompress(ws.rQshiftBytes(clength[1]));
+ }
+
+ // Convert indexed (palette based) image data to RGB
+ var rgb = indexedToRGB(data, numColors, palette, FBU.width, FBU.height);
+
+ // Add it to the render queue
+ display.renderQ_push({
+ 'type': 'blitRgb',
+ 'data': rgb,
+ 'x': FBU.x,
+ 'y': FBU.y,
+ 'width': FBU.width,
+ 'height': FBU.height});
+ return true;
+ }
+
+ var handleCopy = function() {
+ var raw = false;
+ var uncompressedSize = FBU.width * FBU.height * fb_depth;
+ if (uncompressedSize < 12) {
+ raw = true;
+ clength = [0, uncompressedSize];
+ } else {
+ clength = getTightCLength(ws.rQslice(1, 4));
+ }
+ FBU.bytes = 1 + clength[0] + clength[1];
+ if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
+
+ // Shift ctl, clength off
+ ws.rQshiftBytes(1 + clength[0]);
+
+ if (raw) {
+ data = ws.rQshiftBytes(clength[1]);
+ } else {
+ data = decompress(ws.rQshiftBytes(clength[1]));
+ }
+
+ display.renderQ_push({
+ 'type': 'blitRgb',
+ 'data': data,
+ 'x': FBU.x,
+ 'y': FBU.y,
+ 'width': FBU.width,
+ 'height': FBU.height});
+ return true;
+ }
+
+ ctl = ws.rQpeek8();
+
+ // Keep tight reset bits
+ resetStreams = ctl & 0xF;
+
+ // Figure out filter
+ ctl = ctl >> 4;
+ streamId = ctl & 0x3;
+
+ if (ctl === 0x08) cmode = "fill";
+ else if (ctl === 0x09) cmode = "jpeg";
+ else if (ctl === 0x0A) cmode = "png";
+ else if (ctl & 0x04) cmode = "filter";
+ else if (ctl < 0x04) cmode = "copy";
+ else return fail("Illegal tight compression received, ctl: " + ctl);
+
+ if (isTightPNG && (cmode === "filter" || cmode === "copy")) {
+ return fail("filter/copy received in tightPNG mode");
+ }
+
+ switch (cmode) {
+ // fill uses fb_depth because TPIXELs drop the padding byte
+ case "fill": FBU.bytes += fb_depth; break; // TPIXEL
+ case "jpeg": FBU.bytes += 3; break; // max clength
+ case "png": FBU.bytes += 3; break; // max clength
+ case "filter": FBU.bytes += 2; break; // filter id + num colors if palette
+ case "copy": break;
+ }
+
+ if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
+
+ //Util.Debug(" ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
+ //Util.Debug(" cmode: " + cmode);
+
+ // Determine FBU.bytes
+ switch (cmode) {
+ case "fill":
+ ws.rQshift8(); // shift off ctl
+ color = ws.rQshiftBytes(fb_depth);
+ display.renderQ_push({
+ 'type': 'fill',
+ 'x': FBU.x,
+ 'y': FBU.y,
+ 'width': FBU.width,
+ 'height': FBU.height,
+ 'color': [color[2], color[1], color[0]] });
+ break;
+ case "png":
+ case "jpeg":
+ clength = getTightCLength(ws.rQslice(1, 4));
+ FBU.bytes = 1 + clength[0] + clength[1]; // ctl + clength size + jpeg-data
+ if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
+
+ // We have everything, render it
+ //Util.Debug(" jpeg, ws.rQlen(): " + ws.rQlen() + ", clength[0]: " +
+ // clength[0] + ", clength[1]: " + clength[1]);
+ ws.rQshiftBytes(1 + clength[0]); // shift off ctl + compact length
+ img = new Image();
+ img.src = "data:image/" + cmode +
+ extract_data_uri(ws.rQshiftBytes(clength[1]));
+ display.renderQ_push({
+ 'type': 'img',
+ 'img': img,
+ 'x': FBU.x,
+ 'y': FBU.y});
+ img = null;
+ break;
+ case "filter":
+ filterId = rQ[rQi + 1];
+ if (filterId === 1) {
+ if (!handlePalette()) { return false; }
+ } else {
+ // Filter 0, Copy could be valid here, but servers don't send it as an explicit filter
+ // Filter 2, Gradient is valid but not used if jpeg is enabled
+ throw("Unsupported tight subencoding received, filter: " + filterId);
+ }
+ break;
+ case "copy":
+ if (!handleCopy()) { return false; }
+ break;
+ }
+
+ FBU.bytes = 0;
+ FBU.rects -= 1;
+ //Util.Debug(" ending ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
+ //Util.Debug("<< display_tight_png");
+ return true;
+}
+
+extract_data_uri = function(arr) {
+ //var i, stra = [];
+ //for (i=0; i< arr.length; i += 1) {
+ // stra.push(String.fromCharCode(arr[i]));
+ //}
+ //return "," + escape(stra.join(''));
+ return ";base64," + Base64.encode(arr);
+};
+
+encHandlers.TIGHT = function () { return display_tight(false); };
+encHandlers.TIGHT_PNG = function () { return display_tight(true); };
+
+encHandlers.last_rect = function last_rect() {
+ //Util.Debug(">> last_rect");
+ FBU.rects = 0;
+ //Util.Debug("<< last_rect");
+ return true;
+};
+
+encHandlers.DesktopSize = function set_desktopsize() {
+ Util.Debug(">> set_desktopsize");
+ fb_width = FBU.width;
+ fb_height = FBU.height;
+ conf.onFBResize(that, fb_width, fb_height);
+ display.resize(fb_width, fb_height);
+ timing.fbu_rt_start = (new Date()).getTime();
+ // Send a new non-incremental request
+ ws.send(fbUpdateRequests());
+
+ FBU.bytes = 0;
+ FBU.rects -= 1;
+
+ Util.Debug("<< set_desktopsize");
+ return true;
+};
+
+encHandlers.Cursor = function set_cursor() {
+ var x, y, w, h, pixelslength, masklength;
+ Util.Debug(">> set_cursor");
+ x = FBU.x; // hotspot-x
+ y = FBU.y; // hotspot-y
+ w = FBU.width;
+ h = FBU.height;
+
+ pixelslength = w * h * fb_Bpp;
+ masklength = Math.floor((w + 7) / 8) * h;
+
+ FBU.bytes = pixelslength + masklength;
+ if (ws.rQwait("cursor encoding", FBU.bytes)) { return false; }
+
+ //Util.Debug(" set_cursor, x: " + x + ", y: " + y + ", w: " + w + ", h: " + h);
+
+ display.changeCursor(ws.rQshiftBytes(pixelslength),
+ ws.rQshiftBytes(masklength),
+ x, y, w, h);
+
+ FBU.bytes = 0;
+ FBU.rects -= 1;
+
+ Util.Debug("<< set_cursor");
+ return true;
+};
+
+encHandlers.JPEG_quality_lo = function set_jpeg_quality() {
+ Util.Error("Server sent jpeg_quality pseudo-encoding");
+};
+
+encHandlers.compress_lo = function set_compress_level() {
+ Util.Error("Server sent compress level pseudo-encoding");
+};
+
+/*
+ * Client message routines
+ */
+
+pixelFormat = function() {
+ //Util.Debug(">> pixelFormat");
+ var arr;
+ arr = [0]; // msg-type
+ arr.push8(0); // padding
+ arr.push8(0); // padding
+ arr.push8(0); // padding
+
+ arr.push8(fb_Bpp * 8); // bits-per-pixel
+ arr.push8(fb_depth * 8); // depth
+ arr.push8(0); // little-endian
+ arr.push8(conf.true_color ? 1 : 0); // true-color
+
+ arr.push16(255); // red-max
+ arr.push16(255); // green-max
+ arr.push16(255); // blue-max
+ arr.push8(16); // red-shift
+ arr.push8(8); // green-shift
+ arr.push8(0); // blue-shift
+
+ arr.push8(0); // padding
+ arr.push8(0); // padding
+ arr.push8(0); // padding
+ //Util.Debug("<< pixelFormat");
+ return arr;
+};
+
+clientEncodings = function() {
+ //Util.Debug(">> clientEncodings");
+ var arr, i, encList = [];
+
+ for (i=0; i<encodings.length; i += 1) {
+ if ((encodings[i][0] === "Cursor") &&
+ (! conf.local_cursor)) {
+ Util.Debug("Skipping Cursor pseudo-encoding");
+
+ // TODO: remove this when we have tight+non-true-color
+ } else if ((encodings[i][0] === "TIGHT") &&
+ (! conf.true_color)) {
+ Util.Warn("Skipping tight, only support with true color");
+ } else {
+ //Util.Debug("Adding encoding: " + encodings[i][0]);
+ encList.push(encodings[i][1]);
+ }
+ }
+
+ arr = [2]; // msg-type
+ arr.push8(0); // padding
+
+ arr.push16(encList.length); // encoding count
+ for (i=0; i < encList.length; i += 1) {
+ arr.push32(encList[i]);
+ }
+ //Util.Debug("<< clientEncodings: " + arr);
+ return arr;
+};
+
+fbUpdateRequest = function(incremental, x, y, xw, yw) {
+ //Util.Debug(">> fbUpdateRequest");
+ if (typeof(x) === "undefined") { x = 0; }
+ if (typeof(y) === "undefined") { y = 0; }
+ if (typeof(xw) === "undefined") { xw = fb_width; }
+ if (typeof(yw) === "undefined") { yw = fb_height; }
+ var arr;
+ arr = [3]; // msg-type
+ arr.push8(incremental);
+ arr.push16(x);
+ arr.push16(y);
+ arr.push16(xw);
+ arr.push16(yw);
+ //Util.Debug("<< fbUpdateRequest");
+ return arr;
+};
+
+// Based on clean/dirty areas, generate requests to send
+fbUpdateRequests = function() {
+ var cleanDirty = display.getCleanDirtyReset(),
+ arr = [], i, cb, db;
+
+ cb = cleanDirty.cleanBox;
+ if (cb.w > 0 && cb.h > 0) {
+ // Request incremental for clean box
+ arr = arr.concat(fbUpdateRequest(1, cb.x, cb.y, cb.w, cb.h));
+ }
+ for (i = 0; i < cleanDirty.dirtyBoxes.length; i++) {
+ db = cleanDirty.dirtyBoxes[i];
+ // Force all (non-incremental for dirty box
+ arr = arr.concat(fbUpdateRequest(0, db.x, db.y, db.w, db.h));
+ }
+ return arr;
+};
+
+
+
+keyEvent = function(keysym, down) {
+ //Util.Debug(">> keyEvent, keysym: " + keysym + ", down: " + down);
+ var arr;
+ arr = [4]; // msg-type
+ arr.push8(down);
+ arr.push16(0);
+ arr.push32(keysym);
+ //Util.Debug("<< keyEvent");
+ return arr;
+};
+
+pointerEvent = function(x, y) {
+ //Util.Debug(">> pointerEvent, x,y: " + x + "," + y +
+ // " , mask: " + mouse_buttonMask);
+ var arr;
+ arr = [5]; // msg-type
+ arr.push8(mouse_buttonMask);
+ arr.push16(x);
+ arr.push16(y);
+ //Util.Debug("<< pointerEvent");
+ return arr;
+};
+
+clientCutText = function(text) {
+ //Util.Debug(">> clientCutText");
+ var arr, i, n;
+ arr = [6]; // msg-type
+ arr.push8(0); // padding
+ arr.push8(0); // padding
+ arr.push8(0); // padding
+ arr.push32(text.length);
+ n = text.length;
+ for (i=0; i < n; i+=1) {
+ arr.push(text.charCodeAt(i));
+ }
+ //Util.Debug("<< clientCutText:" + arr);
+ return arr;
+};
+
+
+
+//
+// Public API interface functions
+//
+
+that.connect = function(host, port, password, path) {
+ //Util.Debug(">> connect");
+
+ rfb_host = host;
+ rfb_port = port;
+ rfb_password = (password !== undefined) ? password : "";
+ rfb_path = (path !== undefined) ? path : "";
+
+ if ((!rfb_host) || (!rfb_port)) {
+ return fail("Must set host and port");
+ }
+
+ updateState('connect');
+ //Util.Debug("<< connect");
+
+};
+
+that.disconnect = function() {
+ //Util.Debug(">> disconnect");
+ updateState('disconnect', 'Disconnecting');
+ //Util.Debug("<< disconnect");
+};
+
+that.sendPassword = function(passwd) {
+ rfb_password = passwd;
+ rfb_state = "Authentication";
+ setTimeout(init_msg, 1);
+};
+
+that.sendCtrlAltDel = function() {
+ if (rfb_state !== "normal" || conf.view_only) { return false; }
+ Util.Info("Sending Ctrl-Alt-Del");
+ var arr = [];
+ arr = arr.concat(keyEvent(0xFFE3, 1)); // Control
+ arr = arr.concat(keyEvent(0xFFE9, 1)); // Alt
+ arr = arr.concat(keyEvent(0xFFFF, 1)); // Delete
+ arr = arr.concat(keyEvent(0xFFFF, 0)); // Delete
+ arr = arr.concat(keyEvent(0xFFE9, 0)); // Alt
+ arr = arr.concat(keyEvent(0xFFE3, 0)); // Control
+ arr = arr.concat(fbUpdateRequests());
+ ws.send(arr);
+};
+
+// Send a key press. If 'down' is not specified then send a down key
+// followed by an up key.
+that.sendKey = function(code, down) {
+ if (rfb_state !== "normal" || conf.view_only) { return false; }
+ var arr = [];
+ if (typeof down !== 'undefined') {
+ Util.Info("Sending key code (" + (down ? "down" : "up") + "): " + code);
+ arr = arr.concat(keyEvent(code, down ? 1 : 0));
+ } else {
+ Util.Info("Sending key code (down + up): " + code);
+ arr = arr.concat(keyEvent(code, 1));
+ arr = arr.concat(keyEvent(code, 0));
+ }
+ arr = arr.concat(fbUpdateRequests());
+ ws.send(arr);
+};
+
+that.clipboardPasteFrom = function(text) {
+ if (rfb_state !== "normal") { return; }
+ //Util.Debug(">> clipboardPasteFrom: " + text.substr(0,40) + "...");
+ ws.send(clientCutText(text));
+ //Util.Debug("<< clipboardPasteFrom");
+};
+
+// Override internal functions for testing
+that.testMode = function(override_send, data_mode) {
+ test_mode = true;
+ that.recv_message = ws.testMode(override_send, data_mode);
+
+ checkEvents = function () { /* Stub Out */ };
+ that.connect = function(host, port, password) {
+ rfb_host = host;
+ rfb_port = port;
+ rfb_password = password;
+ init_vars();
+ updateState('ProtocolVersion', "Starting VNC handshake");
+ };
+};
+
+
+return constructor(); // Return the public API interface
+
+} // End of RFB()
diff --git a/ui/js/novnc/util.js b/ui/js/novnc/util.js
new file mode 100644
index 0000000..983f260
--- /dev/null
+++ b/ui/js/novnc/util.js
@@ -0,0 +1,381 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2012 Joel Martin
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ */
+
+"use strict";
+/*jslint bitwise: false, white: false */
+/*global window, console, document, navigator, ActiveXObject */
+
+// Globals defined here
+var Util = {};
+
+
+/*
+ * Make arrays quack
+ */
+
+Array.prototype.push8 = function (num) {
+ this.push(num & 0xFF);
+};
+
+Array.prototype.push16 = function (num) {
+ this.push((num >> 8) & 0xFF,
+ (num ) & 0xFF );
+};
+Array.prototype.push32 = function (num) {
+ this.push((num >> 24) & 0xFF,
+ (num >> 16) & 0xFF,
+ (num >> 8) & 0xFF,
+ (num ) & 0xFF );
+};
+
+// IE does not support map (even in IE9)
+//This prototype is provided by the Mozilla foundation and
+//is distributed under the MIT license.
+//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
+if (!Array.prototype.map)
+{
+ Array.prototype.map = function(fun /*, thisp*/)
+ {
+ var len = this.length;
+ if (typeof fun != "function")
+ throw new TypeError();
+
+ var res = new Array(len);
+ var thisp = arguments[1];
+ for (var i = 0; i < len; i++)
+ {
+ if (i in this)
+ res[i] = fun.call(thisp, this[i], i, this);
+ }
+
+ return res;
+ };
+}
+
+//
+// requestAnimationFrame shim with setTimeout fallback
+//
+
+window.requestAnimFrame = (function(){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback){
+ window.setTimeout(callback, 1000 / 60);
+ };
+})();
+
+/*
+ * ------------------------------------------------------
+ * Namespaced in Util
+ * ------------------------------------------------------
+ */
+
+/*
+ * Logging/debug routines
+ */
+
+Util._log_level = 'warn';
+Util.init_logging = function (level) {
+ if (typeof level === 'undefined') {
+ level = Util._log_level;
+ } else {
+ Util._log_level = level;
+ }
+ if (typeof window.console === "undefined") {
+ if (typeof window.opera !== "undefined") {
+ window.console = {
+ 'log' : window.opera.postError,
+ 'warn' : window.opera.postError,
+ 'error': window.opera.postError };
+ } else {
+ window.console = {
+ 'log' : function(m) {},
+ 'warn' : function(m) {},
+ 'error': function(m) {}};
+ }
+ }
+
+ Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
+ switch (level) {
+ case 'debug': Util.Debug = function (msg) { console.log(msg); };
+ case 'info': Util.Info = function (msg) { console.log(msg); };
+ case 'warn': Util.Warn = function (msg) { console.warn(msg); };
+ case 'error': Util.Error = function (msg) { console.error(msg); };
+ case 'none':
+ break;
+ default:
+ throw("invalid logging type '" + level + "'");
+ }
+};
+Util.get_logging = function () {
+ return Util._log_level;
+};
+// Initialize logging level
+Util.init_logging();
+
+
+// Set configuration default for Crockford style function namespaces
+Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) {
+ var getter, setter;
+
+ // Default getter function
+ getter = function (idx) {
+ if ((type in {'arr':1, 'array':1}) &&
+ (typeof idx !== 'undefined')) {
+ return cfg[v][idx];
+ } else {
+ return cfg[v];
+ }
+ };
+
+ // Default setter function
+ setter = function (val, idx) {
+ if (type in {'boolean':1, 'bool':1}) {
+ if ((!val) || (val in {'0':1, 'no':1, 'false':1})) {
+ val = false;
+ } else {
+ val = true;
+ }
+ } else if (type in {'integer':1, 'int':1}) {
+ val = parseInt(val, 10);
+ } else if (type === 'str') {
+ val = String(val);
+ } else if (type === 'func') {
+ if (!val) {
+ val = function () {};
+ }
+ }
+ if (typeof idx !== 'undefined') {
+ cfg[v][idx] = val;
+ } else {
+ cfg[v] = val;
+ }
+ };
+
+ // Set the description
+ api[v + '_description'] = desc;
+
+ // Set the getter function
+ if (typeof api['get_' + v] === 'undefined') {
+ api['get_' + v] = getter;
+ }
+
+ // Set the setter function with extra sanity checks
+ if (typeof api['set_' + v] === 'undefined') {
+ api['set_' + v] = function (val, idx) {
+ if (mode in {'RO':1, 'ro':1}) {
+ throw(v + " is read-only");
+ } else if ((mode in {'WO':1, 'wo':1}) &&
+ (typeof cfg[v] !== 'undefined')) {
+ throw(v + " can only be set once");
+ }
+ setter(val, idx);
+ };
+ }
+
+ // Set the default value
+ if (typeof defaults[v] !== 'undefined') {
+ defval = defaults[v];
+ } else if ((type in {'arr':1, 'array':1}) &&
+ (! (defval instanceof Array))) {
+ defval = [];
+ }
+ // Coerce existing setting to the right type
+ //Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]);
+ setter(defval);
+};
+
+// Set group of configuration defaults
+Util.conf_defaults = function(cfg, api, defaults, arr) {
+ var i;
+ for (i = 0; i < arr.length; i++) {
+ Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1],
+ arr[i][2], arr[i][3], arr[i][4]);
+ }
+};
+
+
+/*
+ * Cross-browser routines
+ */
+
+
+// Dynamically load scripts without using document.write()
+// Reference: http://unixpapa.com/js/dyna.html
+//
+// Handles the case where load_scripts is invoked from a script that
+// itself is loaded via load_scripts. Once all scripts are loaded the
+// window.onscriptsloaded handler is called (if set).
+Util.get_include_uri = function() {
+ return (typeof INCLUDE_URI !== "undefined") ? INCLUDE_URI : "include/";
+}
+Util._loading_scripts = [];
+Util._pending_scripts = [];
+Util.load_scripts = function(files) {
+ var head = document.getElementsByTagName('head')[0], script,
+ ls = Util._loading_scripts, ps = Util._pending_scripts;
+ for (var f=0; f<files.length; f++) {
+ script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = Util.get_include_uri() + files[f];
+ //console.log("loading script: " + script.src);
+ script.onload = script.onreadystatechange = function (e) {
+ while (ls.length > 0 && (ls[0].readyState === 'loaded' ||
+ ls[0].readyState === 'complete')) {
+ // For IE, append the script to trigger execution
+ var s = ls.shift();
+ //console.log("loaded script: " + s.src);
+ head.appendChild(s);
+ }
+ if (!this.readyState ||
+ (Util.Engine.presto && this.readyState === 'loaded') ||
+ this.readyState === 'complete') {
+ if (ps.indexOf(this) >= 0) {
+ this.onload = this.onreadystatechange = null;
+ //console.log("completed script: " + this.src);
+ ps.splice(ps.indexOf(this), 1);
+
+ // Call window.onscriptsload after last script loads
+ if (ps.length === 0 && window.onscriptsload) {
+ window.onscriptsload();
+ }
+ }
+ }
+ };
+ // In-order script execution tricks
+ if (Util.Engine.trident) {
+ // For IE wait until readyState is 'loaded' before
+ // appending it which will trigger execution
+ // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+ ls.push(script);
+ } else {
+ // For webkit and firefox set async=false and append now
+ // https://developer.mozilla.org/en-US/docs/HTML/Element/script
+ script.async = false;
+ head.appendChild(script);
+ }
+ ps.push(script);
+ }
+}
+
+// Get DOM element position on page
+Util.getPosition = function (obj) {
+ var x = 0, y = 0;
+ if (obj.offsetParent) {
+ do {
+ x += obj.offsetLeft;
+ y += obj.offsetTop;
+ obj = obj.offsetParent;
+ } while (obj);
+ }
+ return {'x': x, 'y': y};
+};
+
+// Get mouse event position in DOM element
+Util.getEventPosition = function (e, obj, scale) {
+ var evt, docX, docY, pos;
+ //if (!e) evt = window.event;
+ evt = (e ? e : window.event);
+ evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt);
+ if (evt.pageX || evt.pageY) {
+ docX = evt.pageX;
+ docY = evt.pageY;
+ } else if (evt.clientX || evt.clientY) {
+ docX = evt.clientX + document.body.scrollLeft +
+ document.documentElement.scrollLeft;
+ docY = evt.clientY + document.body.scrollTop +
+ document.documentElement.scrollTop;
+ }
+ pos = Util.getPosition(obj);
+ if (typeof scale === "undefined") {
+ scale = 1;
+ }
+ var x = Math.max(Math.min(docX - pos.x, obj.width-1), 0);
+ var y = Math.max(Math.min(docY - pos.y, obj.height-1), 0);
+ return {'x': x / scale, 'y': y / scale};
+};
+
+
+// Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events
+Util.addEvent = function (obj, evType, fn){
+ if (obj.attachEvent){
+ var r = obj.attachEvent("on"+evType, fn);
+ return r;
+ } else if (obj.addEventListener){
+ obj.addEventListener(evType, fn, false);
+ return true;
+ } else {
+ throw("Handler could not be attached");
+ }
+};
+
+Util.removeEvent = function(obj, evType, fn){
+ if (obj.detachEvent){
+ var r = obj.detachEvent("on"+evType, fn);
+ return r;
+ } else if (obj.removeEventListener){
+ obj.removeEventListener(evType, fn, false);
+ return true;
+ } else {
+ throw("Handler could not be removed");
+ }
+};
+
+Util.stopEvent = function(e) {
+ if (e.stopPropagation) { e.stopPropagation(); }
+ else { e.cancelBubble = true; }
+
+ if (e.preventDefault) { e.preventDefault(); }
+ else { e.returnValue = false; }
+};
+
+
+// Set browser engine versions. Based on mootools.
+Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
+
+Util.Engine = {
+ // Version detection break in Opera 11.60 (errors on arguments.callee.caller reference)
+ //'presto': (function() {
+ // return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
+ 'presto': (function() { return (!window.opera) ? false : true; }()),
+
+ 'trident': (function() {
+ return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()),
+ 'webkit': (function() {
+ try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()),
+ //'webkit': (function() {
+ // return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()),
+ 'gecko': (function() {
+ return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }())
+};
+if (Util.Engine.webkit) {
+ // Extract actual webkit version if available
+ Util.Engine.webkit = (function(v) {
+ var re = new RegExp('WebKit/([0-9\.]*) ');
+ v = (navigator.userAgent.match(re) || ['', v])[1];
+ return parseFloat(v, 10);
+ })(Util.Engine.webkit);
+}
+
+Util.Flash = (function(){
+ var v, version;
+ try {
+ v = navigator.plugins['Shockwave Flash'].description;
+ } catch(err1) {
+ try {
+ v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
+ } catch(err2) {
+ v = '0 r0';
+ }
+ }
+ version = v.match(/\d+/g);
+ return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
+}());
diff --git a/ui/js/novnc/web-socket-js/Makefile.am b/ui/js/novnc/web-socket-js/Makefile.am
new file mode 100644
index 0000000..7d685f5
--- /dev/null
+++ b/ui/js/novnc/web-socket-js/Makefile.am
@@ -0,0 +1,24 @@
+#
+# Kimchi
+#
+# Copyright IBM, Corp. 2013
+#
+# Licensed 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.
+
+websocketdir = $(datadir)/kimchi/ui/js/novnc/web-socket-js
+
+dist_websocket_DATA = \
+ swfobject.js \
+ WebSocketMain.swf \
+ web_socket.js \
+ $(NULL)
diff --git a/ui/js/novnc/web-socket-js/README.txt b/ui/js/novnc/web-socket-js/README.txt
new file mode 100644
index 0000000..91a68cc
--- /dev/null
+++ b/ui/js/novnc/web-socket-js/README.txt
@@ -0,0 +1,109 @@
+* How to try
+
+Assuming you have Web server (e.g. Apache) running at http://example.com/ .
+
+- Download web_socket.rb from:
+ http://github.com/gimite/web-socket-ruby/tree/master
+- Run sample Web Socket server (echo server) in example.com with: (#1)
+ $ ruby web-socket-ruby/samples/echo_server.rb example.com 10081
+- If your server already provides socket policy file at port 843, modify the file to allow access to port 10081. Otherwise you can skip this step. See below for details.
+- Publish the web-socket-js directory with your Web server (e.g. put it in ~/public_html).
+- Change ws://localhost:10081 to ws://example.com:10081 in sample.html.
+- Open sample.html in your browser.
+- After "onopen" is shown, input something, click [Send] and confirm echo back.
+
+#1: First argument of echo_server.rb means that it accepts Web Socket connection from HTML pages in example.com.
+
+
+* Troubleshooting
+
+If it doesn't work, try these:
+
+1. Try Chrome and Firefox 3.x.
+- It doesn't work on Chrome:
+-- It's likely an issue of your code or the server. Debug your code as usual e.g. using console.log.
+- It works on Chrome but it doesn't work on Firefox:
+-- It's likely an issue of web-socket-js specific configuration (e.g. 3 and 4 below).
+- It works on both Chrome and Firefox, but it doesn't work on your browser:
+-- Check "Supported environment" section below. Your browser may not be supported by web-socket-js.
+
+2. Add this line before your code:
+ WEB_SOCKET_DEBUG = true;
+and use Developer Tools (Chrome/Safari) or Firebug (Firefox) to see if console.log outputs any errors.
+
+3. Make sure you do NOT open your HTML page as local file e.g. file:///.../sample.html. web-socket-js doesn't work on local file. Open it via Web server e.g. http:///.../sample.html.
+
+4. If you are NOT using web-socket-ruby as your WebSocket server, you need to place Flash socket policy file on your server. See "Flash socket policy file" section below for details.
+
+5. Check if sample.html bundled with web-socket-js works.
+
+6. Make sure the port used for WebSocket (10081 in example above) is not blocked by your server/client's firewall.
+
+7. Install debugger version of Flash Player available here to see Flash errors:
+http://www.adobe.com/support/flashplayer/downloads.html
+
+
+* Supported environments
+
+It should work on:
+- Google Chrome 4 or later (just uses native implementation)
+- Firefox 3.x, Internet Explorer 8 + Flash Player 9 or later
+
+It may or may not work on other browsers such as Safari, Opera or IE 6. Patch for these browsers are appreciated, but I will not work on fixing issues specific to these browsers by myself.
+
+
+* Flash socket policy file
+
+This implementation uses Flash's socket, which means that your server must provide Flash socket policy file to declare the server accepts connections from Flash.
+
+If you use web-socket-ruby available at
+http://github.com/gimite/web-socket-ruby/tree/master
+, you don't need anything special, because web-socket-ruby handles Flash socket policy file request. But if you already provide socket policy file at port 843, you need to modify the file to allow access to Web Socket port, because it precedes what web-socket-ruby provides.
+
+If you use other Web Socket server implementation, you need to provide socket policy file yourself. See
+http://www.lightsphere.com/dev/articles/flash_socket_policy.html
+for details and sample script to run socket policy file server. node.js implementation is available here:
+http://github.com/LearnBoost/Socket.IO-node/blob/master/lib/socket.io/transports/flashsocket.js
+
+Actually, it's still better to provide socket policy file at port 843 even if you use web-socket-ruby. Flash always try to connect to port 843 first, so providing the file at port 843 makes startup faster.
+
+
+* Cookie considerations
+
+Cookie is sent if Web Socket host is the same as the origin of JavaScript. Otherwise it is not sent, because I don't know way to send right Cookie (which is Cookie of the host of Web Socket, I heard).
+
+Note that it's technically possible that client sends arbitrary string as Cookie and any other headers (by modifying this library for example) once you place Flash socket policy file in your server. So don't trust Cookie and other headers if you allow connection from untrusted origin.
+
+
+* Proxy considerations
+
+The WebSocket spec (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol) specifies instructions for User Agents to support proxied connections by implementing the HTTP CONNECT method.
+
+The AS3 Socket class doesn't implement this mechanism, which renders it useless for the scenarios where the user trying to open a socket is behind a proxy.
+
+The class RFC2817Socket (by Christian Cantrell) effectively lets us implement this, as long as the proxy settings are known and provided by the interface that instantiates the WebSocket. As such, if you want to support proxied conncetions, you'll have to supply this information to the WebSocket constructor when Flash is being used. One way to go about it would be to ask the user for proxy settings information if the initial connection fails.
+
+
+* How to host HTML file and SWF file in different domains
+
+By default, HTML file and SWF file must be in the same domain. You can follow steps below to allow hosting them in different domain.
+
+WARNING: If you use the method below, HTML files in ANY domains can send arbitrary TCP data to your WebSocket server, regardless of configuration in Flash socket policy file. Arbitrary TCP data means that they can even fake request headers including Origin and Cookie.
+
+- Unzip WebSocketMainInsecure.zip to extract WebSocketMainInsecure.swf.
+- Put WebSocketMainInsecure.swf on your server, instead of WebSocketMain.swf.
+- In JavaScript, set WEB_SOCKET_SWF_LOCATION to URL of your WebSocketMainInsecure.swf.
+
+
+* How to build WebSocketMain.swf
+
+Install Flex 4 SDK:
+http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4
+
+$ cd flash-src
+$ ./build.sh
+
+
+* License
+
+New BSD License.
diff --git a/ui/js/novnc/web-socket-js/WebSocketMain.swf b/ui/js/novnc/web-socket-js/WebSocketMain.swf
new file mode 100644
index 0000000000000000000000000000000000000000..8174466912475a494681e9436844f4bf90d909f9
GIT binary patch
literal 177114
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�{?S0&?Rq)c&c-(}SFHOPy4tz`b5gun?zakh{
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	hoe8>6)Ss!@E`XyN(WVfR)gw|2I
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
G)Bgi3fUR8s
literal 0
HcmV?d00001
diff --git a/ui/js/novnc/web-socket-js/swfobject.js b/ui/js/novnc/web-socket-js/swfobject.js
new file mode 100644
index 0000000..02055f2
--- /dev/null
+++ b/ui/js/novnc/web-socket-js/swfobject.js
@@ -0,0 +1,4 @@
+/* SWFObject v2.2 <http://code.google.com/p/swfobject/>
+ is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
+*/
+var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replac!
diff --git a/ui/js/novnc/web-socket-js/web_socket.js b/ui/js/novnc/web-socket-js/web_socket.js
new file mode 100644
index 0000000..a7828fa
--- /dev/null
+++ b/ui/js/novnc/web-socket-js/web_socket.js
@@ -0,0 +1,391 @@
+// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
+// License: New BSD License
+// Reference: http://dev.w3.org/html5/websockets/
+// Reference: http://tools.ietf.org/html/rfc6455
+
+(function() {
+
+ if (window.WEB_SOCKET_FORCE_FLASH) {
+ // Keeps going.
+ } else if (window.WebSocket) {
+ return;
+ } else if (window.MozWebSocket) {
+ // Firefox.
+ window.WebSocket = MozWebSocket;
+ return;
+ }
+
+ var logger;
+ if (window.WEB_SOCKET_LOGGER) {
+ logger = WEB_SOCKET_LOGGER;
+ } else if (window.console && window.console.log && window.console.error) {
+ // In some environment, console is defined but console.log or console.error is missing.
+ logger = window.console;
+ } else {
+ logger = {log: function(){ }, error: function(){ }};
+ }
+
+ // swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash.
+ if (swfobject.getFlashPlayerVersion().major < 10) {
+ logger.error("Flash Player >= 10.0.0 is required.");
+ return;
+ }
+ if (location.protocol == "file:") {
+ logger.error(
+ "WARNING: web-socket-js doesn't work in file:///... URL " +
+ "unless you set Flash Security Settings properly. " +
+ "Open the page via Web server i.e. http://...");
+ }
+
+ /**
+ * Our own implementation of WebSocket class using Flash.
+ * @param {string} url
+ * @param {array or string} protocols
+ * @param {string} proxyHost
+ * @param {int} proxyPort
+ * @param {string} headers
+ */
+ window.WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
+ var self = this;
+ self.__id = WebSocket.__nextId++;
+ WebSocket.__instances[self.__id] = self;
+ self.readyState = WebSocket.CONNECTING;
+ self.bufferedAmount = 0;
+ self.__events = {};
+ if (!protocols) {
+ protocols = [];
+ } else if (typeof protocols == "string") {
+ protocols = [protocols];
+ }
+ // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
+ // Otherwise, when onopen fires immediately, onopen is called before it is set.
+ self.__createTask = setTimeout(function() {
+ WebSocket.__addTask(function() {
+ self.__createTask = null;
+ WebSocket.__flash.create(
+ self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
+ });
+ }, 0);
+ };
+
+ /**
+ * Send data to the web socket.
+ * @param {string} data The data to send to the socket.
+ * @return {boolean} True for success, false for failure.
+ */
+ WebSocket.prototype.send = function(data) {
+ if (this.readyState == WebSocket.CONNECTING) {
+ throw "INVALID_STATE_ERR: Web Socket connection has not been established";
+ }
+ // We use encodeURIComponent() here, because FABridge doesn't work if
+ // the argument includes some characters. We don't use escape() here
+ // because of this:
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape…
+ // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
+ // preserve all Unicode characters either e.g. "\uffff" in Firefox.
+ // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
+ // additional testing.
+ var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
+ if (result < 0) { // success
+ return true;
+ } else {
+ this.bufferedAmount += result;
+ return false;
+ }
+ };
+
+ /**
+ * Close this web socket gracefully.
+ */
+ WebSocket.prototype.close = function() {
+ if (this.__createTask) {
+ clearTimeout(this.__createTask);
+ this.__createTask = null;
+ this.readyState = WebSocket.CLOSED;
+ return;
+ }
+ if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
+ return;
+ }
+ this.readyState = WebSocket.CLOSING;
+ WebSocket.__flash.close(this.__id);
+ };
+
+ /**
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
+ *
+ * @param {string} type
+ * @param {function} listener
+ * @param {boolean} useCapture
+ * @return void
+ */
+ WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
+ if (!(type in this.__events)) {
+ this.__events[type] = [];
+ }
+ this.__events[type].push(listener);
+ };
+
+ /**
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
+ *
+ * @param {string} type
+ * @param {function} listener
+ * @param {boolean} useCapture
+ * @return void
+ */
+ WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
+ if (!(type in this.__events)) return;
+ var events = this.__events[type];
+ for (var i = events.length - 1; i >= 0; --i) {
+ if (events[i] === listener) {
+ events.splice(i, 1);
+ break;
+ }
+ }
+ };
+
+ /**
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
+ *
+ * @param {Event} event
+ * @return void
+ */
+ WebSocket.prototype.dispatchEvent = function(event) {
+ var events = this.__events[event.type] || [];
+ for (var i = 0; i < events.length; ++i) {
+ events[i](event);
+ }
+ var handler = this["on" + event.type];
+ if (handler) handler.apply(this, [event]);
+ };
+
+ /**
+ * Handles an event from Flash.
+ * @param {Object} flashEvent
+ */
+ WebSocket.prototype.__handleEvent = function(flashEvent) {
+
+ if ("readyState" in flashEvent) {
+ this.readyState = flashEvent.readyState;
+ }
+ if ("protocol" in flashEvent) {
+ this.protocol = flashEvent.protocol;
+ }
+
+ var jsEvent;
+ if (flashEvent.type == "open" || flashEvent.type == "error") {
+ jsEvent = this.__createSimpleEvent(flashEvent.type);
+ } else if (flashEvent.type == "close") {
+ jsEvent = this.__createSimpleEvent("close");
+ jsEvent.wasClean = flashEvent.wasClean ? true : false;
+ jsEvent.code = flashEvent.code;
+ jsEvent.reason = flashEvent.reason;
+ } else if (flashEvent.type == "message") {
+ var data = decodeURIComponent(flashEvent.message);
+ jsEvent = this.__createMessageEvent("message", data);
+ } else {
+ throw "unknown event type: " + flashEvent.type;
+ }
+
+ this.dispatchEvent(jsEvent);
+
+ };
+
+ WebSocket.prototype.__createSimpleEvent = function(type) {
+ if (document.createEvent && window.Event) {
+ var event = document.createEvent("Event");
+ event.initEvent(type, false, false);
+ return event;
+ } else {
+ return {type: type, bubbles: false, cancelable: false};
+ }
+ };
+
+ WebSocket.prototype.__createMessageEvent = function(type, data) {
+ if (document.createEvent && window.MessageEvent && !window.opera) {
+ var event = document.createEvent("MessageEvent");
+ event.initMessageEvent("message", false, false, data, null, null, window, null);
+ return event;
+ } else {
+ // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
+ return {type: type, data: data, bubbles: false, cancelable: false};
+ }
+ };
+
+ /**
+ * Define the WebSocket readyState enumeration.
+ */
+ WebSocket.CONNECTING = 0;
+ WebSocket.OPEN = 1;
+ WebSocket.CLOSING = 2;
+ WebSocket.CLOSED = 3;
+
+ // Field to check implementation of WebSocket.
+ WebSocket.__isFlashImplementation = true;
+ WebSocket.__initialized = false;
+ WebSocket.__flash = null;
+ WebSocket.__instances = {};
+ WebSocket.__tasks = [];
+ WebSocket.__nextId = 0;
+
+ /**
+ * Load a new flash security policy file.
+ * @param {string} url
+ */
+ WebSocket.loadFlashPolicyFile = function(url){
+ WebSocket.__addTask(function() {
+ WebSocket.__flash.loadManualPolicyFile(url);
+ });
+ };
+
+ /**
+ * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
+ */
+ WebSocket.__initialize = function() {
+
+ if (WebSocket.__initialized) return;
+ WebSocket.__initialized = true;
+
+ if (WebSocket.__swfLocation) {
+ // For backword compatibility.
+ window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
+ }
+ if (!window.WEB_SOCKET_SWF_LOCATION) {
+ logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
+ return;
+ }
+ if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR &&
+ !WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) &&
+ WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) {
+ var swfHost = RegExp.$1;
+ if (location.host != swfHost) {
+ logger.error(
+ "[WebSocket] You must host HTML and WebSocketMain.swf in the same host " +
+ "('" + location.host + "' != '" + swfHost + "'). " +
+ "See also 'How to host HTML file and SWF file in different domains' section " +
+ "in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " +
+ "by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;");
+ }
+ }
+ var container = document.createElement("div");
+ container.id = "webSocketContainer";
+ // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
+ // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
+ // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
+ // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
+ // the best we can do as far as we know now.
+ container.style.position = "absolute";
+ if (WebSocket.__isFlashLite()) {
+ container.style.left = "0px";
+ container.style.top = "0px";
+ } else {
+ container.style.left = "-100px";
+ container.style.top = "-100px";
+ }
+ var holder = document.createElement("div");
+ holder.id = "webSocketFlash";
+ container.appendChild(holder);
+ document.body.appendChild(container);
+ // See this article for hasPriority:
+ // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc…
+ swfobject.embedSWF(
+ WEB_SOCKET_SWF_LOCATION,
+ "webSocketFlash",
+ "1" /* width */,
+ "1" /* height */,
+ "10.0.0" /* SWF version */,
+ null,
+ null,
+ {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
+ null,
+ function(e) {
+ if (!e.success) {
+ logger.error("[WebSocket] swfobject.embedSWF failed");
+ }
+ }
+ );
+
+ };
+
+ /**
+ * Called by Flash to notify JS that it's fully loaded and ready
+ * for communication.
+ */
+ WebSocket.__onFlashInitialized = function() {
+ // We need to set a timeout here to avoid round-trip calls
+ // to flash during the initialization process.
+ setTimeout(function() {
+ WebSocket.__flash = document.getElementById("webSocketFlash");
+ WebSocket.__flash.setCallerUrl(location.href);
+ WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
+ for (var i = 0; i < WebSocket.__tasks.length; ++i) {
+ WebSocket.__tasks[i]();
+ }
+ WebSocket.__tasks = [];
+ }, 0);
+ };
+
+ /**
+ * Called by Flash to notify WebSockets events are fired.
+ */
+ WebSocket.__onFlashEvent = function() {
+ setTimeout(function() {
+ try {
+ // Gets events using receiveEvents() instead of getting it from event object
+ // of Flash event. This is to make sure to keep message order.
+ // It seems sometimes Flash events don't arrive in the same order as they are sent.
+ var events = WebSocket.__flash.receiveEvents();
+ for (var i = 0; i < events.length; ++i) {
+ WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
+ }
+ } catch (e) {
+ logger.error(e);
+ }
+ }, 0);
+ return true;
+ };
+
+ // Called by Flash.
+ WebSocket.__log = function(message) {
+ logger.log(decodeURIComponent(message));
+ };
+
+ // Called by Flash.
+ WebSocket.__error = function(message) {
+ logger.error(decodeURIComponent(message));
+ };
+
+ WebSocket.__addTask = function(task) {
+ if (WebSocket.__flash) {
+ task();
+ } else {
+ WebSocket.__tasks.push(task);
+ }
+ };
+
+ /**
+ * Test if the browser is running flash lite.
+ * @return {boolean} True if flash lite is running, false otherwise.
+ */
+ WebSocket.__isFlashLite = function() {
+ if (!window.navigator || !window.navigator.mimeTypes) {
+ return false;
+ }
+ var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
+ if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
+ return false;
+ }
+ return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
+ };
+
+ if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
+ // NOTE:
+ // This fires immediately if web_socket.js is dynamically loaded after
+ // the document is loaded.
+ swfobject.addDomLoadEvent(function() {
+ WebSocket.__initialize();
+ });
+ }
+
+})();
diff --git a/ui/js/novnc/websock.js b/ui/js/novnc/websock.js
new file mode 100644
index 0000000..2a2080f
--- /dev/null
+++ b/ui/js/novnc/websock.js
@@ -0,0 +1,422 @@
+/*
+ * Websock: high-performance binary WebSockets
+ * Copyright (C) 2012 Joel Martin
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * Websock is similar to the standard WebSocket object but Websock
+ * enables communication with raw TCP sockets (i.e. the binary stream)
+ * via websockify. This is accomplished by base64 encoding the data
+ * stream between Websock and websockify.
+ *
+ * Websock has built-in receive queue buffering; the message event
+ * does not contain actual data but is simply a notification that
+ * there is new data available. Several rQ* methods are available to
+ * read binary data off of the receive queue.
+ */
+
+/*jslint browser: true, bitwise: false, plusplus: false */
+/*global Util, Base64 */
+
+
+// Load Flash WebSocket emulator if needed
+
+// To force WebSocket emulator even when native WebSocket available
+//window.WEB_SOCKET_FORCE_FLASH = true;
+// To enable WebSocket emulator debug:
+//window.WEB_SOCKET_DEBUG=1;
+
+if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
+ Websock_native = true;
+} else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
+ Websock_native = true;
+ window.WebSocket = window.MozWebSocket;
+} else {
+ /* no builtin WebSocket so load web_socket.js */
+
+ Websock_native = false;
+ (function () {
+ window.WEB_SOCKET_SWF_LOCATION = Util.get_include_uri() +
+ "web-socket-js/WebSocketMain.swf";
+ if (Util.Engine.trident) {
+ Util.Debug("Forcing uncached load of WebSocketMain.swf");
+ window.WEB_SOCKET_SWF_LOCATION += "?" + Math.random();
+ }
+ Util.load_scripts(["web-socket-js/swfobject.js",
+ "web-socket-js/web_socket.js"]);
+ }());
+}
+
+
+function Websock() {
+"use strict";
+
+var api = {}, // Public API
+ websocket = null, // WebSocket object
+ mode = 'base64', // Current WebSocket mode: 'binary', 'base64'
+ rQ = [], // Receive queue
+ rQi = 0, // Receive queue index
+ rQmax = 10000, // Max receive queue size before compacting
+ sQ = [], // Send queue
+
+ eventHandlers = {
+ 'message' : function() {},
+ 'open' : function() {},
+ 'close' : function() {},
+ 'error' : function() {}
+ },
+
+ test_mode = false;
+
+
+//
+// Queue public functions
+//
+
+function get_sQ() {
+ return sQ;
+}
+
+function get_rQ() {
+ return rQ;
+}
+function get_rQi() {
+ return rQi;
+}
+function set_rQi(val) {
+ rQi = val;
+}
+
+function rQlen() {
+ return rQ.length - rQi;
+}
+
+function rQpeek8() {
+ return (rQ[rQi] );
+}
+function rQshift8() {
+ return (rQ[rQi++] );
+}
+function rQunshift8(num) {
+ if (rQi === 0) {
+ rQ.unshift(num);
+ } else {
+ rQi -= 1;
+ rQ[rQi] = num;
+ }
+
+}
+function rQshift16() {
+ return (rQ[rQi++] << 8) +
+ (rQ[rQi++] );
+}
+function rQshift32() {
+ return (rQ[rQi++] << 24) +
+ (rQ[rQi++] << 16) +
+ (rQ[rQi++] << 8) +
+ (rQ[rQi++] );
+}
+function rQshiftStr(len) {
+ if (typeof(len) === 'undefined') { len = rQlen(); }
+ var arr = rQ.slice(rQi, rQi + len);
+ rQi += len;
+ return String.fromCharCode.apply(null, arr);
+}
+function rQshiftBytes(len) {
+ if (typeof(len) === 'undefined') { len = rQlen(); }
+ rQi += len;
+ return rQ.slice(rQi-len, rQi);
+}
+
+function rQslice(start, end) {
+ if (end) {
+ return rQ.slice(rQi + start, rQi + end);
+ } else {
+ return rQ.slice(rQi + start);
+ }
+}
+
+// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
+// to be available in the receive queue. Return true if we need to
+// wait (and possibly print a debug message), otherwise false.
+function rQwait(msg, num, goback) {
+ var rQlen = rQ.length - rQi; // Skip rQlen() function call
+ if (rQlen < num) {
+ if (goback) {
+ if (rQi < goback) {
+ throw("rQwait cannot backup " + goback + " bytes");
+ }
+ rQi -= goback;
+ }
+ //Util.Debug(" waiting for " + (num-rQlen) +
+ // " " + msg + " byte(s)");
+ return true; // true means need more data
+ }
+ return false;
+}
+
+//
+// Private utility routines
+//
+
+function encode_message() {
+ if (mode === 'binary') {
+ // Put in a binary arraybuffer
+ return (new Uint8Array(sQ)).buffer;
+ } else {
+ // base64 encode
+ return Base64.encode(sQ);
+ }
+}
+
+function decode_message(data) {
+ //Util.Debug(">> decode_message: " + data);
+ if (mode === 'binary') {
+ // push arraybuffer values onto the end
+ var u8 = new Uint8Array(data);
+ for (var i = 0; i < u8.length; i++) {
+ rQ.push(u8[i]);
+ }
+ } else {
+ // base64 decode and concat to the end
+ rQ = rQ.concat(Base64.decode(data, 0));
+ }
+ //Util.Debug(">> decode_message, rQ: " + rQ);
+}
+
+
+//
+// Public Send functions
+//
+
+function flush() {
+ if (websocket.bufferedAmount !== 0) {
+ Util.Debug("bufferedAmount: " + websocket.bufferedAmount);
+ }
+ if (websocket.bufferedAmount < api.maxBufferedAmount) {
+ //Util.Debug("arr: " + arr);
+ //Util.Debug("sQ: " + sQ);
+ if (sQ.length > 0) {
+ websocket.send(encode_message(sQ));
+ sQ = [];
+ }
+ return true;
+ } else {
+ Util.Info("Delaying send, bufferedAmount: " +
+ websocket.bufferedAmount);
+ return false;
+ }
+}
+
+// overridable for testing
+function send(arr) {
+ //Util.Debug(">> send_array: " + arr);
+ sQ = sQ.concat(arr);
+ return flush();
+}
+
+function send_string(str) {
+ //Util.Debug(">> send_string: " + str);
+ api.send(str.split('').map(
+ function (chr) { return chr.charCodeAt(0); } ) );
+}
+
+//
+// Other public functions
+
+function recv_message(e) {
+ //Util.Debug(">> recv_message: " + e.data.length);
+
+ try {
+ decode_message(e.data);
+ if (rQlen() > 0) {
+ eventHandlers.message();
+ // Compact the receive queue
+ if (rQ.length > rQmax) {
+ //Util.Debug("Compacting receive queue");
+ rQ = rQ.slice(rQi);
+ rQi = 0;
+ }
+ } else {
+ Util.Debug("Ignoring empty message");
+ }
+ } catch (exc) {
+ if (typeof exc.stack !== 'undefined') {
+ Util.Warn("recv_message, caught exception: " + exc.stack);
+ } else if (typeof exc.description !== 'undefined') {
+ Util.Warn("recv_message, caught exception: " + exc.description);
+ } else {
+ Util.Warn("recv_message, caught exception:" + exc);
+ }
+ if (typeof exc.name !== 'undefined') {
+ eventHandlers.error(exc.name + ": " + exc.message);
+ } else {
+ eventHandlers.error(exc);
+ }
+ }
+ //Util.Debug("<< recv_message");
+}
+
+
+// Set event handlers
+function on(evt, handler) {
+ eventHandlers[evt] = handler;
+}
+
+function init(protocols) {
+ rQ = [];
+ rQi = 0;
+ sQ = [];
+ websocket = null;
+
+ var bt = false,
+ wsbt = false,
+ try_binary = false;
+
+ // Check for full typed array support
+ if (('Uint8Array' in window) &&
+ ('set' in Uint8Array.prototype)) {
+ bt = true;
+ }
+
+ // Check for full binary type support in WebSockets
+ // TODO: this sucks, the property should exist on the prototype
+ // but it does not.
+ //try {
+ // if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) {
+ // Util.Info("Detected binaryType support in WebSockets");
+ wsbt = true;
+ // }
+ //} catch (exc) {
+ // // Just ignore failed test localhost connections
+ //}
+
+ // Default protocols if not specified
+ if (typeof(protocols) === "undefined") {
+ if (wsbt) {
+ protocols = ['binary', 'base64'];
+ } else {
+ protocols = 'base64';
+ }
+ }
+
+ // If no binary support, make sure it was not requested
+ if (!wsbt) {
+ if (protocols === 'binary') {
+ throw("WebSocket binary sub-protocol requested but not supported");
+ }
+ if (typeof(protocols) === "object") {
+ var new_protocols = [];
+ for (var i = 0; i < protocols.length; i++) {
+ if (protocols[i] === 'binary') {
+ Util.Error("Skipping unsupported WebSocket binary sub-protocol");
+ } else {
+ new_protocols.push(protocols[i]);
+ }
+ }
+ if (new_protocols.length > 0) {
+ protocols = new_protocols;
+ } else {
+ throw("Only WebSocket binary sub-protocol was requested and not supported.");
+ }
+ }
+ }
+
+ return protocols;
+}
+
+function open(uri, protocols) {
+ protocols = init(protocols);
+
+ if (test_mode) {
+ websocket = {};
+ } else {
+ websocket = new WebSocket(uri, protocols);
+ if (protocols.indexOf('binary') >= 0) {
+ websocket.binaryType = 'arraybuffer';
+ }
+ }
+
+ websocket.onmessage = recv_message;
+ websocket.onopen = function() {
+ Util.Debug(">> WebSock.onopen");
+ if (websocket.protocol) {
+ mode = websocket.protocol;
+ Util.Info("Server chose sub-protocol: " + websocket.protocol);
+ } else {
+ mode = 'base64';
+ Util.Error("Server select no sub-protocol!: " + websocket.protocol);
+ }
+ eventHandlers.open();
+ Util.Debug("<< WebSock.onopen");
+ };
+ websocket.onclose = function(e) {
+ Util.Debug(">> WebSock.onclose");
+ eventHandlers.close(e);
+ Util.Debug("<< WebSock.onclose");
+ };
+ websocket.onerror = function(e) {
+ Util.Debug(">> WebSock.onerror: " + e);
+ eventHandlers.error(e);
+ Util.Debug("<< WebSock.onerror");
+ };
+}
+
+function close() {
+ if (websocket) {
+ if ((websocket.readyState === WebSocket.OPEN) ||
+ (websocket.readyState === WebSocket.CONNECTING)) {
+ Util.Info("Closing WebSocket connection");
+ websocket.close();
+ }
+ websocket.onmessage = function (e) { return; };
+ }
+}
+
+// Override internal functions for testing
+// Takes a send function, returns reference to recv function
+function testMode(override_send, data_mode) {
+ test_mode = true;
+ mode = data_mode;
+ api.send = override_send;
+ api.close = function () {};
+ return recv_message;
+}
+
+function constructor() {
+ // Configuration settings
+ api.maxBufferedAmount = 200;
+
+ // Direct access to send and receive queues
+ api.get_sQ = get_sQ;
+ api.get_rQ = get_rQ;
+ api.get_rQi = get_rQi;
+ api.set_rQi = set_rQi;
+
+ // Routines to read from the receive queue
+ api.rQlen = rQlen;
+ api.rQpeek8 = rQpeek8;
+ api.rQshift8 = rQshift8;
+ api.rQunshift8 = rQunshift8;
+ api.rQshift16 = rQshift16;
+ api.rQshift32 = rQshift32;
+ api.rQshiftStr = rQshiftStr;
+ api.rQshiftBytes = rQshiftBytes;
+ api.rQslice = rQslice;
+ api.rQwait = rQwait;
+
+ api.flush = flush;
+ api.send = send;
+ api.send_string = send_string;
+
+ api.on = on;
+ api.init = init;
+ api.open = open;
+ api.close = close;
+ api.testMode = testMode;
+
+ return api;
+}
+
+return constructor();
+
+}
diff --git a/ui/js/novnc/webutil.js b/ui/js/novnc/webutil.js
new file mode 100644
index 0000000..c0d4819
--- /dev/null
+++ b/ui/js/novnc/webutil.js
@@ -0,0 +1,216 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2012 Joel Martin
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ */
+
+"use strict";
+/*jslint bitwise: false, white: false */
+/*global Util, window, document */
+
+// Globals defined here
+var WebUtil = {}, $D;
+
+/*
+ * Simple DOM selector by ID
+ */
+if (!window.$D) {
+ window.$D = function (id) {
+ if (document.getElementById) {
+ return document.getElementById(id);
+ } else if (document.all) {
+ return document.all[id];
+ } else if (document.layers) {
+ return document.layers[id];
+ }
+ return undefined;
+ };
+}
+
+
+/*
+ * ------------------------------------------------------
+ * Namespaced in WebUtil
+ * ------------------------------------------------------
+ */
+
+// init log level reading the logging HTTP param
+WebUtil.init_logging = function(level) {
+ if (typeof level !== "undefined") {
+ Util._log_level = level;
+ } else {
+ Util._log_level = (document.location.href.match(
+ /logging=([A-Za-z0-9\._\-]*)/) ||
+ ['', Util._log_level])[1];
+ }
+ Util.init_logging();
+};
+
+
+WebUtil.dirObj = function (obj, depth, parent) {
+ var i, msg = "", val = "";
+ if (! depth) { depth=2; }
+ if (! parent) { parent= ""; }
+
+ // Print the properties of the passed-in object
+ for (i in obj) {
+ if ((depth > 1) && (typeof obj[i] === "object")) {
+ // Recurse attributes that are objects
+ msg += WebUtil.dirObj(obj[i], depth-1, parent + "." + i);
+ } else {
+ //val = new String(obj[i]).replace("\n", " ");
+ if (typeof(obj[i]) === "undefined") {
+ val = "undefined";
+ } else {
+ val = obj[i].toString().replace("\n", " ");
+ }
+ if (val.length > 30) {
+ val = val.substr(0,30) + "...";
+ }
+ msg += parent + "." + i + ": " + val + "\n";
+ }
+ }
+ return msg;
+};
+
+// Read a query string variable
+WebUtil.getQueryVar = function(name, defVal) {
+ var re = new RegExp('[?][^#]*' + name + '=([^&#]*)'),
+ match = document.location.href.match(re);
+ if (typeof defVal === 'undefined') { defVal = null; }
+ if (match) {
+ return decodeURIComponent(match[1]);
+ } else {
+ return defVal;
+ }
+};
+
+
+/*
+ * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
+ */
+
+// No days means only for this browser session
+WebUtil.createCookie = function(name,value,days) {
+ var date, expires;
+ if (days) {
+ date = new Date();
+ date.setTime(date.getTime()+(days*24*60*60*1000));
+ expires = "; expires="+date.toGMTString();
+ }
+ else {
+ expires = "";
+ }
+ document.cookie = name+"="+value+expires+"; path=/";
+};
+
+WebUtil.readCookie = function(name, defaultValue) {
+ var i, c, nameEQ = name + "=", ca = document.cookie.split(';');
+ for(i=0; i < ca.length; i += 1) {
+ c = ca[i];
+ while (c.charAt(0) === ' ') { c = c.substring(1,c.length); }
+ if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); }
+ }
+ return (typeof defaultValue !== 'undefined') ? defaultValue : null;
+};
+
+WebUtil.eraseCookie = function(name) {
+ WebUtil.createCookie(name,"",-1);
+};
+
+/*
+ * Setting handling.
+ */
+
+WebUtil.initSettings = function(callback) {
+ var callbackArgs = Array.prototype.slice.call(arguments, 1);
+ if (window.chrome && window.chrome.storage) {
+ window.chrome.storage.sync.get(function (cfg) {
+ WebUtil.settings = cfg;
+ console.log(WebUtil.settings);
+ if (callback) {
+ callback.apply(this, callbackArgs);
+ }
+ });
+ } else {
+ // No-op
+ if (callback) {
+ callback.apply(this, callbackArgs);
+ }
+ }
+};
+
+// No days means only for this browser session
+WebUtil.writeSetting = function(name, value) {
+ if (window.chrome && window.chrome.storage) {
+ //console.log("writeSetting:", name, value);
+ if (WebUtil.settings[name] !== value) {
+ WebUtil.settings[name] = value;
+ window.chrome.storage.sync.set(WebUtil.settings);
+ }
+ } else {
+ localStorage.setItem(name, value);
+ }
+};
+
+WebUtil.readSetting = function(name, defaultValue) {
+ var value;
+ if (window.chrome && window.chrome.storage) {
+ value = WebUtil.settings[name];
+ } else {
+ value = localStorage.getItem(name);
+ }
+ if (typeof value === "undefined") {
+ value = null;
+ }
+ if (value === null && typeof defaultValue !== undefined) {
+ return defaultValue;
+ } else {
+ return value;
+ }
+};
+
+WebUtil.eraseSetting = function(name) {
+ if (window.chrome && window.chrome.storage) {
+ window.chrome.storage.sync.remove(name);
+ delete WebUtil.settings[name];
+ } else {
+ localStorage.removeItem(name);
+ }
+};
+
+/*
+ * Alternate stylesheet selection
+ */
+WebUtil.getStylesheets = function() { var i, links, sheets = [];
+ links = document.getElementsByTagName("link");
+ for (i = 0; i < links.length; i += 1) {
+ if (links[i].title &&
+ links[i].rel.toUpperCase().indexOf("STYLESHEET") > -1) {
+ sheets.push(links[i]);
+ }
+ }
+ return sheets;
+};
+
+// No sheet means try and use value from cookie, null sheet used to
+// clear all alternates.
+WebUtil.selectStylesheet = function(sheet) {
+ var i, link, sheets = WebUtil.getStylesheets();
+ if (typeof sheet === 'undefined') {
+ sheet = 'default';
+ }
+ for (i=0; i < sheets.length; i += 1) {
+ link = sheets[i];
+ if (link.title === sheet) {
+ Util.Debug("Using stylesheet " + sheet);
+ link.disabled = false;
+ } else {
+ //Util.Debug("Skipping stylesheet " + link.title);
+ link.disabled = true;
+ }
+ }
+ return sheet;
+};
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index c8c422d..1bde45c 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -318,6 +318,7 @@ var kimchi = {
type : 'GET',
dataType : 'json'
}).done(function(data, textStatus, xhr) {
+ http_port = data['http_port'];
proxy_port = data['display_proxy_port'];
kimchi.requestJSON({
url : "/vms/" + encodeURIComponent(vm) + "/connect",
@@ -328,10 +329,9 @@ var kimchi = {
* Due to problems with web sockets and self-signed
* certificates, for now we will always redirect to http
*/
- url = 'https://' + location.hostname + ':' + proxy_port;
- url += "/vnc.html?port=" + proxy_port;
+ url = 'http://' + location.hostname + ':' + http_port;
+ url += "/vnc_auto.html?port=" + proxy_port;
url += "&path=?token=" + encodeURIComponent(vm);
- url += '&encrypt=1'
window.open(url);
});
}).error(function() {
@@ -355,7 +355,6 @@ var kimchi = {
url = 'http://' + location.hostname + ':' + http_port;
url += "/spice.html?port=" + proxy_port + "&listen="
+ data.graphics.listen + "&token=" + encodeURIComponent(vm);
- url += '&encrypt=1'
window.open(url);
});
}).error(function() {
diff --git a/ui/novnc/Makefile.am b/ui/novnc/Makefile.am
deleted file mode 100644
index d0aca93..0000000
--- a/ui/novnc/Makefile.am
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Kimchi
-#
-# Copyright IBM, Corp. 2014
-#
-# Licensed 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.
-
-SUBDIRS = css js
-
-htmldir = $(datadir)/kimchi/ui/novnc
-
-dist_html_DATA = vnc.html $(NULL)
diff --git a/ui/novnc/css/Makefile.am b/ui/novnc/css/Makefile.am
deleted file mode 100644
index 23d178f..0000000
--- a/ui/novnc/css/Makefile.am
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Kimchi
-#
-# Copyright IBM, Corp. 2013
-#
-# Licensed 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.
-
-cssdir = $(datadir)/kimchi/ui/novnc/css
-
-dist_css_DATA = base.css Orbitron700.*
diff --git a/ui/novnc/css/Orbitron700.ttf b/ui/novnc/css/Orbitron700.ttf
deleted file mode 100644
index e28729dc56b0662b5d2506ddfde5a368784f5755..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 38580
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
YaN=?Mu0Qj~<BJ#F#P26F-oE1h0<?nDhX4Qo
diff --git a/ui/novnc/css/Orbitron700.woff b/ui/novnc/css/Orbitron700.woff
deleted file mode 100644
index 61db630cce1c18fd78c71462d82184a32af6089a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 17472
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
aYg+X)x}OQee;ks?lK=p?0sn=t1dRYj;d3$o
diff --git a/ui/novnc/css/base.css b/ui/novnc/css/base.css
deleted file mode 100644
index 89b2b57..0000000
--- a/ui/novnc/css/base.css
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * noVNC base CSS
- * Copyright (C) 2012 Joel Martin
- * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
- * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
- */
-
-body {
- margin:0;
- padding:0;
- font-family: Helvetica;
- /*Background image with light grey curve.*/
- background-color:#494949;
- background-repeat:no-repeat;
- background-position:right bottom;
- height:100%;
-}
-
-html {
- height:100%;
-}
-
-#noVNC_controls ul {
- list-style: none;
- margin: 0px;
- padding: 0px;
-}
-#noVNC_controls li {
- padding-bottom:8px;
-}
-
-#noVNC_host {
- width:150px;
-}
-#noVNC_port {
- width: 80px;
-}
-#noVNC_password {
- width: 150px;
-}
-#noVNC_encrypt {
-}
-#noVNC_connectTimeout {
- width: 30px;
-}
-#noVNC_path {
- width: 100px;
-}
-#noVNC_connect_button {
- width: 110px;
- float:right;
-}
-
-
-#noVNC_view_drag_button {
- display: none;
-}
-#sendCtrlAltDelButton {
- display: none;
-}
-#noVNC_mobile_buttons {
- display: none;
-}
-
-.noVNC-buttons-left {
- float: left;
- padding-left:10px;
- padding-top:4px;
-}
-
-.noVNC-buttons-right {
- float:right;
- right: 0px;
- padding-right:10px;
- padding-top:4px;
-}
-
-#noVNC_status_bar {
- margin-top: 0px;
- padding: 0px;
-}
-
-#noVNC_status_bar div {
- font-size: 12px;
- padding-top: 4px;
- width:100%;
-}
-
-#noVNC_status {
- height:20px;
- text-align: center;
-}
-#noVNC_settings_menu {
- margin: 3px;
- text-align: left;
-}
-#noVNC_settings_menu ul {
- list-style: none;
- margin: 0px;
- padding: 0px;
-}
-
-#noVNC_apply {
- float:right;
-}
-
-.noVNC_status_normal {
- background: #eee;
-}
-.noVNC_status_error {
- background: #f44;
-}
-.noVNC_status_warn {
- background: #ff4;
-}
-
-/* Do not set width/height for VNC_screen or VNC_canvas or incorrect
- * scaling will occur. Canvas resizes to remote VNC settings */
-#noVNC_screen_pad {
- margin: 0px;
- padding: 0px;
- height: 44px;
-}
-#noVNC_screen {
- text-align: center;
- display: table;
- width:100%;
- height:100%;
- background-color:#313131;
- border-bottom-right-radius: 800px 600px;
- /*border-top-left-radius: 800px 600px;*/
-}
-
-#noVNC_container, #noVNC_canvas {
- margin: 0px;
- padding: 0px;
-}
-
-#noVNC_canvas {
- left: 0px;
-}
-
-#VNC_clipboard_clear_button {
- float:right;
-}
-#VNC_clipboard_text {
- font-size: 11px;
-}
-
-#noVNC_clipboard_clear_button {
- float:right;
-}
-
-/*Bubble contents divs*/
-#noVNC_settings {
- display:none;
- margin-top:77px;
- right:20px;
- position:fixed;
-}
-
-#noVNC_controls {
- display:none;
- margin-top:77px;
- right:12px;
- position:fixed;
-}
-#noVNC_controls.top:after {
- right:15px;
-}
-
-#noVNC_description {
- display:none;
- position:fixed;
-
- margin-top:77px;
- right:20px;
- left:20px;
- padding:15px;
- color:#000;
- background:#eee; /* default background for browsers without gradient support */
-
- border:2px solid #E0E0E0;
- -webkit-border-radius:10px;
- -moz-border-radius:10px;
- border-radius:10px;
-}
-
-#noVNC_clipboard {
- display:none;
- margin-top:77px;
- right:30px;
- position:fixed;
-}
-#noVNC_clipboard.top:after {
- right:85px;
-}
-
-#keyboardinput {
- width:1px;
- height:1px;
- background-color:#fff;
- color:#fff;
- border:0;
- position: relative;
- left: -40px;
- z-index: -1;
-}
-
-.noVNC_status_warn {
- background-color:yellow;
-}
-
-/*
- * Advanced Styling
- */
-
-/* Control bar */
-#noVNC-control-bar {
- position:fixed;
- background: #b2bdcd; /* Old browsers */
- background: -moz-linear-gradient(top, #b2bdcd 0%, #899cb3 49%, #7e93af 51%, #6e84a3 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2bdcd), color-stop(49%,#899cb3), color-stop(51%,#7e93af), color-stop(100%,#6e84a3)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* IE10+ */
- background: linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* W3C */
-
- display:block;
- height:44px;
- left:0;
- top:0;
- width:100%;
- z-index:200;
-}
-
-.noVNC_status_button {
- padding: 4px 4px;
- vertical-align: middle;
- border:1px solid #869dbc;
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
- background: #b2bdcd; /* Old browsers */
- background: -moz-linear-gradient(top, #b2bdcd 0%, #899cb3 49%, #7e93af 51%, #6e84a3 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2bdcd), color-stop(49%,#899cb3), color-stop(51%,#7e93af), color-stop(100%,#6e84a3)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* IE10+ */
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b2bdcd', endColorstr='#6e84a3',GradientType=0 ); /* IE6-9 */
- background: linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* W3C */
- /*box-shadow:inset 0.4px 0.4px 0.4px #000000;*/
-}
-
-.noVNC_status_button_selected {
- padding: 4px 4px;
- vertical-align: middle;
- border:1px solid #4366a9;
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- background: #779ced; /* Old browsers */
- background: -moz-linear-gradient(top, #779ced 0%, #3970e0 49%, #2160dd 51%, #2463df 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#779ced), color-stop(49%,#3970e0), color-stop(51%,#2160dd), color-stop(100%,#2463df)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* IE10+ */
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#779ced', endColorstr='#2463df',GradientType=0 ); /* IE6-9 */
- background: linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* W3C */
- /*box-shadow:inset 0.4px 0.4px 0.4px #000000;*/
-}
-
-
-/*Settings Bubble*/
-.triangle-right {
- position:relative;
- padding:15px;
- margin:1em 0 3em;
- color:#fff;
- background:#fff; /* default background for browsers without gradient support */
- /* css3 */
- /*background:-webkit-gradient(linear, 0 0, 0 100%, from(#2e88c4), to(#075698));
- background:-moz-linear-gradient(#2e88c4, #075698);
- background:-o-linear-gradient(#2e88c4, #075698);
- background:linear-gradient(#2e88c4, #075698);*/
- -webkit-border-radius:10px;
- -moz-border-radius:10px;
- border-radius:10px;
- color:#000;
- border:2px solid #E0E0E0;
-}
-
-.triangle-right.top:after {
- border-color: transparent #E0E0E0;
- border-width: 20px 20px 0 0;
- bottom: auto;
- left: auto;
- right: 50px;
- top: -20px;
-}
-
-.triangle-right:after {
- content:"";
- position:absolute;
- bottom:-20px; /* value = - border-top-width - border-bottom-width */
- left:50px; /* controls horizontal position */
- border-width:20px 0 0 20px; /* vary these values to change the angle of the vertex */
- border-style:solid;
- border-color:#E0E0E0 transparent;
- /* reduce the damage in FF3.0 */
- display:block;
- width:0;
-}
-
-.triangle-right.top:after {
- top:-40px; /* value = - border-top-width - border-bottom-width */
- right:50px; /* controls horizontal position */
- bottom:auto;
- left:auto;
- border-width:40px 40px 0 0; /* vary these values to change the angle of the vertex */
- border-color:transparent #E0E0E0;
-}
-
-/*Default noVNC logo.*/
-/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
-@font-face {
- font-family: 'Orbitron';
- font-style: normal;
- font-weight: 700;
- src: local('?'), url('Orbitron700.woff') format('woff'),
- url('Orbitron700.ttf') format('truetype');
-}
-
-#noVNC_logo {
- margin-top: 170px;
- margin-left: 10px;
- color:yellow;
- text-align:left;
- font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
- line-height:90%;
- text-shadow:
- 5px 5px 0 #000,
- -1px -1px 0 #000,
- 1px -1px 0 #000,
- -1px 1px 0 #000,
- 1px 1px 0 #000;
-}
-
-
-#noVNC_logo span{
- color:green;
-}
-
-/* ----------------------------------------
- * Media sizing
- * ----------------------------------------
- */
-
-
-.noVNC_status_button {
- font-size: 12px;
-}
-
-#noVNC_clipboard_text {
- width: 500px;
-}
-
-#noVNC_logo {
- font-size: 180px;
-}
-
-@media screen and (min-width: 481px) and (max-width: 640px) {
- .noVNC_status_button {
- font-size: 10px;
- }
- #noVNC_clipboard_text {
- width: 410px;
- }
- #noVNC_logo {
- font-size: 150px;
- }
-}
-
-@media screen and (min-width: 321px) and (max-width: 480px) {
- .noVNC_status_button {
- font-size: 10px;
- }
- #noVNC_clipboard_text {
- width: 250px;
- }
- #noVNC_logo {
- font-size: 110px;
- }
-}
-
-@media screen and (max-width: 320px) {
- .noVNC_status_button {
- font-size: 9px;
- }
- #noVNC_clipboard_text {
- width: 220px;
- }
- #noVNC_logo {
- font-size: 90px;
- }
-}
diff --git a/ui/novnc/js/Makefile.am b/ui/novnc/js/Makefile.am
deleted file mode 100644
index 0c22fed..0000000
--- a/ui/novnc/js/Makefile.am
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Kimchi
-#
-# Copyright IBM, Corp. 2013
-#
-# Licensed 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.
-
-SUBDIRS = web-socket-js
-
-jsdir = $(datadir)/kimchi/ui/novnc/js
-
-dist_js_DATA = $(wildcard *.js) $(NULL)
diff --git a/ui/novnc/js/base64.js b/ui/novnc/js/base64.js
deleted file mode 100644
index f0891ab..0000000
--- a/ui/novnc/js/base64.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools…
-
-/*jslint white: false, bitwise: false, plusplus: false */
-/*global console */
-
-var Base64 = {
-
-/* Convert data (an array of integers) to a Base64 string. */
-toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
-base64Pad : '=',
-
-encode: function (data) {
- "use strict";
- var result = '';
- var toBase64Table = Base64.toBase64Table;
- var length = data.length
- var lengthpad = (length%3);
- var i = 0, j = 0;
- // Convert every three bytes to 4 ascii characters.
- /* BEGIN LOOP */
- for (i = 0; i < (length - 2); i += 3) {
- result += toBase64Table[data[i] >> 2];
- result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
- result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
- result += toBase64Table[data[i+2] & 0x3f];
- }
- /* END LOOP */
-
- // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
- if (lengthpad === 2) {
- j = length - lengthpad;
- result += toBase64Table[data[j] >> 2];
- result += toBase64Table[((data[j] & 0x03) << 4) + (data[j+1] >> 4)];
- result += toBase64Table[(data[j+1] & 0x0f) << 2];
- result += toBase64Table[64];
- } else if (lengthpad === 1) {
- j = length - lengthpad;
- result += toBase64Table[data[j] >> 2];
- result += toBase64Table[(data[j] & 0x03) << 4];
- result += toBase64Table[64];
- result += toBase64Table[64];
- }
-
- return result;
-},
-
-/* Convert Base64 data to a string */
-toBinaryTable : [
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
- 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
- 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
- -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
- 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
-],
-
-decode: function (data, offset) {
- "use strict";
- offset = typeof(offset) !== 'undefined' ? offset : 0;
- var toBinaryTable = Base64.toBinaryTable;
- var base64Pad = Base64.base64Pad;
- var result, result_length, idx, i, c, padding;
- var leftbits = 0; // number of bits decoded, but yet to be appended
- var leftdata = 0; // bits decoded, but yet to be appended
- var data_length = data.indexOf('=') - offset;
-
- if (data_length < 0) { data_length = data.length - offset; }
-
- /* Every four characters is 3 resulting numbers */
- result_length = (data_length >> 2) * 3 + Math.floor((data_length%4)/1.5);
- result = new Array(result_length);
-
- // Convert one by one.
- /* BEGIN LOOP */
- for (idx = 0, i = offset; i < data.length; i++) {
- c = toBinaryTable[data.charCodeAt(i) & 0x7f];
- padding = (data.charAt(i) === base64Pad);
- // Skip illegal characters and whitespace
- if (c === -1) {
- console.error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
- continue;
- }
-
- // Collect data into leftdata, update bitcount
- leftdata = (leftdata << 6) | c;
- leftbits += 6;
-
- // If we have 8 or more bits, append 8 bits to the result
- if (leftbits >= 8) {
- leftbits -= 8;
- // Append if not padding.
- if (!padding) {
- result[idx++] = (leftdata >> leftbits) & 0xff;
- }
- leftdata &= (1 << leftbits) - 1;
- }
- }
- /* END LOOP */
-
- // If there are any bits left, the base64 string was corrupted
- if (leftbits) {
- throw {name: 'Base64-Error',
- message: 'Corrupted base64 string'};
- }
-
- return result;
-}
-
-}; /* End of Base64 namespace */
diff --git a/ui/novnc/js/des.js b/ui/novnc/js/des.js
deleted file mode 100644
index 2d207c4..0000000
--- a/ui/novnc/js/des.js
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Ported from Flashlight VNC ActionScript implementation:
- * http://www.wizhelp.com/flashlight-vnc/
- *
- * Full attribution follows:
- *
- * -------------------------------------------------------------------------
- *
- * This DES class has been extracted from package Acme.Crypto for use in VNC.
- * The unnecessary odd parity code has been removed.
- *
- * These changes are:
- * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
-
- * DesCipher - the DES encryption method
- *
- * The meat of this code is by Dave Zimmerman <dzimm(a)widget.com>, and is:
- *
- * Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
- * without fee is hereby granted, provided that this copyright notice is kept
- * intact.
- *
- * WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
- * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
- * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
- *
- * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
- * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
- * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
- * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
- * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
- * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
- * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
- * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
- * HIGH RISK ACTIVITIES.
- *
- *
- * The rest is:
- *
- * Copyright (C) 1996 by Jef Poskanzer <jef(a)acme.com>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Visit the ACME Labs Java page for up-to-date versions of this and other
- * fine Java utilities: http://www.acme.com/java/
- */
-
-"use strict";
-/*jslint white: false, bitwise: false, plusplus: false */
-
-function DES(passwd) {
-
-// Tables, permutations, S-boxes, etc.
-var PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
- 25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
- 50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
- totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28],
- z = 0x0, a,b,c,d,e,f, SP1,SP2,SP3,SP4,SP5,SP6,SP7,SP8,
- keys = [];
-
-a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
-SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
- z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
- a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
- c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
-a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
-SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
- a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
- z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
- z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
-a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
-SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
- b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
- c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
- b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
-a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
-SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
- z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
- b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
- c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
-a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
-SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
- a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
- z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
- c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
-a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
-SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
- z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
- b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
- a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
-a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
-SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
- b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
- b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
- z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
-a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
-SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
- c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
- a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
- z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
-
-// Set the key.
-function setKeys(keyBlock) {
- var i, j, l, m, n, o, pc1m = [], pcr = [], kn = [],
- raw0, raw1, rawi, KnLi;
-
- for (j = 0, l = 56; j < 56; ++j, l-=8) {
- l += l<-5 ? 65 : l<-3 ? 31 : l<-1 ? 63 : l===27 ? 35 : 0; // PC1
- m = l & 0x7;
- pc1m[j] = ((keyBlock[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
- }
-
- for (i = 0; i < 16; ++i) {
- m = i << 1;
- n = m + 1;
- kn[m] = kn[n] = 0;
- for (o=28; o<59; o+=28) {
- for (j = o-28; j < o; ++j) {
- l = j + totrot[i];
- if (l < o) {
- pcr[j] = pc1m[l];
- } else {
- pcr[j] = pc1m[l - 28];
- }
- }
- }
- for (j = 0; j < 24; ++j) {
- if (pcr[PC2[j]] !== 0) {
- kn[m] |= 1<<(23-j);
- }
- if (pcr[PC2[j + 24]] !== 0) {
- kn[n] |= 1<<(23-j);
- }
- }
- }
-
- // cookey
- for (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
- raw0 = kn[rawi++];
- raw1 = kn[rawi++];
- keys[KnLi] = (raw0 & 0x00fc0000) << 6;
- keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
- keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
- keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
- ++KnLi;
- keys[KnLi] = (raw0 & 0x0003f000) << 12;
- keys[KnLi] |= (raw0 & 0x0000003f) << 16;
- keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
- keys[KnLi] |= (raw1 & 0x0000003f);
- ++KnLi;
- }
-}
-
-// Encrypt 8 bytes of text
-function enc8(text) {
- var i = 0, b = text.slice(), fval, keysi = 0,
- l, r, x; // left, right, accumulator
-
- // Squash 8 bytes to 2 ints
- l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
- r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
-
- x = ((l >>> 4) ^ r) & 0x0f0f0f0f;
- r ^= x;
- l ^= (x << 4);
- x = ((l >>> 16) ^ r) & 0x0000ffff;
- r ^= x;
- l ^= (x << 16);
- x = ((r >>> 2) ^ l) & 0x33333333;
- l ^= x;
- r ^= (x << 2);
- x = ((r >>> 8) ^ l) & 0x00ff00ff;
- l ^= x;
- r ^= (x << 8);
- r = (r << 1) | ((r >>> 31) & 1);
- x = (l ^ r) & 0xaaaaaaaa;
- l ^= x;
- r ^= x;
- l = (l << 1) | ((l >>> 31) & 1);
-
- for (i = 0; i < 8; ++i) {
- x = (r << 28) | (r >>> 4);
- x ^= keys[keysi++];
- fval = SP7[x & 0x3f];
- fval |= SP5[(x >>> 8) & 0x3f];
- fval |= SP3[(x >>> 16) & 0x3f];
- fval |= SP1[(x >>> 24) & 0x3f];
- x = r ^ keys[keysi++];
- fval |= SP8[x & 0x3f];
- fval |= SP6[(x >>> 8) & 0x3f];
- fval |= SP4[(x >>> 16) & 0x3f];
- fval |= SP2[(x >>> 24) & 0x3f];
- l ^= fval;
- x = (l << 28) | (l >>> 4);
- x ^= keys[keysi++];
- fval = SP7[x & 0x3f];
- fval |= SP5[(x >>> 8) & 0x3f];
- fval |= SP3[(x >>> 16) & 0x3f];
- fval |= SP1[(x >>> 24) & 0x3f];
- x = l ^ keys[keysi++];
- fval |= SP8[x & 0x0000003f];
- fval |= SP6[(x >>> 8) & 0x3f];
- fval |= SP4[(x >>> 16) & 0x3f];
- fval |= SP2[(x >>> 24) & 0x3f];
- r ^= fval;
- }
-
- r = (r << 31) | (r >>> 1);
- x = (l ^ r) & 0xaaaaaaaa;
- l ^= x;
- r ^= x;
- l = (l << 31) | (l >>> 1);
- x = ((l >>> 8) ^ r) & 0x00ff00ff;
- r ^= x;
- l ^= (x << 8);
- x = ((l >>> 2) ^ r) & 0x33333333;
- r ^= x;
- l ^= (x << 2);
- x = ((r >>> 16) ^ l) & 0x0000ffff;
- l ^= x;
- r ^= (x << 16);
- x = ((r >>> 4) ^ l) & 0x0f0f0f0f;
- l ^= x;
- r ^= (x << 4);
-
- // Spread ints to bytes
- x = [r, l];
- for (i = 0; i < 8; i++) {
- b[i] = (x[i>>>2] >>> (8*(3 - (i%4)))) % 256;
- if (b[i] < 0) { b[i] += 256; } // unsigned
- }
- return b;
-}
-
-// Encrypt 16 bytes of text using passwd as key
-function encrypt(t) {
- return enc8(t.slice(0,8)).concat(enc8(t.slice(8,16)));
-}
-
-setKeys(passwd); // Setup keys
-return {'encrypt': encrypt}; // Public interface
-
-} // function DES
diff --git a/ui/novnc/js/display.js b/ui/novnc/js/display.js
deleted file mode 100644
index afddf88..0000000
--- a/ui/novnc/js/display.js
+++ /dev/null
@@ -1,770 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-/*jslint browser: true, white: false, bitwise: false */
-/*global Util, Base64, changeCursor */
-
-function Display(defaults) {
-"use strict";
-
-var that = {}, // Public API methods
- conf = {}, // Configuration attributes
-
- // Private Display namespace variables
- c_ctx = null,
- c_forceCanvas = false,
-
- // Queued drawing actions for in-order rendering
- renderQ = [],
-
- // Predefine function variables (jslint)
- imageDataGet, rgbImageData, bgrxImageData, cmapImageData,
- setFillColor, rescale, scan_renderQ,
-
- // The full frame buffer (logical canvas) size
- fb_width = 0,
- fb_height = 0,
- // The visible "physical canvas" viewport
- viewport = {'x': 0, 'y': 0, 'w' : 0, 'h' : 0 },
- cleanRect = {'x1': 0, 'y1': 0, 'x2': -1, 'y2': -1},
-
- c_prevStyle = "",
- tile = null,
- tile16x16 = null,
- tile_x = 0,
- tile_y = 0;
-
-
-// Configuration attributes
-Util.conf_defaults(conf, that, defaults, [
- ['target', 'wo', 'dom', null, 'Canvas element for rendering'],
- ['context', 'ro', 'raw', null, 'Canvas 2D context for rendering (read-only)'],
- ['logo', 'rw', 'raw', null, 'Logo to display when cleared: {"width": width, "height": height, "data": data}'],
- ['true_color', 'rw', 'bool', true, 'Use true-color pixel data'],
- ['colourMap', 'rw', 'arr', [], 'Colour map array (when not true-color)'],
- ['scale', 'rw', 'float', 1.0, 'Display area scale factor 0.0 - 1.0'],
- ['viewport', 'rw', 'bool', false, 'Use a viewport set with viewportChange()'],
- ['width', 'rw', 'int', null, 'Display area width'],
- ['height', 'rw', 'int', null, 'Display area height'],
-
- ['render_mode', 'ro', 'str', '', 'Canvas rendering mode (read-only)'],
-
- ['prefer_js', 'rw', 'str', null, 'Prefer Javascript over canvas methods'],
- ['cursor_uri', 'rw', 'raw', null, 'Can we render cursor using data URI']
- ]);
-
-// Override some specific getters/setters
-that.get_context = function () { return c_ctx; };
-
-that.set_scale = function(scale) { rescale(scale); };
-
-that.set_width = function (val) { that.resize(val, fb_height); };
-that.get_width = function() { return fb_width; };
-
-that.set_height = function (val) { that.resize(fb_width, val); };
-that.get_height = function() { return fb_height; };
-
-
-
-//
-// Private functions
-//
-
-// Create the public API interface
-function constructor() {
- Util.Debug(">> Display.constructor");
-
- var c, func, i, curDat, curSave,
- has_imageData = false, UE = Util.Engine;
-
- if (! conf.target) { throw("target must be set"); }
-
- if (typeof conf.target === 'string') {
- throw("target must be a DOM element");
- }
-
- c = conf.target;
-
- if (! c.getContext) { throw("no getContext method"); }
-
- if (! c_ctx) { c_ctx = c.getContext('2d'); }
-
- Util.Debug("User Agent: " + navigator.userAgent);
- if (UE.gecko) { Util.Debug("Browser: gecko " + UE.gecko); }
- if (UE.webkit) { Util.Debug("Browser: webkit " + UE.webkit); }
- if (UE.trident) { Util.Debug("Browser: trident " + UE.trident); }
- if (UE.presto) { Util.Debug("Browser: presto " + UE.presto); }
-
- that.clear();
-
- // Check canvas features
- if ('createImageData' in c_ctx) {
- conf.render_mode = "canvas rendering";
- } else {
- throw("Canvas does not support createImageData");
- }
- if (conf.prefer_js === null) {
- Util.Info("Prefering javascript operations");
- conf.prefer_js = true;
- }
-
- // Initialize cached tile imageData
- tile16x16 = c_ctx.createImageData(16, 16);
-
- /*
- * Determine browser support for setting the cursor via data URI
- * scheme
- */
- curDat = [];
- for (i=0; i < 8 * 8 * 4; i += 1) {
- curDat.push(255);
- }
- try {
- curSave = c.style.cursor;
- changeCursor(conf.target, curDat, curDat, 2, 2, 8, 8);
- if (c.style.cursor) {
- if (conf.cursor_uri === null) {
- conf.cursor_uri = true;
- }
- Util.Info("Data URI scheme cursor supported");
- } else {
- if (conf.cursor_uri === null) {
- conf.cursor_uri = false;
- }
- Util.Warn("Data URI scheme cursor not supported");
- }
- c.style.cursor = curSave;
- } catch (exc2) {
- Util.Error("Data URI scheme cursor test exception: " + exc2);
- conf.cursor_uri = false;
- }
-
- Util.Debug("<< Display.constructor");
- return that ;
-}
-
-rescale = function(factor) {
- var c, tp, x, y,
- properties = ['transform', 'WebkitTransform', 'MozTransform', null];
- c = conf.target;
- tp = properties.shift();
- while (tp) {
- if (typeof c.style[tp] !== 'undefined') {
- break;
- }
- tp = properties.shift();
- }
-
- if (tp === null) {
- Util.Debug("No scaling support");
- return;
- }
-
-
- if (typeof(factor) === "undefined") {
- factor = conf.scale;
- } else if (factor > 1.0) {
- factor = 1.0;
- } else if (factor < 0.1) {
- factor = 0.1;
- }
-
- if (conf.scale === factor) {
- //Util.Debug("Display already scaled to '" + factor + "'");
- return;
- }
-
- conf.scale = factor;
- x = c.width - c.width * factor;
- y = c.height - c.height * factor;
- c.style[tp] = "scale(" + conf.scale + ") translate(-" + x + "px, -" + y + "px)";
-};
-
-setFillColor = function(color) {
- var bgr, newStyle;
- if (conf.true_color) {
- bgr = color;
- } else {
- bgr = conf.colourMap[color[0]];
- }
- newStyle = "rgb(" + bgr[2] + "," + bgr[1] + "," + bgr[0] + ")";
- if (newStyle !== c_prevStyle) {
- c_ctx.fillStyle = newStyle;
- c_prevStyle = newStyle;
- }
-};
-
-
-//
-// Public API interface functions
-//
-
-// Shift and/or resize the visible viewport
-that.viewportChange = function(deltaX, deltaY, width, height) {
- var c = conf.target, v = viewport, cr = cleanRect,
- saveImg = null, saveStyle, x1, y1, vx2, vy2, w, h;
-
- if (!conf.viewport) {
- Util.Debug("Setting viewport to full display region");
- deltaX = -v.w; // Clamped later if out of bounds
- deltaY = -v.h; // Clamped later if out of bounds
- width = fb_width;
- height = fb_height;
- }
-
- if (typeof(deltaX) === "undefined") { deltaX = 0; }
- if (typeof(deltaY) === "undefined") { deltaY = 0; }
- if (typeof(width) === "undefined") { width = v.w; }
- if (typeof(height) === "undefined") { height = v.h; }
-
- // Size change
-
- if (width > fb_width) { width = fb_width; }
- if (height > fb_height) { height = fb_height; }
-
- if ((v.w !== width) || (v.h !== height)) {
- // Change width
- if ((width < v.w) && (cr.x2 > v.x + width -1)) {
- cr.x2 = v.x + width - 1;
- }
- v.w = width;
-
- // Change height
- if ((height < v.h) && (cr.y2 > v.y + height -1)) {
- cr.y2 = v.y + height - 1;
- }
- v.h = height;
-
-
- if (v.w > 0 && v.h > 0 && c.width > 0 && c.height > 0) {
- saveImg = c_ctx.getImageData(0, 0,
- (c.width < v.w) ? c.width : v.w,
- (c.height < v.h) ? c.height : v.h);
- }
-
- c.width = v.w;
- c.height = v.h;
-
- if (saveImg) {
- c_ctx.putImageData(saveImg, 0, 0);
- }
- }
-
- vx2 = v.x + v.w - 1;
- vy2 = v.y + v.h - 1;
-
-
- // Position change
-
- if ((deltaX < 0) && ((v.x + deltaX) < 0)) {
- deltaX = - v.x;
- }
- if ((vx2 + deltaX) >= fb_width) {
- deltaX -= ((vx2 + deltaX) - fb_width + 1);
- }
-
- if ((v.y + deltaY) < 0) {
- deltaY = - v.y;
- }
- if ((vy2 + deltaY) >= fb_height) {
- deltaY -= ((vy2 + deltaY) - fb_height + 1);
- }
-
- if ((deltaX === 0) && (deltaY === 0)) {
- //Util.Debug("skipping viewport change");
- return;
- }
- Util.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY);
-
- v.x += deltaX;
- vx2 += deltaX;
- v.y += deltaY;
- vy2 += deltaY;
-
- // Update the clean rectangle
- if (v.x > cr.x1) {
- cr.x1 = v.x;
- }
- if (vx2 < cr.x2) {
- cr.x2 = vx2;
- }
- if (v.y > cr.y1) {
- cr.y1 = v.y;
- }
- if (vy2 < cr.y2) {
- cr.y2 = vy2;
- }
-
- if (deltaX < 0) {
- // Shift viewport left, redraw left section
- x1 = 0;
- w = - deltaX;
- } else {
- // Shift viewport right, redraw right section
- x1 = v.w - deltaX;
- w = deltaX;
- }
- if (deltaY < 0) {
- // Shift viewport up, redraw top section
- y1 = 0;
- h = - deltaY;
- } else {
- // Shift viewport down, redraw bottom section
- y1 = v.h - deltaY;
- h = deltaY;
- }
-
- // Copy the valid part of the viewport to the shifted location
- saveStyle = c_ctx.fillStyle;
- c_ctx.fillStyle = "rgb(255,255,255)";
- if (deltaX !== 0) {
- //that.copyImage(0, 0, -deltaX, 0, v.w, v.h);
- //that.fillRect(x1, 0, w, v.h, [255,255,255]);
- c_ctx.drawImage(c, 0, 0, v.w, v.h, -deltaX, 0, v.w, v.h);
- c_ctx.fillRect(x1, 0, w, v.h);
- }
- if (deltaY !== 0) {
- //that.copyImage(0, 0, 0, -deltaY, v.w, v.h);
- //that.fillRect(0, y1, v.w, h, [255,255,255]);
- c_ctx.drawImage(c, 0, 0, v.w, v.h, 0, -deltaY, v.w, v.h);
- c_ctx.fillRect(0, y1, v.w, h);
- }
- c_ctx.fillStyle = saveStyle;
-};
-
-
-// Return a map of clean and dirty areas of the viewport and reset the
-// tracking of clean and dirty areas.
-//
-// Returns: {'cleanBox': {'x': x, 'y': y, 'w': w, 'h': h},
-// 'dirtyBoxes': [{'x': x, 'y': y, 'w': w, 'h': h}, ...]}
-that.getCleanDirtyReset = function() {
- var v = viewport, c = cleanRect, cleanBox, dirtyBoxes = [],
- vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1;
-
-
- // Copy the cleanRect
- cleanBox = {'x': c.x1, 'y': c.y1,
- 'w': c.x2 - c.x1 + 1, 'h': c.y2 - c.y1 + 1};
-
- if ((c.x1 >= c.x2) || (c.y1 >= c.y2)) {
- // Whole viewport is dirty
- dirtyBoxes.push({'x': v.x, 'y': v.y, 'w': v.w, 'h': v.h});
- } else {
- // Redraw dirty regions
- if (v.x < c.x1) {
- // left side dirty region
- dirtyBoxes.push({'x': v.x, 'y': v.y,
- 'w': c.x1 - v.x + 1, 'h': v.h});
- }
- if (vx2 > c.x2) {
- // right side dirty region
- dirtyBoxes.push({'x': c.x2 + 1, 'y': v.y,
- 'w': vx2 - c.x2, 'h': v.h});
- }
- if (v.y < c.y1) {
- // top/middle dirty region
- dirtyBoxes.push({'x': c.x1, 'y': v.y,
- 'w': c.x2 - c.x1 + 1, 'h': c.y1 - v.y});
- }
- if (vy2 > c.y2) {
- // bottom/middle dirty region
- dirtyBoxes.push({'x': c.x1, 'y': c.y2 + 1,
- 'w': c.x2 - c.x1 + 1, 'h': vy2 - c.y2});
- }
- }
-
- // Reset the cleanRect to the whole viewport
- cleanRect = {'x1': v.x, 'y1': v.y,
- 'x2': v.x + v.w - 1, 'y2': v.y + v.h - 1};
-
- return {'cleanBox': cleanBox, 'dirtyBoxes': dirtyBoxes};
-};
-
-// Translate viewport coordinates to absolute coordinates
-that.absX = function(x) {
- return x + viewport.x;
-};
-that.absY = function(y) {
- return y + viewport.y;
-};
-
-
-that.resize = function(width, height) {
- c_prevStyle = "";
-
- fb_width = width;
- fb_height = height;
-
- rescale(conf.scale);
- that.viewportChange();
-};
-
-that.clear = function() {
-
- if (conf.logo) {
- that.resize(conf.logo.width, conf.logo.height);
- that.blitStringImage(conf.logo.data, 0, 0);
- } else {
- that.resize(640, 20);
- c_ctx.clearRect(0, 0, viewport.w, viewport.h);
- }
-
- renderQ = [];
-
- // No benefit over default ("source-over") in Chrome and firefox
- //c_ctx.globalCompositeOperation = "copy";
-};
-
-that.fillRect = function(x, y, width, height, color) {
- setFillColor(color);
- c_ctx.fillRect(x - viewport.x, y - viewport.y, width, height);
-};
-
-that.copyImage = function(old_x, old_y, new_x, new_y, w, h) {
- var x1 = old_x - viewport.x, y1 = old_y - viewport.y,
- x2 = new_x - viewport.x, y2 = new_y - viewport.y;
- c_ctx.drawImage(conf.target, x1, y1, w, h, x2, y2, w, h);
-};
-
-
-// Start updating a tile
-that.startTile = function(x, y, width, height, color) {
- var data, bgr, red, green, blue, i;
- tile_x = x;
- tile_y = y;
- if ((width === 16) && (height === 16)) {
- tile = tile16x16;
- } else {
- tile = c_ctx.createImageData(width, height);
- }
- data = tile.data;
- if (conf.prefer_js) {
- if (conf.true_color) {
- bgr = color;
- } else {
- bgr = conf.colourMap[color[0]];
- }
- red = bgr[2];
- green = bgr[1];
- blue = bgr[0];
- for (i = 0; i < (width * height * 4); i+=4) {
- data[i ] = red;
- data[i + 1] = green;
- data[i + 2] = blue;
- data[i + 3] = 255;
- }
- } else {
- that.fillRect(x, y, width, height, color);
- }
-};
-
-// Update sub-rectangle of the current tile
-that.subTile = function(x, y, w, h, color) {
- var data, p, bgr, red, green, blue, width, j, i, xend, yend;
- if (conf.prefer_js) {
- data = tile.data;
- width = tile.width;
- if (conf.true_color) {
- bgr = color;
- } else {
- bgr = conf.colourMap[color[0]];
- }
- red = bgr[2];
- green = bgr[1];
- blue = bgr[0];
- xend = x + w;
- yend = y + h;
- for (j = y; j < yend; j += 1) {
- for (i = x; i < xend; i += 1) {
- p = (i + (j * width) ) * 4;
- data[p ] = red;
- data[p + 1] = green;
- data[p + 2] = blue;
- data[p + 3] = 255;
- }
- }
- } else {
- that.fillRect(tile_x + x, tile_y + y, w, h, color);
- }
-};
-
-// Draw the current tile to the screen
-that.finishTile = function() {
- if (conf.prefer_js) {
- c_ctx.putImageData(tile, tile_x - viewport.x, tile_y - viewport.y);
- }
- // else: No-op, if not prefer_js then already done by setSubTile
-};
-
-rgbImageData = function(x, y, vx, vy, width, height, arr, offset) {
- var img, i, j, data;
- /*
- if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
- (x - v.x + width < 0) || (y - v.y + height < 0)) {
- // Skipping because outside of viewport
- return;
- }
- */
- img = c_ctx.createImageData(width, height);
- data = img.data;
- for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+3) {
- data[i ] = arr[j ];
- data[i + 1] = arr[j + 1];
- data[i + 2] = arr[j + 2];
- data[i + 3] = 255; // Set Alpha
- }
- c_ctx.putImageData(img, x - vx, y - vy);
-};
-
-bgrxImageData = function(x, y, vx, vy, width, height, arr, offset) {
- var img, i, j, data;
- /*
- if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
- (x - v.x + width < 0) || (y - v.y + height < 0)) {
- // Skipping because outside of viewport
- return;
- }
- */
- img = c_ctx.createImageData(width, height);
- data = img.data;
- for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
- data[i ] = arr[j + 2];
- data[i + 1] = arr[j + 1];
- data[i + 2] = arr[j ];
- data[i + 3] = 255; // Set Alpha
- }
- c_ctx.putImageData(img, x - vx, y - vy);
-};
-
-cmapImageData = function(x, y, vx, vy, width, height, arr, offset) {
- var img, i, j, data, bgr, cmap;
- img = c_ctx.createImageData(width, height);
- data = img.data;
- cmap = conf.colourMap;
- for (i=0, j=offset; i < (width * height * 4); i+=4, j+=1) {
- bgr = cmap[arr[j]];
- data[i ] = bgr[2];
- data[i + 1] = bgr[1];
- data[i + 2] = bgr[0];
- data[i + 3] = 255; // Set Alpha
- }
- c_ctx.putImageData(img, x - vx, y - vy);
-};
-
-that.blitImage = function(x, y, width, height, arr, offset) {
- if (conf.true_color) {
- bgrxImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
- } else {
- cmapImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
- }
-};
-
-that.blitRgbImage = function(x, y, width, height, arr, offset) {
- if (conf.true_color) {
- rgbImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
- } else {
- // prolly wrong...
- cmapImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
- }
-};
-
-that.blitStringImage = function(str, x, y) {
- var img = new Image();
- img.onload = function () {
- c_ctx.drawImage(img, x - viewport.x, y - viewport.y);
- };
- img.src = str;
-};
-
-// Wrap ctx.drawImage but relative to viewport
-that.drawImage = function(img, x, y) {
- c_ctx.drawImage(img, x - viewport.x, y - viewport.y);
-};
-
-that.renderQ_push = function(action) {
- renderQ.push(action);
- if (renderQ.length === 1) {
- // If this can be rendered immediately it will be, otherwise
- // the scanner will start polling the queue (every
- // requestAnimationFrame interval)
- scan_renderQ();
- }
-};
-
-scan_renderQ = function() {
- var a, ready = true;
- while (ready && renderQ.length > 0) {
- a = renderQ[0];
- switch (a.type) {
- case 'copy':
- that.copyImage(a.old_x, a.old_y, a.x, a.y, a.width, a.height);
- break;
- case 'fill':
- that.fillRect(a.x, a.y, a.width, a.height, a.color);
- break;
- case 'blit':
- that.blitImage(a.x, a.y, a.width, a.height, a.data, 0);
- break;
- case 'blitRgb':
- that.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0);
- break;
- case 'img':
- if (a.img.complete) {
- that.drawImage(a.img, a.x, a.y);
- } else {
- // We need to wait for this image to 'load'
- // to keep things in-order
- ready = false;
- }
- break;
- }
- if (ready) {
- a = renderQ.shift();
- }
- }
- if (renderQ.length > 0) {
- requestAnimFrame(scan_renderQ);
- }
-};
-
-
-that.changeCursor = function(pixels, mask, hotx, hoty, w, h) {
- if (conf.cursor_uri === false) {
- Util.Warn("changeCursor called but no cursor data URI support");
- return;
- }
-
- if (conf.true_color) {
- changeCursor(conf.target, pixels, mask, hotx, hoty, w, h);
- } else {
- changeCursor(conf.target, pixels, mask, hotx, hoty, w, h, conf.colourMap);
- }
-};
-
-that.defaultCursor = function() {
- conf.target.style.cursor = "default";
-};
-
-return constructor(); // Return the public API interface
-
-} // End of Display()
-
-
-/* Set CSS cursor property using data URI encoded cursor file */
-function changeCursor(target, pixels, mask, hotx, hoty, w0, h0, cmap) {
- "use strict";
- var cur = [], rgb, IHDRsz, RGBsz, ANDsz, XORsz, url, idx, alpha, x, y;
- //Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w0: " + w0 + ", h0: " + h0);
-
- var w = w0;
- var h = h0;
- if (h < w)
- h = w; // increase h to make it square
- else
- w = h; // increace w to make it square
-
- // Push multi-byte little-endian values
- cur.push16le = function (num) {
- this.push((num ) & 0xFF,
- (num >> 8) & 0xFF );
- };
- cur.push32le = function (num) {
- this.push((num ) & 0xFF,
- (num >> 8) & 0xFF,
- (num >> 16) & 0xFF,
- (num >> 24) & 0xFF );
- };
-
- IHDRsz = 40;
- RGBsz = w * h * 4;
- XORsz = Math.ceil( (w * h) / 8.0 );
- ANDsz = Math.ceil( (w * h) / 8.0 );
-
- // Main header
- cur.push16le(0); // 0: Reserved
- cur.push16le(2); // 2: .CUR type
- cur.push16le(1); // 4: Number of images, 1 for non-animated ico
-
- // Cursor #1 header (ICONDIRENTRY)
- cur.push(w); // 6: width
- cur.push(h); // 7: height
- cur.push(0); // 8: colors, 0 -> true-color
- cur.push(0); // 9: reserved
- cur.push16le(hotx); // 10: hotspot x coordinate
- cur.push16le(hoty); // 12: hotspot y coordinate
- cur.push32le(IHDRsz + RGBsz + XORsz + ANDsz);
- // 14: cursor data byte size
- cur.push32le(22); // 18: offset of cursor data in the file
-
-
- // Cursor #1 InfoHeader (ICONIMAGE/BITMAPINFO)
- cur.push32le(IHDRsz); // 22: Infoheader size
- cur.push32le(w); // 26: Cursor width
- cur.push32le(h*2); // 30: XOR+AND height
- cur.push16le(1); // 34: number of planes
- cur.push16le(32); // 36: bits per pixel
- cur.push32le(0); // 38: Type of compression
-
- cur.push32le(XORsz + ANDsz); // 43: Size of Image
- // Gimp leaves this as 0
-
- cur.push32le(0); // 46: reserved
- cur.push32le(0); // 50: reserved
- cur.push32le(0); // 54: reserved
- cur.push32le(0); // 58: reserved
-
- // 62: color data (RGBQUAD icColors[])
- for (y = h-1; y >= 0; y -= 1) {
- for (x = 0; x < w; x += 1) {
- if (x >= w0 || y >= h0) {
- cur.push(0); // blue
- cur.push(0); // green
- cur.push(0); // red
- cur.push(0); // alpha
- } else {
- idx = y * Math.ceil(w0 / 8) + Math.floor(x/8);
- alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
- if (cmap) {
- idx = (w0 * y) + x;
- rgb = cmap[pixels[idx]];
- cur.push(rgb[2]); // blue
- cur.push(rgb[1]); // green
- cur.push(rgb[0]); // red
- cur.push(alpha); // alpha
- } else {
- idx = ((w0 * y) + x) * 4;
- cur.push(pixels[idx + 2]); // blue
- cur.push(pixels[idx + 1]); // green
- cur.push(pixels[idx ]); // red
- cur.push(alpha); // alpha
- }
- }
- }
- }
-
- // XOR/bitmask data (BYTE icXOR[])
- // (ignored, just needs to be right size)
- for (y = 0; y < h; y += 1) {
- for (x = 0; x < Math.ceil(w / 8); x += 1) {
- cur.push(0x00);
- }
- }
-
- // AND/bitmask data (BYTE icAND[])
- // (ignored, just needs to be right size)
- for (y = 0; y < h; y += 1) {
- for (x = 0; x < Math.ceil(w / 8); x += 1) {
- cur.push(0x00);
- }
- }
-
- url = "data:image/x-icon;base64," + Base64.encode(cur);
- target.style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default";
- //Util.Debug("<< changeCursor, cur.length: " + cur.length);
-}
diff --git a/ui/novnc/js/input.js b/ui/novnc/js/input.js
deleted file mode 100644
index 03c5e77..0000000
--- a/ui/novnc/js/input.js
+++ /dev/null
@@ -1,1946 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 or any later version (see LICENSE.txt)
- */
-
-/*jslint browser: true, white: false, bitwise: false */
-/*global window, Util */
-
-
-//
-// Keyboard event handler
-//
-
-function Keyboard(defaults) {
-"use strict";
-
-var that = {}, // Public API methods
- conf = {}, // Configuration attributes
-
- keyDownList = []; // List of depressed keys
- // (even if they are happy)
-
-// Configuration attributes
-Util.conf_defaults(conf, that, defaults, [
- ['target', 'wo', 'dom', document, 'DOM element that captures keyboard input'],
- ['focused', 'rw', 'bool', true, 'Capture and send key events'],
-
- ['onKeyPress', 'rw', 'func', null, 'Handler for key press/release']
- ]);
-
-
-//
-// Private functions
-//
-
-// From the event keyCode return the keysym value for keys that need
-// to be suppressed otherwise they may trigger unintended browser
-// actions
-function getKeysymSpecial(evt) {
- var keysym = null;
-
- switch ( evt.keyCode ) {
- // These generate a keyDown and keyPress in Firefox and Opera
- case 8 : keysym = 0xFF08; break; // BACKSPACE
- case 13 : keysym = 0xFF0D; break; // ENTER
-
- // This generates a keyDown and keyPress in Opera
- case 9 : keysym = 0xFF09; break; // TAB
- default : break;
- }
-
- if (evt.type === 'keydown') {
- switch ( evt.keyCode ) {
- case 27 : keysym = 0xFF1B; break; // ESCAPE
- case 46 : keysym = 0xFFFF; break; // DELETE
-
- case 36 : keysym = 0xFF50; break; // HOME
- case 35 : keysym = 0xFF57; break; // END
- case 33 : keysym = 0xFF55; break; // PAGE_UP
- case 34 : keysym = 0xFF56; break; // PAGE_DOWN
- case 45 : keysym = 0xFF63; break; // INSERT
- // '-' during keyPress
- case 37 : keysym = 0xFF51; break; // LEFT
- case 38 : keysym = 0xFF52; break; // UP
- case 39 : keysym = 0xFF53; break; // RIGHT
- case 40 : keysym = 0xFF54; break; // DOWN
- case 16 : keysym = 0xFFE1; break; // SHIFT
- case 17 : keysym = 0xFFE3; break; // CONTROL
- //case 18 : keysym = 0xFFE7; break; // Left Meta (Mac Option)
- case 18 : keysym = 0xFFE9; break; // Left ALT (Mac Command)
-
- case 112 : keysym = 0xFFBE; break; // F1
- case 113 : keysym = 0xFFBF; break; // F2
- case 114 : keysym = 0xFFC0; break; // F3
- case 115 : keysym = 0xFFC1; break; // F4
- case 116 : keysym = 0xFFC2; break; // F5
- case 117 : keysym = 0xFFC3; break; // F6
- case 118 : keysym = 0xFFC4; break; // F7
- case 119 : keysym = 0xFFC5; break; // F8
- case 120 : keysym = 0xFFC6; break; // F9
- case 121 : keysym = 0xFFC7; break; // F10
- case 122 : keysym = 0xFFC8; break; // F11
- case 123 : keysym = 0xFFC9; break; // F12
-
- case 225 : keysym = 0xFE03; break; // AltGr
- case 91 : keysym = 0xFFEC; break; // Super_R (Win Key)
- case 93 : keysym = 0xFF67; break; // Menu (Win Menu)
-
- default : break;
- }
- }
-
- if ((!keysym) && (evt.ctrlKey || evt.altKey)) {
- if ((typeof(evt.which) !== "undefined") && (evt.which > 0)) {
- keysym = evt.which;
- } else {
- // IE9 always
- // Firefox and Opera when ctrl/alt + special
- Util.Warn("which not set, using keyCode");
- keysym = evt.keyCode;
- }
-
- /* Remap symbols */
- switch (keysym) {
- case 186 : keysym = 59; break; // ; (IE)
- case 187 : keysym = 61; break; // = (IE)
- case 188 : keysym = 44; break; // , (Mozilla, IE)
- case 109 : // - (Mozilla, Opera)
- if (Util.Engine.gecko || Util.Engine.presto) {
- keysym = 45; }
- break;
- case 173 : // - (Mozilla)
- if (Util.Engine.gecko) {
- keysym = 45; }
- break;
- case 189 : keysym = 45; break; // - (IE)
- case 190 : keysym = 46; break; // . (Mozilla, IE)
- case 191 : keysym = 47; break; // / (Mozilla, IE)
- case 192 : keysym = 96; break; // ` (Mozilla, IE)
- case 219 : keysym = 91; break; // [ (Mozilla, IE)
- case 220 : keysym = 92; break; // \ (Mozilla, IE)
- case 221 : keysym = 93; break; // ] (Mozilla, IE)
- case 222 : keysym = 39; break; // ' (Mozilla, IE)
- }
-
- /* Remap shifted and unshifted keys */
- if (!!evt.shiftKey) {
- switch (keysym) {
- case 48 : keysym = 41 ; break; // ) (shifted 0)
- case 49 : keysym = 33 ; break; // ! (shifted 1)
- case 50 : keysym = 64 ; break; // @ (shifted 2)
- case 51 : keysym = 35 ; break; // # (shifted 3)
- case 52 : keysym = 36 ; break; // $ (shifted 4)
- case 53 : keysym = 37 ; break; // % (shifted 5)
- case 54 : keysym = 94 ; break; // ^ (shifted 6)
- case 55 : keysym = 38 ; break; // & (shifted 7)
- case 56 : keysym = 42 ; break; // * (shifted 8)
- case 57 : keysym = 40 ; break; // ( (shifted 9)
-
- case 59 : keysym = 58 ; break; // : (shifted `)
- case 61 : keysym = 43 ; break; // + (shifted ;)
- case 44 : keysym = 60 ; break; // < (shifted ,)
- case 45 : keysym = 95 ; break; // _ (shifted -)
- case 46 : keysym = 62 ; break; // > (shifted .)
- case 47 : keysym = 63 ; break; // ? (shifted /)
- case 96 : keysym = 126; break; // ~ (shifted `)
- case 91 : keysym = 123; break; // { (shifted [)
- case 92 : keysym = 124; break; // | (shifted \)
- case 93 : keysym = 125; break; // } (shifted ])
- case 39 : keysym = 34 ; break; // " (shifted ')
- }
- } else if ((keysym >= 65) && (keysym <=90)) {
- /* Remap unshifted A-Z */
- keysym += 32;
- } else if (evt.keyLocation === 3) {
- // numpad keys
- switch (keysym) {
- case 96 : keysym = 48; break; // 0
- case 97 : keysym = 49; break; // 1
- case 98 : keysym = 50; break; // 2
- case 99 : keysym = 51; break; // 3
- case 100: keysym = 52; break; // 4
- case 101: keysym = 53; break; // 5
- case 102: keysym = 54; break; // 6
- case 103: keysym = 55; break; // 7
- case 104: keysym = 56; break; // 8
- case 105: keysym = 57; break; // 9
- case 109: keysym = 45; break; // -
- case 110: keysym = 46; break; // .
- case 111: keysym = 47; break; // /
- }
- }
- }
-
- return keysym;
-}
-
-/* Translate DOM keyPress event to keysym value */
-function getKeysym(evt) {
- var keysym, msg;
-
- if (typeof(evt.which) !== "undefined") {
- // WebKit, Firefox, Opera
- keysym = evt.which;
- } else {
- // IE9
- Util.Warn("which not set, using keyCode");
- keysym = evt.keyCode;
- }
-
- if ((keysym > 255) && (keysym < 0xFF00)) {
- msg = "Mapping character code " + keysym;
- // Map Unicode outside Latin 1 to X11 keysyms
- keysym = unicodeTable[keysym];
- if (typeof(keysym) === 'undefined') {
- keysym = 0;
- }
- Util.Debug(msg + " to " + keysym);
- }
-
- return keysym;
-}
-
-function show_keyDownList(kind) {
- var c;
- var msg = "keyDownList (" + kind + "):\n";
- for (c = 0; c < keyDownList.length; c++) {
- msg = msg + " " + c + " - keyCode: " + keyDownList[c].keyCode +
- " - which: " + keyDownList[c].which + "\n";
- }
- Util.Debug(msg);
-}
-
-function copyKeyEvent(evt) {
- var members = ['type', 'keyCode', 'charCode', 'which',
- 'altKey', 'ctrlKey', 'shiftKey',
- 'keyLocation', 'keyIdentifier'], i, obj = {};
- for (i = 0; i < members.length; i++) {
- if (typeof(evt[members[i]]) !== "undefined") {
- obj[members[i]] = evt[members[i]];
- }
- }
- return obj;
-}
-
-function pushKeyEvent(fevt) {
- keyDownList.push(fevt);
-}
-
-function getKeyEvent(keyCode, pop) {
- var i, fevt = null;
- for (i = keyDownList.length-1; i >= 0; i--) {
- if (keyDownList[i].keyCode === keyCode) {
- if ((typeof(pop) !== "undefined") && (pop)) {
- fevt = keyDownList.splice(i, 1)[0];
- } else {
- fevt = keyDownList[i];
- }
- break;
- }
- }
- return fevt;
-}
-
-function ignoreKeyEvent(evt) {
- // Blarg. Some keys have a different keyCode on keyDown vs keyUp
- if (evt.keyCode === 229) {
- // French AZERTY keyboard dead key.
- // Lame thing is that the respective keyUp is 219 so we can't
- // properly ignore the keyUp event
- return true;
- }
- return false;
-}
-
-
-//
-// Key Event Handling:
-//
-// There are several challenges when dealing with key events:
-// - The meaning and use of keyCode, charCode and which depends on
-// both the browser and the event type (keyDown/Up vs keyPress).
-// - We cannot automatically determine the keyboard layout
-// - The keyDown and keyUp events have a keyCode value that has not
-// been translated by modifier keys.
-// - The keyPress event has a translated (for layout and modifiers)
-// character code but the attribute containing it differs. keyCode
-// contains the translated value in WebKit (Chrome/Safari), Opera
-// 11 and IE9. charCode contains the value in WebKit and Firefox.
-// The which attribute contains the value on WebKit, Firefox and
-// Opera 11.
-// - The keyDown/Up keyCode value indicates (sort of) the physical
-// key was pressed but only for standard US layout. On a US
-// keyboard, the '-' and '_' characters are on the same key and
-// generate a keyCode value of 189. But on an AZERTY keyboard even
-// though they are different physical keys they both still
-// generate a keyCode of 189!
-// - To prevent a key event from propagating to the browser and
-// causing unwanted default actions (such as closing a tab,
-// opening a menu, shifting focus, etc) we must suppress this
-// event in both keyDown and keyPress because not all key strokes
-// generate on a keyPress event. Also, in WebKit and IE9
-// suppressing the keyDown prevents a keyPress but other browsers
-// still generated a keyPress even if keyDown is suppressed.
-//
-// For safe key events, we wait until the keyPress event before
-// reporting a key down event. For unsafe key events, we report a key
-// down event when the keyDown event fires and we suppress any further
-// actions (including keyPress).
-//
-// In order to report a key up event that matches what we reported
-// for the key down event, we keep a list of keys that are currently
-// down. When the keyDown event happens, we add the key event to the
-// list. If it is a safe key event, then we update the which attribute
-// in the most recent item on the list when we received a keyPress
-// event (keyPress should immediately follow keyDown). When we
-// received a keyUp event we search for the event on the list with
-// a matching keyCode and we report the character code using the value
-// in the 'which' attribute that was stored with that key.
-//
-
-function onKeyDown(e) {
- if (! conf.focused) {
- return true;
- }
- var fevt = null, evt = (e ? e : window.event),
- keysym = null, suppress = false;
- //Util.Debug("onKeyDown kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
-
- fevt = copyKeyEvent(evt);
-
- keysym = getKeysymSpecial(evt);
- // Save keysym decoding for use in keyUp
- fevt.keysym = keysym;
- if (keysym) {
- // If it is a key or key combination that might trigger
- // browser behaviors or it has no corresponding keyPress
- // event, then send it immediately
- if (conf.onKeyPress && !ignoreKeyEvent(evt)) {
- Util.Debug("onKeyPress down, keysym: " + keysym +
- " (onKeyDown key: " + evt.keyCode +
- ", which: " + evt.which + ")");
- conf.onKeyPress(keysym, 1, evt);
- }
- suppress = true;
- }
-
- if (! ignoreKeyEvent(evt)) {
- // Add it to the list of depressed keys
- pushKeyEvent(fevt);
- //show_keyDownList('down');
- }
-
- if (suppress) {
- // Suppress bubbling/default actions
- Util.stopEvent(e);
- return false;
- } else {
- // Allow the event to bubble and become a keyPress event which
- // will have the character code translated
- return true;
- }
-}
-
-function onKeyPress(e) {
- if (! conf.focused) {
- return true;
- }
- var evt = (e ? e : window.event),
- kdlen = keyDownList.length, keysym = null;
- //Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
-
- if (((evt.which !== "undefined") && (evt.which === 0)) ||
- (getKeysymSpecial(evt))) {
- // Firefox and Opera generate a keyPress event even if keyDown
- // is suppressed. But the keys we want to suppress will have
- // either:
- // - the which attribute set to 0
- // - getKeysymSpecial() will identify it
- Util.Debug("Ignoring special key in keyPress");
- Util.stopEvent(e);
- return false;
- }
-
- keysym = getKeysym(evt);
-
- // Modify the the which attribute in the depressed keys list so
- // that the keyUp event will be able to have the character code
- // translation available.
- if (kdlen > 0) {
- keyDownList[kdlen-1].keysym = keysym;
- } else {
- Util.Warn("keyDownList empty when keyPress triggered");
- }
-
- //show_keyDownList('press');
-
- // Send the translated keysym
- if (conf.onKeyPress && (keysym > 0)) {
- Util.Debug("onKeyPress down, keysym: " + keysym +
- " (onKeyPress key: " + evt.keyCode +
- ", which: " + evt.which + ")");
- conf.onKeyPress(keysym, 1, evt);
- }
-
- // Stop keypress events just in case
- Util.stopEvent(e);
- return false;
-}
-
-function onKeyUp(e) {
- if (! conf.focused) {
- return true;
- }
- var fevt = null, evt = (e ? e : window.event), keysym;
- //Util.Debug("onKeyUp kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
-
- fevt = getKeyEvent(evt.keyCode, true);
-
- if (fevt) {
- keysym = fevt.keysym;
- } else {
- Util.Warn("Key event (keyCode = " + evt.keyCode +
- ") not found on keyDownList");
- keysym = 0;
- }
-
- //show_keyDownList('up');
-
- if (conf.onKeyPress && (keysym > 0)) {
- //Util.Debug("keyPress up, keysym: " + keysym +
- // " (key: " + evt.keyCode + ", which: " + evt.which + ")");
- Util.Debug("onKeyPress up, keysym: " + keysym +
- " (onKeyPress key: " + evt.keyCode +
- ", which: " + evt.which + ")");
- conf.onKeyPress(keysym, 0, evt);
- }
- Util.stopEvent(e);
- return false;
-}
-
-function allKeysUp() {
- Util.Debug(">> Keyboard.allKeysUp");
- if (keyDownList.length > 0) {
- Util.Info("Releasing pressed/down keys");
- }
- var i, keysym, fevt = null;
- for (i = keyDownList.length-1; i >= 0; i--) {
- fevt = keyDownList.splice(i, 1)[0];
- keysym = fevt.keysym;
- if (conf.onKeyPress && (keysym > 0)) {
- Util.Debug("allKeysUp, keysym: " + keysym +
- " (keyCode: " + fevt.keyCode +
- ", which: " + fevt.which + ")");
- conf.onKeyPress(keysym, 0, fevt);
- }
- }
- Util.Debug("<< Keyboard.allKeysUp");
- return;
-}
-
-//
-// Public API interface functions
-//
-
-that.grab = function() {
- //Util.Debug(">> Keyboard.grab");
- var c = conf.target;
-
- Util.addEvent(c, 'keydown', onKeyDown);
- Util.addEvent(c, 'keyup', onKeyUp);
- Util.addEvent(c, 'keypress', onKeyPress);
-
- // Release (key up) if window loses focus
- Util.addEvent(window, 'blur', allKeysUp);
-
- //Util.Debug("<< Keyboard.grab");
-};
-
-that.ungrab = function() {
- //Util.Debug(">> Keyboard.ungrab");
- var c = conf.target;
-
- Util.removeEvent(c, 'keydown', onKeyDown);
- Util.removeEvent(c, 'keyup', onKeyUp);
- Util.removeEvent(c, 'keypress', onKeyPress);
- Util.removeEvent(window, 'blur', allKeysUp);
-
- // Release (key up) all keys that are in a down state
- allKeysUp();
-
- //Util.Debug(">> Keyboard.ungrab");
-};
-
-return that; // Return the public API interface
-
-} // End of Keyboard()
-
-
-//
-// Mouse event handler
-//
-
-function Mouse(defaults) {
-"use strict";
-
-var that = {}, // Public API methods
- conf = {}, // Configuration attributes
- mouseCaptured = false;
-
-// Configuration attributes
-Util.conf_defaults(conf, that, defaults, [
- ['target', 'ro', 'dom', document, 'DOM element that captures mouse input'],
- ['focused', 'rw', 'bool', true, 'Capture and send mouse clicks/movement'],
- ['scale', 'rw', 'float', 1.0, 'Viewport scale factor 0.0 - 1.0'],
-
- ['onMouseButton', 'rw', 'func', null, 'Handler for mouse button click/release'],
- ['onMouseMove', 'rw', 'func', null, 'Handler for mouse movement'],
- ['touchButton', 'rw', 'int', 1, 'Button mask (1, 2, 4) for touch devices (0 means ignore clicks)']
- ]);
-
-function captureMouse() {
- // capturing the mouse ensures we get the mouseup event
- if (conf.target.setCapture) {
- conf.target.setCapture();
- }
-
- // some browsers give us mouseup events regardless,
- // so if we never captured the mouse, we can disregard the event
- mouseCaptured = true;
-}
-
-function releaseMouse() {
- if (conf.target.releaseCapture) {
- conf.target.releaseCapture();
- }
- mouseCaptured = false;
-}
-//
-// Private functions
-//
-
-function onMouseButton(e, down) {
- var evt, pos, bmask;
- if (! conf.focused) {
- return true;
- }
- evt = (e ? e : window.event);
- pos = Util.getEventPosition(e, conf.target, conf.scale);
- if (e.touches || e.changedTouches) {
- // Touch device
- bmask = conf.touchButton;
- // If bmask is set
- } else if (evt.which) {
- /* everything except IE */
- bmask = 1 << evt.button;
- } else {
- /* IE including 9 */
- bmask = (evt.button & 0x1) + // Left
- (evt.button & 0x2) * 2 + // Right
- (evt.button & 0x4) / 2; // Middle
- }
- //Util.Debug("mouse " + pos.x + "," + pos.y + " down: " + down +
- // " bmask: " + bmask + "(evt.button: " + evt.button + ")");
- if (bmask > 0 && conf.onMouseButton) {
- Util.Debug("onMouseButton " + (down ? "down" : "up") +
- ", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
- conf.onMouseButton(pos.x, pos.y, down, bmask);
- }
- Util.stopEvent(e);
- return false;
-}
-
-function onMouseDown(e) {
- captureMouse();
- onMouseButton(e, 1);
-}
-
-function onMouseUp(e) {
- if (!mouseCaptured) {
- return;
- }
-
- onMouseButton(e, 0);
- releaseMouse();
-}
-
-function onMouseWheel(e) {
- var evt, pos, bmask, wheelData;
- if (! conf.focused) {
- return true;
- }
- evt = (e ? e : window.event);
- pos = Util.getEventPosition(e, conf.target, conf.scale);
- wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
- if (wheelData > 0) {
- bmask = 1 << 3;
- } else {
- bmask = 1 << 4;
- }
- //Util.Debug('mouse scroll by ' + wheelData + ':' + pos.x + "," + pos.y);
- if (conf.onMouseButton) {
- conf.onMouseButton(pos.x, pos.y, 1, bmask);
- conf.onMouseButton(pos.x, pos.y, 0, bmask);
- }
- Util.stopEvent(e);
- return false;
-}
-
-function onMouseMove(e) {
- var evt, pos;
- if (! conf.focused) {
- return true;
- }
- evt = (e ? e : window.event);
- pos = Util.getEventPosition(e, conf.target, conf.scale);
- //Util.Debug('mouse ' + evt.which + '/' + evt.button + ' up:' + pos.x + "," + pos.y);
- if (conf.onMouseMove) {
- conf.onMouseMove(pos.x, pos.y);
- }
- Util.stopEvent(e);
- return false;
-}
-
-function onMouseDisable(e) {
- var evt, pos;
- if (! conf.focused) {
- return true;
- }
- evt = (e ? e : window.event);
- pos = Util.getEventPosition(e, conf.target, conf.scale);
- /* Stop propagation if inside canvas area */
- if ((pos.x >= 0) && (pos.y >= 0) &&
- (pos.x < conf.target.offsetWidth) &&
- (pos.y < conf.target.offsetHeight)) {
- //Util.Debug("mouse event disabled");
- Util.stopEvent(e);
- return false;
- }
- //Util.Debug("mouse event not disabled");
- return true;
-}
-
-//
-// Public API interface functions
-//
-
-that.grab = function() {
- //Util.Debug(">> Mouse.grab");
- var c = conf.target;
-
- if ('ontouchstart' in document.documentElement) {
- Util.addEvent(c, 'touchstart', onMouseDown);
- Util.addEvent(window, 'touchend', onMouseUp);
- Util.addEvent(c, 'touchend', onMouseUp);
- Util.addEvent(c, 'touchmove', onMouseMove);
- } else {
- Util.addEvent(c, 'mousedown', onMouseDown);
- Util.addEvent(window, 'mouseup', onMouseUp);
- Util.addEvent(c, 'mouseup', onMouseUp);
- Util.addEvent(c, 'mousemove', onMouseMove);
- Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
- onMouseWheel);
- }
-
- /* Work around right and middle click browser behaviors */
- Util.addEvent(document, 'click', onMouseDisable);
- Util.addEvent(document.body, 'contextmenu', onMouseDisable);
-
- //Util.Debug("<< Mouse.grab");
-};
-
-that.ungrab = function() {
- //Util.Debug(">> Mouse.ungrab");
- var c = conf.target;
-
- if ('ontouchstart' in document.documentElement) {
- Util.removeEvent(c, 'touchstart', onMouseDown);
- Util.removeEvent(window, 'touchend', onMouseUp);
- Util.removeEvent(c, 'touchend', onMouseUp);
- Util.removeEvent(c, 'touchmove', onMouseMove);
- } else {
- Util.removeEvent(c, 'mousedown', onMouseDown);
- Util.removeEvent(window, 'mouseup', onMouseUp);
- Util.removeEvent(c, 'mouseup', onMouseUp);
- Util.removeEvent(c, 'mousemove', onMouseMove);
- Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
- onMouseWheel);
- }
-
- /* Work around right and middle click browser behaviors */
- Util.removeEvent(document, 'click', onMouseDisable);
- Util.removeEvent(document.body, 'contextmenu', onMouseDisable);
-
- //Util.Debug(">> Mouse.ungrab");
-};
-
-return that; // Return the public API interface
-
-} // End of Mouse()
-
-
-/*
- * Browser keypress to X11 keysym for Unicode characters > U+00FF
- */
-unicodeTable = {
- 0x0104 : 0x01a1,
- 0x02D8 : 0x01a2,
- 0x0141 : 0x01a3,
- 0x013D : 0x01a5,
- 0x015A : 0x01a6,
- 0x0160 : 0x01a9,
- 0x015E : 0x01aa,
- 0x0164 : 0x01ab,
- 0x0179 : 0x01ac,
- 0x017D : 0x01ae,
- 0x017B : 0x01af,
- 0x0105 : 0x01b1,
- 0x02DB : 0x01b2,
- 0x0142 : 0x01b3,
- 0x013E : 0x01b5,
- 0x015B : 0x01b6,
- 0x02C7 : 0x01b7,
- 0x0161 : 0x01b9,
- 0x015F : 0x01ba,
- 0x0165 : 0x01bb,
- 0x017A : 0x01bc,
- 0x02DD : 0x01bd,
- 0x017E : 0x01be,
- 0x017C : 0x01bf,
- 0x0154 : 0x01c0,
- 0x0102 : 0x01c3,
- 0x0139 : 0x01c5,
- 0x0106 : 0x01c6,
- 0x010C : 0x01c8,
- 0x0118 : 0x01ca,
- 0x011A : 0x01cc,
- 0x010E : 0x01cf,
- 0x0110 : 0x01d0,
- 0x0143 : 0x01d1,
- 0x0147 : 0x01d2,
- 0x0150 : 0x01d5,
- 0x0158 : 0x01d8,
- 0x016E : 0x01d9,
- 0x0170 : 0x01db,
- 0x0162 : 0x01de,
- 0x0155 : 0x01e0,
- 0x0103 : 0x01e3,
- 0x013A : 0x01e5,
- 0x0107 : 0x01e6,
- 0x010D : 0x01e8,
- 0x0119 : 0x01ea,
- 0x011B : 0x01ec,
- 0x010F : 0x01ef,
- 0x0111 : 0x01f0,
- 0x0144 : 0x01f1,
- 0x0148 : 0x01f2,
- 0x0151 : 0x01f5,
- 0x0171 : 0x01fb,
- 0x0159 : 0x01f8,
- 0x016F : 0x01f9,
- 0x0163 : 0x01fe,
- 0x02D9 : 0x01ff,
- 0x0126 : 0x02a1,
- 0x0124 : 0x02a6,
- 0x0130 : 0x02a9,
- 0x011E : 0x02ab,
- 0x0134 : 0x02ac,
- 0x0127 : 0x02b1,
- 0x0125 : 0x02b6,
- 0x0131 : 0x02b9,
- 0x011F : 0x02bb,
- 0x0135 : 0x02bc,
- 0x010A : 0x02c5,
- 0x0108 : 0x02c6,
- 0x0120 : 0x02d5,
- 0x011C : 0x02d8,
- 0x016C : 0x02dd,
- 0x015C : 0x02de,
- 0x010B : 0x02e5,
- 0x0109 : 0x02e6,
- 0x0121 : 0x02f5,
- 0x011D : 0x02f8,
- 0x016D : 0x02fd,
- 0x015D : 0x02fe,
- 0x0138 : 0x03a2,
- 0x0156 : 0x03a3,
- 0x0128 : 0x03a5,
- 0x013B : 0x03a6,
- 0x0112 : 0x03aa,
- 0x0122 : 0x03ab,
- 0x0166 : 0x03ac,
- 0x0157 : 0x03b3,
- 0x0129 : 0x03b5,
- 0x013C : 0x03b6,
- 0x0113 : 0x03ba,
- 0x0123 : 0x03bb,
- 0x0167 : 0x03bc,
- 0x014A : 0x03bd,
- 0x014B : 0x03bf,
- 0x0100 : 0x03c0,
- 0x012E : 0x03c7,
- 0x0116 : 0x03cc,
- 0x012A : 0x03cf,
- 0x0145 : 0x03d1,
- 0x014C : 0x03d2,
- 0x0136 : 0x03d3,
- 0x0172 : 0x03d9,
- 0x0168 : 0x03dd,
- 0x016A : 0x03de,
- 0x0101 : 0x03e0,
- 0x012F : 0x03e7,
- 0x0117 : 0x03ec,
- 0x012B : 0x03ef,
- 0x0146 : 0x03f1,
- 0x014D : 0x03f2,
- 0x0137 : 0x03f3,
- 0x0173 : 0x03f9,
- 0x0169 : 0x03fd,
- 0x016B : 0x03fe,
- 0x1E02 : 0x1001e02,
- 0x1E03 : 0x1001e03,
- 0x1E0A : 0x1001e0a,
- 0x1E80 : 0x1001e80,
- 0x1E82 : 0x1001e82,
- 0x1E0B : 0x1001e0b,
- 0x1EF2 : 0x1001ef2,
- 0x1E1E : 0x1001e1e,
- 0x1E1F : 0x1001e1f,
- 0x1E40 : 0x1001e40,
- 0x1E41 : 0x1001e41,
- 0x1E56 : 0x1001e56,
- 0x1E81 : 0x1001e81,
- 0x1E57 : 0x1001e57,
- 0x1E83 : 0x1001e83,
- 0x1E60 : 0x1001e60,
- 0x1EF3 : 0x1001ef3,
- 0x1E84 : 0x1001e84,
- 0x1E85 : 0x1001e85,
- 0x1E61 : 0x1001e61,
- 0x0174 : 0x1000174,
- 0x1E6A : 0x1001e6a,
- 0x0176 : 0x1000176,
- 0x0175 : 0x1000175,
- 0x1E6B : 0x1001e6b,
- 0x0177 : 0x1000177,
- 0x0152 : 0x13bc,
- 0x0153 : 0x13bd,
- 0x0178 : 0x13be,
- 0x203E : 0x047e,
- 0x3002 : 0x04a1,
- 0x300C : 0x04a2,
- 0x300D : 0x04a3,
- 0x3001 : 0x04a4,
- 0x30FB : 0x04a5,
- 0x30F2 : 0x04a6,
- 0x30A1 : 0x04a7,
- 0x30A3 : 0x04a8,
- 0x30A5 : 0x04a9,
- 0x30A7 : 0x04aa,
- 0x30A9 : 0x04ab,
- 0x30E3 : 0x04ac,
- 0x30E5 : 0x04ad,
- 0x30E7 : 0x04ae,
- 0x30C3 : 0x04af,
- 0x30FC : 0x04b0,
- 0x30A2 : 0x04b1,
- 0x30A4 : 0x04b2,
- 0x30A6 : 0x04b3,
- 0x30A8 : 0x04b4,
- 0x30AA : 0x04b5,
- 0x30AB : 0x04b6,
- 0x30AD : 0x04b7,
- 0x30AF : 0x04b8,
- 0x30B1 : 0x04b9,
- 0x30B3 : 0x04ba,
- 0x30B5 : 0x04bb,
- 0x30B7 : 0x04bc,
- 0x30B9 : 0x04bd,
- 0x30BB : 0x04be,
- 0x30BD : 0x04bf,
- 0x30BF : 0x04c0,
- 0x30C1 : 0x04c1,
- 0x30C4 : 0x04c2,
- 0x30C6 : 0x04c3,
- 0x30C8 : 0x04c4,
- 0x30CA : 0x04c5,
- 0x30CB : 0x04c6,
- 0x30CC : 0x04c7,
- 0x30CD : 0x04c8,
- 0x30CE : 0x04c9,
- 0x30CF : 0x04ca,
- 0x30D2 : 0x04cb,
- 0x30D5 : 0x04cc,
- 0x30D8 : 0x04cd,
- 0x30DB : 0x04ce,
- 0x30DE : 0x04cf,
- 0x30DF : 0x04d0,
- 0x30E0 : 0x04d1,
- 0x30E1 : 0x04d2,
- 0x30E2 : 0x04d3,
- 0x30E4 : 0x04d4,
- 0x30E6 : 0x04d5,
- 0x30E8 : 0x04d6,
- 0x30E9 : 0x04d7,
- 0x30EA : 0x04d8,
- 0x30EB : 0x04d9,
- 0x30EC : 0x04da,
- 0x30ED : 0x04db,
- 0x30EF : 0x04dc,
- 0x30F3 : 0x04dd,
- 0x309B : 0x04de,
- 0x309C : 0x04df,
- 0x06F0 : 0x10006f0,
- 0x06F1 : 0x10006f1,
- 0x06F2 : 0x10006f2,
- 0x06F3 : 0x10006f3,
- 0x06F4 : 0x10006f4,
- 0x06F5 : 0x10006f5,
- 0x06F6 : 0x10006f6,
- 0x06F7 : 0x10006f7,
- 0x06F8 : 0x10006f8,
- 0x06F9 : 0x10006f9,
- 0x066A : 0x100066a,
- 0x0670 : 0x1000670,
- 0x0679 : 0x1000679,
- 0x067E : 0x100067e,
- 0x0686 : 0x1000686,
- 0x0688 : 0x1000688,
- 0x0691 : 0x1000691,
- 0x060C : 0x05ac,
- 0x06D4 : 0x10006d4,
- 0x0660 : 0x1000660,
- 0x0661 : 0x1000661,
- 0x0662 : 0x1000662,
- 0x0663 : 0x1000663,
- 0x0664 : 0x1000664,
- 0x0665 : 0x1000665,
- 0x0666 : 0x1000666,
- 0x0667 : 0x1000667,
- 0x0668 : 0x1000668,
- 0x0669 : 0x1000669,
- 0x061B : 0x05bb,
- 0x061F : 0x05bf,
- 0x0621 : 0x05c1,
- 0x0622 : 0x05c2,
- 0x0623 : 0x05c3,
- 0x0624 : 0x05c4,
- 0x0625 : 0x05c5,
- 0x0626 : 0x05c6,
- 0x0627 : 0x05c7,
- 0x0628 : 0x05c8,
- 0x0629 : 0x05c9,
- 0x062A : 0x05ca,
- 0x062B : 0x05cb,
- 0x062C : 0x05cc,
- 0x062D : 0x05cd,
- 0x062E : 0x05ce,
- 0x062F : 0x05cf,
- 0x0630 : 0x05d0,
- 0x0631 : 0x05d1,
- 0x0632 : 0x05d2,
- 0x0633 : 0x05d3,
- 0x0634 : 0x05d4,
- 0x0635 : 0x05d5,
- 0x0636 : 0x05d6,
- 0x0637 : 0x05d7,
- 0x0638 : 0x05d8,
- 0x0639 : 0x05d9,
- 0x063A : 0x05da,
- 0x0640 : 0x05e0,
- 0x0641 : 0x05e1,
- 0x0642 : 0x05e2,
- 0x0643 : 0x05e3,
- 0x0644 : 0x05e4,
- 0x0645 : 0x05e5,
- 0x0646 : 0x05e6,
- 0x0647 : 0x05e7,
- 0x0648 : 0x05e8,
- 0x0649 : 0x05e9,
- 0x064A : 0x05ea,
- 0x064B : 0x05eb,
- 0x064C : 0x05ec,
- 0x064D : 0x05ed,
- 0x064E : 0x05ee,
- 0x064F : 0x05ef,
- 0x0650 : 0x05f0,
- 0x0651 : 0x05f1,
- 0x0652 : 0x05f2,
- 0x0653 : 0x1000653,
- 0x0654 : 0x1000654,
- 0x0655 : 0x1000655,
- 0x0698 : 0x1000698,
- 0x06A4 : 0x10006a4,
- 0x06A9 : 0x10006a9,
- 0x06AF : 0x10006af,
- 0x06BA : 0x10006ba,
- 0x06BE : 0x10006be,
- 0x06CC : 0x10006cc,
- 0x06D2 : 0x10006d2,
- 0x06C1 : 0x10006c1,
- 0x0492 : 0x1000492,
- 0x0493 : 0x1000493,
- 0x0496 : 0x1000496,
- 0x0497 : 0x1000497,
- 0x049A : 0x100049a,
- 0x049B : 0x100049b,
- 0x049C : 0x100049c,
- 0x049D : 0x100049d,
- 0x04A2 : 0x10004a2,
- 0x04A3 : 0x10004a3,
- 0x04AE : 0x10004ae,
- 0x04AF : 0x10004af,
- 0x04B0 : 0x10004b0,
- 0x04B1 : 0x10004b1,
- 0x04B2 : 0x10004b2,
- 0x04B3 : 0x10004b3,
- 0x04B6 : 0x10004b6,
- 0x04B7 : 0x10004b7,
- 0x04B8 : 0x10004b8,
- 0x04B9 : 0x10004b9,
- 0x04BA : 0x10004ba,
- 0x04BB : 0x10004bb,
- 0x04D8 : 0x10004d8,
- 0x04D9 : 0x10004d9,
- 0x04E2 : 0x10004e2,
- 0x04E3 : 0x10004e3,
- 0x04E8 : 0x10004e8,
- 0x04E9 : 0x10004e9,
- 0x04EE : 0x10004ee,
- 0x04EF : 0x10004ef,
- 0x0452 : 0x06a1,
- 0x0453 : 0x06a2,
- 0x0451 : 0x06a3,
- 0x0454 : 0x06a4,
- 0x0455 : 0x06a5,
- 0x0456 : 0x06a6,
- 0x0457 : 0x06a7,
- 0x0458 : 0x06a8,
- 0x0459 : 0x06a9,
- 0x045A : 0x06aa,
- 0x045B : 0x06ab,
- 0x045C : 0x06ac,
- 0x0491 : 0x06ad,
- 0x045E : 0x06ae,
- 0x045F : 0x06af,
- 0x2116 : 0x06b0,
- 0x0402 : 0x06b1,
- 0x0403 : 0x06b2,
- 0x0401 : 0x06b3,
- 0x0404 : 0x06b4,
- 0x0405 : 0x06b5,
- 0x0406 : 0x06b6,
- 0x0407 : 0x06b7,
- 0x0408 : 0x06b8,
- 0x0409 : 0x06b9,
- 0x040A : 0x06ba,
- 0x040B : 0x06bb,
- 0x040C : 0x06bc,
- 0x0490 : 0x06bd,
- 0x040E : 0x06be,
- 0x040F : 0x06bf,
- 0x044E : 0x06c0,
- 0x0430 : 0x06c1,
- 0x0431 : 0x06c2,
- 0x0446 : 0x06c3,
- 0x0434 : 0x06c4,
- 0x0435 : 0x06c5,
- 0x0444 : 0x06c6,
- 0x0433 : 0x06c7,
- 0x0445 : 0x06c8,
- 0x0438 : 0x06c9,
- 0x0439 : 0x06ca,
- 0x043A : 0x06cb,
- 0x043B : 0x06cc,
- 0x043C : 0x06cd,
- 0x043D : 0x06ce,
- 0x043E : 0x06cf,
- 0x043F : 0x06d0,
- 0x044F : 0x06d1,
- 0x0440 : 0x06d2,
- 0x0441 : 0x06d3,
- 0x0442 : 0x06d4,
- 0x0443 : 0x06d5,
- 0x0436 : 0x06d6,
- 0x0432 : 0x06d7,
- 0x044C : 0x06d8,
- 0x044B : 0x06d9,
- 0x0437 : 0x06da,
- 0x0448 : 0x06db,
- 0x044D : 0x06dc,
- 0x0449 : 0x06dd,
- 0x0447 : 0x06de,
- 0x044A : 0x06df,
- 0x042E : 0x06e0,
- 0x0410 : 0x06e1,
- 0x0411 : 0x06e2,
- 0x0426 : 0x06e3,
- 0x0414 : 0x06e4,
- 0x0415 : 0x06e5,
- 0x0424 : 0x06e6,
- 0x0413 : 0x06e7,
- 0x0425 : 0x06e8,
- 0x0418 : 0x06e9,
- 0x0419 : 0x06ea,
- 0x041A : 0x06eb,
- 0x041B : 0x06ec,
- 0x041C : 0x06ed,
- 0x041D : 0x06ee,
- 0x041E : 0x06ef,
- 0x041F : 0x06f0,
- 0x042F : 0x06f1,
- 0x0420 : 0x06f2,
- 0x0421 : 0x06f3,
- 0x0422 : 0x06f4,
- 0x0423 : 0x06f5,
- 0x0416 : 0x06f6,
- 0x0412 : 0x06f7,
- 0x042C : 0x06f8,
- 0x042B : 0x06f9,
- 0x0417 : 0x06fa,
- 0x0428 : 0x06fb,
- 0x042D : 0x06fc,
- 0x0429 : 0x06fd,
- 0x0427 : 0x06fe,
- 0x042A : 0x06ff,
- 0x0386 : 0x07a1,
- 0x0388 : 0x07a2,
- 0x0389 : 0x07a3,
- 0x038A : 0x07a4,
- 0x03AA : 0x07a5,
- 0x038C : 0x07a7,
- 0x038E : 0x07a8,
- 0x03AB : 0x07a9,
- 0x038F : 0x07ab,
- 0x0385 : 0x07ae,
- 0x2015 : 0x07af,
- 0x03AC : 0x07b1,
- 0x03AD : 0x07b2,
- 0x03AE : 0x07b3,
- 0x03AF : 0x07b4,
- 0x03CA : 0x07b5,
- 0x0390 : 0x07b6,
- 0x03CC : 0x07b7,
- 0x03CD : 0x07b8,
- 0x03CB : 0x07b9,
- 0x03B0 : 0x07ba,
- 0x03CE : 0x07bb,
- 0x0391 : 0x07c1,
- 0x0392 : 0x07c2,
- 0x0393 : 0x07c3,
- 0x0394 : 0x07c4,
- 0x0395 : 0x07c5,
- 0x0396 : 0x07c6,
- 0x0397 : 0x07c7,
- 0x0398 : 0x07c8,
- 0x0399 : 0x07c9,
- 0x039A : 0x07ca,
- 0x039B : 0x07cb,
- 0x039C : 0x07cc,
- 0x039D : 0x07cd,
- 0x039E : 0x07ce,
- 0x039F : 0x07cf,
- 0x03A0 : 0x07d0,
- 0x03A1 : 0x07d1,
- 0x03A3 : 0x07d2,
- 0x03A4 : 0x07d4,
- 0x03A5 : 0x07d5,
- 0x03A6 : 0x07d6,
- 0x03A7 : 0x07d7,
- 0x03A8 : 0x07d8,
- 0x03A9 : 0x07d9,
- 0x03B1 : 0x07e1,
- 0x03B2 : 0x07e2,
- 0x03B3 : 0x07e3,
- 0x03B4 : 0x07e4,
- 0x03B5 : 0x07e5,
- 0x03B6 : 0x07e6,
- 0x03B7 : 0x07e7,
- 0x03B8 : 0x07e8,
- 0x03B9 : 0x07e9,
- 0x03BA : 0x07ea,
- 0x03BB : 0x07eb,
- 0x03BC : 0x07ec,
- 0x03BD : 0x07ed,
- 0x03BE : 0x07ee,
- 0x03BF : 0x07ef,
- 0x03C0 : 0x07f0,
- 0x03C1 : 0x07f1,
- 0x03C3 : 0x07f2,
- 0x03C2 : 0x07f3,
- 0x03C4 : 0x07f4,
- 0x03C5 : 0x07f5,
- 0x03C6 : 0x07f6,
- 0x03C7 : 0x07f7,
- 0x03C8 : 0x07f8,
- 0x03C9 : 0x07f9,
- 0x23B7 : 0x08a1,
- 0x2320 : 0x08a4,
- 0x2321 : 0x08a5,
- 0x23A1 : 0x08a7,
- 0x23A3 : 0x08a8,
- 0x23A4 : 0x08a9,
- 0x23A6 : 0x08aa,
- 0x239B : 0x08ab,
- 0x239D : 0x08ac,
- 0x239E : 0x08ad,
- 0x23A0 : 0x08ae,
- 0x23A8 : 0x08af,
- 0x23AC : 0x08b0,
- 0x2264 : 0x08bc,
- 0x2260 : 0x08bd,
- 0x2265 : 0x08be,
- 0x222B : 0x08bf,
- 0x2234 : 0x08c0,
- 0x221D : 0x08c1,
- 0x221E : 0x08c2,
- 0x2207 : 0x08c5,
- 0x223C : 0x08c8,
- 0x2243 : 0x08c9,
- 0x21D4 : 0x08cd,
- 0x21D2 : 0x08ce,
- 0x2261 : 0x08cf,
- //0x221A : 0x08d6,
- 0x2282 : 0x08da,
- 0x2283 : 0x08db,
- 0x2229 : 0x08dc,
- 0x222A : 0x08dd,
- 0x2227 : 0x08de,
- 0x2228 : 0x08df,
- //0x2202 : 0x08ef,
- 0x0192 : 0x08f6,
- 0x2190 : 0x08fb,
- 0x2191 : 0x08fc,
- 0x2192 : 0x08fd,
- 0x2193 : 0x08fe,
- 0x25C6 : 0x09e0,
- 0x2592 : 0x09e1,
- 0x2409 : 0x09e2,
- 0x240C : 0x09e3,
- 0x240D : 0x09e4,
- 0x240A : 0x09e5,
- 0x2424 : 0x09e8,
- 0x240B : 0x09e9,
- 0x2518 : 0x09ea,
- 0x2510 : 0x09eb,
- 0x250C : 0x09ec,
- 0x2514 : 0x09ed,
- 0x253C : 0x09ee,
- 0x23BA : 0x09ef,
- 0x23BB : 0x09f0,
- 0x2500 : 0x09f1,
- 0x23BC : 0x09f2,
- 0x23BD : 0x09f3,
- 0x251C : 0x09f4,
- 0x2524 : 0x09f5,
- 0x2534 : 0x09f6,
- 0x252C : 0x09f7,
- 0x2502 : 0x09f8,
- 0x2003 : 0x0aa1,
- 0x2002 : 0x0aa2,
- 0x2004 : 0x0aa3,
- 0x2005 : 0x0aa4,
- 0x2007 : 0x0aa5,
- 0x2008 : 0x0aa6,
- 0x2009 : 0x0aa7,
- 0x200A : 0x0aa8,
- 0x2014 : 0x0aa9,
- 0x2013 : 0x0aaa,
- 0x2026 : 0x0aae,
- 0x2025 : 0x0aaf,
- 0x2153 : 0x0ab0,
- 0x2154 : 0x0ab1,
- 0x2155 : 0x0ab2,
- 0x2156 : 0x0ab3,
- 0x2157 : 0x0ab4,
- 0x2158 : 0x0ab5,
- 0x2159 : 0x0ab6,
- 0x215A : 0x0ab7,
- 0x2105 : 0x0ab8,
- 0x2012 : 0x0abb,
- 0x215B : 0x0ac3,
- 0x215C : 0x0ac4,
- 0x215D : 0x0ac5,
- 0x215E : 0x0ac6,
- 0x2122 : 0x0ac9,
- 0x2018 : 0x0ad0,
- 0x2019 : 0x0ad1,
- 0x201C : 0x0ad2,
- 0x201D : 0x0ad3,
- 0x211E : 0x0ad4,
- 0x2032 : 0x0ad6,
- 0x2033 : 0x0ad7,
- 0x271D : 0x0ad9,
- 0x2663 : 0x0aec,
- 0x2666 : 0x0aed,
- 0x2665 : 0x0aee,
- 0x2720 : 0x0af0,
- 0x2020 : 0x0af1,
- 0x2021 : 0x0af2,
- 0x2713 : 0x0af3,
- 0x2717 : 0x0af4,
- 0x266F : 0x0af5,
- 0x266D : 0x0af6,
- 0x2642 : 0x0af7,
- 0x2640 : 0x0af8,
- 0x260E : 0x0af9,
- 0x2315 : 0x0afa,
- 0x2117 : 0x0afb,
- 0x2038 : 0x0afc,
- 0x201A : 0x0afd,
- 0x201E : 0x0afe,
- 0x22A4 : 0x0bc2,
- 0x230A : 0x0bc4,
- 0x2218 : 0x0bca,
- 0x2395 : 0x0bcc,
- 0x22A5 : 0x0bce,
- 0x25CB : 0x0bcf,
- 0x2308 : 0x0bd3,
- 0x22A3 : 0x0bdc,
- 0x22A2 : 0x0bfc,
- 0x2017 : 0x0cdf,
- 0x05D0 : 0x0ce0,
- 0x05D1 : 0x0ce1,
- 0x05D2 : 0x0ce2,
- 0x05D3 : 0x0ce3,
- 0x05D4 : 0x0ce4,
- 0x05D5 : 0x0ce5,
- 0x05D6 : 0x0ce6,
- 0x05D7 : 0x0ce7,
- 0x05D8 : 0x0ce8,
- 0x05D9 : 0x0ce9,
- 0x05DA : 0x0cea,
- 0x05DB : 0x0ceb,
- 0x05DC : 0x0cec,
- 0x05DD : 0x0ced,
- 0x05DE : 0x0cee,
- 0x05DF : 0x0cef,
- 0x05E0 : 0x0cf0,
- 0x05E1 : 0x0cf1,
- 0x05E2 : 0x0cf2,
- 0x05E3 : 0x0cf3,
- 0x05E4 : 0x0cf4,
- 0x05E5 : 0x0cf5,
- 0x05E6 : 0x0cf6,
- 0x05E7 : 0x0cf7,
- 0x05E8 : 0x0cf8,
- 0x05E9 : 0x0cf9,
- 0x05EA : 0x0cfa,
- 0x0E01 : 0x0da1,
- 0x0E02 : 0x0da2,
- 0x0E03 : 0x0da3,
- 0x0E04 : 0x0da4,
- 0x0E05 : 0x0da5,
- 0x0E06 : 0x0da6,
- 0x0E07 : 0x0da7,
- 0x0E08 : 0x0da8,
- 0x0E09 : 0x0da9,
- 0x0E0A : 0x0daa,
- 0x0E0B : 0x0dab,
- 0x0E0C : 0x0dac,
- 0x0E0D : 0x0dad,
- 0x0E0E : 0x0dae,
- 0x0E0F : 0x0daf,
- 0x0E10 : 0x0db0,
- 0x0E11 : 0x0db1,
- 0x0E12 : 0x0db2,
- 0x0E13 : 0x0db3,
- 0x0E14 : 0x0db4,
- 0x0E15 : 0x0db5,
- 0x0E16 : 0x0db6,
- 0x0E17 : 0x0db7,
- 0x0E18 : 0x0db8,
- 0x0E19 : 0x0db9,
- 0x0E1A : 0x0dba,
- 0x0E1B : 0x0dbb,
- 0x0E1C : 0x0dbc,
- 0x0E1D : 0x0dbd,
- 0x0E1E : 0x0dbe,
- 0x0E1F : 0x0dbf,
- 0x0E20 : 0x0dc0,
- 0x0E21 : 0x0dc1,
- 0x0E22 : 0x0dc2,
- 0x0E23 : 0x0dc3,
- 0x0E24 : 0x0dc4,
- 0x0E25 : 0x0dc5,
- 0x0E26 : 0x0dc6,
- 0x0E27 : 0x0dc7,
- 0x0E28 : 0x0dc8,
- 0x0E29 : 0x0dc9,
- 0x0E2A : 0x0dca,
- 0x0E2B : 0x0dcb,
- 0x0E2C : 0x0dcc,
- 0x0E2D : 0x0dcd,
- 0x0E2E : 0x0dce,
- 0x0E2F : 0x0dcf,
- 0x0E30 : 0x0dd0,
- 0x0E31 : 0x0dd1,
- 0x0E32 : 0x0dd2,
- 0x0E33 : 0x0dd3,
- 0x0E34 : 0x0dd4,
- 0x0E35 : 0x0dd5,
- 0x0E36 : 0x0dd6,
- 0x0E37 : 0x0dd7,
- 0x0E38 : 0x0dd8,
- 0x0E39 : 0x0dd9,
- 0x0E3A : 0x0dda,
- 0x0E3F : 0x0ddf,
- 0x0E40 : 0x0de0,
- 0x0E41 : 0x0de1,
- 0x0E42 : 0x0de2,
- 0x0E43 : 0x0de3,
- 0x0E44 : 0x0de4,
- 0x0E45 : 0x0de5,
- 0x0E46 : 0x0de6,
- 0x0E47 : 0x0de7,
- 0x0E48 : 0x0de8,
- 0x0E49 : 0x0de9,
- 0x0E4A : 0x0dea,
- 0x0E4B : 0x0deb,
- 0x0E4C : 0x0dec,
- 0x0E4D : 0x0ded,
- 0x0E50 : 0x0df0,
- 0x0E51 : 0x0df1,
- 0x0E52 : 0x0df2,
- 0x0E53 : 0x0df3,
- 0x0E54 : 0x0df4,
- 0x0E55 : 0x0df5,
- 0x0E56 : 0x0df6,
- 0x0E57 : 0x0df7,
- 0x0E58 : 0x0df8,
- 0x0E59 : 0x0df9,
- 0x0587 : 0x1000587,
- 0x0589 : 0x1000589,
- 0x055D : 0x100055d,
- 0x058A : 0x100058a,
- 0x055C : 0x100055c,
- 0x055B : 0x100055b,
- 0x055E : 0x100055e,
- 0x0531 : 0x1000531,
- 0x0561 : 0x1000561,
- 0x0532 : 0x1000532,
- 0x0562 : 0x1000562,
- 0x0533 : 0x1000533,
- 0x0563 : 0x1000563,
- 0x0534 : 0x1000534,
- 0x0564 : 0x1000564,
- 0x0535 : 0x1000535,
- 0x0565 : 0x1000565,
- 0x0536 : 0x1000536,
- 0x0566 : 0x1000566,
- 0x0537 : 0x1000537,
- 0x0567 : 0x1000567,
- 0x0538 : 0x1000538,
- 0x0568 : 0x1000568,
- 0x0539 : 0x1000539,
- 0x0569 : 0x1000569,
- 0x053A : 0x100053a,
- 0x056A : 0x100056a,
- 0x053B : 0x100053b,
- 0x056B : 0x100056b,
- 0x053C : 0x100053c,
- 0x056C : 0x100056c,
- 0x053D : 0x100053d,
- 0x056D : 0x100056d,
- 0x053E : 0x100053e,
- 0x056E : 0x100056e,
- 0x053F : 0x100053f,
- 0x056F : 0x100056f,
- 0x0540 : 0x1000540,
- 0x0570 : 0x1000570,
- 0x0541 : 0x1000541,
- 0x0571 : 0x1000571,
- 0x0542 : 0x1000542,
- 0x0572 : 0x1000572,
- 0x0543 : 0x1000543,
- 0x0573 : 0x1000573,
- 0x0544 : 0x1000544,
- 0x0574 : 0x1000574,
- 0x0545 : 0x1000545,
- 0x0575 : 0x1000575,
- 0x0546 : 0x1000546,
- 0x0576 : 0x1000576,
- 0x0547 : 0x1000547,
- 0x0577 : 0x1000577,
- 0x0548 : 0x1000548,
- 0x0578 : 0x1000578,
- 0x0549 : 0x1000549,
- 0x0579 : 0x1000579,
- 0x054A : 0x100054a,
- 0x057A : 0x100057a,
- 0x054B : 0x100054b,
- 0x057B : 0x100057b,
- 0x054C : 0x100054c,
- 0x057C : 0x100057c,
- 0x054D : 0x100054d,
- 0x057D : 0x100057d,
- 0x054E : 0x100054e,
- 0x057E : 0x100057e,
- 0x054F : 0x100054f,
- 0x057F : 0x100057f,
- 0x0550 : 0x1000550,
- 0x0580 : 0x1000580,
- 0x0551 : 0x1000551,
- 0x0581 : 0x1000581,
- 0x0552 : 0x1000552,
- 0x0582 : 0x1000582,
- 0x0553 : 0x1000553,
- 0x0583 : 0x1000583,
- 0x0554 : 0x1000554,
- 0x0584 : 0x1000584,
- 0x0555 : 0x1000555,
- 0x0585 : 0x1000585,
- 0x0556 : 0x1000556,
- 0x0586 : 0x1000586,
- 0x055A : 0x100055a,
- 0x10D0 : 0x10010d0,
- 0x10D1 : 0x10010d1,
- 0x10D2 : 0x10010d2,
- 0x10D3 : 0x10010d3,
- 0x10D4 : 0x10010d4,
- 0x10D5 : 0x10010d5,
- 0x10D6 : 0x10010d6,
- 0x10D7 : 0x10010d7,
- 0x10D8 : 0x10010d8,
- 0x10D9 : 0x10010d9,
- 0x10DA : 0x10010da,
- 0x10DB : 0x10010db,
- 0x10DC : 0x10010dc,
- 0x10DD : 0x10010dd,
- 0x10DE : 0x10010de,
- 0x10DF : 0x10010df,
- 0x10E0 : 0x10010e0,
- 0x10E1 : 0x10010e1,
- 0x10E2 : 0x10010e2,
- 0x10E3 : 0x10010e3,
- 0x10E4 : 0x10010e4,
- 0x10E5 : 0x10010e5,
- 0x10E6 : 0x10010e6,
- 0x10E7 : 0x10010e7,
- 0x10E8 : 0x10010e8,
- 0x10E9 : 0x10010e9,
- 0x10EA : 0x10010ea,
- 0x10EB : 0x10010eb,
- 0x10EC : 0x10010ec,
- 0x10ED : 0x10010ed,
- 0x10EE : 0x10010ee,
- 0x10EF : 0x10010ef,
- 0x10F0 : 0x10010f0,
- 0x10F1 : 0x10010f1,
- 0x10F2 : 0x10010f2,
- 0x10F3 : 0x10010f3,
- 0x10F4 : 0x10010f4,
- 0x10F5 : 0x10010f5,
- 0x10F6 : 0x10010f6,
- 0x1E8A : 0x1001e8a,
- 0x012C : 0x100012c,
- 0x01B5 : 0x10001b5,
- 0x01E6 : 0x10001e6,
- 0x01D2 : 0x10001d1,
- 0x019F : 0x100019f,
- 0x1E8B : 0x1001e8b,
- 0x012D : 0x100012d,
- 0x01B6 : 0x10001b6,
- 0x01E7 : 0x10001e7,
- //0x01D2 : 0x10001d2,
- 0x0275 : 0x1000275,
- 0x018F : 0x100018f,
- 0x0259 : 0x1000259,
- 0x1E36 : 0x1001e36,
- 0x1E37 : 0x1001e37,
- 0x1EA0 : 0x1001ea0,
- 0x1EA1 : 0x1001ea1,
- 0x1EA2 : 0x1001ea2,
- 0x1EA3 : 0x1001ea3,
- 0x1EA4 : 0x1001ea4,
- 0x1EA5 : 0x1001ea5,
- 0x1EA6 : 0x1001ea6,
- 0x1EA7 : 0x1001ea7,
- 0x1EA8 : 0x1001ea8,
- 0x1EA9 : 0x1001ea9,
- 0x1EAA : 0x1001eaa,
- 0x1EAB : 0x1001eab,
- 0x1EAC : 0x1001eac,
- 0x1EAD : 0x1001ead,
- 0x1EAE : 0x1001eae,
- 0x1EAF : 0x1001eaf,
- 0x1EB0 : 0x1001eb0,
- 0x1EB1 : 0x1001eb1,
- 0x1EB2 : 0x1001eb2,
- 0x1EB3 : 0x1001eb3,
- 0x1EB4 : 0x1001eb4,
- 0x1EB5 : 0x1001eb5,
- 0x1EB6 : 0x1001eb6,
- 0x1EB7 : 0x1001eb7,
- 0x1EB8 : 0x1001eb8,
- 0x1EB9 : 0x1001eb9,
- 0x1EBA : 0x1001eba,
- 0x1EBB : 0x1001ebb,
- 0x1EBC : 0x1001ebc,
- 0x1EBD : 0x1001ebd,
- 0x1EBE : 0x1001ebe,
- 0x1EBF : 0x1001ebf,
- 0x1EC0 : 0x1001ec0,
- 0x1EC1 : 0x1001ec1,
- 0x1EC2 : 0x1001ec2,
- 0x1EC3 : 0x1001ec3,
- 0x1EC4 : 0x1001ec4,
- 0x1EC5 : 0x1001ec5,
- 0x1EC6 : 0x1001ec6,
- 0x1EC7 : 0x1001ec7,
- 0x1EC8 : 0x1001ec8,
- 0x1EC9 : 0x1001ec9,
- 0x1ECA : 0x1001eca,
- 0x1ECB : 0x1001ecb,
- 0x1ECC : 0x1001ecc,
- 0x1ECD : 0x1001ecd,
- 0x1ECE : 0x1001ece,
- 0x1ECF : 0x1001ecf,
- 0x1ED0 : 0x1001ed0,
- 0x1ED1 : 0x1001ed1,
- 0x1ED2 : 0x1001ed2,
- 0x1ED3 : 0x1001ed3,
- 0x1ED4 : 0x1001ed4,
- 0x1ED5 : 0x1001ed5,
- 0x1ED6 : 0x1001ed6,
- 0x1ED7 : 0x1001ed7,
- 0x1ED8 : 0x1001ed8,
- 0x1ED9 : 0x1001ed9,
- 0x1EDA : 0x1001eda,
- 0x1EDB : 0x1001edb,
- 0x1EDC : 0x1001edc,
- 0x1EDD : 0x1001edd,
- 0x1EDE : 0x1001ede,
- 0x1EDF : 0x1001edf,
- 0x1EE0 : 0x1001ee0,
- 0x1EE1 : 0x1001ee1,
- 0x1EE2 : 0x1001ee2,
- 0x1EE3 : 0x1001ee3,
- 0x1EE4 : 0x1001ee4,
- 0x1EE5 : 0x1001ee5,
- 0x1EE6 : 0x1001ee6,
- 0x1EE7 : 0x1001ee7,
- 0x1EE8 : 0x1001ee8,
- 0x1EE9 : 0x1001ee9,
- 0x1EEA : 0x1001eea,
- 0x1EEB : 0x1001eeb,
- 0x1EEC : 0x1001eec,
- 0x1EED : 0x1001eed,
- 0x1EEE : 0x1001eee,
- 0x1EEF : 0x1001eef,
- 0x1EF0 : 0x1001ef0,
- 0x1EF1 : 0x1001ef1,
- 0x1EF4 : 0x1001ef4,
- 0x1EF5 : 0x1001ef5,
- 0x1EF6 : 0x1001ef6,
- 0x1EF7 : 0x1001ef7,
- 0x1EF8 : 0x1001ef8,
- 0x1EF9 : 0x1001ef9,
- 0x01A0 : 0x10001a0,
- 0x01A1 : 0x10001a1,
- 0x01AF : 0x10001af,
- 0x01B0 : 0x10001b0,
- 0x20A0 : 0x10020a0,
- 0x20A1 : 0x10020a1,
- 0x20A2 : 0x10020a2,
- 0x20A3 : 0x10020a3,
- 0x20A4 : 0x10020a4,
- 0x20A5 : 0x10020a5,
- 0x20A6 : 0x10020a6,
- 0x20A7 : 0x10020a7,
- 0x20A8 : 0x10020a8,
- 0x20A9 : 0x10020a9,
- 0x20AA : 0x10020aa,
- 0x20AB : 0x10020ab,
- 0x20AC : 0x20ac,
- 0x2070 : 0x1002070,
- 0x2074 : 0x1002074,
- 0x2075 : 0x1002075,
- 0x2076 : 0x1002076,
- 0x2077 : 0x1002077,
- 0x2078 : 0x1002078,
- 0x2079 : 0x1002079,
- 0x2080 : 0x1002080,
- 0x2081 : 0x1002081,
- 0x2082 : 0x1002082,
- 0x2083 : 0x1002083,
- 0x2084 : 0x1002084,
- 0x2085 : 0x1002085,
- 0x2086 : 0x1002086,
- 0x2087 : 0x1002087,
- 0x2088 : 0x1002088,
- 0x2089 : 0x1002089,
- 0x2202 : 0x1002202,
- 0x2205 : 0x1002205,
- 0x2208 : 0x1002208,
- 0x2209 : 0x1002209,
- 0x220B : 0x100220B,
- 0x221A : 0x100221A,
- 0x221B : 0x100221B,
- 0x221C : 0x100221C,
- 0x222C : 0x100222C,
- 0x222D : 0x100222D,
- 0x2235 : 0x1002235,
- 0x2245 : 0x1002248,
- 0x2247 : 0x1002247,
- 0x2262 : 0x1002262,
- 0x2263 : 0x1002263,
- 0x2800 : 0x1002800,
- 0x2801 : 0x1002801,
- 0x2802 : 0x1002802,
- 0x2803 : 0x1002803,
- 0x2804 : 0x1002804,
- 0x2805 : 0x1002805,
- 0x2806 : 0x1002806,
- 0x2807 : 0x1002807,
- 0x2808 : 0x1002808,
- 0x2809 : 0x1002809,
- 0x280a : 0x100280a,
- 0x280b : 0x100280b,
- 0x280c : 0x100280c,
- 0x280d : 0x100280d,
- 0x280e : 0x100280e,
- 0x280f : 0x100280f,
- 0x2810 : 0x1002810,
- 0x2811 : 0x1002811,
- 0x2812 : 0x1002812,
- 0x2813 : 0x1002813,
- 0x2814 : 0x1002814,
- 0x2815 : 0x1002815,
- 0x2816 : 0x1002816,
- 0x2817 : 0x1002817,
- 0x2818 : 0x1002818,
- 0x2819 : 0x1002819,
- 0x281a : 0x100281a,
- 0x281b : 0x100281b,
- 0x281c : 0x100281c,
- 0x281d : 0x100281d,
- 0x281e : 0x100281e,
- 0x281f : 0x100281f,
- 0x2820 : 0x1002820,
- 0x2821 : 0x1002821,
- 0x2822 : 0x1002822,
- 0x2823 : 0x1002823,
- 0x2824 : 0x1002824,
- 0x2825 : 0x1002825,
- 0x2826 : 0x1002826,
- 0x2827 : 0x1002827,
- 0x2828 : 0x1002828,
- 0x2829 : 0x1002829,
- 0x282a : 0x100282a,
- 0x282b : 0x100282b,
- 0x282c : 0x100282c,
- 0x282d : 0x100282d,
- 0x282e : 0x100282e,
- 0x282f : 0x100282f,
- 0x2830 : 0x1002830,
- 0x2831 : 0x1002831,
- 0x2832 : 0x1002832,
- 0x2833 : 0x1002833,
- 0x2834 : 0x1002834,
- 0x2835 : 0x1002835,
- 0x2836 : 0x1002836,
- 0x2837 : 0x1002837,
- 0x2838 : 0x1002838,
- 0x2839 : 0x1002839,
- 0x283a : 0x100283a,
- 0x283b : 0x100283b,
- 0x283c : 0x100283c,
- 0x283d : 0x100283d,
- 0x283e : 0x100283e,
- 0x283f : 0x100283f,
- 0x2840 : 0x1002840,
- 0x2841 : 0x1002841,
- 0x2842 : 0x1002842,
- 0x2843 : 0x1002843,
- 0x2844 : 0x1002844,
- 0x2845 : 0x1002845,
- 0x2846 : 0x1002846,
- 0x2847 : 0x1002847,
- 0x2848 : 0x1002848,
- 0x2849 : 0x1002849,
- 0x284a : 0x100284a,
- 0x284b : 0x100284b,
- 0x284c : 0x100284c,
- 0x284d : 0x100284d,
- 0x284e : 0x100284e,
- 0x284f : 0x100284f,
- 0x2850 : 0x1002850,
- 0x2851 : 0x1002851,
- 0x2852 : 0x1002852,
- 0x2853 : 0x1002853,
- 0x2854 : 0x1002854,
- 0x2855 : 0x1002855,
- 0x2856 : 0x1002856,
- 0x2857 : 0x1002857,
- 0x2858 : 0x1002858,
- 0x2859 : 0x1002859,
- 0x285a : 0x100285a,
- 0x285b : 0x100285b,
- 0x285c : 0x100285c,
- 0x285d : 0x100285d,
- 0x285e : 0x100285e,
- 0x285f : 0x100285f,
- 0x2860 : 0x1002860,
- 0x2861 : 0x1002861,
- 0x2862 : 0x1002862,
- 0x2863 : 0x1002863,
- 0x2864 : 0x1002864,
- 0x2865 : 0x1002865,
- 0x2866 : 0x1002866,
- 0x2867 : 0x1002867,
- 0x2868 : 0x1002868,
- 0x2869 : 0x1002869,
- 0x286a : 0x100286a,
- 0x286b : 0x100286b,
- 0x286c : 0x100286c,
- 0x286d : 0x100286d,
- 0x286e : 0x100286e,
- 0x286f : 0x100286f,
- 0x2870 : 0x1002870,
- 0x2871 : 0x1002871,
- 0x2872 : 0x1002872,
- 0x2873 : 0x1002873,
- 0x2874 : 0x1002874,
- 0x2875 : 0x1002875,
- 0x2876 : 0x1002876,
- 0x2877 : 0x1002877,
- 0x2878 : 0x1002878,
- 0x2879 : 0x1002879,
- 0x287a : 0x100287a,
- 0x287b : 0x100287b,
- 0x287c : 0x100287c,
- 0x287d : 0x100287d,
- 0x287e : 0x100287e,
- 0x287f : 0x100287f,
- 0x2880 : 0x1002880,
- 0x2881 : 0x1002881,
- 0x2882 : 0x1002882,
- 0x2883 : 0x1002883,
- 0x2884 : 0x1002884,
- 0x2885 : 0x1002885,
- 0x2886 : 0x1002886,
- 0x2887 : 0x1002887,
- 0x2888 : 0x1002888,
- 0x2889 : 0x1002889,
- 0x288a : 0x100288a,
- 0x288b : 0x100288b,
- 0x288c : 0x100288c,
- 0x288d : 0x100288d,
- 0x288e : 0x100288e,
- 0x288f : 0x100288f,
- 0x2890 : 0x1002890,
- 0x2891 : 0x1002891,
- 0x2892 : 0x1002892,
- 0x2893 : 0x1002893,
- 0x2894 : 0x1002894,
- 0x2895 : 0x1002895,
- 0x2896 : 0x1002896,
- 0x2897 : 0x1002897,
- 0x2898 : 0x1002898,
- 0x2899 : 0x1002899,
- 0x289a : 0x100289a,
- 0x289b : 0x100289b,
- 0x289c : 0x100289c,
- 0x289d : 0x100289d,
- 0x289e : 0x100289e,
- 0x289f : 0x100289f,
- 0x28a0 : 0x10028a0,
- 0x28a1 : 0x10028a1,
- 0x28a2 : 0x10028a2,
- 0x28a3 : 0x10028a3,
- 0x28a4 : 0x10028a4,
- 0x28a5 : 0x10028a5,
- 0x28a6 : 0x10028a6,
- 0x28a7 : 0x10028a7,
- 0x28a8 : 0x10028a8,
- 0x28a9 : 0x10028a9,
- 0x28aa : 0x10028aa,
- 0x28ab : 0x10028ab,
- 0x28ac : 0x10028ac,
- 0x28ad : 0x10028ad,
- 0x28ae : 0x10028ae,
- 0x28af : 0x10028af,
- 0x28b0 : 0x10028b0,
- 0x28b1 : 0x10028b1,
- 0x28b2 : 0x10028b2,
- 0x28b3 : 0x10028b3,
- 0x28b4 : 0x10028b4,
- 0x28b5 : 0x10028b5,
- 0x28b6 : 0x10028b6,
- 0x28b7 : 0x10028b7,
- 0x28b8 : 0x10028b8,
- 0x28b9 : 0x10028b9,
- 0x28ba : 0x10028ba,
- 0x28bb : 0x10028bb,
- 0x28bc : 0x10028bc,
- 0x28bd : 0x10028bd,
- 0x28be : 0x10028be,
- 0x28bf : 0x10028bf,
- 0x28c0 : 0x10028c0,
- 0x28c1 : 0x10028c1,
- 0x28c2 : 0x10028c2,
- 0x28c3 : 0x10028c3,
- 0x28c4 : 0x10028c4,
- 0x28c5 : 0x10028c5,
- 0x28c6 : 0x10028c6,
- 0x28c7 : 0x10028c7,
- 0x28c8 : 0x10028c8,
- 0x28c9 : 0x10028c9,
- 0x28ca : 0x10028ca,
- 0x28cb : 0x10028cb,
- 0x28cc : 0x10028cc,
- 0x28cd : 0x10028cd,
- 0x28ce : 0x10028ce,
- 0x28cf : 0x10028cf,
- 0x28d0 : 0x10028d0,
- 0x28d1 : 0x10028d1,
- 0x28d2 : 0x10028d2,
- 0x28d3 : 0x10028d3,
- 0x28d4 : 0x10028d4,
- 0x28d5 : 0x10028d5,
- 0x28d6 : 0x10028d6,
- 0x28d7 : 0x10028d7,
- 0x28d8 : 0x10028d8,
- 0x28d9 : 0x10028d9,
- 0x28da : 0x10028da,
- 0x28db : 0x10028db,
- 0x28dc : 0x10028dc,
- 0x28dd : 0x10028dd,
- 0x28de : 0x10028de,
- 0x28df : 0x10028df,
- 0x28e0 : 0x10028e0,
- 0x28e1 : 0x10028e1,
- 0x28e2 : 0x10028e2,
- 0x28e3 : 0x10028e3,
- 0x28e4 : 0x10028e4,
- 0x28e5 : 0x10028e5,
- 0x28e6 : 0x10028e6,
- 0x28e7 : 0x10028e7,
- 0x28e8 : 0x10028e8,
- 0x28e9 : 0x10028e9,
- 0x28ea : 0x10028ea,
- 0x28eb : 0x10028eb,
- 0x28ec : 0x10028ec,
- 0x28ed : 0x10028ed,
- 0x28ee : 0x10028ee,
- 0x28ef : 0x10028ef,
- 0x28f0 : 0x10028f0,
- 0x28f1 : 0x10028f1,
- 0x28f2 : 0x10028f2,
- 0x28f3 : 0x10028f3,
- 0x28f4 : 0x10028f4,
- 0x28f5 : 0x10028f5,
- 0x28f6 : 0x10028f6,
- 0x28f7 : 0x10028f7,
- 0x28f8 : 0x10028f8,
- 0x28f9 : 0x10028f9,
- 0x28fa : 0x10028fa,
- 0x28fb : 0x10028fb,
- 0x28fc : 0x10028fc,
- 0x28fd : 0x10028fd,
- 0x28fe : 0x10028fe,
- 0x28ff : 0x10028ff
-};
diff --git a/ui/novnc/js/jsunzip.js b/ui/novnc/js/jsunzip.js
deleted file mode 100755
index 7edcca7..0000000
--- a/ui/novnc/js/jsunzip.js
+++ /dev/null
@@ -1,676 +0,0 @@
-/*
- * JSUnzip
- *
- * Copyright (c) 2011 by Erik Moller
- * All Rights Reserved
- *
- * This software is provided 'as-is', without any express
- * or implied warranty. In no event will the authors be
- * held liable for any damages arising from the use of
- * this software.
- *
- * Permission is granted to anyone to use this software
- * for any purpose, including commercial applications,
- * and to alter it and redistribute it freely, subject to
- * the following restrictions:
- *
- * 1. The origin of this software must not be
- * misrepresented; you must not claim that you
- * wrote the original software. If you use this
- * software in a product, an acknowledgment in
- * the product documentation would be appreciated
- * but is not required.
- *
- * 2. Altered source versions must be plainly marked
- * as such, and must not be misrepresented as
- * being the original software.
- *
- * 3. This notice may not be removed or altered from
- * any source distribution.
- */
-
-var tinf;
-
-function JSUnzip() {
-
- this.getInt = function(offset, size) {
- switch (size) {
- case 4:
- return (this.data.charCodeAt(offset + 3) & 0xff) << 24 |
- (this.data.charCodeAt(offset + 2) & 0xff) << 16 |
- (this.data.charCodeAt(offset + 1) & 0xff) << 8 |
- (this.data.charCodeAt(offset + 0) & 0xff);
- break;
- case 2:
- return (this.data.charCodeAt(offset + 1) & 0xff) << 8 |
- (this.data.charCodeAt(offset + 0) & 0xff);
- break;
- default:
- return this.data.charCodeAt(offset) & 0xff;
- break;
- }
- };
-
- this.getDOSDate = function(dosdate, dostime) {
- var day = dosdate & 0x1f;
- var month = ((dosdate >> 5) & 0xf) - 1;
- var year = 1980 + ((dosdate >> 9) & 0x7f)
- var second = (dostime & 0x1f) * 2;
- var minute = (dostime >> 5) & 0x3f;
- hour = (dostime >> 11) & 0x1f;
- return new Date(year, month, day, hour, minute, second);
- }
-
- this.open = function(data) {
- this.data = data;
- this.files = [];
-
- if (this.data.length < 22)
- return { 'status' : false, 'error' : 'Invalid data' };
- var endOfCentralDirectory = this.data.length - 22;
- while (endOfCentralDirectory >= 0 && this.getInt(endOfCentralDirectory, 4) != 0x06054b50)
- --endOfCentralDirectory;
- if (endOfCentralDirectory < 0)
- return { 'status' : false, 'error' : 'Invalid data' };
- if (this.getInt(endOfCentralDirectory + 4, 2) != 0 || this.getInt(endOfCentralDirectory + 6, 2) != 0)
- return { 'status' : false, 'error' : 'No multidisk support' };
-
- var entriesInThisDisk = this.getInt(endOfCentralDirectory + 8, 2);
- var centralDirectoryOffset = this.getInt(endOfCentralDirectory + 16, 4);
- var globalCommentLength = this.getInt(endOfCentralDirectory + 20, 2);
- this.comment = this.data.slice(endOfCentralDirectory + 22, endOfCentralDirectory + 22 + globalCommentLength);
-
- var fileOffset = centralDirectoryOffset;
-
- for (var i = 0; i < entriesInThisDisk; ++i) {
- if (this.getInt(fileOffset + 0, 4) != 0x02014b50)
- return { 'status' : false, 'error' : 'Invalid data' };
- if (this.getInt(fileOffset + 6, 2) > 20)
- return { 'status' : false, 'error' : 'Unsupported version' };
- if (this.getInt(fileOffset + 8, 2) & 1)
- return { 'status' : false, 'error' : 'Encryption not implemented' };
-
- var compressionMethod = this.getInt(fileOffset + 10, 2);
- if (compressionMethod != 0 && compressionMethod != 8)
- return { 'status' : false, 'error' : 'Unsupported compression method' };
-
- var lastModFileTime = this.getInt(fileOffset + 12, 2);
- var lastModFileDate = this.getInt(fileOffset + 14, 2);
- var lastModifiedDate = this.getDOSDate(lastModFileDate, lastModFileTime);
-
- var crc = this.getInt(fileOffset + 16, 4);
- // TODO: crc
-
- var compressedSize = this.getInt(fileOffset + 20, 4);
- var uncompressedSize = this.getInt(fileOffset + 24, 4);
-
- var fileNameLength = this.getInt(fileOffset + 28, 2);
- var extraFieldLength = this.getInt(fileOffset + 30, 2);
- var fileCommentLength = this.getInt(fileOffset + 32, 2);
-
- var relativeOffsetOfLocalHeader = this.getInt(fileOffset + 42, 4);
-
- var fileName = this.data.slice(fileOffset + 46, fileOffset + 46 + fileNameLength);
- var fileComment = this.data.slice(fileOffset + 46 + fileNameLength + extraFieldLength, fileOffset + 46 + fileNameLength + extraFieldLength + fileCommentLength);
-
- if (this.getInt(relativeOffsetOfLocalHeader + 0, 4) != 0x04034b50)
- return { 'status' : false, 'error' : 'Invalid data' };
- var localFileNameLength = this.getInt(relativeOffsetOfLocalHeader + 26, 2);
- var localExtraFieldLength = this.getInt(relativeOffsetOfLocalHeader + 28, 2);
- var localFileContent = relativeOffsetOfLocalHeader + 30 + localFileNameLength + localExtraFieldLength;
-
- this.files[fileName] =
- {
- 'fileComment' : fileComment,
- 'compressionMethod' : compressionMethod,
- 'compressedSize' : compressedSize,
- 'uncompressedSize' : uncompressedSize,
- 'localFileContent' : localFileContent,
- 'lastModifiedDate' : lastModifiedDate
- };
-
- fileOffset += 46 + fileNameLength + extraFieldLength + fileCommentLength;
- }
- return { 'status' : true }
- };
-
-
- this.read = function(fileName) {
- var fileInfo = this.files[fileName];
- if (fileInfo) {
- if (fileInfo.compressionMethod == 8) {
- if (!tinf) {
- tinf = new TINF();
- tinf.init();
- }
- var result = tinf.uncompress(this.data, fileInfo.localFileContent);
- if (result.status == tinf.OK)
- return { 'status' : true, 'data' : result.data };
- else
- return { 'status' : false, 'error' : result.error };
- } else {
- return { 'status' : true, 'data' : this.data.slice(fileInfo.localFileContent, fileInfo.localFileContent + fileInfo.uncompressedSize) };
- }
- }
- return { 'status' : false, 'error' : "File '" + fileName + "' doesn't exist in zip" };
- };
-
-};
-
-
-
-/*
- * tinflate - tiny inflate
- *
- * Copyright (c) 2003 by Joergen Ibsen / Jibz
- * All Rights Reserved
- *
- * http://www.ibsensoftware.com/
- *
- * This software is provided 'as-is', without any express
- * or implied warranty. In no event will the authors be
- * held liable for any damages arising from the use of
- * this software.
- *
- * Permission is granted to anyone to use this software
- * for any purpose, including commercial applications,
- * and to alter it and redistribute it freely, subject to
- * the following restrictions:
- *
- * 1. The origin of this software must not be
- * misrepresented; you must not claim that you
- * wrote the original software. If you use this
- * software in a product, an acknowledgment in
- * the product documentation would be appreciated
- * but is not required.
- *
- * 2. Altered source versions must be plainly marked
- * as such, and must not be misrepresented as
- * being the original software.
- *
- * 3. This notice may not be removed or altered from
- * any source distribution.
- */
-
-/*
- * tinflate javascript port by Erik Moller in May 2011.
- * emoller(a)opera.com
- *
- * read_bits() patched by mike(a)imidio.com to allow
- * reading more then 8 bits (needed in some zlib streams)
- */
-
-"use strict";
-
-function TINF() {
-
-this.OK = 0;
-this.DATA_ERROR = (-3);
-this.WINDOW_SIZE = 32768;
-
-/* ------------------------------ *
- * -- internal data structures -- *
- * ------------------------------ */
-
-this.TREE = function() {
- this.table = new Array(16); /* table of code length counts */
- this.trans = new Array(288); /* code -> symbol translation table */
-};
-
-this.DATA = function(that) {
- this.source = '';
- this.sourceIndex = 0;
- this.tag = 0;
- this.bitcount = 0;
-
- this.dest = [];
-
- this.history = [];
-
- this.ltree = new that.TREE(); /* dynamic length/symbol tree */
- this.dtree = new that.TREE(); /* dynamic distance tree */
-};
-
-/* --------------------------------------------------- *
- * -- uninitialized global data (static structures) -- *
- * --------------------------------------------------- */
-
-this.sltree = new this.TREE(); /* fixed length/symbol tree */
-this.sdtree = new this.TREE(); /* fixed distance tree */
-
-/* extra bits and base tables for length codes */
-this.length_bits = new Array(30);
-this.length_base = new Array(30);
-
-/* extra bits and base tables for distance codes */
-this.dist_bits = new Array(30);
-this.dist_base = new Array(30);
-
-/* special ordering of code length codes */
-this.clcidx = [
- 16, 17, 18, 0, 8, 7, 9, 6,
- 10, 5, 11, 4, 12, 3, 13, 2,
- 14, 1, 15
-];
-
-/* ----------------------- *
- * -- utility functions -- *
- * ----------------------- */
-
-/* build extra bits and base tables */
-this.build_bits_base = function(bits, base, delta, first)
-{
- var i, sum;
-
- /* build bits table */
- for (i = 0; i < delta; ++i) bits[i] = 0;
- for (i = 0; i < 30 - delta; ++i) bits[i + delta] = Math.floor(i / delta);
-
- /* build base table */
- for (sum = first, i = 0; i < 30; ++i)
- {
- base[i] = sum;
- sum += 1 << bits[i];
- }
-}
-
-/* build the fixed huffman trees */
-this.build_fixed_trees = function(lt, dt)
-{
- var i;
-
- /* build fixed length tree */
- for (i = 0; i < 7; ++i) lt.table[i] = 0;
-
- lt.table[7] = 24;
- lt.table[8] = 152;
- lt.table[9] = 112;
-
- for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i;
- for (i = 0; i < 144; ++i) lt.trans[24 + i] = i;
- for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i;
- for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i;
-
- /* build fixed distance tree */
- for (i = 0; i < 5; ++i) dt.table[i] = 0;
-
- dt.table[5] = 32;
-
- for (i = 0; i < 32; ++i) dt.trans[i] = i;
-}
-
-/* given an array of code lengths, build a tree */
-this.build_tree = function(t, lengths, loffset, num)
-{
- var offs = new Array(16);
- var i, sum;
-
- /* clear code length count table */
- for (i = 0; i < 16; ++i) t.table[i] = 0;
-
- /* scan symbol lengths, and sum code length counts */
- for (i = 0; i < num; ++i) t.table[lengths[loffset + i]]++;
-
- t.table[0] = 0;
-
- /* compute offset table for distribution sort */
- for (sum = 0, i = 0; i < 16; ++i)
- {
- offs[i] = sum;
- sum += t.table[i];
- }
-
- /* create code->symbol translation table (symbols sorted by code) */
- for (i = 0; i < num; ++i)
- {
- if (lengths[loffset + i]) t.trans[offs[lengths[loffset + i]]++] = i;
- }
-}
-
-/* ---------------------- *
- * -- decode functions -- *
- * ---------------------- */
-
-/* get one bit from source stream */
-this.getbit = function(d)
-{
- var bit;
-
- /* check if tag is empty */
- if (!d.bitcount--)
- {
- /* load next tag */
- d.tag = d.source[d.sourceIndex++] & 0xff;
- d.bitcount = 7;
- }
-
- /* shift bit out of tag */
- bit = d.tag & 0x01;
- d.tag >>= 1;
-
- return bit;
-}
-
-/* read a num bit value from a stream and add base */
-function read_bits_direct(source, bitcount, tag, idx, num)
-{
- var val = 0;
- while (bitcount < 24) {
- tag = tag | (source[idx++] & 0xff) << bitcount;
- bitcount += 8;
- }
- val = tag & (0xffff >> (16 - num));
- tag >>= num;
- bitcount -= num;
- return [bitcount, tag, idx, val];
-}
-this.read_bits = function(d, num, base)
-{
- if (!num)
- return base;
-
- var ret = read_bits_direct(d.source, d.bitcount, d.tag, d.sourceIndex, num);
- d.bitcount = ret[0];
- d.tag = ret[1];
- d.sourceIndex = ret[2];
- return ret[3] + base;
-}
-
-/* given a data stream and a tree, decode a symbol */
-this.decode_symbol = function(d, t)
-{
- while (d.bitcount < 16) {
- d.tag = d.tag | (d.source[d.sourceIndex++] & 0xff) << d.bitcount;
- d.bitcount += 8;
- }
-
- var sum = 0, cur = 0, len = 0;
- do {
- cur = 2 * cur + ((d.tag & (1 << len)) >> len);
-
- ++len;
-
- sum += t.table[len];
- cur -= t.table[len];
-
- } while (cur >= 0);
-
- d.tag >>= len;
- d.bitcount -= len;
-
- return t.trans[sum + cur];
-}
-
-/* given a data stream, decode dynamic trees from it */
-this.decode_trees = function(d, lt, dt)
-{
- var code_tree = new this.TREE();
- var lengths = new Array(288+32);
- var hlit, hdist, hclen;
- var i, num, length;
-
- /* get 5 bits HLIT (257-286) */
- hlit = this.read_bits(d, 5, 257);
-
- /* get 5 bits HDIST (1-32) */
- hdist = this.read_bits(d, 5, 1);
-
- /* get 4 bits HCLEN (4-19) */
- hclen = this.read_bits(d, 4, 4);
-
- for (i = 0; i < 19; ++i) lengths[i] = 0;
-
- /* read code lengths for code length alphabet */
- for (i = 0; i < hclen; ++i)
- {
- /* get 3 bits code length (0-7) */
- var clen = this.read_bits(d, 3, 0);
-
- lengths[this.clcidx[i]] = clen;
- }
-
- /* build code length tree */
- this.build_tree(code_tree, lengths, 0, 19);
-
- /* decode code lengths for the dynamic trees */
- for (num = 0; num < hlit + hdist; )
- {
- var sym = this.decode_symbol(d, code_tree);
-
- switch (sym)
- {
- case 16:
- /* copy previous code length 3-6 times (read 2 bits) */
- {
- var prev = lengths[num - 1];
- for (length = this.read_bits(d, 2, 3); length; --length)
- {
- lengths[num++] = prev;
- }
- }
- break;
- case 17:
- /* repeat code length 0 for 3-10 times (read 3 bits) */
- for (length = this.read_bits(d, 3, 3); length; --length)
- {
- lengths[num++] = 0;
- }
- break;
- case 18:
- /* repeat code length 0 for 11-138 times (read 7 bits) */
- for (length = this.read_bits(d, 7, 11); length; --length)
- {
- lengths[num++] = 0;
- }
- break;
- default:
- /* values 0-15 represent the actual code lengths */
- lengths[num++] = sym;
- break;
- }
- }
-
- /* build dynamic trees */
- this.build_tree(lt, lengths, 0, hlit);
- this.build_tree(dt, lengths, hlit, hdist);
-}
-
-/* ----------------------------- *
- * -- block inflate functions -- *
- * ----------------------------- */
-
-/* given a stream and two trees, inflate a block of data */
-this.inflate_block_data = function(d, lt, dt)
-{
- // js optimization.
- var ddest = d.dest;
- var ddestlength = ddest.length;
-
- while (1)
- {
- var sym = this.decode_symbol(d, lt);
-
- /* check for end of block */
- if (sym == 256)
- {
- return this.OK;
- }
-
- if (sym < 256)
- {
- ddest[ddestlength++] = sym; // ? String.fromCharCode(sym);
- d.history.push(sym);
- } else {
-
- var length, dist, offs;
- var i;
-
- sym -= 257;
-
- /* possibly get more bits from length code */
- length = this.read_bits(d, this.length_bits[sym], this.length_base[sym]);
-
- dist = this.decode_symbol(d, dt);
-
- /* possibly get more bits from distance code */
- offs = d.history.length - this.read_bits(d, this.dist_bits[dist], this.dist_base[dist]);
-
- if (offs < 0)
- throw ("Invalid zlib offset " + offs);
-
- /* copy match */
- for (i = offs; i < offs + length; ++i) {
- //ddest[ddestlength++] = ddest[i];
- ddest[ddestlength++] = d.history[i];
- d.history.push(d.history[i]);
- }
- }
- }
-}
-
-/* inflate an uncompressed block of data */
-this.inflate_uncompressed_block = function(d)
-{
- var length, invlength;
- var i;
-
- if (d.bitcount > 7) {
- var overflow = Math.floor(d.bitcount / 8);
- d.sourceIndex -= overflow;
- d.bitcount = 0;
- d.tag = 0;
- }
-
- /* get length */
- length = d.source[d.sourceIndex+1];
- length = 256*length + d.source[d.sourceIndex];
-
- /* get one's complement of length */
- invlength = d.source[d.sourceIndex+3];
- invlength = 256*invlength + d.source[d.sourceIndex+2];
-
- /* check length */
- if (length != (~invlength & 0x0000ffff)) return this.DATA_ERROR;
-
- d.sourceIndex += 4;
-
- /* copy block */
- for (i = length; i; --i) {
- d.history.push(d.source[d.sourceIndex]);
- d.dest[d.dest.length] = d.source[d.sourceIndex++];
- }
-
- /* make sure we start next block on a byte boundary */
- d.bitcount = 0;
-
- return this.OK;
-}
-
-/* inflate a block of data compressed with fixed huffman trees */
-this.inflate_fixed_block = function(d)
-{
- /* decode block using fixed trees */
- return this.inflate_block_data(d, this.sltree, this.sdtree);
-}
-
-/* inflate a block of data compressed with dynamic huffman trees */
-this.inflate_dynamic_block = function(d)
-{
- /* decode trees from stream */
- this.decode_trees(d, d.ltree, d.dtree);
-
- /* decode block using decoded trees */
- return this.inflate_block_data(d, d.ltree, d.dtree);
-}
-
-/* ---------------------- *
- * -- public functions -- *
- * ---------------------- */
-
-/* initialize global (static) data */
-this.init = function()
-{
- /* build fixed huffman trees */
- this.build_fixed_trees(this.sltree, this.sdtree);
-
- /* build extra bits and base tables */
- this.build_bits_base(this.length_bits, this.length_base, 4, 3);
- this.build_bits_base(this.dist_bits, this.dist_base, 2, 1);
-
- /* fix a special case */
- this.length_bits[28] = 0;
- this.length_base[28] = 258;
-
- this.reset();
-}
-
-this.reset = function()
-{
- this.d = new this.DATA(this);
- delete this.header;
-}
-
-/* inflate stream from source to dest */
-this.uncompress = function(source, offset)
-{
-
- var d = this.d;
- var bfinal;
-
- /* initialise data */
- d.source = source;
- d.sourceIndex = offset;
- d.bitcount = 0;
-
- d.dest = [];
-
- // Skip zlib header at start of stream
- if (typeof this.header == 'undefined') {
- this.header = this.read_bits(d, 16, 0);
- /* byte 0: 0x78, 7 = 32k window size, 8 = deflate */
- /* byte 1: check bits for header and other flags */
- }
-
- var blocks = 0;
-
- do {
-
- var btype;
- var res;
-
- /* read final block flag */
- bfinal = this.getbit(d);
-
- /* read block type (2 bits) */
- btype = this.read_bits(d, 2, 0);
-
- /* decompress block */
- switch (btype)
- {
- case 0:
- /* decompress uncompressed block */
- res = this.inflate_uncompressed_block(d);
- break;
- case 1:
- /* decompress block with fixed huffman trees */
- res = this.inflate_fixed_block(d);
- break;
- case 2:
- /* decompress block with dynamic huffman trees */
- res = this.inflate_dynamic_block(d);
- break;
- default:
- return { 'status' : this.DATA_ERROR };
- }
-
- if (res != this.OK) return { 'status' : this.DATA_ERROR };
- blocks++;
-
- } while (!bfinal && d.sourceIndex < d.source.length);
-
- d.history = d.history.slice(-this.WINDOW_SIZE);
-
- return { 'status' : this.OK, 'data' : d.dest };
-}
-
-};
diff --git a/ui/novnc/js/main.js b/ui/novnc/js/main.js
deleted file mode 100644
index 22037ec..0000000
--- a/ui/novnc/js/main.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/* noVNC example: simple example using default UI
- * Copyright (C) 2012 Joel Martin
- * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
- * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
- *
- * Connect parameters are provided in query string:
- * http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
- */
-/*jslint white: false */
-/*global window, $, Util, RFB, */
-"use strict";
-
-// Load supporting scripts
-Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
- "input.js", "display.js", "jsunzip.js", "rfb.js"]);
-
-var rfb;
-
-function passwordRequired(rfb) {
-var msg;
-msg = '<form onsubmit="return setPassword();"';
-msg += ' style="margin-bottom: 0px">';
-msg += 'Password Required: ';
-msg += '<input type=password size=10 id="password_input" class="noVNC_status">';
-msg += '<\/form>';
-$D('noVNC_status_bar').setAttribute("class", "noVNC_status_warn");
-$D('noVNC_status').innerHTML = msg;
-}
-function onFBResize(rfb, width, height){
-window.resizeTo(width, height + 90)
-}
-function setPassword() {
-rfb.sendPassword($D('password_input').value);
-return false;
-}
-function sendCtrlAltDel() {
-rfb.sendCtrlAltDel();
-return false;
-}
-function updateState(rfb, state, oldstate, msg) {
-var s, sb, cad, level;
-s = $D('noVNC_status');
-sb = $D('noVNC_status_bar');
-cad = $D('sendCtrlAltDelButton');
-switch (state) {
- case 'failed': level = "error"; break;
- case 'fatal': level = "error"; break;
- case 'normal': level = "normal"; break;
- case 'disconnected': level = "normal"; break;
- case 'loaded': level = "normal"; break;
- default: level = "warn"; break;
-}
-
-if (state === "normal") { cad.disabled = false; }
-else { cad.disabled = true; }
-
-if (typeof(msg) !== 'undefined') {
- sb.setAttribute("class", "noVNC_status_" + level);
- s.innerHTML = msg;
-}
-}
-
-window.onscriptsload = function () {
-var host, port, password, path, token;
-
-$D('sendCtrlAltDelButton').style.display = "inline";
-$D('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
-
-WebUtil.init_logging(WebUtil.getQueryVar('logging', 'warn'));
-document.title = unescape(WebUtil.getQueryVar('title', 'noVNC'));
-// By default, use the host and port of server that served this file
-host = WebUtil.getQueryVar('host', window.location.hostname);
-port = WebUtil.getQueryVar('port', window.location.port);
-
-// If a token variable is passed in, set the parameter in a cookie.
-// This is used by nova-novncproxy.
-token = WebUtil.getQueryVar('token', null);
-if (token) {
- WebUtil.createCookie('token', token, 1)
-}
-
-password = WebUtil.getQueryVar('password', '');
-path = WebUtil.getQueryVar('path', 'websockify');
-
-if ((!host) || (!port)) {
- updateState('failed',
- "Must specify host and port in URL");
- return;
-}
-
-rfb = new RFB({'target': $D('noVNC_canvas'),
- 'encrypt': WebUtil.getQueryVar('encrypt',
- (window.location.protocol === "https:")),
- 'repeaterID': WebUtil.getQueryVar('repeaterID', ''),
- 'true_color': WebUtil.getQueryVar('true_color', true),
- 'local_cursor': WebUtil.getQueryVar('cursor', true),
- 'shared': WebUtil.getQueryVar('shared', true),
- 'view_only': WebUtil.getQueryVar('view_only', false),
- 'updateState': updateState,
- 'onFBResize': onFBResize,
- 'onPasswordRequired': passwordRequired});
-rfb.connect(host, port, password, path);
-};
diff --git a/ui/novnc/js/rfb.js b/ui/novnc/js/rfb.js
deleted file mode 100644
index 4535105..0000000
--- a/ui/novnc/js/rfb.js
+++ /dev/null
@@ -1,1866 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- *
- * TIGHT decoder portion:
- * (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
- */
-
-/*jslint white: false, browser: true, bitwise: false, plusplus: false */
-/*global window, Util, Display, Keyboard, Mouse, Websock, Websock_native, Base64, DES */
-
-
-function RFB(defaults) {
-"use strict";
-
-var that = {}, // Public API methods
- conf = {}, // Configuration attributes
-
- // Pre-declare private functions used before definitions (jslint)
- init_vars, updateState, fail, handle_message,
- init_msg, normal_msg, framebufferUpdate, print_stats,
-
- pixelFormat, clientEncodings, fbUpdateRequest, fbUpdateRequests,
- keyEvent, pointerEvent, clientCutText,
-
- getTightCLength, extract_data_uri,
- keyPress, mouseButton, mouseMove,
-
- checkEvents, // Overridable for testing
-
-
- //
- // Private RFB namespace variables
- //
- rfb_host = '',
- rfb_port = 5900,
- rfb_password = '',
- rfb_path = '',
-
- rfb_state = 'disconnected',
- rfb_version = 0,
- rfb_max_version= 3.8,
- rfb_auth_scheme= '',
-
-
- // In preference order
- encodings = [
- ['COPYRECT', 0x01 ],
- ['TIGHT', 0x07 ],
- ['TIGHT_PNG', -260 ],
- ['HEXTILE', 0x05 ],
- ['RRE', 0x02 ],
- ['RAW', 0x00 ],
- ['DesktopSize', -223 ],
- ['Cursor', -239 ],
-
- // Psuedo-encoding settings
- //['JPEG_quality_lo', -32 ],
- ['JPEG_quality_med', -26 ],
- //['JPEG_quality_hi', -23 ],
- //['compress_lo', -255 ],
- ['compress_hi', -247 ],
- ['last_rect', -224 ]
- ],
-
- encHandlers = {},
- encNames = {},
- encStats = {}, // [rectCnt, rectCntTot]
-
- ws = null, // Websock object
- display = null, // Display object
- keyboard = null, // Keyboard input handler object
- mouse = null, // Mouse input handler object
- sendTimer = null, // Send Queue check timer
- connTimer = null, // connection timer
- disconnTimer = null, // disconnection timer
- msgTimer = null, // queued handle_message timer
-
- // Frame buffer update state
- FBU = {
- rects : 0,
- subrects : 0, // RRE
- lines : 0, // RAW
- tiles : 0, // HEXTILE
- bytes : 0,
- x : 0,
- y : 0,
- width : 0,
- height : 0,
- encoding : 0,
- subencoding : -1,
- background : null,
- zlibs : [] // TIGHT zlib streams
- },
-
- fb_Bpp = 4,
- fb_depth = 3,
- fb_width = 0,
- fb_height = 0,
- fb_name = "",
-
- last_req_time = 0,
- rre_chunk_sz = 100,
-
- timing = {
- last_fbu : 0,
- fbu_total : 0,
- fbu_total_cnt : 0,
- full_fbu_total : 0,
- full_fbu_cnt : 0,
-
- fbu_rt_start : 0,
- fbu_rt_total : 0,
- fbu_rt_cnt : 0,
- pixels : 0
- },
-
- test_mode = false,
-
- def_con_timeout = Websock_native ? 2 : 5,
-
- /* Mouse state */
- mouse_buttonMask = 0,
- mouse_arr = [],
- viewportDragging = false,
- viewportDragPos = {};
-
-// Configuration attributes
-Util.conf_defaults(conf, that, defaults, [
- ['target', 'wo', 'dom', null, 'VNC display rendering Canvas object'],
- ['focusContainer', 'wo', 'dom', document, 'DOM element that captures keyboard input'],
-
- ['encrypt', 'rw', 'bool', false, 'Use TLS/SSL/wss encryption'],
- ['true_color', 'rw', 'bool', true, 'Request true color pixel data'],
- ['local_cursor', 'rw', 'bool', false, 'Request locally rendered cursor'],
- ['shared', 'rw', 'bool', true, 'Request shared mode'],
- ['view_only', 'rw', 'bool', false, 'Disable client mouse/keyboard'],
-
- ['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'],
- ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'],
-
- // UltraVNC repeater ID to connect to
- ['repeaterID', 'rw', 'str', '', 'RepeaterID to connect to'],
-
- ['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'],
-
- ['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'],
- ['fbu_req_rate', 'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'],
-
- // Callback functions
- ['onUpdateState', 'rw', 'func', function() { },
- 'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '],
- ['onPasswordRequired', 'rw', 'func', function() { },
- 'onPasswordRequired(rfb): VNC password is required '],
- ['onClipboard', 'rw', 'func', function() { },
- 'onClipboard(rfb, text): RFB clipboard contents received'],
- ['onBell', 'rw', 'func', function() { },
- 'onBell(rfb): RFB Bell message received '],
- ['onFBUReceive', 'rw', 'func', function() { },
- 'onFBUReceive(rfb, fbu): RFB FBU received but not yet processed '],
- ['onFBUComplete', 'rw', 'func', function() { },
- 'onFBUComplete(rfb, fbu): RFB FBU received and processed '],
- ['onFBResize', 'rw', 'func', function() { },
- 'onFBResize(rfb, width, height): frame buffer resized'],
-
- // These callback names are deprecated
- ['updateState', 'rw', 'func', function() { },
- 'obsolete, use onUpdateState'],
- ['clipboardReceive', 'rw', 'func', function() { },
- 'obsolete, use onClipboard']
- ]);
-
-
-// Override/add some specific configuration getters/setters
-that.set_local_cursor = function(cursor) {
- if ((!cursor) || (cursor in {'0':1, 'no':1, 'false':1})) {
- conf.local_cursor = false;
- } else {
- if (display.get_cursor_uri()) {
- conf.local_cursor = true;
- } else {
- Util.Warn("Browser does not support local cursor");
- }
- }
-};
-
-// These are fake configuration getters
-that.get_display = function() { return display; };
-
-that.get_keyboard = function() { return keyboard; };
-
-that.get_mouse = function() { return mouse; };
-
-
-
-//
-// Setup routines
-//
-
-// Create the public API interface and initialize values that stay
-// constant across connect/disconnect
-function constructor() {
- var i, rmode;
- Util.Debug(">> RFB.constructor");
-
- // Create lookup tables based encoding number
- for (i=0; i < encodings.length; i+=1) {
- encHandlers[encodings[i][1]] = encHandlers[encodings[i][0]];
- encNames[encodings[i][1]] = encodings[i][0];
- encStats[encodings[i][1]] = [0, 0];
- }
- // Initialize display, mouse, keyboard, and websock
- try {
- display = new Display({'target': conf.target});
- } catch (exc) {
- Util.Error("Display exception: " + exc);
- updateState('fatal', "No working Display");
- }
- keyboard = new Keyboard({'target': conf.focusContainer,
- 'onKeyPress': keyPress});
- mouse = new Mouse({'target': conf.target,
- 'onMouseButton': mouseButton,
- 'onMouseMove': mouseMove});
-
- rmode = display.get_render_mode();
-
- ws = new Websock();
- ws.on('message', handle_message);
- ws.on('open', function() {
- if (rfb_state === "connect") {
- updateState('ProtocolVersion', "Starting VNC handshake");
- } else {
- fail("Got unexpected WebSockets connection");
- }
- });
- ws.on('close', function(e) {
- Util.Warn("WebSocket on-close event");
- var msg = "";
- if (e.code) {
- msg = " (code: " + e.code;
- if (e.reason) {
- msg += ", reason: " + e.reason;
- }
- msg += ")";
- }
- if (rfb_state === 'disconnect') {
- updateState('disconnected', 'VNC disconnected' + msg);
- } else if (rfb_state === 'ProtocolVersion') {
- fail('Failed to connect to server' + msg);
- } else if (rfb_state in {'failed':1, 'disconnected':1}) {
- Util.Error("Received onclose while disconnected" + msg);
- } else {
- fail('Server disconnected' + msg);
- }
- });
- ws.on('error', function(e) {
- Util.Warn("WebSocket on-error event");
- //fail("WebSock reported an error");
- });
-
-
- init_vars();
-
- /* Check web-socket-js if no builtin WebSocket support */
- if (Websock_native) {
- Util.Info("Using native WebSockets");
- updateState('loaded', 'noVNC ready: native WebSockets, ' + rmode);
- } else {
- Util.Warn("Using web-socket-js bridge. Flash version: " +
- Util.Flash.version);
- if ((! Util.Flash) ||
- (Util.Flash.version < 9)) {
- updateState('fatal', "WebSockets or <a href='http://get.adobe.com/flashplayer'>Adobe Flash<\/a> is required");
- } else if (document.location.href.substr(0, 7) === "file://") {
- updateState('fatal',
- "'file://' URL is incompatible with Adobe Flash");
- } else {
- updateState('loaded', 'noVNC ready: WebSockets emulation, ' + rmode);
- }
- }
-
- Util.Debug("<< RFB.constructor");
- return that; // Return the public API interface
-}
-
-function connect() {
- Util.Debug(">> RFB.connect");
- var uri;
-
- if (typeof UsingSocketIO !== "undefined") {
- uri = "http://" + rfb_host + ":" + rfb_port + "/" + rfb_path;
- } else {
- if (conf.encrypt) {
- uri = "wss://";
- } else {
- uri = "ws://";
- }
- uri += rfb_host + ":" + rfb_port + "/" + rfb_path;
- }
- Util.Info("connecting to " + uri);
- // TODO: make protocols a configurable
- ws.open(uri, ['binary', 'base64']);
-
- Util.Debug("<< RFB.connect");
-}
-
-// Initialize variables that are reset before each connection
-init_vars = function() {
- var i;
-
- /* Reset state */
- ws.init();
-
- FBU.rects = 0;
- FBU.subrects = 0; // RRE and HEXTILE
- FBU.lines = 0; // RAW
- FBU.tiles = 0; // HEXTILE
- FBU.zlibs = []; // TIGHT zlib encoders
- mouse_buttonMask = 0;
- mouse_arr = [];
-
- // Clear the per connection encoding stats
- for (i=0; i < encodings.length; i+=1) {
- encStats[encodings[i][1]][0] = 0;
- }
-
- for (i=0; i < 4; i++) {
- //FBU.zlibs[i] = new InflateStream();
- FBU.zlibs[i] = new TINF();
- FBU.zlibs[i].init();
- }
-};
-
-// Print statistics
-print_stats = function() {
- var i, s;
- Util.Info("Encoding stats for this connection:");
- for (i=0; i < encodings.length; i+=1) {
- s = encStats[encodings[i][1]];
- if ((s[0] + s[1]) > 0) {
- Util.Info(" " + encodings[i][0] + ": " +
- s[0] + " rects");
- }
- }
- Util.Info("Encoding stats since page load:");
- for (i=0; i < encodings.length; i+=1) {
- s = encStats[encodings[i][1]];
- if ((s[0] + s[1]) > 0) {
- Util.Info(" " + encodings[i][0] + ": " +
- s[1] + " rects");
- }
- }
-};
-
-//
-// Utility routines
-//
-
-
-/*
- * Page states:
- * loaded - page load, equivalent to disconnected
- * disconnected - idle state
- * connect - starting to connect (to ProtocolVersion)
- * normal - connected
- * disconnect - starting to disconnect
- * failed - abnormal disconnect
- * fatal - failed to load page, or fatal error
- *
- * RFB protocol initialization states:
- * ProtocolVersion
- * Security
- * Authentication
- * password - waiting for password, not part of RFB
- * SecurityResult
- * ClientInitialization - not triggered by server message
- * ServerInitialization (to normal)
- */
-updateState = function(state, statusMsg) {
- var func, cmsg, oldstate = rfb_state;
-
- if (state === oldstate) {
- /* Already here, ignore */
- Util.Debug("Already in state '" + state + "', ignoring.");
- return;
- }
-
- /*
- * These are disconnected states. A previous connect may
- * asynchronously cause a connection so make sure we are closed.
- */
- if (state in {'disconnected':1, 'loaded':1, 'connect':1,
- 'disconnect':1, 'failed':1, 'fatal':1}) {
- if (sendTimer) {
- clearInterval(sendTimer);
- sendTimer = null;
- }
-
- if (msgTimer) {
- clearInterval(msgTimer);
- msgTimer = null;
- }
-
- if (display && display.get_context()) {
- keyboard.ungrab();
- mouse.ungrab();
- display.defaultCursor();
- if ((Util.get_logging() !== 'debug') ||
- (state === 'loaded')) {
- // Show noVNC logo on load and when disconnected if
- // debug is off
- display.clear();
- }
- }
-
- ws.close();
- }
-
- if (oldstate === 'fatal') {
- Util.Error("Fatal error, cannot continue");
- }
-
- if ((state === 'failed') || (state === 'fatal')) {
- func = Util.Error;
- } else {
- func = Util.Warn;
- }
-
- cmsg = typeof(statusMsg) !== 'undefined' ? (" Msg: " + statusMsg) : "";
- func("New state '" + state + "', was '" + oldstate + "'." + cmsg);
-
- if ((oldstate === 'failed') && (state === 'disconnected')) {
- // Do disconnect action, but stay in failed state
- rfb_state = 'failed';
- } else {
- rfb_state = state;
- }
-
- if (connTimer && (rfb_state !== 'connect')) {
- Util.Debug("Clearing connect timer");
- clearInterval(connTimer);
- connTimer = null;
- }
-
- if (disconnTimer && (rfb_state !== 'disconnect')) {
- Util.Debug("Clearing disconnect timer");
- clearInterval(disconnTimer);
- disconnTimer = null;
- }
-
- switch (state) {
- case 'normal':
- if ((oldstate === 'disconnected') || (oldstate === 'failed')) {
- Util.Error("Invalid transition from 'disconnected' or 'failed' to 'normal'");
- }
-
- break;
-
-
- case 'connect':
-
- connTimer = setTimeout(function () {
- fail("Connect timeout");
- }, conf.connectTimeout * 1000);
-
- init_vars();
- connect();
-
- // WebSocket.onopen transitions to 'ProtocolVersion'
- break;
-
-
- case 'disconnect':
-
- if (! test_mode) {
- disconnTimer = setTimeout(function () {
- fail("Disconnect timeout");
- }, conf.disconnectTimeout * 1000);
- }
-
- print_stats();
-
- // WebSocket.onclose transitions to 'disconnected'
- break;
-
-
- case 'failed':
- if (oldstate === 'disconnected') {
- Util.Error("Invalid transition from 'disconnected' to 'failed'");
- }
- if (oldstate === 'normal') {
- Util.Error("Error while connected.");
- }
- if (oldstate === 'init') {
- Util.Error("Error while initializing.");
- }
-
- // Make sure we transition to disconnected
- setTimeout(function() { updateState('disconnected'); }, 50);
-
- break;
-
-
- default:
- // No state change action to take
-
- }
-
- if ((oldstate === 'failed') && (state === 'disconnected')) {
- // Leave the failed message
- conf.updateState(that, state, oldstate); // Obsolete
- conf.onUpdateState(that, state, oldstate);
- } else {
- conf.updateState(that, state, oldstate, statusMsg); // Obsolete
- conf.onUpdateState(that, state, oldstate, statusMsg);
- }
-};
-
-fail = function(msg) {
- updateState('failed', msg);
- return false;
-};
-
-handle_message = function() {
- //Util.Debug(">> handle_message ws.rQlen(): " + ws.rQlen());
- //Util.Debug("ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
- if (ws.rQlen() === 0) {
- Util.Warn("handle_message called on empty receive queue");
- return;
- }
- switch (rfb_state) {
- case 'disconnected':
- case 'failed':
- Util.Error("Got data while disconnected");
- break;
- case 'normal':
- if (normal_msg() && ws.rQlen() > 0) {
- // true means we can continue processing
- // Give other events a chance to run
- if (msgTimer === null) {
- Util.Debug("More data to process, creating timer");
- msgTimer = setTimeout(function () {
- msgTimer = null;
- handle_message();
- }, 10);
- } else {
- Util.Debug("More data to process, existing timer");
- }
- }
- break;
- default:
- init_msg();
- break;
- }
-};
-
-
-function genDES(password, challenge) {
- var i, passwd = [];
- for (i=0; i < password.length; i += 1) {
- passwd.push(password.charCodeAt(i));
- }
- return (new DES(passwd)).encrypt(challenge);
-}
-
-function flushClient() {
- if (mouse_arr.length > 0) {
- //send(mouse_arr.concat(fbUpdateRequests()));
- ws.send(mouse_arr);
- setTimeout(function() {
- ws.send(fbUpdateRequests());
- }, 50);
-
- mouse_arr = [];
- return true;
- } else {
- return false;
- }
-}
-
-// overridable for testing
-checkEvents = function() {
- var now;
- if (rfb_state === 'normal' && !viewportDragging) {
- if (! flushClient()) {
- now = new Date().getTime();
- if (now > last_req_time + conf.fbu_req_rate) {
- last_req_time = now;
- ws.send(fbUpdateRequests());
- }
- }
- }
- setTimeout(checkEvents, conf.check_rate);
-};
-
-keyPress = function(keysym, down) {
- var arr;
-
- if (conf.view_only) { return; } // View only, skip keyboard events
-
- arr = keyEvent(keysym, down);
- arr = arr.concat(fbUpdateRequests());
- ws.send(arr);
-};
-
-mouseButton = function(x, y, down, bmask) {
- if (down) {
- mouse_buttonMask |= bmask;
- } else {
- mouse_buttonMask ^= bmask;
- }
-
- if (conf.viewportDrag) {
- if (down && !viewportDragging) {
- viewportDragging = true;
- viewportDragPos = {'x': x, 'y': y};
-
- // Skip sending mouse events
- return;
- } else {
- viewportDragging = false;
- ws.send(fbUpdateRequests()); // Force immediate redraw
- }
- }
-
- if (conf.view_only) { return; } // View only, skip mouse events
-
- mouse_arr = mouse_arr.concat(
- pointerEvent(display.absX(x), display.absY(y)) );
- flushClient();
-};
-
-mouseMove = function(x, y) {
- //Util.Debug('>> mouseMove ' + x + "," + y);
- var deltaX, deltaY;
-
- if (viewportDragging) {
- //deltaX = x - viewportDragPos.x; // drag viewport
- deltaX = viewportDragPos.x - x; // drag frame buffer
- //deltaY = y - viewportDragPos.y; // drag viewport
- deltaY = viewportDragPos.y - y; // drag frame buffer
- viewportDragPos = {'x': x, 'y': y};
-
- display.viewportChange(deltaX, deltaY);
-
- // Skip sending mouse events
- return;
- }
-
- if (conf.view_only) { return; } // View only, skip mouse events
-
- mouse_arr = mouse_arr.concat(
- pointerEvent(display.absX(x), display.absY(y)) );
-};
-
-
-//
-// Server message handlers
-//
-
-// RFB/VNC initialisation message handler
-init_msg = function() {
- //Util.Debug(">> init_msg [rfb_state '" + rfb_state + "']");
-
- var strlen, reason, length, sversion, cversion, repeaterID,
- i, types, num_types, challenge, response, bpp, depth,
- big_endian, red_max, green_max, blue_max, red_shift,
- green_shift, blue_shift, true_color, name_length, is_repeater;
-
- //Util.Debug("ws.rQ (" + ws.rQlen() + ") " + ws.rQslice(0));
- switch (rfb_state) {
-
- case 'ProtocolVersion' :
- if (ws.rQlen() < 12) {
- return fail("Incomplete protocol version");
- }
- sversion = ws.rQshiftStr(12).substr(4,7);
- Util.Info("Server ProtocolVersion: " + sversion);
- is_repeater = 0;
- switch (sversion) {
- case "000.000": is_repeater = 1; break; // UltraVNC repeater
- case "003.003": rfb_version = 3.3; break;
- case "003.006": rfb_version = 3.3; break; // UltraVNC
- case "003.889": rfb_version = 3.3; break; // Apple Remote Desktop
- case "003.007": rfb_version = 3.7; break;
- case "003.008": rfb_version = 3.8; break;
- case "004.000": rfb_version = 3.8; break; // Intel AMT KVM
- case "004.001": rfb_version = 3.8; break; // RealVNC 4.6
- default:
- return fail("Invalid server version " + sversion);
- }
- if (is_repeater) {
- repeaterID = conf.repeaterID;
- while (repeaterID.length < 250) {
- repeaterID += "\0";
- }
- ws.send_string(repeaterID);
- break;
- }
- if (rfb_version > rfb_max_version) {
- rfb_version = rfb_max_version;
- }
-
- if (! test_mode) {
- sendTimer = setInterval(function() {
- // Send updates either at a rate of one update
- // every 50ms, or whatever slower rate the network
- // can handle.
- ws.flush();
- }, 50);
- }
-
- cversion = "00" + parseInt(rfb_version,10) +
- ".00" + ((rfb_version * 10) % 10);
- ws.send_string("RFB " + cversion + "\n");
- updateState('Security', "Sent ProtocolVersion: " + cversion);
- break;
-
- case 'Security' :
- if (rfb_version >= 3.7) {
- // Server sends supported list, client decides
- num_types = ws.rQshift8();
- if (ws.rQwait("security type", num_types, 1)) { return false; }
- if (num_types === 0) {
- strlen = ws.rQshift32();
- reason = ws.rQshiftStr(strlen);
- return fail("Security failure: " + reason);
- }
- rfb_auth_scheme = 0;
- types = ws.rQshiftBytes(num_types);
- Util.Debug("Server security types: " + types);
- for (i=0; i < types.length; i+=1) {
- if ((types[i] > rfb_auth_scheme) && (types[i] < 3)) {
- rfb_auth_scheme = types[i];
- }
- }
- if (rfb_auth_scheme === 0) {
- return fail("Unsupported security types: " + types);
- }
-
- ws.send([rfb_auth_scheme]);
- } else {
- // Server decides
- if (ws.rQwait("security scheme", 4)) { return false; }
- rfb_auth_scheme = ws.rQshift32();
- }
- updateState('Authentication',
- "Authenticating using scheme: " + rfb_auth_scheme);
- init_msg(); // Recursive fallthrough (workaround JSLint complaint)
- break;
-
- // Triggered by fallthough, not by server message
- case 'Authentication' :
- //Util.Debug("Security auth scheme: " + rfb_auth_scheme);
- switch (rfb_auth_scheme) {
- case 0: // connection failed
- if (ws.rQwait("auth reason", 4)) { return false; }
- strlen = ws.rQshift32();
- reason = ws.rQshiftStr(strlen);
- return fail("Auth failure: " + reason);
- case 1: // no authentication
- if (rfb_version >= 3.8) {
- updateState('SecurityResult');
- return;
- }
- // Fall through to ClientInitialisation
- break;
- case 2: // VNC authentication
- if (rfb_password.length === 0) {
- // Notify via both callbacks since it is kind of
- // a RFB state change and a UI interface issue.
- updateState('password', "Password Required");
- conf.onPasswordRequired(that);
- return;
- }
- if (ws.rQwait("auth challenge", 16)) { return false; }
- challenge = ws.rQshiftBytes(16);
- //Util.Debug("Password: " + rfb_password);
- //Util.Debug("Challenge: " + challenge +
- // " (" + challenge.length + ")");
- response = genDES(rfb_password, challenge);
- //Util.Debug("Response: " + response +
- // " (" + response.length + ")");
-
- //Util.Debug("Sending DES encrypted auth response");
- ws.send(response);
- updateState('SecurityResult');
- return;
- default:
- fail("Unsupported auth scheme: " + rfb_auth_scheme);
- return;
- }
- updateState('ClientInitialisation', "No auth required");
- init_msg(); // Recursive fallthrough (workaround JSLint complaint)
- break;
-
- case 'SecurityResult' :
- if (ws.rQwait("VNC auth response ", 4)) { return false; }
- switch (ws.rQshift32()) {
- case 0: // OK
- // Fall through to ClientInitialisation
- break;
- case 1: // failed
- if (rfb_version >= 3.8) {
- length = ws.rQshift32();
- if (ws.rQwait("SecurityResult reason", length, 8)) {
- return false;
- }
- reason = ws.rQshiftStr(length);
- fail(reason);
- } else {
- fail("Authentication failed");
- }
- return;
- case 2: // too-many
- return fail("Too many auth attempts");
- }
- updateState('ClientInitialisation', "Authentication OK");
- init_msg(); // Recursive fallthrough (workaround JSLint complaint)
- break;
-
- // Triggered by fallthough, not by server message
- case 'ClientInitialisation' :
- ws.send([conf.shared ? 1 : 0]); // ClientInitialisation
- updateState('ServerInitialisation', "Authentication OK");
- break;
-
- case 'ServerInitialisation' :
- if (ws.rQwait("server initialization", 24)) { return false; }
-
- /* Screen size */
- fb_width = ws.rQshift16();
- fb_height = ws.rQshift16();
-
- /* PIXEL_FORMAT */
- bpp = ws.rQshift8();
- depth = ws.rQshift8();
- big_endian = ws.rQshift8();
- true_color = ws.rQshift8();
-
- red_max = ws.rQshift16();
- green_max = ws.rQshift16();
- blue_max = ws.rQshift16();
- red_shift = ws.rQshift8();
- green_shift = ws.rQshift8();
- blue_shift = ws.rQshift8();
- ws.rQshiftStr(3); // padding
-
- Util.Info("Screen: " + fb_width + "x" + fb_height +
- ", bpp: " + bpp + ", depth: " + depth +
- ", big_endian: " + big_endian +
- ", true_color: " + true_color +
- ", red_max: " + red_max +
- ", green_max: " + green_max +
- ", blue_max: " + blue_max +
- ", red_shift: " + red_shift +
- ", green_shift: " + green_shift +
- ", blue_shift: " + blue_shift);
-
- if (big_endian !== 0) {
- Util.Warn("Server native endian is not little endian");
- }
- if (red_shift !== 16) {
- Util.Warn("Server native red-shift is not 16");
- }
- if (blue_shift !== 0) {
- Util.Warn("Server native blue-shift is not 0");
- }
-
- /* Connection name/title */
- name_length = ws.rQshift32();
- fb_name = ws.rQshiftStr(name_length);
-
- if (conf.true_color && fb_name === "Intel(r) AMT KVM")
- {
- Util.Warn("Intel AMT KVM only support 8/16 bit depths. Disabling true color");
- conf.true_color = false;
- }
-
- display.set_true_color(conf.true_color);
- conf.onFBResize(that, fb_width, fb_height);
- display.resize(fb_width, fb_height);
- keyboard.grab();
- mouse.grab();
-
- if (conf.true_color) {
- fb_Bpp = 4;
- fb_depth = 3;
- } else {
- fb_Bpp = 1;
- fb_depth = 1;
- }
-
- response = pixelFormat();
- response = response.concat(clientEncodings());
- response = response.concat(fbUpdateRequests());
- timing.fbu_rt_start = (new Date()).getTime();
- timing.pixels = 0;
- ws.send(response);
-
- /* Start pushing/polling */
- setTimeout(checkEvents, conf.check_rate);
-
- if (conf.encrypt) {
- updateState('normal', "Connected (encrypted) to: " + fb_name);
- } else {
- updateState('normal', "Connected (unencrypted) to: " + fb_name);
- }
- break;
- }
- //Util.Debug("<< init_msg");
-};
-
-
-/* Normal RFB/VNC server message handler */
-normal_msg = function() {
- //Util.Debug(">> normal_msg");
-
- var ret = true, msg_type, length, text,
- c, first_colour, num_colours, red, green, blue;
-
- if (FBU.rects > 0) {
- msg_type = 0;
- } else {
- msg_type = ws.rQshift8();
- }
- switch (msg_type) {
- case 0: // FramebufferUpdate
- ret = framebufferUpdate(); // false means need more data
- break;
- case 1: // SetColourMapEntries
- Util.Debug("SetColourMapEntries");
- ws.rQshift8(); // Padding
- first_colour = ws.rQshift16(); // First colour
- num_colours = ws.rQshift16();
- if (ws.rQwait("SetColourMapEntries", num_colours*6, 6)) { return false; }
-
- for (c=0; c < num_colours; c+=1) {
- red = ws.rQshift16();
- //Util.Debug("red before: " + red);
- red = parseInt(red / 256, 10);
- //Util.Debug("red after: " + red);
- green = parseInt(ws.rQshift16() / 256, 10);
- blue = parseInt(ws.rQshift16() / 256, 10);
- display.set_colourMap([blue, green, red], first_colour + c);
- }
- Util.Debug("colourMap: " + display.get_colourMap());
- Util.Info("Registered " + num_colours + " colourMap entries");
- //Util.Debug("colourMap: " + display.get_colourMap());
- break;
- case 2: // Bell
- Util.Debug("Bell");
- conf.onBell(that);
- break;
- case 3: // ServerCutText
- Util.Debug("ServerCutText");
- if (ws.rQwait("ServerCutText header", 7, 1)) { return false; }
- ws.rQshiftBytes(3); // Padding
- length = ws.rQshift32();
- if (ws.rQwait("ServerCutText", length, 8)) { return false; }
-
- text = ws.rQshiftStr(length);
- conf.clipboardReceive(that, text); // Obsolete
- conf.onClipboard(that, text);
- break;
- default:
- fail("Disconnected: illegal server message type " + msg_type);
- Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30));
- break;
- }
- //Util.Debug("<< normal_msg");
- return ret;
-};
-
-framebufferUpdate = function() {
- var now, hdr, fbu_rt_diff, ret = true;
-
- if (FBU.rects === 0) {
- //Util.Debug("New FBU: ws.rQslice(0,20): " + ws.rQslice(0,20));
- if (ws.rQwait("FBU header", 3)) {
- ws.rQunshift8(0); // FBU msg_type
- return false;
- }
- ws.rQshift8(); // padding
- FBU.rects = ws.rQshift16();
- //Util.Debug("FramebufferUpdate, rects:" + FBU.rects);
- FBU.bytes = 0;
- timing.cur_fbu = 0;
- if (timing.fbu_rt_start > 0) {
- now = (new Date()).getTime();
- Util.Info("First FBU latency: " + (now - timing.fbu_rt_start));
- }
- }
-
- while (FBU.rects > 0) {
- if (rfb_state !== "normal") {
- return false;
- }
- if (ws.rQwait("FBU", FBU.bytes)) { return false; }
- if (FBU.bytes === 0) {
- if (ws.rQwait("rect header", 12)) { return false; }
- /* New FramebufferUpdate */
-
- hdr = ws.rQshiftBytes(12);
- FBU.x = (hdr[0] << 8) + hdr[1];
- FBU.y = (hdr[2] << 8) + hdr[3];
- FBU.width = (hdr[4] << 8) + hdr[5];
- FBU.height = (hdr[6] << 8) + hdr[7];
- FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) +
- (hdr[10] << 8) + hdr[11], 10);
-
- conf.onFBUReceive(that,
- {'x': FBU.x, 'y': FBU.y,
- 'width': FBU.width, 'height': FBU.height,
- 'encoding': FBU.encoding,
- 'encodingName': encNames[FBU.encoding]});
-
- if (encNames[FBU.encoding]) {
- // Debug:
- /*
- var msg = "FramebufferUpdate rects:" + FBU.rects;
- msg += " x: " + FBU.x + " y: " + FBU.y;
- msg += " width: " + FBU.width + " height: " + FBU.height;
- msg += " encoding:" + FBU.encoding;
- msg += "(" + encNames[FBU.encoding] + ")";
- msg += ", ws.rQlen(): " + ws.rQlen();
- Util.Debug(msg);
- */
- } else {
- fail("Disconnected: unsupported encoding " +
- FBU.encoding);
- return false;
- }
- }
-
- timing.last_fbu = (new Date()).getTime();
-
- ret = encHandlers[FBU.encoding]();
-
- now = (new Date()).getTime();
- timing.cur_fbu += (now - timing.last_fbu);
-
- if (ret) {
- encStats[FBU.encoding][0] += 1;
- encStats[FBU.encoding][1] += 1;
- timing.pixels += FBU.width * FBU.height;
- }
-
- if (timing.pixels >= (fb_width * fb_height)) {
- if (((FBU.width === fb_width) &&
- (FBU.height === fb_height)) ||
- (timing.fbu_rt_start > 0)) {
- timing.full_fbu_total += timing.cur_fbu;
- timing.full_fbu_cnt += 1;
- Util.Info("Timing of full FBU, cur: " +
- timing.cur_fbu + ", total: " +
- timing.full_fbu_total + ", cnt: " +
- timing.full_fbu_cnt + ", avg: " +
- (timing.full_fbu_total /
- timing.full_fbu_cnt));
- }
- if (timing.fbu_rt_start > 0) {
- fbu_rt_diff = now - timing.fbu_rt_start;
- timing.fbu_rt_total += fbu_rt_diff;
- timing.fbu_rt_cnt += 1;
- Util.Info("full FBU round-trip, cur: " +
- fbu_rt_diff + ", total: " +
- timing.fbu_rt_total + ", cnt: " +
- timing.fbu_rt_cnt + ", avg: " +
- (timing.fbu_rt_total /
- timing.fbu_rt_cnt));
- timing.fbu_rt_start = 0;
- }
- }
- if (! ret) {
- return ret; // false ret means need more data
- }
- }
-
- conf.onFBUComplete(that,
- {'x': FBU.x, 'y': FBU.y,
- 'width': FBU.width, 'height': FBU.height,
- 'encoding': FBU.encoding,
- 'encodingName': encNames[FBU.encoding]});
-
- return true; // We finished this FBU
-};
-
-//
-// FramebufferUpdate encodings
-//
-
-encHandlers.RAW = function display_raw() {
- //Util.Debug(">> display_raw (" + ws.rQlen() + " bytes)");
-
- var cur_y, cur_height;
-
- if (FBU.lines === 0) {
- FBU.lines = FBU.height;
- }
- FBU.bytes = FBU.width * fb_Bpp; // At least a line
- if (ws.rQwait("RAW", FBU.bytes)) { return false; }
- cur_y = FBU.y + (FBU.height - FBU.lines);
- cur_height = Math.min(FBU.lines,
- Math.floor(ws.rQlen()/(FBU.width * fb_Bpp)));
- display.blitImage(FBU.x, cur_y, FBU.width, cur_height,
- ws.get_rQ(), ws.get_rQi());
- ws.rQshiftBytes(FBU.width * cur_height * fb_Bpp);
- FBU.lines -= cur_height;
-
- if (FBU.lines > 0) {
- FBU.bytes = FBU.width * fb_Bpp; // At least another line
- } else {
- FBU.rects -= 1;
- FBU.bytes = 0;
- }
- //Util.Debug("<< display_raw (" + ws.rQlen() + " bytes)");
- return true;
-};
-
-encHandlers.COPYRECT = function display_copy_rect() {
- //Util.Debug(">> display_copy_rect");
-
- var old_x, old_y;
-
- if (ws.rQwait("COPYRECT", 4)) { return false; }
- display.renderQ_push({
- 'type': 'copy',
- 'old_x': ws.rQshift16(),
- 'old_y': ws.rQshift16(),
- 'x': FBU.x,
- 'y': FBU.y,
- 'width': FBU.width,
- 'height': FBU.height});
- FBU.rects -= 1;
- FBU.bytes = 0;
- return true;
-};
-
-encHandlers.RRE = function display_rre() {
- //Util.Debug(">> display_rre (" + ws.rQlen() + " bytes)");
- var color, x, y, width, height, chunk;
-
- if (FBU.subrects === 0) {
- if (ws.rQwait("RRE", 4+fb_Bpp)) { return false; }
- FBU.subrects = ws.rQshift32();
- color = ws.rQshiftBytes(fb_Bpp); // Background
- display.fillRect(FBU.x, FBU.y, FBU.width, FBU.height, color);
- }
- while ((FBU.subrects > 0) && (ws.rQlen() >= (fb_Bpp + 8))) {
- color = ws.rQshiftBytes(fb_Bpp);
- x = ws.rQshift16();
- y = ws.rQshift16();
- width = ws.rQshift16();
- height = ws.rQshift16();
- display.fillRect(FBU.x + x, FBU.y + y, width, height, color);
- FBU.subrects -= 1;
- }
- //Util.Debug(" display_rre: rects: " + FBU.rects +
- // ", FBU.subrects: " + FBU.subrects);
-
- if (FBU.subrects > 0) {
- chunk = Math.min(rre_chunk_sz, FBU.subrects);
- FBU.bytes = (fb_Bpp + 8) * chunk;
- } else {
- FBU.rects -= 1;
- FBU.bytes = 0;
- }
- //Util.Debug("<< display_rre, FBU.bytes: " + FBU.bytes);
- return true;
-};
-
-encHandlers.HEXTILE = function display_hextile() {
- //Util.Debug(">> display_hextile");
- var subencoding, subrects, color, cur_tile,
- tile_x, x, w, tile_y, y, h, xy, s, sx, sy, wh, sw, sh,
- rQ = ws.get_rQ(), rQi = ws.get_rQi();
-
- if (FBU.tiles === 0) {
- FBU.tiles_x = Math.ceil(FBU.width/16);
- FBU.tiles_y = Math.ceil(FBU.height/16);
- FBU.total_tiles = FBU.tiles_x * FBU.tiles_y;
- FBU.tiles = FBU.total_tiles;
- }
-
- /* FBU.bytes comes in as 1, ws.rQlen() at least 1 */
- while (FBU.tiles > 0) {
- FBU.bytes = 1;
- if (ws.rQwait("HEXTILE subencoding", FBU.bytes)) { return false; }
- subencoding = rQ[rQi]; // Peek
- if (subencoding > 30) { // Raw
- fail("Disconnected: illegal hextile subencoding " + subencoding);
- //Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30));
- return false;
- }
- subrects = 0;
- cur_tile = FBU.total_tiles - FBU.tiles;
- tile_x = cur_tile % FBU.tiles_x;
- tile_y = Math.floor(cur_tile / FBU.tiles_x);
- x = FBU.x + tile_x * 16;
- y = FBU.y + tile_y * 16;
- w = Math.min(16, (FBU.x + FBU.width) - x);
- h = Math.min(16, (FBU.y + FBU.height) - y);
-
- /* Figure out how much we are expecting */
- if (subencoding & 0x01) { // Raw
- //Util.Debug(" Raw subencoding");
- FBU.bytes += w * h * fb_Bpp;
- } else {
- if (subencoding & 0x02) { // Background
- FBU.bytes += fb_Bpp;
- }
- if (subencoding & 0x04) { // Foreground
- FBU.bytes += fb_Bpp;
- }
- if (subencoding & 0x08) { // AnySubrects
- FBU.bytes += 1; // Since we aren't shifting it off
- if (ws.rQwait("hextile subrects header", FBU.bytes)) { return false; }
- subrects = rQ[rQi + FBU.bytes-1]; // Peek
- if (subencoding & 0x10) { // SubrectsColoured
- FBU.bytes += subrects * (fb_Bpp + 2);
- } else {
- FBU.bytes += subrects * 2;
- }
- }
- }
-
- /*
- Util.Debug(" tile:" + cur_tile + "/" + (FBU.total_tiles - 1) +
- " (" + tile_x + "," + tile_y + ")" +
- " [" + x + "," + y + "]@" + w + "x" + h +
- ", subenc:" + subencoding +
- "(last: " + FBU.lastsubencoding + "), subrects:" +
- subrects +
- ", ws.rQlen():" + ws.rQlen() + ", FBU.bytes:" + FBU.bytes +
- " last:" + ws.rQslice(FBU.bytes-10, FBU.bytes) +
- " next:" + ws.rQslice(FBU.bytes-1, FBU.bytes+10));
- */
- if (ws.rQwait("hextile", FBU.bytes)) { return false; }
-
- /* We know the encoding and have a whole tile */
- FBU.subencoding = rQ[rQi];
- rQi += 1;
- if (FBU.subencoding === 0) {
- if (FBU.lastsubencoding & 0x01) {
- /* Weird: ignore blanks after RAW */
- Util.Debug(" Ignoring blank after RAW");
- } else {
- display.fillRect(x, y, w, h, FBU.background);
- }
- } else if (FBU.subencoding & 0x01) { // Raw
- display.blitImage(x, y, w, h, rQ, rQi);
- rQi += FBU.bytes - 1;
- } else {
- if (FBU.subencoding & 0x02) { // Background
- FBU.background = rQ.slice(rQi, rQi + fb_Bpp);
- rQi += fb_Bpp;
- }
- if (FBU.subencoding & 0x04) { // Foreground
- FBU.foreground = rQ.slice(rQi, rQi + fb_Bpp);
- rQi += fb_Bpp;
- }
-
- display.startTile(x, y, w, h, FBU.background);
- if (FBU.subencoding & 0x08) { // AnySubrects
- subrects = rQ[rQi];
- rQi += 1;
- for (s = 0; s < subrects; s += 1) {
- if (FBU.subencoding & 0x10) { // SubrectsColoured
- color = rQ.slice(rQi, rQi + fb_Bpp);
- rQi += fb_Bpp;
- } else {
- color = FBU.foreground;
- }
- xy = rQ[rQi];
- rQi += 1;
- sx = (xy >> 4);
- sy = (xy & 0x0f);
-
- wh = rQ[rQi];
- rQi += 1;
- sw = (wh >> 4) + 1;
- sh = (wh & 0x0f) + 1;
-
- display.subTile(sx, sy, sw, sh, color);
- }
- }
- display.finishTile();
- }
- ws.set_rQi(rQi);
- FBU.lastsubencoding = FBU.subencoding;
- FBU.bytes = 0;
- FBU.tiles -= 1;
- }
-
- if (FBU.tiles === 0) {
- FBU.rects -= 1;
- }
-
- //Util.Debug("<< display_hextile");
- return true;
-};
-
-
-// Get 'compact length' header and data size
-getTightCLength = function (arr) {
- var header = 1, data = 0;
- data += arr[0] & 0x7f;
- if (arr[0] & 0x80) {
- header += 1;
- data += (arr[1] & 0x7f) << 7;
- if (arr[1] & 0x80) {
- header += 1;
- data += arr[2] << 14;
- }
- }
- return [header, data];
-};
-
-function display_tight(isTightPNG) {
- //Util.Debug(">> display_tight");
-
- if (fb_depth === 1) {
- fail("Tight protocol handler only implements true color mode");
- }
-
- var ctl, cmode, clength, color, img, data;
- var filterId = -1, resetStreams = 0, streamId = -1;
- var rQ = ws.get_rQ(), rQi = ws.get_rQi();
-
- FBU.bytes = 1; // compression-control byte
- if (ws.rQwait("TIGHT compression-control", FBU.bytes)) { return false; }
-
- var checksum = function(data) {
- var sum=0, i;
- for (i=0; i<data.length;i++) {
- sum += data[i];
- if (sum > 65536) sum -= 65536;
- }
- return sum;
- }
-
- var decompress = function(data) {
- for (var i=0; i<4; i++) {
- if ((resetStreams >> i) & 1) {
- FBU.zlibs[i].reset();
- Util.Info("Reset zlib stream " + i);
- }
- }
- var uncompressed = FBU.zlibs[streamId].uncompress(data, 0);
- if (uncompressed.status !== 0) {
- Util.Error("Invalid data in zlib stream");
- }
- //Util.Warn("Decompressed " + data.length + " to " +
- // uncompressed.data.length + " checksums " +
- // checksum(data) + ":" + checksum(uncompressed.data));
-
- return uncompressed.data;
- }
-
- var indexedToRGB = function (data, numColors, palette, width, height) {
- // Convert indexed (palette based) image data to RGB
- // TODO: reduce number of calculations inside loop
- var dest = [];
- var x, y, b, w, w1, dp, sp;
- if (numColors === 2) {
- w = Math.floor((width + 7) / 8);
- w1 = Math.floor(width / 8);
- for (y = 0; y < height; y++) {
- for (x = 0; x < w1; x++) {
- for (b = 7; b >= 0; b--) {
- dp = (y*width + x*8 + 7-b) * 3;
- sp = (data[y*w + x] >> b & 1) * 3;
- dest[dp ] = palette[sp ];
- dest[dp+1] = palette[sp+1];
- dest[dp+2] = palette[sp+2];
- }
- }
- for (b = 7; b >= 8 - width % 8; b--) {
- dp = (y*width + x*8 + 7-b) * 3;
- sp = (data[y*w + x] >> b & 1) * 3;
- dest[dp ] = palette[sp ];
- dest[dp+1] = palette[sp+1];
- dest[dp+2] = palette[sp+2];
- }
- }
- } else {
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- dp = (y*width + x) * 3;
- sp = data[y*width + x] * 3;
- dest[dp ] = palette[sp ];
- dest[dp+1] = palette[sp+1];
- dest[dp+2] = palette[sp+2];
- }
- }
- }
- return dest;
- };
- var handlePalette = function() {
- var numColors = rQ[rQi + 2] + 1;
- var paletteSize = numColors * fb_depth;
- FBU.bytes += paletteSize;
- if (ws.rQwait("TIGHT palette " + cmode, FBU.bytes)) { return false; }
-
- var bpp = (numColors <= 2) ? 1 : 8;
- var rowSize = Math.floor((FBU.width * bpp + 7) / 8);
- var raw = false;
- if (rowSize * FBU.height < 12) {
- raw = true;
- clength = [0, rowSize * FBU.height];
- } else {
- clength = getTightCLength(ws.rQslice(3 + paletteSize,
- 3 + paletteSize + 3));
- }
- FBU.bytes += clength[0] + clength[1];
- if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
-
- // Shift ctl, filter id, num colors, palette entries, and clength off
- ws.rQshiftBytes(3);
- var palette = ws.rQshiftBytes(paletteSize);
- ws.rQshiftBytes(clength[0]);
-
- if (raw) {
- data = ws.rQshiftBytes(clength[1]);
- } else {
- data = decompress(ws.rQshiftBytes(clength[1]));
- }
-
- // Convert indexed (palette based) image data to RGB
- var rgb = indexedToRGB(data, numColors, palette, FBU.width, FBU.height);
-
- // Add it to the render queue
- display.renderQ_push({
- 'type': 'blitRgb',
- 'data': rgb,
- 'x': FBU.x,
- 'y': FBU.y,
- 'width': FBU.width,
- 'height': FBU.height});
- return true;
- }
-
- var handleCopy = function() {
- var raw = false;
- var uncompressedSize = FBU.width * FBU.height * fb_depth;
- if (uncompressedSize < 12) {
- raw = true;
- clength = [0, uncompressedSize];
- } else {
- clength = getTightCLength(ws.rQslice(1, 4));
- }
- FBU.bytes = 1 + clength[0] + clength[1];
- if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
-
- // Shift ctl, clength off
- ws.rQshiftBytes(1 + clength[0]);
-
- if (raw) {
- data = ws.rQshiftBytes(clength[1]);
- } else {
- data = decompress(ws.rQshiftBytes(clength[1]));
- }
-
- display.renderQ_push({
- 'type': 'blitRgb',
- 'data': data,
- 'x': FBU.x,
- 'y': FBU.y,
- 'width': FBU.width,
- 'height': FBU.height});
- return true;
- }
-
- ctl = ws.rQpeek8();
-
- // Keep tight reset bits
- resetStreams = ctl & 0xF;
-
- // Figure out filter
- ctl = ctl >> 4;
- streamId = ctl & 0x3;
-
- if (ctl === 0x08) cmode = "fill";
- else if (ctl === 0x09) cmode = "jpeg";
- else if (ctl === 0x0A) cmode = "png";
- else if (ctl & 0x04) cmode = "filter";
- else if (ctl < 0x04) cmode = "copy";
- else return fail("Illegal tight compression received, ctl: " + ctl);
-
- if (isTightPNG && (cmode === "filter" || cmode === "copy")) {
- return fail("filter/copy received in tightPNG mode");
- }
-
- switch (cmode) {
- // fill uses fb_depth because TPIXELs drop the padding byte
- case "fill": FBU.bytes += fb_depth; break; // TPIXEL
- case "jpeg": FBU.bytes += 3; break; // max clength
- case "png": FBU.bytes += 3; break; // max clength
- case "filter": FBU.bytes += 2; break; // filter id + num colors if palette
- case "copy": break;
- }
-
- if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
-
- //Util.Debug(" ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
- //Util.Debug(" cmode: " + cmode);
-
- // Determine FBU.bytes
- switch (cmode) {
- case "fill":
- ws.rQshift8(); // shift off ctl
- color = ws.rQshiftBytes(fb_depth);
- display.renderQ_push({
- 'type': 'fill',
- 'x': FBU.x,
- 'y': FBU.y,
- 'width': FBU.width,
- 'height': FBU.height,
- 'color': [color[2], color[1], color[0]] });
- break;
- case "png":
- case "jpeg":
- clength = getTightCLength(ws.rQslice(1, 4));
- FBU.bytes = 1 + clength[0] + clength[1]; // ctl + clength size + jpeg-data
- if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
-
- // We have everything, render it
- //Util.Debug(" jpeg, ws.rQlen(): " + ws.rQlen() + ", clength[0]: " +
- // clength[0] + ", clength[1]: " + clength[1]);
- ws.rQshiftBytes(1 + clength[0]); // shift off ctl + compact length
- img = new Image();
- img.src = "data:image/" + cmode +
- extract_data_uri(ws.rQshiftBytes(clength[1]));
- display.renderQ_push({
- 'type': 'img',
- 'img': img,
- 'x': FBU.x,
- 'y': FBU.y});
- img = null;
- break;
- case "filter":
- filterId = rQ[rQi + 1];
- if (filterId === 1) {
- if (!handlePalette()) { return false; }
- } else {
- // Filter 0, Copy could be valid here, but servers don't send it as an explicit filter
- // Filter 2, Gradient is valid but not used if jpeg is enabled
- throw("Unsupported tight subencoding received, filter: " + filterId);
- }
- break;
- case "copy":
- if (!handleCopy()) { return false; }
- break;
- }
-
- FBU.bytes = 0;
- FBU.rects -= 1;
- //Util.Debug(" ending ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
- //Util.Debug("<< display_tight_png");
- return true;
-}
-
-extract_data_uri = function(arr) {
- //var i, stra = [];
- //for (i=0; i< arr.length; i += 1) {
- // stra.push(String.fromCharCode(arr[i]));
- //}
- //return "," + escape(stra.join(''));
- return ";base64," + Base64.encode(arr);
-};
-
-encHandlers.TIGHT = function () { return display_tight(false); };
-encHandlers.TIGHT_PNG = function () { return display_tight(true); };
-
-encHandlers.last_rect = function last_rect() {
- //Util.Debug(">> last_rect");
- FBU.rects = 0;
- //Util.Debug("<< last_rect");
- return true;
-};
-
-encHandlers.DesktopSize = function set_desktopsize() {
- Util.Debug(">> set_desktopsize");
- fb_width = FBU.width;
- fb_height = FBU.height;
- conf.onFBResize(that, fb_width, fb_height);
- display.resize(fb_width, fb_height);
- timing.fbu_rt_start = (new Date()).getTime();
- // Send a new non-incremental request
- ws.send(fbUpdateRequests());
-
- FBU.bytes = 0;
- FBU.rects -= 1;
-
- Util.Debug("<< set_desktopsize");
- return true;
-};
-
-encHandlers.Cursor = function set_cursor() {
- var x, y, w, h, pixelslength, masklength;
- Util.Debug(">> set_cursor");
- x = FBU.x; // hotspot-x
- y = FBU.y; // hotspot-y
- w = FBU.width;
- h = FBU.height;
-
- pixelslength = w * h * fb_Bpp;
- masklength = Math.floor((w + 7) / 8) * h;
-
- FBU.bytes = pixelslength + masklength;
- if (ws.rQwait("cursor encoding", FBU.bytes)) { return false; }
-
- //Util.Debug(" set_cursor, x: " + x + ", y: " + y + ", w: " + w + ", h: " + h);
-
- display.changeCursor(ws.rQshiftBytes(pixelslength),
- ws.rQshiftBytes(masklength),
- x, y, w, h);
-
- FBU.bytes = 0;
- FBU.rects -= 1;
-
- Util.Debug("<< set_cursor");
- return true;
-};
-
-encHandlers.JPEG_quality_lo = function set_jpeg_quality() {
- Util.Error("Server sent jpeg_quality pseudo-encoding");
-};
-
-encHandlers.compress_lo = function set_compress_level() {
- Util.Error("Server sent compress level pseudo-encoding");
-};
-
-/*
- * Client message routines
- */
-
-pixelFormat = function() {
- //Util.Debug(">> pixelFormat");
- var arr;
- arr = [0]; // msg-type
- arr.push8(0); // padding
- arr.push8(0); // padding
- arr.push8(0); // padding
-
- arr.push8(fb_Bpp * 8); // bits-per-pixel
- arr.push8(fb_depth * 8); // depth
- arr.push8(0); // little-endian
- arr.push8(conf.true_color ? 1 : 0); // true-color
-
- arr.push16(255); // red-max
- arr.push16(255); // green-max
- arr.push16(255); // blue-max
- arr.push8(16); // red-shift
- arr.push8(8); // green-shift
- arr.push8(0); // blue-shift
-
- arr.push8(0); // padding
- arr.push8(0); // padding
- arr.push8(0); // padding
- //Util.Debug("<< pixelFormat");
- return arr;
-};
-
-clientEncodings = function() {
- //Util.Debug(">> clientEncodings");
- var arr, i, encList = [];
-
- for (i=0; i<encodings.length; i += 1) {
- if ((encodings[i][0] === "Cursor") &&
- (! conf.local_cursor)) {
- Util.Debug("Skipping Cursor pseudo-encoding");
-
- // TODO: remove this when we have tight+non-true-color
- } else if ((encodings[i][0] === "TIGHT") &&
- (! conf.true_color)) {
- Util.Warn("Skipping tight, only support with true color");
- } else {
- //Util.Debug("Adding encoding: " + encodings[i][0]);
- encList.push(encodings[i][1]);
- }
- }
-
- arr = [2]; // msg-type
- arr.push8(0); // padding
-
- arr.push16(encList.length); // encoding count
- for (i=0; i < encList.length; i += 1) {
- arr.push32(encList[i]);
- }
- //Util.Debug("<< clientEncodings: " + arr);
- return arr;
-};
-
-fbUpdateRequest = function(incremental, x, y, xw, yw) {
- //Util.Debug(">> fbUpdateRequest");
- if (typeof(x) === "undefined") { x = 0; }
- if (typeof(y) === "undefined") { y = 0; }
- if (typeof(xw) === "undefined") { xw = fb_width; }
- if (typeof(yw) === "undefined") { yw = fb_height; }
- var arr;
- arr = [3]; // msg-type
- arr.push8(incremental);
- arr.push16(x);
- arr.push16(y);
- arr.push16(xw);
- arr.push16(yw);
- //Util.Debug("<< fbUpdateRequest");
- return arr;
-};
-
-// Based on clean/dirty areas, generate requests to send
-fbUpdateRequests = function() {
- var cleanDirty = display.getCleanDirtyReset(),
- arr = [], i, cb, db;
-
- cb = cleanDirty.cleanBox;
- if (cb.w > 0 && cb.h > 0) {
- // Request incremental for clean box
- arr = arr.concat(fbUpdateRequest(1, cb.x, cb.y, cb.w, cb.h));
- }
- for (i = 0; i < cleanDirty.dirtyBoxes.length; i++) {
- db = cleanDirty.dirtyBoxes[i];
- // Force all (non-incremental for dirty box
- arr = arr.concat(fbUpdateRequest(0, db.x, db.y, db.w, db.h));
- }
- return arr;
-};
-
-
-
-keyEvent = function(keysym, down) {
- //Util.Debug(">> keyEvent, keysym: " + keysym + ", down: " + down);
- var arr;
- arr = [4]; // msg-type
- arr.push8(down);
- arr.push16(0);
- arr.push32(keysym);
- //Util.Debug("<< keyEvent");
- return arr;
-};
-
-pointerEvent = function(x, y) {
- //Util.Debug(">> pointerEvent, x,y: " + x + "," + y +
- // " , mask: " + mouse_buttonMask);
- var arr;
- arr = [5]; // msg-type
- arr.push8(mouse_buttonMask);
- arr.push16(x);
- arr.push16(y);
- //Util.Debug("<< pointerEvent");
- return arr;
-};
-
-clientCutText = function(text) {
- //Util.Debug(">> clientCutText");
- var arr, i, n;
- arr = [6]; // msg-type
- arr.push8(0); // padding
- arr.push8(0); // padding
- arr.push8(0); // padding
- arr.push32(text.length);
- n = text.length;
- for (i=0; i < n; i+=1) {
- arr.push(text.charCodeAt(i));
- }
- //Util.Debug("<< clientCutText:" + arr);
- return arr;
-};
-
-
-
-//
-// Public API interface functions
-//
-
-that.connect = function(host, port, password, path) {
- //Util.Debug(">> connect");
-
- rfb_host = host;
- rfb_port = port;
- rfb_password = (password !== undefined) ? password : "";
- rfb_path = (path !== undefined) ? path : "";
-
- if ((!rfb_host) || (!rfb_port)) {
- return fail("Must set host and port");
- }
-
- updateState('connect');
- //Util.Debug("<< connect");
-
-};
-
-that.disconnect = function() {
- //Util.Debug(">> disconnect");
- updateState('disconnect', 'Disconnecting');
- //Util.Debug("<< disconnect");
-};
-
-that.sendPassword = function(passwd) {
- rfb_password = passwd;
- rfb_state = "Authentication";
- setTimeout(init_msg, 1);
-};
-
-that.sendCtrlAltDel = function() {
- if (rfb_state !== "normal" || conf.view_only) { return false; }
- Util.Info("Sending Ctrl-Alt-Del");
- var arr = [];
- arr = arr.concat(keyEvent(0xFFE3, 1)); // Control
- arr = arr.concat(keyEvent(0xFFE9, 1)); // Alt
- arr = arr.concat(keyEvent(0xFFFF, 1)); // Delete
- arr = arr.concat(keyEvent(0xFFFF, 0)); // Delete
- arr = arr.concat(keyEvent(0xFFE9, 0)); // Alt
- arr = arr.concat(keyEvent(0xFFE3, 0)); // Control
- arr = arr.concat(fbUpdateRequests());
- ws.send(arr);
-};
-
-// Send a key press. If 'down' is not specified then send a down key
-// followed by an up key.
-that.sendKey = function(code, down) {
- if (rfb_state !== "normal" || conf.view_only) { return false; }
- var arr = [];
- if (typeof down !== 'undefined') {
- Util.Info("Sending key code (" + (down ? "down" : "up") + "): " + code);
- arr = arr.concat(keyEvent(code, down ? 1 : 0));
- } else {
- Util.Info("Sending key code (down + up): " + code);
- arr = arr.concat(keyEvent(code, 1));
- arr = arr.concat(keyEvent(code, 0));
- }
- arr = arr.concat(fbUpdateRequests());
- ws.send(arr);
-};
-
-that.clipboardPasteFrom = function(text) {
- if (rfb_state !== "normal") { return; }
- //Util.Debug(">> clipboardPasteFrom: " + text.substr(0,40) + "...");
- ws.send(clientCutText(text));
- //Util.Debug("<< clipboardPasteFrom");
-};
-
-// Override internal functions for testing
-that.testMode = function(override_send, data_mode) {
- test_mode = true;
- that.recv_message = ws.testMode(override_send, data_mode);
-
- checkEvents = function () { /* Stub Out */ };
- that.connect = function(host, port, password) {
- rfb_host = host;
- rfb_port = port;
- rfb_password = password;
- init_vars();
- updateState('ProtocolVersion', "Starting VNC handshake");
- };
-};
-
-
-return constructor(); // Return the public API interface
-
-} // End of RFB()
diff --git a/ui/novnc/js/util.js b/ui/novnc/js/util.js
deleted file mode 100644
index 983f260..0000000
--- a/ui/novnc/js/util.js
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-"use strict";
-/*jslint bitwise: false, white: false */
-/*global window, console, document, navigator, ActiveXObject */
-
-// Globals defined here
-var Util = {};
-
-
-/*
- * Make arrays quack
- */
-
-Array.prototype.push8 = function (num) {
- this.push(num & 0xFF);
-};
-
-Array.prototype.push16 = function (num) {
- this.push((num >> 8) & 0xFF,
- (num ) & 0xFF );
-};
-Array.prototype.push32 = function (num) {
- this.push((num >> 24) & 0xFF,
- (num >> 16) & 0xFF,
- (num >> 8) & 0xFF,
- (num ) & 0xFF );
-};
-
-// IE does not support map (even in IE9)
-//This prototype is provided by the Mozilla foundation and
-//is distributed under the MIT license.
-//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
-if (!Array.prototype.map)
-{
- Array.prototype.map = function(fun /*, thisp*/)
- {
- var len = this.length;
- if (typeof fun != "function")
- throw new TypeError();
-
- var res = new Array(len);
- var thisp = arguments[1];
- for (var i = 0; i < len; i++)
- {
- if (i in this)
- res[i] = fun.call(thisp, this[i], i, this);
- }
-
- return res;
- };
-}
-
-//
-// requestAnimationFrame shim with setTimeout fallback
-//
-
-window.requestAnimFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function(callback){
- window.setTimeout(callback, 1000 / 60);
- };
-})();
-
-/*
- * ------------------------------------------------------
- * Namespaced in Util
- * ------------------------------------------------------
- */
-
-/*
- * Logging/debug routines
- */
-
-Util._log_level = 'warn';
-Util.init_logging = function (level) {
- if (typeof level === 'undefined') {
- level = Util._log_level;
- } else {
- Util._log_level = level;
- }
- if (typeof window.console === "undefined") {
- if (typeof window.opera !== "undefined") {
- window.console = {
- 'log' : window.opera.postError,
- 'warn' : window.opera.postError,
- 'error': window.opera.postError };
- } else {
- window.console = {
- 'log' : function(m) {},
- 'warn' : function(m) {},
- 'error': function(m) {}};
- }
- }
-
- Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
- switch (level) {
- case 'debug': Util.Debug = function (msg) { console.log(msg); };
- case 'info': Util.Info = function (msg) { console.log(msg); };
- case 'warn': Util.Warn = function (msg) { console.warn(msg); };
- case 'error': Util.Error = function (msg) { console.error(msg); };
- case 'none':
- break;
- default:
- throw("invalid logging type '" + level + "'");
- }
-};
-Util.get_logging = function () {
- return Util._log_level;
-};
-// Initialize logging level
-Util.init_logging();
-
-
-// Set configuration default for Crockford style function namespaces
-Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) {
- var getter, setter;
-
- // Default getter function
- getter = function (idx) {
- if ((type in {'arr':1, 'array':1}) &&
- (typeof idx !== 'undefined')) {
- return cfg[v][idx];
- } else {
- return cfg[v];
- }
- };
-
- // Default setter function
- setter = function (val, idx) {
- if (type in {'boolean':1, 'bool':1}) {
- if ((!val) || (val in {'0':1, 'no':1, 'false':1})) {
- val = false;
- } else {
- val = true;
- }
- } else if (type in {'integer':1, 'int':1}) {
- val = parseInt(val, 10);
- } else if (type === 'str') {
- val = String(val);
- } else if (type === 'func') {
- if (!val) {
- val = function () {};
- }
- }
- if (typeof idx !== 'undefined') {
- cfg[v][idx] = val;
- } else {
- cfg[v] = val;
- }
- };
-
- // Set the description
- api[v + '_description'] = desc;
-
- // Set the getter function
- if (typeof api['get_' + v] === 'undefined') {
- api['get_' + v] = getter;
- }
-
- // Set the setter function with extra sanity checks
- if (typeof api['set_' + v] === 'undefined') {
- api['set_' + v] = function (val, idx) {
- if (mode in {'RO':1, 'ro':1}) {
- throw(v + " is read-only");
- } else if ((mode in {'WO':1, 'wo':1}) &&
- (typeof cfg[v] !== 'undefined')) {
- throw(v + " can only be set once");
- }
- setter(val, idx);
- };
- }
-
- // Set the default value
- if (typeof defaults[v] !== 'undefined') {
- defval = defaults[v];
- } else if ((type in {'arr':1, 'array':1}) &&
- (! (defval instanceof Array))) {
- defval = [];
- }
- // Coerce existing setting to the right type
- //Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]);
- setter(defval);
-};
-
-// Set group of configuration defaults
-Util.conf_defaults = function(cfg, api, defaults, arr) {
- var i;
- for (i = 0; i < arr.length; i++) {
- Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1],
- arr[i][2], arr[i][3], arr[i][4]);
- }
-};
-
-
-/*
- * Cross-browser routines
- */
-
-
-// Dynamically load scripts without using document.write()
-// Reference: http://unixpapa.com/js/dyna.html
-//
-// Handles the case where load_scripts is invoked from a script that
-// itself is loaded via load_scripts. Once all scripts are loaded the
-// window.onscriptsloaded handler is called (if set).
-Util.get_include_uri = function() {
- return (typeof INCLUDE_URI !== "undefined") ? INCLUDE_URI : "include/";
-}
-Util._loading_scripts = [];
-Util._pending_scripts = [];
-Util.load_scripts = function(files) {
- var head = document.getElementsByTagName('head')[0], script,
- ls = Util._loading_scripts, ps = Util._pending_scripts;
- for (var f=0; f<files.length; f++) {
- script = document.createElement('script');
- script.type = 'text/javascript';
- script.src = Util.get_include_uri() + files[f];
- //console.log("loading script: " + script.src);
- script.onload = script.onreadystatechange = function (e) {
- while (ls.length > 0 && (ls[0].readyState === 'loaded' ||
- ls[0].readyState === 'complete')) {
- // For IE, append the script to trigger execution
- var s = ls.shift();
- //console.log("loaded script: " + s.src);
- head.appendChild(s);
- }
- if (!this.readyState ||
- (Util.Engine.presto && this.readyState === 'loaded') ||
- this.readyState === 'complete') {
- if (ps.indexOf(this) >= 0) {
- this.onload = this.onreadystatechange = null;
- //console.log("completed script: " + this.src);
- ps.splice(ps.indexOf(this), 1);
-
- // Call window.onscriptsload after last script loads
- if (ps.length === 0 && window.onscriptsload) {
- window.onscriptsload();
- }
- }
- }
- };
- // In-order script execution tricks
- if (Util.Engine.trident) {
- // For IE wait until readyState is 'loaded' before
- // appending it which will trigger execution
- // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
- ls.push(script);
- } else {
- // For webkit and firefox set async=false and append now
- // https://developer.mozilla.org/en-US/docs/HTML/Element/script
- script.async = false;
- head.appendChild(script);
- }
- ps.push(script);
- }
-}
-
-// Get DOM element position on page
-Util.getPosition = function (obj) {
- var x = 0, y = 0;
- if (obj.offsetParent) {
- do {
- x += obj.offsetLeft;
- y += obj.offsetTop;
- obj = obj.offsetParent;
- } while (obj);
- }
- return {'x': x, 'y': y};
-};
-
-// Get mouse event position in DOM element
-Util.getEventPosition = function (e, obj, scale) {
- var evt, docX, docY, pos;
- //if (!e) evt = window.event;
- evt = (e ? e : window.event);
- evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt);
- if (evt.pageX || evt.pageY) {
- docX = evt.pageX;
- docY = evt.pageY;
- } else if (evt.clientX || evt.clientY) {
- docX = evt.clientX + document.body.scrollLeft +
- document.documentElement.scrollLeft;
- docY = evt.clientY + document.body.scrollTop +
- document.documentElement.scrollTop;
- }
- pos = Util.getPosition(obj);
- if (typeof scale === "undefined") {
- scale = 1;
- }
- var x = Math.max(Math.min(docX - pos.x, obj.width-1), 0);
- var y = Math.max(Math.min(docY - pos.y, obj.height-1), 0);
- return {'x': x / scale, 'y': y / scale};
-};
-
-
-// Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events
-Util.addEvent = function (obj, evType, fn){
- if (obj.attachEvent){
- var r = obj.attachEvent("on"+evType, fn);
- return r;
- } else if (obj.addEventListener){
- obj.addEventListener(evType, fn, false);
- return true;
- } else {
- throw("Handler could not be attached");
- }
-};
-
-Util.removeEvent = function(obj, evType, fn){
- if (obj.detachEvent){
- var r = obj.detachEvent("on"+evType, fn);
- return r;
- } else if (obj.removeEventListener){
- obj.removeEventListener(evType, fn, false);
- return true;
- } else {
- throw("Handler could not be removed");
- }
-};
-
-Util.stopEvent = function(e) {
- if (e.stopPropagation) { e.stopPropagation(); }
- else { e.cancelBubble = true; }
-
- if (e.preventDefault) { e.preventDefault(); }
- else { e.returnValue = false; }
-};
-
-
-// Set browser engine versions. Based on mootools.
-Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
-
-Util.Engine = {
- // Version detection break in Opera 11.60 (errors on arguments.callee.caller reference)
- //'presto': (function() {
- // return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
- 'presto': (function() { return (!window.opera) ? false : true; }()),
-
- 'trident': (function() {
- return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()),
- 'webkit': (function() {
- try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()),
- //'webkit': (function() {
- // return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()),
- 'gecko': (function() {
- return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }())
-};
-if (Util.Engine.webkit) {
- // Extract actual webkit version if available
- Util.Engine.webkit = (function(v) {
- var re = new RegExp('WebKit/([0-9\.]*) ');
- v = (navigator.userAgent.match(re) || ['', v])[1];
- return parseFloat(v, 10);
- })(Util.Engine.webkit);
-}
-
-Util.Flash = (function(){
- var v, version;
- try {
- v = navigator.plugins['Shockwave Flash'].description;
- } catch(err1) {
- try {
- v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
- } catch(err2) {
- v = '0 r0';
- }
- }
- version = v.match(/\d+/g);
- return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
-}());
diff --git a/ui/novnc/js/web-socket-js/Makefile.am b/ui/novnc/js/web-socket-js/Makefile.am
deleted file mode 100644
index 26ba1c0..0000000
--- a/ui/novnc/js/web-socket-js/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Kimchi
-#
-# Copyright IBM, Corp. 2013
-#
-# Licensed 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.
-
-websocketdir = $(datadir)/kimchi/ui/novnc/js/web-socket-js
-
-dist_websocket_DATA = \
- swfobject.js \
- WebSocketMain.swf \
- web_socket.js \
- $(NULL)
diff --git a/ui/novnc/js/web-socket-js/README.txt b/ui/novnc/js/web-socket-js/README.txt
deleted file mode 100644
index 91a68cc..0000000
--- a/ui/novnc/js/web-socket-js/README.txt
+++ /dev/null
@@ -1,109 +0,0 @@
-* How to try
-
-Assuming you have Web server (e.g. Apache) running at http://example.com/ .
-
-- Download web_socket.rb from:
- http://github.com/gimite/web-socket-ruby/tree/master
-- Run sample Web Socket server (echo server) in example.com with: (#1)
- $ ruby web-socket-ruby/samples/echo_server.rb example.com 10081
-- If your server already provides socket policy file at port 843, modify the file to allow access to port 10081. Otherwise you can skip this step. See below for details.
-- Publish the web-socket-js directory with your Web server (e.g. put it in ~/public_html).
-- Change ws://localhost:10081 to ws://example.com:10081 in sample.html.
-- Open sample.html in your browser.
-- After "onopen" is shown, input something, click [Send] and confirm echo back.
-
-#1: First argument of echo_server.rb means that it accepts Web Socket connection from HTML pages in example.com.
-
-
-* Troubleshooting
-
-If it doesn't work, try these:
-
-1. Try Chrome and Firefox 3.x.
-- It doesn't work on Chrome:
--- It's likely an issue of your code or the server. Debug your code as usual e.g. using console.log.
-- It works on Chrome but it doesn't work on Firefox:
--- It's likely an issue of web-socket-js specific configuration (e.g. 3 and 4 below).
-- It works on both Chrome and Firefox, but it doesn't work on your browser:
--- Check "Supported environment" section below. Your browser may not be supported by web-socket-js.
-
-2. Add this line before your code:
- WEB_SOCKET_DEBUG = true;
-and use Developer Tools (Chrome/Safari) or Firebug (Firefox) to see if console.log outputs any errors.
-
-3. Make sure you do NOT open your HTML page as local file e.g. file:///.../sample.html. web-socket-js doesn't work on local file. Open it via Web server e.g. http:///.../sample.html.
-
-4. If you are NOT using web-socket-ruby as your WebSocket server, you need to place Flash socket policy file on your server. See "Flash socket policy file" section below for details.
-
-5. Check if sample.html bundled with web-socket-js works.
-
-6. Make sure the port used for WebSocket (10081 in example above) is not blocked by your server/client's firewall.
-
-7. Install debugger version of Flash Player available here to see Flash errors:
-http://www.adobe.com/support/flashplayer/downloads.html
-
-
-* Supported environments
-
-It should work on:
-- Google Chrome 4 or later (just uses native implementation)
-- Firefox 3.x, Internet Explorer 8 + Flash Player 9 or later
-
-It may or may not work on other browsers such as Safari, Opera or IE 6. Patch for these browsers are appreciated, but I will not work on fixing issues specific to these browsers by myself.
-
-
-* Flash socket policy file
-
-This implementation uses Flash's socket, which means that your server must provide Flash socket policy file to declare the server accepts connections from Flash.
-
-If you use web-socket-ruby available at
-http://github.com/gimite/web-socket-ruby/tree/master
-, you don't need anything special, because web-socket-ruby handles Flash socket policy file request. But if you already provide socket policy file at port 843, you need to modify the file to allow access to Web Socket port, because it precedes what web-socket-ruby provides.
-
-If you use other Web Socket server implementation, you need to provide socket policy file yourself. See
-http://www.lightsphere.com/dev/articles/flash_socket_policy.html
-for details and sample script to run socket policy file server. node.js implementation is available here:
-http://github.com/LearnBoost/Socket.IO-node/blob/master/lib/socket.io/transports/flashsocket.js
-
-Actually, it's still better to provide socket policy file at port 843 even if you use web-socket-ruby. Flash always try to connect to port 843 first, so providing the file at port 843 makes startup faster.
-
-
-* Cookie considerations
-
-Cookie is sent if Web Socket host is the same as the origin of JavaScript. Otherwise it is not sent, because I don't know way to send right Cookie (which is Cookie of the host of Web Socket, I heard).
-
-Note that it's technically possible that client sends arbitrary string as Cookie and any other headers (by modifying this library for example) once you place Flash socket policy file in your server. So don't trust Cookie and other headers if you allow connection from untrusted origin.
-
-
-* Proxy considerations
-
-The WebSocket spec (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol) specifies instructions for User Agents to support proxied connections by implementing the HTTP CONNECT method.
-
-The AS3 Socket class doesn't implement this mechanism, which renders it useless for the scenarios where the user trying to open a socket is behind a proxy.
-
-The class RFC2817Socket (by Christian Cantrell) effectively lets us implement this, as long as the proxy settings are known and provided by the interface that instantiates the WebSocket. As such, if you want to support proxied conncetions, you'll have to supply this information to the WebSocket constructor when Flash is being used. One way to go about it would be to ask the user for proxy settings information if the initial connection fails.
-
-
-* How to host HTML file and SWF file in different domains
-
-By default, HTML file and SWF file must be in the same domain. You can follow steps below to allow hosting them in different domain.
-
-WARNING: If you use the method below, HTML files in ANY domains can send arbitrary TCP data to your WebSocket server, regardless of configuration in Flash socket policy file. Arbitrary TCP data means that they can even fake request headers including Origin and Cookie.
-
-- Unzip WebSocketMainInsecure.zip to extract WebSocketMainInsecure.swf.
-- Put WebSocketMainInsecure.swf on your server, instead of WebSocketMain.swf.
-- In JavaScript, set WEB_SOCKET_SWF_LOCATION to URL of your WebSocketMainInsecure.swf.
-
-
-* How to build WebSocketMain.swf
-
-Install Flex 4 SDK:
-http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4
-
-$ cd flash-src
-$ ./build.sh
-
-
-* License
-
-New BSD License.
diff --git a/ui/novnc/js/web-socket-js/WebSocketMain.swf b/ui/novnc/js/web-socket-js/WebSocketMain.swf
deleted file mode 100644
index 8174466912475a494681e9436844f4bf90d909f9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 177114
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�{?S0&?Rq)c&c-(}SFHOPy4tz`b5gun?zakh{
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	hoe8>6)Ss!@E`XyN(WVfR)gw|2I
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
G)Bgi3fUR8s
diff --git a/ui/novnc/js/web-socket-js/swfobject.js b/ui/novnc/js/web-socket-js/swfobject.js
deleted file mode 100644
index 02055f2..0000000
--- a/ui/novnc/js/web-socket-js/swfobject.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/* SWFObject v2.2 <http://code.google.com/p/swfobject/>
- is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
-*/
-var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replac!
diff --git a/ui/novnc/js/web-socket-js/web_socket.js b/ui/novnc/js/web-socket-js/web_socket.js
deleted file mode 100644
index a7828fa..0000000
--- a/ui/novnc/js/web-socket-js/web_socket.js
+++ /dev/null
@@ -1,391 +0,0 @@
-// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
-// License: New BSD License
-// Reference: http://dev.w3.org/html5/websockets/
-// Reference: http://tools.ietf.org/html/rfc6455
-
-(function() {
-
- if (window.WEB_SOCKET_FORCE_FLASH) {
- // Keeps going.
- } else if (window.WebSocket) {
- return;
- } else if (window.MozWebSocket) {
- // Firefox.
- window.WebSocket = MozWebSocket;
- return;
- }
-
- var logger;
- if (window.WEB_SOCKET_LOGGER) {
- logger = WEB_SOCKET_LOGGER;
- } else if (window.console && window.console.log && window.console.error) {
- // In some environment, console is defined but console.log or console.error is missing.
- logger = window.console;
- } else {
- logger = {log: function(){ }, error: function(){ }};
- }
-
- // swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash.
- if (swfobject.getFlashPlayerVersion().major < 10) {
- logger.error("Flash Player >= 10.0.0 is required.");
- return;
- }
- if (location.protocol == "file:") {
- logger.error(
- "WARNING: web-socket-js doesn't work in file:///... URL " +
- "unless you set Flash Security Settings properly. " +
- "Open the page via Web server i.e. http://...");
- }
-
- /**
- * Our own implementation of WebSocket class using Flash.
- * @param {string} url
- * @param {array or string} protocols
- * @param {string} proxyHost
- * @param {int} proxyPort
- * @param {string} headers
- */
- window.WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
- var self = this;
- self.__id = WebSocket.__nextId++;
- WebSocket.__instances[self.__id] = self;
- self.readyState = WebSocket.CONNECTING;
- self.bufferedAmount = 0;
- self.__events = {};
- if (!protocols) {
- protocols = [];
- } else if (typeof protocols == "string") {
- protocols = [protocols];
- }
- // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
- // Otherwise, when onopen fires immediately, onopen is called before it is set.
- self.__createTask = setTimeout(function() {
- WebSocket.__addTask(function() {
- self.__createTask = null;
- WebSocket.__flash.create(
- self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
- });
- }, 0);
- };
-
- /**
- * Send data to the web socket.
- * @param {string} data The data to send to the socket.
- * @return {boolean} True for success, false for failure.
- */
- WebSocket.prototype.send = function(data) {
- if (this.readyState == WebSocket.CONNECTING) {
- throw "INVALID_STATE_ERR: Web Socket connection has not been established";
- }
- // We use encodeURIComponent() here, because FABridge doesn't work if
- // the argument includes some characters. We don't use escape() here
- // because of this:
- // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape…
- // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
- // preserve all Unicode characters either e.g. "\uffff" in Firefox.
- // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
- // additional testing.
- var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
- if (result < 0) { // success
- return true;
- } else {
- this.bufferedAmount += result;
- return false;
- }
- };
-
- /**
- * Close this web socket gracefully.
- */
- WebSocket.prototype.close = function() {
- if (this.__createTask) {
- clearTimeout(this.__createTask);
- this.__createTask = null;
- this.readyState = WebSocket.CLOSED;
- return;
- }
- if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
- return;
- }
- this.readyState = WebSocket.CLOSING;
- WebSocket.__flash.close(this.__id);
- };
-
- /**
- * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
- *
- * @param {string} type
- * @param {function} listener
- * @param {boolean} useCapture
- * @return void
- */
- WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
- if (!(type in this.__events)) {
- this.__events[type] = [];
- }
- this.__events[type].push(listener);
- };
-
- /**
- * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
- *
- * @param {string} type
- * @param {function} listener
- * @param {boolean} useCapture
- * @return void
- */
- WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
- if (!(type in this.__events)) return;
- var events = this.__events[type];
- for (var i = events.length - 1; i >= 0; --i) {
- if (events[i] === listener) {
- events.splice(i, 1);
- break;
- }
- }
- };
-
- /**
- * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
- *
- * @param {Event} event
- * @return void
- */
- WebSocket.prototype.dispatchEvent = function(event) {
- var events = this.__events[event.type] || [];
- for (var i = 0; i < events.length; ++i) {
- events[i](event);
- }
- var handler = this["on" + event.type];
- if (handler) handler.apply(this, [event]);
- };
-
- /**
- * Handles an event from Flash.
- * @param {Object} flashEvent
- */
- WebSocket.prototype.__handleEvent = function(flashEvent) {
-
- if ("readyState" in flashEvent) {
- this.readyState = flashEvent.readyState;
- }
- if ("protocol" in flashEvent) {
- this.protocol = flashEvent.protocol;
- }
-
- var jsEvent;
- if (flashEvent.type == "open" || flashEvent.type == "error") {
- jsEvent = this.__createSimpleEvent(flashEvent.type);
- } else if (flashEvent.type == "close") {
- jsEvent = this.__createSimpleEvent("close");
- jsEvent.wasClean = flashEvent.wasClean ? true : false;
- jsEvent.code = flashEvent.code;
- jsEvent.reason = flashEvent.reason;
- } else if (flashEvent.type == "message") {
- var data = decodeURIComponent(flashEvent.message);
- jsEvent = this.__createMessageEvent("message", data);
- } else {
- throw "unknown event type: " + flashEvent.type;
- }
-
- this.dispatchEvent(jsEvent);
-
- };
-
- WebSocket.prototype.__createSimpleEvent = function(type) {
- if (document.createEvent && window.Event) {
- var event = document.createEvent("Event");
- event.initEvent(type, false, false);
- return event;
- } else {
- return {type: type, bubbles: false, cancelable: false};
- }
- };
-
- WebSocket.prototype.__createMessageEvent = function(type, data) {
- if (document.createEvent && window.MessageEvent && !window.opera) {
- var event = document.createEvent("MessageEvent");
- event.initMessageEvent("message", false, false, data, null, null, window, null);
- return event;
- } else {
- // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
- return {type: type, data: data, bubbles: false, cancelable: false};
- }
- };
-
- /**
- * Define the WebSocket readyState enumeration.
- */
- WebSocket.CONNECTING = 0;
- WebSocket.OPEN = 1;
- WebSocket.CLOSING = 2;
- WebSocket.CLOSED = 3;
-
- // Field to check implementation of WebSocket.
- WebSocket.__isFlashImplementation = true;
- WebSocket.__initialized = false;
- WebSocket.__flash = null;
- WebSocket.__instances = {};
- WebSocket.__tasks = [];
- WebSocket.__nextId = 0;
-
- /**
- * Load a new flash security policy file.
- * @param {string} url
- */
- WebSocket.loadFlashPolicyFile = function(url){
- WebSocket.__addTask(function() {
- WebSocket.__flash.loadManualPolicyFile(url);
- });
- };
-
- /**
- * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
- */
- WebSocket.__initialize = function() {
-
- if (WebSocket.__initialized) return;
- WebSocket.__initialized = true;
-
- if (WebSocket.__swfLocation) {
- // For backword compatibility.
- window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
- }
- if (!window.WEB_SOCKET_SWF_LOCATION) {
- logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
- return;
- }
- if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR &&
- !WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) &&
- WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) {
- var swfHost = RegExp.$1;
- if (location.host != swfHost) {
- logger.error(
- "[WebSocket] You must host HTML and WebSocketMain.swf in the same host " +
- "('" + location.host + "' != '" + swfHost + "'). " +
- "See also 'How to host HTML file and SWF file in different domains' section " +
- "in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " +
- "by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;");
- }
- }
- var container = document.createElement("div");
- container.id = "webSocketContainer";
- // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
- // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
- // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
- // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
- // the best we can do as far as we know now.
- container.style.position = "absolute";
- if (WebSocket.__isFlashLite()) {
- container.style.left = "0px";
- container.style.top = "0px";
- } else {
- container.style.left = "-100px";
- container.style.top = "-100px";
- }
- var holder = document.createElement("div");
- holder.id = "webSocketFlash";
- container.appendChild(holder);
- document.body.appendChild(container);
- // See this article for hasPriority:
- // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc…
- swfobject.embedSWF(
- WEB_SOCKET_SWF_LOCATION,
- "webSocketFlash",
- "1" /* width */,
- "1" /* height */,
- "10.0.0" /* SWF version */,
- null,
- null,
- {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
- null,
- function(e) {
- if (!e.success) {
- logger.error("[WebSocket] swfobject.embedSWF failed");
- }
- }
- );
-
- };
-
- /**
- * Called by Flash to notify JS that it's fully loaded and ready
- * for communication.
- */
- WebSocket.__onFlashInitialized = function() {
- // We need to set a timeout here to avoid round-trip calls
- // to flash during the initialization process.
- setTimeout(function() {
- WebSocket.__flash = document.getElementById("webSocketFlash");
- WebSocket.__flash.setCallerUrl(location.href);
- WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
- for (var i = 0; i < WebSocket.__tasks.length; ++i) {
- WebSocket.__tasks[i]();
- }
- WebSocket.__tasks = [];
- }, 0);
- };
-
- /**
- * Called by Flash to notify WebSockets events are fired.
- */
- WebSocket.__onFlashEvent = function() {
- setTimeout(function() {
- try {
- // Gets events using receiveEvents() instead of getting it from event object
- // of Flash event. This is to make sure to keep message order.
- // It seems sometimes Flash events don't arrive in the same order as they are sent.
- var events = WebSocket.__flash.receiveEvents();
- for (var i = 0; i < events.length; ++i) {
- WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
- }
- } catch (e) {
- logger.error(e);
- }
- }, 0);
- return true;
- };
-
- // Called by Flash.
- WebSocket.__log = function(message) {
- logger.log(decodeURIComponent(message));
- };
-
- // Called by Flash.
- WebSocket.__error = function(message) {
- logger.error(decodeURIComponent(message));
- };
-
- WebSocket.__addTask = function(task) {
- if (WebSocket.__flash) {
- task();
- } else {
- WebSocket.__tasks.push(task);
- }
- };
-
- /**
- * Test if the browser is running flash lite.
- * @return {boolean} True if flash lite is running, false otherwise.
- */
- WebSocket.__isFlashLite = function() {
- if (!window.navigator || !window.navigator.mimeTypes) {
- return false;
- }
- var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
- if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
- return false;
- }
- return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
- };
-
- if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
- // NOTE:
- // This fires immediately if web_socket.js is dynamically loaded after
- // the document is loaded.
- swfobject.addDomLoadEvent(function() {
- WebSocket.__initialize();
- });
- }
-
-})();
diff --git a/ui/novnc/js/websock.js b/ui/novnc/js/websock.js
deleted file mode 100644
index 2a2080f..0000000
--- a/ui/novnc/js/websock.js
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Websock: high-performance binary WebSockets
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * Websock is similar to the standard WebSocket object but Websock
- * enables communication with raw TCP sockets (i.e. the binary stream)
- * via websockify. This is accomplished by base64 encoding the data
- * stream between Websock and websockify.
- *
- * Websock has built-in receive queue buffering; the message event
- * does not contain actual data but is simply a notification that
- * there is new data available. Several rQ* methods are available to
- * read binary data off of the receive queue.
- */
-
-/*jslint browser: true, bitwise: false, plusplus: false */
-/*global Util, Base64 */
-
-
-// Load Flash WebSocket emulator if needed
-
-// To force WebSocket emulator even when native WebSocket available
-//window.WEB_SOCKET_FORCE_FLASH = true;
-// To enable WebSocket emulator debug:
-//window.WEB_SOCKET_DEBUG=1;
-
-if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
- Websock_native = true;
-} else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
- Websock_native = true;
- window.WebSocket = window.MozWebSocket;
-} else {
- /* no builtin WebSocket so load web_socket.js */
-
- Websock_native = false;
- (function () {
- window.WEB_SOCKET_SWF_LOCATION = Util.get_include_uri() +
- "web-socket-js/WebSocketMain.swf";
- if (Util.Engine.trident) {
- Util.Debug("Forcing uncached load of WebSocketMain.swf");
- window.WEB_SOCKET_SWF_LOCATION += "?" + Math.random();
- }
- Util.load_scripts(["web-socket-js/swfobject.js",
- "web-socket-js/web_socket.js"]);
- }());
-}
-
-
-function Websock() {
-"use strict";
-
-var api = {}, // Public API
- websocket = null, // WebSocket object
- mode = 'base64', // Current WebSocket mode: 'binary', 'base64'
- rQ = [], // Receive queue
- rQi = 0, // Receive queue index
- rQmax = 10000, // Max receive queue size before compacting
- sQ = [], // Send queue
-
- eventHandlers = {
- 'message' : function() {},
- 'open' : function() {},
- 'close' : function() {},
- 'error' : function() {}
- },
-
- test_mode = false;
-
-
-//
-// Queue public functions
-//
-
-function get_sQ() {
- return sQ;
-}
-
-function get_rQ() {
- return rQ;
-}
-function get_rQi() {
- return rQi;
-}
-function set_rQi(val) {
- rQi = val;
-}
-
-function rQlen() {
- return rQ.length - rQi;
-}
-
-function rQpeek8() {
- return (rQ[rQi] );
-}
-function rQshift8() {
- return (rQ[rQi++] );
-}
-function rQunshift8(num) {
- if (rQi === 0) {
- rQ.unshift(num);
- } else {
- rQi -= 1;
- rQ[rQi] = num;
- }
-
-}
-function rQshift16() {
- return (rQ[rQi++] << 8) +
- (rQ[rQi++] );
-}
-function rQshift32() {
- return (rQ[rQi++] << 24) +
- (rQ[rQi++] << 16) +
- (rQ[rQi++] << 8) +
- (rQ[rQi++] );
-}
-function rQshiftStr(len) {
- if (typeof(len) === 'undefined') { len = rQlen(); }
- var arr = rQ.slice(rQi, rQi + len);
- rQi += len;
- return String.fromCharCode.apply(null, arr);
-}
-function rQshiftBytes(len) {
- if (typeof(len) === 'undefined') { len = rQlen(); }
- rQi += len;
- return rQ.slice(rQi-len, rQi);
-}
-
-function rQslice(start, end) {
- if (end) {
- return rQ.slice(rQi + start, rQi + end);
- } else {
- return rQ.slice(rQi + start);
- }
-}
-
-// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
-// to be available in the receive queue. Return true if we need to
-// wait (and possibly print a debug message), otherwise false.
-function rQwait(msg, num, goback) {
- var rQlen = rQ.length - rQi; // Skip rQlen() function call
- if (rQlen < num) {
- if (goback) {
- if (rQi < goback) {
- throw("rQwait cannot backup " + goback + " bytes");
- }
- rQi -= goback;
- }
- //Util.Debug(" waiting for " + (num-rQlen) +
- // " " + msg + " byte(s)");
- return true; // true means need more data
- }
- return false;
-}
-
-//
-// Private utility routines
-//
-
-function encode_message() {
- if (mode === 'binary') {
- // Put in a binary arraybuffer
- return (new Uint8Array(sQ)).buffer;
- } else {
- // base64 encode
- return Base64.encode(sQ);
- }
-}
-
-function decode_message(data) {
- //Util.Debug(">> decode_message: " + data);
- if (mode === 'binary') {
- // push arraybuffer values onto the end
- var u8 = new Uint8Array(data);
- for (var i = 0; i < u8.length; i++) {
- rQ.push(u8[i]);
- }
- } else {
- // base64 decode and concat to the end
- rQ = rQ.concat(Base64.decode(data, 0));
- }
- //Util.Debug(">> decode_message, rQ: " + rQ);
-}
-
-
-//
-// Public Send functions
-//
-
-function flush() {
- if (websocket.bufferedAmount !== 0) {
- Util.Debug("bufferedAmount: " + websocket.bufferedAmount);
- }
- if (websocket.bufferedAmount < api.maxBufferedAmount) {
- //Util.Debug("arr: " + arr);
- //Util.Debug("sQ: " + sQ);
- if (sQ.length > 0) {
- websocket.send(encode_message(sQ));
- sQ = [];
- }
- return true;
- } else {
- Util.Info("Delaying send, bufferedAmount: " +
- websocket.bufferedAmount);
- return false;
- }
-}
-
-// overridable for testing
-function send(arr) {
- //Util.Debug(">> send_array: " + arr);
- sQ = sQ.concat(arr);
- return flush();
-}
-
-function send_string(str) {
- //Util.Debug(">> send_string: " + str);
- api.send(str.split('').map(
- function (chr) { return chr.charCodeAt(0); } ) );
-}
-
-//
-// Other public functions
-
-function recv_message(e) {
- //Util.Debug(">> recv_message: " + e.data.length);
-
- try {
- decode_message(e.data);
- if (rQlen() > 0) {
- eventHandlers.message();
- // Compact the receive queue
- if (rQ.length > rQmax) {
- //Util.Debug("Compacting receive queue");
- rQ = rQ.slice(rQi);
- rQi = 0;
- }
- } else {
- Util.Debug("Ignoring empty message");
- }
- } catch (exc) {
- if (typeof exc.stack !== 'undefined') {
- Util.Warn("recv_message, caught exception: " + exc.stack);
- } else if (typeof exc.description !== 'undefined') {
- Util.Warn("recv_message, caught exception: " + exc.description);
- } else {
- Util.Warn("recv_message, caught exception:" + exc);
- }
- if (typeof exc.name !== 'undefined') {
- eventHandlers.error(exc.name + ": " + exc.message);
- } else {
- eventHandlers.error(exc);
- }
- }
- //Util.Debug("<< recv_message");
-}
-
-
-// Set event handlers
-function on(evt, handler) {
- eventHandlers[evt] = handler;
-}
-
-function init(protocols) {
- rQ = [];
- rQi = 0;
- sQ = [];
- websocket = null;
-
- var bt = false,
- wsbt = false,
- try_binary = false;
-
- // Check for full typed array support
- if (('Uint8Array' in window) &&
- ('set' in Uint8Array.prototype)) {
- bt = true;
- }
-
- // Check for full binary type support in WebSockets
- // TODO: this sucks, the property should exist on the prototype
- // but it does not.
- //try {
- // if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) {
- // Util.Info("Detected binaryType support in WebSockets");
- wsbt = true;
- // }
- //} catch (exc) {
- // // Just ignore failed test localhost connections
- //}
-
- // Default protocols if not specified
- if (typeof(protocols) === "undefined") {
- if (wsbt) {
- protocols = ['binary', 'base64'];
- } else {
- protocols = 'base64';
- }
- }
-
- // If no binary support, make sure it was not requested
- if (!wsbt) {
- if (protocols === 'binary') {
- throw("WebSocket binary sub-protocol requested but not supported");
- }
- if (typeof(protocols) === "object") {
- var new_protocols = [];
- for (var i = 0; i < protocols.length; i++) {
- if (protocols[i] === 'binary') {
- Util.Error("Skipping unsupported WebSocket binary sub-protocol");
- } else {
- new_protocols.push(protocols[i]);
- }
- }
- if (new_protocols.length > 0) {
- protocols = new_protocols;
- } else {
- throw("Only WebSocket binary sub-protocol was requested and not supported.");
- }
- }
- }
-
- return protocols;
-}
-
-function open(uri, protocols) {
- protocols = init(protocols);
-
- if (test_mode) {
- websocket = {};
- } else {
- websocket = new WebSocket(uri, protocols);
- if (protocols.indexOf('binary') >= 0) {
- websocket.binaryType = 'arraybuffer';
- }
- }
-
- websocket.onmessage = recv_message;
- websocket.onopen = function() {
- Util.Debug(">> WebSock.onopen");
- if (websocket.protocol) {
- mode = websocket.protocol;
- Util.Info("Server chose sub-protocol: " + websocket.protocol);
- } else {
- mode = 'base64';
- Util.Error("Server select no sub-protocol!: " + websocket.protocol);
- }
- eventHandlers.open();
- Util.Debug("<< WebSock.onopen");
- };
- websocket.onclose = function(e) {
- Util.Debug(">> WebSock.onclose");
- eventHandlers.close(e);
- Util.Debug("<< WebSock.onclose");
- };
- websocket.onerror = function(e) {
- Util.Debug(">> WebSock.onerror: " + e);
- eventHandlers.error(e);
- Util.Debug("<< WebSock.onerror");
- };
-}
-
-function close() {
- if (websocket) {
- if ((websocket.readyState === WebSocket.OPEN) ||
- (websocket.readyState === WebSocket.CONNECTING)) {
- Util.Info("Closing WebSocket connection");
- websocket.close();
- }
- websocket.onmessage = function (e) { return; };
- }
-}
-
-// Override internal functions for testing
-// Takes a send function, returns reference to recv function
-function testMode(override_send, data_mode) {
- test_mode = true;
- mode = data_mode;
- api.send = override_send;
- api.close = function () {};
- return recv_message;
-}
-
-function constructor() {
- // Configuration settings
- api.maxBufferedAmount = 200;
-
- // Direct access to send and receive queues
- api.get_sQ = get_sQ;
- api.get_rQ = get_rQ;
- api.get_rQi = get_rQi;
- api.set_rQi = set_rQi;
-
- // Routines to read from the receive queue
- api.rQlen = rQlen;
- api.rQpeek8 = rQpeek8;
- api.rQshift8 = rQshift8;
- api.rQunshift8 = rQunshift8;
- api.rQshift16 = rQshift16;
- api.rQshift32 = rQshift32;
- api.rQshiftStr = rQshiftStr;
- api.rQshiftBytes = rQshiftBytes;
- api.rQslice = rQslice;
- api.rQwait = rQwait;
-
- api.flush = flush;
- api.send = send;
- api.send_string = send_string;
-
- api.on = on;
- api.init = init;
- api.open = open;
- api.close = close;
- api.testMode = testMode;
-
- return api;
-}
-
-return constructor();
-
-}
diff --git a/ui/novnc/js/webutil.js b/ui/novnc/js/webutil.js
deleted file mode 100644
index c0d4819..0000000
--- a/ui/novnc/js/webutil.js
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-"use strict";
-/*jslint bitwise: false, white: false */
-/*global Util, window, document */
-
-// Globals defined here
-var WebUtil = {}, $D;
-
-/*
- * Simple DOM selector by ID
- */
-if (!window.$D) {
- window.$D = function (id) {
- if (document.getElementById) {
- return document.getElementById(id);
- } else if (document.all) {
- return document.all[id];
- } else if (document.layers) {
- return document.layers[id];
- }
- return undefined;
- };
-}
-
-
-/*
- * ------------------------------------------------------
- * Namespaced in WebUtil
- * ------------------------------------------------------
- */
-
-// init log level reading the logging HTTP param
-WebUtil.init_logging = function(level) {
- if (typeof level !== "undefined") {
- Util._log_level = level;
- } else {
- Util._log_level = (document.location.href.match(
- /logging=([A-Za-z0-9\._\-]*)/) ||
- ['', Util._log_level])[1];
- }
- Util.init_logging();
-};
-
-
-WebUtil.dirObj = function (obj, depth, parent) {
- var i, msg = "", val = "";
- if (! depth) { depth=2; }
- if (! parent) { parent= ""; }
-
- // Print the properties of the passed-in object
- for (i in obj) {
- if ((depth > 1) && (typeof obj[i] === "object")) {
- // Recurse attributes that are objects
- msg += WebUtil.dirObj(obj[i], depth-1, parent + "." + i);
- } else {
- //val = new String(obj[i]).replace("\n", " ");
- if (typeof(obj[i]) === "undefined") {
- val = "undefined";
- } else {
- val = obj[i].toString().replace("\n", " ");
- }
- if (val.length > 30) {
- val = val.substr(0,30) + "...";
- }
- msg += parent + "." + i + ": " + val + "\n";
- }
- }
- return msg;
-};
-
-// Read a query string variable
-WebUtil.getQueryVar = function(name, defVal) {
- var re = new RegExp('[?][^#]*' + name + '=([^&#]*)'),
- match = document.location.href.match(re);
- if (typeof defVal === 'undefined') { defVal = null; }
- if (match) {
- return decodeURIComponent(match[1]);
- } else {
- return defVal;
- }
-};
-
-
-/*
- * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
- */
-
-// No days means only for this browser session
-WebUtil.createCookie = function(name,value,days) {
- var date, expires;
- if (days) {
- date = new Date();
- date.setTime(date.getTime()+(days*24*60*60*1000));
- expires = "; expires="+date.toGMTString();
- }
- else {
- expires = "";
- }
- document.cookie = name+"="+value+expires+"; path=/";
-};
-
-WebUtil.readCookie = function(name, defaultValue) {
- var i, c, nameEQ = name + "=", ca = document.cookie.split(';');
- for(i=0; i < ca.length; i += 1) {
- c = ca[i];
- while (c.charAt(0) === ' ') { c = c.substring(1,c.length); }
- if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); }
- }
- return (typeof defaultValue !== 'undefined') ? defaultValue : null;
-};
-
-WebUtil.eraseCookie = function(name) {
- WebUtil.createCookie(name,"",-1);
-};
-
-/*
- * Setting handling.
- */
-
-WebUtil.initSettings = function(callback) {
- var callbackArgs = Array.prototype.slice.call(arguments, 1);
- if (window.chrome && window.chrome.storage) {
- window.chrome.storage.sync.get(function (cfg) {
- WebUtil.settings = cfg;
- console.log(WebUtil.settings);
- if (callback) {
- callback.apply(this, callbackArgs);
- }
- });
- } else {
- // No-op
- if (callback) {
- callback.apply(this, callbackArgs);
- }
- }
-};
-
-// No days means only for this browser session
-WebUtil.writeSetting = function(name, value) {
- if (window.chrome && window.chrome.storage) {
- //console.log("writeSetting:", name, value);
- if (WebUtil.settings[name] !== value) {
- WebUtil.settings[name] = value;
- window.chrome.storage.sync.set(WebUtil.settings);
- }
- } else {
- localStorage.setItem(name, value);
- }
-};
-
-WebUtil.readSetting = function(name, defaultValue) {
- var value;
- if (window.chrome && window.chrome.storage) {
- value = WebUtil.settings[name];
- } else {
- value = localStorage.getItem(name);
- }
- if (typeof value === "undefined") {
- value = null;
- }
- if (value === null && typeof defaultValue !== undefined) {
- return defaultValue;
- } else {
- return value;
- }
-};
-
-WebUtil.eraseSetting = function(name) {
- if (window.chrome && window.chrome.storage) {
- window.chrome.storage.sync.remove(name);
- delete WebUtil.settings[name];
- } else {
- localStorage.removeItem(name);
- }
-};
-
-/*
- * Alternate stylesheet selection
- */
-WebUtil.getStylesheets = function() { var i, links, sheets = [];
- links = document.getElementsByTagName("link");
- for (i = 0; i < links.length; i += 1) {
- if (links[i].title &&
- links[i].rel.toUpperCase().indexOf("STYLESHEET") > -1) {
- sheets.push(links[i]);
- }
- }
- return sheets;
-};
-
-// No sheet means try and use value from cookie, null sheet used to
-// clear all alternates.
-WebUtil.selectStylesheet = function(sheet) {
- var i, link, sheets = WebUtil.getStylesheets();
- if (typeof sheet === 'undefined') {
- sheet = 'default';
- }
- for (i=0; i < sheets.length; i += 1) {
- link = sheets[i];
- if (link.title === sheet) {
- Util.Debug("Using stylesheet " + sheet);
- link.disabled = false;
- } else {
- //Util.Debug("Skipping stylesheet " + link.title);
- link.disabled = true;
- }
- }
- return sheet;
-};
diff --git a/ui/novnc/vnc.html b/ui/novnc/vnc.html
deleted file mode 100644
index 1f4355c..0000000
--- a/ui/novnc/vnc.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<html>
- <!--
- noVNC example: simple example using default UI
- Copyright (C) 2012 Joel Martin
- noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
- This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
-
- Connect parameters are provided in query string:
- http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
- -->
- <head>
- <title>noVNC</title>
- <meta http-equiv="X-UA-Compatible" content="chrome=1">
- <link rel="stylesheet" href="css/base.css" title="plain">
- <script type='text/javascript'>
- var INCLUDE_URI = "js/";
- </script>
- <!--
- <script type='text/javascript'
- src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
- -->
- <script src="js/util.js"></script>
- </head>
-
- <body style="margin: 0px;">
- <div id="noVNC_screen">
- <div id="noVNC_status_bar" class="noVNC_status_bar" style="margin-top: 0px;">
- <table border=0 width="100%"><tr>
- <td><div id="noVNC_status">Loading</div></td>
- <td width="1%"><div id="noVNC_buttons">
- <input type=button value="Send CtrlAltDel"
- id="sendCtrlAltDelButton">
- </div></td>
- </tr></table>
- </div>
- <canvas id="noVNC_canvas" width="640px" height="20px">
- Canvas not supported.
- </canvas>
- </div>
- <script src="js/main.js"></script>
- </body>
-</html>
diff --git a/ui/pages/vnc_auto.html.tmpl b/ui/pages/vnc_auto.html.tmpl
new file mode 100644
index 0000000..0078190
--- /dev/null
+++ b/ui/pages/vnc_auto.html.tmpl
@@ -0,0 +1,44 @@
+#from kimchi.cachebust import href
+<!DOCTYPE html>
+<html>
+ <!--
+ noVNC example: simple example using default UI
+ Copyright (C) 2012 Joel Martin
+ noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
+ This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
+
+ Connect parameters are provided in query string:
+ http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
+ -->
+ <head>
+ <title>noVNC</title>
+ <meta http-equiv="X-UA-Compatible" content="chrome=1">
+ <link rel="stylesheet" href="$href("/css/novnc/base.css")" title="plain">
+ <script type='text/javascript'>
+ var INCLUDE_URI = "/js/novnc/";
+ </script>
+ <!--
+ <script type='text/javascript'
+ src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+ -->
+ <script src="$href("/js/novnc/util.js")"></script>
+ </head>
+
+ <body style="margin: 0px;">
+ <div id="noVNC_screen">
+ <div id="noVNC_status_bar" class="noVNC_status_bar" style="margin-top: 0px;">
+ <table border=0 width="100%"><tr>
+ <td><div id="noVNC_status">Loading</div></td>
+ <td width="1%"><div id="noVNC_buttons">
+ <input type=button value="Send CtrlAltDel"
+ id="sendCtrlAltDelButton">
+ </div></td>
+ </tr></table>
+ </div>
+ <canvas id="noVNC_canvas" width="640px" height="20px">
+ Canvas not supported.
+ </canvas>
+ </div>
+ <script src="$href("/js/novnc/main.js")"></script>
+ </body>
+</html>
--
1.7.10.4
1
0