mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-09 06:31:22 +00:00
Massive reorganization. Separate all objects into individual files. Remove duplicate namespace declarations.
This commit is contained in:
@@ -20,12 +20,6 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for all Guacamole JavaScript objects.
|
|
||||||
* @ignore
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Guacamole = Guacamole || {};
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
/**
|
/**
|
@@ -20,371 +20,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for all Guacamole JavaScript objects.
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Guacamole = Guacamole || {};
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple Guacamole protocol parser that invokes an oninstruction event when
|
|
||||||
* full instructions are available from data received via receive().
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
Guacamole.Parser = function() {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to this parser.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
var parser = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Current buffer of received data. This buffer grows until a full
|
|
||||||
* element is available. After a full element is available, that element
|
|
||||||
* is flushed into the element buffer.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
var buffer = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Buffer of all received, complete elements. After an entire instruction
|
|
||||||
* is read, this buffer is flushed, and a new instruction begins.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
var element_buffer = [];
|
|
||||||
|
|
||||||
// The location of the last element's terminator
|
|
||||||
var element_end = -1;
|
|
||||||
|
|
||||||
// Where to start the next length search or the next element
|
|
||||||
var start_index = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends the given instruction data packet to the internal buffer of
|
|
||||||
* this Guacamole.Parser, executing all completed instructions at
|
|
||||||
* the beginning of this buffer, if any.
|
|
||||||
*
|
|
||||||
* @param {String} packet The instruction data to receive.
|
|
||||||
*/
|
|
||||||
this.receive = function(packet) {
|
|
||||||
|
|
||||||
// Truncate buffer as necessary
|
|
||||||
if (start_index > 4096 && element_end >= start_index) {
|
|
||||||
|
|
||||||
buffer = buffer.substring(start_index);
|
|
||||||
|
|
||||||
// Reset parse relative to truncation
|
|
||||||
element_end -= start_index;
|
|
||||||
start_index = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append data to buffer
|
|
||||||
buffer += packet;
|
|
||||||
|
|
||||||
// While search is within currently received data
|
|
||||||
while (element_end < buffer.length) {
|
|
||||||
|
|
||||||
// If we are waiting for element data
|
|
||||||
if (element_end >= start_index) {
|
|
||||||
|
|
||||||
// We now have enough data for the element. Parse.
|
|
||||||
var element = buffer.substring(start_index, element_end);
|
|
||||||
var terminator = buffer.substring(element_end, element_end+1);
|
|
||||||
|
|
||||||
// Add element to array
|
|
||||||
element_buffer.push(element);
|
|
||||||
|
|
||||||
// If last element, handle instruction
|
|
||||||
if (terminator == ";") {
|
|
||||||
|
|
||||||
// Get opcode
|
|
||||||
var opcode = element_buffer.shift();
|
|
||||||
|
|
||||||
// Call instruction handler.
|
|
||||||
if (parser.oninstruction != null)
|
|
||||||
parser.oninstruction(opcode, element_buffer);
|
|
||||||
|
|
||||||
// Clear elements
|
|
||||||
element_buffer.length = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (terminator != ',')
|
|
||||||
throw new Error("Illegal terminator.");
|
|
||||||
|
|
||||||
// Start searching for length at character after
|
|
||||||
// element terminator
|
|
||||||
start_index = element_end + 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for end of length
|
|
||||||
var length_end = buffer.indexOf(".", start_index);
|
|
||||||
if (length_end != -1) {
|
|
||||||
|
|
||||||
// Parse length
|
|
||||||
var length = parseInt(buffer.substring(element_end+1, length_end));
|
|
||||||
if (length == NaN)
|
|
||||||
throw new Error("Non-numeric character in element length.");
|
|
||||||
|
|
||||||
// Calculate start of element
|
|
||||||
start_index = length_end + 1;
|
|
||||||
|
|
||||||
// Calculate location of element terminator
|
|
||||||
element_end = start_index + length;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no period yet, continue search when more data
|
|
||||||
// is received
|
|
||||||
else {
|
|
||||||
start_index = buffer.length;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end parse loop
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired once for every complete Guacamole instruction received, in order.
|
|
||||||
*
|
|
||||||
* @event
|
|
||||||
* @param {String} opcode The Guacamole instruction opcode.
|
|
||||||
* @param {Array} parameters The parameters provided for the instruction,
|
|
||||||
* if any.
|
|
||||||
*/
|
|
||||||
this.oninstruction = null;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An input stream abstraction used by the Guacamole client to facilitate
|
|
||||||
* transfer of files or other binary data.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @param {String} mimetype The mimetype of the data this stream will receive.
|
|
||||||
*/
|
|
||||||
Guacamole.InputStream = function(mimetype) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to this Guacamole.InputStream.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
var guac_stream = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The length of this Guacamole.InputStream in bytes.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
var length = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mimetype of the data contained within this blob.
|
|
||||||
*/
|
|
||||||
this.mimetype = mimetype;
|
|
||||||
|
|
||||||
// Get blob builder
|
|
||||||
var blob_builder;
|
|
||||||
if (window.BlobBuilder) blob_builder = new BlobBuilder();
|
|
||||||
else if (window.WebKitBlobBuilder) blob_builder = new WebKitBlobBuilder();
|
|
||||||
else if (window.MozBlobBuilder) blob_builder = new MozBlobBuilder();
|
|
||||||
else
|
|
||||||
blob_builder = new (function() {
|
|
||||||
|
|
||||||
var blobs = [];
|
|
||||||
|
|
||||||
/** @ignore */
|
|
||||||
this.append = function(data) {
|
|
||||||
blobs.push(new Blob([data], {"type": mimetype}));
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @ignore */
|
|
||||||
this.getBlob = function() {
|
|
||||||
return new Blob(blobs, {"type": mimetype});
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives the given ArrayBuffer, storing its data within this
|
|
||||||
* Guacamole.InputStream.
|
|
||||||
*
|
|
||||||
* @param {ArrayBuffer} buffer An ArrayBuffer containing the data to be
|
|
||||||
* received.
|
|
||||||
*/
|
|
||||||
this.receive = function(buffer) {
|
|
||||||
|
|
||||||
blob_builder.append(buffer);
|
|
||||||
length += buffer.byteLength;
|
|
||||||
|
|
||||||
// Call handler, if present
|
|
||||||
if (guac_stream.onreceive)
|
|
||||||
guac_stream.onreceive(buffer.byteLength);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes this Guacamole.InputStream such that no further data will be
|
|
||||||
* written.
|
|
||||||
*/
|
|
||||||
this.close = function() {
|
|
||||||
|
|
||||||
// Call handler, if present
|
|
||||||
if (guac_stream.onclose)
|
|
||||||
guac_stream.onclose();
|
|
||||||
|
|
||||||
// NOTE: Currently not enforced.
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current length of this Guacamole.InputStream, in bytes.
|
|
||||||
* @return {Number} The current length of this Guacamole.InputStream.
|
|
||||||
*/
|
|
||||||
this.getLength = function() {
|
|
||||||
return length;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the contents of this Guacamole.InputStream as a Blob.
|
|
||||||
* @return {Blob} The contents of this Guacamole.InputStream.
|
|
||||||
*/
|
|
||||||
this.getBlob = function() {
|
|
||||||
return blob_builder.getBlob();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired once for every blob of data received.
|
|
||||||
*
|
|
||||||
* @event
|
|
||||||
* @param {Number} length The number of bytes received.
|
|
||||||
*/
|
|
||||||
this.onreceive = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired once this stream is finished and no further data will be written.
|
|
||||||
* @event
|
|
||||||
*/
|
|
||||||
this.onclose = null;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Integer pool which returns consistently increasing integers while integers
|
|
||||||
* are in use, and previously-used integers when possible.
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
Guacamole.IntegerPool = function() {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to this integer pool.
|
|
||||||
*/
|
|
||||||
var guac_pool = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of available integers.
|
|
||||||
* @type Number[]
|
|
||||||
*/
|
|
||||||
var pool = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The next integer to return if no more integers remain.
|
|
||||||
* @type Number
|
|
||||||
*/
|
|
||||||
this.next_int = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next available integer in the pool. If possible, a previously
|
|
||||||
* used integer will be returned.
|
|
||||||
*
|
|
||||||
* @return {Number} The next available integer.
|
|
||||||
*/
|
|
||||||
this.next = function() {
|
|
||||||
|
|
||||||
// If free'd integers exist, return one of those
|
|
||||||
if (pool.length > 0)
|
|
||||||
return pool.shift();
|
|
||||||
|
|
||||||
// Otherwise, return a new integer
|
|
||||||
return guac_pool.next_int++;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees the given integer, allowing it to be reused.
|
|
||||||
*
|
|
||||||
* @param {Number} integer The integer to free.
|
|
||||||
*/
|
|
||||||
this.free = function(integer) {
|
|
||||||
pool.push(integer);
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract stream which can receive data.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @param {Guacamole.Client} client The client owning this stream.
|
|
||||||
* @param {Number} index The index of this stream.
|
|
||||||
*/
|
|
||||||
Guacamole.OutputStream = function(client, index) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to this stream.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
var guac_stream = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of this stream.
|
|
||||||
* @type Number
|
|
||||||
*/
|
|
||||||
this.index = index;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when the stream is being closed due to an error.
|
|
||||||
*
|
|
||||||
* @param {String} reason A human-readable reason describing the error.
|
|
||||||
* @param {Number} code The error code associated with the error.
|
|
||||||
*/
|
|
||||||
this.onerror = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired whenever an acknowledgement is received from the server, indicating
|
|
||||||
* that a stream operation has completed.
|
|
||||||
*
|
|
||||||
* @event
|
|
||||||
* @param {String} message A human-readable status message related to the
|
|
||||||
* operation performed.
|
|
||||||
* @param {Number} code The error code associated with the operation.
|
|
||||||
*/
|
|
||||||
this.onack = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the given base64-encoded data to this stream as a blob.
|
|
||||||
*
|
|
||||||
* @param {String} data The base64-encoded data to send.
|
|
||||||
*/
|
|
||||||
this.write = function(data) {
|
|
||||||
client.sendBlob(guac_stream.index, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes this stream.
|
|
||||||
*/
|
|
||||||
this.close = function() {
|
|
||||||
client.endStream(guac_stream.index);
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guacamole protocol client. Given a display element and {@link Guacamole.Tunnel},
|
* Guacamole protocol client. Given a display element and {@link Guacamole.Tunnel},
|
||||||
* automatically handles incoming and outgoing Guacamole instructions via the
|
* automatically handles incoming and outgoing Guacamole instructions via the
|
135
guacamole-common-js/src/main/resources/modules/InputStream.js
Normal file
135
guacamole-common-js/src/main/resources/modules/InputStream.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An input stream abstraction used by the Guacamole client to facilitate
|
||||||
|
* transfer of files or other binary data.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {String} mimetype The mimetype of the data this stream will receive.
|
||||||
|
*/
|
||||||
|
Guacamole.InputStream = function(mimetype) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to this Guacamole.InputStream.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var guac_stream = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of this Guacamole.InputStream in bytes.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var length = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mimetype of the data contained within this blob.
|
||||||
|
*/
|
||||||
|
this.mimetype = mimetype;
|
||||||
|
|
||||||
|
// Get blob builder
|
||||||
|
var blob_builder;
|
||||||
|
if (window.BlobBuilder) blob_builder = new BlobBuilder();
|
||||||
|
else if (window.WebKitBlobBuilder) blob_builder = new WebKitBlobBuilder();
|
||||||
|
else if (window.MozBlobBuilder) blob_builder = new MozBlobBuilder();
|
||||||
|
else
|
||||||
|
blob_builder = new (function() {
|
||||||
|
|
||||||
|
var blobs = [];
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
this.append = function(data) {
|
||||||
|
blobs.push(new Blob([data], {"type": mimetype}));
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
this.getBlob = function() {
|
||||||
|
return new Blob(blobs, {"type": mimetype});
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives the given ArrayBuffer, storing its data within this
|
||||||
|
* Guacamole.InputStream.
|
||||||
|
*
|
||||||
|
* @param {ArrayBuffer} buffer An ArrayBuffer containing the data to be
|
||||||
|
* received.
|
||||||
|
*/
|
||||||
|
this.receive = function(buffer) {
|
||||||
|
|
||||||
|
blob_builder.append(buffer);
|
||||||
|
length += buffer.byteLength;
|
||||||
|
|
||||||
|
// Call handler, if present
|
||||||
|
if (guac_stream.onreceive)
|
||||||
|
guac_stream.onreceive(buffer.byteLength);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this Guacamole.InputStream such that no further data will be
|
||||||
|
* written.
|
||||||
|
*/
|
||||||
|
this.close = function() {
|
||||||
|
|
||||||
|
// Call handler, if present
|
||||||
|
if (guac_stream.onclose)
|
||||||
|
guac_stream.onclose();
|
||||||
|
|
||||||
|
// NOTE: Currently not enforced.
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current length of this Guacamole.InputStream, in bytes.
|
||||||
|
* @return {Number} The current length of this Guacamole.InputStream.
|
||||||
|
*/
|
||||||
|
this.getLength = function() {
|
||||||
|
return length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents of this Guacamole.InputStream as a Blob.
|
||||||
|
* @return {Blob} The contents of this Guacamole.InputStream.
|
||||||
|
*/
|
||||||
|
this.getBlob = function() {
|
||||||
|
return blob_builder.getBlob();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired once for every blob of data received.
|
||||||
|
*
|
||||||
|
* @event
|
||||||
|
* @param {Number} length The number of bytes received.
|
||||||
|
*/
|
||||||
|
this.onreceive = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired once this stream is finished and no further data will be written.
|
||||||
|
* @event
|
||||||
|
*/
|
||||||
|
this.onclose = null;
|
||||||
|
|
||||||
|
};
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integer pool which returns consistently increasing integers while integers
|
||||||
|
* are in use, and previously-used integers when possible.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
Guacamole.IntegerPool = function() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to this integer pool.
|
||||||
|
*/
|
||||||
|
var guac_pool = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of available integers.
|
||||||
|
* @type Number[]
|
||||||
|
*/
|
||||||
|
var pool = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next integer to return if no more integers remain.
|
||||||
|
* @type Number
|
||||||
|
*/
|
||||||
|
this.next_int = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next available integer in the pool. If possible, a previously
|
||||||
|
* used integer will be returned.
|
||||||
|
*
|
||||||
|
* @return {Number} The next available integer.
|
||||||
|
*/
|
||||||
|
this.next = function() {
|
||||||
|
|
||||||
|
// If free'd integers exist, return one of those
|
||||||
|
if (pool.length > 0)
|
||||||
|
return pool.shift();
|
||||||
|
|
||||||
|
// Otherwise, return a new integer
|
||||||
|
return guac_pool.next_int++;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the given integer, allowing it to be reused.
|
||||||
|
*
|
||||||
|
* @param {Number} integer The integer to free.
|
||||||
|
*/
|
||||||
|
this.free = function(integer) {
|
||||||
|
pool.push(integer);
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
@@ -20,12 +20,6 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for all Guacamole JavaScript objects.
|
|
||||||
* @ignore
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Guacamole = Guacamole || {};
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
/**
|
/**
|
@@ -20,12 +20,6 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for all Guacamole JavaScript objects.
|
|
||||||
* @ignore
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Guacamole = Guacamole || {};
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
/**
|
/**
|
@@ -20,12 +20,6 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for all Guacamole JavaScript objects.
|
|
||||||
* @ignore
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Guacamole = Guacamole || {};
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -311,6 +305,113 @@ Guacamole.Mouse = function(element) {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple container for properties describing the state of a mouse.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {Number} x The X position of the mouse pointer in pixels.
|
||||||
|
* @param {Number} y The Y position of the mouse pointer in pixels.
|
||||||
|
* @param {Boolean} left Whether the left mouse button is pressed.
|
||||||
|
* @param {Boolean} middle Whether the middle mouse button is pressed.
|
||||||
|
* @param {Boolean} right Whether the right mouse button is pressed.
|
||||||
|
* @param {Boolean} up Whether the up mouse button is pressed (the fourth
|
||||||
|
* button, usually part of a scroll wheel).
|
||||||
|
* @param {Boolean} down Whether the down mouse button is pressed (the fifth
|
||||||
|
* button, usually part of a scroll wheel).
|
||||||
|
*/
|
||||||
|
Guacamole.Mouse.State = function(x, y, left, middle, right, up, down) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to this Guacamole.Mouse.State.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var guac_state = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current X position of the mouse pointer.
|
||||||
|
* @type Number
|
||||||
|
*/
|
||||||
|
this.x = x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current Y position of the mouse pointer.
|
||||||
|
* @type Number
|
||||||
|
*/
|
||||||
|
this.y = y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the left mouse button is currently pressed.
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
this.left = left;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the middle mouse button is currently pressed.
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
this.middle = middle
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the right mouse button is currently pressed.
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
this.right = right;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the up mouse button is currently pressed. This is the fourth
|
||||||
|
* mouse button, associated with upward scrolling of the mouse scroll
|
||||||
|
* wheel.
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
this.up = up;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the down mouse button is currently pressed. This is the fifth
|
||||||
|
* mouse button, associated with downward scrolling of the mouse scroll
|
||||||
|
* wheel.
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
this.down = down;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the position represented within this state object by the given
|
||||||
|
* element and clientX/clientY coordinates (commonly available within event
|
||||||
|
* objects). Position is translated from clientX/clientY (relative to
|
||||||
|
* viewport) to element-relative coordinates.
|
||||||
|
*
|
||||||
|
* @param {Element} element The element the coordinates should be relative
|
||||||
|
* to.
|
||||||
|
* @param {Number} clientX The X coordinate to translate, viewport-relative.
|
||||||
|
* @param {Number} clientY The Y coordinate to translate, viewport-relative.
|
||||||
|
*/
|
||||||
|
this.fromClientPosition = function(element, clientX, clientY) {
|
||||||
|
|
||||||
|
guac_state.x = clientX - element.offsetLeft;
|
||||||
|
guac_state.y = clientY - element.offsetTop;
|
||||||
|
|
||||||
|
// This is all JUST so we can get the mouse position within the element
|
||||||
|
var parent = element.offsetParent;
|
||||||
|
while (parent && !(parent === document.body)) {
|
||||||
|
guac_state.x -= parent.offsetLeft - parent.scrollLeft;
|
||||||
|
guac_state.y -= parent.offsetTop - parent.scrollTop;
|
||||||
|
|
||||||
|
parent = parent.offsetParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Element ultimately depends on positioning within document body,
|
||||||
|
// take document scroll into account.
|
||||||
|
if (parent) {
|
||||||
|
var documentScrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
|
||||||
|
var documentScrollTop = document.body.scrollTop || document.documentElement.scrollTop;
|
||||||
|
|
||||||
|
guac_state.x -= parent.offsetLeft - documentScrollLeft;
|
||||||
|
guac_state.y -= parent.offsetTop - documentScrollTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides cross-browser relative touch event translation for a given element.
|
* Provides cross-browser relative touch event translation for a given element.
|
||||||
*
|
*
|
||||||
@@ -712,110 +813,3 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple container for properties describing the state of a mouse.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @param {Number} x The X position of the mouse pointer in pixels.
|
|
||||||
* @param {Number} y The Y position of the mouse pointer in pixels.
|
|
||||||
* @param {Boolean} left Whether the left mouse button is pressed.
|
|
||||||
* @param {Boolean} middle Whether the middle mouse button is pressed.
|
|
||||||
* @param {Boolean} right Whether the right mouse button is pressed.
|
|
||||||
* @param {Boolean} up Whether the up mouse button is pressed (the fourth
|
|
||||||
* button, usually part of a scroll wheel).
|
|
||||||
* @param {Boolean} down Whether the down mouse button is pressed (the fifth
|
|
||||||
* button, usually part of a scroll wheel).
|
|
||||||
*/
|
|
||||||
Guacamole.Mouse.State = function(x, y, left, middle, right, up, down) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to this Guacamole.Mouse.State.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
var guac_state = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current X position of the mouse pointer.
|
|
||||||
* @type Number
|
|
||||||
*/
|
|
||||||
this.x = x;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current Y position of the mouse pointer.
|
|
||||||
* @type Number
|
|
||||||
*/
|
|
||||||
this.y = y;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the left mouse button is currently pressed.
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
this.left = left;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the middle mouse button is currently pressed.
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
this.middle = middle
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the right mouse button is currently pressed.
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
this.right = right;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the up mouse button is currently pressed. This is the fourth
|
|
||||||
* mouse button, associated with upward scrolling of the mouse scroll
|
|
||||||
* wheel.
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
this.up = up;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the down mouse button is currently pressed. This is the fifth
|
|
||||||
* mouse button, associated with downward scrolling of the mouse scroll
|
|
||||||
* wheel.
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
this.down = down;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the position represented within this state object by the given
|
|
||||||
* element and clientX/clientY coordinates (commonly available within event
|
|
||||||
* objects). Position is translated from clientX/clientY (relative to
|
|
||||||
* viewport) to element-relative coordinates.
|
|
||||||
*
|
|
||||||
* @param {Element} element The element the coordinates should be relative
|
|
||||||
* to.
|
|
||||||
* @param {Number} clientX The X coordinate to translate, viewport-relative.
|
|
||||||
* @param {Number} clientY The Y coordinate to translate, viewport-relative.
|
|
||||||
*/
|
|
||||||
this.fromClientPosition = function(element, clientX, clientY) {
|
|
||||||
|
|
||||||
guac_state.x = clientX - element.offsetLeft;
|
|
||||||
guac_state.y = clientY - element.offsetTop;
|
|
||||||
|
|
||||||
// This is all JUST so we can get the mouse position within the element
|
|
||||||
var parent = element.offsetParent;
|
|
||||||
while (parent && !(parent === document.body)) {
|
|
||||||
guac_state.x -= parent.offsetLeft - parent.scrollLeft;
|
|
||||||
guac_state.y -= parent.offsetTop - parent.scrollTop;
|
|
||||||
|
|
||||||
parent = parent.offsetParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Element ultimately depends on positioning within document body,
|
|
||||||
// take document scroll into account.
|
|
||||||
if (parent) {
|
|
||||||
var documentScrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
|
|
||||||
var documentScrollTop = document.body.scrollTop || document.documentElement.scrollTop;
|
|
||||||
|
|
||||||
guac_state.x -= parent.offsetLeft - documentScrollLeft;
|
|
||||||
guac_state.y -= parent.offsetTop - documentScrollTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@@ -20,12 +20,6 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for all Guacamole JavaScript objects.
|
|
||||||
* @ignore
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Guacamole = Guacamole || {};
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
/**
|
/**
|
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract stream which can receive data.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {Guacamole.Client} client The client owning this stream.
|
||||||
|
* @param {Number} index The index of this stream.
|
||||||
|
*/
|
||||||
|
Guacamole.OutputStream = function(client, index) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to this stream.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var guac_stream = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of this stream.
|
||||||
|
* @type Number
|
||||||
|
*/
|
||||||
|
this.index = index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when the stream is being closed due to an error.
|
||||||
|
*
|
||||||
|
* @param {String} reason A human-readable reason describing the error.
|
||||||
|
* @param {Number} code The error code associated with the error.
|
||||||
|
*/
|
||||||
|
this.onerror = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired whenever an acknowledgement is received from the server, indicating
|
||||||
|
* that a stream operation has completed.
|
||||||
|
*
|
||||||
|
* @event
|
||||||
|
* @param {String} message A human-readable status message related to the
|
||||||
|
* operation performed.
|
||||||
|
* @param {Number} code The error code associated with the operation.
|
||||||
|
*/
|
||||||
|
this.onack = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the given base64-encoded data to this stream as a blob.
|
||||||
|
*
|
||||||
|
* @param {String} data The base64-encoded data to send.
|
||||||
|
*/
|
||||||
|
this.write = function(data) {
|
||||||
|
client.sendBlob(guac_stream.index, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this stream.
|
||||||
|
*/
|
||||||
|
this.close = function() {
|
||||||
|
client.endStream(guac_stream.index);
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
159
guacamole-common-js/src/main/resources/modules/Parser.js
Normal file
159
guacamole-common-js/src/main/resources/modules/Parser.js
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple Guacamole protocol parser that invokes an oninstruction event when
|
||||||
|
* full instructions are available from data received via receive().
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
Guacamole.Parser = function() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to this parser.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var parser = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current buffer of received data. This buffer grows until a full
|
||||||
|
* element is available. After a full element is available, that element
|
||||||
|
* is flushed into the element buffer.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var buffer = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer of all received, complete elements. After an entire instruction
|
||||||
|
* is read, this buffer is flushed, and a new instruction begins.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var element_buffer = [];
|
||||||
|
|
||||||
|
// The location of the last element's terminator
|
||||||
|
var element_end = -1;
|
||||||
|
|
||||||
|
// Where to start the next length search or the next element
|
||||||
|
var start_index = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the given instruction data packet to the internal buffer of
|
||||||
|
* this Guacamole.Parser, executing all completed instructions at
|
||||||
|
* the beginning of this buffer, if any.
|
||||||
|
*
|
||||||
|
* @param {String} packet The instruction data to receive.
|
||||||
|
*/
|
||||||
|
this.receive = function(packet) {
|
||||||
|
|
||||||
|
// Truncate buffer as necessary
|
||||||
|
if (start_index > 4096 && element_end >= start_index) {
|
||||||
|
|
||||||
|
buffer = buffer.substring(start_index);
|
||||||
|
|
||||||
|
// Reset parse relative to truncation
|
||||||
|
element_end -= start_index;
|
||||||
|
start_index = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append data to buffer
|
||||||
|
buffer += packet;
|
||||||
|
|
||||||
|
// While search is within currently received data
|
||||||
|
while (element_end < buffer.length) {
|
||||||
|
|
||||||
|
// If we are waiting for element data
|
||||||
|
if (element_end >= start_index) {
|
||||||
|
|
||||||
|
// We now have enough data for the element. Parse.
|
||||||
|
var element = buffer.substring(start_index, element_end);
|
||||||
|
var terminator = buffer.substring(element_end, element_end+1);
|
||||||
|
|
||||||
|
// Add element to array
|
||||||
|
element_buffer.push(element);
|
||||||
|
|
||||||
|
// If last element, handle instruction
|
||||||
|
if (terminator == ";") {
|
||||||
|
|
||||||
|
// Get opcode
|
||||||
|
var opcode = element_buffer.shift();
|
||||||
|
|
||||||
|
// Call instruction handler.
|
||||||
|
if (parser.oninstruction != null)
|
||||||
|
parser.oninstruction(opcode, element_buffer);
|
||||||
|
|
||||||
|
// Clear elements
|
||||||
|
element_buffer.length = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (terminator != ',')
|
||||||
|
throw new Error("Illegal terminator.");
|
||||||
|
|
||||||
|
// Start searching for length at character after
|
||||||
|
// element terminator
|
||||||
|
start_index = element_end + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for end of length
|
||||||
|
var length_end = buffer.indexOf(".", start_index);
|
||||||
|
if (length_end != -1) {
|
||||||
|
|
||||||
|
// Parse length
|
||||||
|
var length = parseInt(buffer.substring(element_end+1, length_end));
|
||||||
|
if (length == NaN)
|
||||||
|
throw new Error("Non-numeric character in element length.");
|
||||||
|
|
||||||
|
// Calculate start of element
|
||||||
|
start_index = length_end + 1;
|
||||||
|
|
||||||
|
// Calculate location of element terminator
|
||||||
|
element_end = start_index + length;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no period yet, continue search when more data
|
||||||
|
// is received
|
||||||
|
else {
|
||||||
|
start_index = buffer.length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end parse loop
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired once for every complete Guacamole instruction received, in order.
|
||||||
|
*
|
||||||
|
* @event
|
||||||
|
* @param {String} opcode The Guacamole instruction opcode.
|
||||||
|
* @param {Array} parameters The parameters provided for the instruction,
|
||||||
|
* if any.
|
||||||
|
*/
|
||||||
|
this.oninstruction = null;
|
||||||
|
|
||||||
|
};
|
@@ -20,12 +20,6 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for all Guacamole JavaScript objects.
|
|
||||||
* @ignore
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Guacamole = Guacamole || {};
|
var Guacamole = Guacamole || {};
|
||||||
|
|
||||||
/**
|
/**
|
@@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* Namespace for all Guacamole JavaScript objects.
|
|
||||||
* @ignore
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Guacamole = Guacamole || {};
|
|
Reference in New Issue
Block a user