Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
94
Merge Requests
10
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
A prog2-höz tartozó friss repo anyagok itt elérhetőek:
https://git.iit.bme.hu/
Commit
743f544f
authored
Sep 04, 2013
by
Bach Dániel
Committed by
cloud
Sep 05, 2013
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dashboard: add initial novnc console
parent
bbd57489
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
7656 additions
and
7 deletions
+7656
-7
circle/dashboard/static/dashboard/novnc/base64.js
+115
-0
circle/dashboard/static/dashboard/novnc/des.js
+273
-0
circle/dashboard/static/dashboard/novnc/display.js
+770
-0
circle/dashboard/static/dashboard/novnc/input.js
+1980
-0
circle/dashboard/static/dashboard/novnc/jsunzip.js
+676
-0
circle/dashboard/static/dashboard/novnc/logo.js
+1
-0
circle/dashboard/static/dashboard/novnc/playback.js
+102
-0
circle/dashboard/static/dashboard/novnc/rfb.js
+1872
-0
circle/dashboard/static/dashboard/novnc/ui.js
+761
-0
circle/dashboard/static/dashboard/novnc/util.js
+383
-0
circle/dashboard/static/dashboard/novnc/websock.js
+422
-0
circle/dashboard/static/dashboard/novnc/webutil.js
+216
-0
circle/dashboard/templates/dashboard/vm-detail-console.html
+79
-1
circle/dashboard/templates/dashboard/vm-detail.html
+2
-2
circle/dashboard/urls.py
+4
-4
No files found.
circle/dashboard/static/dashboard/novnc/base64.js
0 → 100644
View file @
743f544f
/* 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/jint/sunspider/string-base64.js
/*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 */
circle/dashboard/static/dashboard/novnc/des.js
0 → 100644
View file @
743f544f
/*
* 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@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@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
circle/dashboard/static/dashboard/novnc/display.js
0 → 100644
View file @
743f544f
/*
* 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);
}
circle/dashboard/static/dashboard/novnc/input.js
0 → 100644
View file @
743f544f
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
* 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
;
var
doubleClickTimer
=
null
,
lastTouchPos
=
null
;
// 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
resetDoubleClickTimer
()
{
doubleClickTimer
=
null
;
}
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
// When two touches occur within 500 ms of each other and are
// closer than 20 pixels together a double click is triggered.
if
(
down
==
1
)
{
if
(
doubleClickTimer
==
null
)
{
lastTouchPos
=
pos
;
}
else
{
clearTimeout
(
doubleClickTimer
);
// When the distance between the two touches is small enough
// force the position of the latter touch to the position of
// the first.
var
xs
=
lastTouchPos
.
x
-
pos
.
x
;
var
ys
=
lastTouchPos
.
y
-
pos
.
y
;
var
d
=
Math
.
sqrt
((
xs
*
xs
)
+
(
ys
*
ys
));
// The goal is to trigger on a certain physical width, the
// devicePixelRatio brings us a bit closer but is not optimal.
if
(
d
<
20
*
window
.
devicePixelRatio
)
{
pos
=
lastTouchPos
;
}
}
doubleClickTimer
=
setTimeout
(
resetDoubleClickTimer
,
500
);
}
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
(
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
.
realx
>=
0
)
&&
(
pos
.
realy
>=
0
)
&&
(
pos
.
realx
<
conf
.
target
.
offsetWidth
)
&&
(
pos
.
realy
<
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
};
circle/dashboard/static/dashboard/novnc/jsunzip.js
0 → 100755
View file @
743f544f
/*
* 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@opera.com
*
* read_bits() patched by mike@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
};
}
};
circle/dashboard/static/dashboard/novnc/logo.js
0 → 100644
View file @
743f544f
noVNC_logo
=
{
"width"
:
640
,
"height"
:
435
,
"data"
:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAGzCAYAAAC/y6a9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAStAAAErQBBHTWggAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7N13fBvlwQfw3522ZMm2vPdIGCFkA4GyoYyGsCmjk+7dQksHL2/H2/dtC4W2tLTlfelu2VA2lEILFCgQIHEGJCQkdjzkLdmWZGvfvX8oOkmJEy/pNO73/Xz44DtLzz2RT7qfnnXC8uXLZUxDlqfdnUYQhIP+bjbPn+5xhypzrmUf6rGzOc5cjzVduXN9/nTPyfRrMt/jzOcY05U5n3L2f95s/34LPW4m/p6FbLp/73xe+5nKnWuZs/07ZOOcnusx5nucbJU727LneuxslDmdTBxn/2NmusyEuZS7kHMxG/XP5Gf3TOVmQzY+u/PhPMnkMcSsH5WIiIiI8goDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHG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"
};
circle/dashboard/static/dashboard/novnc/playback.js
0 → 100644
View file @
743f544f
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
* Licensed under MPL 2.0 (see LICENSE.txt)
*/
"use strict"
;
/*jslint browser: true, white: false */
/*global Util, VNC_frame_data, finish */
var
rfb
,
mode
,
test_state
,
frame_idx
,
frame_length
,
iteration
,
iterations
,
istart_time
,
// Pre-declarations for jslint
send_array
,
next_iteration
,
queue_next_packet
,
do_packet
;
// Override send_array
send_array
=
function
(
arr
)
{
// Stub out send_array
};
next_iteration
=
function
()
{
if
(
iteration
===
0
)
{
frame_length
=
VNC_frame_data
.
length
;
test_state
=
'running'
;
}
else
{
rfb
.
disconnect
();
}
if
(
test_state
!==
'running'
)
{
return
;
}
iteration
+=
1
;
if
(
iteration
>
iterations
)
{
finish
();
return
;
}
frame_idx
=
0
;
istart_time
=
(
new
Date
()).
getTime
();
rfb
.
connect
(
'test'
,
0
,
"bogus"
);
queue_next_packet
();
};
queue_next_packet
=
function
()
{
var
frame
,
foffset
,
toffset
,
delay
;
if
(
test_state
!==
'running'
)
{
return
;
}
frame
=
VNC_frame_data
[
frame_idx
];
while
((
frame_idx
<
frame_length
)
&&
(
frame
.
charAt
(
0
)
===
"}"
))
{
//Util.Debug("Send frame " + frame_idx);
frame_idx
+=
1
;
frame
=
VNC_frame_data
[
frame_idx
];
}
if
(
frame
===
'EOF'
)
{
Util
.
Debug
(
"Finished, found EOF"
);
next_iteration
();
return
;
}
if
(
frame_idx
>=
frame_length
)
{
Util
.
Debug
(
"Finished, no more frames"
);
next_iteration
();
return
;
}
if
(
mode
===
'realtime'
)
{
foffset
=
frame
.
slice
(
1
,
frame
.
indexOf
(
'{'
,
1
));
toffset
=
(
new
Date
()).
getTime
()
-
istart_time
;
delay
=
foffset
-
toffset
;
if
(
delay
<
1
)
{
delay
=
1
;
}
setTimeout
(
do_packet
,
delay
);
}
else
{
setTimeout
(
do_packet
,
1
);
}
};
var
bytes_processed
=
0
;
do_packet
=
function
()
{
//Util.Debug("Processing frame: " + frame_idx);
var
frame
=
VNC_frame_data
[
frame_idx
],
start
=
frame
.
indexOf
(
'{'
,
1
)
+
1
;
bytes_processed
+=
frame
.
length
-
start
;
if
(
VNC_frame_encoding
===
'binary'
)
{
var
u8
=
new
Uint8Array
(
frame
.
length
-
start
);
for
(
var
i
=
0
;
i
<
frame
.
length
-
start
;
i
++
)
{
u8
[
i
]
=
frame
.
charCodeAt
(
start
+
i
);
}
rfb
.
recv_message
({
'data'
:
u8
});
}
else
{
rfb
.
recv_message
({
'data'
:
frame
.
slice
(
start
)});
}
frame_idx
+=
1
;
queue_next_packet
();
};
circle/dashboard/static/dashboard/novnc/rfb.js
0 → 100644
View file @
743f544f
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
* 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'
],
[
'onDesktopName'
,
'rw'
,
'func'
,
function
()
{
},
'onDesktopName(rfb, name): desktop name received'
],
// 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
);
conf
.
onDesktopName
(
that
,
fb_name
);
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
;
FBU
.
bytes
=
4
;
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
)
{
FBU
.
bytes
=
4
+
fb_Bpp
;
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()
circle/dashboard/static/dashboard/novnc/ui.js
0 → 100644
View file @
743f544f
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*/
"use strict"
;
/*jslint white: false, browser: true */
/*global window, $D, Util, WebUtil, RFB, Display */
// Load supporting scripts
window
.
onscriptsload
=
function
()
{
UI
.
load
();
};
Util
.
load_scripts
([
"webutil.js"
,
"base64.js"
,
"websock.js"
,
"des.js"
,
"input.js"
,
"display.js"
,
"jsunzip.js"
,
"rfb.js"
]);
var
UI
=
{
rfb_state
:
'loaded'
,
settingsOpen
:
false
,
connSettingsOpen
:
false
,
popupStatusOpen
:
false
,
clipboardOpen
:
false
,
keyboardVisible
:
false
,
// Setup rfb object, load settings from browser storage, then call
// UI.init to setup the UI/menus
load
:
function
(
callback
)
{
WebUtil
.
initSettings
(
UI
.
start
,
callback
);
},
// Render default UI and initialize settings menu
start
:
function
(
callback
)
{
var
html
=
''
,
i
,
sheet
,
sheets
,
llevels
,
port
;
// Stylesheet selection dropdown
sheet
=
WebUtil
.
selectStylesheet
();
sheets
=
WebUtil
.
getStylesheets
();
for
(
i
=
0
;
i
<
sheets
.
length
;
i
+=
1
)
{
UI
.
addOption
(
$D
(
'noVNC_stylesheet'
),
sheets
[
i
].
title
,
sheets
[
i
].
title
);
}
// Logging selection dropdown
llevels
=
[
'error'
,
'warn'
,
'info'
,
'debug'
];
for
(
i
=
0
;
i
<
llevels
.
length
;
i
+=
1
)
{
UI
.
addOption
(
$D
(
'noVNC_logging'
),
llevels
[
i
],
llevels
[
i
]);
}
// Settings with immediate effects
UI
.
initSetting
(
'logging'
,
'warn'
);
WebUtil
.
init_logging
(
UI
.
getSetting
(
'logging'
));
UI
.
initSetting
(
'stylesheet'
,
'default'
);
WebUtil
.
selectStylesheet
(
null
);
// call twice to get around webkit bug
WebUtil
.
selectStylesheet
(
UI
.
getSetting
(
'stylesheet'
));
// if port == 80 (or 443) then it won't be present and should be
// set manually
port
=
window
.
location
.
port
;
if
(
!
port
)
{
if
(
window
.
location
.
protocol
.
substring
(
0
,
5
)
==
'https'
)
{
port
=
443
;
}
else
if
(
window
.
location
.
protocol
.
substring
(
0
,
4
)
==
'http'
)
{
port
=
80
;
}
}
/* Populate the controls if defaults are provided in the URL */
UI
.
initSetting
(
'host'
,
window
.
location
.
hostname
);
UI
.
initSetting
(
'port'
,
port
);
UI
.
initSetting
(
'password'
,
''
);
UI
.
initSetting
(
'encrypt'
,
(
window
.
location
.
protocol
===
"https:"
));
UI
.
initSetting
(
'true_color'
,
true
);
UI
.
initSetting
(
'cursor'
,
false
);
UI
.
initSetting
(
'shared'
,
true
);
UI
.
initSetting
(
'view_only'
,
false
);
UI
.
initSetting
(
'connectTimeout'
,
2
);
UI
.
initSetting
(
'path'
,
'websockify'
);
UI
.
initSetting
(
'repeaterID'
,
''
);
UI
.
rfb
=
RFB
({
'target'
:
$D
(
'noVNC_canvas'
),
'onUpdateState'
:
UI
.
updateState
,
'onClipboard'
:
UI
.
clipReceive
,
'onDesktopName'
:
UI
.
updateDocumentTitle
});
UI
.
updateVisualState
();
// Unfocus clipboard when over the VNC area
//$D('VNC_screen').onmousemove = function () {
// var keyboard = UI.rfb.get_keyboard();
// if ((! keyboard) || (! keyboard.get_focused())) {
// $D('VNC_clipboard_text').blur();
// }
// };
// Show mouse selector buttons on touch screen devices
if
(
'ontouchstart'
in
document
.
documentElement
)
{
// Show mobile buttons
$D
(
'noVNC_mobile_buttons'
).
style
.
display
=
"inline"
;
UI
.
setMouseButton
();
// Remove the address bar
setTimeout
(
function
()
{
window
.
scrollTo
(
0
,
1
);
},
100
);
UI
.
forceSetting
(
'clip'
,
true
);
$D
(
'noVNC_clip'
).
disabled
=
true
;
}
else
{
UI
.
initSetting
(
'clip'
,
false
);
}
//iOS Safari does not support CSS position:fixed.
//This detects iOS devices and enables javascript workaround.
if
((
navigator
.
userAgent
.
match
(
/iPhone/i
))
||
(
navigator
.
userAgent
.
match
(
/iPod/i
))
||
(
navigator
.
userAgent
.
match
(
/iPad/i
)))
{
//UI.setOnscroll();
//UI.setResize();
}
UI
.
setBarPosition
();
$D
(
'noVNC_host'
).
focus
();
UI
.
setViewClip
();
Util
.
addEvent
(
window
,
'resize'
,
UI
.
setViewClip
);
Util
.
addEvent
(
window
,
'beforeunload'
,
function
()
{
if
(
UI
.
rfb_state
===
'normal'
)
{
return
"You are currently connected."
;
}
}
);
// Show description by default when hosted at for kanaka.github.com
if
(
location
.
host
===
"kanaka.github.com"
)
{
// Open the description dialog
$D
(
'noVNC_description'
).
style
.
display
=
"block"
;
}
else
{
// Open the connect panel on first load
UI
.
toggleConnectPanel
();
}
// Add mouse event click/focus/blur event handlers to the UI
UI
.
addMouseHandlers
();
if
(
typeof
callback
===
"function"
)
{
callback
(
UI
.
rfb
);
}
},
addMouseHandlers
:
function
()
{
// Setup interface handlers that can't be inline
$D
(
"noVNC_view_drag_button"
).
onclick
=
UI
.
setViewDrag
;
$D
(
"noVNC_mouse_button0"
).
onclick
=
function
()
{
UI
.
setMouseButton
(
1
);
};
$D
(
"noVNC_mouse_button1"
).
onclick
=
function
()
{
UI
.
setMouseButton
(
2
);
};
$D
(
"noVNC_mouse_button2"
).
onclick
=
function
()
{
UI
.
setMouseButton
(
4
);
};
$D
(
"noVNC_mouse_button4"
).
onclick
=
function
()
{
UI
.
setMouseButton
(
0
);
};
$D
(
"showKeyboard"
).
onclick
=
UI
.
showKeyboard
;
//$D("keyboardinput").onkeydown = function (event) { onKeyDown(event); };
$D
(
"keyboardinput"
).
onblur
=
UI
.
keyInputBlur
;
$D
(
"sendCtrlAltDelButton"
).
onclick
=
UI
.
sendCtrlAltDel
;
$D
(
"noVNC_status"
).
onclick
=
UI
.
togglePopupStatusPanel
;
$D
(
"noVNC_popup_status_panel"
).
onclick
=
UI
.
togglePopupStatusPanel
;
$D
(
"clipboardButton"
).
onclick
=
UI
.
toggleClipboardPanel
;
$D
(
"settingsButton"
).
onclick
=
UI
.
toggleSettingsPanel
;
$D
(
"connectButton"
).
onclick
=
UI
.
toggleConnectPanel
;
$D
(
"disconnectButton"
).
onclick
=
UI
.
disconnect
;
$D
(
"descriptionButton"
).
onclick
=
UI
.
toggleConnectPanel
;
$D
(
"noVNC_clipboard_text"
).
onfocus
=
UI
.
displayBlur
;
$D
(
"noVNC_clipboard_text"
).
onblur
=
UI
.
displayFocus
;
$D
(
"noVNC_clipboard_text"
).
onchange
=
UI
.
clipSend
;
$D
(
"noVNC_clipboard_clear_button"
).
onclick
=
UI
.
clipClear
;
$D
(
"noVNC_settings_menu"
).
onmouseover
=
UI
.
displayBlur
;
$D
(
"noVNC_settings_menu"
).
onmouseover
=
UI
.
displayFocus
;
$D
(
"noVNC_apply"
).
onclick
=
UI
.
settingsApply
;
$D
(
"noVNC_connect_button"
).
onclick
=
UI
.
connect
;
},
// Read form control compatible setting from cookie
getSetting
:
function
(
name
)
{
var
val
,
ctrl
=
$D
(
'noVNC_'
+
name
);
val
=
WebUtil
.
readSetting
(
name
);
if
(
val
!==
null
&&
ctrl
.
type
===
'checkbox'
)
{
if
(
val
.
toString
().
toLowerCase
()
in
{
'0'
:
1
,
'no'
:
1
,
'false'
:
1
})
{
val
=
false
;
}
else
{
val
=
true
;
}
}
return
val
;
},
// Update cookie and form control setting. If value is not set, then
// updates from control to current cookie setting.
updateSetting
:
function
(
name
,
value
)
{
var
i
,
ctrl
=
$D
(
'noVNC_'
+
name
);
// Save the cookie for this session
if
(
typeof
value
!==
'undefined'
)
{
WebUtil
.
writeSetting
(
name
,
value
);
}
// Update the settings control
value
=
UI
.
getSetting
(
name
);
if
(
ctrl
.
type
===
'checkbox'
)
{
ctrl
.
checked
=
value
;
}
else
if
(
typeof
ctrl
.
options
!==
'undefined'
)
{
for
(
i
=
0
;
i
<
ctrl
.
options
.
length
;
i
+=
1
)
{
if
(
ctrl
.
options
[
i
].
value
===
value
)
{
ctrl
.
selectedIndex
=
i
;
break
;
}
}
}
else
{
/*Weird IE9 error leads to 'null' appearring
in textboxes instead of ''.*/
if
(
value
===
null
)
{
value
=
""
;
}
ctrl
.
value
=
value
;
}
},
// Save control setting to cookie
saveSetting
:
function
(
name
)
{
var
val
,
ctrl
=
$D
(
'noVNC_'
+
name
);
if
(
ctrl
.
type
===
'checkbox'
)
{
val
=
ctrl
.
checked
;
}
else
if
(
typeof
ctrl
.
options
!==
'undefined'
)
{
val
=
ctrl
.
options
[
ctrl
.
selectedIndex
].
value
;
}
else
{
val
=
ctrl
.
value
;
}
WebUtil
.
writeSetting
(
name
,
val
);
//Util.Debug("Setting saved '" + name + "=" + val + "'");
return
val
;
},
// Initial page load read/initialization of settings
initSetting
:
function
(
name
,
defVal
)
{
var
val
;
// Check Query string followed by cookie
val
=
WebUtil
.
getQueryVar
(
name
);
if
(
val
===
null
)
{
val
=
WebUtil
.
readSetting
(
name
,
defVal
);
}
UI
.
updateSetting
(
name
,
val
);
//Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
return
val
;
},
// Force a setting to be a certain value
forceSetting
:
function
(
name
,
val
)
{
UI
.
updateSetting
(
name
,
val
);
return
val
;
},
// Show the popup status panel
togglePopupStatusPanel
:
function
()
{
var
psp
=
$D
(
'noVNC_popup_status_panel'
);
if
(
UI
.
popupStatusOpen
===
true
)
{
psp
.
style
.
display
=
"none"
;
UI
.
popupStatusOpen
=
false
;
}
else
{
psp
.
innerHTML
=
$D
(
'noVNC_status'
).
innerHTML
;
psp
.
style
.
display
=
"block"
;
psp
.
style
.
left
=
window
.
innerWidth
/
2
-
parseInt
(
window
.
getComputedStyle
(
psp
,
false
).
width
)
/
2
-
30
+
"px"
;
UI
.
popupStatusOpen
=
true
;
}
},
// Show the clipboard panel
toggleClipboardPanel
:
function
()
{
// Close the description panel
$D
(
'noVNC_description'
).
style
.
display
=
"none"
;
// Close settings if open
if
(
UI
.
settingsOpen
===
true
)
{
UI
.
settingsApply
();
UI
.
closeSettingsMenu
();
}
// Close connection settings if open
if
(
UI
.
connSettingsOpen
===
true
)
{
UI
.
toggleConnectPanel
();
}
// Close popup status panel if open
if
(
UI
.
popupStatusOpen
===
true
)
{
UI
.
togglePopupStatusPanel
();
}
// Toggle Clipboard Panel
if
(
UI
.
clipboardOpen
===
true
)
{
$D
(
'noVNC_clipboard'
).
style
.
display
=
"none"
;
$D
(
'clipboardButton'
).
className
=
"noVNC_status_button"
;
UI
.
clipboardOpen
=
false
;
}
else
{
$D
(
'noVNC_clipboard'
).
style
.
display
=
"block"
;
$D
(
'clipboardButton'
).
className
=
"noVNC_status_button_selected"
;
UI
.
clipboardOpen
=
true
;
}
},
// Show the connection settings panel/menu
toggleConnectPanel
:
function
()
{
// Close the description panel
$D
(
'noVNC_description'
).
style
.
display
=
"none"
;
// Close connection settings if open
if
(
UI
.
settingsOpen
===
true
)
{
UI
.
settingsApply
();
UI
.
closeSettingsMenu
();
$D
(
'connectButton'
).
className
=
"noVNC_status_button"
;
}
// Close clipboard panel if open
if
(
UI
.
clipboardOpen
===
true
)
{
UI
.
toggleClipboardPanel
();
}
// Close popup status panel if open
if
(
UI
.
popupStatusOpen
===
true
)
{
UI
.
togglePopupStatusPanel
();
}
// Toggle Connection Panel
if
(
UI
.
connSettingsOpen
===
true
)
{
$D
(
'noVNC_controls'
).
style
.
display
=
"none"
;
$D
(
'connectButton'
).
className
=
"noVNC_status_button"
;
UI
.
connSettingsOpen
=
false
;
UI
.
saveSetting
(
'host'
);
UI
.
saveSetting
(
'port'
);
//UI.saveSetting('password');
}
else
{
$D
(
'noVNC_controls'
).
style
.
display
=
"block"
;
$D
(
'connectButton'
).
className
=
"noVNC_status_button_selected"
;
UI
.
connSettingsOpen
=
true
;
$D
(
'noVNC_host'
).
focus
();
}
},
// Toggle the settings menu:
// On open, settings are refreshed from saved cookies.
// On close, settings are applied
toggleSettingsPanel
:
function
()
{
// Close the description panel
$D
(
'noVNC_description'
).
style
.
display
=
"none"
;
if
(
UI
.
settingsOpen
)
{
UI
.
settingsApply
();
UI
.
closeSettingsMenu
();
}
else
{
UI
.
updateSetting
(
'encrypt'
);
UI
.
updateSetting
(
'true_color'
);
if
(
UI
.
rfb
.
get_display
().
get_cursor_uri
())
{
UI
.
updateSetting
(
'cursor'
);
}
else
{
UI
.
updateSetting
(
'cursor'
,
false
);
$D
(
'noVNC_cursor'
).
disabled
=
true
;
}
UI
.
updateSetting
(
'clip'
);
UI
.
updateSetting
(
'shared'
);
UI
.
updateSetting
(
'view_only'
);
UI
.
updateSetting
(
'connectTimeout'
);
UI
.
updateSetting
(
'path'
);
UI
.
updateSetting
(
'repeaterID'
);
UI
.
updateSetting
(
'stylesheet'
);
UI
.
updateSetting
(
'logging'
);
UI
.
openSettingsMenu
();
}
},
// Open menu
openSettingsMenu
:
function
()
{
// Close the description panel
$D
(
'noVNC_description'
).
style
.
display
=
"none"
;
// Close clipboard panel if open
if
(
UI
.
clipboardOpen
===
true
)
{
UI
.
toggleClipboardPanel
();
}
// Close connection settings if open
if
(
UI
.
connSettingsOpen
===
true
)
{
UI
.
toggleConnectPanel
();
}
// Close popup status panel if open
if
(
UI
.
popupStatusOpen
===
true
)
{
UI
.
togglePopupStatusPanel
();
}
$D
(
'noVNC_settings'
).
style
.
display
=
"block"
;
$D
(
'settingsButton'
).
className
=
"noVNC_status_button_selected"
;
UI
.
settingsOpen
=
true
;
},
// Close menu (without applying settings)
closeSettingsMenu
:
function
()
{
$D
(
'noVNC_settings'
).
style
.
display
=
"none"
;
$D
(
'settingsButton'
).
className
=
"noVNC_status_button"
;
UI
.
settingsOpen
=
false
;
},
// Save/apply settings when 'Apply' button is pressed
settingsApply
:
function
()
{
//Util.Debug(">> settingsApply");
UI
.
saveSetting
(
'encrypt'
);
UI
.
saveSetting
(
'true_color'
);
if
(
UI
.
rfb
.
get_display
().
get_cursor_uri
())
{
UI
.
saveSetting
(
'cursor'
);
}
UI
.
saveSetting
(
'clip'
);
UI
.
saveSetting
(
'shared'
);
UI
.
saveSetting
(
'view_only'
);
UI
.
saveSetting
(
'connectTimeout'
);
UI
.
saveSetting
(
'path'
);
UI
.
saveSetting
(
'repeaterID'
);
UI
.
saveSetting
(
'stylesheet'
);
UI
.
saveSetting
(
'logging'
);
// Settings with immediate (non-connected related) effect
WebUtil
.
selectStylesheet
(
UI
.
getSetting
(
'stylesheet'
));
WebUtil
.
init_logging
(
UI
.
getSetting
(
'logging'
));
UI
.
setViewClip
();
UI
.
setViewDrag
(
UI
.
rfb
.
get_viewportDrag
());
//Util.Debug("<< settingsApply");
},
setPassword
:
function
()
{
UI
.
rfb
.
sendPassword
(
$D
(
'noVNC_password'
).
value
);
//Reset connect button.
$D
(
'noVNC_connect_button'
).
value
=
"Connect"
;
$D
(
'noVNC_connect_button'
).
onclick
=
UI
.
Connect
;
//Hide connection panel.
UI
.
toggleConnectPanel
();
return
false
;
},
sendCtrlAltDel
:
function
()
{
UI
.
rfb
.
sendCtrlAltDel
();
},
setMouseButton
:
function
(
num
)
{
var
b
,
blist
=
[
0
,
1
,
2
,
4
],
button
;
if
(
typeof
num
===
'undefined'
)
{
// Disable mouse buttons
num
=
-
1
;
}
if
(
UI
.
rfb
)
{
UI
.
rfb
.
get_mouse
().
set_touchButton
(
num
);
}
for
(
b
=
0
;
b
<
blist
.
length
;
b
++
)
{
button
=
$D
(
'noVNC_mouse_button'
+
blist
[
b
]);
if
(
blist
[
b
]
===
num
)
{
button
.
style
.
display
=
""
;
}
else
{
button
.
style
.
display
=
"none"
;
/*
button.style.backgroundColor = "black";
button.style.color = "lightgray";
button.style.backgroundColor = "";
button.style.color = "";
*/
}
}
},
updateState
:
function
(
rfb
,
state
,
oldstate
,
msg
)
{
var
s
,
sb
,
c
,
d
,
cad
,
vd
,
klass
;
UI
.
rfb_state
=
state
;
switch
(
state
)
{
case
'failed'
:
case
'fatal'
:
klass
=
"noVNC_status_error"
;
break
;
case
'normal'
:
klass
=
"noVNC_status_normal"
;
break
;
case
'disconnected'
:
$D
(
'noVNC_logo'
).
style
.
display
=
"block"
;
// Fall through
case
'loaded'
:
klass
=
"noVNC_status_normal"
;
break
;
case
'password'
:
UI
.
toggleConnectPanel
();
$D
(
'noVNC_connect_button'
).
value
=
"Send Password"
;
$D
(
'noVNC_connect_button'
).
onclick
=
UI
.
setPassword
;
$D
(
'noVNC_password'
).
focus
();
klass
=
"noVNC_status_warn"
;
break
;
default
:
klass
=
"noVNC_status_warn"
;
break
;
}
if
(
typeof
(
msg
)
!==
'undefined'
)
{
$D
(
'noVNC-control-bar'
).
setAttribute
(
"class"
,
klass
);
$D
(
'noVNC_status'
).
innerHTML
=
msg
;
}
UI
.
updateVisualState
();
},
// Disable/enable controls depending on connection state
updateVisualState
:
function
()
{
var
connected
=
UI
.
rfb_state
===
'normal'
?
true
:
false
;
//Util.Debug(">> updateVisualState");
$D
(
'noVNC_encrypt'
).
disabled
=
connected
;
$D
(
'noVNC_true_color'
).
disabled
=
connected
;
if
(
UI
.
rfb
&&
UI
.
rfb
.
get_display
()
&&
UI
.
rfb
.
get_display
().
get_cursor_uri
())
{
$D
(
'noVNC_cursor'
).
disabled
=
connected
;
}
else
{
UI
.
updateSetting
(
'cursor'
,
false
);
$D
(
'noVNC_cursor'
).
disabled
=
true
;
}
$D
(
'noVNC_shared'
).
disabled
=
connected
;
$D
(
'noVNC_view_only'
).
disabled
=
connected
;
$D
(
'noVNC_connectTimeout'
).
disabled
=
connected
;
$D
(
'noVNC_path'
).
disabled
=
connected
;
$D
(
'noVNC_repeaterID'
).
disabled
=
connected
;
if
(
connected
)
{
UI
.
setViewClip
();
UI
.
setMouseButton
(
1
);
$D
(
'clipboardButton'
).
style
.
display
=
"inline"
;
$D
(
'showKeyboard'
).
style
.
display
=
"inline"
;
$D
(
'sendCtrlAltDelButton'
).
style
.
display
=
"inline"
;
}
else
{
UI
.
setMouseButton
();
$D
(
'clipboardButton'
).
style
.
display
=
"none"
;
$D
(
'showKeyboard'
).
style
.
display
=
"none"
;
$D
(
'sendCtrlAltDelButton'
).
style
.
display
=
"none"
;
}
// State change disables viewport dragging.
// It is enabled (toggled) by direct click on the button
UI
.
setViewDrag
(
false
);
switch
(
UI
.
rfb_state
)
{
case
'fatal'
:
case
'failed'
:
case
'loaded'
:
case
'disconnected'
:
$D
(
'connectButton'
).
style
.
display
=
""
;
$D
(
'disconnectButton'
).
style
.
display
=
"none"
;
break
;
default
:
$D
(
'connectButton'
).
style
.
display
=
"none"
;
$D
(
'disconnectButton'
).
style
.
display
=
""
;
break
;
}
//Util.Debug("<< updateVisualState");
},
// Display the desktop name in the document title
updateDocumentTitle
:
function
(
rfb
,
name
)
{
document
.
title
=
name
+
" - noVNC"
;
},
clipReceive
:
function
(
rfb
,
text
)
{
Util
.
Debug
(
">> UI.clipReceive: "
+
text
.
substr
(
0
,
40
)
+
"..."
);
$D
(
'noVNC_clipboard_text'
).
value
=
text
;
Util
.
Debug
(
"<< UI.clipReceive"
);
},
connect
:
function
()
{
var
host
,
port
,
password
,
path
;
UI
.
closeSettingsMenu
();
UI
.
toggleConnectPanel
();
host
=
$D
(
'noVNC_host'
).
value
;
port
=
$D
(
'noVNC_port'
).
value
;
password
=
$D
(
'noVNC_password'
).
value
;
path
=
$D
(
'noVNC_path'
).
value
;
if
((
!
host
)
||
(
!
port
))
{
throw
(
"Must set host and port"
);
}
UI
.
rfb
.
set_encrypt
(
UI
.
getSetting
(
'encrypt'
));
UI
.
rfb
.
set_true_color
(
UI
.
getSetting
(
'true_color'
));
UI
.
rfb
.
set_local_cursor
(
UI
.
getSetting
(
'cursor'
));
UI
.
rfb
.
set_shared
(
UI
.
getSetting
(
'shared'
));
UI
.
rfb
.
set_view_only
(
UI
.
getSetting
(
'view_only'
));
UI
.
rfb
.
set_connectTimeout
(
UI
.
getSetting
(
'connectTimeout'
));
UI
.
rfb
.
set_repeaterID
(
UI
.
getSetting
(
'repeaterID'
));
UI
.
rfb
.
connect
(
host
,
port
,
password
,
path
);
//Close dialog.
setTimeout
(
UI
.
setBarPosition
,
100
);
$D
(
'noVNC_logo'
).
style
.
display
=
"none"
;
},
disconnect
:
function
()
{
UI
.
closeSettingsMenu
();
UI
.
rfb
.
disconnect
();
$D
(
'noVNC_logo'
).
style
.
display
=
"block"
;
UI
.
connSettingsOpen
=
false
;
UI
.
toggleConnectPanel
();
},
displayBlur
:
function
()
{
UI
.
rfb
.
get_keyboard
().
set_focused
(
false
);
UI
.
rfb
.
get_mouse
().
set_focused
(
false
);
},
displayFocus
:
function
()
{
UI
.
rfb
.
get_keyboard
().
set_focused
(
true
);
UI
.
rfb
.
get_mouse
().
set_focused
(
true
);
},
clipClear
:
function
()
{
$D
(
'noVNC_clipboard_text'
).
value
=
""
;
UI
.
rfb
.
clipboardPasteFrom
(
""
);
},
clipSend
:
function
()
{
var
text
=
$D
(
'noVNC_clipboard_text'
).
value
;
Util
.
Debug
(
">> UI.clipSend: "
+
text
.
substr
(
0
,
40
)
+
"..."
);
UI
.
rfb
.
clipboardPasteFrom
(
text
);
Util
.
Debug
(
"<< UI.clipSend"
);
},
// Enable/disable and configure viewport clipping
setViewClip
:
function
(
clip
)
{
var
display
,
cur_clip
,
pos
,
new_w
,
new_h
;
if
(
UI
.
rfb
)
{
display
=
UI
.
rfb
.
get_display
();
}
else
{
return
;
}
cur_clip
=
display
.
get_viewport
();
if
(
typeof
(
clip
)
!==
'boolean'
)
{
// Use current setting
clip
=
UI
.
getSetting
(
'clip'
);
}
if
(
clip
&&
!
cur_clip
)
{
// Turn clipping on
UI
.
updateSetting
(
'clip'
,
true
);
}
else
if
(
!
clip
&&
cur_clip
)
{
// Turn clipping off
UI
.
updateSetting
(
'clip'
,
false
);
display
.
set_viewport
(
false
);
$D
(
'noVNC_canvas'
).
style
.
position
=
'static'
;
display
.
viewportChange
();
}
if
(
UI
.
getSetting
(
'clip'
))
{
// If clipping, update clipping settings
$D
(
'noVNC_canvas'
).
style
.
position
=
'absolute'
;
pos
=
Util
.
getPosition
(
$D
(
'noVNC_canvas'
));
new_w
=
window
.
innerWidth
-
pos
.
x
;
new_h
=
window
.
innerHeight
-
pos
.
y
;
display
.
set_viewport
(
true
);
display
.
viewportChange
(
0
,
0
,
new_w
,
new_h
);
}
},
// Toggle/set/unset the viewport drag/move button
setViewDrag
:
function
(
drag
)
{
var
vmb
=
$D
(
'noVNC_view_drag_button'
);
if
(
!
UI
.
rfb
)
{
return
;
}
if
(
UI
.
rfb_state
===
'normal'
&&
UI
.
rfb
.
get_display
().
get_viewport
())
{
vmb
.
style
.
display
=
"inline"
;
}
else
{
vmb
.
style
.
display
=
"none"
;
}
if
(
typeof
(
drag
)
===
"undefined"
||
typeof
(
drag
)
===
"object"
)
{
// If not specified, then toggle
drag
=
!
UI
.
rfb
.
get_viewportDrag
();
}
if
(
drag
)
{
vmb
.
className
=
"noVNC_status_button_selected"
;
UI
.
rfb
.
set_viewportDrag
(
true
);
}
else
{
vmb
.
className
=
"noVNC_status_button"
;
UI
.
rfb
.
set_viewportDrag
(
false
);
}
},
// On touch devices, show the OS keyboard
showKeyboard
:
function
()
{
if
(
UI
.
keyboardVisible
===
false
)
{
$D
(
'keyboardinput'
).
focus
();
UI
.
keyboardVisible
=
true
;
$D
(
'showKeyboard'
).
className
=
"noVNC_status_button_selected"
;
}
else
if
(
UI
.
keyboardVisible
===
true
)
{
$D
(
'keyboardinput'
).
blur
();
$D
(
'showKeyboard'
).
className
=
"noVNC_status_button"
;
UI
.
keyboardVisible
=
false
;
}
},
keyInputBlur
:
function
()
{
$D
(
'showKeyboard'
).
className
=
"noVNC_status_button"
;
//Weird bug in iOS if you change keyboardVisible
//here it does not actually occur so next time
//you click keyboard icon it doesnt work.
setTimeout
(
function
()
{
UI
.
setKeyboard
();
},
100
);
},
setKeyboard
:
function
()
{
UI
.
keyboardVisible
=
false
;
},
// iOS < Version 5 does not support position fixed. Javascript workaround:
setOnscroll
:
function
()
{
window
.
onscroll
=
function
()
{
UI
.
setBarPosition
();
};
},
setResize
:
function
()
{
window
.
onResize
=
function
()
{
UI
.
setBarPosition
();
};
},
//Helper to add options to dropdown.
addOption
:
function
(
selectbox
,
text
,
value
)
{
var
optn
=
document
.
createElement
(
"OPTION"
);
optn
.
text
=
text
;
optn
.
value
=
value
;
selectbox
.
options
.
add
(
optn
);
},
setBarPosition
:
function
()
{
$D
(
'noVNC-control-bar'
).
style
.
top
=
(
window
.
pageYOffset
)
+
'px'
;
$D
(
'noVNC_mobile_buttons'
).
style
.
left
=
(
window
.
pageXOffset
)
+
'px'
;
var
vncwidth
=
$D
(
'noVNC_screen'
).
style
.
offsetWidth
;
$D
(
'noVNC-control-bar'
).
style
.
width
=
vncwidth
+
'px'
;
}
};
circle/dashboard/static/dashboard/novnc/util.js
0 → 100644
View file @
743f544f
/*
* 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
realx
=
docX
-
pos
.
x
;
var
realy
=
docY
-
pos
.
y
;
var
x
=
Math
.
max
(
Math
.
min
(
realx
,
obj
.
width
-
1
),
0
);
var
y
=
Math
.
max
(
Math
.
min
(
realy
,
obj
.
height
-
1
),
0
);
return
{
'x'
:
x
/
scale
,
'y'
:
y
/
scale
,
'realx'
:
realx
/
scale
,
'realy'
:
realy
/
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
};
}());
circle/dashboard/static/dashboard/novnc/websock.js
0 → 100644
View file @
743f544f
/*
* 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
();
}
circle/dashboard/static/dashboard/novnc/webutil.js
0 → 100644
View file @
743f544f
/*
* 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
;
};
circle/dashboard/templates/dashboard/vm-detail-console.html
View file @
743f544f
CONSOLE
<div
class=
"btn-toolbar"
>
<div
class=
"btn-group"
>
<button
id=
"sendCtrlAltDelButton"
class=
"btn btn-danger small"
href=
"#"
>
Send CtrlAltDel
</button>
<button
id=
"akkount-mate"
class=
"btn btn-default small"
href=
"#"
>
Máténak akkountot adok
</button>
<button
id=
"akkount-bd"
class=
"btn btn-success small"
href=
"#"
>
bd-nek akkountot adok
</button>
</div>
<div
class=
"btn-group"
>
<button
id=
"blabla"
class=
"btn btn-warning small disabled"
href=
"#"
>
GubaSanyinak akkountot adok
</button>
</div>
</div>
<div
class=
"alert alert-info"
id=
"noVNC_status"
>
</div>
<canvas
id=
"noVNC_canvas"
width=
"640px"
height=
"20px"
>
Canvas not supported.
</canvas>
<script
src=
"{{ STATIC_URL }}dashboard/novnc/util.js"
></script>
<script>
"use strict"
;
var
INCLUDE_URI
=
'{{ STATIC_URL }}dashboard/novnc/'
;
Util
.
load_scripts
([
"webutil.js"
,
"base64.js"
,
"websock.js"
,
"des.js"
,
"input.js"
,
"display.js"
,
"jsunzip.js"
,
"rfb.js"
]);
var
rfb
;
function
updateState
(
rfb
,
state
,
oldstate
,
msg
)
{
var
s
,
sb
,
cad
s
=
$
(
'#noVNC_status'
)[
0
];
cad
=
$
(
'#sendCtrlAltDelButton'
)[
0
];
if
(
state
===
"normal"
)
{
cad
.
disabled
=
false
;
}
else
{
cad
.
disabled
=
true
;
}
if
(
typeof
(
msg
)
!==
'undefined'
)
{
s
.
innerHTML
=
msg
;
}
}
$
(
'a[data-toggle$="pill"][href!="#console"]'
).
click
(
function
()
{
alert
(
'SZIA'
);
if
(
rfb
)
{
rfb
.
disconnect
();
rfb
=
0
;
}
$
(
"#vm-info-pane"
).
fadeIn
();
$
(
"#vm-detail-pane"
).
removeClass
(
"col-md-12"
);
});
$
(
'#sendCtrlAltDelButton'
).
click
(
function
()
{
rfb
.
sendCtrlAltDel
();
return
false
;});
$
(
'#akkount-mate'
).
click
(
function
()
{
alert
(
'NEM!!!!!!444'
);
return
false
;});
$
(
'#akkount-bd'
).
click
(
function
()
{
alert
(
'OK, ADOK!!!!!!444'
);
return
false
;});
$
(
'a[href$="console"]'
).
click
(
function
()
{
var
host
,
port
,
password
,
path
;
$
(
"#vm-info-pane"
).
hide
();
$
(
"#vm-detail-pane"
).
addClass
(
"col-md-12"
);
WebUtil
.
init_logging
(
'warn'
);
host
=
'10.9.2.232'
;
port
=
'443'
;
password
=
'tbdgpzhtow'
;
path
=
'vnc/'
;
rfb
=
new
RFB
({
'target'
:
$D
(
'noVNC_canvas'
),
'encrypt'
:
true
,
// (window.location.protocol === "https:"),
'true_color'
:
true
,
'local_cursor'
:
true
,
'shared'
:
true
,
'view_only'
:
false
,
'updateState'
:
updateState
});
rfb
.
connect
(
host
,
port
,
password
,
path
);
});
</script>
circle/dashboard/templates/dashboard/vm-detail.html
View file @
743f544f
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
<h1>
devenv
<small>
550.vm.ik.bme.hu
</small></h1>
<h1>
devenv
<small>
550.vm.ik.bme.hu
</small></h1>
</div>
</div>
<div
class=
"row"
>
<div
class=
"row"
>
<div
class=
"col-md-4"
>
<div
class=
"col-md-4"
id=
"vm-info-pane"
>
<div
class=
"big"
>
<div
class=
"big"
>
<span
class=
"label label-success "
>
RUNNING
</span>
<span
class=
"label label-success "
>
RUNNING
</span>
<div
class=
"btn-group"
>
<div
class=
"btn-group"
>
...
@@ -28,7 +28,7 @@
...
@@ -28,7 +28,7 @@
<dd>
ac metus interdum, tincidunt
</dd>
<dd>
ac metus interdum, tincidunt
</dd>
</dl>
</dl>
</div>
</div>
<div
class=
"col-md-8"
>
<div
class=
"col-md-8"
id=
"vm-detail-pane"
>
<div
class=
"panel panel-default"
id=
"vm-detail-panel"
>
<div
class=
"panel panel-default"
id=
"vm-detail-panel"
>
<ul
class=
"nav nav-pills panel-heading"
>
<ul
class=
"nav nav-pills panel-heading"
>
<li
class=
"active"
>
<li
class=
"active"
>
...
...
circle/dashboard/urls.py
View file @
743f544f
...
@@ -2,8 +2,8 @@ from django.conf.urls import patterns, url
...
@@ -2,8 +2,8 @@ from django.conf.urls import patterns, url
from
.views
import
IndexView
,
VmDetailView
from
.views
import
IndexView
,
VmDetailView
urlpatterns
=
patterns
(
urlpatterns
=
patterns
(
''
,
''
,
url
(
r'^$'
,
IndexView
.
as_view
())
,
url
(
r'^$'
,
IndexView
.
as_view
()
),
url
(
r'^vm/(?P<id>\d+)/$'
,
VmDetailView
.
as_view
(
),
url
(
r'^vm/\d+/$'
,
VmDetailView
.
as_view
()
),
name
=
'dashboard.views.detail'
),
)
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment