mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-10-26 18:22:23 +02:00
fix(web-ui): ship the bundled consoles' lib/ files (VNC and xpra)
The ".gitignore" rules "lib" and "lib64" (from the Python template, meant for a virtualenv at the repository root) match a directory with that name at any depth. They kept two folders of the bundled web UI out of git: - assets/vnc-console/novnc/vendor/pako/lib/ (12 files, zlib for noVNC) - assets/xpra-html5/js/lib/ (20 files) Anything built from a git checkout (GitHub archives, Docker images) ships without them. The server answers a missing asset with the web UI page, so noVNC's module graph fails to load (a module served as text/html) and the VNC console stays on "Initializing VNC Console..."; the xpra console loses its scripts the same way. Anchor both rules to the repository root and add the 32 files, taken from gns3-web-ui v3.1.0a7 (the bundled version); every blob is identical to the one in that tag. A test walks the VNC console's module imports and the xpra pages' scripts and fails on any file that is not in the package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ac01ee6190
commit
406086c177
4
.gitignore
vendored
4
.gitignore
vendored
@ -25,8 +25,8 @@ var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
lib
|
||||
lib64
|
||||
/lib
|
||||
/lib64
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
48
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/utils/common.js
vendored
Normal file
48
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/utils/common.js
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
// reduce buffer size, avoiding mem copy
|
||||
export function shrinkBuf(buf, size) {
|
||||
if (buf.length === size) {
|
||||
return buf;
|
||||
}
|
||||
if (buf.subarray) {
|
||||
return buf.subarray(0, size);
|
||||
}
|
||||
buf.length = size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function arraySet(dest, src, src_offs, len, dest_offs) {
|
||||
if (src.subarray && dest.subarray) {
|
||||
dest.set(src.subarray(src_offs, src_offs + len), dest_offs);
|
||||
return;
|
||||
}
|
||||
// Fallback to ordinary array
|
||||
for (var i = 0; i < len; i++) {
|
||||
dest[dest_offs + i] = src[src_offs + i];
|
||||
}
|
||||
}
|
||||
|
||||
// Join array of chunks to single array.
|
||||
export function flattenChunks(chunks) {
|
||||
var i, l, len, pos, chunk, result;
|
||||
|
||||
// calculate data length
|
||||
len = 0;
|
||||
for (i = 0, l = chunks.length; i < l; i++) {
|
||||
len += chunks[i].length;
|
||||
}
|
||||
|
||||
// join chunks
|
||||
result = new Uint8Array(len);
|
||||
pos = 0;
|
||||
for (i = 0, l = chunks.length; i < l; i++) {
|
||||
chunk = chunks[i];
|
||||
result.set(chunk, pos);
|
||||
pos += chunk.length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export var Buf8 = Uint8Array;
|
||||
export var Buf16 = Uint16Array;
|
||||
export var Buf32 = Int32Array;
|
||||
27
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/adler32.js
vendored
Normal file
27
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/adler32.js
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Note: adler32 takes 12% for level 0 and 2% for level 6.
|
||||
// It doesn't worth to make additional optimizationa as in original.
|
||||
// Small size is preferable.
|
||||
|
||||
export default function adler32(adler, buf, len, pos) {
|
||||
var s1 = (adler & 0xffff) | 0,
|
||||
s2 = ((adler >>> 16) & 0xffff) | 0,
|
||||
n = 0;
|
||||
|
||||
while (len !== 0) {
|
||||
// Set limit ~ twice less than 5552, to keep
|
||||
// s2 in 31-bits, because we force signed ints.
|
||||
// in other case %= will fail.
|
||||
n = len > 2000 ? 2000 : len;
|
||||
len -= n;
|
||||
|
||||
do {
|
||||
s1 = (s1 + buf[pos++]) | 0;
|
||||
s2 = (s2 + s1) | 0;
|
||||
} while (--n);
|
||||
|
||||
s1 %= 65521;
|
||||
s2 %= 65521;
|
||||
}
|
||||
|
||||
return s1 | (s2 << 16) | 0;
|
||||
}
|
||||
45
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/constants.js
vendored
Normal file
45
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/constants.js
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
export default {
|
||||
/* Allowed flush values; see deflate() and inflate() below for details */
|
||||
Z_NO_FLUSH: 0,
|
||||
Z_PARTIAL_FLUSH: 1,
|
||||
Z_SYNC_FLUSH: 2,
|
||||
Z_FULL_FLUSH: 3,
|
||||
Z_FINISH: 4,
|
||||
Z_BLOCK: 5,
|
||||
Z_TREES: 6,
|
||||
|
||||
/* Return codes for the compression/decompression functions. Negative values
|
||||
* are errors, positive values are used for special but normal events.
|
||||
*/
|
||||
Z_OK: 0,
|
||||
Z_STREAM_END: 1,
|
||||
Z_NEED_DICT: 2,
|
||||
Z_ERRNO: -1,
|
||||
Z_STREAM_ERROR: -2,
|
||||
Z_DATA_ERROR: -3,
|
||||
//Z_MEM_ERROR: -4,
|
||||
Z_BUF_ERROR: -5,
|
||||
//Z_VERSION_ERROR: -6,
|
||||
|
||||
/* compression levels */
|
||||
Z_NO_COMPRESSION: 0,
|
||||
Z_BEST_SPEED: 1,
|
||||
Z_BEST_COMPRESSION: 9,
|
||||
Z_DEFAULT_COMPRESSION: -1,
|
||||
|
||||
Z_FILTERED: 1,
|
||||
Z_HUFFMAN_ONLY: 2,
|
||||
Z_RLE: 3,
|
||||
Z_FIXED: 4,
|
||||
Z_DEFAULT_STRATEGY: 0,
|
||||
|
||||
/* Possible values of the data_type field (though see inflate()) */
|
||||
Z_BINARY: 0,
|
||||
Z_TEXT: 1,
|
||||
//Z_ASCII: 1, // = Z_TEXT (deprecated)
|
||||
Z_UNKNOWN: 2,
|
||||
|
||||
/* The deflate compression method */
|
||||
Z_DEFLATED: 8,
|
||||
//Z_NULL: null // Use -1 or null inline, depending on var type
|
||||
};
|
||||
35
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/crc32.js
vendored
Normal file
35
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/crc32.js
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// Note: we can't get significant speed boost here.
|
||||
// So write code to minimize size - no pregenerated tables
|
||||
// and array tools dependencies.
|
||||
|
||||
// Use ordinary array, since untyped makes no boost here
|
||||
export default function makeTable() {
|
||||
var c,
|
||||
table = [];
|
||||
|
||||
for (var n = 0; n < 256; n++) {
|
||||
c = n;
|
||||
for (var k = 0; k < 8; k++) {
|
||||
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
||||
}
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
// Create table on load. Just 255 signed longs. Not a problem.
|
||||
var crcTable = makeTable();
|
||||
|
||||
function crc32(crc, buf, len, pos) {
|
||||
var t = crcTable,
|
||||
end = pos + len;
|
||||
|
||||
crc ^= -1;
|
||||
|
||||
for (var i = pos; i < end; i++) {
|
||||
crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xff];
|
||||
}
|
||||
|
||||
return crc ^ -1; // >>> 0;
|
||||
}
|
||||
1863
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/deflate.js
vendored
Normal file
1863
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/deflate.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
35
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/gzheader.js
vendored
Normal file
35
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/gzheader.js
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
export default function GZheader() {
|
||||
/* true if compressed data believed to be text */
|
||||
this.text = 0;
|
||||
/* modification time */
|
||||
this.time = 0;
|
||||
/* extra flags (not used when writing a gzip file) */
|
||||
this.xflags = 0;
|
||||
/* operating system */
|
||||
this.os = 0;
|
||||
/* pointer to extra field or Z_NULL if none */
|
||||
this.extra = null;
|
||||
/* extra field length (valid if extra != Z_NULL) */
|
||||
this.extra_len = 0; // Actually, we don't need it in JS,
|
||||
// but leave for few code modifications
|
||||
|
||||
//
|
||||
// Setup limits is not necessary because in js we should not preallocate memory
|
||||
// for inflate use constant limit in 65536 bytes
|
||||
//
|
||||
|
||||
/* space at extra (only when reading header) */
|
||||
// this.extra_max = 0;
|
||||
/* pointer to zero-terminated file name or Z_NULL */
|
||||
this.name = '';
|
||||
/* space at name (only when reading header) */
|
||||
// this.name_max = 0;
|
||||
/* pointer to zero-terminated comment or Z_NULL */
|
||||
this.comment = '';
|
||||
/* space at comment (only when reading header) */
|
||||
// this.comm_max = 0;
|
||||
/* true if there was or will be a header crc */
|
||||
this.hcrc = 0;
|
||||
/* true when done reading gzip header (not used when writing a gzip file) */
|
||||
this.done = false;
|
||||
}
|
||||
327
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/inffast.js
vendored
Normal file
327
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/inffast.js
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
// See state defs from inflate.js
|
||||
var BAD = 30; /* got a data error -- remain here until reset */
|
||||
var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
|
||||
|
||||
/*
|
||||
Decode literal, length, and distance codes and write out the resulting
|
||||
literal and match bytes until either not enough input or output is
|
||||
available, an end-of-block is encountered, or a data error is encountered.
|
||||
When large enough input and output buffers are supplied to inflate(), for
|
||||
example, a 16K input buffer and a 64K output buffer, more than 95% of the
|
||||
inflate execution time is spent in this routine.
|
||||
|
||||
Entry assumptions:
|
||||
|
||||
state.mode === LEN
|
||||
strm.avail_in >= 6
|
||||
strm.avail_out >= 258
|
||||
start >= strm.avail_out
|
||||
state.bits < 8
|
||||
|
||||
On return, state.mode is one of:
|
||||
|
||||
LEN -- ran out of enough output space or enough available input
|
||||
TYPE -- reached end of block code, inflate() to interpret next block
|
||||
BAD -- error in block data
|
||||
|
||||
Notes:
|
||||
|
||||
- The maximum input bits used by a length/distance pair is 15 bits for the
|
||||
length code, 5 bits for the length extra, 15 bits for the distance code,
|
||||
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
|
||||
Therefore if strm.avail_in >= 6, then there is enough input to avoid
|
||||
checking for available input while decoding.
|
||||
|
||||
- The maximum bytes that a single length/distance pair can output is 258
|
||||
bytes, which is the maximum length that can be coded. inflate_fast()
|
||||
requires strm.avail_out >= 258 for each loop to avoid checking for
|
||||
output space.
|
||||
*/
|
||||
export default function inflate_fast(strm, start) {
|
||||
var state;
|
||||
var _in; /* local strm.input */
|
||||
var last; /* have enough input while in < last */
|
||||
var _out; /* local strm.output */
|
||||
var beg; /* inflate()'s initial strm.output */
|
||||
var end; /* while out < end, enough space available */
|
||||
//#ifdef INFLATE_STRICT
|
||||
var dmax; /* maximum distance from zlib header */
|
||||
//#endif
|
||||
var wsize; /* window size or zero if not using window */
|
||||
var whave; /* valid bytes in the window */
|
||||
var wnext; /* window write index */
|
||||
// Use `s_window` instead `window`, avoid conflict with instrumentation tools
|
||||
var s_window; /* allocated sliding window, if wsize != 0 */
|
||||
var hold; /* local strm.hold */
|
||||
var bits; /* local strm.bits */
|
||||
var lcode; /* local strm.lencode */
|
||||
var dcode; /* local strm.distcode */
|
||||
var lmask; /* mask for first level of length codes */
|
||||
var dmask; /* mask for first level of distance codes */
|
||||
var here; /* retrieved table entry */
|
||||
var op; /* code bits, operation, extra bits, or */
|
||||
/* window position, window bytes to copy */
|
||||
var len; /* match length, unused bytes */
|
||||
var dist; /* match distance */
|
||||
var from; /* where to copy match from */
|
||||
var from_source;
|
||||
|
||||
var input, output; // JS specific, because we have no pointers
|
||||
|
||||
/* copy state to local variables */
|
||||
state = strm.state;
|
||||
//here = state.here;
|
||||
_in = strm.next_in;
|
||||
input = strm.input;
|
||||
last = _in + (strm.avail_in - 5);
|
||||
_out = strm.next_out;
|
||||
output = strm.output;
|
||||
beg = _out - (start - strm.avail_out);
|
||||
end = _out + (strm.avail_out - 257);
|
||||
//#ifdef INFLATE_STRICT
|
||||
dmax = state.dmax;
|
||||
//#endif
|
||||
wsize = state.wsize;
|
||||
whave = state.whave;
|
||||
wnext = state.wnext;
|
||||
s_window = state.window;
|
||||
hold = state.hold;
|
||||
bits = state.bits;
|
||||
lcode = state.lencode;
|
||||
dcode = state.distcode;
|
||||
lmask = (1 << state.lenbits) - 1;
|
||||
dmask = (1 << state.distbits) - 1;
|
||||
|
||||
/* decode literals and length/distances until end-of-block or not enough
|
||||
input data or output space */
|
||||
|
||||
top: do {
|
||||
if (bits < 15) {
|
||||
hold += input[_in++] << bits;
|
||||
bits += 8;
|
||||
hold += input[_in++] << bits;
|
||||
bits += 8;
|
||||
}
|
||||
|
||||
here = lcode[hold & lmask];
|
||||
|
||||
dolen: for (;;) {
|
||||
// Goto emulation
|
||||
op = here >>> 24 /*here.bits*/;
|
||||
hold >>>= op;
|
||||
bits -= op;
|
||||
op = (here >>> 16) & 0xff /*here.op*/;
|
||||
if (op === 0) {
|
||||
/* literal */
|
||||
//Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
||||
// "inflate: literal '%c'\n" :
|
||||
// "inflate: literal 0x%02x\n", here.val));
|
||||
output[_out++] = here & 0xffff /*here.val*/;
|
||||
} else if (op & 16) {
|
||||
/* length base */
|
||||
len = here & 0xffff /*here.val*/;
|
||||
op &= 15; /* number of extra bits */
|
||||
if (op) {
|
||||
if (bits < op) {
|
||||
hold += input[_in++] << bits;
|
||||
bits += 8;
|
||||
}
|
||||
len += hold & ((1 << op) - 1);
|
||||
hold >>>= op;
|
||||
bits -= op;
|
||||
}
|
||||
//Tracevv((stderr, "inflate: length %u\n", len));
|
||||
if (bits < 15) {
|
||||
hold += input[_in++] << bits;
|
||||
bits += 8;
|
||||
hold += input[_in++] << bits;
|
||||
bits += 8;
|
||||
}
|
||||
here = dcode[hold & dmask];
|
||||
|
||||
dodist: for (;;) {
|
||||
// goto emulation
|
||||
op = here >>> 24 /*here.bits*/;
|
||||
hold >>>= op;
|
||||
bits -= op;
|
||||
op = (here >>> 16) & 0xff /*here.op*/;
|
||||
|
||||
if (op & 16) {
|
||||
/* distance base */
|
||||
dist = here & 0xffff /*here.val*/;
|
||||
op &= 15; /* number of extra bits */
|
||||
if (bits < op) {
|
||||
hold += input[_in++] << bits;
|
||||
bits += 8;
|
||||
if (bits < op) {
|
||||
hold += input[_in++] << bits;
|
||||
bits += 8;
|
||||
}
|
||||
}
|
||||
dist += hold & ((1 << op) - 1);
|
||||
//#ifdef INFLATE_STRICT
|
||||
if (dist > dmax) {
|
||||
strm.msg = 'invalid distance too far back';
|
||||
state.mode = BAD;
|
||||
break top;
|
||||
}
|
||||
//#endif
|
||||
hold >>>= op;
|
||||
bits -= op;
|
||||
//Tracevv((stderr, "inflate: distance %u\n", dist));
|
||||
op = _out - beg; /* max distance in output */
|
||||
if (dist > op) {
|
||||
/* see if copy from window */
|
||||
op = dist - op; /* distance back in window */
|
||||
if (op > whave) {
|
||||
if (state.sane) {
|
||||
strm.msg = 'invalid distance too far back';
|
||||
state.mode = BAD;
|
||||
break top;
|
||||
}
|
||||
|
||||
// (!) This block is disabled in zlib defailts,
|
||||
// don't enable it for binary compatibility
|
||||
//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
||||
// if (len <= op - whave) {
|
||||
// do {
|
||||
// output[_out++] = 0;
|
||||
// } while (--len);
|
||||
// continue top;
|
||||
// }
|
||||
// len -= op - whave;
|
||||
// do {
|
||||
// output[_out++] = 0;
|
||||
// } while (--op > whave);
|
||||
// if (op === 0) {
|
||||
// from = _out - dist;
|
||||
// do {
|
||||
// output[_out++] = output[from++];
|
||||
// } while (--len);
|
||||
// continue top;
|
||||
// }
|
||||
//#endif
|
||||
}
|
||||
from = 0; // window index
|
||||
from_source = s_window;
|
||||
if (wnext === 0) {
|
||||
/* very common case */
|
||||
from += wsize - op;
|
||||
if (op < len) {
|
||||
/* some from window */
|
||||
len -= op;
|
||||
do {
|
||||
output[_out++] = s_window[from++];
|
||||
} while (--op);
|
||||
from = _out - dist; /* rest from output */
|
||||
from_source = output;
|
||||
}
|
||||
} else if (wnext < op) {
|
||||
/* wrap around window */
|
||||
from += wsize + wnext - op;
|
||||
op -= wnext;
|
||||
if (op < len) {
|
||||
/* some from end of window */
|
||||
len -= op;
|
||||
do {
|
||||
output[_out++] = s_window[from++];
|
||||
} while (--op);
|
||||
from = 0;
|
||||
if (wnext < len) {
|
||||
/* some from start of window */
|
||||
op = wnext;
|
||||
len -= op;
|
||||
do {
|
||||
output[_out++] = s_window[from++];
|
||||
} while (--op);
|
||||
from = _out - dist; /* rest from output */
|
||||
from_source = output;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* contiguous in window */
|
||||
from += wnext - op;
|
||||
if (op < len) {
|
||||
/* some from window */
|
||||
len -= op;
|
||||
do {
|
||||
output[_out++] = s_window[from++];
|
||||
} while (--op);
|
||||
from = _out - dist; /* rest from output */
|
||||
from_source = output;
|
||||
}
|
||||
}
|
||||
while (len > 2) {
|
||||
output[_out++] = from_source[from++];
|
||||
output[_out++] = from_source[from++];
|
||||
output[_out++] = from_source[from++];
|
||||
len -= 3;
|
||||
}
|
||||
if (len) {
|
||||
output[_out++] = from_source[from++];
|
||||
if (len > 1) {
|
||||
output[_out++] = from_source[from++];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
from = _out - dist; /* copy direct from output */
|
||||
do {
|
||||
/* minimum length is three */
|
||||
output[_out++] = output[from++];
|
||||
output[_out++] = output[from++];
|
||||
output[_out++] = output[from++];
|
||||
len -= 3;
|
||||
} while (len > 2);
|
||||
if (len) {
|
||||
output[_out++] = output[from++];
|
||||
if (len > 1) {
|
||||
output[_out++] = output[from++];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((op & 64) === 0) {
|
||||
/* 2nd level distance code */
|
||||
here = dcode[(here & 0xffff) /*here.val*/ + (hold & ((1 << op) - 1))];
|
||||
continue dodist;
|
||||
} else {
|
||||
strm.msg = 'invalid distance code';
|
||||
state.mode = BAD;
|
||||
break top;
|
||||
}
|
||||
|
||||
break; // need to emulate goto via "continue"
|
||||
}
|
||||
} else if ((op & 64) === 0) {
|
||||
/* 2nd level length code */
|
||||
here = lcode[(here & 0xffff) /*here.val*/ + (hold & ((1 << op) - 1))];
|
||||
continue dolen;
|
||||
} else if (op & 32) {
|
||||
/* end-of-block */
|
||||
//Tracevv((stderr, "inflate: end of block\n"));
|
||||
state.mode = TYPE;
|
||||
break top;
|
||||
} else {
|
||||
strm.msg = 'invalid literal/length code';
|
||||
state.mode = BAD;
|
||||
break top;
|
||||
}
|
||||
|
||||
break; // need to emulate goto via "continue"
|
||||
}
|
||||
} while (_in < last && _out < end);
|
||||
|
||||
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */
|
||||
len = bits >> 3;
|
||||
_in -= len;
|
||||
bits -= len << 3;
|
||||
hold &= (1 << bits) - 1;
|
||||
|
||||
/* update state and return */
|
||||
strm.next_in = _in;
|
||||
strm.next_out = _out;
|
||||
strm.avail_in = _in < last ? 5 + (last - _in) : 5 - (_in - last);
|
||||
strm.avail_out = _out < end ? 257 + (end - _out) : 257 - (_out - end);
|
||||
state.hold = hold;
|
||||
state.bits = bits;
|
||||
return;
|
||||
}
|
||||
1641
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/inflate.js
vendored
Normal file
1641
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/inflate.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
323
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/inftrees.js
vendored
Normal file
323
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/inftrees.js
vendored
Normal file
@ -0,0 +1,323 @@
|
||||
import * as utils from '../utils/common.js';
|
||||
|
||||
var MAXBITS = 15;
|
||||
var ENOUGH_LENS = 852;
|
||||
var ENOUGH_DISTS = 592;
|
||||
//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
|
||||
|
||||
var CODES = 0;
|
||||
var LENS = 1;
|
||||
var DISTS = 2;
|
||||
|
||||
var lbase = [
|
||||
/* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99,
|
||||
115, 131, 163, 195, 227, 258, 0, 0,
|
||||
];
|
||||
|
||||
var lext = [
|
||||
/* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20,
|
||||
20, 20, 20, 21, 21, 21, 21, 16, 72, 78,
|
||||
];
|
||||
|
||||
var dbase = [
|
||||
/* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025,
|
||||
1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0,
|
||||
];
|
||||
|
||||
var dext = [
|
||||
/* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25,
|
||||
25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64,
|
||||
];
|
||||
|
||||
export default function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) {
|
||||
var bits = opts.bits;
|
||||
//here = opts.here; /* table entry for duplication */
|
||||
|
||||
var len = 0; /* a code's length in bits */
|
||||
var sym = 0; /* index of code symbols */
|
||||
var min = 0,
|
||||
max = 0; /* minimum and maximum code lengths */
|
||||
var root = 0; /* number of index bits for root table */
|
||||
var curr = 0; /* number of index bits for current table */
|
||||
var drop = 0; /* code bits to drop for sub-table */
|
||||
var left = 0; /* number of prefix codes available */
|
||||
var used = 0; /* code entries in table used */
|
||||
var huff = 0; /* Huffman code */
|
||||
var incr; /* for incrementing code, index */
|
||||
var fill; /* index for replicating entries */
|
||||
var low; /* low bits for current root entry */
|
||||
var mask; /* mask for low root bits */
|
||||
var next; /* next available space in table */
|
||||
var base = null; /* base value table to use */
|
||||
var base_index = 0;
|
||||
// var shoextra; /* extra bits table to use */
|
||||
var end; /* use base and extra for symbol > end */
|
||||
var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */
|
||||
var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */
|
||||
var extra = null;
|
||||
var extra_index = 0;
|
||||
|
||||
var here_bits, here_op, here_val;
|
||||
|
||||
/*
|
||||
Process a set of code lengths to create a canonical Huffman code. The
|
||||
code lengths are lens[0..codes-1]. Each length corresponds to the
|
||||
symbols 0..codes-1. The Huffman code is generated by first sorting the
|
||||
symbols by length from short to long, and retaining the symbol order
|
||||
for codes with equal lengths. Then the code starts with all zero bits
|
||||
for the first code of the shortest length, and the codes are integer
|
||||
increments for the same length, and zeros are appended as the length
|
||||
increases. For the deflate format, these bits are stored backwards
|
||||
from their more natural integer increment ordering, and so when the
|
||||
decoding tables are built in the large loop below, the integer codes
|
||||
are incremented backwards.
|
||||
|
||||
This routine assumes, but does not check, that all of the entries in
|
||||
lens[] are in the range 0..MAXBITS. The caller must assure this.
|
||||
1..MAXBITS is interpreted as that code length. zero means that that
|
||||
symbol does not occur in this code.
|
||||
|
||||
The codes are sorted by computing a count of codes for each length,
|
||||
creating from that a table of starting indices for each length in the
|
||||
sorted table, and then entering the symbols in order in the sorted
|
||||
table. The sorted table is work[], with that space being provided by
|
||||
the caller.
|
||||
|
||||
The length counts are used for other purposes as well, i.e. finding
|
||||
the minimum and maximum length codes, determining if there are any
|
||||
codes at all, checking for a valid set of lengths, and looking ahead
|
||||
at length counts to determine sub-table sizes when building the
|
||||
decoding tables.
|
||||
*/
|
||||
|
||||
/* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
|
||||
for (len = 0; len <= MAXBITS; len++) {
|
||||
count[len] = 0;
|
||||
}
|
||||
for (sym = 0; sym < codes; sym++) {
|
||||
count[lens[lens_index + sym]]++;
|
||||
}
|
||||
|
||||
/* bound code lengths, force root to be within code lengths */
|
||||
root = bits;
|
||||
for (max = MAXBITS; max >= 1; max--) {
|
||||
if (count[max] !== 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (root > max) {
|
||||
root = max;
|
||||
}
|
||||
if (max === 0) {
|
||||
/* no symbols to code at all */
|
||||
//table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
|
||||
//table.bits[opts.table_index] = 1; //here.bits = (var char)1;
|
||||
//table.val[opts.table_index++] = 0; //here.val = (var short)0;
|
||||
table[table_index++] = (1 << 24) | (64 << 16) | 0;
|
||||
|
||||
//table.op[opts.table_index] = 64;
|
||||
//table.bits[opts.table_index] = 1;
|
||||
//table.val[opts.table_index++] = 0;
|
||||
table[table_index++] = (1 << 24) | (64 << 16) | 0;
|
||||
|
||||
opts.bits = 1;
|
||||
return 0; /* no symbols, but wait for decoding to report error */
|
||||
}
|
||||
for (min = 1; min < max; min++) {
|
||||
if (count[min] !== 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (root < min) {
|
||||
root = min;
|
||||
}
|
||||
|
||||
/* check for an over-subscribed or incomplete set of lengths */
|
||||
left = 1;
|
||||
for (len = 1; len <= MAXBITS; len++) {
|
||||
left <<= 1;
|
||||
left -= count[len];
|
||||
if (left < 0) {
|
||||
return -1;
|
||||
} /* over-subscribed */
|
||||
}
|
||||
if (left > 0 && (type === CODES || max !== 1)) {
|
||||
return -1; /* incomplete set */
|
||||
}
|
||||
|
||||
/* generate offsets into symbol table for each length for sorting */
|
||||
offs[1] = 0;
|
||||
for (len = 1; len < MAXBITS; len++) {
|
||||
offs[len + 1] = offs[len] + count[len];
|
||||
}
|
||||
|
||||
/* sort symbols by length, by symbol order within each length */
|
||||
for (sym = 0; sym < codes; sym++) {
|
||||
if (lens[lens_index + sym] !== 0) {
|
||||
work[offs[lens[lens_index + sym]]++] = sym;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Create and fill in decoding tables. In this loop, the table being
|
||||
filled is at next and has curr index bits. The code being used is huff
|
||||
with length len. That code is converted to an index by dropping drop
|
||||
bits off of the bottom. For codes where len is less than drop + curr,
|
||||
those top drop + curr - len bits are incremented through all values to
|
||||
fill the table with replicated entries.
|
||||
|
||||
root is the number of index bits for the root table. When len exceeds
|
||||
root, sub-tables are created pointed to by the root entry with an index
|
||||
of the low root bits of huff. This is saved in low to check for when a
|
||||
new sub-table should be started. drop is zero when the root table is
|
||||
being filled, and drop is root when sub-tables are being filled.
|
||||
|
||||
When a new sub-table is needed, it is necessary to look ahead in the
|
||||
code lengths to determine what size sub-table is needed. The length
|
||||
counts are used for this, and so count[] is decremented as codes are
|
||||
entered in the tables.
|
||||
|
||||
used keeps track of how many table entries have been allocated from the
|
||||
provided *table space. It is checked for LENS and DIST tables against
|
||||
the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
|
||||
the initial root table size constants. See the comments in inftrees.h
|
||||
for more information.
|
||||
|
||||
sym increments through all symbols, and the loop terminates when
|
||||
all codes of length max, i.e. all codes, have been processed. This
|
||||
routine permits incomplete codes, so another loop after this one fills
|
||||
in the rest of the decoding tables with invalid code markers.
|
||||
*/
|
||||
|
||||
/* set up for code type */
|
||||
// poor man optimization - use if-else instead of switch,
|
||||
// to avoid deopts in old v8
|
||||
if (type === CODES) {
|
||||
base = extra = work; /* dummy value--not used */
|
||||
end = 19;
|
||||
} else if (type === LENS) {
|
||||
base = lbase;
|
||||
base_index -= 257;
|
||||
extra = lext;
|
||||
extra_index -= 257;
|
||||
end = 256;
|
||||
} else {
|
||||
/* DISTS */
|
||||
base = dbase;
|
||||
extra = dext;
|
||||
end = -1;
|
||||
}
|
||||
|
||||
/* initialize opts for loop */
|
||||
huff = 0; /* starting code */
|
||||
sym = 0; /* starting code symbol */
|
||||
len = min; /* starting code length */
|
||||
next = table_index; /* current table to fill in */
|
||||
curr = root; /* current table index bits */
|
||||
drop = 0; /* current bits to drop from code for index */
|
||||
low = -1; /* trigger new sub-table when len > root */
|
||||
used = 1 << root; /* use root table entries */
|
||||
mask = used - 1; /* mask for comparing low */
|
||||
|
||||
/* check available table space */
|
||||
if ((type === LENS && used > ENOUGH_LENS) || (type === DISTS && used > ENOUGH_DISTS)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* process all codes and make table entries */
|
||||
for (;;) {
|
||||
/* create table entry */
|
||||
here_bits = len - drop;
|
||||
if (work[sym] < end) {
|
||||
here_op = 0;
|
||||
here_val = work[sym];
|
||||
} else if (work[sym] > end) {
|
||||
here_op = extra[extra_index + work[sym]];
|
||||
here_val = base[base_index + work[sym]];
|
||||
} else {
|
||||
here_op = 32 + 64; /* end of block */
|
||||
here_val = 0;
|
||||
}
|
||||
|
||||
/* replicate for those indices with low len bits equal to huff */
|
||||
incr = 1 << (len - drop);
|
||||
fill = 1 << curr;
|
||||
min = fill; /* save offset to next table */
|
||||
do {
|
||||
fill -= incr;
|
||||
table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val | 0;
|
||||
} while (fill !== 0);
|
||||
|
||||
/* backwards increment the len-bit code huff */
|
||||
incr = 1 << (len - 1);
|
||||
while (huff & incr) {
|
||||
incr >>= 1;
|
||||
}
|
||||
if (incr !== 0) {
|
||||
huff &= incr - 1;
|
||||
huff += incr;
|
||||
} else {
|
||||
huff = 0;
|
||||
}
|
||||
|
||||
/* go to next symbol, update count, len */
|
||||
sym++;
|
||||
if (--count[len] === 0) {
|
||||
if (len === max) {
|
||||
break;
|
||||
}
|
||||
len = lens[lens_index + work[sym]];
|
||||
}
|
||||
|
||||
/* create new sub-table if needed */
|
||||
if (len > root && (huff & mask) !== low) {
|
||||
/* if first time, transition to sub-tables */
|
||||
if (drop === 0) {
|
||||
drop = root;
|
||||
}
|
||||
|
||||
/* increment past last table */
|
||||
next += min; /* here min is 1 << curr */
|
||||
|
||||
/* determine length of next table */
|
||||
curr = len - drop;
|
||||
left = 1 << curr;
|
||||
while (curr + drop < max) {
|
||||
left -= count[curr + drop];
|
||||
if (left <= 0) {
|
||||
break;
|
||||
}
|
||||
curr++;
|
||||
left <<= 1;
|
||||
}
|
||||
|
||||
/* check for enough space */
|
||||
used += 1 << curr;
|
||||
if ((type === LENS && used > ENOUGH_LENS) || (type === DISTS && used > ENOUGH_DISTS)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* point entry in root table to sub-table */
|
||||
low = huff & mask;
|
||||
/*table.op[low] = curr;
|
||||
table.bits[low] = root;
|
||||
table.val[low] = next - opts.table_index;*/
|
||||
table[low] = (root << 24) | (curr << 16) | (next - table_index) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill in remaining table entry if code is incomplete (guaranteed to have
|
||||
at most one remaining entry, since if the code is incomplete, the
|
||||
maximum code length that was allowed to get this far is one bit) */
|
||||
if (huff !== 0) {
|
||||
//table.op[next + huff] = 64; /* invalid code marker */
|
||||
//table.bits[next + huff] = len - drop;
|
||||
//table.val[next + huff] = 0;
|
||||
table[next + huff] = ((len - drop) << 24) | (64 << 16) | 0;
|
||||
}
|
||||
|
||||
/* set return parameters */
|
||||
//opts.table_index += used;
|
||||
opts.bits = root;
|
||||
return 0;
|
||||
}
|
||||
11
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/messages.js
vendored
Normal file
11
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/messages.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
export default {
|
||||
2: 'need dictionary' /* Z_NEED_DICT 2 */,
|
||||
1: 'stream end' /* Z_STREAM_END 1 */,
|
||||
0: '' /* Z_OK 0 */,
|
||||
'-1': 'file error' /* Z_ERRNO (-1) */,
|
||||
'-2': 'stream error' /* Z_STREAM_ERROR (-2) */,
|
||||
'-3': 'data error' /* Z_DATA_ERROR (-3) */,
|
||||
'-4': 'insufficient memory' /* Z_MEM_ERROR (-4) */,
|
||||
'-5': 'buffer error' /* Z_BUF_ERROR (-5) */,
|
||||
'-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */,
|
||||
};
|
||||
1162
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/trees.js
vendored
Normal file
1162
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/trees.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
24
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/zstream.js
vendored
Normal file
24
gns3server/static/web-ui/assets/vnc-console/novnc/vendor/pako/lib/zlib/zstream.js
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
export default function ZStream() {
|
||||
/* next input byte */
|
||||
this.input = null; // JS specific, because we have no pointers
|
||||
this.next_in = 0;
|
||||
/* number of bytes available at input */
|
||||
this.avail_in = 0;
|
||||
/* total number of input bytes read so far */
|
||||
this.total_in = 0;
|
||||
/* next output byte should be put there */
|
||||
this.output = null; // JS specific, because we have no pointers
|
||||
this.next_out = 0;
|
||||
/* remaining free space at output */
|
||||
this.avail_out = 0;
|
||||
/* total number of bytes output so far */
|
||||
this.total_out = 0;
|
||||
/* last error message, NULL if no error */
|
||||
this.msg = '' /*Z_NULL*/;
|
||||
/* not visible by applications */
|
||||
this.state = null;
|
||||
/* best guess about the data type: binary or text */
|
||||
this.data_type = 2 /*Z_UNKNOWN*/;
|
||||
/* adler32 value of the uncompressed data */
|
||||
this.adler = 0;
|
||||
}
|
||||
171
gns3server/static/web-ui/assets/xpra-html5/js/lib/FileSaver.js
Normal file
171
gns3server/static/web-ui/assets/xpra-html5/js/lib/FileSaver.js
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* FileSaver.js
|
||||
* A saveAs() FileSaver implementation.
|
||||
*
|
||||
* By Eli Grey, http://eligrey.com
|
||||
*
|
||||
* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
|
||||
* source : http://purl.eligrey.com/github/FileSaver.js
|
||||
*/
|
||||
|
||||
// The one and only way of getting global scope in all environments
|
||||
// https://stackoverflow.com/q/3277182/1008999
|
||||
var _global = typeof window === 'object' && window.window === window
|
||||
? window : typeof self === 'object' && self.self === self
|
||||
? self : typeof global === 'object' && global.global === global
|
||||
? global
|
||||
: this
|
||||
|
||||
function bom (blob, opts) {
|
||||
if (typeof opts === 'undefined') opts = { autoBom: false }
|
||||
else if (typeof opts !== 'object') {
|
||||
console.warn('Deprecated: Expected third argument to be a object')
|
||||
opts = { autoBom: !opts }
|
||||
}
|
||||
|
||||
// prepend BOM for UTF-8 XML and text/* types (including HTML)
|
||||
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
|
||||
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
||||
return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type })
|
||||
}
|
||||
return blob
|
||||
}
|
||||
|
||||
function download (url, name, opts) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open('GET', url)
|
||||
xhr.responseType = 'blob'
|
||||
xhr.onload = function () {
|
||||
saveAs(xhr.response, name, opts)
|
||||
}
|
||||
xhr.onerror = function () {
|
||||
console.error('could not download file')
|
||||
}
|
||||
xhr.send()
|
||||
}
|
||||
|
||||
function corsEnabled (url) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
// use sync to avoid popup blocker
|
||||
xhr.open('HEAD', url, false)
|
||||
try {
|
||||
xhr.send()
|
||||
} catch (e) {}
|
||||
return xhr.status >= 200 && xhr.status <= 299
|
||||
}
|
||||
|
||||
// `a.click()` doesn't work for all browsers (#465)
|
||||
function click (node) {
|
||||
try {
|
||||
node.dispatchEvent(new MouseEvent('click'))
|
||||
} catch (e) {
|
||||
var evt = document.createEvent('MouseEvents')
|
||||
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
|
||||
20, false, false, false, false, 0, null)
|
||||
node.dispatchEvent(evt)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect WebView inside a native macOS app by ruling out all browsers
|
||||
// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
|
||||
// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
|
||||
var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent)
|
||||
|
||||
var saveAs = _global.saveAs || (
|
||||
// probably in some web worker
|
||||
(typeof window !== 'object' || window !== _global)
|
||||
? function saveAs () { /* noop */ }
|
||||
|
||||
// Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
|
||||
: ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)
|
||||
? function saveAs (blob, name, opts) {
|
||||
var URL = _global.URL || _global.webkitURL
|
||||
var a = document.createElement('a')
|
||||
name = name || blob.name || 'download'
|
||||
|
||||
a.download = name
|
||||
a.rel = 'noopener' // tabnabbing
|
||||
|
||||
// TODO: detect chrome extensions & packaged apps
|
||||
// a.target = '_blank'
|
||||
|
||||
if (typeof blob === 'string') {
|
||||
// Support regular links
|
||||
a.href = blob
|
||||
if (a.origin !== location.origin) {
|
||||
corsEnabled(a.href)
|
||||
? download(blob, name, opts)
|
||||
: click(a, a.target = '_blank')
|
||||
} else {
|
||||
click(a)
|
||||
}
|
||||
} else {
|
||||
// Support blobs
|
||||
a.href = URL.createObjectURL(blob)
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
|
||||
setTimeout(function () { click(a) }, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Use msSaveOrOpenBlob as a second approach
|
||||
: 'msSaveOrOpenBlob' in navigator
|
||||
? function saveAs (blob, name, opts) {
|
||||
name = name || blob.name || 'download'
|
||||
|
||||
if (typeof blob === 'string') {
|
||||
if (corsEnabled(blob)) {
|
||||
download(blob, name, opts)
|
||||
} else {
|
||||
var a = document.createElement('a')
|
||||
a.href = blob
|
||||
a.target = '_blank'
|
||||
setTimeout(function () { click(a) })
|
||||
}
|
||||
} else {
|
||||
navigator.msSaveOrOpenBlob(bom(blob, opts), name)
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to using FileReader and a popup
|
||||
: function saveAs (blob, name, opts, popup) {
|
||||
// Open a popup immediately do go around popup blocker
|
||||
// Mostly only available on user interaction and the fileReader is async so...
|
||||
popup = popup || open('', '_blank')
|
||||
if (popup) {
|
||||
popup.document.title =
|
||||
popup.document.body.innerText = 'downloading...'
|
||||
}
|
||||
|
||||
if (typeof blob === 'string') return download(blob, name, opts)
|
||||
|
||||
var force = blob.type === 'application/octet-stream'
|
||||
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
|
||||
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
|
||||
|
||||
if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {
|
||||
// Safari doesn't allow downloading of blob URLs
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function () {
|
||||
var url = reader.result
|
||||
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
|
||||
if (popup) popup.location.href = url
|
||||
else location = url
|
||||
popup = null // reverse-tabnabbing #460
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
} else {
|
||||
var URL = _global.URL || _global.webkitURL
|
||||
var url = URL.createObjectURL(blob)
|
||||
if (popup) popup.location = url
|
||||
else location.href = url
|
||||
popup = null // reverse-tabnabbing #460
|
||||
setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
_global.saveAs = saveAs.saveAs = saveAs
|
||||
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = saveAs;
|
||||
}
|
||||
317
gns3server/static/web-ui/assets/xpra-html5/js/lib/StreamSaver.js
Normal file
317
gns3server/static/web-ui/assets/xpra-html5/js/lib/StreamSaver.js
Normal file
@ -0,0 +1,317 @@
|
||||
/*! streamsaver. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
|
||||
|
||||
/* global chrome location ReadableStream define MessageChannel TransformStream */
|
||||
|
||||
;((name, definition) => {
|
||||
typeof module !== 'undefined'
|
||||
? module.exports = definition()
|
||||
: typeof define === 'function' && typeof define.amd === 'object'
|
||||
? define(definition)
|
||||
: this[name] = definition()
|
||||
})('streamSaver', () => {
|
||||
'use strict'
|
||||
|
||||
const global = typeof window === 'object' ? window : this
|
||||
if (!global.HTMLElement) console.warn('streamsaver is meant to run on browsers main thread')
|
||||
|
||||
let mitmTransporter = null
|
||||
let supportsTransferable = false
|
||||
const test = fn => { try { fn() } catch (e) {} }
|
||||
const ponyfill = global.WebStreamsPolyfill || {}
|
||||
const isSecureContext = global.isSecureContext
|
||||
// TODO: Must come up with a real detection test (#69)
|
||||
let useBlobFallback = /constructor/i.test(global.HTMLElement) || !!global.safari || !!global.WebKitPoint
|
||||
const downloadStrategy = isSecureContext || 'MozAppearance' in document.documentElement.style
|
||||
? 'iframe'
|
||||
: 'navigate'
|
||||
|
||||
const streamSaver = {
|
||||
createWriteStream,
|
||||
WritableStream: global.WritableStream || ponyfill.WritableStream,
|
||||
supported: true,
|
||||
version: { full: '2.0.5', major: 2, minor: 0, dot: 5 },
|
||||
mitm: './mitm.html'
|
||||
}
|
||||
|
||||
/**
|
||||
* create a hidden iframe and append it to the DOM (body)
|
||||
*
|
||||
* @param {string} src page to load
|
||||
* @return {HTMLIFrameElement} page to load
|
||||
*/
|
||||
function makeIframe (src) {
|
||||
if (!src) throw new Error('meh')
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.hidden = true
|
||||
iframe.src = src
|
||||
iframe.loaded = false
|
||||
iframe.name = 'iframe'
|
||||
iframe.isIframe = true
|
||||
iframe.postMessage = (...args) => iframe.contentWindow.postMessage(...args)
|
||||
iframe.addEventListener('load', () => {
|
||||
iframe.loaded = true
|
||||
}, { once: true })
|
||||
document.body.appendChild(iframe)
|
||||
return iframe
|
||||
}
|
||||
|
||||
/**
|
||||
* create a popup that simulates the basic things
|
||||
* of what a iframe can do
|
||||
*
|
||||
* @param {string} src page to load
|
||||
* @return {object} iframe like object
|
||||
*/
|
||||
function makePopup (src) {
|
||||
const options = 'width=200,height=100'
|
||||
const delegate = document.createDocumentFragment()
|
||||
const popup = {
|
||||
frame: global.open(src, 'popup', options),
|
||||
loaded: false,
|
||||
isIframe: false,
|
||||
isPopup: true,
|
||||
remove () { popup.frame.close() },
|
||||
addEventListener (...args) { delegate.addEventListener(...args) },
|
||||
dispatchEvent (...args) { delegate.dispatchEvent(...args) },
|
||||
removeEventListener (...args) { delegate.removeEventListener(...args) },
|
||||
postMessage (...args) { popup.frame.postMessage(...args) }
|
||||
}
|
||||
|
||||
const onReady = evt => {
|
||||
if (evt.source === popup.frame) {
|
||||
popup.loaded = true
|
||||
global.removeEventListener('message', onReady)
|
||||
popup.dispatchEvent(new Event('load'))
|
||||
}
|
||||
}
|
||||
|
||||
global.addEventListener('message', onReady)
|
||||
|
||||
return popup
|
||||
}
|
||||
|
||||
try {
|
||||
// We can't look for service worker since it may still work on http
|
||||
new Response(new ReadableStream())
|
||||
if (isSecureContext && !('serviceWorker' in navigator)) {
|
||||
useBlobFallback = true
|
||||
}
|
||||
} catch (err) {
|
||||
useBlobFallback = true
|
||||
}
|
||||
|
||||
test(() => {
|
||||
// Transferable stream was first enabled in chrome v73 behind a flag
|
||||
const { readable } = new TransformStream()
|
||||
const mc = new MessageChannel()
|
||||
mc.port1.postMessage(readable, [readable])
|
||||
mc.port1.close()
|
||||
mc.port2.close()
|
||||
supportsTransferable = true
|
||||
// Freeze TransformStream object (can only work with native)
|
||||
Object.defineProperty(streamSaver, 'TransformStream', {
|
||||
configurable: false,
|
||||
writable: false,
|
||||
value: TransformStream
|
||||
})
|
||||
})
|
||||
|
||||
function loadTransporter () {
|
||||
if (!mitmTransporter) {
|
||||
mitmTransporter = isSecureContext
|
||||
? makeIframe(streamSaver.mitm)
|
||||
: makePopup(streamSaver.mitm)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} filename filename that should be used
|
||||
* @param {object} options [description]
|
||||
* @param {number} size deprecated
|
||||
* @return {WritableStream<Uint8Array>}
|
||||
*/
|
||||
function createWriteStream (filename, options, size) {
|
||||
let opts = {
|
||||
size: null,
|
||||
pathname: null,
|
||||
writableStrategy: undefined,
|
||||
readableStrategy: undefined
|
||||
}
|
||||
|
||||
let bytesWritten = 0 // by StreamSaver.js (not the service worker)
|
||||
let downloadUrl = null
|
||||
let channel = null
|
||||
let ts = null
|
||||
|
||||
// normalize arguments
|
||||
if (Number.isFinite(options)) {
|
||||
[ size, options ] = [ options, size ]
|
||||
console.warn('[StreamSaver] Deprecated pass an object as 2nd argument when creating a write stream')
|
||||
opts.size = size
|
||||
opts.writableStrategy = options
|
||||
} else if (options && options.highWaterMark) {
|
||||
console.warn('[StreamSaver] Deprecated pass an object as 2nd argument when creating a write stream')
|
||||
opts.size = size
|
||||
opts.writableStrategy = options
|
||||
} else {
|
||||
opts = options || {}
|
||||
}
|
||||
if (!useBlobFallback) {
|
||||
loadTransporter()
|
||||
|
||||
channel = new MessageChannel()
|
||||
|
||||
// Make filename RFC5987 compatible
|
||||
filename = encodeURIComponent(filename.replace(/\//g, ':'))
|
||||
.replace(/['()]/g, escape)
|
||||
.replace(/\*/g, '%2A')
|
||||
|
||||
const response = {
|
||||
transferringReadable: supportsTransferable,
|
||||
pathname: opts.pathname || Math.random().toString().slice(-6) + '/' + filename,
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream; charset=utf-8',
|
||||
'Content-Disposition': "attachment; filename*=UTF-8''" + filename
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.size) {
|
||||
response.headers['Content-Length'] = opts.size
|
||||
}
|
||||
|
||||
const args = [ response, '*', [ channel.port2 ] ]
|
||||
|
||||
if (supportsTransferable) {
|
||||
const transformer = downloadStrategy === 'iframe' ? undefined : {
|
||||
// This transformer & flush method is only used by insecure context.
|
||||
transform (chunk, controller) {
|
||||
if (!(chunk instanceof Uint8Array)) {
|
||||
throw new TypeError('Can only write Uint8Arrays')
|
||||
}
|
||||
bytesWritten += chunk.length
|
||||
controller.enqueue(chunk)
|
||||
|
||||
if (downloadUrl) {
|
||||
location.href = downloadUrl
|
||||
downloadUrl = null
|
||||
}
|
||||
},
|
||||
flush () {
|
||||
if (downloadUrl) {
|
||||
location.href = downloadUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
ts = new streamSaver.TransformStream(
|
||||
transformer,
|
||||
opts.writableStrategy,
|
||||
opts.readableStrategy
|
||||
)
|
||||
const readableStream = ts.readable
|
||||
|
||||
channel.port1.postMessage({ readableStream }, [ readableStream ])
|
||||
}
|
||||
|
||||
channel.port1.onmessage = evt => {
|
||||
// Service worker sent us a link that we should open.
|
||||
if (evt.data.download) {
|
||||
// Special treatment for popup...
|
||||
if (downloadStrategy === 'navigate') {
|
||||
mitmTransporter.remove()
|
||||
mitmTransporter = null
|
||||
if (bytesWritten) {
|
||||
location.href = evt.data.download
|
||||
} else {
|
||||
downloadUrl = evt.data.download
|
||||
}
|
||||
} else {
|
||||
if (mitmTransporter.isPopup) {
|
||||
mitmTransporter.remove()
|
||||
mitmTransporter = null
|
||||
// Special case for firefox, they can keep sw alive with fetch
|
||||
if (downloadStrategy === 'iframe') {
|
||||
makeIframe(streamSaver.mitm)
|
||||
}
|
||||
}
|
||||
|
||||
// We never remove this iframes b/c it can interrupt saving
|
||||
makeIframe(evt.data.download)
|
||||
}
|
||||
} else if (evt.data.abort) {
|
||||
chunks = []
|
||||
channel.port1.postMessage('abort') //send back so controller is aborted
|
||||
channel.port1.onmessage = null
|
||||
channel.port1.close()
|
||||
channel.port2.close()
|
||||
channel = null
|
||||
}
|
||||
}
|
||||
|
||||
if (mitmTransporter.loaded) {
|
||||
mitmTransporter.postMessage(...args)
|
||||
} else {
|
||||
mitmTransporter.addEventListener('load', () => {
|
||||
mitmTransporter.postMessage(...args)
|
||||
}, { once: true })
|
||||
}
|
||||
}
|
||||
|
||||
let chunks = []
|
||||
|
||||
return (!useBlobFallback && ts && ts.writable) || new streamSaver.WritableStream({
|
||||
write (chunk) {
|
||||
if (!(chunk instanceof Uint8Array)) {
|
||||
throw new TypeError('Can only write Uint8Arrays')
|
||||
}
|
||||
if (useBlobFallback) {
|
||||
// Safari... The new IE6
|
||||
// https://github.com/jimmywarting/StreamSaver.js/issues/69
|
||||
//
|
||||
// even though it has everything it fails to download anything
|
||||
// that comes from the service worker..!
|
||||
chunks.push(chunk)
|
||||
return
|
||||
}
|
||||
|
||||
// is called when a new chunk of data is ready to be written
|
||||
// to the underlying sink. It can return a promise to signal
|
||||
// success or failure of the write operation. The stream
|
||||
// implementation guarantees that this method will be called
|
||||
// only after previous writes have succeeded, and never after
|
||||
// close or abort is called.
|
||||
|
||||
// TODO: Kind of important that service worker respond back when
|
||||
// it has been written. Otherwise we can't handle backpressure
|
||||
// EDIT: Transferable streams solves this...
|
||||
channel.port1.postMessage(chunk)
|
||||
bytesWritten += chunk.length
|
||||
|
||||
if (downloadUrl) {
|
||||
location.href = downloadUrl
|
||||
downloadUrl = null
|
||||
}
|
||||
},
|
||||
close () {
|
||||
if (useBlobFallback) {
|
||||
const blob = new Blob(chunks, { type: 'application/octet-stream; charset=utf-8' })
|
||||
const link = document.createElement('a')
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = filename
|
||||
link.click()
|
||||
} else {
|
||||
channel.port1.postMessage('end')
|
||||
}
|
||||
},
|
||||
abort () {
|
||||
chunks = []
|
||||
channel.port1.postMessage('abort')
|
||||
channel.port1.onmessage = null
|
||||
channel.port1.close()
|
||||
channel.port2.close()
|
||||
channel = null
|
||||
}
|
||||
}, opts.writableStrategy)
|
||||
}
|
||||
|
||||
return streamSaver
|
||||
})
|
||||
4655
gns3server/static/web-ui/assets/xpra-html5/js/lib/aurora/aac.js
Normal file
4655
gns3server/static/web-ui/assets/xpra-html5/js/lib/aurora/aac.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
||||
// based on aurora-websocket.js https://github.com/fsbdev/aurora-websocket
|
||||
// MIT licensed
|
||||
|
||||
(function() {
|
||||
var __hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
AV.XpraSource = (function(_super) {
|
||||
__extends(XpraSource, _super);
|
||||
|
||||
function XpraSource() {
|
||||
// constructor
|
||||
}
|
||||
|
||||
XpraSource.prototype.start = function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
XpraSource.prototype.pause = function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
XpraSource.prototype.reset = function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
XpraSource.prototype._on_data = function(data) {
|
||||
var buf = new AV.Buffer(data);
|
||||
return this.emit('data', buf);
|
||||
};
|
||||
|
||||
return XpraSource;
|
||||
|
||||
})(AV.EventEmitter);
|
||||
|
||||
AV.Asset.fromXpraSource = function() {
|
||||
var source;
|
||||
source = new AV.XpraSource();
|
||||
return new AV.Asset(source);
|
||||
};
|
||||
|
||||
AV.Player.fromXpraSource = function() {
|
||||
var asset;
|
||||
asset = AV.Asset.fromXpraSource();
|
||||
return new AV.Player(asset);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
4003
gns3server/static/web-ui/assets/xpra-html5/js/lib/aurora/aurora.js
Normal file
4003
gns3server/static/web-ui/assets/xpra-html5/js/lib/aurora/aurora.js
Normal file
File diff suppressed because one or more lines are too long
799
gns3server/static/web-ui/assets/xpra-html5/js/lib/aurora/flac.js
Normal file
799
gns3server/static/web-ui/assets/xpra-html5/js/lib/aurora/flac.js
Normal file
@ -0,0 +1,799 @@
|
||||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
exports.FLACDemuxer = require('./src/demuxer');
|
||||
exports.FLACDecoder = require('./src/decoder');
|
||||
require('./src/ogg');
|
||||
|
||||
},{"./src/decoder":2,"./src/demuxer":3,"./src/ogg":4}],2:[function(require,module,exports){
|
||||
(function (global){
|
||||
/*
|
||||
* FLAC.js - Free Lossless Audio Codec decoder in JavaScript
|
||||
* Original C version from FFmpeg (c) 2003 Alex Beregszaszi
|
||||
* JavaScript port by Devon Govett and Jens Nockert of Official.fm Labs
|
||||
*
|
||||
* Licensed under the same terms as the original. The original
|
||||
* license follows.
|
||||
*
|
||||
* FLAC.js is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FLAC.js 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. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
var AV = (typeof window !== "undefined" ? window['AV'] : typeof global !== "undefined" ? global['AV'] : null);
|
||||
|
||||
var FLACDecoder = AV.Decoder.extend(function() {
|
||||
AV.Decoder.register('flac', this);
|
||||
|
||||
this.prototype.setCookie = function(cookie) {
|
||||
this.cookie = cookie;
|
||||
|
||||
// initialize arrays
|
||||
this.decoded = [];
|
||||
for (var i = 0; i < this.format.channelsPerFrame; i++) {
|
||||
this.decoded[i] = new Int32Array(cookie.maxBlockSize);
|
||||
}
|
||||
|
||||
// for 24 bit lpc frames, this is used to simulate a 64 bit int
|
||||
this.lpc_total = new Int32Array(2);
|
||||
};
|
||||
|
||||
const BLOCK_SIZES = new Int16Array([
|
||||
0, 192, 576 << 0, 576 << 1, 576 << 2, 576 << 3, 0, 0,
|
||||
256 << 0, 256 << 1, 256 << 2, 256 << 3, 256 << 4, 256 << 5, 256 << 6, 256 << 7
|
||||
]);
|
||||
|
||||
const SAMPLE_RATES = new Int32Array([
|
||||
0, 88200, 176400, 192000,
|
||||
8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
|
||||
0, 0, 0, 0
|
||||
]);
|
||||
|
||||
const SAMPLE_SIZES = new Int8Array([
|
||||
0, 8, 12, 0, 16, 20, 24, 0
|
||||
]);
|
||||
|
||||
const MAX_CHANNELS = 8,
|
||||
CHMODE_INDEPENDENT = 0,
|
||||
CHMODE_LEFT_SIDE = 8,
|
||||
CHMODE_RIGHT_SIDE = 9,
|
||||
CHMODE_MID_SIDE = 10;
|
||||
|
||||
this.prototype.readChunk = function() {
|
||||
var stream = this.bitstream;
|
||||
if (!stream.available(32))
|
||||
return;
|
||||
|
||||
// frame sync code
|
||||
if ((stream.read(15) & 0x7FFF) !== 0x7FFC)
|
||||
throw new Error('Invalid sync code');
|
||||
|
||||
var isVarSize = stream.read(1), // variable block size stream code
|
||||
bsCode = stream.read(4), // block size
|
||||
srCode = stream.read(4), // sample rate code
|
||||
chMode = stream.read(4), // channel mode
|
||||
bpsCode = stream.read(3); // bits per sample
|
||||
|
||||
stream.advance(1); // reserved bit
|
||||
|
||||
// channels
|
||||
this.chMode = chMode;
|
||||
var channels;
|
||||
|
||||
if (chMode < MAX_CHANNELS) {
|
||||
channels = chMode + 1;
|
||||
this.chMode = CHMODE_INDEPENDENT;
|
||||
} else if (chMode <= CHMODE_MID_SIDE) {
|
||||
channels = 2;
|
||||
} else {
|
||||
throw new Error('Invalid channel mode');
|
||||
}
|
||||
|
||||
if (channels !== this.format.channelsPerFrame)
|
||||
throw new Error('Switching channel layout mid-stream not supported.');
|
||||
|
||||
// bits per sample
|
||||
if (bpsCode === 3 || bpsCode === 7)
|
||||
throw new Error('Invalid sample size code');
|
||||
|
||||
this.bps = SAMPLE_SIZES[bpsCode];
|
||||
if (this.bps !== this.format.bitsPerChannel)
|
||||
throw new Error('Switching bits per sample mid-stream not supported.');
|
||||
|
||||
// sample number or frame number
|
||||
// see http://www.hydrogenaudio.org/forums/index.php?s=ea7085ffe6d57132c36e6105c0d434c9&showtopic=88390&pid=754269&st=0&#entry754269
|
||||
var ones = 0;
|
||||
while (stream.read(1) === 1)
|
||||
ones++;
|
||||
|
||||
var frame_or_sample_num = stream.read(7 - ones);
|
||||
for (; ones > 1; ones--) {
|
||||
stream.advance(2); // == 2
|
||||
frame_or_sample_num = (frame_or_sample_num << 6) | stream.read(6);
|
||||
}
|
||||
|
||||
// block size
|
||||
if (bsCode === 0)
|
||||
throw new Error('Reserved blocksize code');
|
||||
else if (bsCode === 6)
|
||||
this.blockSize = stream.read(8) + 1;
|
||||
else if (bsCode === 7)
|
||||
this.blockSize = stream.read(16) + 1;
|
||||
else
|
||||
this.blockSize = BLOCK_SIZES[bsCode];
|
||||
|
||||
// sample rate
|
||||
var sampleRate;
|
||||
if (srCode < 12)
|
||||
sampleRate = SAMPLE_RATES[srCode];
|
||||
else if (srCode === 12)
|
||||
sampleRate = stream.read(8) * 1000;
|
||||
else if (srCode === 13)
|
||||
sampleRate = stream.read(16);
|
||||
else if (srCode === 14)
|
||||
sampleRate = stream.read(16) * 10;
|
||||
else
|
||||
throw new Error('Invalid sample rate code');
|
||||
|
||||
stream.advance(8); // skip CRC check
|
||||
|
||||
// subframes
|
||||
for (var i = 0; i < channels; i++)
|
||||
this.decodeSubframe(i);
|
||||
|
||||
stream.align();
|
||||
stream.advance(16); // skip CRC frame footer
|
||||
|
||||
var is32 = this.bps > 16,
|
||||
output = new ArrayBuffer(this.blockSize * channels * (is32 ? 4 : 2)),
|
||||
buf = is32 ? new Int32Array(output) : new Int16Array(output),
|
||||
blockSize = this.blockSize,
|
||||
decoded = this.decoded,
|
||||
j = 0;
|
||||
|
||||
switch (this.chMode) {
|
||||
case CHMODE_INDEPENDENT:
|
||||
for (var k = 0; k < blockSize; k++) {
|
||||
for (var i = 0; i < channels; i++) {
|
||||
buf[j++] = decoded[i][k];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CHMODE_LEFT_SIDE:
|
||||
for (var i = 0; i < blockSize; i++) {
|
||||
var left = decoded[0][i],
|
||||
right = decoded[1][i];
|
||||
|
||||
buf[j++] = left;
|
||||
buf[j++] = (left - right);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHMODE_RIGHT_SIDE:
|
||||
for (var i = 0; i < blockSize; i++) {
|
||||
var left = decoded[0][i],
|
||||
right = decoded[1][i];
|
||||
|
||||
buf[j++] = (left + right);
|
||||
buf[j++] = right;
|
||||
}
|
||||
break;
|
||||
|
||||
case CHMODE_MID_SIDE:
|
||||
for (var i = 0; i < blockSize; i++) {
|
||||
var left = decoded[0][i],
|
||||
right = decoded[1][i];
|
||||
|
||||
left -= right >> 1;
|
||||
buf[j++] = (left + right);
|
||||
buf[j++] = left;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return buf;
|
||||
};
|
||||
|
||||
this.prototype.decodeSubframe = function(channel) {
|
||||
var wasted = 0,
|
||||
stream = this.bitstream,
|
||||
blockSize = this.blockSize,
|
||||
decoded = this.decoded;
|
||||
|
||||
this.curr_bps = this.bps;
|
||||
if (channel === 0) {
|
||||
if (this.chMode === CHMODE_RIGHT_SIDE)
|
||||
this.curr_bps++;
|
||||
} else {
|
||||
if (this.chMode === CHMODE_LEFT_SIDE || this.chMode === CHMODE_MID_SIDE)
|
||||
this.curr_bps++;
|
||||
}
|
||||
|
||||
if (stream.read(1))
|
||||
throw new Error("Invalid subframe padding");
|
||||
|
||||
var type = stream.read(6);
|
||||
|
||||
if (stream.read(1)) {
|
||||
wasted = 1;
|
||||
while (!stream.read(1))
|
||||
wasted++;
|
||||
|
||||
this.curr_bps -= wasted;
|
||||
}
|
||||
|
||||
if (this.curr_bps > 32)
|
||||
throw new Error("decorrelated bit depth > 32 (" + this.curr_bps + ")");
|
||||
|
||||
if (type === 0) {
|
||||
var tmp = stream.read(this.curr_bps, true);
|
||||
for (var i = 0; i < blockSize; i++)
|
||||
decoded[channel][i] = tmp;
|
||||
|
||||
} else if (type === 1) {
|
||||
var bps = this.curr_bps;
|
||||
for (var i = 0; i < blockSize; i++)
|
||||
decoded[channel][i] = stream.read(bps, true);
|
||||
|
||||
} else if ((type >= 8) && (type <= 12)) {
|
||||
this.decode_subframe_fixed(channel, type & ~0x8);
|
||||
|
||||
} else if (type >= 32) {
|
||||
this.decode_subframe_lpc(channel, (type & ~0x20) + 1);
|
||||
|
||||
} else {
|
||||
throw new Error("Invalid coding type");
|
||||
}
|
||||
|
||||
if (wasted) {
|
||||
for (var i = 0; i < blockSize; i++)
|
||||
decoded[channel][i] <<= wasted;
|
||||
}
|
||||
};
|
||||
|
||||
this.prototype.decode_subframe_fixed = function(channel, predictor_order) {
|
||||
var decoded = this.decoded[channel],
|
||||
stream = this.bitstream,
|
||||
bps = this.curr_bps;
|
||||
|
||||
// warm up samples
|
||||
for (var i = 0; i < predictor_order; i++)
|
||||
decoded[i] = stream.read(bps, true);
|
||||
|
||||
this.decode_residuals(channel, predictor_order);
|
||||
|
||||
var a = 0, b = 0, c = 0, d = 0;
|
||||
|
||||
if (predictor_order > 0)
|
||||
a = decoded[predictor_order - 1];
|
||||
|
||||
if (predictor_order > 1)
|
||||
b = a - decoded[predictor_order - 2];
|
||||
|
||||
if (predictor_order > 2)
|
||||
c = b - decoded[predictor_order - 2] + decoded[predictor_order - 3];
|
||||
|
||||
if (predictor_order > 3)
|
||||
d = c - decoded[predictor_order - 2] + 2 * decoded[predictor_order - 3] - decoded[predictor_order - 4];
|
||||
|
||||
switch (predictor_order) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
var abcd = new Int32Array([a, b, c, d]),
|
||||
blockSize = this.blockSize;
|
||||
|
||||
for (var i = predictor_order; i < blockSize; i++) {
|
||||
abcd[predictor_order - 1] += decoded[i];
|
||||
|
||||
for (var j = predictor_order - 2; j >= 0; j--) {
|
||||
abcd[j] += abcd[j + 1];
|
||||
}
|
||||
|
||||
decoded[i] = abcd[0];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Invalid Predictor Order " + predictor_order);
|
||||
}
|
||||
};
|
||||
|
||||
this.prototype.decode_subframe_lpc = function(channel, predictor_order) {
|
||||
var stream = this.bitstream,
|
||||
decoded = this.decoded[channel],
|
||||
bps = this.curr_bps,
|
||||
blockSize = this.blockSize;
|
||||
|
||||
// warm up samples
|
||||
for (var i = 0; i < predictor_order; i++) {
|
||||
decoded[i] = stream.read(bps, true);
|
||||
}
|
||||
|
||||
var coeff_prec = stream.read(4) + 1;
|
||||
if (coeff_prec === 16)
|
||||
throw new Error("Invalid coefficient precision");
|
||||
|
||||
var qlevel = stream.read(5, true);
|
||||
if (qlevel < 0)
|
||||
throw new Error("Negative qlevel, maybe buggy stream");
|
||||
|
||||
var coeffs = new Int32Array(32);
|
||||
for (var i = 0; i < predictor_order; i++) {
|
||||
coeffs[i] = stream.read(coeff_prec, true);
|
||||
}
|
||||
|
||||
this.decode_residuals(channel, predictor_order);
|
||||
|
||||
if (this.bps <= 16) {
|
||||
for (var i = predictor_order; i < blockSize - 1; i += 2) {
|
||||
var d = decoded[i - predictor_order],
|
||||
s0 = 0, s1 = 0, c = 0;
|
||||
|
||||
for (var j = predictor_order - 1; j > 0; j--) {
|
||||
c = coeffs[j];
|
||||
s0 += c * d;
|
||||
d = decoded[i - j];
|
||||
s1 += c * d;
|
||||
}
|
||||
|
||||
c = coeffs[0];
|
||||
s0 += c * d;
|
||||
d = decoded[i] += (s0 >> qlevel);
|
||||
s1 += c * d;
|
||||
decoded[i + 1] += (s1 >> qlevel);
|
||||
}
|
||||
|
||||
if (i < blockSize) {
|
||||
var sum = 0;
|
||||
for (var j = 0; j < predictor_order; j++)
|
||||
sum += coeffs[j] * decoded[i - j - 1];
|
||||
|
||||
decoded[i] += (sum >> qlevel);
|
||||
}
|
||||
} else {
|
||||
// simulate 64 bit integer using an array of two 32 bit ints
|
||||
var total = this.lpc_total;
|
||||
for (var i = predictor_order; i < blockSize; i++) {
|
||||
// reset total to 0
|
||||
total[0] = 0;
|
||||
total[1] = 0;
|
||||
|
||||
for (j = 0; j < predictor_order; j++) {
|
||||
// simulate `total += coeffs[j] * decoded[i - j - 1]`
|
||||
multiply_add(total, coeffs[j], decoded[i - j - 1]);
|
||||
}
|
||||
|
||||
// simulate `decoded[i] += total >> qlevel`
|
||||
// we know that qlevel < 32 since it is a 5 bit field (see above)
|
||||
decoded[i] += (total[0] >>> qlevel) | (total[1] << (32 - qlevel));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const TWO_PWR_32_DBL = Math.pow(2, 32);
|
||||
|
||||
// performs `total += a * b` on a simulated 64 bit int
|
||||
// total is an Int32Array(2)
|
||||
// a and b are JS numbers (32 bit ints)
|
||||
function multiply_add(total, a, b) {
|
||||
// multiply a * b (we can use normal JS multiplication for this)
|
||||
var r = a * b;
|
||||
var n = r < 0;
|
||||
if (n)
|
||||
r = -r;
|
||||
|
||||
var r_low = (r % TWO_PWR_32_DBL) | 0;
|
||||
var r_high = (r / TWO_PWR_32_DBL) | 0;
|
||||
if (n) {
|
||||
r_low = ~r_low + 1;
|
||||
r_high = ~r_high;
|
||||
}
|
||||
|
||||
// add result to total
|
||||
var a48 = total[1] >>> 16;
|
||||
var a32 = total[1] & 0xFFFF;
|
||||
var a16 = total[0] >>> 16;
|
||||
var a00 = total[0] & 0xFFFF;
|
||||
|
||||
var b48 = r_high >>> 16;
|
||||
var b32 = r_high & 0xFFFF;
|
||||
var b16 = r_low >>> 16;
|
||||
var b00 = r_low & 0xFFFF;
|
||||
|
||||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
|
||||
c00 += a00 + b00;
|
||||
c16 += c00 >>> 16;
|
||||
c00 &= 0xFFFF;
|
||||
c16 += a16 + b16;
|
||||
c32 += c16 >>> 16;
|
||||
c16 &= 0xFFFF;
|
||||
c32 += a32 + b32;
|
||||
c48 += c32 >>> 16;
|
||||
c32 &= 0xFFFF;
|
||||
c48 += a48 + b48;
|
||||
c48 &= 0xFFFF;
|
||||
|
||||
// store result back in total
|
||||
total[0] = (c16 << 16) | c00;
|
||||
total[1] = (c48 << 16) | c32;
|
||||
}
|
||||
|
||||
const INT_MAX = 32767;
|
||||
|
||||
this.prototype.decode_residuals = function(channel, predictor_order) {
|
||||
var stream = this.bitstream,
|
||||
method_type = stream.read(2);
|
||||
|
||||
if (method_type > 1)
|
||||
throw new Error('Illegal residual coding method ' + method_type);
|
||||
|
||||
var rice_order = stream.read(4),
|
||||
samples = (this.blockSize >>> rice_order);
|
||||
|
||||
if (predictor_order > samples)
|
||||
throw new Error('Invalid predictor order ' + predictor_order + ' > ' + samples);
|
||||
|
||||
var decoded = this.decoded[channel],
|
||||
sample = predictor_order,
|
||||
i = predictor_order;
|
||||
|
||||
for (var partition = 0; partition < (1 << rice_order); partition++) {
|
||||
var tmp = stream.read(method_type === 0 ? 4 : 5);
|
||||
|
||||
if (tmp === (method_type === 0 ? 15 : 31)) {
|
||||
tmp = stream.read(5);
|
||||
for (; i < samples; i++)
|
||||
decoded[sample++] = stream.read(tmp, true);
|
||||
|
||||
} else {
|
||||
for (; i < samples; i++)
|
||||
decoded[sample++] = this.golomb(tmp, INT_MAX, 0);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const MIN_CACHE_BITS = 25;
|
||||
|
||||
this.prototype.golomb = function(k, limit, esc_len) {
|
||||
var data = this.bitstream,
|
||||
offset = data.bitPosition,
|
||||
buf = data.peek(32 - offset) << offset,
|
||||
v = 0;
|
||||
|
||||
var log = 31 - clz(buf | 1); // log2(buf)
|
||||
|
||||
if (log - k >= 32 - MIN_CACHE_BITS && 32 - log < limit) {
|
||||
buf >>>= log - k;
|
||||
buf += (30 - log) << k;
|
||||
|
||||
data.advance(32 + k - log);
|
||||
v = buf;
|
||||
|
||||
} else {
|
||||
for (var i = 0; data.read(1) === 0; i++)
|
||||
buf = data.peek(32 - offset) << offset;
|
||||
|
||||
if (i < limit - 1) {
|
||||
if (k)
|
||||
buf = data.read(k);
|
||||
else
|
||||
buf = 0;
|
||||
|
||||
v = buf + (i << k);
|
||||
|
||||
} else if (i === limit - 1) {
|
||||
buf = data.read(esc_len);
|
||||
v = buf + 1;
|
||||
|
||||
} else {
|
||||
v = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return (v >> 1) ^ -(v & 1);
|
||||
};
|
||||
|
||||
// Should be in the damned standard library...
|
||||
function clz(input) {
|
||||
var output = 0,
|
||||
curbyte = 0;
|
||||
|
||||
while(true) { // emulate goto in JS using the break statement :D
|
||||
curbyte = input >>> 24;
|
||||
if (curbyte) break;
|
||||
output += 8;
|
||||
|
||||
curbyte = input >>> 16;
|
||||
if (curbyte & 0xff) break;
|
||||
output += 8;
|
||||
|
||||
curbyte = input >>> 8;
|
||||
if (curbyte & 0xff) break;
|
||||
output += 8;
|
||||
|
||||
curbyte = input;
|
||||
if (curbyte & 0xff) break;
|
||||
output += 8;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
if (!(curbyte & 0xf0))
|
||||
output += 4;
|
||||
else
|
||||
curbyte >>>= 4;
|
||||
|
||||
if (curbyte & 0x8)
|
||||
return output;
|
||||
|
||||
if (curbyte & 0x4)
|
||||
return output + 1;
|
||||
|
||||
if (curbyte & 0x2)
|
||||
return output + 2;
|
||||
|
||||
if (curbyte & 0x1)
|
||||
return output + 3;
|
||||
|
||||
// shouldn't get here
|
||||
return output + 4;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = FLACDecoder;
|
||||
|
||||
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||
},{}],3:[function(require,module,exports){
|
||||
(function (global){
|
||||
/*
|
||||
* FLAC.js - Free Lossless Audio Codec decoder in JavaScript
|
||||
* By Devon Govett and Jens Nockert of Official.fm Labs
|
||||
*
|
||||
* FLAC.js is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FLAC.js 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. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
var AV = (typeof window !== "undefined" ? window['AV'] : typeof global !== "undefined" ? global['AV'] : null);
|
||||
|
||||
var FLACDemuxer = AV.Demuxer.extend(function() {
|
||||
AV.Demuxer.register(this);
|
||||
|
||||
this.probe = function(buffer) {
|
||||
return buffer.peekString(0, 4) === 'fLaC';
|
||||
}
|
||||
|
||||
const STREAMINFO = 0,
|
||||
PADDING = 1,
|
||||
APPLICATION = 2,
|
||||
SEEKTABLE = 3,
|
||||
VORBIS_COMMENT = 4,
|
||||
CUESHEET = 5,
|
||||
PICTURE = 6,
|
||||
INVALID = 127,
|
||||
STREAMINFO_SIZE = 34;
|
||||
|
||||
this.prototype.readChunk = function() {
|
||||
var stream = this.stream;
|
||||
|
||||
if (!this.readHeader && stream.available(4)) {
|
||||
if (stream.readString(4) !== 'fLaC')
|
||||
return this.emit('error', 'Invalid FLAC file.');
|
||||
|
||||
this.readHeader = true;
|
||||
}
|
||||
|
||||
while (stream.available(1) && !this.last) {
|
||||
if (!this.readBlockHeaders) {
|
||||
var tmp = stream.readUInt8();
|
||||
this.last = (tmp & 0x80) === 0x80,
|
||||
this.type = tmp & 0x7F,
|
||||
this.size = stream.readUInt24();
|
||||
}
|
||||
|
||||
if (!this.foundStreamInfo && this.type !== STREAMINFO)
|
||||
return this.emit('error', 'STREAMINFO must be the first block');
|
||||
|
||||
if (!stream.available(this.size))
|
||||
return;
|
||||
|
||||
switch (this.type) {
|
||||
case STREAMINFO:
|
||||
if (this.foundStreamInfo)
|
||||
return this.emit('error', 'STREAMINFO can only occur once.');
|
||||
|
||||
if (this.size !== STREAMINFO_SIZE)
|
||||
return this.emit('error', 'STREAMINFO size is wrong.');
|
||||
|
||||
this.foundStreamInfo = true;
|
||||
var bitstream = new AV.Bitstream(stream);
|
||||
|
||||
var cookie = {
|
||||
minBlockSize: bitstream.read(16),
|
||||
maxBlockSize: bitstream.read(16),
|
||||
minFrameSize: bitstream.read(24),
|
||||
maxFrameSize: bitstream.read(24)
|
||||
};
|
||||
|
||||
this.format = {
|
||||
formatID: 'flac',
|
||||
sampleRate: bitstream.read(20),
|
||||
channelsPerFrame: bitstream.read(3) + 1,
|
||||
bitsPerChannel: bitstream.read(5) + 1
|
||||
};
|
||||
|
||||
this.emit('format', this.format);
|
||||
this.emit('cookie', cookie);
|
||||
|
||||
var sampleCount = bitstream.read(36);
|
||||
this.emit('duration', sampleCount / this.format.sampleRate * 1000 | 0);
|
||||
|
||||
stream.advance(16); // skip MD5 hashes
|
||||
this.readBlockHeaders = false;
|
||||
break;
|
||||
|
||||
/*
|
||||
I am only looking at the least significant 32 bits of sample number and offset data
|
||||
This is more than sufficient for the longest flac file I have (~50 mins 2-channel 16-bit 44.1k which uses about 7.5% of the UInt32 space for the largest offset)
|
||||
Can certainly be improved by storing sample numbers and offests as doubles, but would require additional overriding of the searchTimestamp and seek functions (possibly more?)
|
||||
Also the flac faq suggests it would be possible to find frame lengths and thus create seek points on the fly via decoding but I assume this would be slow
|
||||
I may look into these thigns though as my project progresses
|
||||
*/
|
||||
case SEEKTABLE:
|
||||
for(var s=0; s<this.size/18; s++)
|
||||
{
|
||||
if(stream.peekUInt32(0) == 0xFFFFFFFF && stream.peekUInt32(1) == 0xFFFFFFFF)
|
||||
{
|
||||
//placeholder, ignore
|
||||
stream.advance(18);
|
||||
} else {
|
||||
if(stream.readUInt32() > 0)
|
||||
{
|
||||
this.emit('error', 'Seek points with sample number >UInt32 not supported');
|
||||
}
|
||||
var samplenum = stream.readUInt32();
|
||||
if(stream.readUInt32() > 0)
|
||||
{
|
||||
this.emit('error', 'Seek points with stream offset >UInt32 not supported');
|
||||
}
|
||||
var offset = stream.readUInt32();
|
||||
|
||||
stream.advance(2);
|
||||
|
||||
this.addSeekPoint(offset, samplenum);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VORBIS_COMMENT:
|
||||
// see http://www.xiph.org/vorbis/doc/v-comment.html
|
||||
this.metadata || (this.metadata = {});
|
||||
var len = stream.readUInt32(true);
|
||||
|
||||
this.metadata.vendor = stream.readString(len);
|
||||
var length = stream.readUInt32(true);
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
len = stream.readUInt32(true);
|
||||
var str = stream.readString(len, 'utf8'),
|
||||
idx = str.indexOf('=');
|
||||
|
||||
this.metadata[str.slice(0, idx).toLowerCase()] = str.slice(idx + 1);
|
||||
}
|
||||
|
||||
// TODO: standardize field names across formats
|
||||
break;
|
||||
|
||||
case PICTURE:
|
||||
var type = stream.readUInt32();
|
||||
if (type !== 3) { // make sure this is album art (type 3)
|
||||
stream.advance(this.size - 4);
|
||||
} else {
|
||||
var mimeLen = stream.readUInt32(),
|
||||
mime = stream.readString(mimeLen),
|
||||
descLen = stream.readUInt32(),
|
||||
description = stream.readString(descLen),
|
||||
width = stream.readUInt32(),
|
||||
height = stream.readUInt32(),
|
||||
depth = stream.readUInt32(),
|
||||
colors = stream.readUInt32(),
|
||||
length = stream.readUInt32(),
|
||||
picture = stream.readBuffer(length);
|
||||
|
||||
this.metadata || (this.metadata = {});
|
||||
this.metadata.coverArt = picture;
|
||||
}
|
||||
|
||||
// does anyone want the rest of the info?
|
||||
break;
|
||||
|
||||
default:
|
||||
stream.advance(this.size);
|
||||
this.readBlockHeaders = false;
|
||||
}
|
||||
|
||||
if (this.last && this.metadata)
|
||||
this.emit('metadata', this.metadata);
|
||||
}
|
||||
|
||||
while (stream.available(1) && this.last) {
|
||||
var buffer = stream.readSingleBuffer(stream.remainingBytes());
|
||||
this.emit('data', buffer);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = FLACDemuxer;
|
||||
|
||||
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||
},{}],4:[function(require,module,exports){
|
||||
(function (global){
|
||||
var AV = (typeof window !== "undefined" ? window['AV'] : typeof global !== "undefined" ? global['AV'] : null);
|
||||
|
||||
// if ogg.js exists, register a plugin
|
||||
try {
|
||||
var OggDemuxer = (typeof window !== "undefined" ? window['AV']['OggDemuxer'] : typeof global !== "undefined" ? global['AV']['OggDemuxer'] : null);
|
||||
} catch (e) {};
|
||||
if (!OggDemuxer) return;
|
||||
|
||||
OggDemuxer.plugins.push({
|
||||
magic: "\177FLAC",
|
||||
|
||||
init: function() {
|
||||
this.list = new AV.BufferList();
|
||||
this.stream = new AV.Stream(this.list);
|
||||
},
|
||||
|
||||
readHeaders: function(packet) {
|
||||
var stream = this.stream;
|
||||
this.list.append(new AV.Buffer(packet));
|
||||
|
||||
stream.advance(5); // magic
|
||||
if (stream.readUInt8() != 1)
|
||||
throw new Error('Unsupported FLAC version');
|
||||
|
||||
stream.advance(3);
|
||||
if (stream.peekString(0, 4) != 'fLaC')
|
||||
throw new Error('Not flac');
|
||||
|
||||
this.flac = AV.Demuxer.find(stream.peekSingleBuffer(0, stream.remainingBytes()));
|
||||
if (!this.flac)
|
||||
throw new Error('Flac demuxer not found');
|
||||
|
||||
this.flac.prototype.readChunk.call(this);
|
||||
return true;
|
||||
},
|
||||
|
||||
readPacket: function(packet) {
|
||||
this.list.append(new AV.Buffer(packet));
|
||||
this.flac.prototype.readChunk.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||
},{}]},{},[1])
|
||||
|
||||
|
||||
//# sourceMappingURL=flac.js.map
|
||||
7751
gns3server/static/web-ui/assets/xpra-html5/js/lib/aurora/mp3.js
Normal file
7751
gns3server/static/web-ui/assets/xpra-html5/js/lib/aurora/mp3.js
Normal file
File diff suppressed because it is too large
Load Diff
1711
gns3server/static/web-ui/assets/xpra-html5/js/lib/brotli_decode.js
Normal file
1711
gns3server/static/web-ui/assets/xpra-html5/js/lib/brotli_decode.js
Normal file
File diff suppressed because one or more lines are too long
299
gns3server/static/web-ui/assets/xpra-html5/js/lib/detect-zoom.js
Normal file
299
gns3server/static/web-ui/assets/xpra-html5/js/lib/detect-zoom.js
Normal file
@ -0,0 +1,299 @@
|
||||
/* Detect-zoom
|
||||
* -----------
|
||||
* Cross Browser Zoom and Pixel Ratio Detector
|
||||
* Version 1.0.4 | Apr 1 2013
|
||||
* dual-licensed under the WTFPL and MIT license
|
||||
* Maintained by https://github/tombigel
|
||||
* Original developer https://github.com/yonran
|
||||
*/
|
||||
|
||||
//AMD and CommonJS initialization copied from https://github.com/zohararad/audio5js
|
||||
(function (root, ns, factory) {
|
||||
"use strict";
|
||||
|
||||
if (typeof (module) !== 'undefined' && module.exports) { // CommonJS
|
||||
module.exports = factory(ns, root);
|
||||
} else if (typeof (define) === 'function' && define.amd) { // AMD
|
||||
define("detect-zoom", function () {
|
||||
return factory(ns, root);
|
||||
});
|
||||
} else {
|
||||
root[ns] = factory(ns, root);
|
||||
}
|
||||
|
||||
}(window, 'detectZoom', function () {
|
||||
|
||||
/**
|
||||
* Use devicePixelRatio if supported by the browser
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
var devicePixelRatio = function () {
|
||||
return window.devicePixelRatio || 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fallback function to set default values
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var fallback = function () {
|
||||
return {
|
||||
zoom: 1,
|
||||
devicePxPerCssPx: 1
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* For chrome
|
||||
*
|
||||
*/
|
||||
var chrome = function()
|
||||
{
|
||||
var zoom = Math.round(((window.outerWidth) / window.innerWidth)*100) / 100;
|
||||
return {
|
||||
zoom: zoom,
|
||||
devicePxPerCssPx: zoom * devicePixelRatio()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* For safari (same as chrome)
|
||||
*
|
||||
*/
|
||||
var safari= function()
|
||||
{
|
||||
var zoom = Math.round(((document.documentElement.clientWidth) / window.innerWidth)*100) / 100;
|
||||
return {
|
||||
zoom: zoom,
|
||||
devicePxPerCssPx: zoom * devicePixelRatio()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mobile WebKit
|
||||
* the trick: window.innerWIdth is in CSS pixels, while
|
||||
* screen.width and screen.height are in system pixels.
|
||||
* And there are no scrollbars to mess up the measurement.
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var webkitMobile = function () {
|
||||
var deviceWidth = (Math.abs(window.orientation) == 90) ? screen.height : screen.width;
|
||||
var zoom = deviceWidth / window.innerWidth;
|
||||
return {
|
||||
zoom: zoom,
|
||||
devicePxPerCssPx: zoom * devicePixelRatio()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Desktop Webkit
|
||||
* the trick: an element's clientHeight is in CSS pixels, while you can
|
||||
* set its line-height in system pixels using font-size and
|
||||
* -webkit-text-size-adjust:none.
|
||||
* device-pixel-ratio: http://www.webkit.org/blog/55/high-dpi-web-sites/
|
||||
*
|
||||
* Previous trick (used before http://trac.webkit.org/changeset/100847):
|
||||
* documentElement.scrollWidth is in CSS pixels, while
|
||||
* document.width was in system pixels. Note that this is the
|
||||
* layout width of the document, which is slightly different from viewport
|
||||
* because document width does not include scrollbars and might be wider
|
||||
* due to big elements.
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var webkit = function () {
|
||||
var important = function (str) {
|
||||
return str.replace(/;/g, " !important;");
|
||||
};
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = "1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>0";
|
||||
div.setAttribute('style', important('font: 100px/1em sans-serif; -webkit-text-size-adjust: none; text-size-adjust: none; height: auto; width: 1em; padding: 0; overflow: visible;'));
|
||||
|
||||
// The container exists so that the div will be laid out in its own flow
|
||||
// while not impacting the layout, viewport size, or display of the
|
||||
// webpage as a whole.
|
||||
// Add !important and relevant CSS rule resets
|
||||
// so that other rules cannot affect the results.
|
||||
var container = document.createElement('div');
|
||||
container.setAttribute('style', important('width:0; height:0; overflow:hidden; visibility:hidden; position: absolute;'));
|
||||
container.appendChild(div);
|
||||
|
||||
document.body.appendChild(container);
|
||||
var zoom = 1000 / div.clientHeight;
|
||||
zoom = Math.round(zoom * 100) / 100;
|
||||
document.body.removeChild(container);
|
||||
|
||||
return{
|
||||
zoom: zoom,
|
||||
devicePxPerCssPx: zoom * devicePixelRatio()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* no real trick; device-pixel-ratio is the ratio of device dpi / css dpi.
|
||||
* (Note that this is a different interpretation than Webkit's device
|
||||
* pixel ratio, which is the ratio device dpi / system dpi).
|
||||
*
|
||||
* Also, for Mozilla, there is no difference between the zoom factor and the device ratio.
|
||||
*
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var firefox4 = function () {
|
||||
var zoom = mediaQueryBinarySearch('min--moz-device-pixel-ratio', '', 0, 10, 20, 0.0001);
|
||||
zoom = Math.round(zoom * 100) / 100;
|
||||
return {
|
||||
zoom: zoom,
|
||||
devicePxPerCssPx: zoom
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Firefox 18.x
|
||||
* Mozilla added support for devicePixelRatio to Firefox 18,
|
||||
* but it is affected by the zoom level, so, like in older
|
||||
* Firefox we can't tell if we are in zoom mode or in a device
|
||||
* with a different pixel ratio
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var firefox18 = function () {
|
||||
return {
|
||||
zoom: firefox4().zoom,
|
||||
devicePxPerCssPx: devicePixelRatio()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* works starting Opera 11.11
|
||||
* the trick: outerWidth is the viewport width including scrollbars in
|
||||
* system px, while innerWidth is the viewport width including scrollbars
|
||||
* in CSS px
|
||||
* @return {Object}
|
||||
* @private
|
||||
*/
|
||||
var opera11 = function () {
|
||||
var zoom = window.top.outerWidth / window.top.innerWidth;
|
||||
zoom = Math.round(zoom * 100) / 100;
|
||||
return {
|
||||
zoom: zoom,
|
||||
devicePxPerCssPx: zoom * devicePixelRatio()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Use a binary search through media queries to find zoom level in Firefox
|
||||
* @param property
|
||||
* @param unit
|
||||
* @param a
|
||||
* @param b
|
||||
* @param maxIter
|
||||
* @param epsilon
|
||||
* @return {Number}
|
||||
*/
|
||||
var mediaQueryBinarySearch = function (property, unit, a, b, maxIter, epsilon) {
|
||||
var matchMedia;
|
||||
var head, style, div;
|
||||
if (window.matchMedia) {
|
||||
matchMedia = window.matchMedia;
|
||||
} else {
|
||||
head = document.getElementsByTagName('head')[0];
|
||||
style = document.createElement('style');
|
||||
head.appendChild(style);
|
||||
|
||||
div = document.createElement('div');
|
||||
div.className = 'mediaQueryBinarySearch';
|
||||
div.style.display = 'none';
|
||||
document.body.appendChild(div);
|
||||
|
||||
matchMedia = function (query) {
|
||||
style.sheet.insertRule('@media ' + query + '{.mediaQueryBinarySearch ' + '{text-decoration: underline} }', 0);
|
||||
var matched = getComputedStyle(div, null).textDecoration == 'underline';
|
||||
style.sheet.deleteRule(0);
|
||||
return {matches: matched};
|
||||
};
|
||||
}
|
||||
var ratio = binarySearch(a, b, maxIter);
|
||||
if (div) {
|
||||
head.removeChild(style);
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
return ratio;
|
||||
|
||||
function binarySearch(a, b, maxIter) {
|
||||
var mid = (a + b) / 2;
|
||||
if (maxIter <= 0 || b - a < epsilon) {
|
||||
return mid;
|
||||
}
|
||||
var query = "(" + property + ":" + mid + unit + ")";
|
||||
if (matchMedia(query).matches) {
|
||||
return binarySearch(mid, b, maxIter - 1);
|
||||
} else {
|
||||
return binarySearch(a, mid, maxIter - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate detection function
|
||||
* @private
|
||||
*/
|
||||
var detectFunction = (function () {
|
||||
var func = fallback;
|
||||
//chrome
|
||||
if(!!window.chrome && !(!!window.opera || navigator.userAgent.indexOf(' Opera') >= 0)){
|
||||
func = chrome;
|
||||
}
|
||||
//safari
|
||||
else if(Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0){
|
||||
func = safari;
|
||||
}
|
||||
//Mobile Webkit
|
||||
else if ('orientation' in window && 'webkitRequestAnimationFrame' in window) {
|
||||
func = webkitMobile;
|
||||
}
|
||||
//WebKit
|
||||
else if ('webkitRequestAnimationFrame' in window) {
|
||||
func = webkit;
|
||||
}
|
||||
//Opera
|
||||
else if (navigator.userAgent.indexOf('Opera') >= 0) {
|
||||
func = opera11;
|
||||
}
|
||||
//Last one is Firefox
|
||||
//FF 18.x
|
||||
else if (window.devicePixelRatio) {
|
||||
func = firefox18;
|
||||
}
|
||||
//FF 4.0 - 17.x
|
||||
else if (firefox4().zoom > 0.001) {
|
||||
func = firefox4;
|
||||
}
|
||||
|
||||
return func;
|
||||
}());
|
||||
|
||||
|
||||
return ({
|
||||
|
||||
/**
|
||||
* Ratios.zoom shorthand
|
||||
* @return {Number} Zoom level
|
||||
*/
|
||||
zoom: function () {
|
||||
return detectFunction().zoom;
|
||||
},
|
||||
|
||||
/**
|
||||
* Ratios.devicePxPerCssPx shorthand
|
||||
* @return {Number} devicePxPerCssPx level
|
||||
*/
|
||||
device: function () {
|
||||
return detectFunction().devicePxPerCssPx;
|
||||
}
|
||||
});
|
||||
}));
|
||||
270
gns3server/static/web-ui/assets/xpra-html5/js/lib/hmac.js
Normal file
270
gns3server/static/web-ui/assets/xpra-html5/js/lib/hmac.js
Normal file
@ -0,0 +1,270 @@
|
||||
// https://gist.github.com/stevendesu/2d52f7b5e1f1184af3b667c0b5e054b8?permalink_comment_id=4535312
|
||||
// A simple, open-source, HMAC-SHA256 implementation in pure JavaScript. Designed for efficient minification.
|
||||
// Feel free to choose whatever license you find most permissible, but I offer no warranty for the code.
|
||||
// It's 100% free to do with as you please.
|
||||
|
||||
// To ensure cross-browser support even without a proper SubtleCrypto
|
||||
// impelmentation (or without access to the impelmentation, as is the case with
|
||||
// Chrome loaded over HTTP instead of HTTPS), this library can create SHA-256
|
||||
// HMAC signatures using nothing but raw JavaScript
|
||||
|
||||
/* eslint-disable no-magic-numbers, id-length, no-param-reassign, new-cap */
|
||||
|
||||
// By giving internal functions names that we can mangle, future calls to
|
||||
// them are reduced to a single byte (minor space savings in minified file)
|
||||
var uint8Array = Uint8Array;
|
||||
var uint32Array = Uint32Array;
|
||||
var pow = Math.pow;
|
||||
|
||||
// Will be initialized below
|
||||
// Using a Uint32Array instead of a simple array makes the minified code
|
||||
// a bit bigger (we lose our `unshift()` hack), but comes with huge
|
||||
// performance gains
|
||||
var DEFAULT_STATE = new uint32Array(8);
|
||||
var ROUND_CONSTANTS = [];
|
||||
|
||||
// Reusable object for expanded message
|
||||
// Using a Uint32Array instead of a simple array makes the minified code
|
||||
// 7 bytes larger, but comes with huge performance gains
|
||||
var M = new uint32Array(64);
|
||||
|
||||
// After minification the code to compute the default state and round
|
||||
// constants is smaller than the output. More importantly, this serves as a
|
||||
// good educational aide for anyone wondering where the magic numbers come
|
||||
// from. No magic numbers FTW!
|
||||
function getFractionalBits(n)
|
||||
{
|
||||
return ((n - (n | 0)) * pow(2, 32)) | 0;
|
||||
}
|
||||
|
||||
var n = 2, nPrime = 0;
|
||||
while (nPrime < 64)
|
||||
{
|
||||
// isPrime() was in-lined from its original function form to save
|
||||
// a few bytes
|
||||
var isPrime = true;
|
||||
// Math.sqrt() was replaced with pow(n, 1/2) to save a few bytes
|
||||
// var sqrtN = pow(n, 1 / 2);
|
||||
// So technically to determine if a number is prime you only need to
|
||||
// check numbers up to the square root. However this function only runs
|
||||
// once and we're only computing the first 64 primes (up to 311), so on
|
||||
// any modern CPU this whole function runs in a couple milliseconds.
|
||||
// By going to n / 2 instead of sqrt(n) we net 8 byte savings and no
|
||||
// scaling performance cost
|
||||
for (var factor = 2; factor <= n / 2; factor++)
|
||||
{
|
||||
if (n % factor === 0)
|
||||
{
|
||||
isPrime = false;
|
||||
}
|
||||
}
|
||||
if (isPrime)
|
||||
{
|
||||
if (nPrime < 8)
|
||||
{
|
||||
DEFAULT_STATE[nPrime] = getFractionalBits(pow(n, 1 / 2));
|
||||
}
|
||||
ROUND_CONSTANTS[nPrime] = getFractionalBits(pow(n, 1 / 3));
|
||||
|
||||
nPrime++;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
// For cross-platform support we need to ensure that all 32-bit words are
|
||||
// in the same endianness. A UTF-8 TextEncoder will return BigEndian data,
|
||||
// so upon reading or writing to our ArrayBuffer we'll only swap the bytes
|
||||
// if our system is LittleEndian (which is about 99% of CPUs)
|
||||
var LittleEndian = !!new uint8Array(new uint32Array([1]).buffer)[0];
|
||||
|
||||
function convertEndian(word)
|
||||
{
|
||||
if (LittleEndian)
|
||||
{
|
||||
return (
|
||||
// byte 1 -> byte 4
|
||||
(word >>> 24) |
|
||||
// byte 2 -> byte 3
|
||||
(((word >>> 16) & 0xff) << 8) |
|
||||
// byte 3 -> byte 2
|
||||
((word & 0xff00) << 8) |
|
||||
// byte 4 -> byte 1
|
||||
(word << 24)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return word;
|
||||
}
|
||||
}
|
||||
|
||||
function rightRotate(word, bits)
|
||||
{
|
||||
return (word >>> bits) | (word << (32 - bits));
|
||||
}
|
||||
|
||||
function sha256(data)
|
||||
{
|
||||
// Copy default state
|
||||
var STATE = DEFAULT_STATE.slice();
|
||||
|
||||
// Caching this reduces occurrences of ".length" in minified JavaScript
|
||||
// 3 more byte savings! :D
|
||||
var legth = data.length;
|
||||
|
||||
// Pad data
|
||||
var bitLength = legth * 8;
|
||||
var newBitLength = (512 - ((bitLength + 64) % 512) - 1) + bitLength + 65;
|
||||
|
||||
// "bytes" and "words" are stored BigEndian
|
||||
var bytes = new uint8Array(newBitLength / 8);
|
||||
var words = new uint32Array(bytes.buffer);
|
||||
|
||||
bytes.set(data, 0);
|
||||
// Append a 1
|
||||
bytes[legth] = 0b10000000;
|
||||
// Store length in BigEndian
|
||||
words[words.length - 1] = convertEndian(bitLength);
|
||||
|
||||
// Loop iterator (avoid two instances of "var") -- saves 2 bytes
|
||||
var round;
|
||||
|
||||
// Process blocks (512 bits / 64 bytes / 16 words at a time)
|
||||
for (var block = 0; block < newBitLength / 32; block += 16)
|
||||
{
|
||||
var workingState = STATE.slice();
|
||||
|
||||
// Rounds
|
||||
for (round = 0; round < 64; round++)
|
||||
{
|
||||
var MRound;
|
||||
// Expand message
|
||||
if (round < 16)
|
||||
{
|
||||
// Convert to platform Endianness for later math
|
||||
MRound = convertEndian(words[block + round]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var gamma0x = M[round - 15];
|
||||
var gamma1x = M[round - 2];
|
||||
MRound =
|
||||
M[round - 7] + M[round - 16] + (
|
||||
rightRotate(gamma0x, 7) ^
|
||||
rightRotate(gamma0x, 18) ^
|
||||
(gamma0x >>> 3)
|
||||
) + (
|
||||
rightRotate(gamma1x, 17) ^
|
||||
rightRotate(gamma1x, 19) ^
|
||||
(gamma1x >>> 10)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
// M array matches platform endianness
|
||||
M[round] = MRound |= 0;
|
||||
|
||||
// Computation
|
||||
var t1 =
|
||||
(
|
||||
rightRotate(workingState[4], 6) ^
|
||||
rightRotate(workingState[4], 11) ^
|
||||
rightRotate(workingState[4], 25)
|
||||
) +
|
||||
(
|
||||
(workingState[4] & workingState[5]) ^
|
||||
(~workingState[4] & workingState[6])
|
||||
) + workingState[7] + MRound + ROUND_CONSTANTS[round]
|
||||
;
|
||||
var t2 =
|
||||
(
|
||||
rightRotate(workingState[0], 2) ^
|
||||
rightRotate(workingState[0], 13) ^
|
||||
rightRotate(workingState[0], 22)
|
||||
) +
|
||||
(
|
||||
(workingState[0] & workingState[1]) ^
|
||||
(workingState[2] & (workingState[0] ^
|
||||
workingState[1]))
|
||||
)
|
||||
;
|
||||
|
||||
for (var i = 7; i > 0; i--)
|
||||
{
|
||||
workingState[i] = workingState[i - 1];
|
||||
}
|
||||
workingState[0] = (t1 + t2) | 0;
|
||||
workingState[4] = (workingState[4] + t1) | 0;
|
||||
}
|
||||
|
||||
// Update state
|
||||
for (round = 0; round < 8; round++)
|
||||
{
|
||||
STATE[round] = (STATE[round] + workingState[round]) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally the state needs to be converted to BigEndian for output
|
||||
// And we want to return a Uint8Array, not a Uint32Array
|
||||
return new uint8Array(new uint32Array(
|
||||
STATE.map(function(val) { return convertEndian(val); })
|
||||
).buffer);
|
||||
}
|
||||
|
||||
function hmac(key, data)
|
||||
{
|
||||
if (key.length > 64)
|
||||
key = sha256(key);
|
||||
|
||||
if (key.length < 64)
|
||||
{
|
||||
const tmp = new Uint8Array(64);
|
||||
tmp.set(key, 0);
|
||||
key = tmp;
|
||||
}
|
||||
|
||||
// Generate inner and outer keys
|
||||
var innerKey = new Uint8Array(64);
|
||||
var outerKey = new Uint8Array(64);
|
||||
for (var i = 0; i < 64; i++)
|
||||
{
|
||||
innerKey[i] = 0x36 ^ key[i];
|
||||
outerKey[i] = 0x5c ^ key[i];
|
||||
}
|
||||
|
||||
// Append the innerKey
|
||||
var msg = new Uint8Array(data.length + 64);
|
||||
msg.set(innerKey, 0);
|
||||
msg.set(data, 64);
|
||||
|
||||
// Has the previous message and append the outerKey
|
||||
var result = new Uint8Array(64 + 32);
|
||||
result.set(outerKey, 0);
|
||||
result.set(sha256(msg), 64);
|
||||
|
||||
// Hash the previous message
|
||||
return sha256(result);
|
||||
}
|
||||
|
||||
// Convert a string to a Uint8Array, SHA-256 it, and convert back to string
|
||||
const encoder = new TextEncoder("utf-8");
|
||||
|
||||
function sign(inputKey, inputData)
|
||||
{
|
||||
const key = typeof inputKey === "string" ? encoder.encode(inputKey) : inputKey;
|
||||
const data = typeof inputData === "string" ? encoder.encode(inputData) : inputData;
|
||||
return hmac(key, data);
|
||||
}
|
||||
|
||||
function hash(str)
|
||||
{
|
||||
return hex(sha256(encoder.encode(str)));
|
||||
}
|
||||
|
||||
function hex(bin)
|
||||
{
|
||||
return bin.reduce((acc, val) =>
|
||||
acc + ("00" + val.toString(16)).substr(-2)
|
||||
, "");
|
||||
}
|
||||
229
gns3server/static/web-ui/assets/xpra-html5/js/lib/jquery-transform-draggable.js
vendored
Normal file
229
gns3server/static/web-ui/assets/xpra-html5/js/lib/jquery-transform-draggable.js
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* xpra client
|
||||
* Licensed under MPL 2.0
|
||||
*
|
||||
* Copyright: 2021, Vasyl Gello
|
||||
*
|
||||
* Based on https://stackoverflow.com/a/24263015
|
||||
* Copyright: 2014, gal
|
||||
* License: CC-BY-SA 3.0
|
||||
*/
|
||||
|
||||
/* General matrix transformations */
|
||||
|
||||
var Matrix = function(a, b, c, d, e, f, g, h, i) {
|
||||
if ($.type(a) === 'array') {
|
||||
this.elements = [
|
||||
+a[0], +a[2], +a[4],
|
||||
+a[1], +a[3], +a[5],
|
||||
0, 0, 1
|
||||
];
|
||||
} else {
|
||||
this.elements = [
|
||||
a, b, c,
|
||||
d, e, f,
|
||||
g || 0, h || 0, i || 1
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
Matrix.prototype = {
|
||||
/**
|
||||
* Multiply a 3x3 matrix by a similar matrix or a vector
|
||||
* @param {Matrix|Vector} matrix
|
||||
* @return {Matrix|Vector} Returns a vector if multiplying by a vector
|
||||
*/
|
||||
x: function(matrix) {
|
||||
var isVector = matrix instanceof Vector;
|
||||
|
||||
var a = this.elements,
|
||||
b = matrix.elements;
|
||||
|
||||
if (isVector && b.length === 3) {
|
||||
// b is actually a vector
|
||||
return new Vector(
|
||||
a[0] * b[0] + a[1] * b[1] + a[2] * b[2],
|
||||
a[3] * b[0] + a[4] * b[1] + a[5] * b[2],
|
||||
a[6] * b[0] + a[7] * b[1] + a[8] * b[2]
|
||||
);
|
||||
} else if (b.length === a.length) {
|
||||
// b is a 3x3 matrix
|
||||
return new Matrix(
|
||||
a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
|
||||
a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
|
||||
a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
|
||||
|
||||
a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
|
||||
a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
|
||||
a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
|
||||
|
||||
a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
|
||||
a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
|
||||
a[6] * b[2] + a[7] * b[5] + a[8] * b[8]
|
||||
);
|
||||
}
|
||||
return false; // fail
|
||||
},
|
||||
/**
|
||||
* Generates an inverse of the current matrix
|
||||
* @returns {Matrix}
|
||||
*/
|
||||
inverse: function() {
|
||||
var d = 1 / this.determinant(),
|
||||
a = this.elements;
|
||||
return new Matrix(
|
||||
d * (a[8] * a[4] - a[7] * a[5]),
|
||||
d * (-(a[8] * a[1] - a[7] * a[2])),
|
||||
d * (a[5] * a[1] - a[4] * a[2]),
|
||||
|
||||
d * (-(a[8] * a[3] - a[6] * a[5])),
|
||||
d * (a[8] * a[0] - a[6] * a[2]),
|
||||
d * (-(a[5] * a[0] - a[3] * a[2])),
|
||||
|
||||
d * (a[7] * a[3] - a[6] * a[4]),
|
||||
d * (-(a[7] * a[0] - a[6] * a[1])),
|
||||
d * (a[4] * a[0] - a[3] * a[1])
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Calculates the determinant of the current matrix
|
||||
* @returns {Number}
|
||||
*/
|
||||
determinant: function() {
|
||||
var a = this.elements;
|
||||
return a[0] * (a[8] * a[4] - a[7] * a[5]) - a[3] * (a[8] * a[1] - a[7] * a[2]) + a[6] * (a[5] * a[1] - a[4] * a[2]);
|
||||
}
|
||||
};
|
||||
|
||||
var Vector = function(x, y, z) {
|
||||
this.elements = [x, y, z];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the element at zero-indexed index i
|
||||
* @param {Number} i
|
||||
*/
|
||||
Vector.prototype.e = Matrix.prototype.e = function(i) {
|
||||
|
||||
if (this.elements[i] != undefined) {
|
||||
return this.elements[i];
|
||||
}
|
||||
|
||||
return this.elements;
|
||||
};
|
||||
|
||||
/* Draggable transformation plugin */
|
||||
|
||||
$.ui.plugin.add("draggable", "transform", {
|
||||
start: function(event, ui) {
|
||||
|
||||
if (!$(this).data('ui-draggable')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var inst = $(this).data("ui-draggable");
|
||||
|
||||
inst.matrix = new Matrix(function(matrix) {
|
||||
|
||||
var rmatrix = new RegExp(
|
||||
'^matrix\\(' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\)$'
|
||||
);
|
||||
|
||||
var matrix = rmatrix.exec(matrix);
|
||||
if (matrix) {
|
||||
matrix.shift();
|
||||
}
|
||||
return matrix || [1, 0, 0, 1, 0, 0];
|
||||
|
||||
}([$(this).parents('[style*="transform"]').css('transform')]));
|
||||
},
|
||||
drag: function(event, ui) {
|
||||
|
||||
if (!$(this).data('ui-draggable')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var inst = $(this).data("ui-draggable");
|
||||
|
||||
var t_pos = inst.matrix.inverse().x(new Vector(ui.position.left, ui.position.top, 0));
|
||||
|
||||
ui.position.left = t_pos.e(0);
|
||||
ui.position.top = t_pos.e(1);
|
||||
|
||||
if (inst.options.grid) {
|
||||
ui.position.left = ui.position.left - ui.position.left % inst.options.grid[0];
|
||||
ui.position.top = ui.position.top - ui.position.top % inst.options.grid[1];
|
||||
}
|
||||
|
||||
if (inst.containment) {
|
||||
if (ui.position.left < inst.containment[0]) {
|
||||
ui.position.left = inst.containment[0];
|
||||
}
|
||||
|
||||
if (ui.position.left > inst.containment[2]) {
|
||||
ui.position.left = inst.containment[2];
|
||||
}
|
||||
|
||||
if (ui.position.top < inst.containment[1]) {
|
||||
ui.position.top = inst.containment[1];
|
||||
}
|
||||
|
||||
if (ui.position.top > inst.containment[3]) {
|
||||
ui.position.top = inst.containment[3];
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/* Resizable transformation plugin */
|
||||
|
||||
$.ui.plugin.add("resizable", "transform", {
|
||||
start: function(event, ui) {
|
||||
|
||||
if (!$(this).data('ui-resizable')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var inst = $(this).data("ui-resizable");
|
||||
|
||||
inst.matrix = new Matrix(function(matrix) {
|
||||
|
||||
var rmatrix = new RegExp(
|
||||
'^matrix\\(' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
|
||||
'(\\-?[\\d\\.e]+)' + '\\)$'
|
||||
);
|
||||
|
||||
var matrix = rmatrix.exec(matrix);
|
||||
if (matrix) {
|
||||
matrix.shift();
|
||||
}
|
||||
return matrix || [1, 0, 0, 1, 0, 0];
|
||||
|
||||
}([$(this).parents('[style*="transform"]').css('transform')]));
|
||||
},
|
||||
resize: function(event, ui) {
|
||||
|
||||
if (!$(this).data('ui-resizable')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var inst = $(this).data("ui-resizable");
|
||||
|
||||
if (inst.helper && inst.helper.length > 0) {
|
||||
var t_pos = inst.matrix.inverse().x(new Vector(ui.size.width, ui.size.height, 0));
|
||||
inst.helper[0].width = t_pos.e(0);
|
||||
inst.helper[0].height = t_pos.e(1);
|
||||
}
|
||||
},
|
||||
});
|
||||
18835
gns3server/static/web-ui/assets/xpra-html5/js/lib/jquery-ui.js
vendored
Normal file
18835
gns3server/static/web-ui/assets/xpra-html5/js/lib/jquery-ui.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,252 @@
|
||||
/*!
|
||||
* jQuery throttle / debounce - v1.1 - 3/7/2010
|
||||
* http://benalman.com/projects/jquery-throttle-debounce-plugin/
|
||||
*
|
||||
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
|
||||
// Script: jQuery throttle / debounce: Sometimes, less is more!
|
||||
//
|
||||
// *Version: 1.1, Last updated: 3/7/2010*
|
||||
//
|
||||
// Project Home - http://benalman.com/projects/jquery-throttle-debounce-plugin/
|
||||
// GitHub - http://github.com/cowboy/jquery-throttle-debounce/
|
||||
// Source - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js
|
||||
// (Minified) - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb)
|
||||
//
|
||||
// About: License
|
||||
//
|
||||
// Copyright (c) 2010 "Cowboy" Ben Alman,
|
||||
// Dual licensed under the MIT and GPL licenses.
|
||||
// http://benalman.com/about/license/
|
||||
//
|
||||
// About: Examples
|
||||
//
|
||||
// These working examples, complete with fully commented code, illustrate a few
|
||||
// ways in which this plugin can be used.
|
||||
//
|
||||
// Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/
|
||||
// Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/
|
||||
//
|
||||
// About: Support and Testing
|
||||
//
|
||||
// Information about what version or versions of jQuery this plugin has been
|
||||
// tested with, what browsers it has been tested in, and where the unit tests
|
||||
// reside (so you can test it yourself).
|
||||
//
|
||||
// jQuery Versions - none, 1.3.2, 1.4.2
|
||||
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1.
|
||||
// Unit Tests - http://benalman.com/code/projects/jquery-throttle-debounce/unit/
|
||||
//
|
||||
// About: Release History
|
||||
//
|
||||
// 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks
|
||||
// executed later than they should. Reworked a fair amount of internal
|
||||
// logic as well.
|
||||
// 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over
|
||||
// from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the
|
||||
// no_trailing throttle parameter and debounce functionality.
|
||||
//
|
||||
// Topic: Note for non-jQuery users
|
||||
//
|
||||
// jQuery isn't actually required for this plugin, because nothing internal
|
||||
// uses any jQuery methods or properties. jQuery is just used as a namespace
|
||||
// under which these methods can exist.
|
||||
//
|
||||
// Since jQuery isn't actually required for this plugin, if jQuery doesn't exist
|
||||
// when this plugin is loaded, the method described below will be created in
|
||||
// the `Cowboy` namespace. Usage will be exactly the same, but instead of
|
||||
// $.method() or jQuery.method(), you'll need to use Cowboy.method().
|
||||
|
||||
(function(window,undefined){
|
||||
'$:nomunge'; // Used by YUI compressor.
|
||||
|
||||
// Since jQuery really isn't required for this plugin, use `jQuery` as the
|
||||
// namespace only if it already exists, otherwise use the `Cowboy` namespace,
|
||||
// creating it if necessary.
|
||||
var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ),
|
||||
|
||||
// Internal method reference.
|
||||
jq_throttle;
|
||||
|
||||
// Method: jQuery.throttle
|
||||
//
|
||||
// Throttle execution of a function. Especially useful for rate limiting
|
||||
// execution of handlers on events like resize and scroll. If you want to
|
||||
// rate-limit execution of a function to a single time, see the
|
||||
// <jQuery.debounce> method.
|
||||
//
|
||||
// In this visualization, | is a throttled-function call and X is the actual
|
||||
// callback execution:
|
||||
//
|
||||
// > Throttled with `no_trailing` specified as false or unspecified:
|
||||
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
|
||||
// > X X X X X X X X X X X X
|
||||
// >
|
||||
// > Throttled with `no_trailing` specified as true:
|
||||
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
|
||||
// > X X X X X X X X X X
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback );
|
||||
// >
|
||||
// > jQuery('selector').bind( 'someevent', throttled );
|
||||
// > jQuery('selector').unbind( 'someevent', throttled );
|
||||
//
|
||||
// This also works in jQuery 1.4+:
|
||||
//
|
||||
// > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) );
|
||||
// > jQuery('selector').unbind( 'someevent', callback );
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// delay - (Number) A zero-or-greater delay in milliseconds. For event
|
||||
// callbacks, values around 100 or 250 (or even higher) are most useful.
|
||||
// no_trailing - (Boolean) Optional, defaults to false. If no_trailing is
|
||||
// true, callback will only execute every `delay` milliseconds while the
|
||||
// throttled-function is being called. If no_trailing is false or
|
||||
// unspecified, callback will be executed one final time after the last
|
||||
// throttled-function call. (After the throttled-function has not been
|
||||
// called for `delay` milliseconds, the internal counter is reset)
|
||||
// callback - (Function) A function to be executed after delay milliseconds.
|
||||
// The `this` context and all arguments are passed through, as-is, to
|
||||
// `callback` when the throttled-function is executed.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// (Function) A new, throttled, function.
|
||||
|
||||
$.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) {
|
||||
// After wrapper has stopped being called, this timeout ensures that
|
||||
// `callback` is executed at the proper times in `throttle` and `end`
|
||||
// debounce modes.
|
||||
var timeout_id,
|
||||
|
||||
// Keep track of the last time `callback` was executed.
|
||||
last_exec = 0;
|
||||
|
||||
// `no_trailing` defaults to falsy.
|
||||
if ( typeof no_trailing !== 'boolean' ) {
|
||||
debounce_mode = callback;
|
||||
callback = no_trailing;
|
||||
no_trailing = undefined;
|
||||
}
|
||||
|
||||
// The `wrapper` function encapsulates all of the throttling / debouncing
|
||||
// functionality and when executed will limit the rate at which `callback`
|
||||
// is executed.
|
||||
function wrapper() {
|
||||
var that = this,
|
||||
elapsed = +new Date() - last_exec,
|
||||
args = arguments;
|
||||
|
||||
// Execute `callback` and update the `last_exec` timestamp.
|
||||
function exec() {
|
||||
last_exec = +new Date();
|
||||
callback.apply( that, args );
|
||||
};
|
||||
|
||||
// If `debounce_mode` is true (at_begin) this is used to clear the flag
|
||||
// to allow future `callback` executions.
|
||||
function clear() {
|
||||
timeout_id = undefined;
|
||||
};
|
||||
|
||||
if ( debounce_mode && !timeout_id ) {
|
||||
// Since `wrapper` is being called for the first time and
|
||||
// `debounce_mode` is true (at_begin), execute `callback`.
|
||||
exec();
|
||||
}
|
||||
|
||||
// Clear any existing timeout.
|
||||
timeout_id && clearTimeout( timeout_id );
|
||||
|
||||
if ( debounce_mode === undefined && elapsed > delay ) {
|
||||
// In throttle mode, if `delay` time has been exceeded, execute
|
||||
// `callback`.
|
||||
exec();
|
||||
|
||||
} else if ( no_trailing !== true ) {
|
||||
// In trailing throttle mode, since `delay` time has not been
|
||||
// exceeded, schedule `callback` to execute `delay` ms after most
|
||||
// recent execution.
|
||||
//
|
||||
// If `debounce_mode` is true (at_begin), schedule `clear` to execute
|
||||
// after `delay` ms.
|
||||
//
|
||||
// If `debounce_mode` is false (at end), schedule `callback` to
|
||||
// execute after `delay` ms.
|
||||
timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
|
||||
}
|
||||
};
|
||||
|
||||
// Set the guid of `wrapper` function to the same of original callback, so
|
||||
// it can be removed in jQuery 1.4+ .unbind or .die by using the original
|
||||
// callback as a reference.
|
||||
if ( $.guid ) {
|
||||
wrapper.guid = callback.guid = callback.guid || $.guid++;
|
||||
}
|
||||
|
||||
// Return the wrapper function.
|
||||
return wrapper;
|
||||
};
|
||||
|
||||
// Method: jQuery.debounce
|
||||
//
|
||||
// Debounce execution of a function. Debouncing, unlike throttling,
|
||||
// guarantees that a function is only executed a single time, either at the
|
||||
// very beginning of a series of calls, or at the very end. If you want to
|
||||
// simply rate-limit execution of a function, see the <jQuery.throttle>
|
||||
// method.
|
||||
//
|
||||
// In this visualization, | is a debounced-function call and X is the actual
|
||||
// callback execution:
|
||||
//
|
||||
// > Debounced with `at_begin` specified as false or unspecified:
|
||||
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
|
||||
// > X X
|
||||
// >
|
||||
// > Debounced with `at_begin` specified as true:
|
||||
// > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
|
||||
// > X X
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// > var debounced = jQuery.debounce( delay, [ at_begin, ] callback );
|
||||
// >
|
||||
// > jQuery('selector').bind( 'someevent', debounced );
|
||||
// > jQuery('selector').unbind( 'someevent', debounced );
|
||||
//
|
||||
// This also works in jQuery 1.4+:
|
||||
//
|
||||
// > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) );
|
||||
// > jQuery('selector').unbind( 'someevent', callback );
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// delay - (Number) A zero-or-greater delay in milliseconds. For event
|
||||
// callbacks, values around 100 or 250 (or even higher) are most useful.
|
||||
// at_begin - (Boolean) Optional, defaults to false. If at_begin is false or
|
||||
// unspecified, callback will only be executed `delay` milliseconds after
|
||||
// the last debounced-function call. If at_begin is true, callback will be
|
||||
// executed only at the first debounced-function call. (After the
|
||||
// throttled-function has not been called for `delay` milliseconds, the
|
||||
// internal counter is reset)
|
||||
// callback - (Function) A function to be executed after delay milliseconds.
|
||||
// The `this` context and all arguments are passed through, as-is, to
|
||||
// `callback` when the debounced-function is executed.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// (Function) A new, debounced, function.
|
||||
|
||||
$.debounce = function( delay, at_begin, callback ) {
|
||||
return callback === undefined
|
||||
? jq_throttle( delay, at_begin, false )
|
||||
: jq_throttle( delay, callback, at_begin !== false );
|
||||
};
|
||||
|
||||
})(this);
|
||||
10722
gns3server/static/web-ui/assets/xpra-html5/js/lib/jquery.js
vendored
Normal file
10722
gns3server/static/web-ui/assets/xpra-html5/js/lib/jquery.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4170
gns3server/static/web-ui/assets/xpra-html5/js/lib/jsmpeg.js
Normal file
4170
gns3server/static/web-ui/assets/xpra-html5/js/lib/jsmpeg.js
Normal file
File diff suppressed because it is too large
Load Diff
752
gns3server/static/web-ui/assets/xpra-html5/js/lib/lz4.js
Normal file
752
gns3server/static/web-ui/assets/xpra-html5/js/lib/lz4.js
Normal file
@ -0,0 +1,752 @@
|
||||
// lz4.js - An implementation of Lz4 in plain JavaScript.
|
||||
//
|
||||
// TODO:
|
||||
// - Unify header parsing/writing.
|
||||
// - Support options (block size, checksums)
|
||||
// - Support streams
|
||||
// - Better error handling (handle bad offset, etc.)
|
||||
// - HC support (better search algorithm)
|
||||
// - Tests/benchmarking
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
util = {}
|
||||
|
||||
// Simple hash function, from: http://burtleburtle.net/bob/hash/integer.html.
|
||||
// Chosen because it doesn't use multiply and achieves full avalanche.
|
||||
util.hashU32 = function hashU32(a) {
|
||||
a = a | 0;
|
||||
a = a + 2127912214 + (a << 12) | 0;
|
||||
a = a ^ -949894596 ^ a >>> 19;
|
||||
a = a + 374761393 + (a << 5) | 0;
|
||||
a = a + -744332180 ^ a << 9;
|
||||
a = a + -42973499 + (a << 3) | 0;
|
||||
return a ^ -1252372727 ^ a >>> 16 | 0;
|
||||
}
|
||||
|
||||
// Reads a 64-bit little-endian integer from an array.
|
||||
util.readU64 = function readU64(b, n) {
|
||||
var x = 0;
|
||||
x |= b[n++] << 0;
|
||||
x |= b[n++] << 8;
|
||||
x |= b[n++] << 16;
|
||||
x |= b[n++] << 24;
|
||||
x |= b[n++] << 32;
|
||||
x |= b[n++] << 40;
|
||||
x |= b[n++] << 48;
|
||||
x |= b[n++] << 56;
|
||||
return x;
|
||||
}
|
||||
|
||||
// Reads a 32-bit little-endian integer from an array.
|
||||
util.readU32 = function readU32(b, n) {
|
||||
var x = 0;
|
||||
x |= b[n++] << 0;
|
||||
x |= b[n++] << 8;
|
||||
x |= b[n++] << 16;
|
||||
x |= b[n++] << 24;
|
||||
return x;
|
||||
}
|
||||
|
||||
// Writes a 32-bit little-endian integer from an array.
|
||||
util.writeU32 = function writeU32(b, n, x) {
|
||||
b[n++] = (x >> 0) & 0xff;
|
||||
b[n++] = (x >> 8) & 0xff;
|
||||
b[n++] = (x >> 16) & 0xff;
|
||||
b[n++] = (x >> 24) & 0xff;
|
||||
}
|
||||
|
||||
// Multiplies two numbers using 32-bit integer multiplication.
|
||||
// Algorithm from Emscripten.
|
||||
util.imul = function imul(a, b) {
|
||||
var ah = a >>> 16;
|
||||
var al = a & 65535;
|
||||
var bh = b >>> 16;
|
||||
var bl = b & 65535;
|
||||
|
||||
return al * bl + (ah * bl + al * bh << 16) | 0;
|
||||
};
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
// xxh32.js - implementation of xxhash32 in plain JavaScript
|
||||
|
||||
// xxhash32 primes
|
||||
var prime1 = 0x9e3779b1;
|
||||
var prime2 = 0x85ebca77;
|
||||
var prime3 = 0xc2b2ae3d;
|
||||
var prime4 = 0x27d4eb2f;
|
||||
var prime5 = 0x165667b1;
|
||||
|
||||
// Utility functions/primitives
|
||||
// --
|
||||
|
||||
function rotl32 (x, r) {
|
||||
x = x | 0;
|
||||
r = r | 0;
|
||||
|
||||
return x >>> (32 - r | 0) | x << r | 0;
|
||||
}
|
||||
|
||||
function rotmul32 (h, r, m) {
|
||||
h = h | 0;
|
||||
r = r | 0;
|
||||
m = m | 0;
|
||||
|
||||
return util.imul(h >>> (32 - r | 0) | h << r, m) | 0;
|
||||
}
|
||||
|
||||
function shiftxor32 (h, s) {
|
||||
h = h | 0;
|
||||
s = s | 0;
|
||||
|
||||
return h >>> s ^ h | 0;
|
||||
}
|
||||
|
||||
// Implementation
|
||||
// --
|
||||
|
||||
function xxhapply (h, src, m0, s, m1) {
|
||||
return rotmul32(util.imul(src, m0) + h, s, m1);
|
||||
}
|
||||
|
||||
function xxh1 (h, src, index) {
|
||||
return rotmul32((h + util.imul(src[index], prime5)), 11, prime1);
|
||||
}
|
||||
|
||||
function xxh4 (h, src, index) {
|
||||
return xxhapply(h, util.readU32(src, index), prime3, 17, prime4);
|
||||
}
|
||||
|
||||
function xxh16 (h, src, index) {
|
||||
return [
|
||||
xxhapply(h[0], util.readU32(src, index + 0), prime2, 13, prime1),
|
||||
xxhapply(h[1], util.readU32(src, index + 4), prime2, 13, prime1),
|
||||
xxhapply(h[2], util.readU32(src, index + 8), prime2, 13, prime1),
|
||||
xxhapply(h[3], util.readU32(src, index + 12), prime2, 13, prime1)
|
||||
];
|
||||
}
|
||||
|
||||
function xxh32 (seed, src, index, len) {
|
||||
var h, l;
|
||||
l = len;
|
||||
if (len >= 16) {
|
||||
h = [
|
||||
seed + prime1 + prime2,
|
||||
seed + prime2,
|
||||
seed,
|
||||
seed - prime1
|
||||
];
|
||||
|
||||
while (len >= 16) {
|
||||
h = xxh16(h, src, index);
|
||||
|
||||
index += 16;
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
h = rotl32(h[0], 1) + rotl32(h[1], 7) + rotl32(h[2], 12) + rotl32(h[3], 18) + l;
|
||||
} else {
|
||||
h = (seed + prime5 + len) >>> 0;
|
||||
}
|
||||
|
||||
while (len >= 4) {
|
||||
h = xxh4(h, src, index);
|
||||
|
||||
index += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
h = xxh1(h, src, index);
|
||||
|
||||
index++;
|
||||
len--;
|
||||
}
|
||||
|
||||
h = shiftxor32(util.imul(shiftxor32(util.imul(shiftxor32(h, 15), prime2), 13), prime3), 16);
|
||||
|
||||
return h >>> 0;
|
||||
}
|
||||
|
||||
xxhash = {}
|
||||
xxhash.hash = xxh32;
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
lz4 = {};
|
||||
// Constants
|
||||
// --
|
||||
|
||||
// Compression format parameters/constants.
|
||||
var minMatch = 4;
|
||||
var minLength = 13;
|
||||
var searchLimit = 5;
|
||||
var skipTrigger = 6;
|
||||
var hashSize = 1 << 16;
|
||||
|
||||
// Token constants.
|
||||
var mlBits = 4;
|
||||
var mlMask = (1 << mlBits) - 1;
|
||||
var runBits = 4;
|
||||
var runMask = (1 << runBits) - 1;
|
||||
|
||||
// Shared buffers
|
||||
var blockBuf = makeBuffer(5 << 20);
|
||||
var hashTable = makeHashTable();
|
||||
|
||||
// Frame constants.
|
||||
var magicNum = 0x184D2204;
|
||||
|
||||
// Frame descriptor flags.
|
||||
var fdContentChksum = 0x4;
|
||||
var fdContentSize = 0x8;
|
||||
var fdBlockChksum = 0x10;
|
||||
// var fdBlockIndep = 0x20;
|
||||
var fdVersion = 0x40;
|
||||
var fdVersionMask = 0xC0;
|
||||
|
||||
// Block sizes.
|
||||
var bsUncompressed = 0x80000000;
|
||||
var bsDefault = 7;
|
||||
var bsShift = 4;
|
||||
var bsMask = 7;
|
||||
var bsMap = {
|
||||
4: 0x10000,
|
||||
5: 0x40000,
|
||||
6: 0x100000,
|
||||
7: 0x400000
|
||||
};
|
||||
|
||||
// Utility functions/primitives
|
||||
// --
|
||||
|
||||
// Makes our hashtable. On older browsers, may return a plain array.
|
||||
function makeHashTable () {
|
||||
try {
|
||||
return new Uint32Array(hashSize);
|
||||
} catch (error) {
|
||||
var hashTable = new Array(hashSize);
|
||||
|
||||
for (var i = 0; i < hashSize; i++) {
|
||||
hashTable[i] = 0;
|
||||
}
|
||||
|
||||
return hashTable;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear hashtable.
|
||||
function clearHashTable (table) {
|
||||
for (var i = 0; i < hashSize; i++) {
|
||||
hashTable[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Makes a byte buffer. On older browsers, may return a plain array.
|
||||
function makeBuffer (size) {
|
||||
try {
|
||||
return new Uint8Array(size);
|
||||
} catch (error) {
|
||||
var buf = new Array(size);
|
||||
|
||||
for (var i = 0; i < size; i++) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
function sliceArray (array, start, end) {
|
||||
if (typeof array.buffer !== undefined) {
|
||||
if (Uint8Array.prototype.slice) {
|
||||
return array.slice(start, end);
|
||||
} else {
|
||||
// Uint8Array#slice polyfill.
|
||||
var len = array.length;
|
||||
|
||||
// Calculate start.
|
||||
start = start | 0;
|
||||
start = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len);
|
||||
|
||||
// Calculate end.
|
||||
end = (end === undefined) ? len : end | 0;
|
||||
end = (end < 0) ? Math.max(len + end, 0) : Math.min(end, len);
|
||||
|
||||
// Copy into new array.
|
||||
var arraySlice = new Uint8Array(end - start);
|
||||
for (var i = start, n = 0; i < end;) {
|
||||
arraySlice[n++] = array[i++];
|
||||
}
|
||||
|
||||
return arraySlice;
|
||||
}
|
||||
} else {
|
||||
// Assume normal array.
|
||||
return array.slice(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation
|
||||
// --
|
||||
|
||||
// Calculates an upper bound for lz4 compression.
|
||||
lz4.compressBound = function compressBound (n) {
|
||||
return (n + (n / 255) + 16) | 0;
|
||||
};
|
||||
|
||||
// Calculates an upper bound for lz4 decompression, by reading the data.
|
||||
lz4.decompressBound = function decompressBound (src) {
|
||||
var sIndex = 0;
|
||||
|
||||
// Read magic number
|
||||
if (util.readU32(src, sIndex) !== magicNum) {
|
||||
throw new Error('invalid magic number');
|
||||
}
|
||||
|
||||
sIndex += 4;
|
||||
|
||||
// Read descriptor
|
||||
var descriptor = src[sIndex++];
|
||||
|
||||
// Check version
|
||||
if ((descriptor & fdVersionMask) !== fdVersion) {
|
||||
throw new Error('incompatible descriptor version ' + (descriptor & fdVersionMask));
|
||||
}
|
||||
|
||||
// Read flags
|
||||
var useBlockSum = (descriptor & fdBlockChksum) !== 0;
|
||||
var useContentSize = (descriptor & fdContentSize) !== 0;
|
||||
|
||||
// Read block size
|
||||
var bsIdx = (src[sIndex++] >> bsShift) & bsMask;
|
||||
|
||||
if (bsMap[bsIdx] === undefined) {
|
||||
throw new Error('invalid block size ' + bsIdx);
|
||||
}
|
||||
|
||||
var maxBlockSize = bsMap[bsIdx];
|
||||
|
||||
// Get content size
|
||||
if (useContentSize) {
|
||||
return util.readU64(src, sIndex);
|
||||
}
|
||||
|
||||
// Checksum
|
||||
sIndex++;
|
||||
|
||||
// Read blocks.
|
||||
var maxSize = 0;
|
||||
while (true) {
|
||||
var blockSize = util.readU32(src, sIndex);
|
||||
sIndex += 4;
|
||||
|
||||
if (blockSize & bsUncompressed) {
|
||||
blockSize &= ~bsUncompressed;
|
||||
maxSize += blockSize;
|
||||
} else if (blockSize > 0) {
|
||||
maxSize += maxBlockSize;
|
||||
}
|
||||
|
||||
if (blockSize === 0) {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
if (useBlockSum) {
|
||||
sIndex += 4;
|
||||
}
|
||||
|
||||
sIndex += blockSize;
|
||||
}
|
||||
};
|
||||
|
||||
// Creates a buffer of a given byte-size, falling back to plain arrays.
|
||||
lz4.makeBuffer = makeBuffer;
|
||||
|
||||
// Decompresses a block of Lz4.
|
||||
lz4.decompressBlock = function decompressBlock (src, dst, sIndex, sLength, dIndex) {
|
||||
var mLength, mOffset, sEnd, n, i;
|
||||
var hasCopyWithin = dst.copyWithin !== undefined && dst.fill !== undefined;
|
||||
|
||||
// Setup initial state.
|
||||
sEnd = sIndex + sLength;
|
||||
|
||||
// Consume entire input block.
|
||||
while (sIndex < sEnd) {
|
||||
var token = src[sIndex++];
|
||||
|
||||
// Copy literals.
|
||||
var literalCount = (token >> 4);
|
||||
if (literalCount > 0) {
|
||||
// Parse length.
|
||||
if (literalCount === 0xf) {
|
||||
while (true) {
|
||||
literalCount += src[sIndex];
|
||||
if (src[sIndex++] !== 0xff) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy literals
|
||||
for (n = sIndex + literalCount; sIndex < n;) {
|
||||
dst[dIndex++] = src[sIndex++];
|
||||
}
|
||||
}
|
||||
|
||||
if (sIndex >= sEnd) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Copy match.
|
||||
mLength = (token & 0xf);
|
||||
|
||||
// Parse offset.
|
||||
mOffset = src[sIndex++] | (src[sIndex++] << 8);
|
||||
|
||||
// Parse length.
|
||||
if (mLength === 0xf) {
|
||||
while (true) {
|
||||
mLength += src[sIndex];
|
||||
if (src[sIndex++] !== 0xff) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mLength += minMatch;
|
||||
|
||||
// Copy match
|
||||
// prefer to use typedarray.copyWithin for larger matches
|
||||
// NOTE: copyWithin doesn't work as required by LZ4 for overlapping sequences
|
||||
// e.g. mOffset=1, mLength=30 (repeach char 30 times)
|
||||
// we special case the repeat char w/ array.fill
|
||||
if (hasCopyWithin && mOffset === 1) {
|
||||
dst.fill(dst[dIndex - 1] | 0, dIndex, dIndex + mLength);
|
||||
dIndex += mLength;
|
||||
} else if (hasCopyWithin && mOffset > mLength && mLength > 31) {
|
||||
dst.copyWithin(dIndex, dIndex - mOffset, dIndex - mOffset + mLength);
|
||||
dIndex += mLength;
|
||||
} else {
|
||||
for (i = dIndex - mOffset, n = i + mLength; i < n;) {
|
||||
dst[dIndex++] = dst[i++] | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dIndex;
|
||||
};
|
||||
|
||||
// Compresses a block with Lz4.
|
||||
lz4.compressBlock = function compressBlock (src, dst, sIndex, sLength, hashTable) {
|
||||
var mIndex, mAnchor, mLength, mOffset, mStep;
|
||||
var literalCount, dIndex, sEnd, n;
|
||||
|
||||
// Setup initial state.
|
||||
dIndex = 0;
|
||||
sEnd = sLength + sIndex;
|
||||
mAnchor = sIndex;
|
||||
|
||||
// Process only if block is large enough.
|
||||
if (sLength >= minLength) {
|
||||
var searchMatchCount = (1 << skipTrigger) + 3;
|
||||
|
||||
// Consume until last n literals (Lz4 spec limitation.)
|
||||
while (sIndex + minMatch < sEnd - searchLimit) {
|
||||
var seq = util.readU32(src, sIndex);
|
||||
var hash = util.hashU32(seq) >>> 0;
|
||||
|
||||
// Crush hash to 16 bits.
|
||||
hash = ((hash >> 16) ^ hash) >>> 0 & 0xffff;
|
||||
|
||||
// Look for a match in the hashtable. NOTE: remove one; see below.
|
||||
mIndex = hashTable[hash] - 1;
|
||||
|
||||
// Put pos in hash table. NOTE: add one so that zero = invalid.
|
||||
hashTable[hash] = sIndex + 1;
|
||||
|
||||
// Determine if there is a match (within range.)
|
||||
if (mIndex < 0 || ((sIndex - mIndex) >>> 16) > 0 || util.readU32(src, mIndex) !== seq) {
|
||||
mStep = searchMatchCount++ >> skipTrigger;
|
||||
sIndex += mStep;
|
||||
continue;
|
||||
}
|
||||
|
||||
searchMatchCount = (1 << skipTrigger) + 3;
|
||||
|
||||
// Calculate literal count and offset.
|
||||
literalCount = sIndex - mAnchor;
|
||||
mOffset = sIndex - mIndex;
|
||||
|
||||
// We've already matched one word, so get that out of the way.
|
||||
sIndex += minMatch;
|
||||
mIndex += minMatch;
|
||||
|
||||
// Determine match length.
|
||||
// N.B.: mLength does not include minMatch, Lz4 adds it back
|
||||
// in decoding.
|
||||
mLength = sIndex;
|
||||
while (sIndex < sEnd - searchLimit && src[sIndex] === src[mIndex]) {
|
||||
sIndex++;
|
||||
mIndex++;
|
||||
}
|
||||
mLength = sIndex - mLength;
|
||||
|
||||
// Write token + literal count.
|
||||
var token = mLength < mlMask ? mLength : mlMask;
|
||||
if (literalCount >= runMask) {
|
||||
dst[dIndex++] = (runMask << mlBits) + token;
|
||||
for (n = literalCount - runMask; n >= 0xff; n -= 0xff) {
|
||||
dst[dIndex++] = 0xff;
|
||||
}
|
||||
dst[dIndex++] = n;
|
||||
} else {
|
||||
dst[dIndex++] = (literalCount << mlBits) + token;
|
||||
}
|
||||
|
||||
// Write literals.
|
||||
for (var i = 0; i < literalCount; i++) {
|
||||
dst[dIndex++] = src[mAnchor + i];
|
||||
}
|
||||
|
||||
// Write offset.
|
||||
dst[dIndex++] = mOffset;
|
||||
dst[dIndex++] = (mOffset >> 8);
|
||||
|
||||
// Write match length.
|
||||
if (mLength >= mlMask) {
|
||||
for (n = mLength - mlMask; n >= 0xff; n -= 0xff) {
|
||||
dst[dIndex++] = 0xff;
|
||||
}
|
||||
dst[dIndex++] = n;
|
||||
}
|
||||
|
||||
// Move the anchor.
|
||||
mAnchor = sIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing was encoded.
|
||||
if (mAnchor === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write remaining literals.
|
||||
// Write literal token+count.
|
||||
literalCount = sEnd - mAnchor;
|
||||
if (literalCount >= runMask) {
|
||||
dst[dIndex++] = (runMask << mlBits);
|
||||
for (n = literalCount - runMask; n >= 0xff; n -= 0xff) {
|
||||
dst[dIndex++] = 0xff;
|
||||
}
|
||||
dst[dIndex++] = n;
|
||||
} else {
|
||||
dst[dIndex++] = (literalCount << mlBits);
|
||||
}
|
||||
|
||||
// Write literals.
|
||||
sIndex = mAnchor;
|
||||
while (sIndex < sEnd) {
|
||||
dst[dIndex++] = src[sIndex++];
|
||||
}
|
||||
|
||||
return dIndex;
|
||||
};
|
||||
|
||||
// Decompresses a frame of Lz4 data.
|
||||
lz4.decompressFrame = function decompressFrame (src, dst) {
|
||||
var useBlockSum, useContentSum, useContentSize, descriptor;
|
||||
var sIndex = 0;
|
||||
var dIndex = 0;
|
||||
|
||||
// Read magic number
|
||||
if (util.readU32(src, sIndex) !== magicNum) {
|
||||
throw new Error('invalid magic number');
|
||||
}
|
||||
|
||||
sIndex += 4;
|
||||
|
||||
// Read descriptor
|
||||
descriptor = src[sIndex++];
|
||||
|
||||
// Check version
|
||||
if ((descriptor & fdVersionMask) !== fdVersion) {
|
||||
throw new Error('incompatible descriptor version');
|
||||
}
|
||||
|
||||
// Read flags
|
||||
useBlockSum = (descriptor & fdBlockChksum) !== 0;
|
||||
useContentSum = (descriptor & fdContentChksum) !== 0;
|
||||
useContentSize = (descriptor & fdContentSize) !== 0;
|
||||
|
||||
// Read block size
|
||||
var bsIdx = (src[sIndex++] >> bsShift) & bsMask;
|
||||
|
||||
if (bsMap[bsIdx] === undefined) {
|
||||
throw new Error('invalid block size');
|
||||
}
|
||||
|
||||
if (useContentSize) {
|
||||
// TODO: read content size
|
||||
sIndex += 8;
|
||||
}
|
||||
|
||||
sIndex++;
|
||||
|
||||
// Read blocks.
|
||||
while (true) {
|
||||
var compSize;
|
||||
|
||||
compSize = util.readU32(src, sIndex);
|
||||
sIndex += 4;
|
||||
|
||||
if (compSize === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (useBlockSum) {
|
||||
// TODO: read block checksum
|
||||
sIndex += 4;
|
||||
}
|
||||
|
||||
// Check if block is compressed
|
||||
if ((compSize & bsUncompressed) !== 0) {
|
||||
// Mask off the 'uncompressed' bit
|
||||
compSize &= ~bsUncompressed;
|
||||
|
||||
// Copy uncompressed data into destination buffer.
|
||||
for (var j = 0; j < compSize; j++) {
|
||||
dst[dIndex++] = src[sIndex++];
|
||||
}
|
||||
} else {
|
||||
// Decompress into blockBuf
|
||||
dIndex = lz4.decompressBlock(src, dst, sIndex, compSize, dIndex);
|
||||
sIndex += compSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (useContentSum) {
|
||||
// TODO: read content checksum
|
||||
sIndex += 4;
|
||||
}
|
||||
|
||||
return dIndex;
|
||||
};
|
||||
|
||||
// Compresses data to an Lz4 frame.
|
||||
lz4.compressFrame = function compressFrame (src, dst) {
|
||||
var dIndex = 0;
|
||||
|
||||
// Write magic number.
|
||||
util.writeU32(dst, dIndex, magicNum);
|
||||
dIndex += 4;
|
||||
|
||||
// Descriptor flags.
|
||||
dst[dIndex++] = fdVersion;
|
||||
dst[dIndex++] = bsDefault << bsShift;
|
||||
|
||||
// Descriptor checksum.
|
||||
dst[dIndex] = xxhash.hash(0, dst, 4, dIndex - 4) >> 8;
|
||||
dIndex++;
|
||||
|
||||
// Write blocks.
|
||||
var maxBlockSize = bsMap[bsDefault];
|
||||
var remaining = src.length;
|
||||
var sIndex = 0;
|
||||
|
||||
// Clear the hashtable.
|
||||
clearHashTable(hashTable);
|
||||
|
||||
// Split input into blocks and write.
|
||||
while (remaining > 0) {
|
||||
var compSize = 0;
|
||||
var blockSize = remaining > maxBlockSize ? maxBlockSize : remaining;
|
||||
|
||||
compSize = lz4.compressBlock(src, blockBuf, sIndex, blockSize, hashTable);
|
||||
|
||||
if (compSize > blockSize || compSize === 0) {
|
||||
// Output uncompressed.
|
||||
util.writeU32(dst, dIndex, 0x80000000 | blockSize);
|
||||
dIndex += 4;
|
||||
|
||||
for (var z = sIndex + blockSize; sIndex < z;) {
|
||||
dst[dIndex++] = src[sIndex++];
|
||||
}
|
||||
|
||||
remaining -= blockSize;
|
||||
} else {
|
||||
// Output compressed.
|
||||
util.writeU32(dst, dIndex, compSize);
|
||||
dIndex += 4;
|
||||
|
||||
for (var j = 0; j < compSize;) {
|
||||
dst[dIndex++] = blockBuf[j++];
|
||||
}
|
||||
|
||||
sIndex += blockSize;
|
||||
remaining -= blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Write blank end block.
|
||||
util.writeU32(dst, dIndex, 0);
|
||||
dIndex += 4;
|
||||
|
||||
return dIndex;
|
||||
};
|
||||
|
||||
// Decompresses a buffer containing an Lz4 frame. maxSize is optional; if not
|
||||
// provided, a maximum size will be determined by examining the data. The
|
||||
// buffer returned will always be perfectly-sized.
|
||||
lz4.decompress = function decompress (src, maxSize) {
|
||||
var dst, size;
|
||||
|
||||
if (maxSize === undefined) {
|
||||
maxSize = lz4.decompressBound(src);
|
||||
}
|
||||
dst = lz4.makeBuffer(maxSize);
|
||||
size = lz4.decompressFrame(src, dst);
|
||||
|
||||
if (size !== maxSize) {
|
||||
dst = sliceArray(dst, 0, size);
|
||||
}
|
||||
|
||||
return dst;
|
||||
};
|
||||
|
||||
// Compresses a buffer to an Lz4 frame. maxSize is optional; if not provided,
|
||||
// a buffer will be created based on the theoretical worst output size for a
|
||||
// given input size. The buffer returned will always be perfectly-sized.
|
||||
lz4.compress = function compress (src, maxSize) {
|
||||
var dst, size;
|
||||
|
||||
if (maxSize === undefined) {
|
||||
maxSize = lz4.compressBound(src.length);
|
||||
}
|
||||
|
||||
dst = lz4.makeBuffer(maxSize);
|
||||
size = lz4.compressFrame(src, dst);
|
||||
|
||||
if (size !== maxSize) {
|
||||
dst = sliceArray(dst, 0, size);
|
||||
}
|
||||
|
||||
return dst;
|
||||
};
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
//convenience function added for xpra:
|
||||
lz4.decode = function(data) {
|
||||
const length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
||||
if (length<=0) {
|
||||
throw "invalid length: "+length;
|
||||
}
|
||||
if (length>1024*1024*1024) {
|
||||
throw "length too long: "+length;
|
||||
}
|
||||
const inflated = new Uint8Array(length);
|
||||
lz4.decompressBlock(data, inflated, 4, length, 0);
|
||||
return inflated;
|
||||
}
|
||||
553
gns3server/static/web-ui/assets/xpra-html5/js/lib/rencode.js
Normal file
553
gns3server/static/web-ui/assets/xpra-html5/js/lib/rencode.js
Normal file
@ -0,0 +1,553 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Antoine Martin <antoine@xpra.org>
|
||||
*/
|
||||
|
||||
const RENCODE = {
|
||||
DEFAULT_FLOAT_BITS : 32,
|
||||
MAX_INT_LENGTH : 64,
|
||||
|
||||
CHR_LIST : 59,
|
||||
CHR_DICT : 60,
|
||||
CHR_INT : 61,
|
||||
CHR_INT1 : 62,
|
||||
CHR_INT2 : 63,
|
||||
CHR_INT4 : 64,
|
||||
CHR_INT8 : 65,
|
||||
CHR_FLOAT32 : 66,
|
||||
CHR_FLOAT64 : 44,
|
||||
CHR_TRUE : 67,
|
||||
CHR_FALSE : 68,
|
||||
CHR_NONE : 69,
|
||||
CHR_TERM : 127,
|
||||
|
||||
INT_POS_FIXED_START : 0,
|
||||
INT_POS_FIXED_COUNT : 44,
|
||||
|
||||
DICT_FIXED_START : 102,
|
||||
DICT_FIXED_COUNT : 25,
|
||||
|
||||
INT_NEG_FIXED_START : 70,
|
||||
INT_NEG_FIXED_COUNT : 32,
|
||||
|
||||
STR_FIXED_START : 128,
|
||||
STR_FIXED_COUNT : 64,
|
||||
|
||||
LIST_FIXED_START : 128+64, //STR_FIXED_START + STR_FIXED_COUNT,
|
||||
LIST_FIXED_COUNT : 64,
|
||||
|
||||
COLON_CHARCODE : ":".charCodeAt(0), //for char strings
|
||||
SLASH_CHARCODE : "/".charCodeAt(0), //for byte strings
|
||||
};
|
||||
|
||||
Number.isSafeInteger = Number.isSafeInteger || function (value) {
|
||||
return Number.isInteger(value) && Math.abs(value) <= Number.MAX_SAFE_INTEGER;
|
||||
};
|
||||
|
||||
function utf8ByteArrayToString(bytes) {
|
||||
let out = [], pos = 0, c = 0;
|
||||
while (pos < bytes.length) {
|
||||
const c1 = bytes[pos++];
|
||||
if (c1 < 128) {
|
||||
out[c++] = String.fromCharCode(c1);
|
||||
} else if (c1 > 191 && c1 < 224) {
|
||||
const c2 = bytes[pos++];
|
||||
out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
|
||||
} else if (c1 > 239 && c1 < 365) {
|
||||
// Surrogate Pair
|
||||
const c2 = bytes[pos++];
|
||||
const c3 = bytes[pos++];
|
||||
const c4 = bytes[pos++];
|
||||
const u = ((c1 & 7) << 18 | (c2 & 63) << 12 | (c3 & 63) << 6 | c4 & 63) - 0x10000;
|
||||
out[c++] = String.fromCharCode(0xD800 + (u >> 10));
|
||||
out[c++] = String.fromCharCode(0xDC00 + (u & 1023));
|
||||
} else {
|
||||
const c2 = bytes[pos++];
|
||||
const c3 = bytes[pos++];
|
||||
out[c++] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
|
||||
}
|
||||
}
|
||||
return out.join('');
|
||||
}
|
||||
|
||||
function stringToUtf8ByteArray(str) {
|
||||
let out = [], p = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
let c = str.charCodeAt(i);
|
||||
if (c < 128) {
|
||||
out[p++] = c;
|
||||
} else if (c < 2048) {
|
||||
out[p++] = (c >> 6) | 192;
|
||||
out[p++] = (c & 63) | 128;
|
||||
} else if (
|
||||
((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
|
||||
((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
|
||||
// Surrogate Pair
|
||||
c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
|
||||
out[p++] = (c >> 18) | 240;
|
||||
out[p++] = ((c >> 12) & 63) | 128;
|
||||
out[p++] = ((c >> 6) & 63) | 128;
|
||||
out[p++] = (c & 63) | 128;
|
||||
} else {
|
||||
out[p++] = (c >> 12) | 224;
|
||||
out[p++] = ((c >> 6) & 63) | 128;
|
||||
out[p++] = (c & 63) | 128;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function rencode_string(str) {
|
||||
const bytes = stringToUtf8ByteArray(str);
|
||||
const len = bytes.length;
|
||||
if (len < RENCODE.STR_FIXED_COUNT) {
|
||||
const u8a = new Uint8Array(len+1);
|
||||
u8a[0] = RENCODE.STR_FIXED_START+len;
|
||||
for (let i=0; i<len; ++i) {
|
||||
u8a[i+1] = bytes[i];
|
||||
}
|
||||
return u8a;
|
||||
}
|
||||
const len_str = len.toString();
|
||||
const len_len = len_str.length;
|
||||
const u8a = new Uint8Array(len_len+1+len);
|
||||
for (let i=0; i<len_len; ++i) {
|
||||
u8a[i] = len_str.charCodeAt(i);
|
||||
}
|
||||
const SEPARATOR = ":";
|
||||
u8a[len_len] = SEPARATOR.charCodeAt(0);
|
||||
for (let i=0; i<len_str; ++i) {
|
||||
u8a[len_len+1+i] = bytes[i];
|
||||
}
|
||||
return u8a;
|
||||
}
|
||||
|
||||
function rencode_int(i) {
|
||||
let u8a = null;
|
||||
if (0 <= i && i < RENCODE.INT_POS_FIXED_COUNT) {
|
||||
u8a = new Uint8Array([RENCODE.INT_POS_FIXED_START + i])
|
||||
}
|
||||
else if (-RENCODE.INT_NEG_FIXED_COUNT <= i && i < 0) {
|
||||
u8a = new Uint8Array(new Int8Array([RENCODE.INT_NEG_FIXED_START - 1 -i]).buffer);
|
||||
}
|
||||
else if (-128 <= i && i < 128) {
|
||||
u8a = new Uint8Array(new Int8Array([RENCODE.CHR_INT1, i]).buffer);
|
||||
}
|
||||
else if (-32768 <= i && i < 32768) {
|
||||
u8a = new Uint8Array(new Int8Array([RENCODE.CHR_INT2, Math.floor(i/256) % 256, i%256]).buffer);
|
||||
}
|
||||
else if (-2147483648 <= i && i< 2147483648) {
|
||||
const i8a = new Int8Array(5);
|
||||
i8a[0] = RENCODE.CHR_INT4;
|
||||
i8a[1] = Math.floor(i/256/256/256);
|
||||
i8a[2] = Math.floor(i/256/256) % 256;
|
||||
i8a[3] = Math.floor(i/256) % 256;
|
||||
i8a[4] = i%256;
|
||||
u8a = new Uint8Array(i8a.buffer);
|
||||
}
|
||||
else if (-9223372036854775808 <= i && i < 9223372036854775808) {
|
||||
const i8a = new Int8Array(9);
|
||||
i8a[0] = RENCODE.CHR_INT8;
|
||||
for (let j=0; j<8; ++j) {
|
||||
i8a[8-j] = i%256;
|
||||
i = Math.floor(i/256);
|
||||
}
|
||||
u8a = new Uint8Array(i8a.buffer);
|
||||
}
|
||||
else {
|
||||
const str = i.toString();
|
||||
if (str.length >= RENCODE.MAX_INT_LENGTH) {
|
||||
throw "number too big: "+i;
|
||||
}
|
||||
const str_len = str.length;
|
||||
u8a = new Uint8Array(str_len+2);
|
||||
u8a[0] = RENCODE.CHR_INT;
|
||||
for (let j=0; j<str_len; ++j) {
|
||||
u8a[1+j] = str[j];
|
||||
}
|
||||
u8a[str_len+1] = RENCODE.CHR_TERM;
|
||||
}
|
||||
return u8a;
|
||||
}
|
||||
|
||||
|
||||
function rencode_merge_arrays(rlist) {
|
||||
let len = 0;
|
||||
for (let i=0; i<rlist.length; ++i) {
|
||||
len += rlist[i].length;
|
||||
}
|
||||
const u8a = new Uint8Array(len);
|
||||
let index = 0;
|
||||
for (let i=0; i<rlist.length; ++i) {
|
||||
u8a.set(rlist[i], index);
|
||||
index += rlist[i].length;
|
||||
}
|
||||
return u8a;
|
||||
}
|
||||
|
||||
function rencode_uint8(a) {
|
||||
const len = a.length;
|
||||
const len_str = len.toString();
|
||||
const len_len = len_str.length;
|
||||
const u8a = new Uint8Array(len_len+1+len);
|
||||
for (let i=0; i<len_len; ++i) {
|
||||
u8a[i] = len_str.charCodeAt(i);
|
||||
}
|
||||
const SEPARATOR = "/";
|
||||
u8a[len_len] = SEPARATOR.charCodeAt(0);
|
||||
u8a.set(a, len_len+1);
|
||||
return u8a;
|
||||
}
|
||||
|
||||
function rencode_list(l) {
|
||||
const list_len = l.length;
|
||||
const rlist = [];
|
||||
if (list_len < RENCODE.LIST_FIXED_COUNT) {
|
||||
rlist.push(new Uint8Array([RENCODE.LIST_FIXED_START + list_len]));
|
||||
for (let i=0; i<list_len; ++i) {
|
||||
rlist.push(rencode(l[i]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
rlist.push(new Uint8Array([RENCODE.CHR_LIST]));
|
||||
for (let i=0; i<list_len; ++i) {
|
||||
rlist.push(rencode(l[i]));
|
||||
}
|
||||
rlist.push(new Uint8Array([RENCODE.CHR_TERM]));
|
||||
}
|
||||
return rencode_merge_arrays(rlist);
|
||||
}
|
||||
|
||||
function rencode_dict(dict) {
|
||||
const dict_len = Object.keys(dict).length;
|
||||
const rlist = [];
|
||||
if (dict_len < RENCODE.DICT_FIXED_COUNT) {
|
||||
rlist.push(new Uint8Array([RENCODE.DICT_FIXED_START + dict_len]));
|
||||
for(const key in dict) {
|
||||
const value = dict[key];
|
||||
rlist.push(rencode(key));
|
||||
rlist.push(rencode(value));
|
||||
}
|
||||
}
|
||||
else {
|
||||
rlist.push(new Uint8Array([RENCODE.CHR_DICT]));
|
||||
for(const key in dict) {
|
||||
const value = dict[key];
|
||||
rlist.push(rencode(key));
|
||||
rlist.push(rencode(value));
|
||||
}
|
||||
rlist.push(new Uint8Array([RENCODE.CHR_TERM]));
|
||||
}
|
||||
return rencode_merge_arrays(rlist);
|
||||
}
|
||||
|
||||
function rencode_bool(v) {
|
||||
if (v) {
|
||||
return new Uint8Array([RENCODE.CHR_TRUE]);
|
||||
}
|
||||
else {
|
||||
return new Uint8Array([RENCODE.CHR_FALSE]);
|
||||
}
|
||||
}
|
||||
|
||||
function rencode_none() {
|
||||
return new Uint8Array([RENCODE.CHR_NONE]);
|
||||
}
|
||||
|
||||
function rencode(obj) {
|
||||
if (obj === null || obj === undefined) {
|
||||
return rencode_none();
|
||||
}
|
||||
const type = typeof obj;
|
||||
if(type === 'object') {
|
||||
if(typeof obj.length === 'undefined') {
|
||||
return rencode_dict(obj);
|
||||
}
|
||||
if(obj.constructor===Uint8Array) {
|
||||
return rencode_uint8(obj);
|
||||
}
|
||||
return rencode_list(obj);
|
||||
}
|
||||
switch(type) {
|
||||
case "string": return rencode_string(obj);
|
||||
case "number": return rencode_int(obj);
|
||||
case "list": return rencode_list(obj);
|
||||
case "dictionary": return rencode_dict(obj);
|
||||
case "boolean": return rencode_bool(obj?1:0);
|
||||
default: throw "invalid object type in source: "+type;
|
||||
}
|
||||
}
|
||||
|
||||
function rdecode_string(dec) {
|
||||
let len = 0;
|
||||
while (dec.buf[dec.pos+len]!=RENCODE.COLON_CHARCODE && dec.buf[dec.pos+len]!=RENCODE.SLASH_CHARCODE) {
|
||||
len++;
|
||||
}
|
||||
const str_len_str = String.fromCharCode.apply(null, dec.buf.subarray(dec.pos, dec.pos+len));
|
||||
const str_len = parseInt(str_len_str);
|
||||
if (isNaN(str_len)) {
|
||||
throw "invalid string length: '"+str_len_str+"'";
|
||||
}
|
||||
const binary = dec.buf[dec.pos+len]==RENCODE.SLASH_CHARCODE;
|
||||
dec.pos += len+1;
|
||||
const bytes = dec.buf.subarray(dec.pos, dec.pos+str_len);
|
||||
dec.pos += str_len;
|
||||
if (binary) {
|
||||
return new Uint8Array(bytes);
|
||||
}
|
||||
if (str_len==0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return utf8ByteArrayToString(bytes)
|
||||
}
|
||||
function Uint8ToString(u8a){
|
||||
if (typeof u8a == "string") {
|
||||
return u8a;
|
||||
}
|
||||
|
||||
const CHUNK_SZ = 0x8000;
|
||||
const c = [];
|
||||
for (let i=0; i < u8a.length; i+=CHUNK_SZ) {
|
||||
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ)));
|
||||
}
|
||||
return c.join("");
|
||||
}
|
||||
function rdecode_list(dec) {
|
||||
dec.pos++;
|
||||
const list = [];
|
||||
while (dec.buf[dec.pos]!=RENCODE.CHR_TERM) {
|
||||
list.push(_rdecode(dec));
|
||||
}
|
||||
dec.pos++;
|
||||
return list;
|
||||
}
|
||||
function rdecode_dict(dec) {
|
||||
dec.pos++;
|
||||
const dict = {};
|
||||
while (dec.buf[dec.pos]!=RENCODE.CHR_TERM) {
|
||||
const key = _rdecode(dec);
|
||||
const value = _rdecode(dec);
|
||||
dict[key] = value;
|
||||
}
|
||||
dec.pos++;
|
||||
return dict;
|
||||
}
|
||||
function rdecode_int(dec) {
|
||||
dec.pos++;
|
||||
let len = 0;
|
||||
while (dec.buf[dec.pos+len]!=RENCODE.CHR_TERM) {
|
||||
len++;
|
||||
}
|
||||
const int_str = String.fromCharCode.apply(null, dec.buf.subarray(dec.pos, dec.pos+len));
|
||||
dec.pos += len+1;
|
||||
const i = parseInt(int_str);
|
||||
if (isNaN(i)) {
|
||||
throw "invalid int: '"+int_str+"'";
|
||||
}
|
||||
return i;
|
||||
}
|
||||
function rdecode_intb(dec) {
|
||||
//this magically makes the value signed:
|
||||
let b = dec.buf[dec.pos+1]<<24>>24;
|
||||
dec.pos += 2;
|
||||
return b;
|
||||
}
|
||||
function rdecode_inth(dec) {
|
||||
const slice = dec.buf.slice(dec.pos+1, dec.pos+3)
|
||||
const dv = new DataView(slice.buffer);
|
||||
const s = dv.getInt16(0);
|
||||
dec.pos += 3;
|
||||
return s;
|
||||
}
|
||||
function rdecode_intl(dec) {
|
||||
const slice = dec.buf.slice(dec.pos+1, dec.pos+5)
|
||||
const dv = new DataView(slice.buffer);
|
||||
const s = dv.getInt32(0);
|
||||
dec.pos += 5;
|
||||
return s;
|
||||
}
|
||||
function rdecode_intq(dec) {
|
||||
const slice = dec.buf.slice(dec.pos+1, dec.pos+9)
|
||||
const dv = new DataView(slice.buffer);
|
||||
const s = dv.getBigInt64(0);
|
||||
dec.pos += 9;
|
||||
if (!Number.isSafeInteger(s)) {
|
||||
//console.warn("value is not a safe integer: ", s);
|
||||
}
|
||||
return parseInt(s);
|
||||
}
|
||||
function rdecode_true(dec) {
|
||||
dec.pos++;
|
||||
return true;
|
||||
}
|
||||
function rdecode_false(dec) {
|
||||
dec.pos++;
|
||||
return false;
|
||||
}
|
||||
function rdecode_none(dec) {
|
||||
dec.pos++;
|
||||
return null;
|
||||
}
|
||||
|
||||
const decode_func = new Map();
|
||||
for(let i=0; i<10; i++) {
|
||||
const charcode = i.toString().charCodeAt(0);
|
||||
decode_func[charcode] = rdecode_string;
|
||||
}
|
||||
|
||||
decode_func[RENCODE.CHR_LIST] = rdecode_list
|
||||
decode_func[RENCODE.CHR_DICT] = rdecode_dict
|
||||
decode_func[RENCODE.CHR_INT] = rdecode_int
|
||||
decode_func[RENCODE.CHR_INT1] = rdecode_intb
|
||||
decode_func[RENCODE.CHR_INT2] = rdecode_inth
|
||||
decode_func[RENCODE.CHR_INT4] = rdecode_intl
|
||||
decode_func[RENCODE.CHR_INT8] = rdecode_intq
|
||||
decode_func[RENCODE.CHR_TRUE] = rdecode_true
|
||||
decode_func[RENCODE.CHR_FALSE] = rdecode_false
|
||||
decode_func[RENCODE.CHR_NONE] = rdecode_none
|
||||
|
||||
|
||||
function make_fixed_length_string_decoder(len) {
|
||||
function fixed_length_string_decoder(dec) {
|
||||
dec.pos++;
|
||||
const u8a = dec.buf.subarray(dec.pos, dec.pos+len);
|
||||
dec.pos += len;
|
||||
return utf8ByteArrayToString(u8a);
|
||||
}
|
||||
return fixed_length_string_decoder;
|
||||
}
|
||||
for(let i=0; i<RENCODE.STR_FIXED_COUNT; i++) {
|
||||
decode_func[RENCODE.STR_FIXED_START + i] = make_fixed_length_string_decoder(i);
|
||||
}
|
||||
|
||||
function make_fixed_length_list_decoder(len) {
|
||||
function fixed_length_list_decoder(dec) {
|
||||
dec.pos++;
|
||||
let list = [];
|
||||
for (let i=0; i<len; i++) {
|
||||
list.push(_rdecode(dec));
|
||||
}
|
||||
return list
|
||||
}
|
||||
return fixed_length_list_decoder;
|
||||
}
|
||||
for(let i=0; i<RENCODE.LIST_FIXED_COUNT; i++) {
|
||||
decode_func[RENCODE.LIST_FIXED_START + i] = make_fixed_length_list_decoder(i);
|
||||
}
|
||||
|
||||
function make_fixed_length_dict_decoder(len) {
|
||||
function fixed_length_dict_decoder(dec) {
|
||||
dec.pos++;
|
||||
const dict = {};
|
||||
for(let i=0; i<len; i++) {
|
||||
const key = _rdecode(dec);
|
||||
const value = _rdecode(dec);
|
||||
dict[key] = value;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
return fixed_length_dict_decoder;
|
||||
}
|
||||
for(let i=0; i<RENCODE.DICT_FIXED_COUNT; i++) {
|
||||
decode_func[RENCODE.DICT_FIXED_START + i] = make_fixed_length_dict_decoder(i);
|
||||
}
|
||||
|
||||
function make_int_fixed_decoder(i) {
|
||||
function int_fixed_decoder(dec) {
|
||||
dec.pos++;
|
||||
return i;
|
||||
}
|
||||
return int_fixed_decoder;
|
||||
}
|
||||
for(let i=0; i<RENCODE.INT_POS_FIXED_COUNT; i++) {
|
||||
decode_func[RENCODE.INT_POS_FIXED_START + i] = make_int_fixed_decoder(i)
|
||||
}
|
||||
for(let i=0; i<RENCODE.INT_NEG_FIXED_COUNT; i++) {
|
||||
decode_func[RENCODE.INT_NEG_FIXED_START + i] = make_int_fixed_decoder(-1 - i)
|
||||
}
|
||||
|
||||
|
||||
class DecodeBuffer {
|
||||
constructor(u8a) {
|
||||
this.buf = u8a;
|
||||
this.pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function _rdecode(dec) {
|
||||
if (dec.pos>=dec.buf.length) {
|
||||
throw "reached end of buffer"
|
||||
}
|
||||
const typecode = dec.buf[dec.pos];
|
||||
const decode = decode_func[typecode];
|
||||
if (decode === null || decode === undefined) {
|
||||
//console.log("buffer pos:", dec.pos);
|
||||
//console.log("buffer:", dec.buf.subarray(dec.pos, dec.pos+20))
|
||||
//const str = String.fromCharCode.apply(null, dec.buf.subarray(dec.pos, dec.pos+20));
|
||||
throw "no decoder for typecode "+typecode+" at position "+dec.pos;
|
||||
}
|
||||
return decode(dec);
|
||||
}
|
||||
|
||||
function rdecode(buf) {
|
||||
const type = typeof buf;
|
||||
if (type === "string") {
|
||||
const u8a = new Uint8Array(buf.length);
|
||||
for(let i=0,j=buf.length;i<j;++i){
|
||||
u8a[i] = buf.charCodeAt(i);
|
||||
}
|
||||
return _rdecode(new DecodeBuffer(u8a));
|
||||
}
|
||||
if (type === 'object' && buf.constructor===Uint8Array) {
|
||||
return _rdecode(new DecodeBuffer(buf));
|
||||
}
|
||||
throw "cannot decode "+type;
|
||||
}
|
||||
|
||||
|
||||
function rencode_selftest() {
|
||||
function test_value(input, output) {
|
||||
const u8a_output = new Uint8Array(output);
|
||||
const enc = rencode(input);
|
||||
//console.log("test_value(", input, ", ", output, ") rencode("+input+")="+enc);
|
||||
if (enc.length != u8a_output.length) {
|
||||
throw "failed to encode '"+input+"', expected length "+u8a_output.length+" bytes but got "+enc.length;
|
||||
}
|
||||
for(let i=0,j=enc.length;i<j;++i){
|
||||
if (enc[i] != u8a_output[i]) {
|
||||
throw "failed to encode '"+input+"', expected '"+u8a_output+"' but got '"+enc+"', error at position "+i+": "+enc[i]+" vs "+u8a_output[i];
|
||||
}
|
||||
}
|
||||
const dec = rdecode(enc);
|
||||
if (dec != input) {
|
||||
throw "failed to decode '"+enc+"', expected '"+input+"' but got '"+dec+"'";
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
test_value(true, [67]);
|
||||
test_value(false, [68]);
|
||||
test_value(-10, [79]);
|
||||
test_value(-29, [98]);
|
||||
test_value(1, [1]);
|
||||
test_value(40, [40]);
|
||||
test_value('foobarbaz', [137, 102, 111, 111, 98, 97, 114, 98, 97, 122]);
|
||||
//we don't handle floats
|
||||
//test_value(1234.56, [66, 68, 154, 81, 236]);
|
||||
test_value(100, [62, 100]);
|
||||
test_value(-100, [62, 156]);
|
||||
test_value(7483648, [64, 0, 114, 49, 0]);
|
||||
test_value(-7483648, [64, 255, 141, 207, 0]);
|
||||
test_value(8223372036854775808, [65, 114, 31, 73, 76, 88, 156, 0, 0]);
|
||||
test_value(-8223372036854775808, [65, 141, 224, 182, 179, 167, 100, 0, 0]);
|
||||
test_value(27123, [63, 105, 243]);
|
||||
test_value(-27123, [63, 150, 13]);
|
||||
test_value('\x00', [129, 0]);
|
||||
test_value("fööbar", [136, 102, 195, 182, 195, 182, 98, 97, 114]);
|
||||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
// console.log("rencode failed its self test", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
8853
gns3server/static/web-ui/assets/xpra-html5/js/lib/simple-keyboard.js
Normal file
8853
gns3server/static/web-ui/assets/xpra-html5/js/lib/simple-keyboard.js
Normal file
File diff suppressed because it is too large
Load Diff
3106
gns3server/static/web-ui/assets/xpra-html5/js/lib/slick.js
Normal file
3106
gns3server/static/web-ui/assets/xpra-html5/js/lib/slick.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
77
tests/web/test_bundled_web_ui_assets.py
Normal file
77
tests/web/test_bundled_web_ui_assets.py
Normal file
@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2026 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
The bundled web UI must contain every file its consoles load. Anything built
|
||||
from a git checkout (GitHub archives, Docker images) ships only what is in git,
|
||||
and the server answers a missing asset with the web UI page, so a file left out
|
||||
of git breaks the console at runtime (a JavaScript module served as text/html).
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
WEB_UI_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "gns3server", "static", "web-ui")
|
||||
|
||||
# relative ES module imports and re-exports: import x from "./a.js", export * from "../b.js"
|
||||
MODULE_IMPORT = re.compile(r"""^\s*(?:import|export)\s+(?:[^'";]*?\s+from\s+)?["'](\.{1,2}/[^"']+)["']""", re.MULTILINE)
|
||||
SCRIPT_SRC = re.compile(r"""<script[^>]*\ssrc=["']([^"']+)["']""", re.IGNORECASE)
|
||||
|
||||
|
||||
def missing_module_imports(entry: str) -> list[str]:
|
||||
"""
|
||||
Walks the relative imports from an ES module and returns the imported files that do not exist.
|
||||
"""
|
||||
|
||||
missing, seen, pending = [], set(), [os.path.normpath(entry)]
|
||||
while pending:
|
||||
path = pending.pop()
|
||||
if path in seen:
|
||||
continue
|
||||
seen.add(path)
|
||||
if not os.path.isfile(path):
|
||||
missing.append(os.path.relpath(path, WEB_UI_DIR))
|
||||
continue
|
||||
with open(path, encoding="utf-8") as fd:
|
||||
source = fd.read()
|
||||
for target in MODULE_IMPORT.findall(source):
|
||||
pending.append(os.path.normpath(os.path.join(os.path.dirname(path), target)))
|
||||
return sorted(missing)
|
||||
|
||||
|
||||
def test_vnc_console_modules_are_bundled() -> None:
|
||||
|
||||
entry = os.path.join(WEB_UI_DIR, "assets", "vnc-console", "vnc-controller.js")
|
||||
assert os.path.isfile(entry)
|
||||
assert missing_module_imports(entry) == []
|
||||
|
||||
|
||||
def test_xpra_console_scripts_are_bundled() -> None:
|
||||
|
||||
xpra_dir = os.path.join(WEB_UI_DIR, "assets", "xpra-html5")
|
||||
pages = [name for name in os.listdir(xpra_dir) if name.endswith(".html")]
|
||||
assert pages
|
||||
missing = []
|
||||
for page in pages:
|
||||
with open(os.path.join(xpra_dir, page), encoding="utf-8") as fd:
|
||||
html = fd.read()
|
||||
for src in SCRIPT_SRC.findall(html):
|
||||
if re.match(r"^(?:[a-z]+:)?//", src):
|
||||
continue
|
||||
if not os.path.isfile(os.path.join(xpra_dir, src.split("?")[0])):
|
||||
missing.append(f"{page}: {src}")
|
||||
assert missing == []
|
||||
Loading…
x
Reference in New Issue
Block a user