{"version":3,"sources":["webpack://crmWeb/../code-generation/platform/dependencies/node_modules/qz-tray/qz-tray.js"],"names":[],"mappings":"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","file":"nm.qz-tray.dcafb659ab15312eb8d1.js","sourcesContent":["'use strict';\n\n/**\n * @version 2.2.3\n * @overview QZ Tray Connector\n *

\n * Connects a web client to the QZ Tray software.\n * Enables printing and device communication from javascript.\n */\nvar qz = (function() {\n\n///// POLYFILLS /////\n\n if (!Array.isArray) {\n Array.isArray = function(arg) {\n return Object.prototype.toString.call(arg) === '[object Array]';\n };\n }\n\n if (!Number.isInteger) {\n Number.isInteger = function(value) {\n return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;\n };\n }\n\n///// PRIVATE METHODS /////\n\n var _qz = {\n VERSION: \"2.2.3\", //must match @version above\n DEBUG: false,\n\n log: {\n /** Debugging messages */\n trace: function() { if (_qz.DEBUG) { console.log.apply(console, arguments); } },\n /** General messages */\n info: function() { console.info.apply(console, arguments); },\n /** General warnings */\n warn: function() { console.warn.apply(console, arguments); },\n /** Debugging errors */\n allay: function() { if (_qz.DEBUG) { console.warn.apply(console, arguments); } },\n /** General errors */\n error: function() { console.error.apply(console, arguments); }\n },\n\n\n //stream types\n streams: {\n serial: 'SERIAL', usb: 'USB', hid: 'HID', printer: 'PRINTER', file: 'FILE', socket: 'SOCKET'\n },\n\n\n websocket: {\n /** The actual websocket object managing the connection. */\n connection: null,\n /** Track if a connection attempt is being cancelled. */\n shutdown: false,\n\n /** Default parameters used on new connections. Override values using options parameter on {@link qz.websocket.connect}. */\n connectConfig: {\n host: [\"localhost\", \"localhost.qz.io\"], //hosts QZ Tray can be running on\n hostIndex: 0, //internal var - index on host array\n usingSecure: true, //boolean use of secure protocol\n protocol: {\n secure: \"wss://\", //secure websocket\n insecure: \"ws://\" //insecure websocket\n },\n port: {\n secure: [8181, 8282, 8383, 8484], //list of secure ports QZ Tray could be listening on\n insecure: [8182, 8283, 8384, 8485], //list of insecure ports QZ Tray could be listening on\n portIndex: 0 //internal var - index on active port array\n },\n keepAlive: 60, //time between pings to keep connection alive, in seconds\n retries: 0, //number of times to reconnect before failing\n delay: 0 //seconds before firing a connection\n },\n\n setup: {\n /** Loop through possible ports to open connection, sets web socket calls that will settle the promise. */\n findConnection: function(config, resolve, reject) {\n if (_qz.websocket.shutdown) {\n reject(new Error(\"Connection attempt cancelled by user\"));\n return;\n }\n\n //force flag if missing ports\n if (!config.port.secure.length) {\n if (!config.port.insecure.length) {\n reject(new Error(\"No ports have been specified to connect over\"));\n return;\n } else if (config.usingSecure) {\n _qz.log.error(\"No secure ports specified - forcing insecure connection\");\n config.usingSecure = false;\n }\n } else if (!config.port.insecure.length && !config.usingSecure) {\n _qz.log.trace(\"No insecure ports specified - forcing secure connection\");\n config.usingSecure = true;\n }\n\n var deeper = function() {\n if (_qz.websocket.shutdown) {\n //connection attempt was cancelled, bail out\n reject(new Error(\"Connection attempt cancelled by user\"));\n return;\n }\n\n config.port.portIndex++;\n\n if ((config.usingSecure && config.port.portIndex >= config.port.secure.length)\n || (!config.usingSecure && config.port.portIndex >= config.port.insecure.length)) {\n if (config.hostIndex >= config.host.length - 1) {\n //give up, all hope is lost\n reject(new Error(\"Unable to establish connection with QZ\"));\n return;\n } else {\n config.hostIndex++;\n config.port.portIndex = 0;\n }\n }\n\n // recursive call until connection established or all ports are exhausted\n _qz.websocket.setup.findConnection(config, resolve, reject);\n };\n\n var address;\n if (config.usingSecure) {\n address = config.protocol.secure + config.host[config.hostIndex] + \":\" + config.port.secure[config.port.portIndex];\n } else {\n address = config.protocol.insecure + config.host[config.hostIndex] + \":\" + config.port.insecure[config.port.portIndex];\n }\n\n try {\n _qz.log.trace(\"Attempting connection\", address);\n _qz.websocket.connection = new _qz.tools.ws(address);\n }\n catch(err) {\n _qz.log.error(err);\n deeper();\n return;\n }\n\n if (_qz.websocket.connection != null) {\n _qz.websocket.connection.established = false;\n\n //called on successful connection to qz, begins setup of websocket calls and resolves connect promise after certificate is sent\n _qz.websocket.connection.onopen = function(evt) {\n if (!_qz.websocket.connection.established) {\n _qz.log.trace(evt);\n _qz.log.info(\"Established connection with QZ Tray on \" + address);\n\n _qz.websocket.setup.openConnection({ resolve: resolve, reject: reject });\n\n if (config.keepAlive > 0) {\n var interval = setInterval(function() {\n if (!_qz.tools.isActive() || _qz.websocket.connection.interval !== interval) {\n clearInterval(interval);\n return;\n }\n\n _qz.websocket.connection.send(\"ping\");\n }, config.keepAlive * 1000);\n\n _qz.websocket.connection.interval = interval;\n }\n }\n };\n\n //called during websocket close during setup\n _qz.websocket.connection.onclose = function() {\n // Safari compatibility fix to raise error event\n if (_qz.websocket.connection && typeof navigator !== 'undefined' && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {\n _qz.websocket.connection.onerror();\n }\n };\n\n //called for errors during setup (such as invalid ports), reject connect promise only if all ports have been tried\n _qz.websocket.connection.onerror = function(evt) {\n _qz.log.trace(evt);\n\n _qz.websocket.connection = null;\n\n deeper();\n };\n } else {\n reject(new Error(\"Unable to create a websocket connection\"));\n }\n },\n\n /** Finish setting calls on successful connection, sets web socket calls that won't settle the promise. */\n openConnection: function(openPromise) {\n _qz.websocket.connection.established = true;\n\n //called when an open connection is closed\n _qz.websocket.connection.onclose = function(evt) {\n _qz.log.trace(evt);\n\n _qz.websocket.connection = null;\n _qz.websocket.callClose(evt);\n _qz.log.info(\"Closed connection with QZ Tray\");\n\n for(var uid in _qz.websocket.pendingCalls) {\n if (_qz.websocket.pendingCalls.hasOwnProperty(uid)) {\n _qz.websocket.pendingCalls[uid].reject(new Error(\"Connection closed before response received\"));\n }\n }\n\n //if this is set, then an explicit close call was made\n if (this.promise != undefined) {\n this.promise.resolve();\n }\n };\n\n //called for any errors with an open connection\n _qz.websocket.connection.onerror = function(evt) {\n _qz.websocket.callError(evt);\n };\n\n //send JSON objects to qz\n _qz.websocket.connection.sendData = function(obj) {\n _qz.log.trace(\"Preparing object for websocket\", obj);\n\n if (obj.timestamp == undefined) {\n obj.timestamp = Date.now();\n if (typeof obj.timestamp !== 'number') {\n obj.timestamp = new Date().getTime();\n }\n }\n if (obj.promise != undefined) {\n obj.uid = _qz.websocket.setup.newUID();\n _qz.websocket.pendingCalls[obj.uid] = obj.promise;\n }\n\n // track requesting monitor\n obj.position = {\n x: typeof screen !== 'undefined' ? ((screen.availWidth || screen.width) / 2) + (screen.left || screen.availLeft || 0) : 0,\n y: typeof screen !== 'undefined' ? ((screen.availHeight || screen.height) / 2) + (screen.top || screen.availTop || 0) : 0\n };\n\n try {\n if (obj.call != undefined && obj.signature == undefined && _qz.security.needsSigned(obj.call)) {\n var signObj = {\n call: obj.call,\n params: obj.params,\n timestamp: obj.timestamp\n };\n\n //make a hashing promise if not already one\n var hashing = _qz.tools.hash(_qz.tools.stringify(signObj));\n if (!hashing.then) {\n hashing = _qz.tools.promise(function(resolve) {\n resolve(hashing);\n });\n }\n\n hashing.then(function(hashed) {\n return _qz.security.callSign(hashed);\n }).then(function(signature) {\n _qz.log.trace(\"Signature for call\", signature);\n obj.signature = signature || \"\";\n obj.signAlgorithm = _qz.security.signAlgorithm;\n\n _qz.signContent = undefined;\n _qz.websocket.connection.send(_qz.tools.stringify(obj));\n });\n } else {\n _qz.log.trace(\"Signature for call\", obj.signature);\n\n //called for pre-signed content and (unsigned) setup calls\n _qz.websocket.connection.send(_qz.tools.stringify(obj));\n }\n }\n catch(err) {\n _qz.log.error(err);\n\n if (obj.promise != undefined) {\n obj.promise.reject(err);\n delete _qz.websocket.pendingCalls[obj.uid];\n }\n }\n };\n\n //receive message from qz\n _qz.websocket.connection.onmessage = function(evt) {\n var returned = JSON.parse(evt.data);\n\n if (returned.uid == null) {\n if (returned.type == null) {\n //incorrect response format, likely connected to incompatible qz version\n _qz.websocket.connection.close(4003, \"Connected to incompatible QZ Tray version\");\n\n } else {\n //streams (callbacks only, no promises)\n switch(returned.type) {\n case _qz.streams.serial:\n if (!returned.event) {\n returned.event = JSON.stringify({ portName: returned.key, output: returned.data });\n }\n\n _qz.serial.callSerial(JSON.parse(returned.event));\n break;\n case _qz.streams.socket:\n _qz.socket.callSocket(JSON.parse(returned.event));\n break;\n case _qz.streams.usb:\n if (!returned.event) {\n returned.event = JSON.stringify({ vendorId: returned.key[0], productId: returned.key[1], output: returned.data });\n }\n\n _qz.usb.callUsb(JSON.parse(returned.event));\n break;\n case _qz.streams.hid:\n _qz.hid.callHid(JSON.parse(returned.event));\n break;\n case _qz.streams.printer:\n _qz.printers.callPrinter(JSON.parse(returned.event));\n break;\n case _qz.streams.file:\n _qz.file.callFile(JSON.parse(returned.event));\n break;\n default:\n _qz.log.allay(\"Cannot determine stream type for callback\", returned);\n break;\n }\n }\n\n return;\n }\n\n _qz.log.trace(\"Received response from websocket\", returned);\n\n var promise = _qz.websocket.pendingCalls[returned.uid];\n if (promise == undefined) {\n _qz.log.allay('No promise found for returned response');\n } else {\n if (returned.error != undefined) {\n promise.reject(new Error(returned.error));\n } else {\n promise.resolve(returned.result);\n }\n }\n\n delete _qz.websocket.pendingCalls[returned.uid];\n };\n\n\n //send up the certificate before making any calls\n //also gives the user a chance to deny the connection\n function sendCert(cert) {\n if (cert === undefined) { cert = null; }\n\n //websocket setup, query what version is connected\n qz.api.getVersion().then(function(version) {\n _qz.websocket.connection.version = version;\n _qz.websocket.connection.semver = version.toLowerCase().replace(/-rc\\./g, \"-rc\").split(/[\\\\+\\\\.-]/g);\n for(var i = 0; i < _qz.websocket.connection.semver.length; i++) {\n try {\n if (i == 3 && _qz.websocket.connection.semver[i].toLowerCase().indexOf(\"rc\") == 0) {\n // Handle \"rc1\" pre-release by negating build info\n _qz.websocket.connection.semver[i] = -(_qz.websocket.connection.semver[i].replace(/\\D/g, \"\"));\n continue;\n }\n _qz.websocket.connection.semver[i] = parseInt(_qz.websocket.connection.semver[i]);\n }\n catch(ignore) {}\n\n if (_qz.websocket.connection.semver.length < 4) {\n _qz.websocket.connection.semver[3] = 0;\n }\n }\n\n //algorithm can be declared before a connection, check for incompatibilities now that we have one\n _qz.compatible.algorithm(true);\n }).then(function() {\n _qz.websocket.connection.sendData({ certificate: cert, promise: openPromise });\n });\n }\n\n _qz.security.callCert().then(sendCert).catch(function(error) {\n _qz.log.warn(\"Failed to get certificate:\", error);\n\n if (_qz.security.rejectOnCertFailure) {\n openPromise.reject(error);\n } else {\n sendCert(null);\n }\n });\n },\n\n /** Generate unique ID used to map a response to a call. */\n newUID: function() {\n var len = 6;\n return (new Array(len + 1).join(\"0\") + (Math.random() * Math.pow(36, len) << 0).toString(36)).slice(-len)\n }\n },\n\n dataPromise: function(callName, params, signature, signingTimestamp) {\n return _qz.tools.promise(function(resolve, reject) {\n var msg = {\n call: callName,\n promise: { resolve: resolve, reject: reject },\n params: params,\n signature: signature,\n timestamp: signingTimestamp\n };\n\n _qz.websocket.connection.sendData(msg);\n });\n },\n\n /** Library of promises awaiting a response, uid -> promise */\n pendingCalls: {},\n\n /** List of functions to call on error from the websocket. */\n errorCallbacks: [],\n /** Calls all functions registered to listen for errors. */\n callError: function(evt) {\n if (Array.isArray(_qz.websocket.errorCallbacks)) {\n for(var i = 0; i < _qz.websocket.errorCallbacks.length; i++) {\n _qz.websocket.errorCallbacks[i](evt);\n }\n } else {\n _qz.websocket.errorCallbacks(evt);\n }\n },\n\n /** List of function to call on closing from the websocket. */\n closedCallbacks: [],\n /** Calls all functions registered to listen for closing. */\n callClose: function(evt) {\n if (Array.isArray(_qz.websocket.closedCallbacks)) {\n for(var i = 0; i < _qz.websocket.closedCallbacks.length; i++) {\n _qz.websocket.closedCallbacks[i](evt);\n }\n } else {\n _qz.websocket.closedCallbacks(evt);\n }\n }\n },\n\n\n printing: {\n /** Default options used for new printer configs. Can be overridden using {@link qz.configs.setDefaults}. */\n defaultConfig: {\n //value purposes are explained in the qz.configs.setDefaults docs\n\n bounds: null,\n colorType: 'color',\n copies: 1,\n density: 0,\n duplex: false,\n fallbackDensity: null,\n interpolation: 'bicubic',\n jobName: null,\n legacy: false,\n margins: 0,\n orientation: null,\n paperThickness: null,\n printerTray: null,\n rasterize: false,\n rotation: 0,\n scaleContent: true,\n size: null,\n units: 'in',\n\n forceRaw: false,\n encoding: null,\n spool: null\n }\n },\n\n\n serial: {\n /** List of functions called when receiving data from serial connection. */\n serialCallbacks: [],\n /** Calls all functions registered to listen for serial events. */\n callSerial: function(streamEvent) {\n if (Array.isArray(_qz.serial.serialCallbacks)) {\n for(var i = 0; i < _qz.serial.serialCallbacks.length; i++) {\n _qz.serial.serialCallbacks[i](streamEvent);\n }\n } else {\n _qz.serial.serialCallbacks(streamEvent);\n }\n }\n },\n\n\n socket: {\n /** List of functions called when receiving data from network socket connection. */\n socketCallbacks: [],\n /** Calls all functions registered to listen for network socket events. */\n callSocket: function(socketEvent) {\n if (Array.isArray(_qz.socket.socketCallbacks)) {\n for(var i = 0; i < _qz.socket.socketCallbacks.length; i++) {\n _qz.socket.socketCallbacks[i](socketEvent);\n }\n } else {\n _qz.socket.socketCallbacks(socketEvent);\n }\n }\n },\n\n\n usb: {\n /** List of functions called when receiving data from usb connection. */\n usbCallbacks: [],\n /** Calls all functions registered to listen for usb events. */\n callUsb: function(streamEvent) {\n if (Array.isArray(_qz.usb.usbCallbacks)) {\n for(var i = 0; i < _qz.usb.usbCallbacks.length; i++) {\n _qz.usb.usbCallbacks[i](streamEvent);\n }\n } else {\n _qz.usb.usbCallbacks(streamEvent);\n }\n }\n },\n\n\n hid: {\n /** List of functions called when receiving data from hid connection. */\n hidCallbacks: [],\n /** Calls all functions registered to listen for hid events. */\n callHid: function(streamEvent) {\n if (Array.isArray(_qz.hid.hidCallbacks)) {\n for(var i = 0; i < _qz.hid.hidCallbacks.length; i++) {\n _qz.hid.hidCallbacks[i](streamEvent);\n }\n } else {\n _qz.hid.hidCallbacks(streamEvent);\n }\n }\n },\n\n\n printers: {\n /** List of functions called when receiving data from printer connection. */\n printerCallbacks: [],\n /** Calls all functions registered to listen for printer events. */\n callPrinter: function(streamEvent) {\n if (Array.isArray(_qz.printers.printerCallbacks)) {\n for(var i = 0; i < _qz.printers.printerCallbacks.length; i++) {\n _qz.printers.printerCallbacks[i](streamEvent);\n }\n } else {\n _qz.printers.printerCallbacks(streamEvent);\n }\n }\n },\n\n\n file: {\n /** List of functions called when receiving info regarding file changes. */\n fileCallbacks: [],\n /** Calls all functions registered to listen for file events. */\n callFile: function(streamEvent) {\n if (Array.isArray(_qz.file.fileCallbacks)) {\n for(var i = 0; i < _qz.file.fileCallbacks.length; i++) {\n _qz.file.fileCallbacks[i](streamEvent);\n }\n } else {\n _qz.file.fileCallbacks(streamEvent);\n }\n }\n },\n\n\n security: {\n /** Function used to resolve promise when acquiring site's public certificate. */\n certHandler: function(resolve, reject) { reject(); },\n /** Called to create new promise (using {@link _qz.security.certHandler}) for certificate retrieval. */\n callCert: function() {\n if (typeof _qz.security.certHandler.then === 'function') {\n //already a promise\n return _qz.security.certHandler;\n } else if (_qz.security.certHandler.constructor.name === \"AsyncFunction\") {\n //already callable as a promise\n return _qz.security.certHandler();\n } else {\n //turn into a promise\n return _qz.tools.promise(_qz.security.certHandler);\n }\n },\n\n /** Function used to create promise resolver when requiring signed calls. */\n signatureFactory: function() { return function(resolve) { resolve(); } },\n /** Called to create new promise (using {@link _qz.security.signatureFactory}) for signed calls. */\n callSign: function(toSign) {\n if (_qz.security.signatureFactory.constructor.name === \"AsyncFunction\") {\n //use directly\n return _qz.security.signatureFactory(toSign);\n } else {\n //use in a promise\n return _qz.tools.promise(_qz.security.signatureFactory(toSign));\n }\n },\n\n /** Signing algorithm used on signatures */\n signAlgorithm: \"SHA1\",\n\n rejectOnCertFailure: false,\n\n needsSigned: function(callName) {\n const undialoged = [\n \"printers.getStatus\",\n \"printers.stopListening\",\n \"usb.isClaimed\",\n \"usb.closeStream\",\n \"usb.releaseDevice\",\n \"hid.stopListening\",\n \"hid.isClaimed\",\n \"hid.closeStream\",\n \"hid.releaseDevice\",\n \"file.stopListening\",\n \"getVersion\"\n ];\n\n return callName != null && undialoged.indexOf(callName) === -1;\n }\n },\n\n\n tools: {\n /** Create a new promise */\n promise: function(resolver) {\n //prefer global object for historical purposes\n if (typeof RSVP !== 'undefined') {\n return new RSVP.Promise(resolver);\n } else if (typeof Promise !== 'undefined') {\n return new Promise(resolver);\n } else {\n _qz.log.error(\"Promise/A+ support is required. See qz.api.setPromiseType(...)\");\n }\n },\n\n /** Stub for rejecting with an Error from withing a Promise */\n reject: function(error) {\n return _qz.tools.promise(function(resolve, reject) {\n reject(error);\n });\n },\n\n stringify: function(object) {\n //old versions of prototype affect stringify\n var pjson = Array.prototype.toJSON;\n delete Array.prototype.toJSON;\n\n function skipKeys(key, value) {\n if (key === \"promise\") {\n return undefined;\n }\n\n return value;\n }\n\n var result = JSON.stringify(object, skipKeys);\n\n if (pjson) {\n Array.prototype.toJSON = pjson;\n }\n\n return result;\n },\n\n hash: function(data) {\n //prefer global object for historical purposes\n if (typeof Sha256 !== 'undefined') {\n return Sha256.hash(data);\n } else {\n return _qz.SHA.hash(data);\n }\n },\n\n ws: typeof WebSocket !== 'undefined' ? WebSocket : null,\n\n absolute: function(loc) {\n if (typeof window !== 'undefined' && typeof document.createElement === 'function') {\n var a = document.createElement(\"a\");\n a.href = loc;\n return a.href;\n } else if (typeof exports === 'object') {\n //node.js\n require('path').resolve(loc);\n }\n return loc;\n },\n\n relative: function(data) {\n for(var i = 0; i < data.length; i++) {\n if (data[i].constructor === Object) {\n var absolute = false;\n\n if (data[i].data && data[i].data.search && data[i].data.search(/data:image\\/\\w+;base64,/) === 0) {\n //upgrade from old base64 behavior\n data[i].flavor = \"base64\";\n data[i].data = data[i].data.replace(/^data:image\\/\\w+;base64,/, \"\");\n } else if (data[i].flavor) {\n //if flavor is known, we can directly check for absolute flavor types\n if ([\"FILE\", \"XML\"].indexOf(data[i].flavor.toUpperCase()) > -1) {\n absolute = true;\n }\n } else if (data[i].format && [\"HTML\", \"IMAGE\", \"PDF\", \"FILE\", \"XML\"].indexOf(data[i].format.toUpperCase()) > -1) {\n //if flavor is not known, all valid pixel formats default to file flavor\n //previous v2.0 data also used format as what is now flavor, so we check for those values here too\n absolute = true;\n } else if (data[i].type && (([\"PIXEL\", \"IMAGE\", \"PDF\"].indexOf(data[i].type.toUpperCase()) > -1 && !data[i].format)\n || ([\"HTML\", \"PDF\"].indexOf(data[i].type.toUpperCase()) > -1 && (!data[i].format || data[i].format.toUpperCase() === \"FILE\")))) {\n //if all we know is pixel type, then it is image's file flavor\n //previous v2.0 data also used type as what is now format, so we check for those value here too\n absolute = true;\n }\n\n if (absolute) {\n //change relative links to absolute\n data[i].data = _qz.tools.absolute(data[i].data);\n }\n if (data[i].options && typeof data[i].options.overlay === 'string') {\n data[i].options.overlay = _qz.tools.absolute(data[i].options.overlay);\n }\n }\n }\n },\n\n /** Performs deep copy to target from remaining params */\n extend: function(target) {\n //special case when reassigning properties as objects in a deep copy\n if (typeof target !== 'object') {\n target = {};\n }\n\n for(var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n if (!source) { continue; }\n\n for(var key in source) {\n if (source.hasOwnProperty(key)) {\n if (target === source[key]) { continue; }\n\n if (source[key] && source[key].constructor && source[key].constructor === Object) {\n var clone;\n if (Array.isArray(source[key])) {\n clone = target[key] || [];\n } else {\n clone = target[key] || {};\n }\n\n target[key] = _qz.tools.extend(clone, source[key]);\n } else if (source[key] !== undefined) {\n target[key] = source[key];\n }\n }\n }\n }\n\n return target;\n },\n\n versionCompare: function(major, minor, patch, build) {\n if (_qz.tools.assertActive()) {\n var semver = _qz.websocket.connection.semver;\n if (semver[0] != major) {\n return semver[0] - major;\n }\n if (minor != undefined && semver[1] != minor) {\n return semver[1] - minor;\n }\n if (patch != undefined && semver[2] != patch) {\n return semver[2] - patch;\n }\n if (build != undefined && semver.length > 3 && semver[3] != build) {\n return Number.isInteger(semver[3]) && Number.isInteger(build) ? semver[3] - build : semver[3].toString().localeCompare(build.toString());\n }\n return 0;\n }\n },\n\n isVersion: function(major, minor, patch, build) {\n return _qz.tools.versionCompare(major, minor, patch, build) == 0;\n },\n\n isActive: function() {\n return !_qz.websocket.shutdown && _qz.websocket.connection != null\n && (_qz.websocket.connection.readyState === _qz.tools.ws.OPEN\n || _qz.websocket.connection.readyState === _qz.tools.ws.CONNECTING);\n },\n\n assertActive: function() {\n if (_qz.tools.isActive()) {\n return true;\n }\n // Promise won't reject on throw; yet better than 'undefined'\n throw new Error(\"A connection to QZ has not been established yet\");\n },\n\n uint8ArrayToHex: function(uint8) {\n return Array.from(uint8)\n .map(function(i) { return i.toString(16).padStart(2, '0'); })\n .join('');\n },\n\n uint8ArrayToBase64: function(uint8) {\n /**\n * Adapted from Egor Nepomnyaschih's code under MIT Licence (C) 2020\n * see https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727\n */\n var map = [\n \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\",\n \"V\", \"W\", \"X\", \"Y\", \"Z\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\",\n \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"+\", \"/\"\n ];\n\n var result = '', i, l = uint8.length;\n for (i = 2; i < l; i += 3) {\n result += map[uint8[i - 2] >> 2];\n result += map[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];\n result += map[((uint8[i - 1] & 0x0F) << 2) | (uint8[i] >> 6)];\n result += map[uint8[i] & 0x3F];\n }\n if (i === l + 1) { // 1 octet yet to write\n result += map[uint8[i - 2] >> 2];\n result += map[(uint8[i - 2] & 0x03) << 4];\n result += \"==\";\n }\n if (i === l) { // 2 octets yet to write\n result += map[uint8[i - 2] >> 2];\n result += map[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];\n result += map[(uint8[i - 1] & 0x0F) << 2];\n result += \"=\";\n }\n return result;\n },\n },\n\n compatible: {\n /** Converts message format to a previous version's */\n data: function(printData) {\n // special handling for Uint8Array\n for(var i = 0; i < printData.length; i++) {\n if (printData[i].constructor === Object && printData[i].data instanceof Uint8Array) {\n if (printData[i].flavor) {\n var flavor = printData[i].flavor.toString().toUpperCase();\n switch(flavor) {\n case 'BASE64':\n printData[i].data = _qz.tools.uint8ArrayToBase64(printData[i].data);\n break;\n case 'HEX':\n printData[i].data = _qz.tools.uint8ArrayToHex(printData[i].data);\n break;\n default:\n throw new Error(\"Uint8Array conversion to '\" + flavor + \"' is not supported.\");\n }\n }\n }\n }\n\n if (_qz.tools.isVersion(2, 0)) {\n /*\n 2.0.x conversion\n -----\n type=pixel -> use format as 2.0 type (unless 'command' format, which forces 2.0 'raw' type)\n type=raw -> 2.0 type has to be 'raw'\n if format is 'image' -> force 2.0 'image' format, ignore everything else (unsupported in 2.0)\n\n flavor translates straight to 2.0 format (unless forced to 'raw'/'image')\n */\n _qz.log.trace(\"Converting print data to v2.0 for \" + _qz.websocket.connection.version);\n for(var i = 0; i < printData.length; i++) {\n if (printData[i].constructor === Object) {\n if (printData[i].type && printData[i].type.toUpperCase() === \"RAW\" && printData[i].format && printData[i].format.toUpperCase() === \"IMAGE\") {\n if (printData[i].flavor && printData[i].flavor.toUpperCase() === \"BASE64\") {\n //special case for raw base64 images\n printData[i].data = \"data:image/compat;base64,\" + printData[i].data;\n }\n printData[i].flavor = \"IMAGE\"; //forces 'image' format when shifting for conversion\n }\n if ((printData[i].type && printData[i].type.toUpperCase() === \"RAW\") || (printData[i].format && printData[i].format.toUpperCase() === \"COMMAND\")) {\n printData[i].format = \"RAW\"; //forces 'raw' type when shifting for conversion\n }\n\n printData[i].type = printData[i].format;\n printData[i].format = printData[i].flavor;\n delete printData[i].flavor;\n }\n }\n }\n },\n\n /* Converts config defaults to match previous version */\n config: function(config, dirty) {\n if (_qz.tools.isVersion(2, 0)) {\n if (!dirty.rasterize) {\n config.rasterize = true;\n }\n }\n if(_qz.tools.versionCompare(2, 2) < 0) {\n if(config.forceRaw !== 'undefined') {\n config.altPrinting = config.forceRaw;\n delete config.forceRaw;\n }\n }\n if(_qz.tools.versionCompare(2, 1, 2, 11) < 0) {\n if(config.spool) {\n if(config.spool.size) {\n config.perSpool = config.spool.size;\n delete config.spool.size;\n }\n if(config.spool.end) {\n config.endOfDoc = config.spool.end;\n delete config.spool.end;\n }\n delete config.spool;\n }\n }\n return config;\n },\n\n /** Compat wrapper with previous version **/\n networking: function(hostname, port, signature, signingTimestamp, mappingCallback) {\n // Use 2.0\n if (_qz.tools.isVersion(2, 0)) {\n return _qz.tools.promise(function(resolve, reject) {\n _qz.websocket.dataPromise('websocket.getNetworkInfo', {\n hostname: hostname,\n port: port\n }, signature, signingTimestamp).then(function(data) {\n if (typeof mappingCallback !== 'undefined') {\n resolve(mappingCallback(data));\n } else {\n resolve(data);\n }\n }, reject);\n });\n }\n // Wrap 2.1\n return _qz.tools.promise(function(resolve, reject) {\n _qz.websocket.dataPromise('networking.device', {\n hostname: hostname,\n port: port\n }, signature, signingTimestamp).then(function(data) {\n resolve({ ipAddress: data.ip, macAddress: data.mac });\n }, reject);\n });\n },\n\n /** Check if QZ version supports chosen algorithm */\n algorithm: function(quiet) {\n //if not connected yet we will assume compatibility exists for the time being\n if (_qz.tools.isActive()) {\n if (_qz.tools.isVersion(2, 0)) {\n if (!quiet) {\n _qz.log.warn(\"Connected to an older version of QZ, alternate signature algorithms are not supported\");\n }\n return false;\n }\n }\n\n return true;\n }\n },\n\n /**\n * Adapted from Chris Veness's code under MIT Licence (C) 2002\n * see http://www.movable-type.co.uk/scripts/sha256.html\n */\n SHA: {\n //@formatter:off - keep this block compact\n hash: function(msg) {\n // add trailing '1' bit (+ 0's padding) to string [§5.1.1]\n msg = _qz.SHA._utf8Encode(msg) + String.fromCharCode(0x80);\n\n // constants [§4.2.2]\n var K = [\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n ];\n // initial hash value [§5.3.1]\n var H = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ];\n\n // convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]\n var l = msg.length / 4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length\n var N = Math.ceil(l / 16); // number of 16-integer-blocks required to hold 'l' ints\n var M = new Array(N);\n\n for(var i = 0; i < N; i++) {\n M[i] = new Array(16);\n for(var j = 0; j < 16; j++) { // encode 4 chars per integer, big-endian encoding\n M[i][j] = (msg.charCodeAt(i * 64 + j * 4) << 24) | (msg.charCodeAt(i * 64 + j * 4 + 1) << 16) |\n (msg.charCodeAt(i * 64 + j * 4 + 2) << 8) | (msg.charCodeAt(i * 64 + j * 4 + 3));\n } // note running off the end of msg is ok 'cos bitwise ops on NaN return 0\n }\n // add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]\n // note: most significant word would be (len-1)*8 >>> 32, but since JS converts\n // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators\n M[N-1][14] = ((msg.length - 1) * 8) / Math.pow(2, 32);\n M[N-1][14] = Math.floor(M[N-1][14]);\n M[N-1][15] = ((msg.length - 1) * 8) & 0xffffffff;\n\n // HASH COMPUTATION [§6.1.2]\n var W = new Array(64); var a, b, c, d, e, f, g, h;\n for(var i = 0; i < N; i++) {\n // 1 - prepare message schedule 'W'\n for(var t = 0; t < 16; t++) { W[t] = M[i][t]; }\n for(var t = 16; t < 64; t++) { W[t] = (_qz.SHA._dev1(W[t-2]) + W[t-7] + _qz.SHA._dev0(W[t-15]) + W[t-16]) & 0xffffffff; }\n // 2 - initialise working variables a, b, c, d, e, f, g, h with previous hash value\n a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; f = H[5]; g = H[6]; h = H[7];\n // 3 - main loop (note 'addition modulo 2^32')\n for(var t = 0; t < 64; t++) {\n var T1 = h + _qz.SHA._sig1(e) + _qz.SHA._ch(e, f, g) + K[t] + W[t];\n var T2 = _qz.SHA._sig0(a) + _qz.SHA._maj(a, b, c);\n h = g; g = f; f = e; e = (d + T1) & 0xffffffff;\n d = c; c = b; b = a; a = (T1 + T2) & 0xffffffff;\n }\n // 4 - compute the new intermediate hash value (note 'addition modulo 2^32')\n H[0] = (H[0]+a) & 0xffffffff; H[1] = (H[1]+b) & 0xffffffff; H[2] = (H[2]+c) & 0xffffffff; H[3] = (H[3]+d) & 0xffffffff;\n H[4] = (H[4]+e) & 0xffffffff; H[5] = (H[5]+f) & 0xffffffff; H[6] = (H[6]+g) & 0xffffffff; H[7] = (H[7]+h) & 0xffffffff;\n }\n\n return _qz.SHA._hexStr(H[0]) + _qz.SHA._hexStr(H[1]) + _qz.SHA._hexStr(H[2]) + _qz.SHA._hexStr(H[3]) +\n _qz.SHA._hexStr(H[4]) + _qz.SHA._hexStr(H[5]) + _qz.SHA._hexStr(H[6]) + _qz.SHA._hexStr(H[7]);\n },\n\n // Rotates right (circular right shift) value x by n positions\n _rotr: function(n, x) { return (x >>> n) | (x << (32 - n)); },\n // logical functions\n _sig0: function(x) { return _qz.SHA._rotr(2, x) ^ _qz.SHA._rotr(13, x) ^ _qz.SHA._rotr(22, x); },\n _sig1: function(x) { return _qz.SHA._rotr(6, x) ^ _qz.SHA._rotr(11, x) ^ _qz.SHA._rotr(25, x); },\n _dev0: function(x) { return _qz.SHA._rotr(7, x) ^ _qz.SHA._rotr(18, x) ^ (x >>> 3); },\n _dev1: function(x) { return _qz.SHA._rotr(17, x) ^ _qz.SHA._rotr(19, x) ^ (x >>> 10); },\n _ch: function(x, y, z) { return (x & y) ^ (~x & z); },\n _maj: function(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); },\n // note can't use toString(16) as it is implementation-dependant, and in IE returns signed numbers when used on full words\n _hexStr: function(n) { var s = \"\", v; for(var i = 7; i >= 0; i--) { v = (n >>> (i * 4)) & 0xf; s += v.toString(16); } return s; },\n // implementation of deprecated unescape() based on https://cwestblog.com/2011/05/23/escape-unescape-deprecated/ (and comments)\n _unescape: function(str) {\n return str.replace(/%(u[\\da-f]{4}|[\\da-f]{2})/gi, function(seq) {\n if (seq.length - 1) {\n return String.fromCharCode(parseInt(seq.substring(seq.length - 3 ? 2 : 1), 16))\n } else {\n var code = seq.charCodeAt(0);\n return code < 256 ? \"%\" + (0 + code.toString(16)).slice(-2).toUpperCase() : \"%u\" + (\"000\" + code.toString(16)).slice(-4).toUpperCase()\n }\n });\n },\n _utf8Encode: function(str) {\n return _qz.SHA._unescape(encodeURIComponent(str));\n }\n //@formatter:on\n },\n };\n\n\n///// CONFIG CLASS ////\n\n /** Object to handle configured printer options. */\n function Config(printer, opts) {\n\n this.config = _qz.tools.extend({}, _qz.printing.defaultConfig); //create a copy of the default options\n this._dirtyOpts = {}; //track which config options have changed from the defaults\n\n /**\n * Set the printer assigned to this config.\n * @param {string|Object} newPrinter Name of printer. Use object type to specify printing to file or host.\n * @param {string} [newPrinter.name] Name of printer to send printing.\n * @param {string} [newPrinter.file] DEPRECATED: Name of file to send printing.\n * @param {string} [newPrinter.host] IP address or host name to send printing.\n * @param {string} [newPrinter.port] Port used by <printer.host>.\n */\n this.setPrinter = function(newPrinter) {\n if (typeof newPrinter === 'string') {\n newPrinter = { name: newPrinter };\n }\n\n if(newPrinter && newPrinter.file) {\n // TODO: Warn for UNC paths too https://github.com/qzind/tray/issues/730\n if(newPrinter.file.indexOf(\"\\\\\\\\\") != 0) {\n _qz.log.warn(\"Printing to file is deprecated. See https://github.com/qzind/tray/issues/730\");\n }\n }\n\n this.printer = newPrinter;\n };\n\n /**\n * @returns {Object} The printer currently assigned to this config.\n */\n this.getPrinter = function() {\n return this.printer;\n };\n\n /**\n * Alter any of the printer options currently applied to this config.\n * @param newOpts {Object} The options to change. See qz.configs.setDefaults docs for available values.\n *\n * @see qz.configs.setDefaults\n */\n this.reconfigure = function(newOpts) {\n for(var key in newOpts) {\n if (newOpts[key] !== undefined) {\n this._dirtyOpts[key] = true;\n }\n }\n\n _qz.tools.extend(this.config, newOpts);\n };\n\n /**\n * @returns {Object} The currently applied options on this config.\n */\n this.getOptions = function() {\n return _qz.compatible.config(this.config, this._dirtyOpts);\n };\n\n // init calls for new config object\n this.setPrinter(printer);\n this.reconfigure(opts);\n }\n\n /**\n * Shortcut method for calling qz.print with a particular config.\n * @param {Array} data Array of data being sent to the printer. See qz.print docs for available values.\n * @param {boolean} [signature] Pre-signed signature of JSON string containing call, params, and timestamp.\n * @param {number} [signingTimestamp] Required with signature. Timestamp used with pre-signed content.\n *\n * @example\n * qz.print(myConfig, ...); // OR\n * myConfig.print(...);\n *\n * @see qz.print\n */\n Config.prototype.print = function(data, signature, signingTimestamp) {\n qz.print(this, data, signature, signingTimestamp);\n };\n\n\n///// PUBLIC METHODS /////\n\n /** @namespace qz */\n var qz = {\n\n /**\n * Calls related specifically to the web socket connection.\n * @namespace qz.websocket\n */\n websocket: {\n /**\n * Check connection status. Active connection is necessary for other calls to run.\n *\n * @returns {boolean} If there is an active connection with QZ Tray.\n *\n * @see connect\n *\n * @memberof qz.websocket\n */\n isActive: function() {\n return _qz.tools.isActive();\n },\n\n /**\n * Call to setup connection with QZ Tray on user's system.\n *\n * @param {Object} [options] Configuration options for the web socket connection.\n * @param {string|Array} [options.host=['localhost', 'localhost.qz.io']] Host running the QZ Tray software.\n * @param {Object} [options.port] Config options for ports to cycle.\n * @param {Array} [options.port.secure=[8181, 8282, 8383, 8484]] Array of secure (WSS) ports to try\n * @param {Array} [options.port.insecure=[8182, 8283, 8384, 8485]] Array of insecure (WS) ports to try\n * @param {boolean} [options.usingSecure=true] If the web socket should try to use secure ports for connecting.\n * @param {number} [options.keepAlive=60] Seconds between keep-alive pings to keep connection open. Set to 0 to disable.\n * @param {number} [options.retries=0] Number of times to reconnect before failing.\n * @param {number} [options.delay=0] Seconds before firing a connection. Ignored if options.retries is 0.\n *\n * @returns {Promise}\n *\n * @memberof qz.websocket\n */\n connect: function(options) {\n return _qz.tools.promise(function(resolve, reject) {\n if (_qz.websocket.connection) {\n const state = _qz.websocket.connection.readyState;\n\n if (state === _qz.tools.ws.OPEN) {\n reject(new Error(\"An open connection with QZ Tray already exists\"));\n return;\n } else if (state === _qz.tools.ws.CONNECTING) {\n reject(new Error(\"The current connection attempt has not returned yet\"));\n return;\n } else if (state === _qz.tools.ws.CLOSING) {\n reject(new Error(\"Waiting for previous disconnect request to complete\"));\n return;\n }\n }\n\n if (!_qz.tools.ws) {\n reject(new Error(\"WebSocket not supported by this browser\"));\n return;\n } else if (!_qz.tools.ws.CLOSED || _qz.tools.ws.CLOSED == 2) {\n reject(new Error(\"Unsupported WebSocket version detected: HyBi-00/Hixie-76\"));\n return;\n }\n\n //ensure some form of options exists for value checks\n if (options == undefined) { options = {}; }\n\n //disable secure ports if page is not secure\n if (typeof location === 'undefined' || location.protocol !== 'https:') {\n //respect forcing secure ports if it is defined, otherwise disable\n if (typeof options.usingSecure === 'undefined') {\n _qz.log.trace(\"Disabling secure ports due to insecure page\");\n options.usingSecure = false;\n }\n }\n\n //ensure any hosts are passed to internals as an array\n if (typeof options.host !== 'undefined' && !Array.isArray(options.host)) {\n options.host = [options.host];\n }\n\n _qz.websocket.shutdown = false; //reset state for new connection attempt\n var attempt = function(count) {\n var tried = false;\n var nextAttempt = function() {\n if (!tried) {\n tried = true;\n\n if (options && count < options.retries) {\n attempt(count + 1);\n } else {\n _qz.websocket.connection = null;\n reject.apply(null, arguments);\n }\n }\n };\n\n var delayed = function() {\n var config = _qz.tools.extend({}, _qz.websocket.connectConfig, options);\n _qz.websocket.setup.findConnection(config, resolve, nextAttempt)\n };\n if (count == 0) {\n delayed(); // only retries will be called with a delay\n } else {\n setTimeout(delayed, options.delay * 1000);\n }\n };\n\n attempt(0);\n });\n },\n\n /**\n * Stop any active connection with QZ Tray.\n *\n * @returns {Promise}\n *\n * @memberof qz.websocket\n */\n disconnect: function() {\n return _qz.tools.promise(function(resolve, reject) {\n if (_qz.websocket.connection != null) {\n if (_qz.tools.isActive()) {\n // handles closing both 'connecting' and 'connected' states\n _qz.websocket.shutdown = true;\n _qz.websocket.connection.promise = { resolve: resolve, reject: reject };\n _qz.websocket.connection.close();\n } else {\n reject(new Error(\"Current connection is still closing\"));\n }\n } else {\n reject(new Error(\"No open connection with QZ Tray\"));\n }\n });\n },\n\n /**\n * List of functions called for any connections errors outside of an API call.

\n * Also called if {@link websocket#connect} fails to connect.\n *\n * @param {Function|Array} calls Single or array of Function({Event} event) calls.\n *\n * @memberof qz.websocket\n */\n setErrorCallbacks: function(calls) {\n _qz.websocket.errorCallbacks = calls;\n },\n\n /**\n * List of functions called for any connection closing event outside of an API call.

\n * Also called when {@link websocket#disconnect} is called.\n *\n * @param {Function|Array} calls Single or array of Function({Event} event) calls.\n *\n * @memberof qz.websocket\n */\n setClosedCallbacks: function(calls) {\n _qz.websocket.closedCallbacks = calls;\n },\n\n /**\n * @deprecated Since 2.1.0. Please use qz.networking.device() instead\n *\n * @param {string} [hostname] Hostname to try to connect to when determining network interfaces, defaults to \"google.com\"\n * @param {number} [port] Port to use with custom hostname, defaults to 443\n * @param {string} [signature] Pre-signed signature of hashed JSON string containing call='websocket.getNetworkInfo', params object, and timestamp.\n * @param {number} [signingTimestamp] Required with signature. Timestamp used with pre-signed content.\n *\n * @returns {Promise|Error>} Connected system's network information.\n *\n * @memberof qz.websocket\n */\n getNetworkInfo: _qz.compatible.networking,\n\n /**\n * @returns {Object<{socket: String, host: String, port: Number}>} Details of active websocket connection\n *\n * @memberof qz.websocket\n */\n getConnectionInfo: function() {\n if (_qz.tools.assertActive()) {\n var url = _qz.websocket.connection.url.split(/[:\\/]+/g);\n return { socket: url[0], host: url[1], port: +url[2] };\n }\n }\n },\n\n\n /**\n * Calls related to getting printer information from the connection.\n * @namespace qz.printers\n */\n printers: {\n /**\n * @param {string} [signature] Pre-signed signature of hashed JSON string containing call='printers.getDefault, params, and timestamp.\n * @param {number} [signingTimestamp] Required with signature. Timestamp used with pre-signed content.\n *\n * @returns {Promise} Name of the connected system's default printer.\n *\n * @memberof qz.printers\n */\n getDefault: function(signature, signingTimestamp) {\n return _qz.websocket.dataPromise('printers.getDefault', null, signature, signingTimestamp);\n },\n\n /**\n * @param {string} [query] Search for a specific printer. All printers are returned if not provided.\n * @param {string} [signature] Pre-signed signature of hashed JSON string containing call='printers.find', params, and timestamp.\n * @param {number} [signingTimestamp] Required with signature. Timestamp used with pre-signed content.\n *\n * @returns {Promise|string|Error>} The matched printer name if query is provided.\n * Otherwise an array of printer names found on the connected system.\n *\n * @memberof qz.printers\n */\n find: function(query, signature, signingTimestamp) {\n return _qz.websocket.dataPromise('printers.find', { query: query }, signature, signingTimestamp);\n },\n\n /**\n * Provides a list, with additional information, for each printer available to QZ.\n *\n * @returns {Promise|Object|Error>}\n *\n * @memberof qz.printers\n */\n details: function() {\n return _qz.websocket.dataPromise('printers.detail');\n },\n\n /**\n * Start listening for printer status events, such as paper_jam events.\n * Reported under the ACTION type in the streamEvent on callbacks.\n *\n * @returns {Promise}\n * @since 2.1.0\n *\n * @see qz.printers.setPrinterCallbacks\n *\n * @param {null|string|Array} printers Printer or list of printers to listen to, null listens to all.\n * @param {Object|null} [options] Printer listener options\n * @param {null|boolean} [options.jobData=false] Flag indicating if raw spool file content should be return as well as status information (Windows only)\n * @param {null|number} [options.maxJobData=-1] Maximum number of bytes to returns for raw spooled file content (Windows only)\n * @param {null|string} [options.flavor=\"plain\"] Flavor of data format returned. Valid flavors are [base64 | hex | plain*] (Windows only)\n *\n * @memberof qz.printers\n */\n startListening: function(printers, options) {\n if (!Array.isArray(printers)) {\n printers = [printers];\n }\n var params = {\n printerNames: printers\n };\n if (options && options.jobData == true) params.jobData = true;\n if (options && options.maxJobData) params.maxJobData = options.maxJobData;\n if (options && options.flavor) params.flavor = options.flavor;\n return _qz.websocket.dataPromise('printers.startListening', params);\n },\n\n /**\n * Stop listening for printer status actions.\n *\n * @returns {Promise}\n * @since 2.1.0\n *\n * @see qz.printers.setPrinterCallbacks\n *\n * @memberof qz.printers\n */\n stopListening: function() {\n return _qz.websocket.dataPromise('printers.stopListening');\n },\n\n /**\n * Retrieve current printer status from any active listeners.\n *\n * @returns {Promise}\n * @since 2.1.0\n *\n * @see qz.printers.startListening\n *\n * @memberof qz.printers\n */\n getStatus: function() {\n return _qz.websocket.dataPromise('printers.getStatus');\n },\n\n /**\n * List of functions called for any printer status change.\n * Event data will contain {string} printerName and {string} status for all types.\n * For RECEIVE types, {Array} output (in hexadecimal format).\n * For ERROR types, {string} exception.\n * For ACTION types, {string} actionType.\n *\n * @param {Function|Array} calls Single or array of Function({Object} eventData) calls.\n * @since 2.1.0\n *\n * @memberof qz.printers\n */\n setPrinterCallbacks: function(calls) {\n _qz.printers.printerCallbacks = calls;\n }\n },\n\n /**\n * Calls related to setting up new printer configurations.\n * @namespace qz.configs\n */\n configs: {\n /**\n * Default options used by new configs if not overridden.\n * Setting a value to NULL will use the printer's default options.\n * Updating these will not update the options on any created config.\n *\n * @param {Object} options Default options used by printer configs if not overridden.\n *\n * @param {Object} [options.bounds=null] Bounding box rectangle.\n * @param {number} [options.bounds.x=0] Distance from left for bounding box starting corner\n * @param {number} [options.bounds.y=0] Distance from top for bounding box starting corner\n * @param {number} [options.bounds.width=0] Width of bounding box\n * @param {number} [options.bounds.height=0] Height of bounding box\n * @param {string} [options.colorType='color'] Valid values [color | grayscale | blackwhite]\n * @param {number} [options.copies=1] Number of copies to be printed.\n * @param {number|Array|Object|Array|string} [options.density=0] Pixel density (DPI, DPMM, or DPCM depending on [options.units]).\n * If provided as an array, uses the first supported density found (or the first entry if none found).\n * If provided as a string, valid values are [best | draft], corresponding to highest or lowest reported density respectively.\n * @param {number} [options.density.cross=0] Asymmetric pixel density for the cross feed direction.\n * @param {number} [options.density.feed=0] Asymmetric pixel density for the feed direction.\n * @param {boolean|string} [options.duplex=false] Double sided printing, Can specify duplex style by passing a string value: [one-sided | duplex | long-edge | tumble | short-edge]\n * @param {number} [options.fallbackDensity=null] Value used when default density value cannot be read, or in cases where reported as \"Normal\" by the driver, (in DPI, DPMM, or DPCM depending on [options.units]).\n * @param {string} [options.interpolation='bicubic'] Valid values [bicubic | bilinear | nearest-neighbor]. Controls how images are handled when resized.\n * @param {string} [options.jobName=null] Name to display in print queue.\n * @param {boolean} [options.legacy=false] If legacy style printing should be used.\n * @param {Object|number} [options.margins=0] If just a number is provided, it is used as the margin for all sides.\n * @param {number} [options.margins.top=0]\n * @param {number} [options.margins.right=0]\n * @param {number} [options.margins.bottom=0]\n * @param {number} [options.margins.left=0]\n * @param {string} [options.orientation=null] Valid values [portrait | landscape | reverse-landscape | null].\n * If set to null, orientation will be determined automatically.\n * @param {number} [options.paperThickness=null]\n * @param {string|number} [options.printerTray=null] Printer tray to pull from. The number N assumes string equivalent of 'Tray N'. Uses printer default if NULL.\n * @param {boolean} [options.rasterize=false] Whether documents should be rasterized before printing.\n * Specifying [options.density] for PDF print formats will set this to true.\n * @param {number} [options.rotation=0] Image rotation in degrees.\n * @param {boolean} [options.scaleContent=true] Scales print content to page size, keeping ratio.\n * @param {Object} [options.size=null] Paper size.\n * @param {number} [options.size.width=null] Page width.\n * @param {number} [options.size.height=null] Page height.\n * @param {string} [options.units='in'] Page units, applies to paper size, margins, and density. Valid value [in | cm | mm]\n *\n * @param {boolean} [options.forceRaw=false] Print the specified raw data using direct method, skipping the driver. Not yet supported on Windows.\n * @param {string|Object} [options.encoding=null] Character set for commands. Can be provided as an object for converting encoding types for RAW types.\n * @param {string} [options.encoding.from] If this encoding type is provided, RAW type commands will be parsed from this for the purpose of being converted to the encoding.to value.\n * @param {string} [options.encoding.to] Encoding RAW type commands will be converted into. If encoding.from is not provided, this will be treated as if a string was passed for encoding.\n * @param {string} [options.endOfDoc=null] DEPRECATED Raw only: Character(s) denoting end of a page to control spooling.\n * @param {number} [options.perSpool=1] DEPRECATED: Raw only: Number of pages per spool.\n * @param {boolean} [options.retainTemp=false] Retain any temporary files used. Ignored unless forceRaw true.\n * @param {Object} [options.spool=null] Advanced spooling options.\n * @param {number} [options.spool.size=null] Number of pages per spool. Default is no limit. If spool.end is provided, defaults to 1\n * @param {string} [options.spool.end=null] Raw only: Character(s) denoting end of a page to control spooling.\n *\n * @memberof qz.configs\n */\n setDefaults: function(options) {\n _qz.tools.extend(_qz.printing.defaultConfig, options);\n },\n\n /**\n * Creates new printer config to be used in printing.\n *\n * @param {string|object} printer Name of printer. Use object type to specify printing to file or host.\n * @param {string} [printer.name] Name of printer to send printing.\n * @param {string} [printer.file] Name of file to send printing.\n * @param {string} [printer.host] IP address or host name to send printing.\n * @param {string} [printer.port] Port used by <printer.host>.\n * @param {Object} [options] Override any of the default options for this config only.\n *\n * @returns {Config} The new config.\n *\n * @see configs.setDefaults\n *\n * @memberof qz.configs\n */\n create: function(printer, options) {\n return new Config(printer, options);\n }\n },\n\n\n /**\n * Send data to selected config for printing.\n * The promise for this method will resolve when the document has been sent to the printer. Actual printing may not be complete.\n *

\n * Optionally, print requests can be pre-signed:\n * Signed content consists of a JSON object string containing no spacing,\n * following the format of the \"call\" and \"params\" keys in the API call, with the addition of a \"timestamp\" key in milliseconds\n * ex. '{\"call\":\"\",\"params\":{...},\"timestamp\":1450000000}'\n *\n * @param {Object|Array>} configs Previously created config object or objects.\n * @param {Array|Array>} data Array of data being sent to the printer.
\n * String values are interpreted as {type: 'raw', format: 'command', flavor: 'plain', data: <string>}.\n * @param {string} data.data\n * @param {string} data.type Printing type. Valid types are [pixel | raw*]. *Default\n * @param {string} data.format Format of data type used. *Default per type

\n * For [pixel] types, valid formats are [html | image* | pdf].

\n * For [raw] types, valid formats are [command* | html | image | pdf].\n * @param {string} data.flavor Flavor of data format used. *Default per format

\n * For [command] formats, valid flavors are [base64 | file | hex | plain* | xml].

\n * For [html] formats, valid flavors are [file* | plain].

\n * For [image] formats, valid flavors are [base64 | file*].

\n * For [pdf] formats, valid flavors are [base64 | file*].\n * @param {Object} [data.options]\n * @param {string} [data.options.language] Required with [raw] type + [image] format. Printer language.\n * @param {number} [data.options.x] Optional with [raw] type + [image] format. The X position of the image.\n * @param {number} [data.options.y] Optional with [raw] type + [image] format. The Y position of the image.\n * @param {string|number} [data.options.dotDensity] Optional with [raw] type + [image] format.\n * @param {number} [data.precision=128] Optional with [raw] type [image] format. Bit precision of the ribbons.\n * @param {boolean|string|Array>} [data.options.overlay=false] Optional with [raw] type [image] format.\n * Boolean sets entire layer, string sets mask image, Array sets array of rectangles in format [x1,y1,x2,y2].\n * @param {string} [data.options.xmlTag] Required with [xml] flavor. Tag name containing base64 formatted data.\n * @param {number} [data.options.pageWidth] Optional with [html | pdf] formats. Width of the rendering.\n * Defaults to paper width.\n * @param {number} [data.options.pageHeight] Optional with [html | pdf] formats. Height of the rendering.\n * Defaults to paper height for [pdf], or auto sized for [html].\n * @param {string} [data.options.pageRanges] Optional with [pdf] formats. Comma-separated list of page ranges to include.\n * @param {boolean} [data.options.ignoreTransparency=false] Optional with [pdf] formats. Instructs transparent PDF elements to be ignored.\n * Transparent PDF elements are known to degrade performance and quality when printing.\n * @param {boolean} [data.options.altFontRendering=false] Optional with [pdf] formats. Instructs PDF to be rendered using PDFBOX 1.8 techniques.\n * Drastically improves low-DPI PDF print quality on Windows.\n * @param {...*} [arguments] Additionally three more parameters can be specified:

\n * {boolean} [resumeOnError=false] Whether the chain should continue printing if it hits an error on one the the prints.

\n * {string|Array} [signature] Pre-signed signature(s) of the JSON string for containing call, params, and timestamp.

\n * {number|Array} [signingTimestamps] Required to match with signature. Timestamps for each of the passed pre-signed content.\n *\n * @returns {Promise}\n *\n * @see qz.configs.create\n *\n * @memberof qz\n */\n print: function(configs, data) {\n var resumeOnError = false,\n signatures = [],\n signaturesTimestamps = [];\n\n //find optional parameters\n if (arguments.length >= 3) {\n if (typeof arguments[2] === 'boolean') {\n resumeOnError = arguments[2];\n\n if (arguments.length >= 5) {\n signatures = arguments[3];\n signaturesTimestamps = arguments[4];\n }\n } else if (arguments.length >= 4) {\n signatures = arguments[2];\n signaturesTimestamps = arguments[3];\n }\n\n //ensure values are arrays for consistency\n if (signatures && !Array.isArray(signatures)) { signatures = [signatures]; }\n if (signaturesTimestamps && !Array.isArray(signaturesTimestamps)) { signaturesTimestamps = [signaturesTimestamps]; }\n }\n\n if (!Array.isArray(configs)) { configs = [configs]; } //single config -> array of configs\n if (!Array.isArray(data[0])) { data = [data]; } //single data array -> array of data arrays\n\n //clean up data formatting\n for(var d = 0; d < data.length; d++) {\n _qz.tools.relative(data[d]);\n _qz.compatible.data(data[d]);\n }\n\n var sendToPrint = function(mapping) {\n var params = {\n printer: mapping.config.getPrinter(),\n options: mapping.config.getOptions(),\n data: mapping.data\n };\n\n return _qz.websocket.dataPromise('print', params, mapping.signature, mapping.timestamp);\n };\n\n //chain instead of Promise.all, so resumeOnError can collect each error\n var chain = [];\n for(var i = 0; i < configs.length || i < data.length; i++) {\n (function(i_) {\n var map = {\n config: configs[Math.min(i_, configs.length - 1)],\n data: data[Math.min(i_, data.length - 1)],\n signature: signatures[i_],\n timestamp: signaturesTimestamps[i_]\n };\n\n chain.push(function() { return sendToPrint(map) });\n })(i);\n }\n\n //setup to catch errors if needed\n var fallThrough = null;\n if (resumeOnError) {\n var fallen = [];\n fallThrough = function(err) { fallen.push(err); };\n\n //final promise to reject any errors as a group\n chain.push(function() {\n return _qz.tools.promise(function(resolve, reject) {\n fallen.length ? reject(fallen) : resolve();\n });\n });\n }\n\n var last = null;\n chain.reduce(function(sequence, link) {\n last = sequence.catch(fallThrough).then(link); //catch is ignored if fallThrough is null\n return last;\n }, _qz.tools.promise(function(r) { r(); })); //an immediately resolved promise to start off the chain\n\n //return last promise so users can chain off final action or catch when stopping on error\n return last;\n },\n\n\n /**\n * Calls related to interaction with serial ports.\n * @namespace qz.serial\n */\n serial: {\n /**\n * @returns {Promise|Error>} Communication (RS232, COM, TTY) ports available on connected system.\n *\n * @memberof qz.serial\n */\n findPorts: function() {\n return _qz.websocket.dataPromise('serial.findPorts');\n },\n\n /**\n * List of functions called for any response from open serial ports.\n * Event data will contain {string} portName for all types.\n * For RECEIVE types, {string} output.\n * For ERROR types, {string} exception.\n *\n * @param {Function|Array} calls Single or array of Function({object} streamEvent) calls.\n *\n * @memberof qz.serial\n */\n setSerialCallbacks: function(calls) {\n _qz.serial.serialCallbacks = calls;\n },\n\n /**\n * Opens a serial port for sending and receiving data\n *\n * @param {string} port Name of serial port to open.\n * @param {Object} [options] Serial port configurations.\n * @param {number} [options.baudRate=9600] Serial port speed. Set to 0 for auto negotiation.\n * @param {number} [options.dataBits=8] Serial port data bits. Set to 0 for auto negotiation.\n * @param {number} [options.stopBits=1] Serial port stop bits. Set to 0 for auto negotiation.\n * @param {string} [options.parity='NONE'] Serial port parity. Set to AUTO for auto negotiation. Valid values [NONE | EVEN | ODD | MARK | SPACE | AUTO]\n * @param {string} [options.flowControl='NONE'] Serial port flow control. Set to AUTO for auto negotiation. Valid values [NONE | XONXOFF | XONXOFF_OUT | XONXOFF_IN | RTSCTS | RTSCTS_OUT | RTSCTS_IN | AUTO]\n * @param {string} [options.encoding='UTF-8'] Character set for communications.\n * @param {string} [options.start=0x0002] DEPRECATED: Legacy character denoting start of serial response. Use options.rx.start instead.\n * @param {string} [options.end=0x000D] DEPRECATED: Legacy character denoting end of serial response. Use options.rx.end instead.\n * @param {number} [options.width] DEPRECATED: Legacy use for fixed-width response serial communication. Use options.rx.width instead.\n * @param {Object} [options.rx] Serial communications response definitions. If an object is passed but no options are defined, all response data will be sent back as it is received unprocessed.\n * @param {string|Array} [options.rx.start] Character(s) denoting start of response bytes. Used in conjunction with `end`, `width`, or `lengthbit` property.\n * @param {string} [options.rx.end] Character denoting end of response bytes. Used in conjunction with `start` property.\n * @param {number} [options.rx.width] Fixed width size of response bytes (not including header if `start` is set). Used alone or in conjunction with `start` property.\n * @param {boolean} [options.rx.untilNewline] Returns data between newline characters (`\\n` or `\\r`) Truncates empty responses. Overrides `start`, `end`, `width`.\n * @param {number|Object} [options.rx.lengthBytes] If a number is passed it is treated as the length index. Other values are left as their defaults.\n * @param {number} [options.rx.lengthBytes.index=0] Position of the response byte (not including response `start` bytes) used to denote the length of the remaining response data.\n * @param {number} [options.rx.lengthBytes.length=1] Length of response length bytes after response header.\n * @param {string} [options.rx.lengthBytes.endian='BIG'] Byte endian for multi-byte length values. Valid values [BIG | LITTLE]\n * @param {number|Object} [options.rx.crcBytes] If a number is passed it is treated as the crc length. Other values are left as their defaults.\n * @param {number} [options.rx.crcBytes.index=0] Position after the response data (not including length or data bytes) used to denote the crc.\n * @param {number} [options.rx.crcBytes.length=1] Length of response crc bytes after the response data length.\n * @param {boolean} [options.rx.includeHeader=false] Whether any of the header bytes (`start` bytes and any length bytes) should be included in the processed response.\n * @param {string} [options.rx.encoding] Override the encoding used for response data. Uses the same value as options.encoding otherwise.\n *\n * @returns {Promise}\n *\n * @memberof qz.serial\n */\n openPort: function(port, options) {\n var params = {\n port: port,\n options: options\n };\n return _qz.websocket.dataPromise('serial.openPort', params);\n },\n\n /**\n * Send commands over a serial port.\n * Any responses from the device will be sent to serial callback functions.\n *\n * @param {string} port An open serial port to send data.\n * @param {string|Array|Object} data Data to be sent to the serial device.\n * @param {string} [data.type='PLAIN'] Valid values [FILE | PLAIN | HEX | BASE64]\n * @param {string|Array} data.data Data to be sent to the serial device.\n * @param {Object} options Serial port configuration updates. See qz.serial.openPort `options` docs for available values.\n * For best performance, it is recommended to only set these values on the port open call.\n *\n * @returns {Promise}\n *\n * @see qz.serial.setSerialCallbacks\n *\n * @memberof qz.serial\n */\n sendData: function(port, data, options) {\n if (_qz.tools.versionCompare(2, 1, 0, 12) >= 0) {\n if (typeof data !== 'object') {\n data = {\n data: data,\n type: \"PLAIN\"\n }\n }\n\n if (data.type && data.type.toUpperCase() == \"FILE\") {\n data.data = _qz.tools.absolute(data.data);\n }\n }\n\n var params = {\n port: port,\n data: data,\n options: options\n };\n return _qz.websocket.dataPromise('serial.sendData', params);\n },\n\n /**\n * @param {string} port Name of port to close.\n *\n * @returns {Promise}\n *\n * @memberof qz.serial\n */\n closePort: function(port) {\n return _qz.websocket.dataPromise('serial.closePort', { port: port });\n }\n },\n\n /**\n * Calls related to interaction with communication sockets.\n * @namespace qz.socket\n */\n socket: {\n /**\n * Opens a network port for sending and receiving data.\n *\n * @param {string} host The connection hostname.\n * @param {number} port The connection port number.\n * @param {Object} [options] Network socket configuration.\n * @param {string} [options.encoding='UTF-8'] Character set for communications.\n *\n * @memberof qz.socket\n */\n open: function(host, port, options) {\n var params = {\n host: host,\n port: port,\n options: options\n };\n return _qz.websocket.dataPromise(\"socket.open\", params);\n },\n\n /**\n * @param {string} host The connection hostname.\n * @param {number} port The connection port number.\n *\n * @memberof qz.socket\n */\n close: function(host, port) {\n var params = {\n host: host,\n port: port\n };\n return _qz.websocket.dataPromise(\"socket.close\", params);\n },\n\n /**\n * Send data over an open socket.\n *\n * @param {string} host The connection hostname.\n * @param {number} port The connection port number.\n * @param {string|Object} data Data to be sent over the port.\n * @param {string} [data.type='PLAIN'] Valid values [PLAIN]\n * @param {string} data.data Data to be sent over the port.\n *\n * @memberof qz.socket\n */\n sendData: function(host, port, data) {\n if (typeof data !== 'object') {\n data = {\n data: data,\n type: \"PLAIN\"\n };\n }\n\n var params = {\n host: host,\n port: port,\n data: data\n };\n return _qz.websocket.dataPromise(\"socket.sendData\", params);\n },\n\n /**\n * List of functions called for any response from open network sockets.\n * Event data will contain {string} host and {number} port for all types.\n * For RECEIVE types, {string} response.\n * For ERROR types, {string} exception.\n *\n * @param {Function|Array} calls Single or array of Function({Object} eventData) calls.\n *\n * @memberof qz.socket\n */\n setSocketCallbacks: function(calls) {\n _qz.socket.socketCallbacks = calls;\n }\n },\n\n /**\n * Calls related to interaction with USB devices.\n * @namespace qz.usb\n */\n usb: {\n /**\n * List of available USB devices. Includes (hexadecimal) vendor ID, (hexadecimal) product ID, and hub status.\n * If supported, also returns manufacturer and product descriptions.\n *\n * @param includeHubs Whether to include USB hubs.\n * @returns {Promise|Error>} Array of JSON objects containing information on connected USB devices.\n *\n * @memberof qz.usb\n */\n listDevices: function(includeHubs) {\n return _qz.websocket.dataPromise('usb.listDevices', { includeHubs: includeHubs });\n },\n\n /**\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @returns {Promise|Error>} List of available (hexadecimal) interfaces on a USB device.\n *\n * @memberof qz.usb\n */\n listInterfaces: function(deviceInfo) {\n if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility\n\n return _qz.websocket.dataPromise('usb.listInterfaces', deviceInfo);\n },\n\n /**\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @param deviceInfo.iface Hex string of interface on the USB device to search.\n * @returns {Promise|Error>} List of available (hexadecimal) endpoints on a USB device's interface.\n *\n * @memberof qz.usb\n */\n listEndpoints: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n interface: arguments[2]\n };\n }\n\n return _qz.websocket.dataPromise('usb.listEndpoints', deviceInfo);\n },\n\n /**\n * List of functions called for any response from open usb devices.\n * Event data will contain {string} vendorId and {string} productId for all types.\n * For RECEIVE types, {Array} output (in hexadecimal format).\n * For ERROR types, {string} exception.\n *\n * @param {Function|Array} calls Single or array of Function({Object} eventData) calls.\n *\n * @memberof qz.usb\n */\n setUsbCallbacks: function(calls) {\n _qz.usb.usbCallbacks = calls;\n },\n\n /**\n * Claim a USB device's interface to enable sending/reading data across an endpoint.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @param deviceInfo.interface Hex string of interface on the USB device to claim.\n * @returns {Promise}\n *\n * @memberof qz.usb\n */\n claimDevice: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n interface: arguments[2]\n };\n }\n\n return _qz.websocket.dataPromise('usb.claimDevice', deviceInfo);\n },\n\n /**\n * Check the current claim state of a USB device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @returns {Promise}\n *\n * @since 2.0.2\n * @memberOf qz.usb\n */\n isClaimed: function(deviceInfo) {\n if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility\n\n return _qz.websocket.dataPromise('usb.isClaimed', deviceInfo);\n },\n\n /**\n * Send data to a claimed USB device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @param deviceInfo.endpoint Hex string of endpoint on the claimed interface for the USB device.\n * @param deviceInfo.data Bytes to send over specified endpoint.\n * @param {string} [deviceInfo.type='PLAIN'] Valid values [FILE | PLAIN | HEX | BASE64]\n * @returns {Promise}\n *\n * @memberof qz.usb\n */\n sendData: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n endpoint: arguments[2],\n data: arguments[3]\n };\n }\n\n if (_qz.tools.versionCompare(2, 1, 0, 12) >= 0) {\n if (typeof deviceInfo.data !== 'object') {\n deviceInfo.data = {\n data: deviceInfo.data,\n type: \"PLAIN\"\n }\n }\n\n if (deviceInfo.data.type && deviceInfo.data.type.toUpperCase() == \"FILE\") {\n deviceInfo.data.data = _qz.tools.absolute(deviceInfo.data.data);\n }\n }\n\n return _qz.websocket.dataPromise('usb.sendData', deviceInfo);\n },\n\n /**\n * Read data from a claimed USB device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @param deviceInfo.endpoint Hex string of endpoint on the claimed interface for the USB device.\n * @param deviceInfo.responseSize Size of the byte array to receive a response in.\n * @returns {Promise|Error>} List of (hexadecimal) bytes received from the USB device.\n *\n * @memberof qz.usb\n */\n readData: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n endpoint: arguments[2],\n responseSize: arguments[3]\n };\n }\n\n return _qz.websocket.dataPromise('usb.readData', deviceInfo);\n },\n\n /**\n * Provides a continuous stream of read data from a claimed USB device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @param deviceInfo.endpoint Hex string of endpoint on the claimed interface for the USB device.\n * @param deviceInfo.responseSize Size of the byte array to receive a response in.\n * @param deviceInfo.interval=100 Frequency to send read data back, in milliseconds.\n * @returns {Promise}\n *\n * @see qz.usb.setUsbCallbacks\n *\n * @memberof qz.usb\n */\n openStream: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n endpoint: arguments[2],\n responseSize: arguments[3],\n interval: arguments[4]\n };\n }\n\n return _qz.websocket.dataPromise('usb.openStream', deviceInfo);\n },\n\n /**\n * Stops the stream of read data from a claimed USB device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @param deviceInfo.endpoint Hex string of endpoint on the claimed interface for the USB device.\n * @returns {Promise}\n *\n * @memberof qz.usb\n */\n closeStream: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n endpoint: arguments[2]\n };\n }\n\n return _qz.websocket.dataPromise('usb.closeStream', deviceInfo);\n },\n\n /**\n * Release a claimed USB device to free resources after sending/reading data.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of USB device's vendor ID.\n * @param deviceInfo.productId Hex string of USB device's product ID.\n * @returns {Promise}\n *\n * @memberof qz.usb\n */\n releaseDevice: function(deviceInfo) {\n if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility\n\n return _qz.websocket.dataPromise('usb.releaseDevice', deviceInfo);\n }\n },\n\n\n /**\n * Calls related to interaction with HID USB devices
\n * Many of these calls can be accomplished from the qz.usb namespace,\n * but HID allows for simpler interaction\n * @namespace qz.hid\n * @since 2.0.1\n */\n hid: {\n /**\n * List of available HID devices. Includes (hexadecimal) vendor ID and (hexadecimal) product ID.\n * If available, also returns manufacturer and product descriptions.\n *\n * @returns {Promise|Error>} Array of JSON objects containing information on connected HID devices.\n * @since 2.0.1\n *\n * @memberof qz.hid\n */\n listDevices: function() {\n return _qz.websocket.dataPromise('hid.listDevices');\n },\n\n /**\n * Start listening for HID device actions, such as attach / detach events.\n * Reported under the ACTION type in the streamEvent on callbacks.\n *\n * @returns {Promise}\n * @since 2.0.1\n *\n * @see qz.hid.setHidCallbacks\n *\n * @memberof qz.hid\n */\n startListening: function() {\n return _qz.websocket.dataPromise('hid.startListening');\n },\n\n /**\n * Stop listening for HID device actions.\n *\n * @returns {Promise}\n * @since 2.0.1\n *\n * @see qz.hid.setHidCallbacks\n *\n * @memberof qz.hid\n */\n stopListening: function() {\n return _qz.websocket.dataPromise('hid.stopListening');\n },\n\n /**\n * List of functions called for any response from open usb devices.\n * Event data will contain {string} vendorId and {string} productId for all types.\n * For RECEIVE types, {Array} output (in hexadecimal format).\n * For ERROR types, {string} exception.\n * For ACTION types, {string} actionType.\n *\n * @param {Function|Array} calls Single or array of Function({Object} eventData) calls.\n * @since 2.0.1\n *\n * @memberof qz.hid\n */\n setHidCallbacks: function(calls) {\n _qz.hid.hidCallbacks = calls;\n },\n\n /**\n * Claim a HID device to enable sending/reading data across.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @returns {Promise}\n * @since 2.0.1\n *\n * @memberof qz.hid\n */\n claimDevice: function(deviceInfo) {\n if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility\n\n return _qz.websocket.dataPromise('hid.claimDevice', deviceInfo);\n },\n\n /**\n * Check the current claim state of a HID device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @returns {Promise}\n *\n * @since 2.0.2\n * @memberOf qz.hid\n */\n isClaimed: function(deviceInfo) {\n if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility\n\n return _qz.websocket.dataPromise('hid.isClaimed', deviceInfo);\n },\n\n /**\n * Send data to a claimed HID device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @param deviceInfo.data Bytes to send over specified endpoint.\n * @param deviceInfo.endpoint=0x00 First byte of the data packet signifying the HID report ID.\n * Must be 0x00 for devices only supporting a single report.\n * @param deviceInfo.reportId=0x00 Alias for deviceInfo.endpoint. Not used if endpoint is provided.\n * @param {string} [deviceInfo.type='PLAIN'] Valid values [FILE | PLAIN | HEX | BASE64]\n * @returns {Promise}\n * @since 2.0.1\n *\n * @memberof qz.hid\n */\n sendData: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n data: arguments[2],\n endpoint: arguments[3]\n };\n }\n\n if (_qz.tools.versionCompare(2, 1, 0, 12) >= 0) {\n if (typeof deviceInfo.data !== 'object') {\n deviceInfo.data = {\n data: deviceInfo.data,\n type: \"PLAIN\"\n }\n }\n\n if (deviceInfo.data.type && deviceInfo.data.type.toUpperCase() == \"FILE\") {\n deviceInfo.data.data = _qz.tools.absolute(deviceInfo.data.data);\n }\n } else {\n if (typeof deviceInfo.data === 'object') {\n if (deviceInfo.data.type.toUpperCase() !== \"PLAIN\"\n || typeof deviceInfo.data.data !== \"string\") {\n return _qz.tools.reject(new Error(\"Data format is not supported with connected QZ Tray version \" + _qz.websocket.connection.version));\n }\n\n deviceInfo.data = deviceInfo.data.data;\n }\n }\n\n return _qz.websocket.dataPromise('hid.sendData', deviceInfo);\n },\n\n /**\n * Read data from a claimed HID device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @param deviceInfo.responseSize Size of the byte array to receive a response in.\n * @returns {Promise|Error>} List of (hexadecimal) bytes received from the HID device.\n * @since 2.0.1\n *\n * @memberof qz.hid\n */\n readData: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n responseSize: arguments[2]\n };\n }\n\n return _qz.websocket.dataPromise('hid.readData', deviceInfo);\n },\n\n /**\n * Send a feature report to a claimed HID device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @param deviceInfo.data Bytes to send over specified endpoint.\n * @param deviceInfo.endpoint=0x00 First byte of the data packet signifying the HID report ID.\n * Must be 0x00 for devices only supporting a single report.\n * @param deviceInfo.reportId=0x00 Alias for deviceInfo.endpoint. Not used if endpoint is provided.\n * @param {string} [deviceInfo.type='PLAIN'] Valid values [FILE | PLAIN | HEX | BASE64]\n * @returns {Promise}\n *\n * @memberof qz.hid\n */\n sendFeatureReport: function(deviceInfo) {\n return _qz.websocket.dataPromise('hid.sendFeatureReport', deviceInfo);\n },\n\n /**\n * Get a feature report from a claimed HID device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @param deviceInfo.responseSize Size of the byte array to receive a response in.\n * @returns {Promise|Error>} List of (hexadecimal) bytes received from the HID device.\n *\n * @memberof qz.hid\n */\n getFeatureReport: function(deviceInfo) {\n return _qz.websocket.dataPromise('hid.getFeatureReport', deviceInfo);\n },\n\n /**\n * Provides a continuous stream of read data from a claimed HID device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @param deviceInfo.responseSize Size of the byte array to receive a response in.\n * @param deviceInfo.interval=100 Frequency to send read data back, in milliseconds.\n * @returns {Promise}\n * @since 2.0.1\n *\n * @see qz.hid.setHidCallbacks\n *\n * @memberof qz.hid\n */\n openStream: function(deviceInfo) {\n //backwards compatibility\n if (typeof deviceInfo !== 'object') {\n deviceInfo = {\n vendorId: arguments[0],\n productId: arguments[1],\n responseSize: arguments[2],\n interval: arguments[3]\n };\n }\n\n return _qz.websocket.dataPromise('hid.openStream', deviceInfo);\n },\n\n /**\n * Stops the stream of read data from a claimed HID device.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @returns {Promise}\n * @since 2.0.1\n *\n * @memberof qz.hid\n */\n closeStream: function(deviceInfo) {\n if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility\n\n return _qz.websocket.dataPromise('hid.closeStream', deviceInfo);\n },\n\n /**\n * Release a claimed HID device to free resources after sending/reading data.\n *\n * @param {object} deviceInfo Config details of the HID device.\n * @param deviceInfo.vendorId Hex string of HID device's vendor ID.\n * @param deviceInfo.productId Hex string of HID device's product ID.\n * @param deviceInfo.usagePage Hex string of HID device's usage page when multiple are present.\n * @param deviceInfo.serial Serial ID of HID device.\n * @returns {Promise}\n * @since 2.0.1\n *\n * @memberof qz.hid\n */\n releaseDevice: function(deviceInfo) {\n if (typeof deviceInfo !== 'object') { deviceInfo = { vendorId: arguments[0], productId: arguments[1] }; } //backwards compatibility\n\n return _qz.websocket.dataPromise('hid.releaseDevice', deviceInfo);\n }\n },\n\n\n /**\n * Calls related to interactions with the filesystem\n * @namespace qz.file\n * @since 2.1\n */\n file: {\n /**\n * List of files available at the given directory.
\n * Due to security reasons, paths are limited to the qz data directory unless overridden via properties file.\n *\n * @param {string} path Relative or absolute directory path. Must reside in qz data directory or a white-listed location.\n * @param {Object} [params] Object containing file access parameters\n * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections\n * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user\n * @returns {Promise|Error>} Array of files at the given path\n *\n * @memberof qz.file\n */\n list: function(path, params) {\n var param = _qz.tools.extend({ path: path }, params);\n return _qz.websocket.dataPromise('file.list', param);\n },\n\n /**\n * Reads contents of file at the given path.
\n * Due to security reasons, paths are limited to the qz data directory unless overridden via properties file.\n *\n * @param {string} path Relative or absolute file path. Must reside in qz data directory or a white-listed location.\n * @param {Object} [params] Object containing file access parameters\n * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections\n * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user\n * @param {string} [params.flavor='plain'] Flavor of data format used, valid flavors are [base64 | hex | plain].\n * @returns {Promise} String containing the file contents\n *\n * @memberof qz.file\n */\n read: function(path, params) {\n var param = _qz.tools.extend({ path: path }, params);\n return _qz.websocket.dataPromise('file.read', param);\n },\n\n /**\n * Writes data to the file at the given path.
\n * Due to security reasons, paths are limited to the qz data directory unless overridden via properties file.\n *\n * @param {string} path Relative or absolute file path. Must reside in qz data directory or a white-listed location.\n * @param {Object} params Object containing file access parameters\n * @param {string} params.data File data to be written\n * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections\n * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user\n * @param {boolean} [params.append=false] Appends to the end of the file if set, otherwise overwrites existing contents\n * @param {string} [params.flavor='plain'] Flavor of data format used, valid flavors are [base64 | file | hex | plain].\n * @returns {Promise}\n *\n * @memberof qz.file\n */\n write: function(path, params) {\n var param = _qz.tools.extend({ path: path }, params);\n return _qz.websocket.dataPromise('file.write', param);\n },\n\n /**\n * Deletes a file at given path.
\n * Due to security reasons, paths are limited to the qz data directory unless overridden via properties file.\n *\n * @param {string} path Relative or absolute file path. Must reside in qz data directory or a white-listed location.\n * @param {Object} [params] Object containing file access parameters\n * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections\n * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user\n * @returns {Promise}\n *\n * @memberof qz.file\n */\n remove: function(path, params) {\n var param = _qz.tools.extend({ path: path }, params);\n return _qz.websocket.dataPromise('file.remove', param);\n },\n\n /**\n * Provides a continuous stream of events (and optionally data) from a local file.\n *\n * @param {string} path Relative or absolute directory path. Must reside in qz data directory or a white-listed location.\n * @param {Object} [params] Object containing file access parameters\n * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections\n * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user\n * @param {Object} [params.listener] If defined, file data will be returned on events\n * @param {number} [params.listener.bytes=-1] Number of bytes to return or -1 for all\n * @param {number} [params.listener.lines=-1] Number of lines to return or -1 for all\n * @param {boolean} [params.listener.reverse] Controls whether data should be returned from the bottom of the file. Default value is true for line mode and false for byte mode.\n * @param {string|Array} [params.include] File patterns to match. Blank values will be ignored.\n * @param {string|Array} [params.exclude] File patterns to exclude. Blank values will be ignored. Takes priority over params.include.\n * @param {boolean} [params.ignoreCase=true] Whether params.include or params.exclude are case-sensitive.\n * @returns {Promise}\n * @since 2.1.0\n *\n * @see qz.file.setFileCallbacks\n *\n * @memberof qz.file\n */\n startListening: function(path, params) {\n if (params && typeof params.include !== 'undefined' && !Array.isArray(params.include)) {\n params.include = [params.include];\n }\n if (params && typeof params.exclude !== 'undefined' && !Array.isArray(params.exclude)) {\n params.exclude = [params.exclude];\n }\n var param = _qz.tools.extend({ path: path }, params);\n return _qz.websocket.dataPromise('file.startListening', param);\n },\n\n /**\n * Closes listeners with the provided settings. Omitting the path parameter will result in all listeners closing.\n *\n * @param {string} [path] Previously opened directory path of listener to close, or omit to close all.\n * @param {Object} [params] Object containing file access parameters\n * @param {boolean} [params.sandbox=true] If relative location from root is only available to the certificate's connection, otherwise all connections\n * @param {boolean} [params.shared=true] If relative location from root is accessible to all users on the system, otherwise just the current user\n * @returns {Promise}\n *\n * @memberof qz.file\n */\n stopListening: function(path, params) {\n var param = _qz.tools.extend({ path: path }, params);\n return _qz.websocket.dataPromise('file.stopListening', param);\n },\n\n /**\n * List of functions called for any response from a file listener.\n * For ERROR types event data will contain, {string} message.\n * For ACTION types event data will contain, {string} file {string} eventType {string} [data].\n *\n * @param {Function|Array} calls Single or array of Function({Object} eventData) calls.\n * @since 2.1.0\n *\n * @memberof qz.file\n */\n setFileCallbacks: function(calls) {\n _qz.file.fileCallbacks = calls;\n }\n },\n\n /**\n * Calls related to networking information\n * @namespace qz.networking\n * @since 2.1.0\n */\n networking: {\n /**\n * @param {string} [hostname] Hostname to try to connect to when determining network interfaces, defaults to \"google.com\"\n * @param {number} [port] Port to use with custom hostname, defaults to 443\n * @returns {Promise} Connected system's network information.\n *\n * @memberof qz.networking\n * @since 2.1.0\n */\n device: function(hostname, port) {\n // Wrap 2.0\n if (_qz.tools.isVersion(2, 0)) {\n return _qz.compatible.networking(hostname, port, null, null, function(data) {\n return { ip: data.ipAddress, mac: data.macAddress };\n });\n }\n // Use 2.1\n return _qz.websocket.dataPromise('networking.device', {\n hostname: hostname,\n port: port\n });\n },\n\n /**\n * Get computer hostname\n *\n * @param {string} [hostname] DEPRECATED Hostname to try to connect to when determining network interfaces, defaults to \"google.com\"\n * @param {number} [port] DEPRECATED Port to use with custom hostname, defaults to 443\n * @returns {Promise} Connected system's hostname.\n *\n * @memberof qz.networking\n * @since 2.2.2\n */\n hostname: function(hostname, port) {\n // Wrap < 2.2.2\n if (_qz.tools.versionCompare(2, 2, 2) < 0) {\n return _qz.tools.promise(function(resolve, reject) {\n _qz.websocket.dataPromise('networking.device', { hostname: hostname, port: port }).then(function(device) {\n console.log(device);\n resolve(device.hostname);\n });\n });\n } else {\n return _qz.websocket.dataPromise('networking.hostname');\n }\n },\n\n /**\n * @param {string} [hostname] Hostname to try to connect to when determining network interfaces, defaults to \"google.com\"\n * @param {number} [port] Port to use with custom hostname, defaults to 443\n * @returns {Promise|Error>} Connected system's network information.\n *\n * @memberof qz.networking\n * @since 2.1.0\n */\n devices: function(hostname, port) {\n // Wrap 2.0\n if (_qz.tools.isVersion(2, 0)) {\n return _qz.compatible.networking(hostname, port, null, null, function(data) {\n return [{ ip: data.ipAddress, mac: data.macAddress }];\n });\n }\n // Use 2.1\n return _qz.websocket.dataPromise('networking.devices', {\n hostname: hostname,\n port: port\n });\n }\n },\n\n\n /**\n * Calls related to signing connection requests.\n * @namespace qz.security\n */\n security: {\n /**\n * Set promise resolver for calls to acquire the site's certificate.\n *\n * @param {Function|AsyncFunction|Promise} promiseHandler Either a function that will be used as a promise resolver (of format Function({function} resolve, {function}reject)),\n * an async function, or a promise. Any of which should return the public certificate via their respective resolve call.\n * @param {Object} [options] Configuration options for the certificate resolver\n * @param {boolean} [options.rejectOnFailure=[false]] Overrides default behavior to call resolve with a blank certificate on failure.\n * @memberof qz.security\n */\n setCertificatePromise: function(promiseHandler, options) {\n _qz.security.certHandler = promiseHandler;\n _qz.security.rejectOnCertFailure = !!(options && options.rejectOnFailure);\n },\n\n /**\n * Set promise factory for calls to sign API calls.\n *\n * @param {Function|AsyncFunction} promiseFactory Either a function that accepts a string parameter of the data to be signed\n * and returns a function to be used as a promise resolver (of format Function({function} resolve, {function}reject)),\n * or an async function that can take a string parameter of the data to be signed. Either of which should return the signed contents of\n * the passed string parameter via their respective resolve call.\n *\n * @example\n * qz.security.setSignaturePromise(function(dataToSign) {\n * return function(resolve, reject) {\n * $.ajax(\"/signing-url?data=\" + dataToSign).then(resolve, reject);\n * }\n * })\n *\n * @memberof qz.security\n */\n setSignaturePromise: function(promiseFactory) {\n _qz.security.signatureFactory = promiseFactory;\n },\n\n /**\n * Set which signing algorithm QZ will check signatures against.\n *\n * @param {string} algorithm The algorithm used in signing. Valid values: [SHA1 | SHA256 | SHA512]\n * @since 2.1.0\n *\n * @memberof qz.security\n */\n setSignatureAlgorithm: function(algorithm) {\n //warn for incompatibilities if known\n if (!_qz.compatible.algorithm()) {\n return;\n }\n\n if ([\"SHA1\", \"SHA256\", \"SHA512\"].indexOf(algorithm.toUpperCase()) < 0) {\n _qz.log.error(\"Signing algorithm '\" + algorithm + \"' is not supported.\");\n } else {\n _qz.security.signAlgorithm = algorithm;\n }\n },\n\n /**\n * Get the signing algorithm QZ will be checking signatures against.\n *\n * @returns {string} The algorithm used in signing.\n * @since 2.1.0\n *\n * @memberof qz.security\n */\n getSignatureAlgorithm: function() {\n return _qz.security.signAlgorithm;\n }\n },\n\n /**\n * Calls related to compatibility adjustments\n * @namespace qz.api\n */\n api: {\n /**\n * Show or hide QZ api debugging statements in the browser console.\n *\n * @param {boolean} show Whether the debugging logs for QZ should be shown. Hidden by default.\n * @returns {boolean} Value of debugging flag\n * @memberof qz.api\n */\n showDebug: function(show) {\n return (_qz.DEBUG = show);\n },\n\n /**\n * Get version of connected QZ Tray application.\n *\n * @returns {Promise} Version number of QZ Tray.\n *\n * @memberof qz.api\n */\n getVersion: function() {\n return _qz.websocket.dataPromise('getVersion');\n },\n\n /**\n * Checks for the specified version of connected QZ Tray application.\n *\n * @param {string|number} [major] Major version to check\n * @param {string|number} [minor] Minor version to check\n * @param {string|number} [patch] Patch version to check\n *\n * @memberof qz.api\n */\n isVersion: _qz.tools.isVersion,\n\n /**\n * Checks if the connected QZ Tray application is greater than the specified version.\n *\n * @param {string|number} major Major version to check\n * @param {string|number} [minor] Minor version to check\n * @param {string|number} [patch] Patch version to check\n * @param {string|number} [build] Build version to check\n * @returns {boolean} True if connected version is greater than the version specified.\n *\n * @memberof qz.api\n * @since 2.1.0-4\n */\n isVersionGreater: function(major, minor, patch, build) {\n return _qz.tools.versionCompare(major, minor, patch, build) > 0;\n },\n\n /**\n * Checks if the connected QZ Tray application is less than the specified version.\n *\n * @param {string|number} major Major version to check\n * @param {string|number} [minor] Minor version to check\n * @param {string|number} [patch] Patch version to check\n * @param {string|number} [build] Build version to check\n * @returns {boolean} True if connected version is less than the version specified.\n *\n * @memberof qz.api\n * @since 2.1.0-4\n */\n isVersionLess: function(major, minor, patch, build) {\n return _qz.tools.versionCompare(major, minor, patch, build) < 0;\n },\n\n /**\n * Change the promise library used by QZ API.\n * Should be called before any initialization to avoid possible errors.\n *\n * @param {Function} promiser Function({function} resolver) called to create new promises.\n *\n * @memberof qz.api\n */\n setPromiseType: function(promiser) {\n _qz.tools.promise = promiser;\n },\n\n /**\n * Change the SHA-256 hashing function used by QZ API.\n * Should be called before any initialization to avoid possible errors.\n *\n * @param {Function} hasher Function({function} message) called to create hash of passed string.\n *\n * @memberof qz.api\n */\n setSha256Type: function(hasher) {\n _qz.tools.hash = hasher;\n },\n\n /**\n * Change the WebSocket handler.\n * Should be called before any initialization to avoid possible errors.\n *\n * @param {Function} ws Function({function} WebSocket) called to override the internal WebSocket handler.\n *\n * @memberof qz.api\n */\n setWebSocketType: function(ws) {\n _qz.tools.ws = ws;\n }\n },\n\n /**\n * Version of this JavaScript library\n *\n * @constant {string}\n *\n * @memberof qz\n */\n version: _qz.VERSION\n };\n\n return qz;\n})();\n\n\n(function() {\n if (typeof define === 'function' && define.amd) {\n define(qz);\n } else if (typeof exports === 'object') {\n module.exports = qz;\n } else {\n window.qz = qz;\n }\n})();\n"],"sourceRoot":""}