var BABYLON; (function (BABYLON) { // Screenshots var screenshotCanvas; var cloneValue = function (source, destinationObject) { if (!source) return null; if (source instanceof BABYLON.Mesh) { return null; } if (source instanceof BABYLON.SubMesh) { return source.clone(destinationObject); } else if (source.clone) { return source.clone(); } return null; }; var Tools = (function () { function Tools() { } Tools.GetConstructorName = function (obj) { var str = (obj.prototype ? obj.prototype.constructor : obj.constructor).toString(); var cname = str.match(/function\s(\w*)/)[1]; var aliases = ["", "anonymous", "Anonymous"]; return aliases.indexOf(cname) > -1 ? "Function" : cname; }; Tools.ToHex = function (i) { var str = i.toString(16); if (i <= 15) { return ("0" + str).toUpperCase(); } return str.toUpperCase(); }; Tools.SetImmediate = function (action) { if (window.setImmediate) { window.setImmediate(action); } else { setTimeout(action, 1); } }; Tools.IsExponentOfTwo = function (value) { var count = 1; do { count *= 2; } while (count < value); return count === value; }; Tools.GetExponentOfTwo = function (value, max) { var count = 1; do { count *= 2; } while (count < value); if (count > max) count = max; return count; }; Tools.GetFilename = function (path) { var index = path.lastIndexOf("/"); if (index < 0) return path; return path.substring(index + 1); }; Tools.GetDOMTextContent = function (element) { var result = ""; var child = element.firstChild; while (child) { if (child.nodeType === 3) { result += child.textContent; } child = child.nextSibling; } return result; }; Tools.ToDegrees = function (angle) { return angle * 180 / Math.PI; }; Tools.ToRadians = function (angle) { return angle * Math.PI / 180; }; Tools.EncodeArrayBufferTobase64 = function (buffer) { var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var output = ""; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0; var bytes = new Uint8Array(buffer); while (i < bytes.length) { chr1 = bytes[i++]; chr2 = i < bytes.length ? bytes[i++] : Number.NaN; // Not sure if the index chr3 = i < bytes.length ? bytes[i++] : Number.NaN; // checks are needed here enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output += keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); } return "data:image/png;base64," + output; }; Tools.ExtractMinAndMaxIndexed = function (positions, indices, indexStart, indexCount) { var minimum = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); var maximum = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); for (var index = indexStart; index < indexStart + indexCount; index++) { var current = new BABYLON.Vector3(positions[indices[index] * 3], positions[indices[index] * 3 + 1], positions[indices[index] * 3 + 2]); minimum = BABYLON.Vector3.Minimize(current, minimum); maximum = BABYLON.Vector3.Maximize(current, maximum); } return { minimum: minimum, maximum: maximum }; }; Tools.ExtractMinAndMax = function (positions, start, count) { var minimum = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); var maximum = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); for (var index = start; index < start + count; index++) { var current = new BABYLON.Vector3(positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2]); minimum = BABYLON.Vector3.Minimize(current, minimum); maximum = BABYLON.Vector3.Maximize(current, maximum); } return { minimum: minimum, maximum: maximum }; }; Tools.MakeArray = function (obj, allowsNullUndefined) { if (allowsNullUndefined !== true && (obj === undefined || obj == null)) return undefined; return Array.isArray(obj) ? obj : [obj]; }; // Misc. Tools.GetPointerPrefix = function () { var eventPrefix = "pointer"; // Check if hand.js is referenced or if the browser natively supports pointer events if (!navigator.pointerEnabled) { eventPrefix = "mouse"; } return eventPrefix; }; Tools.QueueNewFrame = function (func) { if (window.requestAnimationFrame) window.requestAnimationFrame(func); else if (window.msRequestAnimationFrame) window.msRequestAnimationFrame(func); else if (window.webkitRequestAnimationFrame) window.webkitRequestAnimationFrame(func); else if (window.mozRequestAnimationFrame) window.mozRequestAnimationFrame(func); else if (window.oRequestAnimationFrame) window.oRequestAnimationFrame(func); else { window.setTimeout(func, 16); } }; Tools.RequestFullscreen = function (element) { if (element.requestFullscreen) element.requestFullscreen(); else if (element.msRequestFullscreen) element.msRequestFullscreen(); else if (element.webkitRequestFullscreen) element.webkitRequestFullscreen(); else if (element.mozRequestFullScreen) element.mozRequestFullScreen(); }; Tools.ExitFullscreen = function () { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitCancelFullScreen) { document.webkitCancelFullScreen(); } else if (document.msCancelFullScreen) { document.msCancelFullScreen(); } }; // External files Tools.CleanUrl = function (url) { url = url.replace(/#/mg, "%23"); return url; }; Tools.LoadImage = function (url, onload, onerror, database) { if (url instanceof ArrayBuffer) { url = Tools.EncodeArrayBufferTobase64(url); } url = Tools.CleanUrl(url); var img = new Image(); if (url.substr(0, 5) !== "data:") { if (Tools.CorsBehavior) { switch (typeof (Tools.CorsBehavior)) { case "function": var result = Tools.CorsBehavior(url); if (result) { img.crossOrigin = result; } break; case "string": default: img.crossOrigin = Tools.CorsBehavior; break; } } } img.onload = function () { onload(img); }; img.onerror = function (err) { Tools.Error("Error while trying to load texture: " + url); img.src = "data:image/jpg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QBmRXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAAExAAIAAAAQAAAATgAAAAAAAABgAAAAAQAAAGAAAAABcGFpbnQubmV0IDQuMC41AP/bAEMABAIDAwMCBAMDAwQEBAQFCQYFBQUFCwgIBgkNCw0NDQsMDA4QFBEODxMPDAwSGBITFRYXFxcOERkbGRYaFBYXFv/bAEMBBAQEBQUFCgYGChYPDA8WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFv/AABEIAQABAAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APH6KKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FCiiigD6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++gooooA+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gUKKKKAPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76CiiigD5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BQooooA+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/voKKKKAPl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FCiiigD6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++gooooA+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gUKKKKAPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76CiiigD5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BQooooA+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/voKKKKAPl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FCiiigD6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++gooooA+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gUKKKKAPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76Pl+iiivuj+BT6gooor4U/vo+X6KKK+6P4FPqCiiivhT++j5fooor7o/gU+oKKKK+FP76P//Z"; onload(img); }; var noIndexedDB = function () { img.src = url; }; var loadFromIndexedDB = function () { database.loadImageFromDB(url, img); }; //ANY database to do! if (database && database.enableTexturesOffline && BABYLON.Database.IsUASupportingBlobStorage) { database.openAsync(loadFromIndexedDB, noIndexedDB); } else { if (url.indexOf("file:") === -1) { noIndexedDB(); } else { try { var textureName = url.substring(5); var blobURL; try { blobURL = URL.createObjectURL(BABYLON.FilesInput.FilesTextures[textureName], { oneTimeOnly: true }); } catch (ex) { // Chrome doesn't support oneTimeOnly parameter blobURL = URL.createObjectURL(BABYLON.FilesInput.FilesTextures[textureName]); } img.src = blobURL; } catch (e) { img.src = null; } } } return img; }; //ANY Tools.LoadFile = function (url, callback, progressCallBack, database, useArrayBuffer, onError) { url = Tools.CleanUrl(url); var noIndexedDB = function () { var request = new XMLHttpRequest(); var loadUrl = Tools.BaseUrl + url; request.open('GET', loadUrl, true); if (useArrayBuffer) { request.responseType = "arraybuffer"; } request.onprogress = progressCallBack; request.onreadystatechange = function () { if (request.readyState === 4) { if (request.status === 200 || Tools.ValidateXHRData(request, !useArrayBuffer ? 1 : 6)) { callback(!useArrayBuffer ? request.responseText : request.response); } else { if (onError) { onError(); } else { throw new Error("Error status: " + request.status + " - Unable to load " + loadUrl); } } } }; request.send(null); }; var loadFromIndexedDB = function () { database.loadFileFromDB(url, callback, progressCallBack, noIndexedDB, useArrayBuffer); }; if (url.indexOf("file:") !== -1) { var fileName = url.substring(5); Tools.ReadFile(BABYLON.FilesInput.FilesToLoad[fileName], callback, progressCallBack, true); } else { // Caching all files if (database && database.enableSceneOffline) { database.openAsync(loadFromIndexedDB, noIndexedDB); } else { noIndexedDB(); } } }; Tools.ReadFileAsDataURL = function (fileToLoad, callback, progressCallback) { var reader = new FileReader(); reader.onload = function (e) { //target doesn't have result from ts 1.3 callback(e.target['result']); }; reader.onprogress = progressCallback; reader.readAsDataURL(fileToLoad); }; Tools.ReadFile = function (fileToLoad, callback, progressCallBack, useArrayBuffer) { var reader = new FileReader(); reader.onerror = function (e) { Tools.Log("Error while reading file: " + fileToLoad.name); callback(JSON.stringify({ autoClear: true, clearColor: [1, 0, 0], ambientColor: [0, 0, 0], gravity: [0, -9.807, 0], meshes: [], cameras: [], lights: [] })); }; reader.onload = function (e) { //target doesn't have result from ts 1.3 callback(e.target['result']); }; reader.onprogress = progressCallBack; if (!useArrayBuffer) { // Asynchronous read reader.readAsText(fileToLoad); } else { reader.readAsArrayBuffer(fileToLoad); } }; //returns a downloadable url to a file content. Tools.FileAsURL = function (content) { var fileBlob = new Blob([content]); var url = window.URL || window.webkitURL; var link = url.createObjectURL(fileBlob); return link; }; // Misc. Tools.Clamp = function (value, min, max) { if (min === void 0) { min = 0; } if (max === void 0) { max = 1; } return Math.min(max, Math.max(min, value)); }; // Returns -1 when value is a negative number and // +1 when value is a positive number. Tools.Sign = function (value) { value = +value; // convert to a number if (value === 0 || isNaN(value)) return value; return value > 0 ? 1 : -1; }; Tools.Format = function (value, decimals) { if (decimals === void 0) { decimals = 2; } return value.toFixed(decimals); }; Tools.CheckExtends = function (v, min, max) { if (v.x < min.x) min.x = v.x; if (v.y < min.y) min.y = v.y; if (v.z < min.z) min.z = v.z; if (v.x > max.x) max.x = v.x; if (v.y > max.y) max.y = v.y; if (v.z > max.z) max.z = v.z; }; Tools.WithinEpsilon = function (a, b, epsilon) { if (epsilon === void 0) { epsilon = 1.401298E-45; } var num = a - b; return -epsilon <= num && num <= epsilon; }; Tools.DeepCopy = function (source, destination, doNotCopyList, mustCopyList) { for (var prop in source) { if (prop[0] === "_" && (!mustCopyList || mustCopyList.indexOf(prop) === -1)) { continue; } if (doNotCopyList && doNotCopyList.indexOf(prop) !== -1) { continue; } var sourceValue = source[prop]; var typeOfSourceValue = typeof sourceValue; if (typeOfSourceValue === "function") { continue; } if (typeOfSourceValue === "object") { if (sourceValue instanceof Array) { destination[prop] = []; if (sourceValue.length > 0) { if (typeof sourceValue[0] == "object") { for (var index = 0; index < sourceValue.length; index++) { var clonedValue = cloneValue(sourceValue[index], destination); if (destination[prop].indexOf(clonedValue) === -1) { destination[prop].push(clonedValue); } } } else { destination[prop] = sourceValue.slice(0); } } } else { destination[prop] = cloneValue(sourceValue, destination); } } else { destination[prop] = sourceValue; } } }; Tools.IsEmpty = function (obj) { for (var i in obj) { return false; } return true; }; Tools.RegisterTopRootEvents = function (events) { for (var index = 0; index < events.length; index++) { var event = events[index]; window.addEventListener(event.name, event.handler, false); try { if (window.parent) { window.parent.addEventListener(event.name, event.handler, false); } } catch (e) { } } }; Tools.UnregisterTopRootEvents = function (events) { for (var index = 0; index < events.length; index++) { var event = events[index]; window.removeEventListener(event.name, event.handler); try { if (window.parent) { window.parent.removeEventListener(event.name, event.handler); } } catch (e) { } } }; Tools.DumpFramebuffer = function (width, height, engine, successCallback) { // Read the contents of the framebuffer var numberOfChannelsByLine = width * 4; var halfHeight = height / 2; //Reading datas from WebGL var data = engine.readPixels(0, 0, width, height); //To flip image on Y axis. for (var i = 0; i < halfHeight; i++) { for (var j = 0; j < numberOfChannelsByLine; j++) { var currentCell = j + i * numberOfChannelsByLine; var targetLine = height - i - 1; var targetCell = j + targetLine * numberOfChannelsByLine; var temp = data[currentCell]; data[currentCell] = data[targetCell]; data[targetCell] = temp; } } // Create a 2D canvas to store the result if (!screenshotCanvas) { screenshotCanvas = document.createElement('canvas'); } screenshotCanvas.width = width; screenshotCanvas.height = height; var context = screenshotCanvas.getContext('2d'); // Copy the pixels to a 2D canvas var imageData = context.createImageData(width, height); //cast is due to ts error in lib.d.ts, see here - https://github.com/Microsoft/TypeScript/issues/949 var castData = imageData.data; castData.set(data); context.putImageData(imageData, 0, 0); var base64Image = screenshotCanvas.toDataURL(); if (successCallback) { successCallback(base64Image); } else { //Creating a link if the browser have the download attribute on the a tag, to automatically start download generated image. if (("download" in document.createElement("a"))) { var a = window.document.createElement("a"); a.href = base64Image; var date = new Date(); var stringDate = date.getFullYear() + "-" + date.getMonth() + "-" + date.getDate() + "_" + date.getHours() + "-" + ('0' + date.getMinutes()).slice(-2); a.setAttribute("download", "screenshot_" + stringDate + ".png"); window.document.body.appendChild(a); a.addEventListener("click", function () { a.parentElement.removeChild(a); }); a.click(); } else { var newWindow = window.open(""); var img = newWindow.document.createElement("img"); img.src = base64Image; newWindow.document.body.appendChild(img); } } }; Tools.CreateScreenshot = function (engine, camera, size, successCallback) { var width; var height; //If a precision value is specified if (size.precision) { width = Math.round(engine.getRenderWidth() * size.precision); height = Math.round(width / engine.getAspectRatio(camera)); size = { width: width, height: height }; } else if (size.width && size.height) { width = size.width; height = size.height; } else if (size.width && !size.height) { width = size.width; height = Math.round(width / engine.getAspectRatio(camera)); size = { width: width, height: height }; } else if (size.height && !size.width) { height = size.height; width = Math.round(height * engine.getAspectRatio(camera)); size = { width: width, height: height }; } else if (!isNaN(size)) { height = size; width = size; } else { Tools.Error("Invalid 'size' parameter !"); return; } var scene = camera.getScene(); var previousCamera = null; if (scene.activeCamera !== camera) { previousCamera = scene.activeCamera; scene.activeCamera = camera; } //At this point size can be a number, or an object (according to engine.prototype.createRenderTargetTexture method) var texture = new BABYLON.RenderTargetTexture("screenShot", size, scene, false, false); texture.renderList = scene.meshes; texture.onAfterRender = function () { Tools.DumpFramebuffer(width, height, engine, successCallback); }; scene.incrementRenderId(); texture.render(true); texture.dispose(); if (previousCamera) { scene.activeCamera = previousCamera; } }; // XHR response validator for local file scenario Tools.ValidateXHRData = function (xhr, dataType) { // 1 for text (.babylon, manifest and shaders), 2 for TGA, 4 for DDS, 7 for all if (dataType === void 0) { dataType = 7; } try { if (dataType & 1) { if (xhr.responseText && xhr.responseText.length > 0) { return true; } else if (dataType === 1) { return false; } } if (dataType & 2) { // Check header width and height since there is no "TGA" magic number var tgaHeader = BABYLON.Internals.TGATools.GetTGAHeader(xhr.response); if (tgaHeader.width && tgaHeader.height && tgaHeader.width > 0 && tgaHeader.height > 0) { return true; } else if (dataType === 2) { return false; } } if (dataType & 4) { // Check for the "DDS" magic number var ddsHeader = new Uint8Array(xhr.response, 0, 3); if (ddsHeader[0] === 68 && ddsHeader[1] === 68 && ddsHeader[2] === 83) { return true; } else { return false; } } } catch (e) { } return false; }; Object.defineProperty(Tools, "NoneLogLevel", { get: function () { return Tools._NoneLogLevel; }, enumerable: true, configurable: true }); Object.defineProperty(Tools, "MessageLogLevel", { get: function () { return Tools._MessageLogLevel; }, enumerable: true, configurable: true }); Object.defineProperty(Tools, "WarningLogLevel", { get: function () { return Tools._WarningLogLevel; }, enumerable: true, configurable: true }); Object.defineProperty(Tools, "ErrorLogLevel", { get: function () { return Tools._ErrorLogLevel; }, enumerable: true, configurable: true }); Object.defineProperty(Tools, "AllLogLevel", { get: function () { return Tools._MessageLogLevel | Tools._WarningLogLevel | Tools._ErrorLogLevel; }, enumerable: true, configurable: true }); Tools._AddLogEntry = function (entry) { Tools._LogCache = entry + Tools._LogCache; if (Tools.OnNewCacheEntry) { Tools.OnNewCacheEntry(entry); } }; Tools._FormatMessage = function (message) { var padStr = function (i) { return (i < 10) ? "0" + i : "" + i; }; var date = new Date(); return "[" + padStr(date.getHours()) + ":" + padStr(date.getMinutes()) + ":" + padStr(date.getSeconds()) + "]: " + message; }; Tools._LogDisabled = function (message) { // nothing to do }; Tools._LogEnabled = function (message) { var formattedMessage = Tools._FormatMessage(message); console.log("BJS - " + formattedMessage); var entry = "