diff --git a/.gitignore b/.gitignore index 65e13a3..c945875 100644 --- a/.gitignore +++ b/.gitignore @@ -1,106 +1,27 @@ -/localdb +# Binary dumps from StageLinq library +localdb/ +waveform.bin + +# JS compiled dist/ # Logs logs *.log +log.txt -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories +# NodeJS directories node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ # TypeScript cache *.tsbuildinfo -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# Next.js build output -.next - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and *not* Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ +# VSCode configs +.vscode/ +*.code-workspace -# TernJS port file -.tern-port +# Mac Finder junk +.DS_Store -log.txt \ No newline at end of file +# Scratch folder +_scratch_ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 9514b4b..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Launch JS", - "program": "${workspaceFolder}/dist/cli.js", - "internalConsoleOptions": "openOnSessionStart", - "sourceMaps": true, - "smartStep": true, - "outputCapture": "std", - "skipFiles": [ - "${workspaceFolder}/node_modules/**/*.js", - "${workspaceFolder}/lib/**/*.js", - "/**/*.js" - ] - }, - { - "type": "node", - "request": "launch", - "name": "Launch TS", - "program": "${workspaceFolder}/cli/index.ts", - "preLaunchTask": "tsc: build - tsconfig.json", - "internalConsoleOptions": "openOnSessionStart", - "outFiles": ["${workspaceFolder}/dist/**/*.js"], - "sourceMaps": true, - "smartStep": true, - "outputCapture": "std", - "skipFiles": [ - "${workspaceFolder}/node_modules/**/*.js", - "${workspaceFolder}/lib/**/*.js", - "/**/*.js" - ] - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 3b20c71..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "type": "typescript", - "tsconfig": "tsconfig.json", - "option": "watch", - "presentation": { - "echo": true, - "reveal": "silent", - "focus": false, - "panel": "shared" - }, - "isBackground": true, - "runOptions": { "runOn": "folderOpen" }, - "problemMatcher": ["$tsc-watch"], - "group": { - "kind": "build", - "isDefault": true - }, - "label": "tsc: watch - tsconfig.json" - } - ] -} diff --git a/Databases/Databases.ts b/Databases/Databases.ts deleted file mode 100644 index efbd433..0000000 --- a/Databases/Databases.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { ConnectionInfo, Source } from '../types'; -import { EventEmitter } from 'stream'; -import { FileTransfer } from '../services'; -import { getTempFilePath } from '../utils'; -import { Logger } from '../LogEmitter'; -import { NetworkDevice } from '../network'; -import * as fs from 'fs'; - -export declare interface Databases { - on(event: 'dbDownloaded', listener: (sourceName: string, dbPath: string) => void): this; - on(event: 'dbDownloading', listener: (sourceName: string, dbPath: string) => void): this; - on(event: 'dbProgress', listener: (sourceName: string, total: number, bytesDownloaded: number, percentComplete: number) => void): this; -} - -export class Databases extends EventEmitter { - - sources: Map = new Map(); - - constructor() { - super(); - } - - async downloadSourcesFromDevice(connectionInfo: ConnectionInfo, networkDevice: NetworkDevice) { - const service = await networkDevice.connectToService(FileTransfer); - const sources = await service.getSources(); - const output: string[] = []; - for (const source of sources) { - const deviceId = /(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/i - .exec(Buffer.from(connectionInfo.token).toString('hex')).splice(1).join('-'); - const dbConnectionName = `net://${deviceId}/${source.name}`; - Logger.debug(`DB network path: ${dbConnectionName}`); - if (this.sources.has(dbConnectionName)) { - Logger.debug(`Already seen ${source} on ${connectionInfo.address}:${connectionInfo.port}`); - } else { - await this.downloadDb(dbConnectionName, service, source); - output.push(dbConnectionName); - } - } - return output; - } - - /** - * Download databases from this network source. - */ - async downloadDb(sourceId: string, service: FileTransfer, source: Source) { - const dbPath = getTempFilePath(`${sourceId}/m.db`); - - // Read database from source - Logger.debug(`Reading database ${sourceId}`); - this.emit('dbDownloading', sourceId, dbPath); - - service.on('fileTransferProgress', (progress) => { - this.emit('dbProgress', sourceId, progress.total, progress.bytesDownloaded, progress.percentComplete); - }); - - // Save database to a file - await service.waitTillAvailable(); - const file = await service.getFile(source.database.location); - Logger.debug(`Saving ${sourceId} to ${dbPath}`); - fs.writeFileSync(dbPath, Buffer.from(file)); - this.sources.set(sourceId, dbPath); - - Logger.debug(`Downloaded ${sourceId} to ${dbPath}`); - this.emit('dbDownloaded', sourceId, dbPath); - } - - getDbPath(dbSourceName?: string) { - if (!this.sources.size) - throw new Error(`No data sources have been downloaded`); - - if (!dbSourceName || !this.sources.has(dbSourceName)) { - - // Hack: Denon will save metadata on streaming files but only on an - // internal database. So if the source is "(Unknown)streaming://" - // return the first internal database we find. - for (const entry of Array.from(this.sources.entries())) { - if (/\(Internal\)/.test(entry[0])) { - Logger.debug(`Returning copy of internal database`); - return this.sources.get(entry[0]); - } - } - - // Else, throw an exception. - throw new Error(`Data source "${dbSourceName}" doesn't exist.`); - } - - return this.sources.get(dbSourceName); - } - -} diff --git a/Databases/DbConnection.ts b/Databases/DbConnection.ts deleted file mode 100644 index 0b3819f..0000000 --- a/Databases/DbConnection.ts +++ /dev/null @@ -1,51 +0,0 @@ -import Database = require('better-sqlite3'); -import { Track } from '../types'; - - -export class DbConnection { - - private db: Database.Database; - private dbPath: string; - - constructor(dbPath: string) { - this.dbPath = dbPath; - console.debug(`Opening ${this.dbPath}`); - this.db = new Database(this.dbPath); - } - - /** - * Execute a SQL query. - * - * @param query SQL query to execute - * @param params Parameters for BetterSqlite3 result.all. - * @returns - */ - querySource(query: string, ...params: any[]): T[] { - console.debug(`Querying ${this.dbPath}: ${query} (${params.join(', ')})`); - const result = this.db.prepare(query); - return result.all(params); - } - - /** - * Return track's DB entry. - * - * @param trackPath Path of track on the source's filesystem. - * @returns - */ - getTrackInfo(trackPath: string): Track { - let result: Track[]; - if (/streaming:\/\//.test(trackPath)) { - result = this.querySource('SELECT * FROM Track WHERE uri = (?) LIMIT 1', trackPath); - } else { - result = this.querySource('SELECT * FROM Track WHERE path = (?) LIMIT 1', trackPath); - } - if (!result) throw new Error(`Could not find track: ${trackPath} in database.`); - return result[0]; - } - - close() { - console.debug(`Closing ${this.dbPath}`); - this.db.close(); - } - -} diff --git a/Databases/index.ts b/Databases/index.ts deleted file mode 100644 index 63cefa1..0000000 --- a/Databases/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './Databases'; -export * from './DbConnection'; \ No newline at end of file diff --git a/Discovery/index.ts b/Discovery/index.ts new file mode 100644 index 0000000..2da64b5 --- /dev/null +++ b/Discovery/index.ts @@ -0,0 +1,238 @@ +import { EventEmitter } from 'events'; +import { Logger } from '../LogEmitter'; +import { strict as assert } from 'assert'; +import { ConnectionInfo, DiscoveryMessage, DiscoveryMessageOptions, IpAddress, Units, DeviceId } from '../types'; +import { sleep, WriteContext, ReadContext } from '../utils'; +import { Socket, RemoteInfo, createSocket } from 'dgram'; +import { subnet, SubnetInfo } from 'ip'; +import { networkInterfaces } from 'os'; + +const ANNOUNCEMENT_INTERVAL = 1000; +const LISTEN_PORT = 51337; +const DISCOVERY_MESSAGE_MARKER = 'airD'; + +enum Action { + Login = 'DISCOVERER_HOWDY_', + Logout = 'DISCOVERER_EXIT_', +} + +type DeviceDiscoveryCallback = (info: ConnectionInfo) => void; + +export declare interface Discovery { + on(event: 'newDiscoveryDevice', listener: (info: DiscoveryMessage) => void): this; + on(event: 'updatedDiscoveryDevice', listener: (info: DiscoveryMessage) => void): this; + on(event: 'announcing', listener: (info: DiscoveryMessage) => void): this; + on(event: 'listening', listener: () => void): this; +} + +export class Discovery extends EventEmitter { + private socket: Socket; + private address: IpAddress; + private broadcastAddress: IpAddress; + private options: DiscoveryMessageOptions = null; + private peers: Map = new Map(); + private deviceId: DeviceId = null; + private announceTimer: NodeJS.Timer; + + /** + * Get list of devices + * @returns {string[]} An array of DeviceId strings + */ + public getDeviceList(): string[] { + return [...this.peers.keys()]; + } + + /** + * Get array of device ConnectionInfos + * @returns {ConnectionInfo[]} An array of ConnectionInfos + */ + public getDevices(): ConnectionInfo[] { + return [...this.peers.values()]; + } + + /** + * Start Discovery Listener + * @param {DiscoveryMessageOptions} options + */ + listen(options: DiscoveryMessageOptions) { + this.options = options; + this.deviceId = options.deviceId; + + this.emit('listening'); + + this.listenForDevices((connectionInfo: ConnectionInfo) => this.emit('discoveryDevice', connectionInfo)); + } + + /** + * Announce library to network + * @param {number} port Port for Directory Service + */ + async announce(port: number) { + assert(this.socket); + this.socket.setBroadcast(true); + const discoveryMessage = this.createDiscoveryMessage(Action.Login, this.options, port); + await sleep(500); + const ips = this.findBroadcastIPs(); + const address = ips.filter((ip) => { + return ip.contains(this.address) === true; + }); + this.broadcastAddress = address.shift().broadcastAddress; + const msg = this.writeDiscoveryMessage(discoveryMessage); + this.broadcastMessage(this.socket, msg, LISTEN_PORT, this.broadcastAddress); + this.emit('announcing', discoveryMessage); + Logger.debug(`Broadcast Discovery Message ${this.deviceId.string} ${discoveryMessage.source}`); + this.announceTimer = setInterval( + this.broadcastMessage, + ANNOUNCEMENT_INTERVAL, + this.socket, + msg, + LISTEN_PORT, + this.broadcastAddress + ); + } + + /** + * Unanounce Library to network + */ + async unannounce(): Promise { + assert(this.announceTimer); + clearInterval(this.announceTimer); + this.announceTimer = null; + const discoveryMessage = this.createDiscoveryMessage(Action.Logout, this.options); + const msg = this.writeDiscoveryMessage(discoveryMessage); + + await this.broadcastMessage(this.socket, msg, LISTEN_PORT, this.broadcastAddress); + await this.socket.close(); + + Logger.debug('Broadcast Unannounce Message'); + } + + //////////// PRIVATE METHODS /////////////// + + /** + * Broadcast Discovery Message + * @param {Socket} socket + * @param {Buffer} msg + * @param {number} port + * @param {IpAddress} address + */ + private async broadcastMessage(socket: Socket, msg: Buffer, port: number, address: IpAddress): Promise { + await socket.send(msg, port, address); + } + + /** + * Listen for new devices on the network and callback when a new one is found. + * @param {DeviceDiscoveryCallback} callback Callback when new device is discovered. + */ + + private async listenForDevices(callback: DeviceDiscoveryCallback) { + this.socket = createSocket('udp4'); + this.socket.on('message', (announcement: Uint8Array, remote: RemoteInfo) => { + const ctx = new ReadContext(announcement.buffer, false); + const result = this.readConnectionInfo(ctx, remote.address); + if (!this.address) { + this.address = remote.address; + } + assert(ctx.tell() === remote.size); + callback(result); + }); + this.socket.bind({ + port: LISTEN_PORT, + exclusive: false, + }); + } + + /** + * Read Connection Info from Context + * @param {ReadContext} ctx + * @param {IpAddress} address + * @returns {ConnectionInfo} + */ + private readConnectionInfo(ctx: ReadContext, address: IpAddress): ConnectionInfo { + const magic = ctx.getString(4); + if (magic !== DISCOVERY_MESSAGE_MARKER) { + return null; + } + + const connectionInfo: ConnectionInfo = { + deviceId: new DeviceId(ctx.read(16)), + source: ctx.readNetworkStringUTF16(), + action: ctx.readNetworkStringUTF16(), + software: { + name: ctx.readNetworkStringUTF16(), + version: ctx.readNetworkStringUTF16(), + }, + port: ctx.readUInt16(), + address: address, + }; + + if (Units[connectionInfo.software.name]) { + connectionInfo.unit = Units[connectionInfo.software.name]; + } + + assert(ctx.isEOF()); + return connectionInfo; + } + + /** + * Create a Discovery Message + * @param {string} action + * @param {DiscoveryMessageOptions} discoveryMessageOptions + * @param {number} port + * @returns {DiscoveryMessage} + */ + private createDiscoveryMessage( + action: string, + discoveryMessageOptions: DiscoveryMessageOptions, + port?: number + ): DiscoveryMessage { + const msg: DiscoveryMessage = { + action: action, + port: port || 0, + deviceId: discoveryMessageOptions.deviceId, + software: { + name: discoveryMessageOptions.name, + version: discoveryMessageOptions.version, + }, + source: discoveryMessageOptions.source, + }; + return msg; + } + + /** + * + * @param {DiscoveryMessage} message + * @returns {Buffer} + */ + private writeDiscoveryMessage(message: DiscoveryMessage): Buffer { + const ctx = new WriteContext(); + ctx.writeFixedSizedString(DISCOVERY_MESSAGE_MARKER); + ctx.write(message.deviceId.array); + ctx.writeNetworkStringUTF16(message.source); + ctx.writeNetworkStringUTF16(message.action); + ctx.writeNetworkStringUTF16(message.software.name); + ctx.writeNetworkStringUTF16(message.software.version); + ctx.writeUInt16(message.port); + return ctx.getBuffer(); + } + + /** + * Get list of Broadcast-enabled Network Interfaces + * @returns {SubnetInfo[]} + */ + private findBroadcastIPs(): SubnetInfo[] { + const interfaces = Object.values(networkInterfaces()); + assert(interfaces.length); + const ips = []; + for (const i of interfaces) { + assert(i && i.length); + for (const entry of i) { + if (entry.family === 'IPv4' && entry.internal === false) { + const info = subnet(entry.address, entry.netmask); + ips.push(info); + } + } + } + return ips; + } +} diff --git a/LogEmitter/index.ts b/LogEmitter/index.ts index 613cbe5..fd0bce4 100644 --- a/LogEmitter/index.ts +++ b/LogEmitter/index.ts @@ -1,51 +1,87 @@ import { EventEmitter } from 'stream'; +import * as fs from 'fs'; export declare interface Logger { - on(event: 'log', listener: (...args: any) => void): this; - on(event: 'error', listener: (...args: any) => void): this; - on(event: 'warn', listener: (...args: any) => void): this; - on(event: 'info', listener: (...args: any) => void): this; - on(event: 'debug', listener: (...args: any) => void): this; - on(event: 'silly', listener: (...args: any) => void): this; - on(event: 'any', listener: (...args: any) => void): this; + on(event: 'log', listener: (...args: any) => void): this; + on(event: 'error', listener: (...args: any) => void): this; + on(event: 'warn', listener: (...args: any) => void): this; + on(event: 'info', listener: (...args: any) => void): this; + on(event: 'debug', listener: (...args: any) => void): this; + on(event: 'silly', listener: (...args: any) => void): this; + on(event: 'any', listener: (...args: any) => void): this; } export class Logger extends EventEmitter { + private logStream: fs.WriteStream = null; + private static _instance: Logger; + private timeStart: number; - private static _instance: Logger; - - static get instance() { - return this._instance || (this._instance = new this()); - } - - static log(...args: any) { - Logger.instance.emit('log', ...args); - Logger.instance.emit('any', ...args); - } - - static error(...args: any) { - Logger.instance.emit('error', ...args); - Logger.instance.emit('any', ...args); - } - - static warn(...args: any) { - Logger.instance.emit('warn', ...args); - Logger.instance.emit('any', ...args); - } - - static info(...args: any) { - Logger.instance.emit('info', ...args); - Logger.instance.emit('any', ...args); - } - - static debug(...args: any) { - Logger.instance.emit('debug', ...args); - Logger.instance.emit('any', ...args); - } - - static silly(...args: any) { - Logger.instance.emit('silly', ...args); - Logger.instance.emit('any', ...args); - } + + /** + * Logger Utility Class + * @param {string} _fileName + */ + constructor(_fileName?: string) { + super(); + const fileName = _fileName || 'log.txt'; + this.logStream = fs.createWriteStream(fileName);//, {flags: 'a'}); + const hrTime = process.hrtime(); + const logTime = Math.floor((hrTime[0] * 1000000 + hrTime[1] / 1000)); + this.timeStart = logTime; + this.logEntry('[BEGIN]\n'); + } + + static get instance() { + return this._instance || (this._instance = new this()); + } + + private logEntry(...args: any) { + const hrTime = process.hrtime(); + const logTime = Math.floor((hrTime[0] * 1000000 + hrTime[1] / 1000)); + this.logStream.write(`[${logTime - this.timeStart}] ${[args.join(' ')]}\n`); + + } + + static log(...args: any) { + Logger.instance.emit('log', ...args); + Logger.instance.emit('any', ...args); + Logger.instance.logEntry(...args); + } + + static error(...args: any) { + Logger.instance.emit('error', ...args); + Logger.instance.emit('any', ...args); + Logger.instance.logEntry(...args); + } + + static warn(...args: any) { + Logger.instance.emit('warn', ...args); + Logger.instance.emit('any', ...args); + Logger.instance.logEntry(...args); + } + + static info(...args: any) { + Logger.instance.emit('info', ...args); + Logger.instance.emit('any', ...args); + Logger.instance.logEntry(...args); + } + + static debug(...args: any) { + Logger.instance.emit('debug', ...args); + Logger.instance.emit('any', ...args); + Logger.instance.logEntry(...args); + } + + static silly(...args: any) { + Logger.instance.emit('silly', ...args); + Logger.instance.emit('any', ...args); + Logger.instance.logEntry(...args); + } + + static silent(...args: any) { + //Logger.instance.emit('silly', ...args); + Logger.instance.emit('any', ...args); + Logger.instance.logEntry(...args); + } } \ No newline at end of file diff --git a/README.md b/README.md index 3e360cb..71db3ea 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,259 @@ -# StageLinq +# StageLinqJS - A Robust Implementation of StageLinq Library -NodeJS library implementation to access information through the Denon StageLinq protocol. +## Description +This branch implements the methods demonstrated previously in the StageLinq Listener branch. +Rather than searching out devices via discovery, we are able to have devices initiate connections to the library. As demonstrated, this approach: +* Greatly reduces complexity. -# Features +* Speeds up the connection & initialization process (almost every sleep() call has been eliminated without and affect thus far). -* Tested with Denon two SC6000s, X1850, Prime 4, Prime 2, and Prime Go. -* Event emitters for state changes, tracks getting loaded, and current playing track. -* Event emitter for debug logging. -* Downloads source databases for you. -* You can implement handling the database yourself or use this library's BetterSqlite3 dependency. +* Handles disconnection and reconnection of devices gracefully and simply. ---- +* Allows connections from devices we couldn't use previously (i.e. x1800/x1850 mixers). -## Usage +## Notes on Terminilogy + +An effort has been made to standardize the syntax used in the library, and to be consitent with the syntax Denon uses (when they have, in fact, been consistent themselves). + +### Physical & Network +| Syntax | Description | Example | +| --- | --- | --- | +| Unit | A discrete physical player, controller, or mixer | SC600, PRIME4, X1850 | +| Device | A unique StageLinq network entity, represented by a DeviceId | _See DeviceId_ +| Service | An instance of a particular Service endpoint | StateMap, FileTransfer, BeatInfo | +| DeviceId | The GUID representing a StageLinq Device. | 12345678-1234-1234-1234-123456789ABC | + +### Software & States +| Syntax | Description | Example | +| --- | --- | --- | +| Deck (1..4) | A singular music-playing instance on a Unit | An SC5000 has 2 Decks, A PRIME4 has 4 Decks | +| Layer (A..B) | For switching between two Decks on a Unit | Layer A is Deck 1, Layer B is Deck 2 | +| Track | A music file loaded on a Deck | | +| Song | Sometimes used interchangabley with Track in some State names | | + + + + +## Implementing Selected Services +We can choose which services to implement by including them in the `StageLinqOptions` parameter passed to Stagelinq on initialization. +```ts +const stageLinqOptions: StageLinqOptions = { + downloadDbSources: true, + actingAs: ActingAsDevice.StageLinqJS, + services: [ + Services.StateMap, + Services.BeatInfo, + Services.FileTransfer, + ], +} +``` + +## Starting StageLinq + +The main StageLinq class is now a Static Class: +```ts +StageLinq.options = stageLinqOptions; + +await StageLinq.connect(); +await StageLinq.disconnect(); +``` + + +## Discovery +Discovery emits a number of messages which may be helpful when debugging. ```ts -import { StageLinq } from '../StageLinq'; +StageLinq.discovery.on('listening', () => { + console.log(`[DISCOVERY] Listening`) +}); -const options = { downloadDbSources: true }; -const stageLinq = new StageLinq(options); +StageLinq.discovery.on('announcing', (info) => { + console.log(`[DISCOVERY] Broadcasting Announce ${info.deviceId.string} Port ${info.port} ${info.source} ${info.software.name}:${info.software.version}`) +}); -stageLinq.devices.on('ready', (connectionInfo) => { - console.log(`Device ${connectionInfo.software.name} on ` + - `${connectionInfo.address}:${connectionInfo.port} is ready.`); +StageLinq.discovery.on('newDiscoveryDevice', (info) => { + console.log(`[DISCOVERY] New Device ${info.deviceId.string} ${info.source} ${info.software.name} ${info.software.version}`) }); -stageLinq.devices.on('trackLoaded', (status) => { - console.log(`"${status.title}" - ${status.artist} loaded on player ` + - `${status.deck})`); +StageLinq.discovery.on('updatedDiscoveryDevice', (info) => { + console.log(`[DISCOVERY] Updated Device ${info.deviceId.string} Port:${info.port} ${info.source} ${info.software.name} ${info.software.version}`) +}); +``` + +`updatedDiscoveryDevice` is emitted when a Device is broadcasting a new Directory port, which is indicative of a reset. The Device should automatically reconnect without any action required from the user. + +Discovery offers a few methods for getting ConnectionInfos for Devices on the network: +```ts +/** + * Get ConnectionInfo + * @param {DeviceId} deviceId + * @returns {ConnectionInfo} + */ +public getConnectionInfo(deviceId: DeviceId): ConnectionInfo { + return this.peers.get(deviceId.string); +} + +/** + * Get list of devices + * @returns {string[]} An array of DeviceId strings + */ +public getDeviceList(): string[] { + return [...this.peers.keys()] +} + +/** + * Get array of device ConnectionInfos + * @returns {ConnectionInfo[]} An array of ConnectionInfos + */ +public getDevices(): ConnectionInfo[] { + return [...this.peers.values()] +} +``` + + + +## StateMap + + +```ts +StateMap.emitter.on('newDevice', (service: StateMapDevice) => { + console.log(`[STATEMAP] Subscribing to States on ${service.deviceId.string}`); + service.subscribe(); }); -stageLinq.devices.on('nowPlaying', (status) => { - console.log(`Now Playing: "${status.title}" - ${status.artist})`); +StateMap.emitter.on('stateMessage', async (data: StateData) => { + console.log(`[STATEMAP] ${data.deviceId.string} ${data.name} => ${JSON.stringify(data.json)}`); + }); +``` + +### Using NowPlaying-type updates from StageLinq.status + +```ts +async function deckIsMaster(data: StateData) { + if (data.json.state) { + const deck = parseInt(data.name.substring(12, 13)) + await sleep(250); + const track = stageLinq.status.getTrack(data.deviceId, deck) + console.log(`Now Playing: `, track) + } +} + +async function songLoaded(data: StateData) { + if (data.json.state) { + const deck = parseInt(data.name.substring(12, 13)) + await sleep(250); + const track = stageLinq.status.getTrack(data.deviceId, deck) + console.log(`Track Loaded: `, track) + if (stageLinq.fileTransfer && stageLinq.options.downloadDbSources) { + const trackInfo = await getTrackInfo(stageLinq, track.source.name, track.source.location, track.TrackNetworkPath); + console.log('Track DB Info: ', trackInfo) + downloadFile(stageLinq, track.source.name, track.source.location, track.source.path, Path.resolve(os.tmpdir())); + } + } +} + +StateMap.emitter,on('newDevice', async (service: StateMapDevice) => { + console.log(`[STATEMAP] Subscribing to States on ${service.deviceId.string}`); + + const info = StageLinq.devices.device(service.deviceId).info + for (let i = 1; i <= info.unit.decks; i++) { + service.addListener(`/Engine/Deck${i}/DeckIsMaster`, deckIsMaster); + service.addListener(`/Engine/Deck${i}/Track/SongLoaded`, songLoaded); + } + service.subscribe(); }); ``` -A [complete example](https://github.com/chrisle/StageLinq/blob/main/cli/index.ts) with all events and options can be found in the CLI. +## FileTransfer & Sources + +```ts +FileTransfer.emitter.on('fileTransferProgress', (source, file, txid, progress) => { + console.log(`[FILETRANSFER] ${source.name} id:{${txid}} Reading ${file}: ${progressBar(10, progress.bytesDownloaded, progress.total)} (${Math.ceil(progress.percentComplete)}%)`); +}); ---- +FileTransfer.emitter.on('fileTransferComplete', (source, file, txid) => { + console.log(`[FILETRANSFER] Complete ${source.name} id:{${txid}} ${file}`); +}); -## Overview +StageLing.sources.on('newSource', (source: Source) => { + console.log(`[FILETRANSFER] Source Available: (${source.name})`); +}); -The idea behind this library is to have a structure something like this: +StageLing.sources.on('sourceRemoved', (sourceName: string, deviceId: DeviceId) => { + console.log(`[FILETRANSFER] Source Removed: ${sourceName} on ${deviceId.string}`); +}); -**StageLinq > Devices > Player > Deck** +StageLing.sources.on('dbDownloaded', (source: Source) => { + console.log(`[FILETRANSFER] Database Downloaded: (${source.name})`); +}); +``` -A StageLinq sets up a device listener and a class that handles all the -devices (`StageLinqDevices`). +## BeatInfo -`StageLinqDevices` figures out if it wants to connect or not and handles -connections. There may be one or more device on the network. For each device it -will try to connect to it and subscribe to it's `StateMap`. +```ts +const beatOptions = { + // Resolution for triggering callback + // 0 = every message WARNING, it's a lot! + // 1 = every beat + // 4 = every 4 beats + // .25 = every 1/4 beat + everyNBeats: 1, +} + +// User callback function. +// Will be triggered everytime a player's beat counter crosses the resolution threshold +function beatCallback(bd: BeatData,) { + let deckBeatString = "" + for (let i = 0; i < bd.deckCount; i++) { + deckBeatString += `Deck: ${i + 1} Beat: ${bd.deck[i].beat.toFixed(3)}/${bd.deck[i].totalBeats.toFixed(0)} ` + } + console.log(`[BEATINFO] ${bd.deviceId.string} clock: ${bd.clock} ${deckBeatString}`); +} + +//// callback is optional, BeatInfo messages can be consumed by: +// - user callback +// - event messages +// - reading the register +const beatMethod = { + useCallback: true, + useEvent: false, + useRegister: false, +}; -Currently there is only one type of device: `Player`. A `Player` may have up to -4 decks A, B, C, D (aka "layers"). The `Player` handles incoming messages, -parses them, groups them, and emits events. These events bubble up to the -`Device`. -## Database +BeatInfo.emitter.on('newDevice', async (beatInfo: BeatInfo) => { + console.log(`[BEATINFO] New Device ${beatInfo.deviceId.string}`) -You can use BetterSqlite3 bundled into this library or let this library -download the files for you, then choose your own Sqlite library to -query the database. See CLI example. + if (beatMethod.useCallback) { + beatInfo.startBeatInfo(beatOptions, beatCallback); + } -## Logging + if (beatMethod.useEvent) { + beatInfo.startBeatInfo(beatOptions); + BeatInfo.emitter.on('beatMsg', (bd) => { + if (bd.message) { + beatCallback(bd); + } + }); + } -I needed the logging to be used outside of the library so I made them events -that you can listen to. + if (beatMethod.useRegister) { + beatInfo.startBeatInfo(beatOptions); -* `error`: When something bad happens. -* `warn`: When something happens but doesn't affect anything. -* `info`/`log`: When we have something to say -* `debug`: Spits out the parsed version of the packets. -* `silly`: Dumps all kinds of internal stuff + function beatFunc(beatInfo: BeatInfo) { + const beatData = beatInfo.getBeatData(); + if (beatData) beatCallback(beatData); + } + + setTimeout(beatFunc, 4000, beatInfo) + } +}) + +``` -## About -Forked from @MarByteBeep's code. +## Additional Notes on the Listener Method -Additional reverse engineering work: https://github.com/chrisle/stagelinq-pcap +* The Directory service is the only one which is *required* as it is the initial connection endpoint for remote devices. -Used in my app Now Playing https://www.nowplaying2.com +* Only tokens of a specific structure seem to work, otherwise devices won't initiate a connection. One requirement *seems* to be that they start with `0xFFFFFFFFFFFF`, but some more research into this is needed. \ No newline at end of file diff --git a/Sources/DbConnection.ts b/Sources/DbConnection.ts new file mode 100644 index 0000000..5f9f91f --- /dev/null +++ b/Sources/DbConnection.ts @@ -0,0 +1,92 @@ +import Database = require('better-sqlite3'); +import { TrackDBEntry } from '../types'; +import { Logger } from '../LogEmitter'; +import { inflate } from 'zlib' + +export class DbConnection { + private db: Database.Database; + private dbPath: string; + /** + * Create a SQLite DB Interface + * @constructor + * @param {string} dbPath file path to SQLite.db file + */ + constructor(dbPath: string) { + this.dbPath = dbPath; + Logger.debug(`Opening ${this.dbPath}`); + this.db = new Database(this.dbPath); + this.db.pragma('journal_mode = WAL'); + } + + /** + * Execute a SQL query. + * + * @param {string} query SQL query to execute + * @param {any} params Parameters for BetterSqlite3 result.all. + * @returns + */ + querySource(query: string, ...params: any[]): T[] { + Logger.debug(`Querying ${this.dbPath}: ${query} (${params.join(', ')})`); + const result = this.db.prepare(query); + return result.all(params); + } + + /** + * Inflate Zlib compressed data + * @param {Buffer} data + * @returns {Promise} Zlib inflated data + */ + private async zInflate(data: Buffer): Promise { + return new Promise((resolve, reject) => { + inflate(data.slice(4), (err, buffer) => { + if (err) { + reject(err); + } else { + resolve(buffer); + } + }); + }); + } + + /** + * Return track's DB entry. + * + * @param {string} _trackPath Path of track on the source's filesystem. + * @returns {Promise} + */ + async getTrackInfo(_trackPath: string): Promise { + const trackPath = _trackPath.split('/').slice(5, _trackPath.length).join('/') + const result: TrackDBEntry[] = this.querySource('SELECT * FROM Track WHERE path = (?) LIMIT 1', trackPath); + if (!result) throw new Error(`Could not find track: ${trackPath} in database.`); + + result[0].trackData = await this.zInflate(result[0].trackData); + result[0].overviewWaveFormData = await this.zInflate(result[0].overviewWaveFormData); + result[0].beatData = await this.zInflate(result[0].beatData); + + return result[0]; + } + + /** + * + * @param {number} id /ID of track in the database + * @returns {Promise} + */ + async getTrackById(id: number): Promise { + const result: TrackDBEntry[] = this.querySource('SELECT * FROM Track WHERE id = (?) LIMIT 1', id); + if (!result) throw new Error(`Could not find track id: ${id} in database.`); + result[0].trackData = await this.zInflate(result[0].trackData); + result[0].overviewWaveFormData = await this.zInflate(result[0].overviewWaveFormData); + result[0].beatData = await this.zInflate(result[0].beatData); + return result[0]; + } + + + /** + * Close DB Connection + */ + close() { + Logger.debug(`Closing ${this.dbPath}`); + this.db.close(); + } + +} diff --git a/Sources/index.ts b/Sources/index.ts new file mode 100644 index 0000000..f8f764f --- /dev/null +++ b/Sources/index.ts @@ -0,0 +1,282 @@ +import { EventEmitter } from 'events'; +import { Services, DeviceId } from '../types'; +import { Logger } from '../LogEmitter'; +import * as fs from 'fs'; +import { DbConnection } from './DbConnection'; +import { getTempFilePath } from '../utils'; +import { StageLinq } from '../StageLinq'; +import { Broadcast, BroadcastMessage, FileTransfer } from '../services'; + + +export declare interface Sources { + /** + * + * @event newSource + */ + on(event: 'newSource', listener: (source: Source) => void): this; + on(event: 'sourceRemoved', listener: (sourceName: string, deviceId: DeviceId) => void): this; + on(event: 'dbDownloaded', listener: (source: Source) => void): this; +} + +export class Sources extends EventEmitter { + #sources: Map = new Map(); + + /** + * Sources EndPoint Class + */ + + + /** + * Check if sources has Source + * @param {string} sourceName - Name of source in EngineOS, eg: 'DJ STICK (USB 1)' + * @param {DeviceId} deviceId - DeviceID instance + * @returns {boolean} true if has source + */ + hasSource(sourceName: string, deviceId: DeviceId): boolean { + return this.#sources.has(`${deviceId.string}${sourceName}`); + } + + /** + * Check if sources has Source AND source has downloaded DB + * @param {string} sourceName - Name of source in EngineOS, eg: 'DJ STICK (USB 1)' + * @param {DeviceId} deviceId - DeviceID instance + * @returns {boolean} true if has Source AND the source has downloaded DB + */ + hasSourceAndDB(sourceName: string, deviceId: DeviceId): boolean { + const source = this.#sources.get(`${deviceId.string}${sourceName}`); + const dbs = source.getDatabases().filter(db => db.downloaded) + return (source && dbs.length) ? true : false + } + + /** + * Get Source + * @param {string} sourceName Name of source in EngineOS, eg: 'DJ STICK (USB 1)' + * @param {DeviceId} deviceId DeviceID instance + * @returns {Source} + */ + getSource(sourceName: string, deviceId: DeviceId): Source { + return this.#sources.get(`${deviceId.string}${sourceName}`); + } + + /** + * Get all Sources + * @param {DeviceId} [deviceId] Optional narrow results by DeviceId + * @returns {Source[]} an array of Sources + */ + getSources(deviceId?: DeviceId): Source[] { + if (deviceId) { + const filteredMap = new Map([...this.#sources.entries()].filter(entry => entry[0].substring(0, 36) == deviceId.string)) + return [...filteredMap.values()] + } + return [...this.#sources.values()] + } + + /** + * Add a new Source + * @param {Source} source + */ + setSource(source: Source) { + this.#sources.set(`${source.deviceId.string}${source.name}`, source); + this.emit('newSource', source); + } + + /** + * Delete Source + * @param {string} sourceName name of the source + * @param {DeviceId} deviceId + */ + deleteSource(sourceName: string, deviceId: DeviceId) { + this.#sources.delete(`${deviceId.string}${sourceName}`) + this.emit('sourceRemoved', sourceName, deviceId); + } + + /** + * Get Databases by UUID + * @param {string} uuid + * @returns {Database[]} + */ + getDBByUuid(uuid: string): Database[] { + const dbs = [...this.#sources.values()].map(src => src.getDatabases()).flat(1) + return dbs.filter(db => db.uuid == uuid) + } + + /** + * Download a file from Source + * @param {Source} source + * @param {string} path + * @returns {Promise} + */ + async downloadFile(source: Source, path: string): Promise { + const service = StageLinq.devices.device(source.deviceId).service('FileTransfer') as FileTransfer; + await service.isAvailable(); + + try { + const file = await service.getFile(source, path); + return file; + } catch (err) { + Logger.error(err); + throw new Error(err); + } + } + + /** + * Download DBs from source + * @param {Source} source + */ + async downloadDbs(source: Source) { + Logger.debug(`downloadDb request for ${source.name}`); + for (const database of source.getDatabases()) { + Logger.info(`downloading ${database.filename}`) + await database.downloadDb(); + } + this.emit('dbDownloaded', source); + this.setSource(source); + Logger.debug(`Downloaded ${source.deviceId.string}/${source.name}`); + } +} + +type DBInfo = { + id: number; + uuid: string; +} + +export class Source { + name: string; + deviceId: DeviceId; + #databases: Map = new Map(); + + /** + * Source Type Class + * @constructor + * @param {string} name + * @param {DeviceId} deviceId + */ + + + constructor(name: string, deviceId: DeviceId) { + this.name = name; + this.deviceId = deviceId; + } + /** + * Get a Database by File Name + * @param {string }name Filename eg "m.db" + * @returns {Database} + */ + getDatabase(name?: string): Database { + return this.#databases.get(name || "m.db") + } + + /** + * Get an array of all Databases + * @returns {Database[]} + */ + + getDatabases(): Database[] { + return [...this.#databases.values()] + } + + /** + * New Database Constructor + * @param {string} filename + * @param {number} size + * @param {string} remotePath + * @returns + */ + newDatabase(filename: string, size: number, remotePath: string): Database { + const db = new Database(filename, size, remotePath, this) + this.#databases.set(db.filename, db); + return db + } + +} + + +class Database { + deviceId: DeviceId = null; + size: number; + filename: string; + remotePath: string; + localPath: string = null; + uuid: string = null; + source: Source = null; + sourceName: string = null; + txid: number; + downloaded: boolean = false; + + /** + * Database Type Class + * @constructor + * @param {string} filename name of the file EG: 'm.db' + * @param {number} size size of the file + * @param {string} remotePath remote path (excl filename) of file + * @param {Source} source Source that the DB file is on + * @param {Transfer} transfer + */ + constructor(filename: string, size: number, remotePath: string, source: Source) { + this.filename = filename; + this.size = size; + this.remotePath = remotePath; + this.sourceName = source.name; + this.source = source; + this.deviceId = source.deviceId; + this.localPath = getTempFilePath(`${source.deviceId.string}/${source.name}/`); + } + + /** + * Get full remote path & filename + */ + get remoteDBPath() { + return `${this.remotePath}/${this.filename}` + } + + /** + * Get full local path & filename + */ + get localDBPath() { + return `${this.localPath}/${this.filename}` + } + + /** + * Create new Connection to the DB for Querying + * @returns {DbConnection} + */ + connection(): DbConnection { + return new DbConnection(this.localDBPath) + } + + + /** + * Downloads the Database + */ + async downloadDb() { + const source = StageLinq.sources.getSource(this.sourceName, this.deviceId) + const service = StageLinq.devices.device(this.deviceId).service("FileTransfer") as FileTransfer; + + Logger.info(`Reading database ${source.deviceId.string}/${source.name}/${this.filename}`); + const file = await service.getFile(source, this.remoteDBPath); + Logger.info(`Saving ${this.remoteDBPath}} to ${this.localDBPath}`); + fs.writeFileSync(this.localDBPath, Buffer.from(file)); + this.downloaded = true; + await this.processDB(); + Logger.info(`Downloaded ${source.deviceId.string}/${source.name} to ${this.remoteDBPath}`); + } + + private async processDB() { + const db = new DbConnection(this.localDBPath) + const result: DBInfo[] = await db.querySource('SELECT * FROM Information LIMIT 1') + this.uuid = result[0].uuid + db.close(); + + if (StageLinq.options.services.includes(Services.Broadcast)) { + Broadcast.emitter.addListener(this.uuid, (key, value) => this.broadcastListener(key, value)) + Logger.debug(`Sources added broadcast listener for ${this.uuid}`); + } + } + + private broadcastListener(key: string, value: BroadcastMessage) { + Logger.silly(`MSG FROM BROADCAST ${key}`, value); + // const service = StageLinq.devices.device(this.deviceId).service('FileTransfer') as FileTransfer + // service.getSourceDirInfo(this.source); + } + +} diff --git a/StageLinq/index.ts b/StageLinq/index.ts index c90736a..4246b2d 100644 --- a/StageLinq/index.ts +++ b/StageLinq/index.ts @@ -1,60 +1,75 @@ -import { announce, createDiscoveryMessage, StageLinqListener, unannounce } from '../network'; -import { EventEmitter } from 'events'; -import { StageLinqDevices } from '../network/StageLinqDevices'; +import { Discovery } from '../Discovery'; import { Logger } from '../LogEmitter'; -import { Action, ActingAsDevice, StageLinqOptions } from '../types'; +import { ActingAsDevice, StageLinqOptions, DeviceId } from '../types'; +import { Devices } from '../devices' +import { Sources } from '../Sources'; +import { Service, Directory } from '../services'; +import { Status } from '../status'; + const DEFAULT_OPTIONS: StageLinqOptions = { - maxRetries: 3, - actingAs: ActingAsDevice.NowPlaying, - downloadDbSources: true, - enableFileTranfer: true + actingAs: ActingAsDevice.StageLinqJS, + downloadDbSources: true, }; /** - * Main StageLinq class. + * Main StageLinq static class. */ -export class StageLinq extends EventEmitter { - - devices: StageLinqDevices; - logger: Logger = Logger.instance; - options: StageLinqOptions; - - private listener: StageLinqListener; - - constructor(options?: StageLinqOptions) { - super(); - this.options = { ...DEFAULT_OPTIONS, ...options }; - this.devices = new StageLinqDevices(this.options); - } - - /** - * Connect to the StageLinq network. - */ - async connect() { - this.listener = new StageLinqListener(); - const msg = createDiscoveryMessage(Action.Login, this.options.actingAs); - await announce(msg); - this.listener.listenForDevices(async (connectionInfo) => { - await this.devices.handleDevice(connectionInfo); - }); - } - - /** - * Disconnect from the StageLinq network. - */ - async disconnect() { - try { - this.devices.disconnectAll(); - const msg = createDiscoveryMessage(Action.Logout, this.options.actingAs) - await unannounce(msg); - } catch(e) { - throw new Error(e); - } - } - - get databases() { - return this.devices.databases; - } +export class StageLinq { + static options: StageLinqOptions = DEFAULT_OPTIONS; + static readonly logger: Logger = Logger.instance; + static readonly discovery: Discovery = new Discovery(); + static readonly devices = new Devices(); + static readonly sources: Sources = new Sources(); + static readonly status: Status = new Status(); + static directory: Directory = null; + + + /** + * Service Constructor Factory Function + * @param {Service} Service + * @param {DeviceId} [deviceId] + * @returns {Promise>} + */ + static async startServiceListener>(ctor: { + new(_deviceId?: DeviceId): T; + }, deviceId?: DeviceId): Promise { + const service = new ctor(deviceId); + + await service.start(); + return service; + } + + /** + * Connect to the StageLinq network. + */ + static async connect() { + // Initialize Discovery agent + StageLinq.discovery.listen(StageLinq.options.actingAs); + + //Directory is required + StageLinq.directory = await StageLinq.startServiceListener(Directory); + + // Announce myself with Directory port + await StageLinq.discovery.announce(StageLinq.directory.serverInfo.port); + } + /** + * Disconnect from the StageLinq network. + * Close all open Servers + */ + static async disconnect() { + try { + Logger.warn('disconnecting'); + await this.directory.stop(); + const services = await StageLinq.devices.getDeviceServices(); + for (const service of services) { + console.log(`closing ${service.name} on ${service.deviceId.string}`); + await service.stop() + } + await StageLinq.discovery.unannounce(); + } catch (e) { + throw new Error(e); + } + } } \ No newline at end of file diff --git a/TODO.md b/TODO.md index 067374b..4b6737c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,8 @@ # TODO -- [ ] Figure out how fader start works. -- [ ] Refactor MarByteBeep's album art code. -- [ ] Get track metadata from DB. +- [ ] Ensure library is JS compatible +- [ ] Easy import of types for end user +- [ ] JsDoc all functions/methods/etc +- [ ] Tests? +- [ ] Update Dependancies +- [ ] Test more edge cases diff --git a/cli/index.ts b/cli/index.ts index a3545dc..4e23630 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -1,187 +1,303 @@ -import { ActingAsDevice, PlayerStatus } from '../types'; -import { DbConnection } from "../Databases"; +import { ActingAsDevice, StageLinqOptions, Services, DeviceId } from '../types'; +import { StateData, StateMap, BeatData, BeatInfo, FileTransfer, Broadcast } from '../services'; +import { Source } from '../Sources' import { sleep } from '../utils/sleep'; import { StageLinq } from '../StageLinq'; +import { Logger } from '../LogEmitter'; import * as fs from 'fs'; import * as os from 'os'; -import * as path from 'path'; +import * as Path from 'path'; require('console-stamp')(console, { - format: ':date(HH:MM:ss) :label', + format: ':date(HH:MM:ss) :label', }); -/** - * Get track information for latest playing song. - * - * @param stageLinq Instance of StageLinq. - * @param status Player to get track info from. - * @returns Track info - */ -function getTrackInfo(stageLinq: StageLinq, status: PlayerStatus) { - try { - const dbPath = stageLinq.databases.getDbPath(status.dbSourceName) - const connection = new DbConnection(dbPath); - const result = connection.getTrackInfo(status.trackPath); - connection.close(); - console.log('Database entry:', result); - return result; - } catch(e) { - console.error(e); - } +function progressBar(size: number, bytes: number, total: number): string { + const progress = Math.ceil((bytes / total) * 10) + let progressArrary = new Array(size); + progressArrary.fill(' '); + if (progress) { + for (let i = 0; i < progress; i++) { + progressArrary[i] = '|' + } + } + return `[${progressArrary.join('')}]` } -/** - * Download the currently playing song from the media. - * - * @param stageLinq Instance of StageLinq. - * @param status Player to download the current song from. - * @param dest Path to save file to. - */ -async function downloadFile(stageLinq: StageLinq, status: PlayerStatus, dest: string) { - try { - const data = await stageLinq.devices.downloadFile(status.deviceId, status.trackPathAbsolute); - if (data) { - fs.writeFileSync(dest, Buffer.from(data)); - console.log(`Downloaded ${status.trackPathAbsolute} to ${dest}`); - } - } catch(e) { - console.error(`Could not download ${status.trackPathAbsolute}`); - } +// async function getTrackInfo(sourceName: string, deviceId: DeviceId, trackName: string) { +// while (!StageLinq.sources.hasSourceAndDB(sourceName, deviceId)) { +// await sleep(1000); +// } +// try { +// const source = StageLinq.sources.getSource(sourceName, deviceId); +// const connection = source.getDatabase().connection; +// const result = await connection.getTrackInfo(trackName); +// connection.close(); +// return result; +// } catch (e) { +// console.error(e); +// } +// } + +async function downloadFile(sourceName: string, deviceId: DeviceId, path: string, dest?: string) { + while (!StageLinq.sources.hasSource(sourceName, deviceId)) { + await sleep(250) + } + try { + const source = StageLinq.sources.getSource(sourceName, deviceId); + const data = await StageLinq.sources.downloadFile(source, path); + if (dest && data) { + const filePath = `${dest}/${path.split('/').pop()}` + fs.writeFileSync(filePath, Buffer.from(data)); + } + } catch (e) { + console.error(`Could not download ${path}`); + console.error(e) + } } + async function main() { - console.log('Starting CLI'); - - const stageLinqOptions = { - - // If set to true, download the source DBs in a temporary location. - // (default: true) - downloadDbSources: false, - - // Max number of attempts to connect to a StageLinq device. - // (default: 3) - maxRetries: 3, - - // What device to emulate on the network. - // (default: Now Playing) - actingAs: ActingAsDevice.NowPlaying - } - - const stageLinq = new StageLinq(stageLinqOptions); - - // Setup how you want to handle logs coming from StageLinq - stageLinq.logger.on('error', (...args: any) => { - console.error(...args); - }); - stageLinq.logger.on('warn', (...args: any) => { - console.warn(...args); - }); - stageLinq.logger.on('info', (...args: any) => { - console.info(...args); - }); - stageLinq.logger.on('log', (...args: any) => { - console.log(...args); - }); - stageLinq.logger.on('debug', (...args: any) => { - console.debug(...args); - }); - // Note: Silly is very verbose! - // stageLinq.logger.on('silly', (...args: any) => { - // console.debug(...args); - // }); - - // Fires when we connect to any device - stageLinq.devices.on('connected', async (connectionInfo) => { - console.log(`Successfully connected to ${connectionInfo.software.name}`); - - if (stageLinq.options.downloadDbSources) { - // Fires when the database source starts downloading. - stageLinq.databases.on('dbDownloading', (sourceName, dbPath) => { - console.log(`Downloading ${sourceName} to ${dbPath}`); - }); - - // Fires while the database source is being read - stageLinq.databases.on('dbProgress', (sourceName, total, bytes, percent) => { - console.debug(`Reading ${sourceName}: ${bytes}/${total} (${Math.ceil(percent)}%)`); - }); - - // Fires when the database source has been read and saved to a temporary path. - stageLinq.databases.on('dbDownloaded', (sourceName, dbPath) => { - console.log(`Database (${sourceName}) has been downloaded to ${dbPath}`); - }); - } - - }); - - // Fires when StageLinq and all devices are ready to use. - stageLinq.devices.on('ready', () => { - console.log(`StageLinq is ready!`); - }); - - // Fires when a new track is loaded on to a player. - stageLinq.devices.on('trackLoaded', async (status) => { - - // Example of how to connect to the database using this library's - // implementation of BetterSqlite3 to get additional information. - if (stageLinq.options.downloadDbSources) { - getTrackInfo(stageLinq, status); - } - - // Example of how to download the actual track from the media. - await downloadFile(stageLinq, status, path.resolve(os.tmpdir(), 'media')); - }); - - // Fires when a track has started playing. - stageLinq.devices.on('nowPlaying', (status) => { - console.log(`Now Playing on [${status.deck}]: ${status.title} - ${status.artist}`) - }); - - // Fires when StageLinq receives messages from a device. - stageLinq.devices.on('message', (connectionInfo, data) => { - const msg = data.message.json - ? JSON.stringify(data.message.json) - : data.message.interval; - console.debug(`${connectionInfo.address}:${connectionInfo.port} ` + - `${data.message.name} => ${msg}`); - }); - - // Fires when the state of a device has changed. - stageLinq.devices.on('stateChanged', (status) => { - console.log(`Updating state [${status.deck}]`, status) - }); - - ///////////////////////////////////////////////////////////////////////// - // CLI - - let returnCode = 0; - try { - process.on('SIGINT', async function () { - console.info('... exiting'); - // Ensure SIGINT won't be impeded by some error - try { - await stageLinq.disconnect(); - } catch (err: any) { - const message = err.stack.toString(); - console.error(message); - } - process.exit(returnCode); - }); - - await stageLinq.connect(); - - while (true) { - await sleep(250); - } - - } catch (err: any) { - const message = err.stack.toString(); - console.error(message); - returnCode = 1; - } - - await stageLinq.disconnect(); - process.exit(returnCode); + console.log('Starting CLI'); + + const stageLinqOptions: StageLinqOptions = { + downloadDbSources: true, + actingAs: ActingAsDevice.StageLinqJS, + services: [ + Services.StateMap, + Services.FileTransfer, + Services.BeatInfo, + Services.Broadcast, + ], + } + + StageLinq.options = stageLinqOptions; + + StageLinq.logger.on('error', (...args: any) => { + console.error(...args); + }); + StageLinq.logger.on('warn', (...args: any) => { + console.warn(...args); + args.push("\n"); + }); + StageLinq.logger.on('info', (...args: any) => { + console.info(...args); + args.push("\n"); + }); + StageLinq.logger.on('log', (...args: any) => { + console.log(...args); + args.push("\n"); + }); + // StageLinq.logger.on('debug', (...args: any) => { + // console.debug(...args); + // args.push("\n"); + // }); + //Note: Silly is very verbose! + // stageLinq.logger.on('silly', (...args: any) => { + // console.debug(...args); + // }); + + + StageLinq.discovery.on('listening', () => { + console.log(`[DISCOVERY] Listening`) + }); + + StageLinq.discovery.on('announcing', (info) => { + console.log(`[DISCOVERY] Broadcasting Announce ${info.deviceId.string} Port ${info.port} ${info.source} ${info.software.name}:${info.software.version}`) + }); + + StageLinq.discovery.on('newDiscoveryDevice', (info) => { + console.log(`[DISCOVERY] New Device ${info.deviceId.string} ${info.source} ${info.software.name} ${info.software.version}`) + }); + + StageLinq.discovery.on('updatedDiscoveryDevice', (info) => { + console.log(`[DISCOVERY] Updated Device ${info.deviceId.string} Port:${info.port} ${info.source} ${info.software.name} ${info.software.version}`) + }); + + + StageLinq.devices.on('newDevice', (device) => { + console.log(`[DEVICES] New Device ${device.deviceId.string}`) + }); + + StageLinq.devices.on('newService', (device, service) => { + console.log(`[DEVICES] New ${service.name} Service on ${device.deviceId.string} port ${service.serverInfo.port}`) + }); + + + if (stageLinqOptions.services.includes(Services.Broadcast)) { + + Broadcast.emitter.on('message', async (deviceId: DeviceId, name: string, value) => { + console.log(`[BROADCAST] ${deviceId.string} ${name}`, value); + const db = StageLinq.sources.getDBByUuid(value.databaseUuid); + if (db.length) { + const connection = db[0].connection(); + const track = await connection.getTrackById(value.trackId); + connection.close(); + console.log('[BROADCAST] Track Changed:', track); + } + }) + + } + + + if (stageLinqOptions.services.includes(Services.StateMap)) { + + async function deckIsMaster(data: StateData) { + if (data.json.state) { + const deck = parseInt(data.name.substring(12, 13)); + await sleep(250); + const track = StageLinq.status.getTrack(data.deviceId, deck); + console.log(`Now Playing: `, track); + if (stageLinqOptions.services.includes(Services.FileTransfer) && StageLinq.options.downloadDbSources) { + downloadFile(track.source.name, track.source.location, track.source.path, Path.resolve(os.tmpdir())); + } + } + } + + + StateMap.emitter.on('newDevice', async (service: StateMap) => { + console.log(`[STATEMAP] Subscribing to States on ${service.deviceId.string}`); + + for (let i = 1; i <= service.device.deckCount(); i++) { + service.addListener(`/Engine/Deck${i}/DeckIsMaster`, deckIsMaster); + } + + service.subscribe(); + }); + + StateMap.emitter.on('stateMessage', async (data: StateData) => { + Logger.info(`[STATEMAP] ${data.deviceId.string} ${data.name} => ${JSON.stringify(data.json)}`); + }); + + } + + + if (stageLinqOptions.services.includes(Services.FileTransfer)) { + + + FileTransfer.emitter.on('fileTransferProgress', (source, file, txid, progress) => { + Logger.debug(`[FILETRANSFER] ${source.name} id:{${txid}} Reading ${file}: ${progressBar(10, progress.bytesDownloaded, progress.total)} (${Math.ceil(progress.percentComplete)}%)`); + }); + + FileTransfer.emitter.on('fileTransferComplete', (source, file, txid) => { + console.log(`[FILETRANSFER] Complete ${source.name} id:{${txid}} ${file}`); + }); + + StageLinq.sources.on('newSource', (source: Source) => { + console.log(`[SOURCES] Source Available: (${source.name})`); + }); + + StageLinq.sources.on('dbDownloaded', (source: Source) => { + console.log(`[SOURCES] Database Downloaded: (${source.name})`); + }); + + StageLinq.sources.on('sourceRemoved', (sourceName: string, deviceId: DeviceId) => { + console.log(`[SOURCES] Source Removed: ${sourceName} on ${deviceId.string}`); + }); + + } + + + if (stageLinqOptions.services.includes(Services.BeatInfo)) { + + /** + * Resolution for triggering callback + * 0 = every message WARNING, it's a lot! + * 1 = every beat + * 4 = every 4 beats + * .25 = every 1/4 beat + */ + const beatOptions = { + everyNBeats: 1, + } + + /** + * User callback function. + * Will be triggered everytime a player's beat counter crosses the resolution threshold + * @param {BeatData} bd + */ + function beatCallback(bd: BeatData,) { + let deckBeatString = "" + for (let i = 0; i < bd.deckCount; i++) { + deckBeatString += `Deck: ${i + 1} Beat: ${bd.deck[i].beat.toFixed(3)}/${bd.deck[i].totalBeats.toFixed(0)} ` + } + console.log(`[BEATINFO] ${bd.deviceId.string} clock: ${bd.clock} ${deckBeatString}`); + } + + //// callback is optional, BeatInfo messages can be consumed by: + // - user callback + // - event messages + // - reading the register + const beatMethod = { + useCallback: true, + useEvent: false, + useRegister: false, + }; + + BeatInfo.emitter.on('newDevice', async (beatInfo: BeatInfo) => { + console.log(`[BEATINFO] New Device ${beatInfo.deviceId.string}`) + + if (beatMethod.useCallback) { + beatInfo.startBeatInfo(beatOptions, beatCallback); + } + + if (beatMethod.useEvent) { + beatInfo.startBeatInfo(beatOptions); + BeatInfo.emitter.on('beatMessage', (bd) => { + + if (bd) { + beatCallback(bd); + } + }); + } + + if (beatMethod.useRegister) { + beatInfo.startBeatInfo(beatOptions); + + function beatFunc(beatInfo: BeatInfo) { + const beatData = beatInfo.getBeatData(); + if (beatData) beatCallback(beatData); + } + + setTimeout(beatFunc, 4000, beatInfo) + } + + }) + } + + + ///////////////////////////////////////////////////////////////////////// + // CLI + + let returnCode = 0; + try { + process.on('SIGINT', async function () { + console.info('... exiting'); + + try { + await StageLinq.disconnect(); + } catch (err: any) { + const message = err.stack.toString(); + console.error(message); + } + process.exit(returnCode); + }); + + await StageLinq.connect(); + + while (true) { + await sleep(250); + } + + } catch (err: any) { + const message = err.stack.toString(); + console.error(message); + returnCode = 1; + } + + await StageLinq.disconnect(); + process.exit(returnCode); } main(); diff --git a/cli/nowPlaying.ts b/cli/nowPlaying.ts new file mode 100644 index 0000000..1062806 --- /dev/null +++ b/cli/nowPlaying.ts @@ -0,0 +1,99 @@ +import { ActingAsDevice, StageLinqOptions, Services, DeviceId } from '../types'; +import { StateData, StateMap } from '../services'; +import { sleep } from '../utils/sleep'; +import { StageLinq } from '../StageLinq'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as Path from 'path'; + + +async function main() { + + const stageLinqOptions: StageLinqOptions = { + downloadDbSources: true, + actingAs: ActingAsDevice.NowPlaying, + services: [ + Services.StateMap, + Services.FileTransfer, + ], + } + + //const stageLinq = new StageLinq(stageLinqOptions); + StageLinq.options = stageLinqOptions + + async function downloadFile(sourceName: string, deviceId: DeviceId, path: string, dest?: string) { + while (!StageLinq.sources.hasSource(sourceName, deviceId)) { + await sleep(250) + } + try { + const source = StageLinq.sources.getSource(sourceName, deviceId); + const data = await StageLinq.sources.downloadFile(source, path); + if (dest && data) { + const filePath = `${dest}/${path.split('/').pop()}` + fs.writeFileSync(filePath, Buffer.from(data)); + } + console.log(`Downloaded ${path}`) + } catch (e) { + console.error(`Could not download ${path}`); + console.error(e) + } + } + + async function deckIsMaster(data: StateData) { + if (data.json.state) { + const deck = parseInt(data.name.substring(12, 13)) + await sleep(250); + const track = StageLinq.status.getTrack(data.deviceId, deck) + + if (StageLinq.options.downloadDbSources) { + downloadFile(track.source.name, track.source.location, track.source.path, Path.resolve(os.tmpdir())); + } + + console.log(`Now Playing: `, track) //Or however you consume it + } + } + + + StateMap.emitter.on('newDevice', async (service: StateMap) => { + + for (let i = 1; i <= service.device.deckCount(); i++) { + service.addListener(`/Engine/Deck${i}/DeckIsMaster`, deckIsMaster); + } + + service.subscribe(); + }); + + ///////////////////////////////////////////////////////////////////////// + // CLI + + let returnCode = 0; + try { + process.on('SIGINT', async function () { + console.info('... exiting'); + + try { + await StageLinq.disconnect(); + } catch (err: any) { + const message = err.stack.toString(); + console.error(message); + } + process.exit(returnCode); + }); + + await StageLinq.connect(); + + while (true) { + await sleep(250); + } + + } catch (err: any) { + const message = err.stack.toString(); + console.error(message); + returnCode = 1; + } + + await StageLinq.disconnect(); + process.exit(returnCode); +} + +main(); \ No newline at end of file diff --git a/devices/Player.ts b/devices/Player.ts deleted file mode 100644 index e359988..0000000 --- a/devices/Player.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { EventEmitter } from 'events'; -import { PlayerLayerState, PlayerStatus, ServiceMessage } from '../types'; -import { PlayerMessageQueue } from './PlayerMessageQueue'; -import { StateData, StateMap } from '../services'; -import { Logger } from '../LogEmitter'; - -export declare interface Player { - on(event: 'trackLoaded', listener: (status: PlayerStatus) => void): this; - on(event: 'stateChanged', listener: (status: PlayerStatus) => void): this; - on(event: 'nowPlaying', listener: (status: PlayerStatus) => void): this; -} - -////////////////////////////////////////////////////////////////////////////// - -interface PlayerOptions { - stateMap: StateMap; - address: string, - port: number; - deviceId: string; -} - -interface SourceAndTrackPath { - source: string; - trackPath: string; - trackPathAbsolute: string; -} - -/** - * A player represents a device on the StageLinq network. - * - * A player on the network may have up to 4 decks (or "layers" as they're - * called on the harware). A player may also be given a player number. - * - * If you're using a Denon Prime Go/2/4 then you should only get one number. - * If you're using a Denon SC5000/SC6000 then you assign the numbers in the - * Denon's settings screen. - * - * Master tempo and master status only apply if you are using SC5000/SC6000 - * and if they're both on the network. - * - * A queue is used to group all the incoming messages from StageLinq to give us - * a single updated PlayerStatus object. - */ -export class Player extends EventEmitter { - - private player: number; // Player number as reported by the device. - private address: string; // IP address - private port: number; // Port - private masterTempo: number; // Current master tempo BPM - private masterStatus: boolean; // If this device has the matser tempo - private decks: Map = new Map(); - private lastTrackNetworkPath: Map = new Map(); - private queue: {[layer: string]: PlayerMessageQueue} = {}; - private deviceId: string; - - /** - * Initialize a player device. - * - * @param networkDevice Network device - * @param stateMap Statemap service - */ - constructor(options: PlayerOptions) { - super(); - options.stateMap.on('message', this.messageHandler.bind(this)); - this.address = options.address; - this.port = options.port; - this.deviceId = options.deviceId; - this.queue = { - A: new PlayerMessageQueue('A').onDataReady(this.handleUpdate.bind(this)), - B: new PlayerMessageQueue('B').onDataReady(this.handleUpdate.bind(this)), - C: new PlayerMessageQueue('C').onDataReady(this.handleUpdate.bind(this)), - D: new PlayerMessageQueue('D').onDataReady(this.handleUpdate.bind(this)), - }; - } - - /** - * Parse the state data and push it into the update queue. - * - * @param data State data from Denon. - * @returns - */ - private messageHandler(data: ServiceMessage) { - const message = data.message - if (!message.json) return; - const name = message.name; - const json = message.json as any; - - if (/Client\/Preferences\/Player$/.test(name)) { - this.player = parseInt(json.string); - return; - } - if (/Engine\/Master\/MasterTempo/.test(name)) { - this.masterTempo = json.value; - return; - } - if (/Engine\/Sync\/Network\/MasterStatus/.test(name)) { - this.masterStatus = json.state; - return; - } - - const split = message.name.split('/'); - - const deck = - (/PlayerJogColor[A-D]$/.test(name)) ? split[3].replace('PlayerJogColor', '') - : (/Engine\/Deck\d\//.test(name)) ? this.deckNumberToLayer(split[2]) - : null; - - const cueData = - (/PlayState$/.test(name)) ? { playState: json.state } - : (/Track\/TrackNetworkPath$/.test(name)) ? { - trackNetworkPath: json.string, - source: this.getSourceAndTrackPath(json.string).source, - trackPath: this.getSourceAndTrackPath(json.string).trackPath, - trackPathAbsolute: this.getSourceAndTrackPath(json.string).trackPathAbsolute - } - : (/Track\/SongLoaded$/.test(name)) ? { songLoaded: json.state } - : (/Track\/SongName$/.test(name)) ? { title: json.string } - : (/Track\/ArtistName$/.test(name)) ? { artist: json.string } - : (/Track\/TrackData$/.test(name)) ? { hasTrackData: json.state } - : (/Track\/TrackName$/.test(name)) ? { fileLocation: json.string } - : (/CurrentBPM$/.test(name)) ? { currentBpm: json.value } - : (/ExternalMixerVolume$/.test(name)) ? { externalMixerVolume: json.value } - : (/Play$/.test(name)) ? { play: json.state } - : (/PlayerJogColor[A-D]$/.test(name)) ? { jogColor: json.color } - : null; - - if (cueData) { - this.queue[deck].push({ layer: deck, ...cueData }); - } - } - - /** - * Update current state and emit. - * @param data - */ - private handleUpdate(data: PlayerLayerState) { - Logger.debug(`data: ${JSON.stringify(data, null, 2)}`); - - const layer = data.layer; - - // A new song my be loading onto a layer but not yet fully downloaded. - // For example streaming a song from Beatport Link. - let isNewTrack = true; - const lastTrackNetworkPath = this.lastTrackNetworkPath.get(layer); - if (lastTrackNetworkPath && data.trackNetworkPath) { - if (data.trackNetworkPath === lastTrackNetworkPath) { - isNewTrack = false; - } - } - this.lastTrackNetworkPath.set(layer, data.trackNetworkPath); - - // This will be true once a song has been fully downloaded / loaded. - const isSongLoaded = data.hasOwnProperty('songLoaded'); - - // If a new song is loaded drop all the previous track data. - if (isNewTrack && isSongLoaded) { - Logger.debug(`Replacing state ${layer}`); - this.decks.set(layer, data); - } else { - Logger.debug(`Updating state ${layer}`); - this.decks.set(layer, { ...this.decks.get(layer), ...data }); - } - - const result = this.decks.get(layer); - const deck = `${this.player}${result.layer}`; - - const output = { - deck: deck, - player: this.player, - layer: layer, - address: this.address, - port: this.port, - masterTempo: this.masterTempo, - masterStatus: this.masterStatus, - deviceId: `net://${this.deviceId}`, - ...result - }; - - // We're casting here because we originally built it up piecemeal. - const currentState = output as PlayerStatus; - - if (currentState.trackNetworkPath && currentState.trackNetworkPath.startsWith('net:')) { - const pathParts = currentState.trackNetworkPath.split('net://')[1].split('/', 2); - currentState.dbSourceName = `net://${pathParts[0]}/${pathParts[1]}`; - currentState.deviceId = `net://${pathParts[0]}`; - } else if (!currentState.source || /Unknown/.test(currentState.source)) { - // Tracks from streaming sources won't be in the database. - currentState.dbSourceName = ''; - } else { - currentState.dbSourceName = `net://${this.deviceId}/${currentState.source}`; - } - - // If a song is loaded and we have a location emit the trackLoaded event. - if (isSongLoaded && currentState.trackNetworkPath) - this.emit('trackLoaded', currentState); - - // If the song is actually playing emit the nowPlaying event. - if (result.playState) this.emit('nowPlaying', currentState); - - // Emit that the state has changed. - this.emit('stateChanged', currentState); - } - - private deckNumberToLayer(deck: string) { - const index = parseInt(deck.replace('Deck', '')) - 1; - return 'ABCD'[index]; - } - - private getSourceAndTrackPath(p_path: string): SourceAndTrackPath { - if (!p_path || p_path.length === 0) return { source: '', trackPath: '', trackPathAbsolute: '' }; - const parts = p_path.split('/'); - const source = parts[3]; - let trackPath = parts.slice(5).join('/'); - - // Handle streaming tracks. - if (/\(Unknown\)/.test(source)) { - return { - source: source.replace(':', ''), - trackPath: `streaming://${trackPath}`, - trackPathAbsolute: `streaming://${trackPath}` - } - } - - if (parts[4] !== 'Engine Library') { - // This probably occurs with RekordBox conversions; tracks are outside Engine Library folder - trackPath = `../${parts[4]}/${trackPath}`; - } - - return { - source: source, - trackPath: trackPath, - trackPathAbsolute: `/${source}/Engine Library/${trackPath}` - }; - } - -} \ No newline at end of file diff --git a/devices/PlayerMessageQueue.ts b/devices/PlayerMessageQueue.ts deleted file mode 100644 index d9bed22..0000000 --- a/devices/PlayerMessageQueue.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { PlayerLayerState } from '../types'; - -// How long to wait for all the messages to come in before firing the callback. -// It seems that anything less than 1 second is too fast. -export const UPDATE_RATE_MS = 1500; - -export type DataQueueCallback = (data: PlayerLayerState) => void; - -/** - * Collect all the messages from a player together and return it as one object. - * - * The Denon hardware will fire several messages in quick succession. This will - * take them all in, then after UPDATE_RATE_MS will merge all the data - * as a single update to the `onDataReady` callback. - * - * For example, when you move the fader up you get several ExternalMixerVolume - * messages where the value goes up from 0 to 1. Instead firing off loads - * of updates we're only interested in the last one. - */ -export class PlayerMessageQueue { - - private callback: DataQueueCallback; - private data: PlayerLayerState[] = []; - private timeout: NodeJS.Timer | null = null; - private layer: string; - - constructor(layer: string) { - this.layer = layer; - } - - /** - * Push data into the queue. - * @param data Parsed data from a player. - */ - push(data: PlayerLayerState) { - this.data.push(data); - if (!this.timeout) { - this.timeout = setTimeout(this.emptyCue.bind(this), UPDATE_RATE_MS); - } - } - - /** - * Merge data, empty the queue, clear the timeout, and fire the callback. - */ - emptyCue() { - let output: any = { layer: this.layer }; - this.data.map(d => { output = { ...output, ...d }; }); - this.data = []; - clearTimeout(this.timeout); - this.timeout = null; - this.callback(output as PlayerLayerState); - } - - /** - * Execute this callback when there is new data from the Denon hardware. - * @param callback User callback when we have an update. - * @returns - */ - onDataReady(callback: DataQueueCallback) { - this.callback = callback; - return this; - } -} diff --git a/devices/index.ts b/devices/index.ts new file mode 100644 index 0000000..84e3a77 --- /dev/null +++ b/devices/index.ts @@ -0,0 +1,203 @@ +import { EventEmitter } from 'events'; +import { Logger } from '../LogEmitter'; +import { Service } from '../services'; +import { ConnectionInfo, DeviceId, Units } from '../types'; +import { sleep } from '../utils'; +import { StageLinq } from '../StageLinq'; + + +function isStageLinqDevice(info: ConnectionInfo): boolean { + return !!Units[info.software.name] +} + +function isMixer(info: ConnectionInfo): boolean { + return Units[info.software.name]?.type === "MIXER" +} + +function portHasChanged(incoming: ConnectionInfo, current: ConnectionInfo): boolean { + return incoming.port !== current?.port +} + +export declare interface Devices { + on(event: 'newDevice', listener: (device: Device) => void): this; + on(event: 'newService', listener: (device: Device, service: InstanceType) => void): this; +} + +export class Devices extends EventEmitter { + #devices: Map = new Map(); + + + constructor() { + super() + this.initListeners() + } + + private async initListeners() { + // while (!StageLinq && !StageLinq.discovery) { + // await sleep(100); + // } + await sleep(250); + StageLinq.discovery.addListener('discoveryDevice', (info: ConnectionInfo) => this.deviceListener(info)) + while (!StageLinq.directory) { + await sleep(250); + } + StageLinq.directory.addListener('newService', (service) => this.serviceListener(service)) + } + + private serviceListener(service: InstanceType) { + this.addService(service.deviceId, service) + service.addListener('closingService', (service) => this.deleteService(service.deviceId, service.name)) + } + + private deviceListener(info: ConnectionInfo) { + const currentDevice = this.#devices.get(info.deviceId.string) + + if ((!this.#devices.has(info.deviceId.string) || portHasChanged(info, currentDevice?.info)) + && isStageLinqDevice(info) + && !isMixer(info) + ) { + + Logger.debug(`Setting New Device! ${info.deviceId.string} ${info.software.name}`) + const device = new Device(info) + this.#devices.set(info.deviceId.string, device) + this.emit('newDevice', device) + } + } + + + + /** + * + * @param {DeviceId} deviceId + * @returns {Promise} + */ + async getDevice(deviceId: DeviceId): Promise { + while (!this.hasDevice(deviceId)) { + await sleep(150); + } + return this.#devices.get(deviceId.string) + } + + /** + * + * @param {DeviceId} deviceId + * @returns {Device} + */ + device(deviceId: DeviceId): Device { + return this.#devices.get(deviceId.string) + } + + /** + * + * @param {DeviceId} deviceId + * @returns {boolean} + */ + hasDevice(deviceId: DeviceId): boolean { + return this.#devices.has(deviceId.string) + } + + /** + * Get an array of all current Service Instances + * @returns {Promise[]>} + */ + async getDeviceServices(): Promise[]> { + return [...this.#devices.values()].flatMap(device => device.getServices()) + } + + /** + * + * @param {DeviceId} deviceId + * @param {Service} service + */ + private addService(deviceId: DeviceId, service: InstanceType) { + const device = this.device(deviceId) + device.addService(service) + } + + /** + * + * @param {DeviceId} deviceId + * @param {string} serviceName + */ + private deleteService(deviceId: DeviceId, serviceName: string) { + const device = this.device(deviceId); + device.deleteService(serviceName) + } + + + +} + +export class Device { + readonly deviceId: DeviceId; + info: ConnectionInfo; + #services: Map> = new Map(); + + /** + * @constructor + * @param {connectionInfo} info + */ + constructor(info: ConnectionInfo) { + this.deviceId = info.deviceId; + this.info = info; + } + + /** + * Get # of decks on this device + * @returns {number} + */ + deckCount(): number { + return this.info.unit.decks + } + + /** + * Get a service instance by name + * @param {string} serviceName + * @returns {InstanceType} + */ + service(serviceName: string): InstanceType { + return this.#services.get(serviceName) + } + + /** + * Check if Device has Service + * @param {string} serviceName + * @returns {boolean} + */ + hasService(serviceName: string): boolean { + return this.#services.has(serviceName) + } + + /** + * Get an Array of names of all current Services on this Device + * @returns {string[]} + */ + getServiceNames(): string[] { + return [...this.#services.keys()] + } + + /** + * Get an Array of all current Services on this Device + * @returns {InstanceType[]} + */ + getServices(): InstanceType[] { + return [...this.#services.values()] + } + + /** + * Add an instantiated Service + * @param {Service} service + */ + + addService(service: InstanceType) { + this.#services.set(service.name, service) + } + + /** + * Remove a service + * @param {string} serviceName + */ + deleteService(serviceName: string) { + this.#services.delete(serviceName) + } +} \ No newline at end of file diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e2ac661 --- /dev/null +++ b/docs/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css new file mode 100644 index 0000000..b0f579a --- /dev/null +++ b/docs/assets/highlight.css @@ -0,0 +1,99 @@ +:root { + --light-hl-0: #0000FF; + --dark-hl-0: #569CD6; + --light-hl-1: #000000; + --dark-hl-1: #D4D4D4; + --light-hl-2: #0070C1; + --dark-hl-2: #4FC1FF; + --light-hl-3: #267F99; + --dark-hl-3: #4EC9B0; + --light-hl-4: #001080; + --dark-hl-4: #9CDCFE; + --light-hl-5: #AF00DB; + --dark-hl-5: #C586C0; + --light-hl-6: #795E26; + --dark-hl-6: #DCDCAA; + --light-hl-7: #A31515; + --dark-hl-7: #CE9178; + --light-hl-8: #000000FF; + --dark-hl-8: #D4D4D4; + --light-hl-9: #008000; + --dark-hl-9: #6A9955; + --light-hl-10: #098658; + --dark-hl-10: #B5CEA8; + --light-code-background: #FFFFFF; + --dark-code-background: #1E1E1E; +} + +@media (prefers-color-scheme: light) { :root { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --hl-9: var(--light-hl-9); + --hl-10: var(--light-hl-10); + --code-background: var(--light-code-background); +} } + +@media (prefers-color-scheme: dark) { :root { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --hl-9: var(--dark-hl-9); + --hl-10: var(--dark-hl-10); + --code-background: var(--dark-code-background); +} } + +:root[data-theme='light'] { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --hl-9: var(--light-hl-9); + --hl-10: var(--light-hl-10); + --code-background: var(--light-code-background); +} + +:root[data-theme='dark'] { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --hl-9: var(--dark-hl-9); + --hl-10: var(--dark-hl-10); + --code-background: var(--dark-code-background); +} + +.hl-0 { color: var(--hl-0); } +.hl-1 { color: var(--hl-1); } +.hl-2 { color: var(--hl-2); } +.hl-3 { color: var(--hl-3); } +.hl-4 { color: var(--hl-4); } +.hl-5 { color: var(--hl-5); } +.hl-6 { color: var(--hl-6); } +.hl-7 { color: var(--hl-7); } +.hl-8 { color: var(--hl-8); } +.hl-9 { color: var(--hl-9); } +.hl-10 { color: var(--hl-10); } +pre, code { background: var(--code-background); } diff --git a/docs/assets/main.js b/docs/assets/main.js new file mode 100644 index 0000000..f7c8366 --- /dev/null +++ b/docs/assets/main.js @@ -0,0 +1,58 @@ +"use strict"; +"use strict";(()=>{var Qe=Object.create;var ae=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var Oe=Object.getPrototypeOf,Re=Object.prototype.hasOwnProperty;var _e=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Me=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ce(e))!Re.call(t,i)&&i!==n&&ae(t,i,{get:()=>e[i],enumerable:!(r=Pe(e,i))||r.enumerable});return t};var De=(t,e,n)=>(n=t!=null?Qe(Oe(t)):{},Me(e||!t||!t.__esModule?ae(n,"default",{value:t,enumerable:!0}):n,t));var de=_e((ce,he)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(n){e.console&&console.warn&&console.warn(n)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var h=t.utils.clone(n)||{};h.position=[a,l],h.index=s.length,s.push(new t.Token(r.slice(a,o),h))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ou?h+=2:a==u&&(n+=r[l+1]*i[h+1],l+=2,h+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var h=s.str.charAt(0),m=s.str.charAt(1),v;m in s.node.edges?v=s.node.edges[m]:(v=new t.TokenSet,s.node.edges[m]=v),s.str.length==1&&(v.final=!0),i.push({node:v,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,n){typeof define=="function"&&define.amd?define(n):typeof ce=="object"?he.exports=n():e.lunr=n()}(this,function(){return t})})()});var le=[];function B(t,e){le.push({selector:e,constructor:t})}var Y=class{constructor(){this.alwaysVisibleMember=null;this.createComponents(document.body),this.ensureFocusedElementVisible(),window.addEventListener("hashchange",()=>this.ensureFocusedElementVisible())}createComponents(e){le.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r,app:this}),r.dataset.hasInstance=String(!0))})})}filterChanged(){this.ensureFocusedElementVisible()}ensureFocusedElementVisible(){this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null);let e=document.getElementById(location.hash.substring(1));if(!e)return;let n=e.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(n&&n.offsetParent==null){this.alwaysVisibleMember=n,n.classList.add("always-visible");let r=document.createElement("p");r.classList.add("warning"),r.textContent="This member is normally hidden due to your filter settings.",n.prepend(r)}}};var I=class{constructor(e){this.el=e.el,this.app=e.app}};var J=class{constructor(){this.listeners={}}addEventListener(e,n){e in this.listeners||(this.listeners[e]=[]),this.listeners[e].push(n)}removeEventListener(e,n){if(!(e in this.listeners))return;let r=this.listeners[e];for(let i=0,s=r.length;i{let n=Date.now();return(...r)=>{n+e-Date.now()<0&&(t(...r),n=Date.now())}};var re=class extends J{constructor(){super();this.scrollTop=0;this.lastY=0;this.width=0;this.height=0;this.showToolbar=!0;this.toolbar=document.querySelector(".tsd-page-toolbar"),this.navigation=document.querySelector(".col-menu"),window.addEventListener("scroll",ne(()=>this.onScroll(),10)),window.addEventListener("resize",ne(()=>this.onResize(),10)),this.searchInput=document.querySelector("#tsd-search input"),this.searchInput&&this.searchInput.addEventListener("focus",()=>{this.hideShowToolbar()}),this.onResize(),this.onScroll()}triggerResize(){let n=new CustomEvent("resize",{detail:{width:this.width,height:this.height}});this.dispatchEvent(n)}onResize(){this.width=window.innerWidth||0,this.height=window.innerHeight||0;let n=new CustomEvent("resize",{detail:{width:this.width,height:this.height}});this.dispatchEvent(n)}onScroll(){this.scrollTop=window.scrollY||0;let n=new CustomEvent("scroll",{detail:{scrollTop:this.scrollTop}});this.dispatchEvent(n),this.hideShowToolbar()}hideShowToolbar(){let n=this.showToolbar;this.showToolbar=this.lastY>=this.scrollTop||this.scrollTop<=0||!!this.searchInput&&this.searchInput===document.activeElement,n!==this.showToolbar&&(this.toolbar.classList.toggle("tsd-page-toolbar--hide"),this.navigation?.classList.toggle("col-menu--hide")),this.lastY=this.scrollTop}},R=re;R.instance=new re;var X=class extends I{constructor(n){super(n);this.anchors=[];this.index=-1;R.instance.addEventListener("resize",()=>this.onResize()),R.instance.addEventListener("scroll",r=>this.onScroll(r)),this.createAnchors()}createAnchors(){let n=window.location.href;n.indexOf("#")!=-1&&(n=n.substring(0,n.indexOf("#"))),this.el.querySelectorAll("a").forEach(r=>{let i=r.href;if(i.indexOf("#")==-1||i.substring(0,n.length)!=n)return;let s=i.substring(i.indexOf("#")+1),o=document.querySelector("a.tsd-anchor[name="+s+"]"),a=r.parentNode;!o||!a||this.anchors.push({link:a,anchor:o,position:0})}),this.onResize()}onResize(){let n;for(let i=0,s=this.anchors.length;ii.position-s.position);let r=new CustomEvent("scroll",{detail:{scrollTop:R.instance.scrollTop}});this.onScroll(r)}onScroll(n){let r=n.detail.scrollTop+5,i=this.anchors,s=i.length-1,o=this.index;for(;o>-1&&i[o].position>r;)o-=1;for(;o-1&&this.anchors[this.index].link.classList.remove("focus"),this.index=o,this.index>-1&&this.anchors[this.index].link.classList.add("focus"))}};var ue=(t,e=100)=>{let n;return()=>{clearTimeout(n),n=setTimeout(()=>t(),e)}};var me=De(de());function ve(){let t=document.getElementById("tsd-search");if(!t)return;let e=document.getElementById("search-script");t.classList.add("loading"),e&&(e.addEventListener("error",()=>{t.classList.remove("loading"),t.classList.add("failure")}),e.addEventListener("load",()=>{t.classList.remove("loading"),t.classList.add("ready")}),window.searchData&&t.classList.remove("loading"));let n=document.querySelector("#tsd-search input"),r=document.querySelector("#tsd-search .results");if(!n||!r)throw new Error("The input field or the result list wrapper was not found");let i=!1;r.addEventListener("mousedown",()=>i=!0),r.addEventListener("mouseup",()=>{i=!1,t.classList.remove("has-focus")}),n.addEventListener("focus",()=>t.classList.add("has-focus")),n.addEventListener("blur",()=>{i||(i=!1,t.classList.remove("has-focus"))});let s={base:t.dataset.base+"/"};Fe(t,r,n,s)}function Fe(t,e,n,r){n.addEventListener("input",ue(()=>{He(t,e,n,r)},200));let i=!1;n.addEventListener("keydown",s=>{i=!0,s.key=="Enter"?Ve(e,n):s.key=="Escape"?n.blur():s.key=="ArrowUp"?pe(e,-1):s.key==="ArrowDown"?pe(e,1):i=!1}),n.addEventListener("keypress",s=>{i&&s.preventDefault()}),document.body.addEventListener("keydown",s=>{s.altKey||s.ctrlKey||s.metaKey||!n.matches(":focus")&&s.key==="/"&&(n.focus(),s.preventDefault())})}function Ae(t,e){t.index||window.searchData&&(e.classList.remove("loading"),e.classList.add("ready"),t.data=window.searchData,t.index=me.Index.load(window.searchData.index))}function He(t,e,n,r){if(Ae(r,t),!r.index||!r.data)return;e.textContent="";let i=n.value.trim(),s=i?r.index.search(`*${i}*`):[];for(let o=0;oa.score-o.score);for(let o=0,a=Math.min(10,s.length);o${fe(u.parent,i)}.${l}`);let h=document.createElement("li");h.classList.value=u.classes??"";let m=document.createElement("a");m.href=r.base+u.url,m.innerHTML=l,h.append(m),e.appendChild(h)}}function pe(t,e){let n=t.querySelector(".current");if(!n)n=t.querySelector(e==1?"li:first-child":"li:last-child"),n&&n.classList.add("current");else{let r=n;if(e===1)do r=r.nextElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);else do r=r.previousElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);r&&(n.classList.remove("current"),r.classList.add("current"))}}function Ve(t,e){let n=t.querySelector(".current");if(n||(n=t.querySelector("li:first-child")),n){let r=n.querySelector("a");r&&(window.location.href=r.href),e.blur()}}function fe(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(ie(t.substring(s,o)),`${ie(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(ie(t.substring(s))),i.join("")}var Ne={"&":"&","<":"<",">":">","'":"'",'"':"""};function ie(t){return t.replace(/[&<>"'"]/g,e=>Ne[e])}var F="mousedown",ye="mousemove",j="mouseup",Z={x:0,y:0},ge=!1,se=!1,Be=!1,A=!1,xe=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(xe?"is-mobile":"not-mobile");xe&&"ontouchstart"in document.documentElement&&(Be=!0,F="touchstart",ye="touchmove",j="touchend");document.addEventListener(F,t=>{se=!0,A=!1;let e=F=="touchstart"?t.targetTouches[0]:t;Z.y=e.pageY||0,Z.x=e.pageX||0});document.addEventListener(ye,t=>{if(se&&!A){let e=F=="touchstart"?t.targetTouches[0]:t,n=Z.x-(e.pageX||0),r=Z.y-(e.pageY||0);A=Math.sqrt(n*n+r*r)>10}});document.addEventListener(j,()=>{se=!1});document.addEventListener("click",t=>{ge&&(t.preventDefault(),t.stopImmediatePropagation(),ge=!1)});var K=class extends I{constructor(n){super(n);this.className=this.el.dataset.toggle||"",this.el.addEventListener(j,r=>this.onPointerUp(r)),this.el.addEventListener("click",r=>r.preventDefault()),document.addEventListener(F,r=>this.onDocumentPointerDown(r)),document.addEventListener(j,r=>this.onDocumentPointerUp(r))}setActive(n){if(this.active==n)return;this.active=n,document.documentElement.classList.toggle("has-"+this.className,n),this.el.classList.toggle("active",n);let r=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(r),setTimeout(()=>document.documentElement.classList.remove(r),500)}onPointerUp(n){A||(this.setActive(!0),n.preventDefault())}onDocumentPointerDown(n){if(this.active){if(n.target.closest(".col-menu, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(n){if(!A&&this.active&&n.target.closest(".col-menu")){let r=n.target.closest("a");if(r){let i=window.location.href;i.indexOf("#")!=-1&&(i=i.substring(0,i.indexOf("#"))),r.href.substring(0,i.length)==i&&setTimeout(()=>this.setActive(!1),250)}}}};var oe;try{oe=localStorage}catch{oe={getItem(){return null},setItem(){}}}var Q=oe;var Le=document.head.appendChild(document.createElement("style"));Le.dataset.for="filters";var ee=class extends I{constructor(n){super(n);this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),Le.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } +`}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.checked}setLocalStorage(n){Q.setItem(this.key,n.toString()),this.value=n,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),this.app.filterChanged(),document.querySelectorAll(".tsd-index-section").forEach(n=>{n.style.display="block";let r=Array.from(n.querySelectorAll(".tsd-index-link")).every(i=>i.offsetParent==null);n.style.display=r?"none":"block"})}};var te=class extends I{constructor(n){super(n);this.calculateHeights(),this.summary=this.el.querySelector(".tsd-accordion-summary"),this.icon=this.summary.querySelector("svg"),this.key=`tsd-accordion-${this.summary.textContent.replace(/\s+/g,"-").toLowerCase()}`,this.setLocalStorage(this.fromLocalStorage(),!0),this.summary.addEventListener("click",r=>this.toggleVisibility(r)),this.icon.style.transform=this.getIconRotation()}getIconRotation(n=this.el.open){return`rotate(${n?0:-90}deg)`}calculateHeights(){let n=this.el.open,{position:r,left:i}=this.el.style;this.el.style.position="fixed",this.el.style.left="-9999px",this.el.open=!0,this.expandedHeight=this.el.offsetHeight+"px",this.el.open=!1,this.collapsedHeight=this.el.offsetHeight+"px",this.el.open=n,this.el.style.height=n?this.expandedHeight:this.collapsedHeight,this.el.style.position=r,this.el.style.left=i}toggleVisibility(n){n.preventDefault(),this.el.style.overflow="hidden",this.el.open?this.collapse():this.expand()}expand(n=!0){this.el.open=!0,this.animate(this.collapsedHeight,this.expandedHeight,{opening:!0,duration:n?300:0})}collapse(n=!0){this.animate(this.expandedHeight,this.collapsedHeight,{opening:!1,duration:n?300:0})}animate(n,r,{opening:i,duration:s=300}){if(this.animation)return;let o={duration:s,easing:"ease"};this.animation=this.el.animate({height:[n,r]},o),this.icon.animate({transform:[this.icon.style.transform||this.getIconRotation(!i),this.getIconRotation(i)]},o).addEventListener("finish",()=>{this.icon.style.transform=this.getIconRotation(i)}),this.animation.addEventListener("finish",()=>this.animationEnd(i))}animationEnd(n){this.el.open=n,this.animation=void 0,this.el.style.height="auto",this.el.style.overflow="visible",this.setLocalStorage(n)}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.open}setLocalStorage(n,r=!1){this.fromLocalStorage()===n&&!r||(Q.setItem(this.key,n.toString()),this.el.open=n,this.handleValueChange(r))}handleValueChange(n=!1){this.fromLocalStorage()===this.el.open&&!n||(this.fromLocalStorage()?this.expand(!1):this.collapse(!1))}};function be(t){let e=Q.getItem("tsd-theme")||"os";t.value=e,Ee(e),t.addEventListener("change",()=>{Q.setItem("tsd-theme",t.value),Ee(t.value)})}function Ee(t){document.documentElement.dataset.theme=t}ve();B(X,".menu-highlight");B(K,"a[data-toggle]");B(te,".tsd-index-accordion");B(ee,".tsd-filter-item input[type=checkbox]");var we=document.getElementById("theme");we&&be(we);var je=new Y;Object.defineProperty(window,"app",{value:je});})(); +/*! Bundled license information: + +lunr/lunr.js: + (** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + *) + (*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + *) + (*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + *) +*/ diff --git a/docs/assets/search.js b/docs/assets/search.js new file mode 100644 index 0000000..41f603a --- /dev/null +++ b/docs/assets/search.js @@ -0,0 +1 @@ +window.searchData = JSON.parse("{\"kinds\":{\"8\":\"Enumeration\",\"16\":\"Enumeration Member\",\"32\":\"Variable\",\"64\":\"Function\",\"128\":\"Class\",\"256\":\"Interface\",\"512\":\"Constructor\",\"1024\":\"Property\",\"2048\":\"Method\",\"65536\":\"Type literal\",\"262144\":\"Accessor\",\"4194304\":\"Type alias\"},\"rows\":[{\"kind\":128,\"name\":\"Discovery\",\"url\":\"classes/Discovery.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Discovery.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"on\",\"url\":\"classes/Discovery.html#on\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Discovery\"},{\"kind\":1024,\"name\":\"socket\",\"url\":\"classes/Discovery.html#socket\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":1024,\"name\":\"address\",\"url\":\"classes/Discovery.html#address\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":1024,\"name\":\"broadcastAddress\",\"url\":\"classes/Discovery.html#broadcastAddress\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":1024,\"name\":\"options\",\"url\":\"classes/Discovery.html#options\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":1024,\"name\":\"peers\",\"url\":\"classes/Discovery.html#peers\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/Discovery.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":1024,\"name\":\"announceTimer\",\"url\":\"classes/Discovery.html#announceTimer\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":1024,\"name\":\"hasLooped\",\"url\":\"classes/Discovery.html#hasLooped\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"getConnectionInfo\",\"url\":\"classes/Discovery.html#getConnectionInfo\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"getDeviceList\",\"url\":\"classes/Discovery.html#getDeviceList\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"getDevices\",\"url\":\"classes/Discovery.html#getDevices\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"listen\",\"url\":\"classes/Discovery.html#listen\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"announce\",\"url\":\"classes/Discovery.html#announce\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"unannounce\",\"url\":\"classes/Discovery.html#unannounce\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"broadcastMessage\",\"url\":\"classes/Discovery.html#broadcastMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"listenForDevices\",\"url\":\"classes/Discovery.html#listenForDevices\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"readConnectionInfo\",\"url\":\"classes/Discovery.html#readConnectionInfo\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"createDiscoveryMessage\",\"url\":\"classes/Discovery.html#createDiscoveryMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"writeDiscoveryMessage\",\"url\":\"classes/Discovery.html#writeDiscoveryMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":2048,\"name\":\"findBroadcastIPs\",\"url\":\"classes/Discovery.html#findBroadcastIPs\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Discovery\"},{\"kind\":256,\"name\":\"FileTransferData\",\"url\":\"interfaces/FileTransferData.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"service\",\"url\":\"interfaces/FileTransferData.html#service\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferData\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"interfaces/FileTransferData.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferData\"},{\"kind\":1024,\"name\":\"txid\",\"url\":\"interfaces/FileTransferData.html#txid\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferData\"},{\"kind\":1024,\"name\":\"size\",\"url\":\"interfaces/FileTransferData.html#size\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferData\"},{\"kind\":1024,\"name\":\"offset\",\"url\":\"interfaces/FileTransferData.html#offset\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferData\"},{\"kind\":1024,\"name\":\"sources\",\"url\":\"interfaces/FileTransferData.html#sources\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferData\"},{\"kind\":1024,\"name\":\"data\",\"url\":\"interfaces/FileTransferData.html#data\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferData\"},{\"kind\":256,\"name\":\"FileTransferProgress\",\"url\":\"interfaces/FileTransferProgress.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"sizeLeft\",\"url\":\"interfaces/FileTransferProgress.html#sizeLeft\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferProgress\"},{\"kind\":1024,\"name\":\"total\",\"url\":\"interfaces/FileTransferProgress.html#total\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferProgress\"},{\"kind\":1024,\"name\":\"bytesDownloaded\",\"url\":\"interfaces/FileTransferProgress.html#bytesDownloaded\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferProgress\"},{\"kind\":1024,\"name\":\"percentComplete\",\"url\":\"interfaces/FileTransferProgress.html#percentComplete\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"FileTransferProgress\"},{\"kind\":128,\"name\":\"FileTransfer\",\"url\":\"classes/FileTransfer.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":1024,\"name\":\"emitter\",\"url\":\"classes/FileTransfer.html#emitter\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"#txid\",\"url\":\"classes/FileTransfer.html#_txid\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"instances\",\"url\":\"classes/FileTransfer.html#instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/FileTransfer.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"on\",\"url\":\"classes/FileTransfer.html#on\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/FileTransfer.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"receivedFile\",\"url\":\"classes/FileTransfer.html#receivedFile\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"#isAvailable\",\"url\":\"classes/FileTransfer.html#_isAvailable\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"newTxid\",\"url\":\"classes/FileTransfer.html#newTxid\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"instanceListener\",\"url\":\"classes/FileTransfer.html#instanceListener\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"parseData\",\"url\":\"classes/FileTransfer.html#parseData\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"messageHandler\",\"url\":\"classes/FileTransfer.html#messageHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"getFile\",\"url\":\"classes/FileTransfer.html#getFile\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"updateSources\",\"url\":\"classes/FileTransfer.html#updateSources\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"getSources\",\"url\":\"classes/FileTransfer.html#getSources\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"getSourceDirInfo\",\"url\":\"classes/FileTransfer.html#getSourceDirInfo\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"isAvailable\",\"url\":\"classes/FileTransfer.html#isAvailable\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"requestService\",\"url\":\"classes/FileTransfer.html#requestService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"releaseService\",\"url\":\"classes/FileTransfer.html#releaseService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"waitForFileMessage\",\"url\":\"classes/FileTransfer.html#waitForFileMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"requestStat\",\"url\":\"classes/FileTransfer.html#requestStat\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"requestSources\",\"url\":\"classes/FileTransfer.html#requestSources\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"requestPathInfo\",\"url\":\"classes/FileTransfer.html#requestPathInfo\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"requestFileTransferId\",\"url\":\"classes/FileTransfer.html#requestFileTransferId\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"requestChunkRange\",\"url\":\"classes/FileTransfer.html#requestChunkRange\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"signalTransferComplete\",\"url\":\"classes/FileTransfer.html#signalTransferComplete\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"signalMessageComplete\",\"url\":\"classes/FileTransfer.html#signalMessageComplete\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"sendNoSourcesReply\",\"url\":\"classes/FileTransfer.html#sendNoSourcesReply\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"device\",\"url\":\"classes/FileTransfer.html#device\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/FileTransfer.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"server\",\"url\":\"classes/FileTransfer.html#server\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"serverInfo\",\"url\":\"classes/FileTransfer.html#serverInfo\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"socket\",\"url\":\"classes/FileTransfer.html#socket\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"isBufferedService\",\"url\":\"classes/FileTransfer.html#isBufferedService\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/FileTransfer.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"start\",\"url\":\"classes/FileTransfer.html#start\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"stop\",\"url\":\"classes/FileTransfer.html#stop\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"waitForMessage\",\"url\":\"classes/FileTransfer.html#waitForMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"write\",\"url\":\"classes/FileTransfer.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"writeWithLength\",\"url\":\"classes/FileTransfer.html#writeWithLength\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":2048,\"name\":\"closeService\",\"url\":\"classes/FileTransfer.html#closeService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"FileTransfer\"},{\"kind\":128,\"name\":\"Service\",\"url\":\"classes/Service.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":1024,\"name\":\"instances\",\"url\":\"classes/Service.html#instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Service.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/Service.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"device\",\"url\":\"classes/Service.html#device\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/Service.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"server\",\"url\":\"classes/Service.html#server\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"serverInfo\",\"url\":\"classes/Service.html#serverInfo\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"socket\",\"url\":\"classes/Service.html#socket\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"isBufferedService\",\"url\":\"classes/Service.html#isBufferedService\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/Service.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":1024,\"name\":\"messageBuffer\",\"url\":\"classes/Service.html#messageBuffer\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"startServer\",\"url\":\"classes/Service.html#startServer\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"start\",\"url\":\"classes/Service.html#start\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"stop\",\"url\":\"classes/Service.html#stop\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"subMessageTest\",\"url\":\"classes/Service.html#subMessageTest\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"dataHandler\",\"url\":\"classes/Service.html#dataHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"waitForMessage\",\"url\":\"classes/Service.html#waitForMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"write\",\"url\":\"classes/Service.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"writeWithLength\",\"url\":\"classes/Service.html#writeWithLength\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"closeService\",\"url\":\"classes/Service.html#closeService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"parseData\",\"url\":\"classes/Service.html#parseData\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"messageHandler\",\"url\":\"classes/Service.html#messageHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":2048,\"name\":\"instanceListener\",\"url\":\"classes/Service.html#instanceListener\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Service\"},{\"kind\":256,\"name\":\"StateData\",\"url\":\"interfaces/StateData.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"service\",\"url\":\"interfaces/StateData.html#service\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StateData\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"interfaces/StateData.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StateData\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"interfaces/StateData.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StateData\"},{\"kind\":1024,\"name\":\"json\",\"url\":\"interfaces/StateData.html#json\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StateData\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"interfaces/StateData.html#json.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"StateData.json\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"interfaces/StateData.html#json.__type.type\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateData.json.__type\"},{\"kind\":1024,\"name\":\"string\",\"url\":\"interfaces/StateData.html#json.__type.string\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateData.json.__type\"},{\"kind\":1024,\"name\":\"value\",\"url\":\"interfaces/StateData.html#json.__type.value\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateData.json.__type\"},{\"kind\":1024,\"name\":\"state\",\"url\":\"interfaces/StateData.html#json.__type.state\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateData.json.__type\"},{\"kind\":1024,\"name\":\"interval\",\"url\":\"interfaces/StateData.html#interval\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StateData\"},{\"kind\":128,\"name\":\"StateMap\",\"url\":\"classes/StateMap.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":1024,\"name\":\"emitter\",\"url\":\"classes/StateMap.html#emitter\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"#instances\",\"url\":\"classes/StateMap.html#_instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"instances\",\"url\":\"classes/StateMap.html#instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/StateMap.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/StateMap.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"instanceListener\",\"url\":\"classes/StateMap.html#instanceListener\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"subscribe\",\"url\":\"classes/StateMap.html#subscribe\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"parseData\",\"url\":\"classes/StateMap.html#parseData\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"messageHandler\",\"url\":\"classes/StateMap.html#messageHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"sendStateResponse\",\"url\":\"classes/StateMap.html#sendStateResponse\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"subscribeState\",\"url\":\"classes/StateMap.html#subscribeState\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"device\",\"url\":\"classes/StateMap.html#device\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/StateMap.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"server\",\"url\":\"classes/StateMap.html#server\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"serverInfo\",\"url\":\"classes/StateMap.html#serverInfo\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"socket\",\"url\":\"classes/StateMap.html#socket\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"isBufferedService\",\"url\":\"classes/StateMap.html#isBufferedService\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/StateMap.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"start\",\"url\":\"classes/StateMap.html#start\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"stop\",\"url\":\"classes/StateMap.html#stop\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"waitForMessage\",\"url\":\"classes/StateMap.html#waitForMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"write\",\"url\":\"classes/StateMap.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"writeWithLength\",\"url\":\"classes/StateMap.html#writeWithLength\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":2048,\"name\":\"closeService\",\"url\":\"classes/StateMap.html#closeService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"StateMap\"},{\"kind\":256,\"name\":\"DirectoryData\",\"url\":\"interfaces/DirectoryData.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"interfaces/DirectoryData.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DirectoryData\"},{\"kind\":128,\"name\":\"Directory\",\"url\":\"classes/Directory.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":1024,\"name\":\"instances\",\"url\":\"classes/Directory.html#instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Directory.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/Directory.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"isBufferedService\",\"url\":\"classes/Directory.html#isBufferedService\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"timeAlive\",\"url\":\"classes/Directory.html#timeAlive\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"parseData\",\"url\":\"classes/Directory.html#parseData\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"messageHandler\",\"url\":\"classes/Directory.html#messageHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"sendServiceAnnouncement\",\"url\":\"classes/Directory.html#sendServiceAnnouncement\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"sendTimeStampReply\",\"url\":\"classes/Directory.html#sendTimeStampReply\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"instanceListener\",\"url\":\"classes/Directory.html#instanceListener\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"device\",\"url\":\"classes/Directory.html#device\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/Directory.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"server\",\"url\":\"classes/Directory.html#server\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"serverInfo\",\"url\":\"classes/Directory.html#serverInfo\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"socket\",\"url\":\"classes/Directory.html#socket\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/Directory.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"start\",\"url\":\"classes/Directory.html#start\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"stop\",\"url\":\"classes/Directory.html#stop\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"waitForMessage\",\"url\":\"classes/Directory.html#waitForMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"write\",\"url\":\"classes/Directory.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"writeWithLength\",\"url\":\"classes/Directory.html#writeWithLength\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":2048,\"name\":\"closeService\",\"url\":\"classes/Directory.html#closeService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Directory\"},{\"kind\":256,\"name\":\"BeatData\",\"url\":\"interfaces/BeatData.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"service\",\"url\":\"interfaces/BeatData.html#service\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"BeatData\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"interfaces/BeatData.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"BeatData\"},{\"kind\":1024,\"name\":\"clock\",\"url\":\"interfaces/BeatData.html#clock\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"BeatData\"},{\"kind\":1024,\"name\":\"deckCount\",\"url\":\"interfaces/BeatData.html#deckCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"BeatData\"},{\"kind\":1024,\"name\":\"deck\",\"url\":\"interfaces/BeatData.html#deck\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"BeatData\"},{\"kind\":128,\"name\":\"BeatInfo\",\"url\":\"classes/BeatInfo.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":1024,\"name\":\"#instances\",\"url\":\"classes/BeatInfo.html#_instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"emitter\",\"url\":\"classes/BeatInfo.html#emitter\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"getInstances\",\"url\":\"classes/BeatInfo.html#getInstances\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"instances\",\"url\":\"classes/BeatInfo.html#instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/BeatInfo.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"on\",\"url\":\"classes/BeatInfo.html#on\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/BeatInfo.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"#userBeatCallback\",\"url\":\"classes/BeatInfo.html#_userBeatCallback\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"#userBeatOptions\",\"url\":\"classes/BeatInfo.html#_userBeatOptions\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"#currentBeatData\",\"url\":\"classes/BeatInfo.html#_currentBeatData\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"isBufferedService\",\"url\":\"classes/BeatInfo.html#isBufferedService\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"instanceListener\",\"url\":\"classes/BeatInfo.html#instanceListener\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"deleteDevice\",\"url\":\"classes/BeatInfo.html#deleteDevice\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"getBeatData\",\"url\":\"classes/BeatInfo.html#getBeatData\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"startBeatInfo\",\"url\":\"classes/BeatInfo.html#startBeatInfo\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"sendBeatInfoRequest\",\"url\":\"classes/BeatInfo.html#sendBeatInfoRequest\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"parseData\",\"url\":\"classes/BeatInfo.html#parseData\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"messageHandler\",\"url\":\"classes/BeatInfo.html#messageHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"device\",\"url\":\"classes/BeatInfo.html#device\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/BeatInfo.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"server\",\"url\":\"classes/BeatInfo.html#server\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"serverInfo\",\"url\":\"classes/BeatInfo.html#serverInfo\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"socket\",\"url\":\"classes/BeatInfo.html#socket\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/BeatInfo.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"start\",\"url\":\"classes/BeatInfo.html#start\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"stop\",\"url\":\"classes/BeatInfo.html#stop\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"waitForMessage\",\"url\":\"classes/BeatInfo.html#waitForMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"write\",\"url\":\"classes/BeatInfo.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"writeWithLength\",\"url\":\"classes/BeatInfo.html#writeWithLength\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":2048,\"name\":\"closeService\",\"url\":\"classes/BeatInfo.html#closeService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"BeatInfo\"},{\"kind\":256,\"name\":\"TimeSyncData\",\"url\":\"interfaces/TimeSyncData.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"msgs\",\"url\":\"interfaces/TimeSyncData.html#msgs\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TimeSyncData\"},{\"kind\":1024,\"name\":\"timestamp\",\"url\":\"interfaces/TimeSyncData.html#timestamp\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TimeSyncData\"},{\"kind\":128,\"name\":\"TimeSynchronization\",\"url\":\"classes/TimeSynchronization.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":1024,\"name\":\"instances\",\"url\":\"classes/TimeSynchronization.html#instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/TimeSynchronization.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/TimeSynchronization.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"isBufferedService\",\"url\":\"classes/TimeSynchronization.html#isBufferedService\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"localTime\",\"url\":\"classes/TimeSynchronization.html#localTime\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"remoteTime\",\"url\":\"classes/TimeSynchronization.html#remoteTime\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"avgTimeArray\",\"url\":\"classes/TimeSynchronization.html#avgTimeArray\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"sendTimeSyncRequest\",\"url\":\"classes/TimeSynchronization.html#sendTimeSyncRequest\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"timeSyncMsgHelper\",\"url\":\"classes/TimeSynchronization.html#timeSyncMsgHelper\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"getTimeStamp\",\"url\":\"classes/TimeSynchronization.html#getTimeStamp\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"sendTimeSyncQuery\",\"url\":\"classes/TimeSynchronization.html#sendTimeSyncQuery\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"parseData\",\"url\":\"classes/TimeSynchronization.html#parseData\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"timeAvg\",\"url\":\"classes/TimeSynchronization.html#timeAvg\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"messageHandler\",\"url\":\"classes/TimeSynchronization.html#messageHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"instanceListener\",\"url\":\"classes/TimeSynchronization.html#instanceListener\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"device\",\"url\":\"classes/TimeSynchronization.html#device\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/TimeSynchronization.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"server\",\"url\":\"classes/TimeSynchronization.html#server\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"serverInfo\",\"url\":\"classes/TimeSynchronization.html#serverInfo\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"socket\",\"url\":\"classes/TimeSynchronization.html#socket\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/TimeSynchronization.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"start\",\"url\":\"classes/TimeSynchronization.html#start\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"stop\",\"url\":\"classes/TimeSynchronization.html#stop\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"waitForMessage\",\"url\":\"classes/TimeSynchronization.html#waitForMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"write\",\"url\":\"classes/TimeSynchronization.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"writeWithLength\",\"url\":\"classes/TimeSynchronization.html#writeWithLength\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":2048,\"name\":\"closeService\",\"url\":\"classes/TimeSynchronization.html#closeService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"TimeSynchronization\"},{\"kind\":4194304,\"name\":\"BroadcastMessage\",\"url\":\"types/BroadcastMessage.html\",\"classes\":\"tsd-kind-type-alias\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"types/BroadcastMessage.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"BroadcastMessage\"},{\"kind\":1024,\"name\":\"databaseUuid\",\"url\":\"types/BroadcastMessage.html#__type.databaseUuid\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"BroadcastMessage.__type\"},{\"kind\":1024,\"name\":\"trackId\",\"url\":\"types/BroadcastMessage.html#__type.trackId\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"BroadcastMessage.__type\"},{\"kind\":1024,\"name\":\"listId\",\"url\":\"types/BroadcastMessage.html#__type.listId\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"BroadcastMessage.__type\"},{\"kind\":1024,\"name\":\"sessionId\",\"url\":\"types/BroadcastMessage.html#__type.sessionId\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"BroadcastMessage.__type\"},{\"kind\":256,\"name\":\"BroadcastData\",\"url\":\"interfaces/BroadcastData.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":128,\"name\":\"Broadcast\",\"url\":\"classes/Broadcast.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":1024,\"name\":\"emitter\",\"url\":\"classes/Broadcast.html#emitter\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"instances\",\"url\":\"classes/Broadcast.html#instances\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Broadcast.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/Broadcast.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"isBufferedService\",\"url\":\"classes/Broadcast.html#isBufferedService\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"parseData\",\"url\":\"classes/Broadcast.html#parseData\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"messageHandler\",\"url\":\"classes/Broadcast.html#messageHandler\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"instanceListener\",\"url\":\"classes/Broadcast.html#instanceListener\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"device\",\"url\":\"classes/Broadcast.html#device\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/Broadcast.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"server\",\"url\":\"classes/Broadcast.html#server\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"serverInfo\",\"url\":\"classes/Broadcast.html#serverInfo\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"socket\",\"url\":\"classes/Broadcast.html#socket\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":1024,\"name\":\"timeout\",\"url\":\"classes/Broadcast.html#timeout\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"start\",\"url\":\"classes/Broadcast.html#start\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"stop\",\"url\":\"classes/Broadcast.html#stop\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"waitForMessage\",\"url\":\"classes/Broadcast.html#waitForMessage\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"write\",\"url\":\"classes/Broadcast.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"writeWithLength\",\"url\":\"classes/Broadcast.html#writeWithLength\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":2048,\"name\":\"closeService\",\"url\":\"classes/Broadcast.html#closeService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"Broadcast\"},{\"kind\":128,\"name\":\"StageLinq\",\"url\":\"classes/StageLinq.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":1024,\"name\":\"options\",\"url\":\"classes/StageLinq.html#options\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":1024,\"name\":\"logger\",\"url\":\"classes/StageLinq.html#logger\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":1024,\"name\":\"devices\",\"url\":\"classes/StageLinq.html#devices\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":1024,\"name\":\"discovery\",\"url\":\"classes/StageLinq.html#discovery\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":1024,\"name\":\"sources\",\"url\":\"classes/StageLinq.html#sources\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":1024,\"name\":\"status\",\"url\":\"classes/StageLinq.html#status\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":1024,\"name\":\"directory\",\"url\":\"classes/StageLinq.html#directory\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":2048,\"name\":\"startServiceListener\",\"url\":\"classes/StageLinq.html#startServiceListener\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":2048,\"name\":\"connect\",\"url\":\"classes/StageLinq.html#connect\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":2048,\"name\":\"disconnect\",\"url\":\"classes/StageLinq.html#disconnect\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/StageLinq.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"StageLinq\"},{\"kind\":128,\"name\":\"Track\",\"url\":\"classes/Track.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Track.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"#prefix\",\"url\":\"classes/Track.html#_prefix\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"#source\",\"url\":\"classes/Track.html#_source\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Track\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/Track.html#_source.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"Track.#source\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/Track.html#_source.__type.name\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"Track.#source.__type\"},{\"kind\":1024,\"name\":\"location\",\"url\":\"classes/Track.html#_source.__type.location\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"Track.#source.__type\"},{\"kind\":1024,\"name\":\"path\",\"url\":\"classes/Track.html#_source.__type.path\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"Track.#source.__type\"},{\"kind\":1024,\"name\":\"ArtistName\",\"url\":\"classes/Track.html#ArtistName\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"CurrentBPM\",\"url\":\"classes/Track.html#CurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"SampleRate\",\"url\":\"classes/Track.html#SampleRate\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"SongAnalyzed\",\"url\":\"classes/Track.html#SongAnalyzed\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"SongLoaded\",\"url\":\"classes/Track.html#SongLoaded\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"SongName\",\"url\":\"classes/Track.html#SongName\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"SoundSwitchGUID\",\"url\":\"classes/Track.html#SoundSwitchGUID\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"TrackBytes\",\"url\":\"classes/Track.html#TrackBytes\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"TrackLength\",\"url\":\"classes/Track.html#TrackLength\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"TrackName\",\"url\":\"classes/Track.html#TrackName\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"TrackNetworkPath\",\"url\":\"classes/Track.html#TrackNetworkPath\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":1024,\"name\":\"TrackURI\",\"url\":\"classes/Track.html#TrackURI\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":262144,\"name\":\"prefix\",\"url\":\"classes/Track.html#prefix\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":262144,\"name\":\"source\",\"url\":\"classes/Track.html#source\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class\",\"parent\":\"Track\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/Track.html#source.source-1.__type-1\",\"classes\":\"tsd-kind-type-literal\",\"parent\":\"Track.source.source\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/Track.html#source.source-1.__type-1.name-1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"Track.source.source.__type\"},{\"kind\":1024,\"name\":\"location\",\"url\":\"classes/Track.html#source.source-1.__type-1.location-1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"Track.source.source.__type\"},{\"kind\":1024,\"name\":\"path\",\"url\":\"classes/Track.html#source.source-1.__type-1.path-1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"Track.source.source.__type\"},{\"kind\":256,\"name\":\"TrackDBEntry\",\"url\":\"interfaces/TrackDBEntry.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"id\",\"url\":\"interfaces/TrackDBEntry.html#id\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"playOrder\",\"url\":\"interfaces/TrackDBEntry.html#playOrder\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"length\",\"url\":\"interfaces/TrackDBEntry.html#length\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"bpm\",\"url\":\"interfaces/TrackDBEntry.html#bpm\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"year\",\"url\":\"interfaces/TrackDBEntry.html#year\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"path\",\"url\":\"interfaces/TrackDBEntry.html#path\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"filename\",\"url\":\"interfaces/TrackDBEntry.html#filename\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"bitrate\",\"url\":\"interfaces/TrackDBEntry.html#bitrate\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"bpmAnalyzed\",\"url\":\"interfaces/TrackDBEntry.html#bpmAnalyzed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"albumArtId\",\"url\":\"interfaces/TrackDBEntry.html#albumArtId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"fileBytes\",\"url\":\"interfaces/TrackDBEntry.html#fileBytes\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"title\",\"url\":\"interfaces/TrackDBEntry.html#title\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"artist\",\"url\":\"interfaces/TrackDBEntry.html#artist\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"album\",\"url\":\"interfaces/TrackDBEntry.html#album\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"genre\",\"url\":\"interfaces/TrackDBEntry.html#genre\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"comment\",\"url\":\"interfaces/TrackDBEntry.html#comment\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"label\",\"url\":\"interfaces/TrackDBEntry.html#label\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"composer\",\"url\":\"interfaces/TrackDBEntry.html#composer\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"remixer\",\"url\":\"interfaces/TrackDBEntry.html#remixer\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"key\",\"url\":\"interfaces/TrackDBEntry.html#key\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"rating\",\"url\":\"interfaces/TrackDBEntry.html#rating\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"albumArt\",\"url\":\"interfaces/TrackDBEntry.html#albumArt\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"timeLastPlayed\",\"url\":\"interfaces/TrackDBEntry.html#timeLastPlayed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"isPlayed\",\"url\":\"interfaces/TrackDBEntry.html#isPlayed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"fileType\",\"url\":\"interfaces/TrackDBEntry.html#fileType\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"isAnalyzed\",\"url\":\"interfaces/TrackDBEntry.html#isAnalyzed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"dateCreated\",\"url\":\"interfaces/TrackDBEntry.html#dateCreated\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"dateAdded\",\"url\":\"interfaces/TrackDBEntry.html#dateAdded\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"isAvailable\",\"url\":\"interfaces/TrackDBEntry.html#isAvailable\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"isMetadataOfPackedTrackChanged\",\"url\":\"interfaces/TrackDBEntry.html#isMetadataOfPackedTrackChanged\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"isPerfomanceDataOfPackedTrackChanged\",\"url\":\"interfaces/TrackDBEntry.html#isPerfomanceDataOfPackedTrackChanged\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"playedIndicator\",\"url\":\"interfaces/TrackDBEntry.html#playedIndicator\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"isMetadataImported\",\"url\":\"interfaces/TrackDBEntry.html#isMetadataImported\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"pdbImportKey\",\"url\":\"interfaces/TrackDBEntry.html#pdbImportKey\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"streamingSource\",\"url\":\"interfaces/TrackDBEntry.html#streamingSource\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"uri\",\"url\":\"interfaces/TrackDBEntry.html#uri\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"isBeatGridLocked\",\"url\":\"interfaces/TrackDBEntry.html#isBeatGridLocked\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"originDatabaseUuid\",\"url\":\"interfaces/TrackDBEntry.html#originDatabaseUuid\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"originTrackId\",\"url\":\"interfaces/TrackDBEntry.html#originTrackId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"trackData\",\"url\":\"interfaces/TrackDBEntry.html#trackData\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"overviewWaveFormData\",\"url\":\"interfaces/TrackDBEntry.html#overviewWaveFormData\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"beatData\",\"url\":\"interfaces/TrackDBEntry.html#beatData\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"quickCues\",\"url\":\"interfaces/TrackDBEntry.html#quickCues\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"loops\",\"url\":\"interfaces/TrackDBEntry.html#loops\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"thirdPartySourceId\",\"url\":\"interfaces/TrackDBEntry.html#thirdPartySourceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"streamingFlags\",\"url\":\"interfaces/TrackDBEntry.html#streamingFlags\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"explicitLyrics\",\"url\":\"interfaces/TrackDBEntry.html#explicitLyrics\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":1024,\"name\":\"activeOnLoadLoops\",\"url\":\"interfaces/TrackDBEntry.html#activeOnLoadLoops\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"TrackDBEntry\"},{\"kind\":32,\"name\":\"StateNames\",\"url\":\"variables/StateNames.html\",\"classes\":\"tsd-kind-variable\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"variables/StateNames.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-variable\",\"parent\":\"StateNames\"},{\"kind\":1024,\"name\":\"player\",\"url\":\"variables/StateNames.html#__type.player\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"variables/StateNames.html#__type.player.__type-2\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"StateNames.__type.player\"},{\"kind\":1024,\"name\":\"ClientLibrarianDevicesControllerCurrentDevice\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientLibrarianDevicesControllerCurrentDevice\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientLibrarianDevicesControllerCurrentDeviceNetworkPath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientLibrarianDevicesControllerCurrentDeviceNetworkPath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientLibrarianDevicesControllerHasSDCardConnected\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientLibrarianDevicesControllerHasSDCardConnected\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientLibrarianDevicesControllerHasUsbDeviceConnected\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientLibrarianDevicesControllerHasUsbDeviceConnected\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesLayerA\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesLayerA\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesLayerB\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesLayerB\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesPlayer\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesPlayer\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesPlayerJogColorA\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesPlayerJogColorA\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesPlayerJogColorB\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesPlayerJogColorB\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor1\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor1A\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor1A\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor1B\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor1B\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor2\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor2\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor2A\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor2A\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor2B\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor2B\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor3\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor3\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor3A\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor3A\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor3B\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor3B\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor4\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor4\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor4A\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor4A\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationPlayerColor4B\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationPlayerColor4B\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"ClientPreferencesProfileApplicationSyncMode\",\"url\":\"variables/StateNames.html#__type.player.__type-2.ClientPreferencesProfileApplicationSyncMode\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1SyncPlayState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1SyncPlayState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2SyncPlayState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2SyncPlayState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3SyncPlayState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3SyncPlayState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4SyncPlayState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4SyncPlayState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1DeckIsMaster\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1DeckIsMaster\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2DeckIsMaster\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2DeckIsMaster\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3DeckIsMaster\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3DeckIsMaster\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4DeckIsMaster\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4DeckIsMaster\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineSyncNetworkSyncType\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineSyncNetworkSyncType\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineSyncNetworkMasterStatus\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineSyncNetworkMasterStatus\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineMasterMasterTempo\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineMasterMasterTempo\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeckCount\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeckCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1CurrentBPM\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1CurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1ExternalMixerVolume\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1ExternalMixerVolume\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1ExternalScratchWheelTouch\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1ExternalScratchWheelTouch\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1PadsView\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1PadsView\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1Play\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1Play\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1PlayState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1PlayState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1PlayStatePath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1PlayStatePath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1Speed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1Speed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1SpeedNeutral\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1SpeedNeutral\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1SpeedOffsetDown\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1SpeedOffsetDown\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1SpeedOffsetUp\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1SpeedOffsetUp\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1SpeedRange\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1SpeedRange\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1SpeedState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1SpeedState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1SyncMode\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1SyncMode\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackArtistName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackArtistName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackBleep\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackBleep\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackCuePosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackCuePosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackCurrentBPM\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackCurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackCurrentKeyIndex\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackCurrentKeyIndex\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackCurrentLoopInPosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackCurrentLoopInPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackCurrentLoopOutPosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackCurrentLoopOutPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackCurrentLoopSizeInBeats\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackCurrentLoopSizeInBeats\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackKeyLock\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackKeyLock\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopEnableState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopEnableState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopQuickLoop1\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopQuickLoop1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopQuickLoop2\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopQuickLoop2\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopQuickLoop3\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopQuickLoop3\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopQuickLoop4\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopQuickLoop4\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopQuickLoop5\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopQuickLoop5\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopQuickLoop6\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopQuickLoop6\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopQuickLoop7\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopQuickLoop7\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackLoopQuickLoop8\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackLoopQuickLoop8\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackPlayPauseLEDState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackPlayPauseLEDState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackSampleRate\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackSampleRate\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackSongAnalyzed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackSongAnalyzed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackSongLoaded\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackSongLoaded\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackSongName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackSongName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackSoundSwitchGUID\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackSoundSwitchGUID\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackTrackBytes\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackTrackBytes\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackTrackData\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackTrackData\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackTrackLength\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackTrackLength\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackTrackName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackTrackName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackTrackNetworkPath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackTrackNetworkPath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackTrackURI\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackTrackURI\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck1TrackTrackWasPlayed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck1TrackTrackWasPlayed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2CurrentBPM\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2CurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2ExternalMixerVolume\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2ExternalMixerVolume\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2ExternalScratchWheelTouch\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2ExternalScratchWheelTouch\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2PadsView\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2PadsView\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2Play\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2Play\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2PlayState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2PlayState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2PlayStatePath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2PlayStatePath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2Speed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2Speed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2SpeedNeutral\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2SpeedNeutral\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2SpeedOffsetDown\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2SpeedOffsetDown\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2SpeedOffsetUp\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2SpeedOffsetUp\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2SpeedRange\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2SpeedRange\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2SpeedState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2SpeedState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2SyncMode\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2SyncMode\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackArtistName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackArtistName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackBleep\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackBleep\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackCuePosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackCuePosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackCurrentBPM\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackCurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackCurrentKeyIndex\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackCurrentKeyIndex\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackCurrentLoopInPosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackCurrentLoopInPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackCurrentLoopOutPosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackCurrentLoopOutPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackCurrentLoopSizeInBeats\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackCurrentLoopSizeInBeats\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackKeyLock\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackKeyLock\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopEnableState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopEnableState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopQuickLoop1\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopQuickLoop1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopQuickLoop2\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopQuickLoop2\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopQuickLoop3\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopQuickLoop3\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopQuickLoop4\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopQuickLoop4\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopQuickLoop5\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopQuickLoop5\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopQuickLoop6\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopQuickLoop6\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopQuickLoop7\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopQuickLoop7\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackLoopQuickLoop8\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackLoopQuickLoop8\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackPlayPauseLEDState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackPlayPauseLEDState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackSampleRate\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackSampleRate\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackSongAnalyzed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackSongAnalyzed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackSongLoaded\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackSongLoaded\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackSongName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackSongName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackSoundSwitchGUID\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackSoundSwitchGUID\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackTrackBytes\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackTrackBytes\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackTrackData\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackTrackData\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackTrackLength\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackTrackLength\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackTrackName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackTrackName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackTrackNetworkPath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackTrackNetworkPath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackTrackURI\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackTrackURI\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck2TrackTrackWasPlayed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck2TrackTrackWasPlayed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3CurrentBPM\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3CurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3ExternalMixerVolume\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3ExternalMixerVolume\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3ExternalScratchWheelTouch\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3ExternalScratchWheelTouch\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3PadsView\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3PadsView\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3Play\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3Play\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3PlayState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3PlayState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3PlayStatePath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3PlayStatePath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3Speed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3Speed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3SpeedNeutral\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3SpeedNeutral\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3SpeedOffsetDown\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3SpeedOffsetDown\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3SpeedOffsetUp\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3SpeedOffsetUp\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3SpeedRange\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3SpeedRange\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3SpeedState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3SpeedState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3SyncMode\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3SyncMode\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackArtistName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackArtistName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackBleep\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackBleep\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackCuePosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackCuePosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackCurrentBPM\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackCurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackCurrentKeyIndex\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackCurrentKeyIndex\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackCurrentLoopInPosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackCurrentLoopInPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackCurrentLoopOutPosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackCurrentLoopOutPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackCurrentLoopSizeInBeats\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackCurrentLoopSizeInBeats\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackKeyLock\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackKeyLock\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopEnableState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopEnableState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopQuickLoop1\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopQuickLoop1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopQuickLoop2\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopQuickLoop2\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopQuickLoop3\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopQuickLoop3\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopQuickLoop4\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopQuickLoop4\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopQuickLoop5\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopQuickLoop5\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopQuickLoop6\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopQuickLoop6\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopQuickLoop7\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopQuickLoop7\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackLoopQuickLoop8\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackLoopQuickLoop8\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackPlayPauseLEDState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackPlayPauseLEDState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackSampleRate\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackSampleRate\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackSongAnalyzed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackSongAnalyzed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackSongLoaded\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackSongLoaded\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackSongName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackSongName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackSoundSwitchGUID\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackSoundSwitchGUID\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackTrackBytes\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackTrackBytes\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackTrackData\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackTrackData\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackTrackLength\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackTrackLength\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackTrackName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackTrackName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackTrackNetworkPath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackTrackNetworkPath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackTrackURI\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackTrackURI\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck3TrackTrackWasPlayed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck3TrackTrackWasPlayed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4CurrentBPM\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4CurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4ExternalMixerVolume\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4ExternalMixerVolume\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4ExternalScratchWheelTouch\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4ExternalScratchWheelTouch\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4PadsView\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4PadsView\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4Play\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4Play\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4PlayState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4PlayState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4PlayStatePath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4PlayStatePath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4Speed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4Speed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4SpeedNeutral\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4SpeedNeutral\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4SpeedOffsetDown\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4SpeedOffsetDown\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4SpeedOffsetUp\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4SpeedOffsetUp\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4SpeedRange\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4SpeedRange\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4SpeedState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4SpeedState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4SyncMode\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4SyncMode\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackArtistName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackArtistName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackBleep\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackBleep\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackCuePosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackCuePosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackCurrentBPM\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackCurrentBPM\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackCurrentKeyIndex\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackCurrentKeyIndex\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackCurrentLoopInPosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackCurrentLoopInPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackCurrentLoopOutPosition\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackCurrentLoopOutPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackCurrentLoopSizeInBeats\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackCurrentLoopSizeInBeats\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackKeyLock\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackKeyLock\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopEnableState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopEnableState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopQuickLoop1\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopQuickLoop1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopQuickLoop2\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopQuickLoop2\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopQuickLoop3\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopQuickLoop3\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopQuickLoop4\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopQuickLoop4\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopQuickLoop5\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopQuickLoop5\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopQuickLoop6\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopQuickLoop6\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopQuickLoop7\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopQuickLoop7\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackLoopQuickLoop8\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackLoopQuickLoop8\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackPlayPauseLEDState\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackPlayPauseLEDState\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackSampleRate\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackSampleRate\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackSongAnalyzed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackSongAnalyzed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackSongLoaded\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackSongLoaded\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackSongName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackSongName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackSoundSwitchGUID\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackSoundSwitchGUID\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackTrackBytes\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackTrackBytes\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackTrackData\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackTrackData\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackTrackLength\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackTrackLength\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackTrackName\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackTrackName\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackTrackNetworkPath\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackTrackNetworkPath\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackTrackURI\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackTrackURI\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"EngineDeck4TrackTrackWasPlayed\",\"url\":\"variables/StateNames.html#__type.player.__type-2.EngineDeck4TrackTrackWasPlayed\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"GUIDecksDeckActiveDeck\",\"url\":\"variables/StateNames.html#__type.player.__type-2.GUIDecksDeckActiveDeck\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.player.__type\"},{\"kind\":1024,\"name\":\"mixer\",\"url\":\"variables/StateNames.html#__type.mixer\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"StateNames.__type.mixer\"},{\"kind\":1024,\"name\":\"MixerCH1faderPosition\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerCH1faderPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerCH2faderPosition\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerCH2faderPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerCH3faderPosition\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerCH3faderPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerCH4faderPosition\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerCH4faderPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerCrossfaderPosition\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerCrossfaderPosition\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerChannelAssignment1\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerChannelAssignment1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerChannelAssignment2\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerChannelAssignment2\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerChannelAssignment3\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerChannelAssignment3\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerChannelAssignment4\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerChannelAssignment4\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":1024,\"name\":\"MixerNumberOfChannels\",\"url\":\"variables/StateNames.html#__type.mixer.__type-1.MixerNumberOfChannels\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"StateNames.__type.mixer.__type\"},{\"kind\":32,\"name\":\"Units\",\"url\":\"variables/Units.html\",\"classes\":\"tsd-kind-variable\"},{\"kind\":256,\"name\":\"DiscoveryMessage\",\"url\":\"interfaces/DiscoveryMessage.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"interfaces/DiscoveryMessage.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessage\"},{\"kind\":1024,\"name\":\"source\",\"url\":\"interfaces/DiscoveryMessage.html#source\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessage\"},{\"kind\":1024,\"name\":\"action\",\"url\":\"interfaces/DiscoveryMessage.html#action\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessage\"},{\"kind\":1024,\"name\":\"software\",\"url\":\"interfaces/DiscoveryMessage.html#software\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessage\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"interfaces/DiscoveryMessage.html#software.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"DiscoveryMessage.software\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"interfaces/DiscoveryMessage.html#software.__type.name\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"DiscoveryMessage.software.__type\"},{\"kind\":1024,\"name\":\"version\",\"url\":\"interfaces/DiscoveryMessage.html#software.__type.version\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"DiscoveryMessage.software.__type\"},{\"kind\":1024,\"name\":\"port\",\"url\":\"interfaces/DiscoveryMessage.html#port\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessage\"},{\"kind\":256,\"name\":\"ConnectionInfo\",\"url\":\"interfaces/ConnectionInfo.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"address\",\"url\":\"interfaces/ConnectionInfo.html#address\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"ConnectionInfo\"},{\"kind\":1024,\"name\":\"unit\",\"url\":\"interfaces/ConnectionInfo.html#unit\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"ConnectionInfo\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"interfaces/ConnectionInfo.html#unit.__type-1\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"ConnectionInfo.unit\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"interfaces/ConnectionInfo.html#unit.__type-1.name-1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"ConnectionInfo.unit.__type\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"interfaces/ConnectionInfo.html#unit.__type-1.type\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"ConnectionInfo.unit.__type\"},{\"kind\":1024,\"name\":\"decks\",\"url\":\"interfaces/ConnectionInfo.html#unit.__type-1.decks\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"ConnectionInfo.unit.__type\"},{\"kind\":1024,\"name\":\"addressPort\",\"url\":\"interfaces/ConnectionInfo.html#addressPort\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"ConnectionInfo\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"interfaces/ConnectionInfo.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"ConnectionInfo\"},{\"kind\":1024,\"name\":\"source\",\"url\":\"interfaces/ConnectionInfo.html#source\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"ConnectionInfo\"},{\"kind\":1024,\"name\":\"action\",\"url\":\"interfaces/ConnectionInfo.html#action\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"ConnectionInfo\"},{\"kind\":1024,\"name\":\"software\",\"url\":\"interfaces/ConnectionInfo.html#software\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"ConnectionInfo\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"interfaces/ConnectionInfo.html#software.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-property\",\"parent\":\"ConnectionInfo.software\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"interfaces/ConnectionInfo.html#software.__type.name\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"ConnectionInfo.software.__type\"},{\"kind\":1024,\"name\":\"version\",\"url\":\"interfaces/ConnectionInfo.html#software.__type.version\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"ConnectionInfo.software.__type\"},{\"kind\":1024,\"name\":\"port\",\"url\":\"interfaces/ConnectionInfo.html#port\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"ConnectionInfo\"},{\"kind\":256,\"name\":\"ServiceMessage\",\"url\":\"interfaces/ServiceMessage.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"id\",\"url\":\"interfaces/ServiceMessage.html#id\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"ServiceMessage\"},{\"kind\":1024,\"name\":\"message\",\"url\":\"interfaces/ServiceMessage.html#message\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"ServiceMessage\"},{\"kind\":4194304,\"name\":\"IpAddress\",\"url\":\"types/IpAddress.html\",\"classes\":\"tsd-kind-type-alias\"},{\"kind\":4194304,\"name\":\"IpAddressPort\",\"url\":\"types/IpAddressPort.html\",\"classes\":\"tsd-kind-type-alias\"},{\"kind\":256,\"name\":\"DiscoveryMessageOptions\",\"url\":\"interfaces/DiscoveryMessageOptions.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"interfaces/DiscoveryMessageOptions.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessageOptions\"},{\"kind\":1024,\"name\":\"version\",\"url\":\"interfaces/DiscoveryMessageOptions.html#version\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessageOptions\"},{\"kind\":1024,\"name\":\"source\",\"url\":\"interfaces/DiscoveryMessageOptions.html#source\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessageOptions\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"interfaces/DiscoveryMessageOptions.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessageOptions\"},{\"kind\":1024,\"name\":\"port\",\"url\":\"interfaces/DiscoveryMessageOptions.html#port\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"DiscoveryMessageOptions\"},{\"kind\":256,\"name\":\"StageLinqOptions\",\"url\":\"interfaces/StageLinqOptions.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"maxRetries\",\"url\":\"interfaces/StageLinqOptions.html#maxRetries\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StageLinqOptions\"},{\"kind\":1024,\"name\":\"actingAs\",\"url\":\"interfaces/StageLinqOptions.html#actingAs\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StageLinqOptions\"},{\"kind\":1024,\"name\":\"downloadDbSources\",\"url\":\"interfaces/StageLinqOptions.html#downloadDbSources\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StageLinqOptions\"},{\"kind\":1024,\"name\":\"services\",\"url\":\"interfaces/StageLinqOptions.html#services\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StageLinqOptions\"},{\"kind\":1024,\"name\":\"connectToMixer\",\"url\":\"interfaces/StageLinqOptions.html#connectToMixer\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"StageLinqOptions\"},{\"kind\":8,\"name\":\"Services\",\"url\":\"enums/Services.html\",\"classes\":\"tsd-kind-enum\"},{\"kind\":16,\"name\":\"StateMap\",\"url\":\"enums/Services.html#StateMap\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"Services\"},{\"kind\":16,\"name\":\"FileTransfer\",\"url\":\"enums/Services.html#FileTransfer\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"Services\"},{\"kind\":16,\"name\":\"BeatInfo\",\"url\":\"enums/Services.html#BeatInfo\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"Services\"},{\"kind\":16,\"name\":\"Broadcast\",\"url\":\"enums/Services.html#Broadcast\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"Services\"},{\"kind\":16,\"name\":\"TimeSynchronization\",\"url\":\"enums/Services.html#TimeSynchronization\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"Services\"},{\"kind\":16,\"name\":\"Directory\",\"url\":\"enums/Services.html#Directory\",\"classes\":\"tsd-kind-enum-member tsd-parent-kind-enum\",\"parent\":\"Services\"},{\"kind\":32,\"name\":\"ActingAsDevice\",\"url\":\"variables/ActingAsDevice.html\",\"classes\":\"tsd-kind-variable\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"variables/ActingAsDevice.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-variable\",\"parent\":\"ActingAsDevice\"},{\"kind\":128,\"name\":\"Context\",\"url\":\"classes/Context.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Context.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Context\"},{\"kind\":1024,\"name\":\"buffer\",\"url\":\"classes/Context.html#buffer\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Context\"},{\"kind\":1024,\"name\":\"pos\",\"url\":\"classes/Context.html#pos\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Context\"},{\"kind\":1024,\"name\":\"littleEndian\",\"url\":\"classes/Context.html#littleEndian\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Context\"},{\"kind\":2048,\"name\":\"sizeLeft\",\"url\":\"classes/Context.html#sizeLeft\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Context\"},{\"kind\":2048,\"name\":\"tell\",\"url\":\"classes/Context.html#tell\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Context\"},{\"kind\":2048,\"name\":\"seek\",\"url\":\"classes/Context.html#seek\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Context\"},{\"kind\":2048,\"name\":\"set\",\"url\":\"classes/Context.html#set\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Context\"},{\"kind\":2048,\"name\":\"isEOF\",\"url\":\"classes/Context.html#isEOF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Context\"},{\"kind\":2048,\"name\":\"isLittleEndian\",\"url\":\"classes/Context.html#isLittleEndian\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Context\"},{\"kind\":2048,\"name\":\"rewind\",\"url\":\"classes/Context.html#rewind\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Context\"},{\"kind\":64,\"name\":\"getTempFilePath\",\"url\":\"functions/getTempFilePath.html\",\"classes\":\"tsd-kind-function\"},{\"kind\":128,\"name\":\"ReadContext\",\"url\":\"classes/ReadContext.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/ReadContext.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"read\",\"url\":\"classes/ReadContext.html#read\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"peek\",\"url\":\"classes/ReadContext.html#peek\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readRemaining\",\"url\":\"classes/ReadContext.html#readRemaining\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readRemainingAsNewBuffer\",\"url\":\"classes/ReadContext.html#readRemainingAsNewBuffer\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readRemainingAsNewArrayBuffer\",\"url\":\"classes/ReadContext.html#readRemainingAsNewArrayBuffer\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readRemainingAsNewCtx\",\"url\":\"classes/ReadContext.html#readRemainingAsNewCtx\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"getString\",\"url\":\"classes/ReadContext.html#getString\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readNetworkStringUTF16\",\"url\":\"classes/ReadContext.html#readNetworkStringUTF16\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readFloat64\",\"url\":\"classes/ReadContext.html#readFloat64\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readUInt64\",\"url\":\"classes/ReadContext.html#readUInt64\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readUInt32\",\"url\":\"classes/ReadContext.html#readUInt32\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readInt32\",\"url\":\"classes/ReadContext.html#readInt32\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readUInt16\",\"url\":\"classes/ReadContext.html#readUInt16\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"readUInt8\",\"url\":\"classes/ReadContext.html#readUInt8\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"ReadContext\"},{\"kind\":1024,\"name\":\"buffer\",\"url\":\"classes/ReadContext.html#buffer\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":1024,\"name\":\"pos\",\"url\":\"classes/ReadContext.html#pos\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":1024,\"name\":\"littleEndian\",\"url\":\"classes/ReadContext.html#littleEndian\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"sizeLeft\",\"url\":\"classes/ReadContext.html#sizeLeft\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"tell\",\"url\":\"classes/ReadContext.html#tell\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"seek\",\"url\":\"classes/ReadContext.html#seek\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"set\",\"url\":\"classes/ReadContext.html#set\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"isEOF\",\"url\":\"classes/ReadContext.html#isEOF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"isLittleEndian\",\"url\":\"classes/ReadContext.html#isLittleEndian\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":2048,\"name\":\"rewind\",\"url\":\"classes/ReadContext.html#rewind\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"ReadContext\"},{\"kind\":128,\"name\":\"WriteContext\",\"url\":\"classes/WriteContext.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/WriteContext.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":1024,\"name\":\"autoGrow\",\"url\":\"classes/WriteContext.html#autoGrow\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"getBuffer\",\"url\":\"classes/WriteContext.html#getBuffer\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"sizeLeft\",\"url\":\"classes/WriteContext.html#sizeLeft\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"checkSize\",\"url\":\"classes/WriteContext.html#checkSize\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"resize\",\"url\":\"classes/WriteContext.html#resize\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"write\",\"url\":\"classes/WriteContext.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"writeFixedSizedString\",\"url\":\"classes/WriteContext.html#writeFixedSizedString\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"writeNetworkStringUTF16\",\"url\":\"classes/WriteContext.html#writeNetworkStringUTF16\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"writeUInt64\",\"url\":\"classes/WriteContext.html#writeUInt64\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"writeUInt32\",\"url\":\"classes/WriteContext.html#writeUInt32\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"writeInt32\",\"url\":\"classes/WriteContext.html#writeInt32\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"writeUInt16\",\"url\":\"classes/WriteContext.html#writeUInt16\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"writeUInt8\",\"url\":\"classes/WriteContext.html#writeUInt8\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"WriteContext\"},{\"kind\":1024,\"name\":\"buffer\",\"url\":\"classes/WriteContext.html#buffer\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":1024,\"name\":\"pos\",\"url\":\"classes/WriteContext.html#pos\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":1024,\"name\":\"littleEndian\",\"url\":\"classes/WriteContext.html#littleEndian\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"tell\",\"url\":\"classes/WriteContext.html#tell\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"seek\",\"url\":\"classes/WriteContext.html#seek\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"set\",\"url\":\"classes/WriteContext.html#set\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"isEOF\",\"url\":\"classes/WriteContext.html#isEOF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"isLittleEndian\",\"url\":\"classes/WriteContext.html#isLittleEndian\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":2048,\"name\":\"rewind\",\"url\":\"classes/WriteContext.html#rewind\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"WriteContext\"},{\"kind\":64,\"name\":\"sleep\",\"url\":\"functions/sleep.html\",\"classes\":\"tsd-kind-function\"},{\"kind\":128,\"name\":\"DeviceId\",\"url\":\"classes/DeviceId.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/DeviceId.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"DeviceId\"},{\"kind\":1024,\"name\":\"m_str\",\"url\":\"classes/DeviceId.html#m_str\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"DeviceId\"},{\"kind\":1024,\"name\":\"m_array\",\"url\":\"classes/DeviceId.html#m_array\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"DeviceId\"},{\"kind\":262144,\"name\":\"string\",\"url\":\"classes/DeviceId.html#string\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class\",\"parent\":\"DeviceId\"},{\"kind\":262144,\"name\":\"array\",\"url\":\"classes/DeviceId.html#array\",\"classes\":\"tsd-kind-accessor tsd-parent-kind-class\",\"parent\":\"DeviceId\"},{\"kind\":128,\"name\":\"Devices\",\"url\":\"classes/Devices.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":2048,\"name\":\"on\",\"url\":\"classes/Devices.html#on\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":1024,\"name\":\"#devices\",\"url\":\"classes/Devices.html#_devices\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"addDevice\",\"url\":\"classes/Devices.html#addDevice\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"getDevice\",\"url\":\"classes/Devices.html#getDevice\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"device\",\"url\":\"classes/Devices.html#device\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"hasDevice\",\"url\":\"classes/Devices.html#hasDevice\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"hasNewInfo\",\"url\":\"classes/Devices.html#hasNewInfo\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"updateDeviceInfo\",\"url\":\"classes/Devices.html#updateDeviceInfo\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"getDeviceServices\",\"url\":\"classes/Devices.html#getDeviceServices\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"addService\",\"url\":\"classes/Devices.html#addService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":2048,\"name\":\"deleteService\",\"url\":\"classes/Devices.html#deleteService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Devices\"},{\"kind\":128,\"name\":\"Device\",\"url\":\"classes/Device.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Device.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/Device.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":1024,\"name\":\"info\",\"url\":\"classes/Device.html#info\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":1024,\"name\":\"#services\",\"url\":\"classes/Device.html#_services\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Device\"},{\"kind\":2048,\"name\":\"deckCount\",\"url\":\"classes/Device.html#deckCount\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":2048,\"name\":\"service\",\"url\":\"classes/Device.html#service\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":2048,\"name\":\"hasService\",\"url\":\"classes/Device.html#hasService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":2048,\"name\":\"getServiceNames\",\"url\":\"classes/Device.html#getServiceNames\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":2048,\"name\":\"getServices\",\"url\":\"classes/Device.html#getServices\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":2048,\"name\":\"addService\",\"url\":\"classes/Device.html#addService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":2048,\"name\":\"deleteService\",\"url\":\"classes/Device.html#deleteService\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Device\"},{\"kind\":128,\"name\":\"DbConnection\",\"url\":\"classes/DbConnection.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/DbConnection.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"DbConnection\"},{\"kind\":1024,\"name\":\"db\",\"url\":\"classes/DbConnection.html#db\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"DbConnection\"},{\"kind\":1024,\"name\":\"dbPath\",\"url\":\"classes/DbConnection.html#dbPath\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"DbConnection\"},{\"kind\":2048,\"name\":\"querySource\",\"url\":\"classes/DbConnection.html#querySource\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"DbConnection\"},{\"kind\":2048,\"name\":\"zInflate\",\"url\":\"classes/DbConnection.html#zInflate\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-is-private\",\"parent\":\"DbConnection\"},{\"kind\":2048,\"name\":\"getTrackInfo\",\"url\":\"classes/DbConnection.html#getTrackInfo\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"DbConnection\"},{\"kind\":2048,\"name\":\"getTrackById\",\"url\":\"classes/DbConnection.html#getTrackById\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"DbConnection\"},{\"kind\":2048,\"name\":\"close\",\"url\":\"classes/DbConnection.html#close\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"DbConnection\"},{\"kind\":128,\"name\":\"Sources\",\"url\":\"classes/Sources.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":2048,\"name\":\"on\",\"url\":\"classes/Sources.html#on\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":1024,\"name\":\"#sources\",\"url\":\"classes/Sources.html#_sources\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"hasSource\",\"url\":\"classes/Sources.html#hasSource\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"hasSourceAndDB\",\"url\":\"classes/Sources.html#hasSourceAndDB\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"getSource\",\"url\":\"classes/Sources.html#getSource\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"getSources\",\"url\":\"classes/Sources.html#getSources\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"setSource\",\"url\":\"classes/Sources.html#setSource\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"deleteSource\",\"url\":\"classes/Sources.html#deleteSource\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"getDBByUuid\",\"url\":\"classes/Sources.html#getDBByUuid\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"downloadFile\",\"url\":\"classes/Sources.html#downloadFile\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":2048,\"name\":\"downloadDbs\",\"url\":\"classes/Sources.html#downloadDbs\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Sources\"},{\"kind\":128,\"name\":\"Source\",\"url\":\"classes/Source.html\",\"classes\":\"tsd-kind-class\"},{\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Source.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Source\"},{\"kind\":1024,\"name\":\"name\",\"url\":\"classes/Source.html#name\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Source\"},{\"kind\":1024,\"name\":\"deviceId\",\"url\":\"classes/Source.html#deviceId\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Source\"},{\"kind\":1024,\"name\":\"#databases\",\"url\":\"classes/Source.html#_databases\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-private\",\"parent\":\"Source\"},{\"kind\":2048,\"name\":\"getDatabase\",\"url\":\"classes/Source.html#getDatabase\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Source\"},{\"kind\":2048,\"name\":\"getDatabases\",\"url\":\"classes/Source.html#getDatabases\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Source\"},{\"kind\":2048,\"name\":\"newDatabase\",\"url\":\"classes/Source.html#newDatabase\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Source\"}],\"index\":{\"version\":\"2.3.9\",\"fields\":[\"name\",\"comment\"],\"fieldVectors\":[[\"name/0\",[0,57.078]],[\"comment/0\",[]],[\"name/1\",[1,37.619]],[\"comment/1\",[]],[\"name/2\",[2,49.193]],[\"comment/2\",[]],[\"name/3\",[3,44.84]],[\"comment/3\",[]],[\"name/4\",[4,57.078]],[\"comment/4\",[]],[\"name/5\",[5,62.186]],[\"comment/5\",[]],[\"name/6\",[6,57.078]],[\"comment/6\",[]],[\"name/7\",[7,62.186]],[\"comment/7\",[]],[\"name/8\",[8,37.063]],[\"comment/8\",[]],[\"name/9\",[9,62.186]],[\"comment/9\",[]],[\"name/10\",[10,62.186]],[\"comment/10\",[]],[\"name/11\",[11,62.186]],[\"comment/11\",[]],[\"name/12\",[12,62.186]],[\"comment/12\",[]],[\"name/13\",[13,62.186]],[\"comment/13\",[]],[\"name/14\",[14,62.186]],[\"comment/14\",[]],[\"name/15\",[15,62.186]],[\"comment/15\",[]],[\"name/16\",[16,62.186]],[\"comment/16\",[]],[\"name/17\",[17,57.078]],[\"comment/17\",[]],[\"name/18\",[18,62.186]],[\"comment/18\",[]],[\"name/19\",[19,62.186]],[\"comment/19\",[]],[\"name/20\",[20,62.186]],[\"comment/20\",[]],[\"name/21\",[21,62.186]],[\"comment/21\",[]],[\"name/22\",[22,62.186]],[\"comment/22\",[]],[\"name/23\",[23,62.186]],[\"comment/23\",[]],[\"name/24\",[24,49.193]],[\"comment/24\",[]],[\"name/25\",[8,37.063]],[\"comment/25\",[]],[\"name/26\",[25,57.078]],[\"comment/26\",[]],[\"name/27\",[26,62.186]],[\"comment/27\",[]],[\"name/28\",[27,62.186]],[\"comment/28\",[]],[\"name/29\",[28,51.2]],[\"comment/29\",[]],[\"name/30\",[29,62.186]],[\"comment/30\",[]],[\"name/31\",[30,62.186]],[\"comment/31\",[]],[\"name/32\",[31,51.2]],[\"comment/32\",[]],[\"name/33\",[32,62.186]],[\"comment/33\",[]],[\"name/34\",[33,62.186]],[\"comment/34\",[]],[\"name/35\",[34,62.186]],[\"comment/35\",[]],[\"name/36\",[35,57.078]],[\"comment/36\",[]],[\"name/37\",[36,51.2]],[\"comment/37\",[]],[\"name/38\",[25,57.078]],[\"comment/38\",[]],[\"name/39\",[37,43.728]],[\"comment/39\",[]],[\"name/40\",[1,37.619]],[\"comment/40\",[]],[\"name/41\",[2,49.193]],[\"comment/41\",[]],[\"name/42\",[38,38.832]],[\"comment/42\",[]],[\"name/43\",[39,62.186]],[\"comment/43\",[]],[\"name/44\",[40,53.713]],[\"comment/44\",[]],[\"name/45\",[41,62.186]],[\"comment/45\",[]],[\"name/46\",[42,46.092]],[\"comment/46\",[]],[\"name/47\",[43,46.092]],[\"comment/47\",[]],[\"name/48\",[44,46.092]],[\"comment/48\",[]],[\"name/49\",[45,62.186]],[\"comment/49\",[]],[\"name/50\",[46,62.186]],[\"comment/50\",[]],[\"name/51\",[47,57.078]],[\"comment/51\",[]],[\"name/52\",[48,62.186]],[\"comment/52\",[]],[\"name/53\",[40,53.713]],[\"comment/53\",[]],[\"name/54\",[49,62.186]],[\"comment/54\",[]],[\"name/55\",[50,62.186]],[\"comment/55\",[]],[\"name/56\",[51,62.186]],[\"comment/56\",[]],[\"name/57\",[52,62.186]],[\"comment/57\",[]],[\"name/58\",[53,62.186]],[\"comment/58\",[]],[\"name/59\",[54,62.186]],[\"comment/59\",[]],[\"name/60\",[55,62.186]],[\"comment/60\",[]],[\"name/61\",[56,62.186]],[\"comment/61\",[]],[\"name/62\",[57,62.186]],[\"comment/62\",[]],[\"name/63\",[58,62.186]],[\"comment/63\",[]],[\"name/64\",[59,62.186]],[\"comment/64\",[]],[\"name/65\",[60,43.728]],[\"comment/65\",[]],[\"name/66\",[8,37.063]],[\"comment/66\",[]],[\"name/67\",[61,46.092]],[\"comment/67\",[]],[\"name/68\",[62,46.092]],[\"comment/68\",[]],[\"name/69\",[3,44.84]],[\"comment/69\",[]],[\"name/70\",[63,46.092]],[\"comment/70\",[]],[\"name/71\",[64,46.092]],[\"comment/71\",[]],[\"name/72\",[65,46.092]],[\"comment/72\",[]],[\"name/73\",[66,46.092]],[\"comment/73\",[]],[\"name/74\",[67,46.092]],[\"comment/74\",[]],[\"name/75\",[68,44.84]],[\"comment/75\",[]],[\"name/76\",[69,46.092]],[\"comment/76\",[]],[\"name/77\",[70,46.092]],[\"comment/77\",[]],[\"name/78\",[24,49.193]],[\"comment/78\",[]],[\"name/79\",[37,43.728]],[\"comment/79\",[]],[\"name/80\",[1,37.619]],[\"comment/80\",[]],[\"name/81\",[38,38.832]],[\"comment/81\",[]],[\"name/82\",[60,43.728]],[\"comment/82\",[]],[\"name/83\",[8,37.063]],[\"comment/83\",[]],[\"name/84\",[61,46.092]],[\"comment/84\",[]],[\"name/85\",[62,46.092]],[\"comment/85\",[]],[\"name/86\",[3,44.84]],[\"comment/86\",[]],[\"name/87\",[63,46.092]],[\"comment/87\",[]],[\"name/88\",[64,46.092]],[\"comment/88\",[]],[\"name/89\",[71,62.186]],[\"comment/89\",[]],[\"name/90\",[72,62.186]],[\"comment/90\",[]],[\"name/91\",[65,46.092]],[\"comment/91\",[]],[\"name/92\",[66,46.092]],[\"comment/92\",[]],[\"name/93\",[73,62.186]],[\"comment/93\",[]],[\"name/94\",[74,62.186]],[\"comment/94\",[]],[\"name/95\",[67,46.092]],[\"comment/95\",[]],[\"name/96\",[68,44.84]],[\"comment/96\",[]],[\"name/97\",[69,46.092]],[\"comment/97\",[]],[\"name/98\",[70,46.092]],[\"comment/98\",[]],[\"name/99\",[43,46.092]],[\"comment/99\",[]],[\"name/100\",[44,46.092]],[\"comment/100\",[]],[\"name/101\",[42,46.092]],[\"comment/101\",[]],[\"name/102\",[75,62.186]],[\"comment/102\",[]],[\"name/103\",[24,49.193]],[\"comment/103\",[]],[\"name/104\",[8,37.063]],[\"comment/104\",[]],[\"name/105\",[38,38.832]],[\"comment/105\",[]],[\"name/106\",[76,62.186]],[\"comment/106\",[]],[\"name/107\",[77,41.817]],[\"comment/107\",[]],[\"name/108\",[78,57.078]],[\"comment/108\",[]],[\"name/109\",[79,57.078]],[\"comment/109\",[]],[\"name/110\",[80,62.186]],[\"comment/110\",[]],[\"name/111\",[81,62.186]],[\"comment/111\",[]],[\"name/112\",[82,62.186]],[\"comment/112\",[]],[\"name/113\",[83,57.078]],[\"comment/113\",[]],[\"name/114\",[36,51.2]],[\"comment/114\",[]],[\"name/115\",[37,43.728]],[\"comment/115\",[]],[\"name/116\",[37,43.728]],[\"comment/116\",[]],[\"name/117\",[1,37.619]],[\"comment/117\",[]],[\"name/118\",[38,38.832]],[\"comment/118\",[]],[\"name/119\",[42,46.092]],[\"comment/119\",[]],[\"name/120\",[84,62.186]],[\"comment/120\",[]],[\"name/121\",[43,46.092]],[\"comment/121\",[]],[\"name/122\",[44,46.092]],[\"comment/122\",[]],[\"name/123\",[85,62.186]],[\"comment/123\",[]],[\"name/124\",[86,62.186]],[\"comment/124\",[]],[\"name/125\",[60,43.728]],[\"comment/125\",[]],[\"name/126\",[8,37.063]],[\"comment/126\",[]],[\"name/127\",[61,46.092]],[\"comment/127\",[]],[\"name/128\",[62,46.092]],[\"comment/128\",[]],[\"name/129\",[3,44.84]],[\"comment/129\",[]],[\"name/130\",[63,46.092]],[\"comment/130\",[]],[\"name/131\",[64,46.092]],[\"comment/131\",[]],[\"name/132\",[65,46.092]],[\"comment/132\",[]],[\"name/133\",[66,46.092]],[\"comment/133\",[]],[\"name/134\",[67,46.092]],[\"comment/134\",[]],[\"name/135\",[68,44.84]],[\"comment/135\",[]],[\"name/136\",[69,46.092]],[\"comment/136\",[]],[\"name/137\",[70,46.092]],[\"comment/137\",[]],[\"name/138\",[87,62.186]],[\"comment/138\",[]],[\"name/139\",[8,37.063]],[\"comment/139\",[]],[\"name/140\",[88,53.713]],[\"comment/140\",[]],[\"name/141\",[37,43.728]],[\"comment/141\",[]],[\"name/142\",[1,37.619]],[\"comment/142\",[]],[\"name/143\",[38,38.832]],[\"comment/143\",[]],[\"name/144\",[63,46.092]],[\"comment/144\",[]],[\"name/145\",[89,62.186]],[\"comment/145\",[]],[\"name/146\",[43,46.092]],[\"comment/146\",[]],[\"name/147\",[44,46.092]],[\"comment/147\",[]],[\"name/148\",[90,62.186]],[\"comment/148\",[]],[\"name/149\",[91,62.186]],[\"comment/149\",[]],[\"name/150\",[42,46.092]],[\"comment/150\",[]],[\"name/151\",[60,43.728]],[\"comment/151\",[]],[\"name/152\",[8,37.063]],[\"comment/152\",[]],[\"name/153\",[61,46.092]],[\"comment/153\",[]],[\"name/154\",[62,46.092]],[\"comment/154\",[]],[\"name/155\",[3,44.84]],[\"comment/155\",[]],[\"name/156\",[64,46.092]],[\"comment/156\",[]],[\"name/157\",[65,46.092]],[\"comment/157\",[]],[\"name/158\",[66,46.092]],[\"comment/158\",[]],[\"name/159\",[67,46.092]],[\"comment/159\",[]],[\"name/160\",[68,44.84]],[\"comment/160\",[]],[\"name/161\",[69,46.092]],[\"comment/161\",[]],[\"name/162\",[70,46.092]],[\"comment/162\",[]],[\"name/163\",[92,57.078]],[\"comment/163\",[]],[\"name/164\",[24,49.193]],[\"comment/164\",[]],[\"name/165\",[8,37.063]],[\"comment/165\",[]],[\"name/166\",[93,62.186]],[\"comment/166\",[]],[\"name/167\",[94,57.078]],[\"comment/167\",[]],[\"name/168\",[95,62.186]],[\"comment/168\",[]],[\"name/169\",[96,57.078]],[\"comment/169\",[]],[\"name/170\",[37,43.728]],[\"comment/170\",[]],[\"name/171\",[36,51.2]],[\"comment/171\",[]],[\"name/172\",[97,62.186]],[\"comment/172\",[]],[\"name/173\",[37,43.728]],[\"comment/173\",[]],[\"name/174\",[1,37.619]],[\"comment/174\",[]],[\"name/175\",[2,49.193]],[\"comment/175\",[]],[\"name/176\",[38,38.832]],[\"comment/176\",[]],[\"name/177\",[98,62.186]],[\"comment/177\",[]],[\"name/178\",[99,62.186]],[\"comment/178\",[]],[\"name/179\",[100,62.186]],[\"comment/179\",[]],[\"name/180\",[63,46.092]],[\"comment/180\",[]],[\"name/181\",[42,46.092]],[\"comment/181\",[]],[\"name/182\",[101,62.186]],[\"comment/182\",[]],[\"name/183\",[102,62.186]],[\"comment/183\",[]],[\"name/184\",[103,62.186]],[\"comment/184\",[]],[\"name/185\",[104,62.186]],[\"comment/185\",[]],[\"name/186\",[43,46.092]],[\"comment/186\",[]],[\"name/187\",[44,46.092]],[\"comment/187\",[]],[\"name/188\",[60,43.728]],[\"comment/188\",[]],[\"name/189\",[8,37.063]],[\"comment/189\",[]],[\"name/190\",[61,46.092]],[\"comment/190\",[]],[\"name/191\",[62,46.092]],[\"comment/191\",[]],[\"name/192\",[3,44.84]],[\"comment/192\",[]],[\"name/193\",[64,46.092]],[\"comment/193\",[]],[\"name/194\",[65,46.092]],[\"comment/194\",[]],[\"name/195\",[66,46.092]],[\"comment/195\",[]],[\"name/196\",[67,46.092]],[\"comment/196\",[]],[\"name/197\",[68,44.84]],[\"comment/197\",[]],[\"name/198\",[69,46.092]],[\"comment/198\",[]],[\"name/199\",[70,46.092]],[\"comment/199\",[]],[\"name/200\",[105,62.186]],[\"comment/200\",[]],[\"name/201\",[106,62.186]],[\"comment/201\",[]],[\"name/202\",[107,62.186]],[\"comment/202\",[]],[\"name/203\",[108,57.078]],[\"comment/203\",[]],[\"name/204\",[37,43.728]],[\"comment/204\",[]],[\"name/205\",[1,37.619]],[\"comment/205\",[]],[\"name/206\",[38,38.832]],[\"comment/206\",[]],[\"name/207\",[63,46.092]],[\"comment/207\",[]],[\"name/208\",[109,62.186]],[\"comment/208\",[]],[\"name/209\",[110,62.186]],[\"comment/209\",[]],[\"name/210\",[111,62.186]],[\"comment/210\",[]],[\"name/211\",[112,62.186]],[\"comment/211\",[]],[\"name/212\",[113,62.186]],[\"comment/212\",[]],[\"name/213\",[114,62.186]],[\"comment/213\",[]],[\"name/214\",[115,62.186]],[\"comment/214\",[]],[\"name/215\",[43,46.092]],[\"comment/215\",[]],[\"name/216\",[116,62.186]],[\"comment/216\",[]],[\"name/217\",[44,46.092]],[\"comment/217\",[]],[\"name/218\",[42,46.092]],[\"comment/218\",[]],[\"name/219\",[60,43.728]],[\"comment/219\",[]],[\"name/220\",[8,37.063]],[\"comment/220\",[]],[\"name/221\",[61,46.092]],[\"comment/221\",[]],[\"name/222\",[62,46.092]],[\"comment/222\",[]],[\"name/223\",[3,44.84]],[\"comment/223\",[]],[\"name/224\",[64,46.092]],[\"comment/224\",[]],[\"name/225\",[65,46.092]],[\"comment/225\",[]],[\"name/226\",[66,46.092]],[\"comment/226\",[]],[\"name/227\",[67,46.092]],[\"comment/227\",[]],[\"name/228\",[68,44.84]],[\"comment/228\",[]],[\"name/229\",[69,46.092]],[\"comment/229\",[]],[\"name/230\",[70,46.092]],[\"comment/230\",[]],[\"name/231\",[17,57.078]],[\"comment/231\",[]],[\"name/232\",[77,41.817]],[\"comment/232\",[]],[\"name/233\",[117,62.186]],[\"comment/233\",[]],[\"name/234\",[118,62.186]],[\"comment/234\",[]],[\"name/235\",[119,62.186]],[\"comment/235\",[]],[\"name/236\",[120,62.186]],[\"comment/236\",[]],[\"name/237\",[121,62.186]],[\"comment/237\",[]],[\"name/238\",[122,57.078]],[\"comment/238\",[]],[\"name/239\",[36,51.2]],[\"comment/239\",[]],[\"name/240\",[37,43.728]],[\"comment/240\",[]],[\"name/241\",[1,37.619]],[\"comment/241\",[]],[\"name/242\",[38,38.832]],[\"comment/242\",[]],[\"name/243\",[63,46.092]],[\"comment/243\",[]],[\"name/244\",[43,46.092]],[\"comment/244\",[]],[\"name/245\",[44,46.092]],[\"comment/245\",[]],[\"name/246\",[42,46.092]],[\"comment/246\",[]],[\"name/247\",[60,43.728]],[\"comment/247\",[]],[\"name/248\",[8,37.063]],[\"comment/248\",[]],[\"name/249\",[61,46.092]],[\"comment/249\",[]],[\"name/250\",[62,46.092]],[\"comment/250\",[]],[\"name/251\",[3,44.84]],[\"comment/251\",[]],[\"name/252\",[64,46.092]],[\"comment/252\",[]],[\"name/253\",[65,46.092]],[\"comment/253\",[]],[\"name/254\",[66,46.092]],[\"comment/254\",[]],[\"name/255\",[67,46.092]],[\"comment/255\",[]],[\"name/256\",[68,44.84]],[\"comment/256\",[]],[\"name/257\",[69,46.092]],[\"comment/257\",[]],[\"name/258\",[70,46.092]],[\"comment/258\",[]],[\"name/259\",[123,62.186]],[\"comment/259\",[]],[\"name/260\",[6,57.078]],[\"comment/260\",[]],[\"name/261\",[124,62.186]],[\"comment/261\",[]],[\"name/262\",[125,53.713]],[\"comment/262\",[]],[\"name/263\",[0,57.078]],[\"comment/263\",[]],[\"name/264\",[28,51.2]],[\"comment/264\",[]],[\"name/265\",[126,62.186]],[\"comment/265\",[]],[\"name/266\",[88,53.713]],[\"comment/266\",[]],[\"name/267\",[127,62.186]],[\"comment/267\",[]],[\"name/268\",[128,62.186]],[\"comment/268\",[]],[\"name/269\",[129,62.186]],[\"comment/269\",[]],[\"name/270\",[1,37.619]],[\"comment/270\",[]],[\"name/271\",[130,62.186]],[\"comment/271\",[]],[\"name/272\",[1,37.619]],[\"comment/272\",[]],[\"name/273\",[131,57.078]],[\"comment/273\",[]],[\"name/274\",[132,47.523]],[\"comment/274\",[]],[\"name/275\",[77,41.817]],[\"comment/275\",[]],[\"name/276\",[38,38.832]],[\"comment/276\",[]],[\"name/277\",[133,57.078]],[\"comment/277\",[]],[\"name/278\",[134,53.713]],[\"comment/278\",[]],[\"name/279\",[135,62.186]],[\"comment/279\",[]],[\"name/280\",[136,62.186]],[\"comment/280\",[]],[\"name/281\",[137,62.186]],[\"comment/281\",[]],[\"name/282\",[138,62.186]],[\"comment/282\",[]],[\"name/283\",[139,62.186]],[\"comment/283\",[]],[\"name/284\",[140,62.186]],[\"comment/284\",[]],[\"name/285\",[141,62.186]],[\"comment/285\",[]],[\"name/286\",[142,62.186]],[\"comment/286\",[]],[\"name/287\",[143,62.186]],[\"comment/287\",[]],[\"name/288\",[144,62.186]],[\"comment/288\",[]],[\"name/289\",[145,62.186]],[\"comment/289\",[]],[\"name/290\",[146,62.186]],[\"comment/290\",[]],[\"name/291\",[131,57.078]],[\"comment/291\",[]],[\"name/292\",[132,47.523]],[\"comment/292\",[]],[\"name/293\",[77,41.817]],[\"comment/293\",[]],[\"name/294\",[38,38.832]],[\"comment/294\",[]],[\"name/295\",[133,57.078]],[\"comment/295\",[]],[\"name/296\",[134,53.713]],[\"comment/296\",[]],[\"name/297\",[147,62.186]],[\"comment/297\",[]],[\"name/298\",[148,57.078]],[\"comment/298\",[]],[\"name/299\",[149,62.186]],[\"comment/299\",[]],[\"name/300\",[150,62.186]],[\"comment/300\",[]],[\"name/301\",[151,62.186]],[\"comment/301\",[]],[\"name/302\",[152,62.186]],[\"comment/302\",[]],[\"name/303\",[134,53.713]],[\"comment/303\",[]],[\"name/304\",[153,62.186]],[\"comment/304\",[]],[\"name/305\",[154,62.186]],[\"comment/305\",[]],[\"name/306\",[155,62.186]],[\"comment/306\",[]],[\"name/307\",[156,62.186]],[\"comment/307\",[]],[\"name/308\",[157,62.186]],[\"comment/308\",[]],[\"name/309\",[158,62.186]],[\"comment/309\",[]],[\"name/310\",[159,62.186]],[\"comment/310\",[]],[\"name/311\",[160,62.186]],[\"comment/311\",[]],[\"name/312\",[161,62.186]],[\"comment/312\",[]],[\"name/313\",[162,62.186]],[\"comment/313\",[]],[\"name/314\",[163,62.186]],[\"comment/314\",[]],[\"name/315\",[164,62.186]],[\"comment/315\",[]],[\"name/316\",[165,62.186]],[\"comment/316\",[]],[\"name/317\",[166,62.186]],[\"comment/317\",[]],[\"name/318\",[167,62.186]],[\"comment/318\",[]],[\"name/319\",[168,62.186]],[\"comment/319\",[]],[\"name/320\",[169,62.186]],[\"comment/320\",[]],[\"name/321\",[170,62.186]],[\"comment/321\",[]],[\"name/322\",[171,62.186]],[\"comment/322\",[]],[\"name/323\",[172,62.186]],[\"comment/323\",[]],[\"name/324\",[173,62.186]],[\"comment/324\",[]],[\"name/325\",[174,62.186]],[\"comment/325\",[]],[\"name/326\",[40,53.713]],[\"comment/326\",[]],[\"name/327\",[175,62.186]],[\"comment/327\",[]],[\"name/328\",[176,62.186]],[\"comment/328\",[]],[\"name/329\",[177,62.186]],[\"comment/329\",[]],[\"name/330\",[178,62.186]],[\"comment/330\",[]],[\"name/331\",[179,62.186]],[\"comment/331\",[]],[\"name/332\",[180,62.186]],[\"comment/332\",[]],[\"name/333\",[181,62.186]],[\"comment/333\",[]],[\"name/334\",[182,62.186]],[\"comment/334\",[]],[\"name/335\",[183,62.186]],[\"comment/335\",[]],[\"name/336\",[184,62.186]],[\"comment/336\",[]],[\"name/337\",[185,62.186]],[\"comment/337\",[]],[\"name/338\",[186,62.186]],[\"comment/338\",[]],[\"name/339\",[92,57.078]],[\"comment/339\",[]],[\"name/340\",[187,62.186]],[\"comment/340\",[]],[\"name/341\",[188,62.186]],[\"comment/341\",[]],[\"name/342\",[189,62.186]],[\"comment/342\",[]],[\"name/343\",[190,62.186]],[\"comment/343\",[]],[\"name/344\",[191,62.186]],[\"comment/344\",[]],[\"name/345\",[192,62.186]],[\"comment/345\",[]],[\"name/346\",[193,62.186]],[\"comment/346\",[]],[\"name/347\",[77,41.817]],[\"comment/347\",[]],[\"name/348\",[194,62.186]],[\"comment/348\",[]],[\"name/349\",[77,41.817]],[\"comment/349\",[]],[\"name/350\",[195,62.186]],[\"comment/350\",[]],[\"name/351\",[196,62.186]],[\"comment/351\",[]],[\"name/352\",[197,62.186]],[\"comment/352\",[]],[\"name/353\",[198,62.186]],[\"comment/353\",[]],[\"name/354\",[199,62.186]],[\"comment/354\",[]],[\"name/355\",[200,62.186]],[\"comment/355\",[]],[\"name/356\",[201,62.186]],[\"comment/356\",[]],[\"name/357\",[202,62.186]],[\"comment/357\",[]],[\"name/358\",[203,62.186]],[\"comment/358\",[]],[\"name/359\",[204,62.186]],[\"comment/359\",[]],[\"name/360\",[205,62.186]],[\"comment/360\",[]],[\"name/361\",[206,62.186]],[\"comment/361\",[]],[\"name/362\",[207,62.186]],[\"comment/362\",[]],[\"name/363\",[208,62.186]],[\"comment/363\",[]],[\"name/364\",[209,62.186]],[\"comment/364\",[]],[\"name/365\",[210,62.186]],[\"comment/365\",[]],[\"name/366\",[211,62.186]],[\"comment/366\",[]],[\"name/367\",[212,62.186]],[\"comment/367\",[]],[\"name/368\",[213,62.186]],[\"comment/368\",[]],[\"name/369\",[214,62.186]],[\"comment/369\",[]],[\"name/370\",[215,62.186]],[\"comment/370\",[]],[\"name/371\",[216,62.186]],[\"comment/371\",[]],[\"name/372\",[217,62.186]],[\"comment/372\",[]],[\"name/373\",[218,62.186]],[\"comment/373\",[]],[\"name/374\",[219,62.186]],[\"comment/374\",[]],[\"name/375\",[220,62.186]],[\"comment/375\",[]],[\"name/376\",[221,62.186]],[\"comment/376\",[]],[\"name/377\",[222,62.186]],[\"comment/377\",[]],[\"name/378\",[223,62.186]],[\"comment/378\",[]],[\"name/379\",[224,62.186]],[\"comment/379\",[]],[\"name/380\",[225,62.186]],[\"comment/380\",[]],[\"name/381\",[226,62.186]],[\"comment/381\",[]],[\"name/382\",[227,62.186]],[\"comment/382\",[]],[\"name/383\",[228,62.186]],[\"comment/383\",[]],[\"name/384\",[229,62.186]],[\"comment/384\",[]],[\"name/385\",[230,62.186]],[\"comment/385\",[]],[\"name/386\",[231,62.186]],[\"comment/386\",[]],[\"name/387\",[232,62.186]],[\"comment/387\",[]],[\"name/388\",[233,62.186]],[\"comment/388\",[]],[\"name/389\",[234,62.186]],[\"comment/389\",[]],[\"name/390\",[235,62.186]],[\"comment/390\",[]],[\"name/391\",[236,62.186]],[\"comment/391\",[]],[\"name/392\",[237,62.186]],[\"comment/392\",[]],[\"name/393\",[238,62.186]],[\"comment/393\",[]],[\"name/394\",[239,62.186]],[\"comment/394\",[]],[\"name/395\",[240,62.186]],[\"comment/395\",[]],[\"name/396\",[241,62.186]],[\"comment/396\",[]],[\"name/397\",[242,62.186]],[\"comment/397\",[]],[\"name/398\",[243,62.186]],[\"comment/398\",[]],[\"name/399\",[244,62.186]],[\"comment/399\",[]],[\"name/400\",[245,62.186]],[\"comment/400\",[]],[\"name/401\",[246,62.186]],[\"comment/401\",[]],[\"name/402\",[247,62.186]],[\"comment/402\",[]],[\"name/403\",[248,62.186]],[\"comment/403\",[]],[\"name/404\",[249,62.186]],[\"comment/404\",[]],[\"name/405\",[250,62.186]],[\"comment/405\",[]],[\"name/406\",[251,62.186]],[\"comment/406\",[]],[\"name/407\",[252,62.186]],[\"comment/407\",[]],[\"name/408\",[253,62.186]],[\"comment/408\",[]],[\"name/409\",[254,62.186]],[\"comment/409\",[]],[\"name/410\",[255,62.186]],[\"comment/410\",[]],[\"name/411\",[256,62.186]],[\"comment/411\",[]],[\"name/412\",[257,62.186]],[\"comment/412\",[]],[\"name/413\",[258,62.186]],[\"comment/413\",[]],[\"name/414\",[259,62.186]],[\"comment/414\",[]],[\"name/415\",[260,62.186]],[\"comment/415\",[]],[\"name/416\",[261,62.186]],[\"comment/416\",[]],[\"name/417\",[262,62.186]],[\"comment/417\",[]],[\"name/418\",[263,62.186]],[\"comment/418\",[]],[\"name/419\",[264,62.186]],[\"comment/419\",[]],[\"name/420\",[265,62.186]],[\"comment/420\",[]],[\"name/421\",[266,62.186]],[\"comment/421\",[]],[\"name/422\",[267,62.186]],[\"comment/422\",[]],[\"name/423\",[268,62.186]],[\"comment/423\",[]],[\"name/424\",[269,62.186]],[\"comment/424\",[]],[\"name/425\",[270,62.186]],[\"comment/425\",[]],[\"name/426\",[271,62.186]],[\"comment/426\",[]],[\"name/427\",[272,62.186]],[\"comment/427\",[]],[\"name/428\",[273,62.186]],[\"comment/428\",[]],[\"name/429\",[274,62.186]],[\"comment/429\",[]],[\"name/430\",[275,62.186]],[\"comment/430\",[]],[\"name/431\",[276,62.186]],[\"comment/431\",[]],[\"name/432\",[277,62.186]],[\"comment/432\",[]],[\"name/433\",[278,62.186]],[\"comment/433\",[]],[\"name/434\",[279,62.186]],[\"comment/434\",[]],[\"name/435\",[280,62.186]],[\"comment/435\",[]],[\"name/436\",[281,62.186]],[\"comment/436\",[]],[\"name/437\",[282,62.186]],[\"comment/437\",[]],[\"name/438\",[283,62.186]],[\"comment/438\",[]],[\"name/439\",[284,62.186]],[\"comment/439\",[]],[\"name/440\",[285,62.186]],[\"comment/440\",[]],[\"name/441\",[286,62.186]],[\"comment/441\",[]],[\"name/442\",[287,62.186]],[\"comment/442\",[]],[\"name/443\",[288,62.186]],[\"comment/443\",[]],[\"name/444\",[289,62.186]],[\"comment/444\",[]],[\"name/445\",[290,62.186]],[\"comment/445\",[]],[\"name/446\",[291,62.186]],[\"comment/446\",[]],[\"name/447\",[292,62.186]],[\"comment/447\",[]],[\"name/448\",[293,62.186]],[\"comment/448\",[]],[\"name/449\",[294,62.186]],[\"comment/449\",[]],[\"name/450\",[295,62.186]],[\"comment/450\",[]],[\"name/451\",[296,62.186]],[\"comment/451\",[]],[\"name/452\",[297,62.186]],[\"comment/452\",[]],[\"name/453\",[298,62.186]],[\"comment/453\",[]],[\"name/454\",[299,62.186]],[\"comment/454\",[]],[\"name/455\",[300,62.186]],[\"comment/455\",[]],[\"name/456\",[301,62.186]],[\"comment/456\",[]],[\"name/457\",[302,62.186]],[\"comment/457\",[]],[\"name/458\",[303,62.186]],[\"comment/458\",[]],[\"name/459\",[304,62.186]],[\"comment/459\",[]],[\"name/460\",[305,62.186]],[\"comment/460\",[]],[\"name/461\",[306,62.186]],[\"comment/461\",[]],[\"name/462\",[307,62.186]],[\"comment/462\",[]],[\"name/463\",[308,62.186]],[\"comment/463\",[]],[\"name/464\",[309,62.186]],[\"comment/464\",[]],[\"name/465\",[310,62.186]],[\"comment/465\",[]],[\"name/466\",[311,62.186]],[\"comment/466\",[]],[\"name/467\",[312,62.186]],[\"comment/467\",[]],[\"name/468\",[313,62.186]],[\"comment/468\",[]],[\"name/469\",[314,62.186]],[\"comment/469\",[]],[\"name/470\",[315,62.186]],[\"comment/470\",[]],[\"name/471\",[316,62.186]],[\"comment/471\",[]],[\"name/472\",[317,62.186]],[\"comment/472\",[]],[\"name/473\",[318,62.186]],[\"comment/473\",[]],[\"name/474\",[319,62.186]],[\"comment/474\",[]],[\"name/475\",[320,62.186]],[\"comment/475\",[]],[\"name/476\",[321,62.186]],[\"comment/476\",[]],[\"name/477\",[322,62.186]],[\"comment/477\",[]],[\"name/478\",[323,62.186]],[\"comment/478\",[]],[\"name/479\",[324,62.186]],[\"comment/479\",[]],[\"name/480\",[325,62.186]],[\"comment/480\",[]],[\"name/481\",[326,62.186]],[\"comment/481\",[]],[\"name/482\",[327,62.186]],[\"comment/482\",[]],[\"name/483\",[328,62.186]],[\"comment/483\",[]],[\"name/484\",[329,62.186]],[\"comment/484\",[]],[\"name/485\",[330,62.186]],[\"comment/485\",[]],[\"name/486\",[331,62.186]],[\"comment/486\",[]],[\"name/487\",[332,62.186]],[\"comment/487\",[]],[\"name/488\",[333,62.186]],[\"comment/488\",[]],[\"name/489\",[334,62.186]],[\"comment/489\",[]],[\"name/490\",[335,62.186]],[\"comment/490\",[]],[\"name/491\",[336,62.186]],[\"comment/491\",[]],[\"name/492\",[337,62.186]],[\"comment/492\",[]],[\"name/493\",[338,62.186]],[\"comment/493\",[]],[\"name/494\",[339,62.186]],[\"comment/494\",[]],[\"name/495\",[340,62.186]],[\"comment/495\",[]],[\"name/496\",[341,62.186]],[\"comment/496\",[]],[\"name/497\",[342,62.186]],[\"comment/497\",[]],[\"name/498\",[343,62.186]],[\"comment/498\",[]],[\"name/499\",[344,62.186]],[\"comment/499\",[]],[\"name/500\",[345,62.186]],[\"comment/500\",[]],[\"name/501\",[346,62.186]],[\"comment/501\",[]],[\"name/502\",[347,62.186]],[\"comment/502\",[]],[\"name/503\",[348,62.186]],[\"comment/503\",[]],[\"name/504\",[349,62.186]],[\"comment/504\",[]],[\"name/505\",[350,62.186]],[\"comment/505\",[]],[\"name/506\",[351,62.186]],[\"comment/506\",[]],[\"name/507\",[352,62.186]],[\"comment/507\",[]],[\"name/508\",[353,62.186]],[\"comment/508\",[]],[\"name/509\",[354,62.186]],[\"comment/509\",[]],[\"name/510\",[355,62.186]],[\"comment/510\",[]],[\"name/511\",[356,62.186]],[\"comment/511\",[]],[\"name/512\",[357,62.186]],[\"comment/512\",[]],[\"name/513\",[358,62.186]],[\"comment/513\",[]],[\"name/514\",[359,62.186]],[\"comment/514\",[]],[\"name/515\",[360,62.186]],[\"comment/515\",[]],[\"name/516\",[361,62.186]],[\"comment/516\",[]],[\"name/517\",[362,62.186]],[\"comment/517\",[]],[\"name/518\",[363,62.186]],[\"comment/518\",[]],[\"name/519\",[364,62.186]],[\"comment/519\",[]],[\"name/520\",[365,62.186]],[\"comment/520\",[]],[\"name/521\",[366,62.186]],[\"comment/521\",[]],[\"name/522\",[367,62.186]],[\"comment/522\",[]],[\"name/523\",[368,62.186]],[\"comment/523\",[]],[\"name/524\",[369,62.186]],[\"comment/524\",[]],[\"name/525\",[370,62.186]],[\"comment/525\",[]],[\"name/526\",[371,62.186]],[\"comment/526\",[]],[\"name/527\",[372,62.186]],[\"comment/527\",[]],[\"name/528\",[373,62.186]],[\"comment/528\",[]],[\"name/529\",[374,62.186]],[\"comment/529\",[]],[\"name/530\",[375,62.186]],[\"comment/530\",[]],[\"name/531\",[376,62.186]],[\"comment/531\",[]],[\"name/532\",[377,62.186]],[\"comment/532\",[]],[\"name/533\",[378,62.186]],[\"comment/533\",[]],[\"name/534\",[379,62.186]],[\"comment/534\",[]],[\"name/535\",[380,62.186]],[\"comment/535\",[]],[\"name/536\",[381,62.186]],[\"comment/536\",[]],[\"name/537\",[382,62.186]],[\"comment/537\",[]],[\"name/538\",[383,62.186]],[\"comment/538\",[]],[\"name/539\",[384,62.186]],[\"comment/539\",[]],[\"name/540\",[385,62.186]],[\"comment/540\",[]],[\"name/541\",[386,62.186]],[\"comment/541\",[]],[\"name/542\",[387,62.186]],[\"comment/542\",[]],[\"name/543\",[388,62.186]],[\"comment/543\",[]],[\"name/544\",[389,62.186]],[\"comment/544\",[]],[\"name/545\",[390,62.186]],[\"comment/545\",[]],[\"name/546\",[391,62.186]],[\"comment/546\",[]],[\"name/547\",[392,62.186]],[\"comment/547\",[]],[\"name/548\",[393,62.186]],[\"comment/548\",[]],[\"name/549\",[394,62.186]],[\"comment/549\",[]],[\"name/550\",[395,62.186]],[\"comment/550\",[]],[\"name/551\",[396,62.186]],[\"comment/551\",[]],[\"name/552\",[397,62.186]],[\"comment/552\",[]],[\"name/553\",[398,62.186]],[\"comment/553\",[]],[\"name/554\",[399,62.186]],[\"comment/554\",[]],[\"name/555\",[400,62.186]],[\"comment/555\",[]],[\"name/556\",[401,62.186]],[\"comment/556\",[]],[\"name/557\",[402,62.186]],[\"comment/557\",[]],[\"name/558\",[403,62.186]],[\"comment/558\",[]],[\"name/559\",[404,62.186]],[\"comment/559\",[]],[\"name/560\",[405,62.186]],[\"comment/560\",[]],[\"name/561\",[406,62.186]],[\"comment/561\",[]],[\"name/562\",[407,62.186]],[\"comment/562\",[]],[\"name/563\",[408,62.186]],[\"comment/563\",[]],[\"name/564\",[409,62.186]],[\"comment/564\",[]],[\"name/565\",[410,62.186]],[\"comment/565\",[]],[\"name/566\",[77,41.817]],[\"comment/566\",[]],[\"name/567\",[411,62.186]],[\"comment/567\",[]],[\"name/568\",[412,62.186]],[\"comment/568\",[]],[\"name/569\",[413,62.186]],[\"comment/569\",[]],[\"name/570\",[414,62.186]],[\"comment/570\",[]],[\"name/571\",[415,62.186]],[\"comment/571\",[]],[\"name/572\",[416,62.186]],[\"comment/572\",[]],[\"name/573\",[417,62.186]],[\"comment/573\",[]],[\"name/574\",[418,62.186]],[\"comment/574\",[]],[\"name/575\",[419,62.186]],[\"comment/575\",[]],[\"name/576\",[420,62.186]],[\"comment/576\",[]],[\"name/577\",[421,62.186]],[\"comment/577\",[]],[\"name/578\",[422,62.186]],[\"comment/578\",[]],[\"name/579\",[8,37.063]],[\"comment/579\",[]],[\"name/580\",[132,47.523]],[\"comment/580\",[]],[\"name/581\",[423,57.078]],[\"comment/581\",[]],[\"name/582\",[424,57.078]],[\"comment/582\",[]],[\"name/583\",[77,41.817]],[\"comment/583\",[]],[\"name/584\",[38,38.832]],[\"comment/584\",[]],[\"name/585\",[425,53.713]],[\"comment/585\",[]],[\"name/586\",[426,53.713]],[\"comment/586\",[]],[\"name/587\",[427,62.186]],[\"comment/587\",[]],[\"name/588\",[4,57.078]],[\"comment/588\",[]],[\"name/589\",[428,62.186]],[\"comment/589\",[]],[\"name/590\",[77,41.817]],[\"comment/590\",[]],[\"name/591\",[38,38.832]],[\"comment/591\",[]],[\"name/592\",[78,57.078]],[\"comment/592\",[]],[\"name/593\",[429,62.186]],[\"comment/593\",[]],[\"name/594\",[430,62.186]],[\"comment/594\",[]],[\"name/595\",[8,37.063]],[\"comment/595\",[]],[\"name/596\",[132,47.523]],[\"comment/596\",[]],[\"name/597\",[423,57.078]],[\"comment/597\",[]],[\"name/598\",[424,57.078]],[\"comment/598\",[]],[\"name/599\",[77,41.817]],[\"comment/599\",[]],[\"name/600\",[38,38.832]],[\"comment/600\",[]],[\"name/601\",[425,53.713]],[\"comment/601\",[]],[\"name/602\",[426,53.713]],[\"comment/602\",[]],[\"name/603\",[431,62.186]],[\"comment/603\",[]],[\"name/604\",[148,57.078]],[\"comment/604\",[]],[\"name/605\",[432,62.186]],[\"comment/605\",[]],[\"name/606\",[433,62.186]],[\"comment/606\",[]],[\"name/607\",[434,62.186]],[\"comment/607\",[]],[\"name/608\",[435,62.186]],[\"comment/608\",[]],[\"name/609\",[38,38.832]],[\"comment/609\",[]],[\"name/610\",[425,53.713]],[\"comment/610\",[]],[\"name/611\",[132,47.523]],[\"comment/611\",[]],[\"name/612\",[8,37.063]],[\"comment/612\",[]],[\"name/613\",[426,53.713]],[\"comment/613\",[]],[\"name/614\",[436,62.186]],[\"comment/614\",[]],[\"name/615\",[437,62.186]],[\"comment/615\",[]],[\"name/616\",[438,62.186]],[\"comment/616\",[]],[\"name/617\",[439,62.186]],[\"comment/617\",[]],[\"name/618\",[440,53.713]],[\"comment/618\",[]],[\"name/619\",[441,62.186]],[\"comment/619\",[]],[\"name/620\",[440,53.713]],[\"comment/620\",[]],[\"name/621\",[83,57.078]],[\"comment/621\",[]],[\"name/622\",[35,57.078]],[\"comment/622\",[]],[\"name/623\",[96,57.078]],[\"comment/623\",[]],[\"name/624\",[122,57.078]],[\"comment/624\",[]],[\"name/625\",[108,57.078]],[\"comment/625\",[]],[\"name/626\",[88,53.713]],[\"comment/626\",[]],[\"name/627\",[442,62.186]],[\"comment/627\",[]],[\"name/628\",[77,41.817]],[\"comment/628\",[]],[\"name/629\",[443,62.186]],[\"comment/629\",[]],[\"name/630\",[1,37.619]],[\"comment/630\",[]],[\"name/631\",[444,53.713]],[\"comment/631\",[]],[\"name/632\",[445,53.713]],[\"comment/632\",[]],[\"name/633\",[446,53.713]],[\"comment/633\",[]],[\"name/634\",[31,51.2]],[\"comment/634\",[]],[\"name/635\",[447,53.713]],[\"comment/635\",[]],[\"name/636\",[448,53.713]],[\"comment/636\",[]],[\"name/637\",[449,53.713]],[\"comment/637\",[]],[\"name/638\",[450,53.713]],[\"comment/638\",[]],[\"name/639\",[451,53.713]],[\"comment/639\",[]],[\"name/640\",[452,53.713]],[\"comment/640\",[]],[\"name/641\",[453,62.186]],[\"comment/641\",[]],[\"name/642\",[454,62.186]],[\"comment/642\",[]],[\"name/643\",[1,37.619]],[\"comment/643\",[]],[\"name/644\",[455,62.186]],[\"comment/644\",[]],[\"name/645\",[456,62.186]],[\"comment/645\",[]],[\"name/646\",[457,62.186]],[\"comment/646\",[]],[\"name/647\",[458,62.186]],[\"comment/647\",[]],[\"name/648\",[459,62.186]],[\"comment/648\",[]],[\"name/649\",[460,62.186]],[\"comment/649\",[]],[\"name/650\",[461,62.186]],[\"comment/650\",[]],[\"name/651\",[462,62.186]],[\"comment/651\",[]],[\"name/652\",[463,62.186]],[\"comment/652\",[]],[\"name/653\",[464,62.186]],[\"comment/653\",[]],[\"name/654\",[465,62.186]],[\"comment/654\",[]],[\"name/655\",[466,62.186]],[\"comment/655\",[]],[\"name/656\",[467,62.186]],[\"comment/656\",[]],[\"name/657\",[468,62.186]],[\"comment/657\",[]],[\"name/658\",[444,53.713]],[\"comment/658\",[]],[\"name/659\",[445,53.713]],[\"comment/659\",[]],[\"name/660\",[446,53.713]],[\"comment/660\",[]],[\"name/661\",[31,51.2]],[\"comment/661\",[]],[\"name/662\",[447,53.713]],[\"comment/662\",[]],[\"name/663\",[448,53.713]],[\"comment/663\",[]],[\"name/664\",[449,53.713]],[\"comment/664\",[]],[\"name/665\",[450,53.713]],[\"comment/665\",[]],[\"name/666\",[451,53.713]],[\"comment/666\",[]],[\"name/667\",[452,53.713]],[\"comment/667\",[]],[\"name/668\",[469,62.186]],[\"comment/668\",[]],[\"name/669\",[1,37.619]],[\"comment/669\",[]],[\"name/670\",[470,62.186]],[\"comment/670\",[]],[\"name/671\",[471,62.186]],[\"comment/671\",[]],[\"name/672\",[31,51.2]],[\"comment/672\",[]],[\"name/673\",[472,62.186]],[\"comment/673\",[]],[\"name/674\",[473,62.186]],[\"comment/674\",[]],[\"name/675\",[68,44.84]],[\"comment/675\",[]],[\"name/676\",[474,62.186]],[\"comment/676\",[]],[\"name/677\",[475,62.186]],[\"comment/677\",[]],[\"name/678\",[476,62.186]],[\"comment/678\",[]],[\"name/679\",[477,62.186]],[\"comment/679\",[]],[\"name/680\",[478,62.186]],[\"comment/680\",[]],[\"name/681\",[479,62.186]],[\"comment/681\",[]],[\"name/682\",[480,62.186]],[\"comment/682\",[]],[\"name/683\",[444,53.713]],[\"comment/683\",[]],[\"name/684\",[445,53.713]],[\"comment/684\",[]],[\"name/685\",[446,53.713]],[\"comment/685\",[]],[\"name/686\",[447,53.713]],[\"comment/686\",[]],[\"name/687\",[448,53.713]],[\"comment/687\",[]],[\"name/688\",[449,53.713]],[\"comment/688\",[]],[\"name/689\",[450,53.713]],[\"comment/689\",[]],[\"name/690\",[451,53.713]],[\"comment/690\",[]],[\"name/691\",[452,53.713]],[\"comment/691\",[]],[\"name/692\",[481,62.186]],[\"comment/692\",[]],[\"name/693\",[8,37.063]],[\"comment/693\",[]],[\"name/694\",[1,37.619]],[\"comment/694\",[]],[\"name/695\",[482,62.186]],[\"comment/695\",[]],[\"name/696\",[483,62.186]],[\"comment/696\",[]],[\"name/697\",[79,57.078]],[\"comment/697\",[]],[\"name/698\",[484,62.186]],[\"comment/698\",[]],[\"name/699\",[125,53.713]],[\"comment/699\",[]],[\"name/700\",[2,49.193]],[\"comment/700\",[]],[\"name/701\",[125,53.713]],[\"comment/701\",[]],[\"name/702\",[485,62.186]],[\"comment/702\",[]],[\"name/703\",[486,62.186]],[\"comment/703\",[]],[\"name/704\",[60,43.728]],[\"comment/704\",[]],[\"name/705\",[487,62.186]],[\"comment/705\",[]],[\"name/706\",[488,62.186]],[\"comment/706\",[]],[\"name/707\",[489,62.186]],[\"comment/707\",[]],[\"name/708\",[490,62.186]],[\"comment/708\",[]],[\"name/709\",[491,57.078]],[\"comment/709\",[]],[\"name/710\",[492,57.078]],[\"comment/710\",[]],[\"name/711\",[60,43.728]],[\"comment/711\",[]],[\"name/712\",[1,37.619]],[\"comment/712\",[]],[\"name/713\",[8,37.063]],[\"comment/713\",[]],[\"name/714\",[493,62.186]],[\"comment/714\",[]],[\"name/715\",[440,53.713]],[\"comment/715\",[]],[\"name/716\",[94,57.078]],[\"comment/716\",[]],[\"name/717\",[24,49.193]],[\"comment/717\",[]],[\"name/718\",[494,62.186]],[\"comment/718\",[]],[\"name/719\",[495,62.186]],[\"comment/719\",[]],[\"name/720\",[496,62.186]],[\"comment/720\",[]],[\"name/721\",[491,57.078]],[\"comment/721\",[]],[\"name/722\",[492,57.078]],[\"comment/722\",[]],[\"name/723\",[497,62.186]],[\"comment/723\",[]],[\"name/724\",[1,37.619]],[\"comment/724\",[]],[\"name/725\",[498,62.186]],[\"comment/725\",[]],[\"name/726\",[499,62.186]],[\"comment/726\",[]],[\"name/727\",[500,62.186]],[\"comment/727\",[]],[\"name/728\",[501,62.186]],[\"comment/728\",[]],[\"name/729\",[502,62.186]],[\"comment/729\",[]],[\"name/730\",[503,62.186]],[\"comment/730\",[]],[\"name/731\",[504,62.186]],[\"comment/731\",[]],[\"name/732\",[28,51.2]],[\"comment/732\",[]],[\"name/733\",[2,49.193]],[\"comment/733\",[]],[\"name/734\",[28,51.2]],[\"comment/734\",[]],[\"name/735\",[505,62.186]],[\"comment/735\",[]],[\"name/736\",[506,62.186]],[\"comment/736\",[]],[\"name/737\",[507,62.186]],[\"comment/737\",[]],[\"name/738\",[47,57.078]],[\"comment/738\",[]],[\"name/739\",[508,62.186]],[\"comment/739\",[]],[\"name/740\",[509,62.186]],[\"comment/740\",[]],[\"name/741\",[510,62.186]],[\"comment/741\",[]],[\"name/742\",[511,62.186]],[\"comment/742\",[]],[\"name/743\",[512,62.186]],[\"comment/743\",[]],[\"name/744\",[132,47.523]],[\"comment/744\",[]],[\"name/745\",[1,37.619]],[\"comment/745\",[]],[\"name/746\",[38,38.832]],[\"comment/746\",[]],[\"name/747\",[8,37.063]],[\"comment/747\",[]],[\"name/748\",[513,62.186]],[\"comment/748\",[]],[\"name/749\",[514,62.186]],[\"comment/749\",[]],[\"name/750\",[515,62.186]],[\"comment/750\",[]],[\"name/751\",[516,62.186]],[\"comment/751\",[]]],\"invertedIndex\":[[\"__type\",{\"_index\":77,\"name\":{\"107\":{},\"232\":{},\"275\":{},\"293\":{},\"347\":{},\"349\":{},\"566\":{},\"583\":{},\"590\":{},\"599\":{},\"628\":{}},\"comment\":{}}],[\"actingas\",{\"_index\":438,\"name\":{\"616\":{}},\"comment\":{}}],[\"actingasdevice\",{\"_index\":442,\"name\":{\"627\":{}},\"comment\":{}}],[\"action\",{\"_index\":423,\"name\":{\"581\":{},\"597\":{}},\"comment\":{}}],[\"activeonloadloops\",{\"_index\":192,\"name\":{\"345\":{}},\"comment\":{}}],[\"adddevice\",{\"_index\":485,\"name\":{\"702\":{}},\"comment\":{}}],[\"address\",{\"_index\":4,\"name\":{\"4\":{},\"588\":{}},\"comment\":{}}],[\"addressport\",{\"_index\":430,\"name\":{\"594\":{}},\"comment\":{}}],[\"addservice\",{\"_index\":491,\"name\":{\"709\":{},\"721\":{}},\"comment\":{}}],[\"album\",{\"_index\":160,\"name\":{\"311\":{}},\"comment\":{}}],[\"albumart\",{\"_index\":168,\"name\":{\"319\":{}},\"comment\":{}}],[\"albumartid\",{\"_index\":156,\"name\":{\"307\":{}},\"comment\":{}}],[\"announce\",{\"_index\":15,\"name\":{\"15\":{}},\"comment\":{}}],[\"announcetimer\",{\"_index\":9,\"name\":{\"9\":{}},\"comment\":{}}],[\"array\",{\"_index\":484,\"name\":{\"698\":{}},\"comment\":{}}],[\"artist\",{\"_index\":159,\"name\":{\"310\":{}},\"comment\":{}}],[\"artistname\",{\"_index\":135,\"name\":{\"279\":{}},\"comment\":{}}],[\"autogrow\",{\"_index\":470,\"name\":{\"670\":{}},\"comment\":{}}],[\"avgtimearray\",{\"_index\":111,\"name\":{\"210\":{}},\"comment\":{}}],[\"beatdata\",{\"_index\":92,\"name\":{\"163\":{},\"339\":{}},\"comment\":{}}],[\"beatinfo\",{\"_index\":96,\"name\":{\"169\":{},\"623\":{}},\"comment\":{}}],[\"bitrate\",{\"_index\":154,\"name\":{\"305\":{}},\"comment\":{}}],[\"bpm\",{\"_index\":151,\"name\":{\"301\":{}},\"comment\":{}}],[\"bpmanalyzed\",{\"_index\":155,\"name\":{\"306\":{}},\"comment\":{}}],[\"broadcast\",{\"_index\":122,\"name\":{\"238\":{},\"624\":{}},\"comment\":{}}],[\"broadcastaddress\",{\"_index\":5,\"name\":{\"5\":{}},\"comment\":{}}],[\"broadcastdata\",{\"_index\":121,\"name\":{\"237\":{}},\"comment\":{}}],[\"broadcastmessage\",{\"_index\":17,\"name\":{\"17\":{},\"231\":{}},\"comment\":{}}],[\"buffer\",{\"_index\":444,\"name\":{\"631\":{},\"658\":{},\"683\":{}},\"comment\":{}}],[\"bytesdownloaded\",{\"_index\":33,\"name\":{\"34\":{}},\"comment\":{}}],[\"checksize\",{\"_index\":472,\"name\":{\"673\":{}},\"comment\":{}}],[\"clientlibrariandevicescontrollercurrentdevice\",{\"_index\":195,\"name\":{\"350\":{}},\"comment\":{}}],[\"clientlibrariandevicescontrollercurrentdevicenetworkpath\",{\"_index\":196,\"name\":{\"351\":{}},\"comment\":{}}],[\"clientlibrariandevicescontrollerhassdcardconnected\",{\"_index\":197,\"name\":{\"352\":{}},\"comment\":{}}],[\"clientlibrariandevicescontrollerhasusbdeviceconnected\",{\"_index\":198,\"name\":{\"353\":{}},\"comment\":{}}],[\"clientpreferenceslayera\",{\"_index\":199,\"name\":{\"354\":{}},\"comment\":{}}],[\"clientpreferenceslayerb\",{\"_index\":200,\"name\":{\"355\":{}},\"comment\":{}}],[\"clientpreferencesplayer\",{\"_index\":201,\"name\":{\"356\":{}},\"comment\":{}}],[\"clientpreferencesplayerjogcolora\",{\"_index\":202,\"name\":{\"357\":{}},\"comment\":{}}],[\"clientpreferencesplayerjogcolorb\",{\"_index\":203,\"name\":{\"358\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor1\",{\"_index\":204,\"name\":{\"359\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor1a\",{\"_index\":205,\"name\":{\"360\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor1b\",{\"_index\":206,\"name\":{\"361\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor2\",{\"_index\":207,\"name\":{\"362\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor2a\",{\"_index\":208,\"name\":{\"363\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor2b\",{\"_index\":209,\"name\":{\"364\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor3\",{\"_index\":210,\"name\":{\"365\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor3a\",{\"_index\":211,\"name\":{\"366\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor3b\",{\"_index\":212,\"name\":{\"367\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor4\",{\"_index\":213,\"name\":{\"368\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor4a\",{\"_index\":214,\"name\":{\"369\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationplayercolor4b\",{\"_index\":215,\"name\":{\"370\":{}},\"comment\":{}}],[\"clientpreferencesprofileapplicationsyncmode\",{\"_index\":216,\"name\":{\"371\":{}},\"comment\":{}}],[\"clock\",{\"_index\":93,\"name\":{\"166\":{}},\"comment\":{}}],[\"close\",{\"_index\":504,\"name\":{\"731\":{}},\"comment\":{}}],[\"closeservice\",{\"_index\":70,\"name\":{\"77\":{},\"98\":{},\"137\":{},\"162\":{},\"199\":{},\"230\":{},\"258\":{}},\"comment\":{}}],[\"comment\",{\"_index\":162,\"name\":{\"313\":{}},\"comment\":{}}],[\"composer\",{\"_index\":164,\"name\":{\"315\":{}},\"comment\":{}}],[\"connect\",{\"_index\":128,\"name\":{\"268\":{}},\"comment\":{}}],[\"connectioninfo\",{\"_index\":427,\"name\":{\"587\":{}},\"comment\":{}}],[\"connecttomixer\",{\"_index\":441,\"name\":{\"619\":{}},\"comment\":{}}],[\"constructor\",{\"_index\":1,\"name\":{\"1\":{},\"40\":{},\"80\":{},\"117\":{},\"142\":{},\"174\":{},\"205\":{},\"241\":{},\"270\":{},\"272\":{},\"630\":{},\"643\":{},\"669\":{},\"694\":{},\"712\":{},\"724\":{},\"745\":{}},\"comment\":{}}],[\"context\",{\"_index\":443,\"name\":{\"629\":{}},\"comment\":{}}],[\"creatediscoverymessage\",{\"_index\":20,\"name\":{\"20\":{}},\"comment\":{}}],[\"currentbeatdata\",{\"_index\":100,\"name\":{\"179\":{}},\"comment\":{}}],[\"currentbpm\",{\"_index\":136,\"name\":{\"280\":{}},\"comment\":{}}],[\"data\",{\"_index\":29,\"name\":{\"30\":{}},\"comment\":{}}],[\"databases\",{\"_index\":513,\"name\":{\"748\":{}},\"comment\":{}}],[\"databaseuuid\",{\"_index\":117,\"name\":{\"233\":{}},\"comment\":{}}],[\"datahandler\",{\"_index\":74,\"name\":{\"94\":{}},\"comment\":{}}],[\"dateadded\",{\"_index\":174,\"name\":{\"325\":{}},\"comment\":{}}],[\"datecreated\",{\"_index\":173,\"name\":{\"324\":{}},\"comment\":{}}],[\"db\",{\"_index\":498,\"name\":{\"725\":{}},\"comment\":{}}],[\"dbconnection\",{\"_index\":497,\"name\":{\"723\":{}},\"comment\":{}}],[\"dbpath\",{\"_index\":499,\"name\":{\"726\":{}},\"comment\":{}}],[\"deck\",{\"_index\":95,\"name\":{\"168\":{}},\"comment\":{}}],[\"deckcount\",{\"_index\":94,\"name\":{\"167\":{},\"716\":{}},\"comment\":{}}],[\"decks\",{\"_index\":429,\"name\":{\"593\":{}},\"comment\":{}}],[\"deletedevice\",{\"_index\":101,\"name\":{\"182\":{}},\"comment\":{}}],[\"deleteservice\",{\"_index\":492,\"name\":{\"710\":{},\"722\":{}},\"comment\":{}}],[\"deletesource\",{\"_index\":509,\"name\":{\"740\":{}},\"comment\":{}}],[\"device\",{\"_index\":60,\"name\":{\"65\":{},\"82\":{},\"125\":{},\"151\":{},\"188\":{},\"219\":{},\"247\":{},\"704\":{},\"711\":{}},\"comment\":{}}],[\"deviceid\",{\"_index\":8,\"name\":{\"8\":{},\"25\":{},\"66\":{},\"83\":{},\"104\":{},\"126\":{},\"139\":{},\"152\":{},\"165\":{},\"189\":{},\"220\":{},\"248\":{},\"579\":{},\"595\":{},\"612\":{},\"693\":{},\"713\":{},\"747\":{}},\"comment\":{}}],[\"devices\",{\"_index\":125,\"name\":{\"262\":{},\"699\":{},\"701\":{}},\"comment\":{}}],[\"directory\",{\"_index\":88,\"name\":{\"140\":{},\"266\":{},\"626\":{}},\"comment\":{}}],[\"directorydata\",{\"_index\":87,\"name\":{\"138\":{}},\"comment\":{}}],[\"disconnect\",{\"_index\":129,\"name\":{\"269\":{}},\"comment\":{}}],[\"discovery\",{\"_index\":0,\"name\":{\"0\":{},\"263\":{}},\"comment\":{}}],[\"discoverymessage\",{\"_index\":422,\"name\":{\"578\":{}},\"comment\":{}}],[\"discoverymessageoptions\",{\"_index\":435,\"name\":{\"608\":{}},\"comment\":{}}],[\"downloaddbs\",{\"_index\":512,\"name\":{\"743\":{}},\"comment\":{}}],[\"downloaddbsources\",{\"_index\":439,\"name\":{\"617\":{}},\"comment\":{}}],[\"downloadfile\",{\"_index\":511,\"name\":{\"742\":{}},\"comment\":{}}],[\"emitter\",{\"_index\":36,\"name\":{\"37\":{},\"114\":{},\"171\":{},\"239\":{}},\"comment\":{}}],[\"enginedeck1currentbpm\",{\"_index\":229,\"name\":{\"384\":{}},\"comment\":{}}],[\"enginedeck1deckismaster\",{\"_index\":221,\"name\":{\"376\":{}},\"comment\":{}}],[\"enginedeck1externalmixervolume\",{\"_index\":230,\"name\":{\"385\":{}},\"comment\":{}}],[\"enginedeck1externalscratchwheeltouch\",{\"_index\":231,\"name\":{\"386\":{}},\"comment\":{}}],[\"enginedeck1padsview\",{\"_index\":232,\"name\":{\"387\":{}},\"comment\":{}}],[\"enginedeck1play\",{\"_index\":233,\"name\":{\"388\":{}},\"comment\":{}}],[\"enginedeck1playstate\",{\"_index\":234,\"name\":{\"389\":{}},\"comment\":{}}],[\"enginedeck1playstatepath\",{\"_index\":235,\"name\":{\"390\":{}},\"comment\":{}}],[\"enginedeck1speed\",{\"_index\":236,\"name\":{\"391\":{}},\"comment\":{}}],[\"enginedeck1speedneutral\",{\"_index\":237,\"name\":{\"392\":{}},\"comment\":{}}],[\"enginedeck1speedoffsetdown\",{\"_index\":238,\"name\":{\"393\":{}},\"comment\":{}}],[\"enginedeck1speedoffsetup\",{\"_index\":239,\"name\":{\"394\":{}},\"comment\":{}}],[\"enginedeck1speedrange\",{\"_index\":240,\"name\":{\"395\":{}},\"comment\":{}}],[\"enginedeck1speedstate\",{\"_index\":241,\"name\":{\"396\":{}},\"comment\":{}}],[\"enginedeck1syncmode\",{\"_index\":242,\"name\":{\"397\":{}},\"comment\":{}}],[\"enginedeck1syncplaystate\",{\"_index\":217,\"name\":{\"372\":{}},\"comment\":{}}],[\"enginedeck1trackartistname\",{\"_index\":243,\"name\":{\"398\":{}},\"comment\":{}}],[\"enginedeck1trackbleep\",{\"_index\":244,\"name\":{\"399\":{}},\"comment\":{}}],[\"enginedeck1trackcueposition\",{\"_index\":245,\"name\":{\"400\":{}},\"comment\":{}}],[\"enginedeck1trackcurrentbpm\",{\"_index\":246,\"name\":{\"401\":{}},\"comment\":{}}],[\"enginedeck1trackcurrentkeyindex\",{\"_index\":247,\"name\":{\"402\":{}},\"comment\":{}}],[\"enginedeck1trackcurrentloopinposition\",{\"_index\":248,\"name\":{\"403\":{}},\"comment\":{}}],[\"enginedeck1trackcurrentloopoutposition\",{\"_index\":249,\"name\":{\"404\":{}},\"comment\":{}}],[\"enginedeck1trackcurrentloopsizeinbeats\",{\"_index\":250,\"name\":{\"405\":{}},\"comment\":{}}],[\"enginedeck1trackkeylock\",{\"_index\":251,\"name\":{\"406\":{}},\"comment\":{}}],[\"enginedeck1trackloopenablestate\",{\"_index\":252,\"name\":{\"407\":{}},\"comment\":{}}],[\"enginedeck1trackloopquickloop1\",{\"_index\":253,\"name\":{\"408\":{}},\"comment\":{}}],[\"enginedeck1trackloopquickloop2\",{\"_index\":254,\"name\":{\"409\":{}},\"comment\":{}}],[\"enginedeck1trackloopquickloop3\",{\"_index\":255,\"name\":{\"410\":{}},\"comment\":{}}],[\"enginedeck1trackloopquickloop4\",{\"_index\":256,\"name\":{\"411\":{}},\"comment\":{}}],[\"enginedeck1trackloopquickloop5\",{\"_index\":257,\"name\":{\"412\":{}},\"comment\":{}}],[\"enginedeck1trackloopquickloop6\",{\"_index\":258,\"name\":{\"413\":{}},\"comment\":{}}],[\"enginedeck1trackloopquickloop7\",{\"_index\":259,\"name\":{\"414\":{}},\"comment\":{}}],[\"enginedeck1trackloopquickloop8\",{\"_index\":260,\"name\":{\"415\":{}},\"comment\":{}}],[\"enginedeck1trackplaypauseledstate\",{\"_index\":261,\"name\":{\"416\":{}},\"comment\":{}}],[\"enginedeck1tracksamplerate\",{\"_index\":262,\"name\":{\"417\":{}},\"comment\":{}}],[\"enginedeck1tracksonganalyzed\",{\"_index\":263,\"name\":{\"418\":{}},\"comment\":{}}],[\"enginedeck1tracksongloaded\",{\"_index\":264,\"name\":{\"419\":{}},\"comment\":{}}],[\"enginedeck1tracksongname\",{\"_index\":265,\"name\":{\"420\":{}},\"comment\":{}}],[\"enginedeck1tracksoundswitchguid\",{\"_index\":266,\"name\":{\"421\":{}},\"comment\":{}}],[\"enginedeck1tracktrackbytes\",{\"_index\":267,\"name\":{\"422\":{}},\"comment\":{}}],[\"enginedeck1tracktrackdata\",{\"_index\":268,\"name\":{\"423\":{}},\"comment\":{}}],[\"enginedeck1tracktracklength\",{\"_index\":269,\"name\":{\"424\":{}},\"comment\":{}}],[\"enginedeck1tracktrackname\",{\"_index\":270,\"name\":{\"425\":{}},\"comment\":{}}],[\"enginedeck1tracktracknetworkpath\",{\"_index\":271,\"name\":{\"426\":{}},\"comment\":{}}],[\"enginedeck1tracktrackuri\",{\"_index\":272,\"name\":{\"427\":{}},\"comment\":{}}],[\"enginedeck1tracktrackwasplayed\",{\"_index\":273,\"name\":{\"428\":{}},\"comment\":{}}],[\"enginedeck2currentbpm\",{\"_index\":274,\"name\":{\"429\":{}},\"comment\":{}}],[\"enginedeck2deckismaster\",{\"_index\":222,\"name\":{\"377\":{}},\"comment\":{}}],[\"enginedeck2externalmixervolume\",{\"_index\":275,\"name\":{\"430\":{}},\"comment\":{}}],[\"enginedeck2externalscratchwheeltouch\",{\"_index\":276,\"name\":{\"431\":{}},\"comment\":{}}],[\"enginedeck2padsview\",{\"_index\":277,\"name\":{\"432\":{}},\"comment\":{}}],[\"enginedeck2play\",{\"_index\":278,\"name\":{\"433\":{}},\"comment\":{}}],[\"enginedeck2playstate\",{\"_index\":279,\"name\":{\"434\":{}},\"comment\":{}}],[\"enginedeck2playstatepath\",{\"_index\":280,\"name\":{\"435\":{}},\"comment\":{}}],[\"enginedeck2speed\",{\"_index\":281,\"name\":{\"436\":{}},\"comment\":{}}],[\"enginedeck2speedneutral\",{\"_index\":282,\"name\":{\"437\":{}},\"comment\":{}}],[\"enginedeck2speedoffsetdown\",{\"_index\":283,\"name\":{\"438\":{}},\"comment\":{}}],[\"enginedeck2speedoffsetup\",{\"_index\":284,\"name\":{\"439\":{}},\"comment\":{}}],[\"enginedeck2speedrange\",{\"_index\":285,\"name\":{\"440\":{}},\"comment\":{}}],[\"enginedeck2speedstate\",{\"_index\":286,\"name\":{\"441\":{}},\"comment\":{}}],[\"enginedeck2syncmode\",{\"_index\":287,\"name\":{\"442\":{}},\"comment\":{}}],[\"enginedeck2syncplaystate\",{\"_index\":218,\"name\":{\"373\":{}},\"comment\":{}}],[\"enginedeck2trackartistname\",{\"_index\":288,\"name\":{\"443\":{}},\"comment\":{}}],[\"enginedeck2trackbleep\",{\"_index\":289,\"name\":{\"444\":{}},\"comment\":{}}],[\"enginedeck2trackcueposition\",{\"_index\":290,\"name\":{\"445\":{}},\"comment\":{}}],[\"enginedeck2trackcurrentbpm\",{\"_index\":291,\"name\":{\"446\":{}},\"comment\":{}}],[\"enginedeck2trackcurrentkeyindex\",{\"_index\":292,\"name\":{\"447\":{}},\"comment\":{}}],[\"enginedeck2trackcurrentloopinposition\",{\"_index\":293,\"name\":{\"448\":{}},\"comment\":{}}],[\"enginedeck2trackcurrentloopoutposition\",{\"_index\":294,\"name\":{\"449\":{}},\"comment\":{}}],[\"enginedeck2trackcurrentloopsizeinbeats\",{\"_index\":295,\"name\":{\"450\":{}},\"comment\":{}}],[\"enginedeck2trackkeylock\",{\"_index\":296,\"name\":{\"451\":{}},\"comment\":{}}],[\"enginedeck2trackloopenablestate\",{\"_index\":297,\"name\":{\"452\":{}},\"comment\":{}}],[\"enginedeck2trackloopquickloop1\",{\"_index\":298,\"name\":{\"453\":{}},\"comment\":{}}],[\"enginedeck2trackloopquickloop2\",{\"_index\":299,\"name\":{\"454\":{}},\"comment\":{}}],[\"enginedeck2trackloopquickloop3\",{\"_index\":300,\"name\":{\"455\":{}},\"comment\":{}}],[\"enginedeck2trackloopquickloop4\",{\"_index\":301,\"name\":{\"456\":{}},\"comment\":{}}],[\"enginedeck2trackloopquickloop5\",{\"_index\":302,\"name\":{\"457\":{}},\"comment\":{}}],[\"enginedeck2trackloopquickloop6\",{\"_index\":303,\"name\":{\"458\":{}},\"comment\":{}}],[\"enginedeck2trackloopquickloop7\",{\"_index\":304,\"name\":{\"459\":{}},\"comment\":{}}],[\"enginedeck2trackloopquickloop8\",{\"_index\":305,\"name\":{\"460\":{}},\"comment\":{}}],[\"enginedeck2trackplaypauseledstate\",{\"_index\":306,\"name\":{\"461\":{}},\"comment\":{}}],[\"enginedeck2tracksamplerate\",{\"_index\":307,\"name\":{\"462\":{}},\"comment\":{}}],[\"enginedeck2tracksonganalyzed\",{\"_index\":308,\"name\":{\"463\":{}},\"comment\":{}}],[\"enginedeck2tracksongloaded\",{\"_index\":309,\"name\":{\"464\":{}},\"comment\":{}}],[\"enginedeck2tracksongname\",{\"_index\":310,\"name\":{\"465\":{}},\"comment\":{}}],[\"enginedeck2tracksoundswitchguid\",{\"_index\":311,\"name\":{\"466\":{}},\"comment\":{}}],[\"enginedeck2tracktrackbytes\",{\"_index\":312,\"name\":{\"467\":{}},\"comment\":{}}],[\"enginedeck2tracktrackdata\",{\"_index\":313,\"name\":{\"468\":{}},\"comment\":{}}],[\"enginedeck2tracktracklength\",{\"_index\":314,\"name\":{\"469\":{}},\"comment\":{}}],[\"enginedeck2tracktrackname\",{\"_index\":315,\"name\":{\"470\":{}},\"comment\":{}}],[\"enginedeck2tracktracknetworkpath\",{\"_index\":316,\"name\":{\"471\":{}},\"comment\":{}}],[\"enginedeck2tracktrackuri\",{\"_index\":317,\"name\":{\"472\":{}},\"comment\":{}}],[\"enginedeck2tracktrackwasplayed\",{\"_index\":318,\"name\":{\"473\":{}},\"comment\":{}}],[\"enginedeck3currentbpm\",{\"_index\":319,\"name\":{\"474\":{}},\"comment\":{}}],[\"enginedeck3deckismaster\",{\"_index\":223,\"name\":{\"378\":{}},\"comment\":{}}],[\"enginedeck3externalmixervolume\",{\"_index\":320,\"name\":{\"475\":{}},\"comment\":{}}],[\"enginedeck3externalscratchwheeltouch\",{\"_index\":321,\"name\":{\"476\":{}},\"comment\":{}}],[\"enginedeck3padsview\",{\"_index\":322,\"name\":{\"477\":{}},\"comment\":{}}],[\"enginedeck3play\",{\"_index\":323,\"name\":{\"478\":{}},\"comment\":{}}],[\"enginedeck3playstate\",{\"_index\":324,\"name\":{\"479\":{}},\"comment\":{}}],[\"enginedeck3playstatepath\",{\"_index\":325,\"name\":{\"480\":{}},\"comment\":{}}],[\"enginedeck3speed\",{\"_index\":326,\"name\":{\"481\":{}},\"comment\":{}}],[\"enginedeck3speedneutral\",{\"_index\":327,\"name\":{\"482\":{}},\"comment\":{}}],[\"enginedeck3speedoffsetdown\",{\"_index\":328,\"name\":{\"483\":{}},\"comment\":{}}],[\"enginedeck3speedoffsetup\",{\"_index\":329,\"name\":{\"484\":{}},\"comment\":{}}],[\"enginedeck3speedrange\",{\"_index\":330,\"name\":{\"485\":{}},\"comment\":{}}],[\"enginedeck3speedstate\",{\"_index\":331,\"name\":{\"486\":{}},\"comment\":{}}],[\"enginedeck3syncmode\",{\"_index\":332,\"name\":{\"487\":{}},\"comment\":{}}],[\"enginedeck3syncplaystate\",{\"_index\":219,\"name\":{\"374\":{}},\"comment\":{}}],[\"enginedeck3trackartistname\",{\"_index\":333,\"name\":{\"488\":{}},\"comment\":{}}],[\"enginedeck3trackbleep\",{\"_index\":334,\"name\":{\"489\":{}},\"comment\":{}}],[\"enginedeck3trackcueposition\",{\"_index\":335,\"name\":{\"490\":{}},\"comment\":{}}],[\"enginedeck3trackcurrentbpm\",{\"_index\":336,\"name\":{\"491\":{}},\"comment\":{}}],[\"enginedeck3trackcurrentkeyindex\",{\"_index\":337,\"name\":{\"492\":{}},\"comment\":{}}],[\"enginedeck3trackcurrentloopinposition\",{\"_index\":338,\"name\":{\"493\":{}},\"comment\":{}}],[\"enginedeck3trackcurrentloopoutposition\",{\"_index\":339,\"name\":{\"494\":{}},\"comment\":{}}],[\"enginedeck3trackcurrentloopsizeinbeats\",{\"_index\":340,\"name\":{\"495\":{}},\"comment\":{}}],[\"enginedeck3trackkeylock\",{\"_index\":341,\"name\":{\"496\":{}},\"comment\":{}}],[\"enginedeck3trackloopenablestate\",{\"_index\":342,\"name\":{\"497\":{}},\"comment\":{}}],[\"enginedeck3trackloopquickloop1\",{\"_index\":343,\"name\":{\"498\":{}},\"comment\":{}}],[\"enginedeck3trackloopquickloop2\",{\"_index\":344,\"name\":{\"499\":{}},\"comment\":{}}],[\"enginedeck3trackloopquickloop3\",{\"_index\":345,\"name\":{\"500\":{}},\"comment\":{}}],[\"enginedeck3trackloopquickloop4\",{\"_index\":346,\"name\":{\"501\":{}},\"comment\":{}}],[\"enginedeck3trackloopquickloop5\",{\"_index\":347,\"name\":{\"502\":{}},\"comment\":{}}],[\"enginedeck3trackloopquickloop6\",{\"_index\":348,\"name\":{\"503\":{}},\"comment\":{}}],[\"enginedeck3trackloopquickloop7\",{\"_index\":349,\"name\":{\"504\":{}},\"comment\":{}}],[\"enginedeck3trackloopquickloop8\",{\"_index\":350,\"name\":{\"505\":{}},\"comment\":{}}],[\"enginedeck3trackplaypauseledstate\",{\"_index\":351,\"name\":{\"506\":{}},\"comment\":{}}],[\"enginedeck3tracksamplerate\",{\"_index\":352,\"name\":{\"507\":{}},\"comment\":{}}],[\"enginedeck3tracksonganalyzed\",{\"_index\":353,\"name\":{\"508\":{}},\"comment\":{}}],[\"enginedeck3tracksongloaded\",{\"_index\":354,\"name\":{\"509\":{}},\"comment\":{}}],[\"enginedeck3tracksongname\",{\"_index\":355,\"name\":{\"510\":{}},\"comment\":{}}],[\"enginedeck3tracksoundswitchguid\",{\"_index\":356,\"name\":{\"511\":{}},\"comment\":{}}],[\"enginedeck3tracktrackbytes\",{\"_index\":357,\"name\":{\"512\":{}},\"comment\":{}}],[\"enginedeck3tracktrackdata\",{\"_index\":358,\"name\":{\"513\":{}},\"comment\":{}}],[\"enginedeck3tracktracklength\",{\"_index\":359,\"name\":{\"514\":{}},\"comment\":{}}],[\"enginedeck3tracktrackname\",{\"_index\":360,\"name\":{\"515\":{}},\"comment\":{}}],[\"enginedeck3tracktracknetworkpath\",{\"_index\":361,\"name\":{\"516\":{}},\"comment\":{}}],[\"enginedeck3tracktrackuri\",{\"_index\":362,\"name\":{\"517\":{}},\"comment\":{}}],[\"enginedeck3tracktrackwasplayed\",{\"_index\":363,\"name\":{\"518\":{}},\"comment\":{}}],[\"enginedeck4currentbpm\",{\"_index\":364,\"name\":{\"519\":{}},\"comment\":{}}],[\"enginedeck4deckismaster\",{\"_index\":224,\"name\":{\"379\":{}},\"comment\":{}}],[\"enginedeck4externalmixervolume\",{\"_index\":365,\"name\":{\"520\":{}},\"comment\":{}}],[\"enginedeck4externalscratchwheeltouch\",{\"_index\":366,\"name\":{\"521\":{}},\"comment\":{}}],[\"enginedeck4padsview\",{\"_index\":367,\"name\":{\"522\":{}},\"comment\":{}}],[\"enginedeck4play\",{\"_index\":368,\"name\":{\"523\":{}},\"comment\":{}}],[\"enginedeck4playstate\",{\"_index\":369,\"name\":{\"524\":{}},\"comment\":{}}],[\"enginedeck4playstatepath\",{\"_index\":370,\"name\":{\"525\":{}},\"comment\":{}}],[\"enginedeck4speed\",{\"_index\":371,\"name\":{\"526\":{}},\"comment\":{}}],[\"enginedeck4speedneutral\",{\"_index\":372,\"name\":{\"527\":{}},\"comment\":{}}],[\"enginedeck4speedoffsetdown\",{\"_index\":373,\"name\":{\"528\":{}},\"comment\":{}}],[\"enginedeck4speedoffsetup\",{\"_index\":374,\"name\":{\"529\":{}},\"comment\":{}}],[\"enginedeck4speedrange\",{\"_index\":375,\"name\":{\"530\":{}},\"comment\":{}}],[\"enginedeck4speedstate\",{\"_index\":376,\"name\":{\"531\":{}},\"comment\":{}}],[\"enginedeck4syncmode\",{\"_index\":377,\"name\":{\"532\":{}},\"comment\":{}}],[\"enginedeck4syncplaystate\",{\"_index\":220,\"name\":{\"375\":{}},\"comment\":{}}],[\"enginedeck4trackartistname\",{\"_index\":378,\"name\":{\"533\":{}},\"comment\":{}}],[\"enginedeck4trackbleep\",{\"_index\":379,\"name\":{\"534\":{}},\"comment\":{}}],[\"enginedeck4trackcueposition\",{\"_index\":380,\"name\":{\"535\":{}},\"comment\":{}}],[\"enginedeck4trackcurrentbpm\",{\"_index\":381,\"name\":{\"536\":{}},\"comment\":{}}],[\"enginedeck4trackcurrentkeyindex\",{\"_index\":382,\"name\":{\"537\":{}},\"comment\":{}}],[\"enginedeck4trackcurrentloopinposition\",{\"_index\":383,\"name\":{\"538\":{}},\"comment\":{}}],[\"enginedeck4trackcurrentloopoutposition\",{\"_index\":384,\"name\":{\"539\":{}},\"comment\":{}}],[\"enginedeck4trackcurrentloopsizeinbeats\",{\"_index\":385,\"name\":{\"540\":{}},\"comment\":{}}],[\"enginedeck4trackkeylock\",{\"_index\":386,\"name\":{\"541\":{}},\"comment\":{}}],[\"enginedeck4trackloopenablestate\",{\"_index\":387,\"name\":{\"542\":{}},\"comment\":{}}],[\"enginedeck4trackloopquickloop1\",{\"_index\":388,\"name\":{\"543\":{}},\"comment\":{}}],[\"enginedeck4trackloopquickloop2\",{\"_index\":389,\"name\":{\"544\":{}},\"comment\":{}}],[\"enginedeck4trackloopquickloop3\",{\"_index\":390,\"name\":{\"545\":{}},\"comment\":{}}],[\"enginedeck4trackloopquickloop4\",{\"_index\":391,\"name\":{\"546\":{}},\"comment\":{}}],[\"enginedeck4trackloopquickloop5\",{\"_index\":392,\"name\":{\"547\":{}},\"comment\":{}}],[\"enginedeck4trackloopquickloop6\",{\"_index\":393,\"name\":{\"548\":{}},\"comment\":{}}],[\"enginedeck4trackloopquickloop7\",{\"_index\":394,\"name\":{\"549\":{}},\"comment\":{}}],[\"enginedeck4trackloopquickloop8\",{\"_index\":395,\"name\":{\"550\":{}},\"comment\":{}}],[\"enginedeck4trackplaypauseledstate\",{\"_index\":396,\"name\":{\"551\":{}},\"comment\":{}}],[\"enginedeck4tracksamplerate\",{\"_index\":397,\"name\":{\"552\":{}},\"comment\":{}}],[\"enginedeck4tracksonganalyzed\",{\"_index\":398,\"name\":{\"553\":{}},\"comment\":{}}],[\"enginedeck4tracksongloaded\",{\"_index\":399,\"name\":{\"554\":{}},\"comment\":{}}],[\"enginedeck4tracksongname\",{\"_index\":400,\"name\":{\"555\":{}},\"comment\":{}}],[\"enginedeck4tracksoundswitchguid\",{\"_index\":401,\"name\":{\"556\":{}},\"comment\":{}}],[\"enginedeck4tracktrackbytes\",{\"_index\":402,\"name\":{\"557\":{}},\"comment\":{}}],[\"enginedeck4tracktrackdata\",{\"_index\":403,\"name\":{\"558\":{}},\"comment\":{}}],[\"enginedeck4tracktracklength\",{\"_index\":404,\"name\":{\"559\":{}},\"comment\":{}}],[\"enginedeck4tracktrackname\",{\"_index\":405,\"name\":{\"560\":{}},\"comment\":{}}],[\"enginedeck4tracktracknetworkpath\",{\"_index\":406,\"name\":{\"561\":{}},\"comment\":{}}],[\"enginedeck4tracktrackuri\",{\"_index\":407,\"name\":{\"562\":{}},\"comment\":{}}],[\"enginedeck4tracktrackwasplayed\",{\"_index\":408,\"name\":{\"563\":{}},\"comment\":{}}],[\"enginedeckcount\",{\"_index\":228,\"name\":{\"383\":{}},\"comment\":{}}],[\"enginemastermastertempo\",{\"_index\":227,\"name\":{\"382\":{}},\"comment\":{}}],[\"enginesyncnetworkmasterstatus\",{\"_index\":226,\"name\":{\"381\":{}},\"comment\":{}}],[\"enginesyncnetworksynctype\",{\"_index\":225,\"name\":{\"380\":{}},\"comment\":{}}],[\"explicitlyrics\",{\"_index\":191,\"name\":{\"344\":{}},\"comment\":{}}],[\"filebytes\",{\"_index\":157,\"name\":{\"308\":{}},\"comment\":{}}],[\"filename\",{\"_index\":153,\"name\":{\"304\":{}},\"comment\":{}}],[\"filetransfer\",{\"_index\":35,\"name\":{\"36\":{},\"622\":{}},\"comment\":{}}],[\"filetransferdata\",{\"_index\":23,\"name\":{\"23\":{}},\"comment\":{}}],[\"filetransferprogress\",{\"_index\":30,\"name\":{\"31\":{}},\"comment\":{}}],[\"filetype\",{\"_index\":171,\"name\":{\"322\":{}},\"comment\":{}}],[\"findbroadcastips\",{\"_index\":22,\"name\":{\"22\":{}},\"comment\":{}}],[\"genre\",{\"_index\":161,\"name\":{\"312\":{}},\"comment\":{}}],[\"getbeatdata\",{\"_index\":102,\"name\":{\"183\":{}},\"comment\":{}}],[\"getbuffer\",{\"_index\":471,\"name\":{\"671\":{}},\"comment\":{}}],[\"getconnectioninfo\",{\"_index\":11,\"name\":{\"11\":{}},\"comment\":{}}],[\"getdatabase\",{\"_index\":514,\"name\":{\"749\":{}},\"comment\":{}}],[\"getdatabases\",{\"_index\":515,\"name\":{\"750\":{}},\"comment\":{}}],[\"getdbbyuuid\",{\"_index\":510,\"name\":{\"741\":{}},\"comment\":{}}],[\"getdevice\",{\"_index\":486,\"name\":{\"703\":{}},\"comment\":{}}],[\"getdevicelist\",{\"_index\":12,\"name\":{\"12\":{}},\"comment\":{}}],[\"getdevices\",{\"_index\":13,\"name\":{\"13\":{}},\"comment\":{}}],[\"getdeviceservices\",{\"_index\":490,\"name\":{\"708\":{}},\"comment\":{}}],[\"getfile\",{\"_index\":45,\"name\":{\"49\":{}},\"comment\":{}}],[\"getinstances\",{\"_index\":97,\"name\":{\"172\":{}},\"comment\":{}}],[\"getservicenames\",{\"_index\":495,\"name\":{\"719\":{}},\"comment\":{}}],[\"getservices\",{\"_index\":496,\"name\":{\"720\":{}},\"comment\":{}}],[\"getsource\",{\"_index\":507,\"name\":{\"737\":{}},\"comment\":{}}],[\"getsourcedirinfo\",{\"_index\":48,\"name\":{\"52\":{}},\"comment\":{}}],[\"getsources\",{\"_index\":47,\"name\":{\"51\":{},\"738\":{}},\"comment\":{}}],[\"getstring\",{\"_index\":461,\"name\":{\"650\":{}},\"comment\":{}}],[\"gettempfilepath\",{\"_index\":453,\"name\":{\"641\":{}},\"comment\":{}}],[\"gettimestamp\",{\"_index\":114,\"name\":{\"213\":{}},\"comment\":{}}],[\"gettrackbyid\",{\"_index\":503,\"name\":{\"730\":{}},\"comment\":{}}],[\"gettrackinfo\",{\"_index\":502,\"name\":{\"729\":{}},\"comment\":{}}],[\"guidecksdeckactivedeck\",{\"_index\":409,\"name\":{\"564\":{}},\"comment\":{}}],[\"hasdevice\",{\"_index\":487,\"name\":{\"705\":{}},\"comment\":{}}],[\"haslooped\",{\"_index\":10,\"name\":{\"10\":{}},\"comment\":{}}],[\"hasnewinfo\",{\"_index\":488,\"name\":{\"706\":{}},\"comment\":{}}],[\"hasservice\",{\"_index\":494,\"name\":{\"718\":{}},\"comment\":{}}],[\"hassource\",{\"_index\":505,\"name\":{\"735\":{}},\"comment\":{}}],[\"hassourceanddb\",{\"_index\":506,\"name\":{\"736\":{}},\"comment\":{}}],[\"id\",{\"_index\":148,\"name\":{\"298\":{},\"604\":{}},\"comment\":{}}],[\"info\",{\"_index\":493,\"name\":{\"714\":{}},\"comment\":{}}],[\"instancelistener\",{\"_index\":42,\"name\":{\"46\":{},\"101\":{},\"119\":{},\"150\":{},\"181\":{},\"218\":{},\"246\":{}},\"comment\":{}}],[\"instances\",{\"_index\":37,\"name\":{\"39\":{},\"79\":{},\"115\":{},\"116\":{},\"141\":{},\"170\":{},\"173\":{},\"204\":{},\"240\":{}},\"comment\":{}}],[\"interval\",{\"_index\":82,\"name\":{\"112\":{}},\"comment\":{}}],[\"ipaddress\",{\"_index\":433,\"name\":{\"606\":{}},\"comment\":{}}],[\"ipaddressport\",{\"_index\":434,\"name\":{\"607\":{}},\"comment\":{}}],[\"isanalyzed\",{\"_index\":172,\"name\":{\"323\":{}},\"comment\":{}}],[\"isavailable\",{\"_index\":40,\"name\":{\"44\":{},\"53\":{},\"326\":{}},\"comment\":{}}],[\"isbeatgridlocked\",{\"_index\":182,\"name\":{\"334\":{}},\"comment\":{}}],[\"isbufferedservice\",{\"_index\":63,\"name\":{\"70\":{},\"87\":{},\"130\":{},\"144\":{},\"180\":{},\"207\":{},\"243\":{}},\"comment\":{}}],[\"iseof\",{\"_index\":450,\"name\":{\"638\":{},\"665\":{},\"689\":{}},\"comment\":{}}],[\"islittleendian\",{\"_index\":451,\"name\":{\"639\":{},\"666\":{},\"690\":{}},\"comment\":{}}],[\"ismetadataimported\",{\"_index\":178,\"name\":{\"330\":{}},\"comment\":{}}],[\"ismetadataofpackedtrackchanged\",{\"_index\":175,\"name\":{\"327\":{}},\"comment\":{}}],[\"isperfomancedataofpackedtrackchanged\",{\"_index\":176,\"name\":{\"328\":{}},\"comment\":{}}],[\"isplayed\",{\"_index\":170,\"name\":{\"321\":{}},\"comment\":{}}],[\"json\",{\"_index\":76,\"name\":{\"106\":{}},\"comment\":{}}],[\"key\",{\"_index\":166,\"name\":{\"317\":{}},\"comment\":{}}],[\"label\",{\"_index\":163,\"name\":{\"314\":{}},\"comment\":{}}],[\"length\",{\"_index\":150,\"name\":{\"300\":{}},\"comment\":{}}],[\"listen\",{\"_index\":14,\"name\":{\"14\":{}},\"comment\":{}}],[\"listenfordevices\",{\"_index\":18,\"name\":{\"18\":{}},\"comment\":{}}],[\"listid\",{\"_index\":119,\"name\":{\"235\":{}},\"comment\":{}}],[\"littleendian\",{\"_index\":446,\"name\":{\"633\":{},\"660\":{},\"685\":{}},\"comment\":{}}],[\"localtime\",{\"_index\":109,\"name\":{\"208\":{}},\"comment\":{}}],[\"location\",{\"_index\":133,\"name\":{\"277\":{},\"295\":{}},\"comment\":{}}],[\"logger\",{\"_index\":124,\"name\":{\"261\":{}},\"comment\":{}}],[\"loops\",{\"_index\":188,\"name\":{\"341\":{}},\"comment\":{}}],[\"m_array\",{\"_index\":483,\"name\":{\"696\":{}},\"comment\":{}}],[\"m_str\",{\"_index\":482,\"name\":{\"695\":{}},\"comment\":{}}],[\"maxretries\",{\"_index\":437,\"name\":{\"615\":{}},\"comment\":{}}],[\"message\",{\"_index\":432,\"name\":{\"605\":{}},\"comment\":{}}],[\"messagebuffer\",{\"_index\":71,\"name\":{\"89\":{}},\"comment\":{}}],[\"messagehandler\",{\"_index\":44,\"name\":{\"48\":{},\"100\":{},\"122\":{},\"147\":{},\"187\":{},\"217\":{},\"245\":{}},\"comment\":{}}],[\"mixer\",{\"_index\":410,\"name\":{\"565\":{}},\"comment\":{}}],[\"mixerch1faderposition\",{\"_index\":411,\"name\":{\"567\":{}},\"comment\":{}}],[\"mixerch2faderposition\",{\"_index\":412,\"name\":{\"568\":{}},\"comment\":{}}],[\"mixerch3faderposition\",{\"_index\":413,\"name\":{\"569\":{}},\"comment\":{}}],[\"mixerch4faderposition\",{\"_index\":414,\"name\":{\"570\":{}},\"comment\":{}}],[\"mixerchannelassignment1\",{\"_index\":416,\"name\":{\"572\":{}},\"comment\":{}}],[\"mixerchannelassignment2\",{\"_index\":417,\"name\":{\"573\":{}},\"comment\":{}}],[\"mixerchannelassignment3\",{\"_index\":418,\"name\":{\"574\":{}},\"comment\":{}}],[\"mixerchannelassignment4\",{\"_index\":419,\"name\":{\"575\":{}},\"comment\":{}}],[\"mixercrossfaderposition\",{\"_index\":415,\"name\":{\"571\":{}},\"comment\":{}}],[\"mixernumberofchannels\",{\"_index\":420,\"name\":{\"576\":{}},\"comment\":{}}],[\"msgs\",{\"_index\":106,\"name\":{\"201\":{}},\"comment\":{}}],[\"name\",{\"_index\":38,\"name\":{\"42\":{},\"81\":{},\"105\":{},\"118\":{},\"143\":{},\"176\":{},\"206\":{},\"242\":{},\"276\":{},\"294\":{},\"584\":{},\"591\":{},\"600\":{},\"609\":{},\"746\":{}},\"comment\":{}}],[\"newdatabase\",{\"_index\":516,\"name\":{\"751\":{}},\"comment\":{}}],[\"newtxid\",{\"_index\":41,\"name\":{\"45\":{}},\"comment\":{}}],[\"offset\",{\"_index\":27,\"name\":{\"28\":{}},\"comment\":{}}],[\"on\",{\"_index\":2,\"name\":{\"2\":{},\"41\":{},\"175\":{},\"700\":{},\"733\":{}},\"comment\":{}}],[\"options\",{\"_index\":6,\"name\":{\"6\":{},\"260\":{}},\"comment\":{}}],[\"origindatabaseuuid\",{\"_index\":183,\"name\":{\"335\":{}},\"comment\":{}}],[\"origintrackid\",{\"_index\":184,\"name\":{\"336\":{}},\"comment\":{}}],[\"overviewwaveformdata\",{\"_index\":186,\"name\":{\"338\":{}},\"comment\":{}}],[\"parsedata\",{\"_index\":43,\"name\":{\"47\":{},\"99\":{},\"121\":{},\"146\":{},\"186\":{},\"215\":{},\"244\":{}},\"comment\":{}}],[\"path\",{\"_index\":134,\"name\":{\"278\":{},\"296\":{},\"303\":{}},\"comment\":{}}],[\"pdbimportkey\",{\"_index\":179,\"name\":{\"331\":{}},\"comment\":{}}],[\"peek\",{\"_index\":456,\"name\":{\"645\":{}},\"comment\":{}}],[\"peers\",{\"_index\":7,\"name\":{\"7\":{}},\"comment\":{}}],[\"percentcomplete\",{\"_index\":34,\"name\":{\"35\":{}},\"comment\":{}}],[\"playedindicator\",{\"_index\":177,\"name\":{\"329\":{}},\"comment\":{}}],[\"player\",{\"_index\":194,\"name\":{\"348\":{}},\"comment\":{}}],[\"playorder\",{\"_index\":149,\"name\":{\"299\":{}},\"comment\":{}}],[\"port\",{\"_index\":426,\"name\":{\"586\":{},\"602\":{},\"613\":{}},\"comment\":{}}],[\"pos\",{\"_index\":445,\"name\":{\"632\":{},\"659\":{},\"684\":{}},\"comment\":{}}],[\"prefix\",{\"_index\":131,\"name\":{\"273\":{},\"291\":{}},\"comment\":{}}],[\"querysource\",{\"_index\":500,\"name\":{\"727\":{}},\"comment\":{}}],[\"quickcues\",{\"_index\":187,\"name\":{\"340\":{}},\"comment\":{}}],[\"rating\",{\"_index\":167,\"name\":{\"318\":{}},\"comment\":{}}],[\"read\",{\"_index\":455,\"name\":{\"644\":{}},\"comment\":{}}],[\"readconnectioninfo\",{\"_index\":19,\"name\":{\"19\":{}},\"comment\":{}}],[\"readcontext\",{\"_index\":454,\"name\":{\"642\":{}},\"comment\":{}}],[\"readfloat64\",{\"_index\":463,\"name\":{\"652\":{}},\"comment\":{}}],[\"readint32\",{\"_index\":466,\"name\":{\"655\":{}},\"comment\":{}}],[\"readnetworkstringutf16\",{\"_index\":462,\"name\":{\"651\":{}},\"comment\":{}}],[\"readremaining\",{\"_index\":457,\"name\":{\"646\":{}},\"comment\":{}}],[\"readremainingasnewarraybuffer\",{\"_index\":459,\"name\":{\"648\":{}},\"comment\":{}}],[\"readremainingasnewbuffer\",{\"_index\":458,\"name\":{\"647\":{}},\"comment\":{}}],[\"readremainingasnewctx\",{\"_index\":460,\"name\":{\"649\":{}},\"comment\":{}}],[\"readuint16\",{\"_index\":467,\"name\":{\"656\":{}},\"comment\":{}}],[\"readuint32\",{\"_index\":465,\"name\":{\"654\":{}},\"comment\":{}}],[\"readuint64\",{\"_index\":464,\"name\":{\"653\":{}},\"comment\":{}}],[\"readuint8\",{\"_index\":468,\"name\":{\"657\":{}},\"comment\":{}}],[\"receivedfile\",{\"_index\":39,\"name\":{\"43\":{}},\"comment\":{}}],[\"releaseservice\",{\"_index\":50,\"name\":{\"55\":{}},\"comment\":{}}],[\"remixer\",{\"_index\":165,\"name\":{\"316\":{}},\"comment\":{}}],[\"remotetime\",{\"_index\":110,\"name\":{\"209\":{}},\"comment\":{}}],[\"requestchunkrange\",{\"_index\":56,\"name\":{\"61\":{}},\"comment\":{}}],[\"requestfiletransferid\",{\"_index\":55,\"name\":{\"60\":{}},\"comment\":{}}],[\"requestpathinfo\",{\"_index\":54,\"name\":{\"59\":{}},\"comment\":{}}],[\"requestservice\",{\"_index\":49,\"name\":{\"54\":{}},\"comment\":{}}],[\"requestsources\",{\"_index\":53,\"name\":{\"58\":{}},\"comment\":{}}],[\"requeststat\",{\"_index\":52,\"name\":{\"57\":{}},\"comment\":{}}],[\"resize\",{\"_index\":473,\"name\":{\"674\":{}},\"comment\":{}}],[\"rewind\",{\"_index\":452,\"name\":{\"640\":{},\"667\":{},\"691\":{}},\"comment\":{}}],[\"samplerate\",{\"_index\":137,\"name\":{\"281\":{}},\"comment\":{}}],[\"seek\",{\"_index\":448,\"name\":{\"636\":{},\"663\":{},\"687\":{}},\"comment\":{}}],[\"sendbeatinforequest\",{\"_index\":104,\"name\":{\"185\":{}},\"comment\":{}}],[\"sendnosourcesreply\",{\"_index\":59,\"name\":{\"64\":{}},\"comment\":{}}],[\"sendserviceannouncement\",{\"_index\":90,\"name\":{\"148\":{}},\"comment\":{}}],[\"sendstateresponse\",{\"_index\":85,\"name\":{\"123\":{}},\"comment\":{}}],[\"sendtimestampreply\",{\"_index\":91,\"name\":{\"149\":{}},\"comment\":{}}],[\"sendtimesyncquery\",{\"_index\":115,\"name\":{\"214\":{}},\"comment\":{}}],[\"sendtimesyncrequest\",{\"_index\":112,\"name\":{\"211\":{}},\"comment\":{}}],[\"server\",{\"_index\":61,\"name\":{\"67\":{},\"84\":{},\"127\":{},\"153\":{},\"190\":{},\"221\":{},\"249\":{}},\"comment\":{}}],[\"serverinfo\",{\"_index\":62,\"name\":{\"68\":{},\"85\":{},\"128\":{},\"154\":{},\"191\":{},\"222\":{},\"250\":{}},\"comment\":{}}],[\"service\",{\"_index\":24,\"name\":{\"24\":{},\"78\":{},\"103\":{},\"164\":{},\"717\":{}},\"comment\":{}}],[\"servicemessage\",{\"_index\":431,\"name\":{\"603\":{}},\"comment\":{}}],[\"services\",{\"_index\":440,\"name\":{\"618\":{},\"620\":{},\"715\":{}},\"comment\":{}}],[\"sessionid\",{\"_index\":120,\"name\":{\"236\":{}},\"comment\":{}}],[\"set\",{\"_index\":449,\"name\":{\"637\":{},\"664\":{},\"688\":{}},\"comment\":{}}],[\"setsource\",{\"_index\":508,\"name\":{\"739\":{}},\"comment\":{}}],[\"signalmessagecomplete\",{\"_index\":58,\"name\":{\"63\":{}},\"comment\":{}}],[\"signaltransfercomplete\",{\"_index\":57,\"name\":{\"62\":{}},\"comment\":{}}],[\"size\",{\"_index\":26,\"name\":{\"27\":{}},\"comment\":{}}],[\"sizeleft\",{\"_index\":31,\"name\":{\"32\":{},\"634\":{},\"661\":{},\"672\":{}},\"comment\":{}}],[\"sleep\",{\"_index\":481,\"name\":{\"692\":{}},\"comment\":{}}],[\"socket\",{\"_index\":3,\"name\":{\"3\":{},\"69\":{},\"86\":{},\"129\":{},\"155\":{},\"192\":{},\"223\":{},\"251\":{}},\"comment\":{}}],[\"software\",{\"_index\":424,\"name\":{\"582\":{},\"598\":{}},\"comment\":{}}],[\"songanalyzed\",{\"_index\":138,\"name\":{\"282\":{}},\"comment\":{}}],[\"songloaded\",{\"_index\":139,\"name\":{\"283\":{}},\"comment\":{}}],[\"songname\",{\"_index\":140,\"name\":{\"284\":{}},\"comment\":{}}],[\"soundswitchguid\",{\"_index\":141,\"name\":{\"285\":{}},\"comment\":{}}],[\"source\",{\"_index\":132,\"name\":{\"274\":{},\"292\":{},\"580\":{},\"596\":{},\"611\":{},\"744\":{}},\"comment\":{}}],[\"sources\",{\"_index\":28,\"name\":{\"29\":{},\"264\":{},\"732\":{},\"734\":{}},\"comment\":{}}],[\"stagelinq\",{\"_index\":123,\"name\":{\"259\":{}},\"comment\":{}}],[\"stagelinqoptions\",{\"_index\":436,\"name\":{\"614\":{}},\"comment\":{}}],[\"start\",{\"_index\":65,\"name\":{\"72\":{},\"91\":{},\"132\":{},\"157\":{},\"194\":{},\"225\":{},\"253\":{}},\"comment\":{}}],[\"startbeatinfo\",{\"_index\":103,\"name\":{\"184\":{}},\"comment\":{}}],[\"startserver\",{\"_index\":72,\"name\":{\"90\":{}},\"comment\":{}}],[\"startservicelistener\",{\"_index\":127,\"name\":{\"267\":{}},\"comment\":{}}],[\"state\",{\"_index\":81,\"name\":{\"111\":{}},\"comment\":{}}],[\"statedata\",{\"_index\":75,\"name\":{\"102\":{}},\"comment\":{}}],[\"statemap\",{\"_index\":83,\"name\":{\"113\":{},\"621\":{}},\"comment\":{}}],[\"statenames\",{\"_index\":193,\"name\":{\"346\":{}},\"comment\":{}}],[\"status\",{\"_index\":126,\"name\":{\"265\":{}},\"comment\":{}}],[\"stop\",{\"_index\":66,\"name\":{\"73\":{},\"92\":{},\"133\":{},\"158\":{},\"195\":{},\"226\":{},\"254\":{}},\"comment\":{}}],[\"streamingflags\",{\"_index\":190,\"name\":{\"343\":{}},\"comment\":{}}],[\"streamingsource\",{\"_index\":180,\"name\":{\"332\":{}},\"comment\":{}}],[\"string\",{\"_index\":79,\"name\":{\"109\":{},\"697\":{}},\"comment\":{}}],[\"submessagetest\",{\"_index\":73,\"name\":{\"93\":{}},\"comment\":{}}],[\"subscribe\",{\"_index\":84,\"name\":{\"120\":{}},\"comment\":{}}],[\"subscribestate\",{\"_index\":86,\"name\":{\"124\":{}},\"comment\":{}}],[\"tell\",{\"_index\":447,\"name\":{\"635\":{},\"662\":{},\"686\":{}},\"comment\":{}}],[\"thirdpartysourceid\",{\"_index\":189,\"name\":{\"342\":{}},\"comment\":{}}],[\"timealive\",{\"_index\":89,\"name\":{\"145\":{}},\"comment\":{}}],[\"timeavg\",{\"_index\":116,\"name\":{\"216\":{}},\"comment\":{}}],[\"timelastplayed\",{\"_index\":169,\"name\":{\"320\":{}},\"comment\":{}}],[\"timeout\",{\"_index\":64,\"name\":{\"71\":{},\"88\":{},\"131\":{},\"156\":{},\"193\":{},\"224\":{},\"252\":{}},\"comment\":{}}],[\"timestamp\",{\"_index\":107,\"name\":{\"202\":{}},\"comment\":{}}],[\"timesyncdata\",{\"_index\":105,\"name\":{\"200\":{}},\"comment\":{}}],[\"timesynchronization\",{\"_index\":108,\"name\":{\"203\":{},\"625\":{}},\"comment\":{}}],[\"timesyncmsghelper\",{\"_index\":113,\"name\":{\"212\":{}},\"comment\":{}}],[\"title\",{\"_index\":158,\"name\":{\"309\":{}},\"comment\":{}}],[\"total\",{\"_index\":32,\"name\":{\"33\":{}},\"comment\":{}}],[\"track\",{\"_index\":130,\"name\":{\"271\":{}},\"comment\":{}}],[\"trackbytes\",{\"_index\":142,\"name\":{\"286\":{}},\"comment\":{}}],[\"trackdata\",{\"_index\":185,\"name\":{\"337\":{}},\"comment\":{}}],[\"trackdbentry\",{\"_index\":147,\"name\":{\"297\":{}},\"comment\":{}}],[\"trackid\",{\"_index\":118,\"name\":{\"234\":{}},\"comment\":{}}],[\"tracklength\",{\"_index\":143,\"name\":{\"287\":{}},\"comment\":{}}],[\"trackname\",{\"_index\":144,\"name\":{\"288\":{}},\"comment\":{}}],[\"tracknetworkpath\",{\"_index\":145,\"name\":{\"289\":{}},\"comment\":{}}],[\"trackuri\",{\"_index\":146,\"name\":{\"290\":{}},\"comment\":{}}],[\"txid\",{\"_index\":25,\"name\":{\"26\":{},\"38\":{}},\"comment\":{}}],[\"type\",{\"_index\":78,\"name\":{\"108\":{},\"592\":{}},\"comment\":{}}],[\"unannounce\",{\"_index\":16,\"name\":{\"16\":{}},\"comment\":{}}],[\"unit\",{\"_index\":428,\"name\":{\"589\":{}},\"comment\":{}}],[\"units\",{\"_index\":421,\"name\":{\"577\":{}},\"comment\":{}}],[\"updatedeviceinfo\",{\"_index\":489,\"name\":{\"707\":{}},\"comment\":{}}],[\"updatesources\",{\"_index\":46,\"name\":{\"50\":{}},\"comment\":{}}],[\"uri\",{\"_index\":181,\"name\":{\"333\":{}},\"comment\":{}}],[\"userbeatcallback\",{\"_index\":98,\"name\":{\"177\":{}},\"comment\":{}}],[\"userbeatoptions\",{\"_index\":99,\"name\":{\"178\":{}},\"comment\":{}}],[\"value\",{\"_index\":80,\"name\":{\"110\":{}},\"comment\":{}}],[\"version\",{\"_index\":425,\"name\":{\"585\":{},\"601\":{},\"610\":{}},\"comment\":{}}],[\"waitforfilemessage\",{\"_index\":51,\"name\":{\"56\":{}},\"comment\":{}}],[\"waitformessage\",{\"_index\":67,\"name\":{\"74\":{},\"95\":{},\"134\":{},\"159\":{},\"196\":{},\"227\":{},\"255\":{}},\"comment\":{}}],[\"write\",{\"_index\":68,\"name\":{\"75\":{},\"96\":{},\"135\":{},\"160\":{},\"197\":{},\"228\":{},\"256\":{},\"675\":{}},\"comment\":{}}],[\"writecontext\",{\"_index\":469,\"name\":{\"668\":{}},\"comment\":{}}],[\"writediscoverymessage\",{\"_index\":21,\"name\":{\"21\":{}},\"comment\":{}}],[\"writefixedsizedstring\",{\"_index\":474,\"name\":{\"676\":{}},\"comment\":{}}],[\"writeint32\",{\"_index\":478,\"name\":{\"680\":{}},\"comment\":{}}],[\"writenetworkstringutf16\",{\"_index\":475,\"name\":{\"677\":{}},\"comment\":{}}],[\"writeuint16\",{\"_index\":479,\"name\":{\"681\":{}},\"comment\":{}}],[\"writeuint32\",{\"_index\":477,\"name\":{\"679\":{}},\"comment\":{}}],[\"writeuint64\",{\"_index\":476,\"name\":{\"678\":{}},\"comment\":{}}],[\"writeuint8\",{\"_index\":480,\"name\":{\"682\":{}},\"comment\":{}}],[\"writewithlength\",{\"_index\":69,\"name\":{\"76\":{},\"97\":{},\"136\":{},\"161\":{},\"198\":{},\"229\":{},\"257\":{}},\"comment\":{}}],[\"year\",{\"_index\":152,\"name\":{\"302\":{}},\"comment\":{}}],[\"zinflate\",{\"_index\":501,\"name\":{\"728\":{}},\"comment\":{}}]],\"pipeline\":[]}}"); \ No newline at end of file diff --git a/docs/assets/style.css b/docs/assets/style.css new file mode 100644 index 0000000..496e66f --- /dev/null +++ b/docs/assets/style.css @@ -0,0 +1,1279 @@ +:root { + /* Light */ + --light-color-background: #f2f4f8; + --light-color-background-secondary: #eff0f1; + --light-color-warning-text: #222; + --light-color-background-warning: #e6e600; + --light-color-icon-background: var(--light-color-background); + --light-color-accent: #c5c7c9; + --light-color-text: #222; + --light-color-text-aside: #707070; + --light-color-link: #4da6ff; + --light-color-ts: #db1373; + --light-color-ts-interface: #139d2c; + --light-color-ts-enum: #9c891a; + --light-color-ts-class: #2484e5; + --light-color-ts-function: #572be7; + --light-color-ts-namespace: #b111c9; + --light-color-ts-private: #707070; + --light-color-ts-variable: #4d68ff; + --light-external-icon: url("data:image/svg+xml;utf8,"); + --light-color-scheme: light; + + /* Dark */ + --dark-color-background: #2b2e33; + --dark-color-background-secondary: #1e2024; + --dark-color-background-warning: #bebe00; + --dark-color-warning-text: #222; + --dark-color-icon-background: var(--dark-color-background-secondary); + --dark-color-accent: #9096a2; + --dark-color-text: #f5f5f5; + --dark-color-text-aside: #dddddd; + --dark-color-link: #00aff4; + --dark-color-ts: #ff6492; + --dark-color-ts-interface: #6cff87; + --dark-color-ts-enum: #f4d93e; + --dark-color-ts-class: #61b0ff; + --dark-color-ts-function: #9772ff; + --dark-color-ts-namespace: #e14dff; + --dark-color-ts-private: #e2e2e2; + --dark-color-ts-variable: #4d68ff; + --dark-external-icon: url("data:image/svg+xml;utf8,"); + --dark-color-scheme: dark; +} + +@media (prefers-color-scheme: light) { + :root { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + --color-ts: var(--light-color-ts); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-class: var(--light-color-ts-class); + --color-ts-function: var(--light-color-ts-function); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-private: var(--light-color-ts-private); + --color-ts-variable: var(--light-color-ts-variable); + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + --color-ts: var(--dark-color-ts); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-private: var(--dark-color-ts-private); + --color-ts-variable: var(--dark-color-ts-variable); + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } +} + +html { + color-scheme: var(--color-scheme); +} + +body { + margin: 0; +} + +:root[data-theme="light"] { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + --color-ts: var(--light-color-ts); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-class: var(--light-color-ts-class); + --color-ts-function: var(--light-color-ts-function); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-private: var(--light-color-ts-private); + --color-ts-variable: var(--light-color-ts-variable); + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); +} + +:root[data-theme="dark"] { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + --color-ts: var(--dark-color-ts); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-private: var(--dark-color-ts-private); + --color-ts-variable: var(--dark-color-ts-variable); + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); +} + +.always-visible, +.always-visible .tsd-signatures { + display: inherit !important; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 1.2; +} + +h1 { + font-size: 1.875rem; + margin: 0.67rem 0; +} + +h2 { + font-size: 1.5rem; + margin: 0.83rem 0; +} + +h3 { + font-size: 1.25rem; + margin: 1rem 0; +} + +h4 { + font-size: 1.05rem; + margin: 1.33rem 0; +} + +h5 { + font-size: 1rem; + margin: 1.5rem 0; +} + +h6 { + font-size: 0.875rem; + margin: 2.33rem 0; +} + +.uppercase { + text-transform: uppercase; +} + +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +dl, +menu, +ol, +ul { + margin: 1em 0; +} + +dd { + margin: 0 0 0 40px; +} + +.container { + max-width: 1600px; + padding: 0 2rem; +} + +@media (min-width: 640px) { + .container { + padding: 0 4rem; + } +} +@media (min-width: 1200px) { + .container { + padding: 0 8rem; + } +} +@media (min-width: 1600px) { + .container { + padding: 0 12rem; + } +} + +/* Footer */ +.tsd-generator { + border-top: 1px solid var(--color-accent); + padding-top: 1rem; + padding-bottom: 1rem; + max-height: 3.5rem; +} + +.tsd-generator > p { + margin-top: 0; + margin-bottom: 0; + padding: 0 1rem; +} + +.container-main { + display: flex; + justify-content: space-between; + position: relative; + margin: 0 auto; +} + +.col-4, +.col-8 { + box-sizing: border-box; + float: left; + padding: 2rem 1rem; +} + +.col-4 { + flex: 0 0 25%; +} +.col-8 { + flex: 1 0; + flex-wrap: wrap; + padding-left: 0; +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +@keyframes fade-out { + from { + opacity: 1; + visibility: visible; + } + to { + opacity: 0; + } +} +@keyframes fade-in-delayed { + 0% { + opacity: 0; + } + 33% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +@keyframes fade-out-delayed { + 0% { + opacity: 1; + visibility: visible; + } + 66% { + opacity: 0; + } + 100% { + opacity: 0; + } +} +@keyframes shift-to-left { + from { + transform: translate(0, 0); + } + to { + transform: translate(-25%, 0); + } +} +@keyframes unshift-to-left { + from { + transform: translate(-25%, 0); + } + to { + transform: translate(0, 0); + } +} +@keyframes pop-in-from-right { + from { + transform: translate(100%, 0); + } + to { + transform: translate(0, 0); + } +} +@keyframes pop-out-to-right { + from { + transform: translate(0, 0); + visibility: visible; + } + to { + transform: translate(100%, 0); + } +} +body { + background: var(--color-background); + font-family: "Segoe UI", sans-serif; + font-size: 16px; + color: var(--color-text); +} + +a { + color: var(--color-link); + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +a.external[target="_blank"] { + background-image: var(--external-icon); + background-position: top 3px right; + background-repeat: no-repeat; + padding-right: 13px; +} + +code, +pre { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 0.2em; + margin: 0; + font-size: 0.875rem; + border-radius: 0.8em; +} + +pre { + padding: 10px; + border: 0.1em solid var(--color-accent); +} +pre code { + padding: 0; + font-size: 100%; +} + +blockquote { + margin: 1em 0; + padding-left: 1em; + border-left: 4px solid gray; +} + +.tsd-typography { + line-height: 1.333em; +} +.tsd-typography ul { + list-style: square; + padding: 0 0 0 20px; + margin: 0; +} +.tsd-typography h4, +.tsd-typography .tsd-index-panel h3, +.tsd-index-panel .tsd-typography h3, +.tsd-typography h5, +.tsd-typography h6 { + font-size: 1em; + margin: 0; +} +.tsd-typography h5, +.tsd-typography h6 { + font-weight: normal; +} +.tsd-typography p, +.tsd-typography ul, +.tsd-typography ol { + margin: 1em 0; +} + +@media (max-width: 1024px) { + html .col-content { + float: none; + max-width: 100%; + width: 100%; + padding-top: 3rem; + } + html .col-menu { + position: fixed !important; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + z-index: 1024; + top: 0 !important; + bottom: 0 !important; + left: auto !important; + right: 0 !important; + padding: 1.5rem 1.5rem 0 0; + max-width: 25rem; + visibility: hidden; + background-color: var(--color-background); + transform: translate(100%, 0); + } + html .col-menu > *:last-child { + padding-bottom: 20px; + } + html .overlay { + content: ""; + display: block; + position: fixed; + z-index: 1023; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + visibility: hidden; + } + + .to-has-menu .overlay { + animation: fade-in 0.4s; + } + + .to-has-menu :is(header, footer, .col-content) { + animation: shift-to-left 0.4s; + } + + .to-has-menu .col-menu { + animation: pop-in-from-right 0.4s; + } + + .from-has-menu .overlay { + animation: fade-out 0.4s; + } + + .from-has-menu :is(header, footer, .col-content) { + animation: unshift-to-left 0.4s; + } + + .from-has-menu .col-menu { + animation: pop-out-to-right 0.4s; + } + + .has-menu body { + overflow: hidden; + } + .has-menu .overlay { + visibility: visible; + } + .has-menu :is(header, footer, .col-content) { + transform: translate(-25%, 0); + } + .has-menu .col-menu { + visibility: visible; + transform: translate(0, 0); + display: flex; + flex-direction: column; + gap: 1.5rem; + max-height: 100vh; + padding: 1rem 2rem; + } + .has-menu .tsd-navigation { + max-height: 100%; + } +} + +.tsd-breadcrumb { + margin: 0; + padding: 0; + color: var(--color-text-aside); +} +.tsd-breadcrumb a { + color: var(--color-text-aside); + text-decoration: none; +} +.tsd-breadcrumb a:hover { + text-decoration: underline; +} +.tsd-breadcrumb li { + display: inline; +} +.tsd-breadcrumb li:after { + content: " / "; +} + +.tsd-comment-tags { + display: flex; + flex-direction: column; +} +dl.tsd-comment-tag-group { + display: flex; + align-items: center; + overflow: hidden; + margin: 0.5em 0; +} +dl.tsd-comment-tag-group dt { + display: flex; + margin-right: 0.5em; + font-size: 0.875em; + font-weight: normal; +} +dl.tsd-comment-tag-group dd { + margin: 0; +} +code.tsd-tag { + padding: 0.25em 0.4em; + border: 0.1em solid var(--color-accent); + margin-right: 0.25em; + font-size: 70%; +} +h1 code.tsd-tag:first-of-type { + margin-left: 0.25em; +} + +dl.tsd-comment-tag-group dd:before, +dl.tsd-comment-tag-group dd:after { + content: " "; +} +dl.tsd-comment-tag-group dd pre, +dl.tsd-comment-tag-group dd:after { + clear: both; +} +dl.tsd-comment-tag-group p { + margin: 0; +} + +.tsd-panel.tsd-comment .lead { + font-size: 1.1em; + line-height: 1.333em; + margin-bottom: 2em; +} +.tsd-panel.tsd-comment .lead:last-child { + margin-bottom: 0; +} + +.tsd-filter-visibility h4 { + font-size: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.5rem; + margin: 0; +} +.tsd-filter-item:not(:last-child) { + margin-bottom: 0.5rem; +} +.tsd-filter-input { + display: flex; + width: fit-content; + width: -moz-fit-content; + align-items: center; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + cursor: pointer; +} +.tsd-filter-input input[type="checkbox"] { + cursor: pointer; + position: absolute; + width: 1.5em; + height: 1.5em; + opacity: 0; +} +.tsd-filter-input input[type="checkbox"]:disabled { + pointer-events: none; +} +.tsd-filter-input svg { + cursor: pointer; + width: 1.5em; + height: 1.5em; + margin-right: 0.5em; + border-radius: 0.33em; + /* Leaving this at full opacity breaks event listeners on Firefox. + Don't remove unless you know what you're doing. */ + opacity: 0.99; +} +.tsd-filter-input input[type="checkbox"]:focus + svg { + transform: scale(0.95); +} +.tsd-filter-input input[type="checkbox"]:focus:not(:focus-visible) + svg { + transform: scale(1); +} +.tsd-checkbox-background { + fill: var(--color-accent); +} +input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { + stroke: var(--color-text); +} +.tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { + fill: var(--color-background); + stroke: var(--color-accent); + stroke-width: 0.25rem; +} +.tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { + stroke: var(--color-accent); +} + +.tsd-theme-toggle { + padding-top: 0.75rem; +} +.tsd-theme-toggle > h4 { + display: inline; + vertical-align: middle; + margin-right: 0.75rem; +} + +.tsd-hierarchy { + list-style: square; + margin: 0; +} +.tsd-hierarchy .target { + font-weight: bold; +} + +.tsd-panel-group.tsd-index-group { + margin-bottom: 0; +} +.tsd-index-panel .tsd-index-list { + list-style: none; + line-height: 1.333em; + margin: 0; + padding: 0.25rem 0 0 0; + overflow: hidden; + display: grid; + grid-template-columns: repeat(3, 1fr); + column-gap: 1rem; + grid-template-rows: auto; +} +@media (max-width: 1024px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(2, 1fr); + } +} +@media (max-width: 768px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(1, 1fr); + } +} +.tsd-index-panel .tsd-index-list li { + -webkit-page-break-inside: avoid; + -moz-page-break-inside: avoid; + -ms-page-break-inside: avoid; + -o-page-break-inside: avoid; + page-break-inside: avoid; +} +.tsd-index-panel a, +.tsd-index-panel a.tsd-parent-kind-module { + color: var(--color-ts); +} +.tsd-index-panel a.tsd-parent-kind-interface { + color: var(--color-ts-interface); +} +.tsd-index-panel a.tsd-parent-kind-enum { + color: var(--color-ts-enum); +} +.tsd-index-panel a.tsd-parent-kind-class { + color: var(--color-ts-class); +} +.tsd-index-panel a.tsd-kind-module { + color: var(--color-ts-namespace); +} +.tsd-index-panel a.tsd-kind-interface { + color: var(--color-ts-interface); +} +.tsd-index-panel a.tsd-kind-enum { + color: var(--color-ts-enum); +} +.tsd-index-panel a.tsd-kind-class { + color: var(--color-ts-class); +} +.tsd-index-panel a.tsd-kind-function { + color: var(--color-ts-function); +} +.tsd-index-panel a.tsd-kind-namespace { + color: var(--color-ts-namespace); +} +.tsd-index-panel a.tsd-kind-variable { + color: var(--color-ts-variable); +} +.tsd-index-panel a.tsd-is-private { + color: var(--color-ts-private); +} + +.tsd-flag { + display: inline-block; + padding: 0.25em 0.4em; + border-radius: 4px; + color: var(--color-comment-tag-text); + background-color: var(--color-comment-tag); + text-indent: 0; + font-size: 75%; + line-height: 1; + font-weight: normal; +} + +.tsd-anchor { + position: absolute; + top: -100px; +} + +.tsd-member { + position: relative; +} +.tsd-member .tsd-anchor + h3 { + display: flex; + align-items: center; + margin-top: 0; + margin-bottom: 0; + border-bottom: none; +} +.tsd-member [data-tsd-kind] { + color: var(--color-ts); +} +.tsd-member [data-tsd-kind="Interface"] { + color: var(--color-ts-interface); +} +.tsd-member [data-tsd-kind="Enum"] { + color: var(--color-ts-enum); +} +.tsd-member [data-tsd-kind="Class"] { + color: var(--color-ts-class); +} +.tsd-member [data-tsd-kind="Private"] { + color: var(--color-ts-private); +} + +.tsd-navigation a { + display: block; + margin: 0.4rem 0; + border-left: 2px solid transparent; + color: var(--color-text); + text-decoration: none; + transition: border-left-color 0.1s; +} +.tsd-navigation a:hover { + text-decoration: underline; +} +.tsd-navigation ul { + margin: 0; + padding: 0; + list-style: none; +} +.tsd-navigation li { + padding: 0; +} + +.tsd-navigation.primary .tsd-accordion-details > ul { + margin-top: 0.75rem; +} +.tsd-navigation.primary a { + padding: 0.75rem 0.5rem; + margin: 0; +} +.tsd-navigation.primary ul li a { + margin-left: 0.5rem; +} +.tsd-navigation.primary ul li li a { + margin-left: 1.5rem; +} +.tsd-navigation.primary ul li li li a { + margin-left: 2.5rem; +} +.tsd-navigation.primary ul li li li li a { + margin-left: 3.5rem; +} +.tsd-navigation.primary ul li li li li li a { + margin-left: 4.5rem; +} +.tsd-navigation.primary ul li li li li li li a { + margin-left: 5.5rem; +} +.tsd-navigation.primary li.current > a { + border-left: 0.15rem var(--color-text) solid; +} +.tsd-navigation.primary li.selected > a { + font-weight: bold; + border-left: 0.2rem var(--color-text) solid; +} +.tsd-navigation.primary ul li a:hover { + border-left: 0.2rem var(--color-text-aside) solid; +} +.tsd-navigation.primary li.globals + li > span, +.tsd-navigation.primary li.globals + li > a { + padding-top: 20px; +} + +.tsd-navigation.secondary.tsd-navigation--toolbar-hide { + max-height: calc(100vh - 1rem); + top: 0.5rem; +} +.tsd-navigation.secondary > ul { + display: inline; + padding-right: 0.5rem; + transition: opacity 0.2s; +} +.tsd-navigation.secondary ul li a { + padding-left: 0; +} +.tsd-navigation.secondary ul li li a { + padding-left: 1.1rem; +} +.tsd-navigation.secondary ul li li li a { + padding-left: 2.2rem; +} +.tsd-navigation.secondary ul li li li li a { + padding-left: 3.3rem; +} +.tsd-navigation.secondary ul li li li li li a { + padding-left: 4.4rem; +} +.tsd-navigation.secondary ul li li li li li li a { + padding-left: 5.5rem; +} + +#tsd-sidebar-links a { + margin-top: 0; + margin-bottom: 0.5rem; + line-height: 1.25rem; +} +#tsd-sidebar-links a:last-of-type { + margin-bottom: 0; +} + +a.tsd-index-link { + margin: 0.25rem 0; + font-size: 1rem; + line-height: 1.25rem; + display: inline-flex; + align-items: center; +} +.tsd-accordion-summary > h1, +.tsd-accordion-summary > h2, +.tsd-accordion-summary > h3, +.tsd-accordion-summary > h4, +.tsd-accordion-summary > h5 { + display: inline-flex; + align-items: center; + vertical-align: middle; + margin-bottom: 0; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} +.tsd-accordion-summary { + display: block; + cursor: pointer; +} +.tsd-accordion-summary > * { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} +.tsd-accordion-summary::-webkit-details-marker { + display: none; +} +.tsd-index-accordion .tsd-accordion-summary svg { + margin-right: 0.25rem; +} +.tsd-index-content > :not(:first-child) { + margin-top: 0.75rem; +} +.tsd-index-heading { + margin-top: 1.5rem; + margin-bottom: 0.75rem; +} + +.tsd-kind-icon { + margin-right: 0.5rem; + width: 1.25rem; + height: 1.25rem; + min-width: 1.25rem; + min-height: 1.25rem; +} +.tsd-kind-icon path { + transform-origin: center; + transform: scale(1.1); +} +.tsd-signature > .tsd-kind-icon { + margin-right: 0.8rem; +} + +@media (min-width: 1025px) { + .col-content { + margin: 2rem auto; + } + + .menu-sticky-wrap { + position: sticky; + height: calc(100vh - 2rem); + top: 4rem; + right: 0; + padding: 0 1.5rem; + padding-top: 1rem; + margin-top: 3rem; + transition: 0.3s ease-in-out; + transition-property: top, padding-top, padding, height; + overflow-y: auto; + } + .col-menu { + border-left: 1px solid var(--color-accent); + } + .col-menu--hide { + top: 1rem; + } + .col-menu .tsd-navigation:not(:last-child) { + padding-bottom: 1.75rem; + } +} + +.tsd-panel { + margin-bottom: 2.5rem; +} +.tsd-panel.tsd-member { + margin-bottom: 4rem; +} +.tsd-panel:empty { + display: none; +} +.tsd-panel > h1, +.tsd-panel > h2, +.tsd-panel > h3 { + margin: 1.5rem -1.5rem 0.75rem -1.5rem; + padding: 0 1.5rem 0.75rem 1.5rem; +} +.tsd-panel > h1.tsd-before-signature, +.tsd-panel > h2.tsd-before-signature, +.tsd-panel > h3.tsd-before-signature { + margin-bottom: 0; + border-bottom: none; +} + +.tsd-panel-group { + margin: 4rem 0; +} +.tsd-panel-group.tsd-index-group { + margin: 2rem 0; +} +.tsd-panel-group.tsd-index-group details { + margin: 2rem 0; +} + +#tsd-search { + transition: background-color 0.2s; +} +#tsd-search .title { + position: relative; + z-index: 2; +} +#tsd-search .field { + position: absolute; + left: 0; + top: 0; + right: 2.5rem; + height: 100%; +} +#tsd-search .field input { + box-sizing: border-box; + position: relative; + top: -50px; + z-index: 1; + width: 100%; + padding: 0 10px; + opacity: 0; + outline: 0; + border: 0; + background: transparent; + color: var(--color-text); +} +#tsd-search .field label { + position: absolute; + overflow: hidden; + right: -40px; +} +#tsd-search .field input, +#tsd-search .title, +#tsd-toolbar-links a { + transition: opacity 0.2s; +} +#tsd-search .results { + position: absolute; + visibility: hidden; + top: 40px; + width: 100%; + margin: 0; + padding: 0; + list-style: none; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); +} +#tsd-search .results li { + padding: 0 10px; + background-color: var(--color-background); +} +#tsd-search .results li:nth-child(even) { + background-color: var(--color-background-secondary); +} +#tsd-search .results li.state { + display: none; +} +#tsd-search .results li.current, +#tsd-search .results li:hover { + background-color: var(--color-accent); +} +#tsd-search .results a { + display: block; +} +#tsd-search .results a:before { + top: 10px; +} +#tsd-search .results span.parent { + color: var(--color-text-aside); + font-weight: normal; +} +#tsd-search.has-focus { + background-color: var(--color-accent); +} +#tsd-search.has-focus .field input { + top: 0; + opacity: 1; +} +#tsd-search.has-focus .title, +#tsd-search.has-focus #tsd-toolbar-links a { + z-index: 0; + opacity: 0; +} +#tsd-search.has-focus .results { + visibility: visible; +} +#tsd-search.loading .results li.state.loading { + display: block; +} +#tsd-search.failure .results li.state.failure { + display: block; +} + +#tsd-toolbar-links { + position: absolute; + top: 0; + right: 2rem; + height: 100%; + display: flex; + align-items: center; + justify-content: flex-end; +} +#tsd-toolbar-links a { + margin-left: 1.5rem; +} +#tsd-toolbar-links a:hover { + text-decoration: underline; +} + +.tsd-signature { + margin: 0 0 1rem 0; + padding: 1rem 0.5rem; + border: 1px solid var(--color-accent); + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 14px; + overflow-x: auto; +} + +.tsd-signature-symbol { + color: var(--color-text-aside); + font-weight: normal; +} + +.tsd-signature-type { + font-style: italic; + font-weight: normal; +} + +.tsd-signatures { + padding: 0; + margin: 0 0 1em 0; + list-style-type: none; +} +.tsd-signatures .tsd-signature { + margin: 0; + border-color: var(--color-accent); + border-width: 1px 0; + transition: background-color 0.1s; +} +.tsd-description .tsd-signatures .tsd-signature { + border-width: 1px; +} + +ul.tsd-parameter-list, +ul.tsd-type-parameter-list { + list-style: square; + margin: 0; + padding-left: 20px; +} +ul.tsd-parameter-list > li.tsd-parameter-signature, +ul.tsd-type-parameter-list > li.tsd-parameter-signature { + list-style: none; + margin-left: -20px; +} +ul.tsd-parameter-list h5, +ul.tsd-type-parameter-list h5 { + font-size: 16px; + margin: 1em 0 0.5em 0; +} +.tsd-sources { + margin-top: 1rem; + font-size: 0.875em; +} +.tsd-sources a { + color: var(--color-text-aside); + text-decoration: underline; +} +.tsd-sources ul { + list-style: none; + padding: 0; +} + +.tsd-page-toolbar { + position: fixed; + z-index: 1; + top: 0; + left: 0; + width: 100%; + color: var(--color-text); + background: var(--color-background-secondary); + border-bottom: 1px var(--color-accent) solid; + transition: transform 0.3s ease-in-out; +} +.tsd-page-toolbar a { + color: var(--color-text); + text-decoration: none; +} +.tsd-page-toolbar a.title { + font-weight: bold; +} +.tsd-page-toolbar a.title:hover { + text-decoration: underline; +} +.tsd-page-toolbar .tsd-toolbar-contents { + display: flex; + justify-content: space-between; + height: 2.5rem; + margin: 0 auto; +} +.tsd-page-toolbar .table-cell { + position: relative; + white-space: nowrap; + line-height: 40px; +} +.tsd-page-toolbar .table-cell:first-child { + width: 100%; +} +.tsd-page-toolbar .tsd-toolbar-icon { + box-sizing: border-box; + line-height: 0; + padding: 12px 0; +} + +.tsd-page-toolbar--hide { + transform: translateY(-100%); +} + +.tsd-widget { + display: inline-block; + overflow: hidden; + opacity: 0.8; + height: 40px; + transition: opacity 0.1s, background-color 0.2s; + vertical-align: bottom; + cursor: pointer; +} +.tsd-widget:hover { + opacity: 0.9; +} +.tsd-widget.active { + opacity: 1; + background-color: var(--color-accent); +} +.tsd-widget.no-caption { + width: 40px; +} +.tsd-widget.no-caption:before { + margin: 0; +} + +.tsd-widget.options, +.tsd-widget.menu { + display: none; +} +@media (max-width: 1024px) { + .tsd-widget.options, + .tsd-widget.menu { + display: inline-block; + } +} +input[type="checkbox"] + .tsd-widget:before { + background-position: -120px 0; +} +input[type="checkbox"]:checked + .tsd-widget:before { + background-position: -160px 0; +} + +img { + max-width: 100%; +} + +.tsd-anchor-icon { + display: inline-flex; + align-items: center; + margin-left: 0.5rem; + vertical-align: middle; + color: var(--color-text); +} + +.tsd-anchor-icon svg { + width: 1em; + height: 1em; + visibility: hidden; +} + +.tsd-anchor-link:hover > .tsd-anchor-icon svg { + visibility: visible; +} + +.deprecated { + text-decoration: line-through; +} + +.warning { + padding: 1rem; + color: var(--color-warning-text); + background: var(--color-background-warning); +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--color-accent) var(--color-icon-background); +} + +*::-webkit-scrollbar { + width: 0.75rem; +} + +*::-webkit-scrollbar-track { + background: var(--color-icon-background); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--color-accent); + border-radius: 999rem; + border: 0.25rem solid var(--color-icon-background); +} diff --git a/docs/classes/BeatInfo.html b/docs/classes/BeatInfo.html new file mode 100644 index 0000000..3963e39 --- /dev/null +++ b/docs/classes/BeatInfo.html @@ -0,0 +1,1117 @@ +BeatInfo | StageLinqJS
+
+ +
+
+
+
+ +

Class BeatInfo

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
#currentBeatData: BeatData = null
+
+ +
#userBeatCallback: BeatCallback = null
+
+ +
#userBeatOptions: BeatOptions = null
+
+ +
device: Device
+
+ +
deviceId: DeviceId = null
+
+ +
isBufferedService: boolean = true
+
+ +
name: "BeatInfo" = "BeatInfo"
+
+ +
server: Server = null
+
+ +
serverInfo: AddressInfo
+
+ +
socket: Socket = null
+
+ +
timeout: Timer
+
+ +
#instances: Map<string, BeatInfo> = ...
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
emitter: EventEmitter = ...
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+ +
instances: Map<string, Service<unknown>> = ...
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns BeatInfo

+
+ +
    + +
  • +

    Callback for server timeout timer +Runs if device doesn't conect to service server

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: DeviceId
    • +
    • +
      serviceName: string
    • +
    • +
      server: Server
    +

    Returns Promise<void>

+
+ +
+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns BeatInfo

+
+ +
    + +
  • +

    Adds the listener function to the end of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.on('foo', () => console.log('a'));
    myEE.prependListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.1.101

    +
    +
    +

    Parameters

    +
    +

    Returns BeatInfo

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns BeatInfo

+
+ +
+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns BeatInfo

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns BeatInfo

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns BeatInfo

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns BeatInfo

+
+ +
    + +
  • +

    Send Subscribe to BeatInfo message to Device

    +
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns BeatInfo

+
+ +
+
+ +
    + +
  • +

    Start BeatInfo

    +
    +
    +

    Parameters

    +
      +
    • +
      options: BeatOptions
    • +
    • +
      Optional beatCB: BeatCallback
      +

      Optional User callback

      +
    +

    Returns void

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Broadcast.html b/docs/classes/Broadcast.html new file mode 100644 index 0000000..5795052 --- /dev/null +++ b/docs/classes/Broadcast.html @@ -0,0 +1,1019 @@ +Broadcast | StageLinqJS
+
+ +
+
+
+
+ +

Class Broadcast

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
device: Device
+
+ +
deviceId: DeviceId = null
+
+ +
isBufferedService: boolean = false
+
+ +
name: "Broadcast" = "Broadcast"
+
+ +
server: Server = null
+
+ +
serverInfo: AddressInfo
+
+ +
socket: Socket = null
+
+ +
timeout: Timer
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
emitter: EventEmitter = ...
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+ +
instances: Map<string, Service<unknown>> = ...
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Broadcast

+
+ +
    + +
  • +

    Callback for server timeout timer +Runs if device doesn't conect to service server

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: DeviceId
    • +
    • +
      serviceName: string
    • +
    • +
      server: Server
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Broadcast

+
+ +
    + +
  • +

    Adds the listener function to the end of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.on('foo', () => console.log('a'));
    myEE.prependListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.1.101

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Broadcast

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Broadcast

+
+ +
+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Broadcast

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Broadcast

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns Broadcast

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Broadcast

+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns Broadcast

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Context.html b/docs/classes/Context.html new file mode 100644 index 0000000..e679fcc --- /dev/null +++ b/docs/classes/Context.html @@ -0,0 +1,192 @@ +Context | StageLinqJS
+
+ +
+
+
+
+ +

Class Context

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_buffer: ArrayBuffer
    • +
    • +
      Optional p_littleEndian: boolean
    +

    Returns Context

+
+

Properties

+
+ +
buffer: ArrayBuffer
+
+ +
littleEndian: boolean
+
+ +
pos: number
+
+

Methods

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_bytes: number
    +

    Returns void

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_offset: number
    +

    Returns void

+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/DbConnection.html b/docs/classes/DbConnection.html new file mode 100644 index 0000000..294359a --- /dev/null +++ b/docs/classes/DbConnection.html @@ -0,0 +1,203 @@ +DbConnection | StageLinqJS
+
+ +
+
+
+
+ +

Class DbConnection

+
+

Hierarchy

+
    +
  • DbConnection
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
db: Database
+
+ +
dbPath: string
+
+

Methods

+
+ +
+
+ +
+
+ +
    + +
  • +

    Return track's DB entry.

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      _trackPath: string
      +

      Path of track on the source's filesystem.

      +
    +

    Returns Promise<TrackDBEntry>

+
+ +
    + +
  • +

    Execute a SQL query.

    + +

    Returns

    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      query: string
      +

      SQL query to execute

      +
    • +
    • +
      Rest ...params: any[]
      +

      Parameters for BetterSqlite3 result.all.

      +
    +

    Returns T[]

+
+ +
    + +
  • +

    Inflate Zlib compressed data

    + +

    Returns

    Zlib inflated data

    +
    +
    +

    Parameters

    +
      +
    • +
      data: Buffer
    +

    Returns Promise<Buffer>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Device.html b/docs/classes/Device.html new file mode 100644 index 0000000..a24e54b --- /dev/null +++ b/docs/classes/Device.html @@ -0,0 +1,216 @@ +Device | StageLinqJS
+
+ +
+
+
+
+ +

Class Device

+
+

Hierarchy

+
    +
  • Device
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
#services: Map<string, Service<unknown>> = ...
+
+ +
deviceId: DeviceId
+
+ +
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Get # of decks on this device

    + +

    Returns

    +

    Returns number

+
+ +
    + +
  • +

    Remove a service

    +
    +
    +

    Parameters

    +
      +
    • +
      serviceName: string
    +

    Returns void

+
+ +
    + +
  • +

    Get an Array of names of all current Services on this Device

    + +

    Returns

    +

    Returns string[]

+
+ +
+
+ +
    + +
  • +

    Check if Device has Service

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      serviceName: string
    +

    Returns boolean

+
+ +
    + +
  • +

    Get a service instance by name

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      serviceName: string
    +

    Returns Service<unknown>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/DeviceId.html b/docs/classes/DeviceId.html new file mode 100644 index 0000000..4b03193 --- /dev/null +++ b/docs/classes/DeviceId.html @@ -0,0 +1,128 @@ +DeviceId | StageLinqJS
+
+ +
+
+
+
+ +

Class DeviceId

+
+

Hierarchy

+
    +
  • DeviceId
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Accessors

+
+
+

Constructors

+
+ +
    + +
  • +

    DeviceId

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: string | Uint8Array
      +

      string or Uint8Array to initialize new DeviceId

      +
    +

    Returns DeviceId

+
+

Properties

+
+ +
m_array: Uint8Array
+
+ +
m_str: string
+
+

Accessors

+
+ +
    +
  • get array(): Uint8Array
  • +
  • +

    Return DeviceId as Uint8Array

    +
    +

    Returns Uint8Array

+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Devices.html b/docs/classes/Devices.html new file mode 100644 index 0000000..b1f1e87 --- /dev/null +++ b/docs/classes/Devices.html @@ -0,0 +1,916 @@ +Devices | StageLinqJS
+
+ +
+
+
+
+ +

Class Devices

+
+

Hierarchy

+
    +
  • EventEmitter +
      +
    • Devices
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      Optional options: EventEmitterOptions
    +

    Returns Devices

+
+

Properties

+
+ +
#devices: Map<string, Device> = ...
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Devices

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
+
+ +
    + +
  • +

    Get an array of all current Service Instances

    + +

    Returns

    +

    Returns Promise<Service<unknown>[]>

+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Devices

+
+ +
+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Devices

+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Devices

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Devices

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns Devices

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Devices

+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns Devices

+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Directory.html b/docs/classes/Directory.html new file mode 100644 index 0000000..e820eaa --- /dev/null +++ b/docs/classes/Directory.html @@ -0,0 +1,1047 @@ +Directory | StageLinqJS
+
+ +
+
+
+
+ +

Class Directory

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
device: Device
+
+ +
deviceId: DeviceId = null
+
+ +
isBufferedService: false = false
+
+ +
name: "Directory" = 'Directory'
+
+ +
server: Server = null
+
+ +
serverInfo: AddressInfo
+
+ +
socket: Socket = null
+
+ +
timeAlive: number
+
+ +
timeout: Timer
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+ +
instances: Map<string, Service<unknown>> = ...
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Directory

+
+ +
    + +
  • +

    Callback for server timeout timer +Runs if device doesn't conect to service server

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: DeviceId
    • +
    • +
      serviceName: string
    • +
    • +
      server: Server
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Directory

+
+ +
    + +
  • +

    Adds the listener function to the end of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.on('foo', () => console.log('a'));
    myEE.prependListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.1.101

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Directory

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Directory

+
+ +
+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Directory

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Directory

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns Directory

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Directory

+
+ +
    + +
  • +

    Send Service announcement with list of Service:Port

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: DeviceId
    • +
    • +
      socket: Socket
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Send TimeStamp reply to Device

    +
    +
    +

    Parameters

    +
      +
    • +
      token: Uint8Array
      +

      Token from recepient Device

      +
    • +
    • +
      socket: Socket
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns Directory

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Discovery.html b/docs/classes/Discovery.html new file mode 100644 index 0000000..c36f1c7 --- /dev/null +++ b/docs/classes/Discovery.html @@ -0,0 +1,1057 @@ +Discovery | StageLinqJS
+
+ +
+
+
+
+ +

Class Discovery

+
+

Hierarchy

+
    +
  • EventEmitter +
      +
    • Discovery
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
address: string
+
+ +
announceTimer: Timer
+
+ +
broadcastAddress: string
+
+ +
deviceId: DeviceId = null
+
+ +
hasLooped: boolean = false
+
+ +
options: DiscoveryMessageOptions = null
+
+ +
peers: Map<string, ConnectionInfo> = ...
+
+ +
socket: Socket
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Discovery

+
+ +
    + +
  • +

    Announce library to network

    +
    +
    +

    Parameters

    +
      +
    • +
      port: number
      +

      Port for Directory Service

      +
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Broadcast Discovery Message

    +
    +
    +

    Parameters

    +
      +
    • +
      socket: Socket
    • +
    • +
      msg: Buffer
    • +
    • +
      port: number
    • +
    • +
      address: string
    +

    Returns Promise<void>

+
+ +
+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
    + +
  • +

    Get list of Broadcast-enabled Network Interfaces

    + +

    Returns

    +

    Returns SubnetInfo[]

+
+ +
+
+ +
    + +
  • +

    Get list of devices

    + +

    Returns

    An array of DeviceId strings

    +
    +

    Returns string[]

+
+ +
+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Listen for new devices on the network and callback when a new one is found.

    +
    +
    +

    Parameters

    +
      +
    • +
      callback: DeviceDiscoveryCallback
      +

      Callback when new device is discovered.

      +
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Discovery

+
+ +
+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Discovery

+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Discovery

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Discovery

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns Discovery

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Discovery

+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns Discovery

+
+ +
    + +
  • +

    Unanounce Library to network

    +
    +

    Returns Promise<void>

+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/FileTransfer.html b/docs/classes/FileTransfer.html new file mode 100644 index 0000000..59ea9a5 --- /dev/null +++ b/docs/classes/FileTransfer.html @@ -0,0 +1,1367 @@ +FileTransfer | StageLinqJS
+
+ +
+
+
+
+ +

Class FileTransfer

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
#isAvailable: boolean = true
+
+ +
device: Device
+
+ +
deviceId: DeviceId = null
+
+ +
isBufferedService: boolean = true
+
+ +
name: string = "FileTransfer"
+
+ +
receivedFile: WriteContext = null
+
+ +
server: Server = null
+
+ +
serverInfo: AddressInfo
+
+ +
socket: Socket = null
+
+ +
timeout: Timer
+
+ +
#txid: number = 2
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
emitter: EventEmitter = ...
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+ +
instances: Map<string, Service<unknown>> = ...
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns FileTransfer

+
+ +
    + +
  • +

    Callback for server timeout timer +Runs if device doesn't conect to service server

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: DeviceId
    • +
    • +
      serviceName: string
    • +
    • +
      server: Server
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
    + +
  • +

    Reads a file on the device and returns a buffer.

    +
    +
    +

    USE WITH CAUTION! <<

    +
    +
    +

    Downloading seems eat a lot of CPU on the device and might cause it to +be unresponsive while downloading big files. Also, it seems that transfers +top out at around 10MB/sec.

    + +

    Returns

    Contents of the file.

    +
    +
    +

    Parameters

    +
      +
    • +
      source: Source
    • +
    • +
      filePath: string
      +

      Location of the file on the device.

      +
    +

    Returns Promise<Uint8Array>

+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Get Sources from Device

    +
    +
    +

    Parameters

    +
      +
    • +
      sources: string[]
      +

      Array of sourceNames

      +
    +

    Returns Promise<void>

+
+ +
+
+ +
    + +
  • +

    Promise will resolve when service is available

    +
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns FileTransfer

+
+ +
    + +
  • +

    Adds the listener function to the end of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.on('foo', () => console.log('a'));
    myEE.prependListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.1.101

    +
    +
    +

    Parameters

    +
      +
    • +
      event: "fileTransferProgress"
      +

      The name of the event.

      +
    • +
    • +
      listener: ((source: Source, fileName: string, txid: number, progress: FileTransferProgress) => void)
      +

      The callback function

      +
      +
    +

    Returns FileTransfer

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      event: "fileTransferComplete"
    • +
    • +
      listener: ((source: Source, fileName: string, txid: number) => void)
      +
        +
      • +
          +
        • (source: Source, fileName: string, txid: number): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            source: Source
          • +
          • +
            fileName: string
          • +
          • +
            txid: number
          +

          Returns void

    +

    Returns FileTransfer

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns FileTransfer

+
+ +
+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns FileTransfer

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns FileTransfer

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns FileTransfer

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns FileTransfer

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      txid: number
      +

      Transfer ID for this session

      +
    • +
    • +
      chunkStartId: number
    • +
    • +
      chunkEndId: number
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Request TxId for file

    +
    +
    +

    Parameters

    +
      +
    • +
      filepath: string
    • +
    • +
      txid: number
    +

    Returns Promise<void>

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      path: string
    • +
    • +
      txid: number
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Promise will resolve when service is available +and will set service as unavailable.

    +
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Request current sources attached to device

    +
    +
    +

    Parameters

    +
      +
    • +
      txid: number
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Request fstat on file from Device

    +
    +
    +

    Parameters

    +
      +
    • +
      filepath: string
    • +
    • +
      txid: number
    +

    Returns Promise<void>

+
+ +
+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns FileTransfer

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      txid: number
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Signal Transfer Completed

    +
    +
    +

    Parameters

    +
      +
    • +
      txid: number
    +

    Returns Promise<void>

+
+ +
+
+ +
+
+ +
    + +
  • +

    Gets new sources and deletes those which have been removed

    +
    +
    +

    Parameters

    +
      +
    • +
      sources: string[]
      +

      an array of current sources from device

      +
    +

    Returns Promise<void>

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/ReadContext.html b/docs/classes/ReadContext.html new file mode 100644 index 0000000..daa9dfb --- /dev/null +++ b/docs/classes/ReadContext.html @@ -0,0 +1,359 @@ +ReadContext | StageLinqJS
+
+ +
+
+
+
+ +

Class ReadContext

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
buffer: ArrayBuffer
+
+ +
littleEndian: boolean
+
+ +
pos: number
+
+

Methods

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_bytes: number
    +

    Returns string

+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_bytes: number
    +

    Returns Buffer

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_bytes: number
    +

    Returns Uint8Array

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Service.html b/docs/classes/Service.html new file mode 100644 index 0000000..b192a2f --- /dev/null +++ b/docs/classes/Service.html @@ -0,0 +1,1065 @@ +Service | StageLinqJS
+
+ +
+
+
+
+ +

Class Service<T>Abstract

+
+

Type Parameters

+
    +
  • +

    T

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
device: Device
+
+ +
deviceId: DeviceId = null
+
+ +
isBufferedService: boolean = true
+
+ +
messageBuffer: Buffer = null
+
+ +
name: string = "Service"
+
+ +
server: Server = null
+
+ +
serverInfo: AddressInfo
+
+ +
socket: Socket = null
+
+ +
timeout: Timer
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+ +
instances: Map<string, Service<unknown>> = ...
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Service<T>

+
+ +
    + +
  • +

    Callback for server timeout timer +Runs if device doesn't conect to service server

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: DeviceId
    • +
    • +
      serviceName: string
    • +
    • +
      server: Server
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Handle incoming Data from Server Socket

    +
    +
    +

    Parameters

    +
      +
    • +
      data: Buffer
    • +
    • +
      socket: Socket
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      eventName: string
    • +
    • +
      Rest ...args: any
    +

    Returns void

+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Service<T>

+
+ +
    + +
  • +

    Adds the listener function to the end of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.on('foo', () => console.log('a'));
    myEE.prependListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.1.101

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Service<T>

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Service<T>

+
+ +
+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Service<T>

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Service<T>

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns Service<T>

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Service<T>

+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns Service<T>

+
+ +
    + +
  • +

    Start Service Listener

    + +

    Returns

    +

    Returns Promise<AddressInfo>

+
+ +
    + +
  • +

    Creates a new Server for Service

    + +

    Returns

    +

    Returns Promise<Server>

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      buff: Buffer
    +

    Returns Promise<boolean>

+
+ +
    + +
  • +

    Wait for a message from the wire

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      eventMessage: string
    • +
    • +
      messageId: number
    +

    Returns Promise<T>

+
+ +
+
+ +
    + +
  • +

    Write a length-prefixed Context message to the socket

    + +

    Returns

    true if data written

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<boolean>

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Source.html b/docs/classes/Source.html new file mode 100644 index 0000000..97ae2e6 --- /dev/null +++ b/docs/classes/Source.html @@ -0,0 +1,166 @@ +Source | StageLinqJS
+
+ +
+
+
+
+ +

Class Source

+
+

Hierarchy

+
    +
  • Source
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
#databases: Map<string, Database> = ...
+
+ +
deviceId: DeviceId
+
+ +
name: string
+
+

Methods

+
+ +
    + +
  • +

    Get a Database by File Name

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      Optional name: string
      +

      Filename eg "m.db"

      +
    +

    Returns Database

+
+ +
    + +
  • +

    Get an array of all Databases

    + +

    Returns

    +

    Returns Database[]

+
+ +
    + +
  • +

    New Database Constructor

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      filename: string
    • +
    • +
      size: number
    • +
    • +
      remotePath: string
    +

    Returns Database

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Sources.html b/docs/classes/Sources.html new file mode 100644 index 0000000..0fed960 --- /dev/null +++ b/docs/classes/Sources.html @@ -0,0 +1,982 @@ +Sources | StageLinqJS
+
+ +
+
+
+
+ +

Class Sources

+
+

Hierarchy

+
    +
  • EventEmitter +
      +
    • Sources
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      Optional options: EventEmitterOptions
    +

    Returns Sources

+
+

Properties

+
+ +
#sources: Map<string, Source> = ...
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Sources

+
+ +
    + +
  • +

    Delete Source

    +
    +
    +

    Parameters

    +
      +
    • +
      sourceName: string
      +

      name of the source

      +
    • +
    • +
      deviceId: DeviceId
    +

    Returns void

+
+ +
+
+ +
    + +
  • +

    Download a file from Source

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      source: Source
    • +
    • +
      path: string
    +

    Returns Promise<Uint8Array>

+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
    + +
  • +

    Get Databases by UUID

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      uuid: string
    +

    Returns Database[]

+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
    + +
  • +

    Get Source

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      sourceName: string
      +

      Name of source in EngineOS, eg: 'DJ STICK (USB 1)'

      +
    • +
    • +
      deviceId: DeviceId
      +

      DeviceID instance

      +
    +

    Returns Source

+
+ +
+
+ +
    + +
  • +

    Check if sources has Source

    + +

    Returns

    true if has source

    +
    +
    +

    Parameters

    +
      +
    • +
      sourceName: string
      +

      Name of source in EngineOS, eg: 'DJ STICK (USB 1)'

      +
    • +
    • +
      deviceId: DeviceId
      +

      DeviceID instance

      +
    +

    Returns boolean

+
+ +
    + +
  • +

    Check if sources has Source AND source has downloaded DB

    + +

    Returns

    true if has Source AND the source has downloaded DB

    +
    +
    +

    Parameters

    +
      +
    • +
      sourceName: string
      +

      Name of source in EngineOS, eg: 'DJ STICK (USB 1)'

      +
    • +
    • +
      deviceId: DeviceId
      +

      DeviceID instance

      +
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Sources

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Sources

+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Sources

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Sources

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns Sources

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns Sources

+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns Sources

+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+

Events

+
+ +
    + +
  • +

    newSource

    +
    +
    +

    Parameters

    +
      +
    • +
      event: "newSource"
    • +
    • +
      listener: ((source: Source) => void)
      +
        +
      • +
          +
        • (source: Source): void
        • +
        • +
          +

          Parameters

          +
          +

          Returns void

    +

    Returns Sources

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      event: "sourceRemoved"
    • +
    • +
      listener: ((sourceName: string, deviceId: DeviceId) => void)
      +
        +
      • +
          +
        • (sourceName: string, deviceId: DeviceId): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            sourceName: string
          • +
          • +
            deviceId: DeviceId
          +

          Returns void

    +

    Returns Sources

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      event: "dbDownloaded"
    • +
    • +
      listener: ((source: Source) => void)
      +
        +
      • +
          +
        • (source: Source): void
        • +
        • +
          +

          Parameters

          +
          +

          Returns void

    +

    Returns Sources

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/StageLinq.html b/docs/classes/StageLinq.html new file mode 100644 index 0000000..a3e68dd --- /dev/null +++ b/docs/classes/StageLinq.html @@ -0,0 +1,192 @@ +StageLinq | StageLinqJS
+
+ +
+
+
+
+ +

Class StageLinq

+
+

Main StageLinq static class.

+
+
+

Hierarchy

+
    +
  • StageLinq
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
devices: Devices = ...
+
+ +
directory: Directory = null
+
+ +
discovery: Discovery = ...
+
+ +
logger: Logger = Logger.instance
+
+ +
options: StageLinqOptions = DEFAULT_OPTIONS
+
+ +
sources: Sources = ...
+
+ +
status: Status = ...
+
+

Methods

+
+ +
    + +
  • +

    Connect to the StageLinq network.

    +
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Disconnect from the StageLinq network. +Close all open Servers

    +
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Service Constructor Factory Function

    + +

    Returns

    +
    +

    Type Parameters

    +
    +
    +

    Parameters

    +
      +
    • +
      ctor: (new (_deviceId?: DeviceId) => T)
      +
        +
      • +
          +
        • new (_deviceId?: DeviceId): T
        • +
        • +
          +

          Parameters

          +
          +

          Returns T

    • +
    • +
      Optional deviceId: DeviceId
    +

    Returns Promise<T>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/StateMap.html b/docs/classes/StateMap.html new file mode 100644 index 0000000..1371ac3 --- /dev/null +++ b/docs/classes/StateMap.html @@ -0,0 +1,1083 @@ +StateMap | StageLinqJS
+
+ +
+
+
+
+ +

Class StateMap

+
+

StateMap Class

+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
device: Device
+
+ +
deviceId: DeviceId = null
+
+ +
isBufferedService: boolean = true
+
+ +
name: "StateMap" = "StateMap"
+
+ +
server: Server = null
+
+ +
serverInfo: AddressInfo
+
+ +
socket: Socket = null
+
+ +
timeout: Timer
+
+ +
#instances: Map<string, StateMap> = ...
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
emitter: EventEmitter = ...
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+ +
instances: Map<string, Service<unknown>> = ...
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns StateMap

+
+ +
    + +
  • +

    Callback for server timeout timer +Runs if device doesn't conect to service server

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: DeviceId
    • +
    • +
      serviceName: string
    • +
    • +
      server: Server
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns StateMap

+
+ +
    + +
  • +

    Adds the listener function to the end of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.on('foo', () => console.log('a'));
    myEE.prependListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.1.101

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns StateMap

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns StateMap

+
+ +
+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns StateMap

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns StateMap

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns StateMap

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns StateMap

+
+ +
    + +
  • +

    Respond to StateMap request with rejection

    +
    +
    +

    Parameters

    +
      +
    • +
      state: string
    • +
    • +
      socket: Socket
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns StateMap

+
+ +
+
+ +
+
+ +
    + +
  • +

    Subscribe to StateMap States

    +
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Send subcribe to state message to device

    +
    +
    +

    Parameters

    +
      +
    • +
      state: string
      +

      Path/Name of the State

      +
    • +
    • +
      interval: number
      +

      TODO clear this up

      +
    • +
    • +
      socket: Socket
    +

    Returns Promise<void>

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/TimeSynchronization.html b/docs/classes/TimeSynchronization.html new file mode 100644 index 0000000..51a5e4c --- /dev/null +++ b/docs/classes/TimeSynchronization.html @@ -0,0 +1,1095 @@ +TimeSynchronization | StageLinqJS
+
+ +
+
+
+
+ +

Class TimeSynchronization

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
avgTimeArray: bigint[] = []
+
+ +
device: Device
+
+ +
deviceId: DeviceId = null
+
+ +
isBufferedService: boolean = false
+
+ +
localTime: bigint
+
+ +
name: "TimeSynchronization" = "TimeSynchronization"
+
+ +
remoteTime: bigint
+
+ +
server: Server = null
+
+ +
serverInfo: AddressInfo
+
+ +
socket: Socket = null
+
+ +
timeout: Timer
+
+ +
captureRejectionSymbol: typeof captureRejectionSymbol
+
+ +
captureRejections: boolean
+

Sets or gets the default captureRejection value for all emitters.

+
+
+ +
defaultMaxListeners: number
+
+ +
errorMonitor: typeof errorMonitor
+

This symbol shall be used to install a listener for only monitoring 'error' +events. Listeners installed using this symbol are called before the regular +'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an +'error' event is emitted, therefore the process will still crash if no +regular 'error' listener is installed.

+
+
+ +
instances: Map<string, Service<unknown>> = ...
+
+

Methods

+
+ +
    + +
  • +

    Alias for emitter.on(eventName, listener).

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns TimeSynchronization

+
+ +
    + +
  • +

    Callback for server timeout timer +Runs if device doesn't conect to service server

    +
    +
    +

    Parameters

    +
      +
    • +
      deviceId: DeviceId
    • +
    • +
      serviceName: string
    • +
    • +
      server: Server
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Synchronously calls each of the listeners registered for the event namedeventName, in the order they were registered, passing the supplied arguments +to each.

    +

    Returns true if the event had listeners, false otherwise.

    +
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();

    // First listener
    myEmitter.on('event', function firstListener() {
    console.log('Helloooo! first listener');
    });
    // Second listener
    myEmitter.on('event', function secondListener(arg1, arg2) {
    console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
    });
    // Third listener
    myEmitter.on('event', function thirdListener(...args) {
    const parameters = args.join(', ');
    console.log(`event with parameters ${parameters} in third listener`);
    });

    console.log(myEmitter.listeners('event'));

    myEmitter.emit('event', 1, 2, 3, 4, 5);

    // Prints:
    // [
    // [Function: firstListener],
    // [Function: secondListener],
    // [Function: thirdListener]
    // ]
    // Helloooo! first listener
    // event with parameters 1, 2 in second listener
    // event with parameters 1, 2, 3, 4, 5 in third listener +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      Rest ...args: any[]
    +

    Returns boolean

+
+ +
    + +
  • +

    Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    const EventEmitter = require('events');
    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Since

    v6.0.0

    +
    +

    Returns (string | symbol)[]

+
+ +
    + +
  • +

    Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    + +

    Since

    v1.0.0

    +
    +

    Returns number

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns the number of listeners listening to the event named eventName.

    + +

    Since

    v3.2.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event being listened for

      +
    +

    Returns number

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
+
+ +
    + +
  • +

    Alias for emitter.removeListener().

    + +

    Since

    v10.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns TimeSynchronization

+
+ +
    + +
  • +

    Adds the listener function to the end of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.on('foo', () => console.log('a'));
    myEE.prependListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.1.101

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns TimeSynchronization

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName. The +next time eventName is triggered, this listener is removed and then invoked.

    +
    server.once('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    By default, event listeners are invoked in the order they are added. Theemitter.prependOnceListener() method can be used as an alternative to add the +event listener to the beginning of the listeners array.

    +
    const myEE = new EventEmitter();
    myEE.once('foo', () => console.log('a'));
    myEE.prependOnceListener('foo', () => console.log('b'));
    myEE.emit('foo');
    // Prints:
    // b
    // a +
    + +

    Since

    v0.3.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns TimeSynchronization

+
+ +
+
+ +
    + +
  • +

    Adds the listener function to the beginning of the listeners array for the +event named eventName. No checks are made to see if the listener has +already been added. Multiple calls passing the same combination of eventNameand listener will result in the listener being added, and called, multiple +times.

    +
    server.prependListener('connection', (stream) => {
    console.log('someone connected!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns TimeSynchronization

+
+ +
    + +
  • +

    Adds a one-timelistener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this +listener is removed, and then invoked.

    +
    server.prependOnceListener('connection', (stream) => {
    console.log('Ah, we have our first user!');
    }); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v6.0.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
      +

      The name of the event.

      +
    • +
    • +
      listener: ((...args: any[]) => void)
      +

      The callback function

      +
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns TimeSynchronization

+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Since

    v9.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional event: string | symbol
    +

    Returns TimeSynchronization

+
+ +
    + +
  • +

    Removes the specified listener from the listener array for the event namedeventName.

    +
    const callback = (stream) => {
    console.log('someone connected!');
    };
    server.on('connection', callback);
    // ...
    server.removeListener('connection', callback); +
    +

    removeListener() will remove, at most, one instance of a listener from the +listener array. If any single listener has been added multiple times to the +listener array for the specified eventName, then removeListener() must be +called multiple times to remove each instance.

    +

    Once an event is emitted, all listeners attached to it at the +time of emitting are called in order. This implies that anyremoveListener() or removeAllListeners() calls after emitting and before the last listener finishes execution +will not remove them fromemit() in progress. Subsequent events behave as expected.

    +
    const myEmitter = new MyEmitter();

    const callbackA = () => {
    console.log('A');
    myEmitter.removeListener('event', callbackB);
    };

    const callbackB = () => {
    console.log('B');
    };

    myEmitter.on('event', callbackA);

    myEmitter.on('event', callbackB);

    // callbackA removes listener callbackB but it will still be called.
    // Internal listener array at time of emit [callbackA, callbackB]
    myEmitter.emit('event');
    // Prints:
    // A
    // B

    // callbackB is now removed.
    // Internal listener array [callbackA]
    myEmitter.emit('event');
    // Prints:
    // A +
    +

    Because listeners are managed using an internal array, calling this will +change the position indices of any listener registered after the listener +being removed. This will not impact the order in which listeners are called, +but it means that any copies of the listener array as returned by +the emitter.listeners() method will need to be recreated.

    +

    When a single function has been added as a handler multiple times for a single +event (as in the example below), removeListener() will remove the most +recently added instance. In the example the once('ping')listener is removed:

    +
    const ee = new EventEmitter();

    function pong() {
    console.log('pong');
    }

    ee.on('ping', pong);
    ee.once('ping', pong);
    ee.removeListener('ping', pong);

    ee.emit('ping');
    ee.emit('ping'); +
    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.1.26

    +
    +
    +

    Parameters

    +
      +
    • +
      eventName: string | symbol
    • +
    • +
      listener: ((...args: any[]) => void)
      +
        +
      • +
          +
        • (...args: any[]): void
        • +
        • +
          +

          Parameters

          +
            +
          • +
            Rest ...args: any[]
          +

          Returns void

    +

    Returns TimeSynchronization

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      localTime: bigint
    • +
    • +
      remoteTime: bigint
    +

    Returns void

+
+ +
+
+ +
    + +
  • +

    By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set toInfinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    + +

    Since

    v0.3.5

    +
    +
    +

    Parameters

    +
      +
    • +
      n: number
    +

    Returns TimeSynchronization

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      msgId: number
    • +
    • +
      msgs: bigint[]
    +

    Returns Buffer

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    const { getEventListeners, EventEmitter } = require('events');

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    getEventListeners(ee, 'foo'); // [listener]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    getEventListeners(et, 'foo'); // [listener]
    } +
    + +

    Since

    v15.2.0, v14.17.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter | _DOMEventTarget
    • +
    • +
      name: string | symbol
    +

    Returns Function[]

+
+ +
    + +
  • +

    A class method that returns the number of listeners for the given eventNameregistered on the given emitter.

    +
    const { EventEmitter, listenerCount } = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Since

    v0.9.12

    + +

    Deprecated

    Since v3.2.0 - Use listenerCount instead.

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
      +

      The emitter to query

      +
    • +
    • +
      eventName: string | symbol
      +

      The event name

      +
    +

    Returns number

+
+ +
    + +
  • +
    const { on, EventEmitter } = require('events');

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })(); +
    +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    const { on, EventEmitter } = require('events');
    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Since

    v13.6.0, v12.16.0

    + +

    Returns

    that iterates eventName events emitted by the emitter

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: EventEmitter
    • +
    • +
      eventName: string
      +

      The name of the event being listened for

      +
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns AsyncIterableIterator<any>

+
+ +
    + +
  • +

    Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    const { once, EventEmitter } = require('events');

    async function run() {
    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.log('error happened', err);
    }
    }

    run(); +
    +

    The special handling of the 'error' event is only used when events.once()is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.log('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    +

    An AbortSignal can be used to cancel waiting for the event:

    +
    const { EventEmitter, once } = require('events');

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Since

    v11.13.0, v10.16.0

    +
    +
    +

    Parameters

    +
      +
    • +
      emitter: _NodeEventTarget
    • +
    • +
      eventName: string | symbol
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

  • + +
  • +
    +

    Parameters

    +
      +
    • +
      emitter: _DOMEventTarget
    • +
    • +
      eventName: string
    • +
    • +
      Optional options: StaticEventEmitterOptions
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +
    const {
    setMaxListeners,
    EventEmitter
    } = require('events');

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Since

    v15.4.0

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional n: number
      +

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • +
    • +
      Rest ...eventTargets: (EventEmitter | _DOMEventTarget)[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/Track.html b/docs/classes/Track.html new file mode 100644 index 0000000..14d9af8 --- /dev/null +++ b/docs/classes/Track.html @@ -0,0 +1,243 @@ +Track | StageLinqJS
+
+ +
+
+
+
+ +

Class Track

+
+

Hierarchy

+
    +
  • Track
+
+

Implements

+
    +
  • Partial<ITrackData>
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +

    Track Type Class

    +
    +
    +

    Parameters

    +
      +
    • +
      prefix: string
      +

      State prefix that should proceed the property

      +
    +

    Returns Track

+
+

Properties

+
+ +
#prefix: string
+
+ +
#source: {
    location: DeviceId;
    name: string;
    path: string;
} = null
+
+

Type declaration

+
    +
  • +
    location: DeviceId
  • +
  • +
    name: string
  • +
  • +
    path: string
+
+ +
ArtistName: string = ""
+
+ +
CurrentBPM: number = 0
+
+ +
SampleRate: number = 0
+
+ +
SongAnalyzed: boolean = false
+
+ +
SongLoaded: boolean = false
+
+ +
SongName: string = ""
+
+ +
SoundSwitchGUID: string = ""
+
+ +
TrackBytes: number = 0
+
+ +
TrackLength: number = 0
+
+ +
TrackName: string = ""
+
+ +
TrackNetworkPath: string = ""
+
+ +
TrackURI: string = ""
+
+

Accessors

+
+ +
+
+ +
    +
  • get source(): {
        location: DeviceId;
        name: string;
        path: string;
    }
  • +
  • +

    Returns {
        location: DeviceId;
        name: string;
        path: string;
    }

    +
      +
    • +
      location: DeviceId
    • +
    • +
      name: string
    • +
    • +
      path: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/classes/WriteContext.html b/docs/classes/WriteContext.html new file mode 100644 index 0000000..946b36f --- /dev/null +++ b/docs/classes/WriteContext.html @@ -0,0 +1,366 @@ +WriteContext | StageLinqJS
+
+ +
+
+
+
+ +

Class WriteContext

+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
autoGrow: boolean
+
+ +
buffer: ArrayBuffer
+
+ +
littleEndian: boolean
+
+ +
pos: number
+
+

Methods

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_size: number
    +

    Returns void

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_buffer: Uint8Array
    • +
    • +
      p_bytes: number = -1
    +

    Returns number

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_string: string
    +

    Returns number

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_value: number
    +

    Returns number

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_string: string
    +

    Returns number

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_value: number
    +

    Returns number

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_value: number
    +

    Returns number

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_value: bigint
    +

    Returns number

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p_value: number
    +

    Returns number

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/enums/Services.html b/docs/enums/Services.html new file mode 100644 index 0000000..15111f6 --- /dev/null +++ b/docs/enums/Services.html @@ -0,0 +1,99 @@ +Services | StageLinqJS
+
+ +
+
+
+
+ +

Enumeration Services

+
+
+
+ +
+
+

Enumeration Members

+
+ +
BeatInfo: "BeatInfo"
+
+ +
Broadcast: "Broadcast"
+
+ +
Directory: "Directory"
+
+ +
FileTransfer: "FileTransfer"
+
+ +
StateMap: "StateMap"
+
+ +
TimeSynchronization: "TimeSynchronization"
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/functions/getTempFilePath.html b/docs/functions/getTempFilePath.html new file mode 100644 index 0000000..5a4ecaa --- /dev/null +++ b/docs/functions/getTempFilePath.html @@ -0,0 +1,102 @@ +getTempFilePath | StageLinqJS
+
+ +
+
+
+
+ +

Function getTempFilePath

+
+
    + +
  • +

    Recursively create a directory under the OS's temp path.

    + +

    Returns

    Absolute path

    +
    +
    +

    Parameters

    +
      +
    • +
      p_path: string
      +

      Directory to create including filename

      +
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/functions/sleep.html b/docs/functions/sleep.html new file mode 100644 index 0000000..0287029 --- /dev/null +++ b/docs/functions/sleep.html @@ -0,0 +1,101 @@ +sleep | StageLinqJS
+
+ +
+
+
+
+ +

Function sleep

+
+
    + +
  • +

    Sleep Utility Function

    + +

    Returns

    +
    +

    Parameters

    +
      +
    • +
      p_ms: number
      +

      //time in ms to sleep

      +
    +

    Returns Promise<void>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..85ce1df --- /dev/null +++ b/docs/index.html @@ -0,0 +1,232 @@ +StageLinqJS
+
+ +
+
+
+
+

StageLinqJS

+
+ +

StageLinqJS - A Robust Implementation of StageLinq Library

+
+ + +

Description

+
+

This branch implements the methods demonstrated previously in the StageLinq Listener branch. +Rather than searching out devices via discovery, we are able to have devices initiate connections to the library. As demonstrated, this approach:

+
    +
  • Greatly reduces complexity.

    +
  • +
  • Speeds up the connection & initialization process (almost every sleep() call has been eliminated without and affect thus far).

    +
  • +
  • Handles disconnection and reconnection of devices gracefully and simply.

    +
  • +
  • Allows connections from devices we couldn't use previously (i.e. x1800/x1850 mixers).

    +
  • +
+ + +

Notes on Terminilogy

+
+

An effort has been made to standardize the syntax used in the library, and to be consitent with the syntax Denon uses (when they have, in fact, been consistent themselves).

+ + +

Physical & Network

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SyntaxDescriptionExample
UnitA discrete physical player, controller, or mixerSC600, PRIME4, X1850
DeviceA unique StageLinq network entity, represented by a DeviceIdSee DeviceId
ServiceAn instance of a particular Service endpointStateMap, FileTransfer, BeatInfo
DeviceIdThe GUID representing a StageLinq Device.12345678-1234-1234-1234-123456789ABC
+ + +

Software & States

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SyntaxDescriptionExample
Deck (1..4)A singular music-playing instance on a UnitAn SC5000 has 2 Decks, A PRIME4 has 4 Decks
Layer (A..B)For switching between two Decks on a UnitLayer A is Deck 1, Layer B is Deck 2
TrackA music file loaded on a Deck
SongSometimes used interchangabley with Track in some State names
+ + +

Implementing Selected Services

+
+

We can choose which services to implement by including them in the StageLinqOptions parameter passed to Stagelinq on initialization.

+
const stageLinqOptions: StageLinqOptions = {
downloadDbSources: true,
actingAs: ActingAsDevice.StageLinqJS,
services: [
Services.StateMap,
Services.BeatInfo,
Services.FileTransfer,
],
} +
+ + +

Starting StageLinq

+
+

The main StageLinq class is now a Static Class:

+
StageLinq.options = stageLinqOptions;

await StageLinq.connect();
await StageLinq.disconnect(); +
+ + +

Discovery

+
+

Discovery emits a number of messages which may be helpful when debugging.

+
StageLinq.discovery.on('listening', () => {
console.log(`[DISCOVERY] Listening`)
});

StageLinq.discovery.on('announcing', (info) => {
console.log(`[DISCOVERY] Broadcasting Announce ${info.deviceId.string} Port ${info.port} ${info.source} ${info.software.name}:${info.software.version}`)
});

StageLinq.discovery.on('newDiscoveryDevice', (info) => {
console.log(`[DISCOVERY] New Device ${info.deviceId.string} ${info.source} ${info.software.name} ${info.software.version}`)
});

StageLinq.discovery.on('updatedDiscoveryDevice', (info) => {
console.log(`[DISCOVERY] Updated Device ${info.deviceId.string} Port:${info.port} ${info.source} ${info.software.name} ${info.software.version}`)
}); +
+

updatedDiscoveryDevice is emitted when a Device is broadcasting a new Directory port, which is indicative of a reset. The Device should automatically reconnect without any action required from the user.

+

Discovery offers a few methods for getting ConnectionInfos for Devices on the network:

+
/**
* Get ConnectionInfo
* @param {DeviceId} deviceId
* @returns {ConnectionInfo}
*/
public getConnectionInfo(deviceId: DeviceId): ConnectionInfo {
return this.peers.get(deviceId.string);
}

/**
* Get list of devices
* @returns {string[]} An array of DeviceId strings
*/
public getDeviceList(): string[] {
return [...this.peers.keys()]
}

/**
* Get array of device ConnectionInfos
* @returns {ConnectionInfo[]} An array of ConnectionInfos
*/
public getDevices(): ConnectionInfo[] {
return [...this.peers.values()]
} +
+ + +

StateMap

+
+
StateMap.emitter.on('newDevice', (service: StateMapDevice) => {
console.log(`[STATEMAP] Subscribing to States on ${service.deviceId.string}`);
service.subscribe();
});

StateMap.emitter.on('stateMessage', async (data: StateData) => {
console.log(`[STATEMAP] ${data.deviceId.string} ${data.name} => ${JSON.stringify(data.json)}`);
}); +
+ + +

Using NowPlaying-type updates from StageLinq.status

+
+
async function deckIsMaster(data: StateData) {
if (data.json.state) {
const deck = parseInt(data.name.substring(12, 13))
await sleep(250);
const track = stageLinq.status.getTrack(data.deviceId, deck)
console.log(`Now Playing: `, track)
}
}

async function songLoaded(data: StateData) {
if (data.json.state) {
const deck = parseInt(data.name.substring(12, 13))
await sleep(250);
const track = stageLinq.status.getTrack(data.deviceId, deck)
console.log(`Track Loaded: `, track)
if (stageLinq.fileTransfer && stageLinq.options.downloadDbSources) {
const trackInfo = await getTrackInfo(stageLinq, track.source.name, track.source.location, track.TrackNetworkPath);
console.log('Track DB Info: ', trackInfo)
downloadFile(stageLinq, track.source.name, track.source.location, track.source.path, Path.resolve(os.tmpdir()));
}
}
}

StateMap.emitter,on('newDevice', async (service: StateMapDevice) => {
console.log(`[STATEMAP] Subscribing to States on ${service.deviceId.string}`);

const info = StageLinq.devices.device(service.deviceId).info
for (let i = 1; i <= info.unit.decks; i++) {
service.addListener(`/Engine/Deck${i}/DeckIsMaster`, deckIsMaster);
service.addListener(`/Engine/Deck${i}/Track/SongLoaded`, songLoaded);
}
service.subscribe();
}); +
+ + +

FileTransfer & Sources

+
+
FileTransfer.emitter.on('fileTransferProgress', (source, file, txid, progress) => {
console.log(`[FILETRANSFER] ${source.name} id:{${txid}} Reading ${file}: ${progressBar(10, progress.bytesDownloaded, progress.total)} (${Math.ceil(progress.percentComplete)}%)`);
});

FileTransfer.emitter.on('fileTransferComplete', (source, file, txid) => {
console.log(`[FILETRANSFER] Complete ${source.name} id:{${txid}} ${file}`);
});

StageLing.sources.on('newSource', (source: Source) => {
console.log(`[FILETRANSFER] Source Available: (${source.name})`);
});

StageLing.sources.on('sourceRemoved', (sourceName: string, deviceId: DeviceId) => {
console.log(`[FILETRANSFER] Source Removed: ${sourceName} on ${deviceId.string}`);
});

StageLing.sources.on('dbDownloaded', (source: Source) => {
console.log(`[FILETRANSFER] Database Downloaded: (${source.name})`);
}); +
+ + +

BeatInfo

+
+
const beatOptions = {
// Resolution for triggering callback
// 0 = every message WARNING, it's a lot!
// 1 = every beat
// 4 = every 4 beats
// .25 = every 1/4 beat
everyNBeats: 1,
}

// User callback function.
// Will be triggered everytime a player's beat counter crosses the resolution threshold
function beatCallback(bd: BeatData,) {
let deckBeatString = ""
for (let i = 0; i < bd.deckCount; i++) {
deckBeatString += `Deck: ${i + 1} Beat: ${bd.deck[i].beat.toFixed(3)}/${bd.deck[i].totalBeats.toFixed(0)} `
}
console.log(`[BEATINFO] ${bd.deviceId.string} clock: ${bd.clock} ${deckBeatString}`);
}

//// callback is optional, BeatInfo messages can be consumed by:
// - user callback
// - event messages
// - reading the register
const beatMethod = {
useCallback: true,
useEvent: false,
useRegister: false,
};


BeatInfo.emitter.on('newBeatInfoDevice', async (beatInfo: BeatInfo) => {
console.log(`[BEATINFO] New Device ${beatInfo.deviceId.string}`)

if (beatMethod.useCallback) {
beatInfo.startBeatInfo(beatOptions, beatCallback);
}

if (beatMethod.useEvent) {
beatInfo.startBeatInfo(beatOptions);
BeatInfo.emitter.on('beatMsg', (bd) => {
if (bd.message) {
beatCallback(bd);
}
});
}

if (beatMethod.useRegister) {
beatInfo.startBeatInfo(beatOptions);

function beatFunc(beatInfo: BeatInfo) {
const beatData = beatInfo.getBeatData();
if (beatData) beatCallback(beatData);
}

setTimeout(beatFunc, 4000, beatInfo)
}
})
+
+ + +

Additional Notes on the Listener Method

+
+
    +
  • The Directory service is the only one which is required as it is the initial connection endpoint for remote devices.

    +
  • +
  • Only tokens of a specific structure seem to work, otherwise devices won't initiate a connection. One requirement seems to be that they start with 0xFFFFFFFFFFFF, but some more research into this is needed.

    +
  • +
+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/BeatData.html b/docs/interfaces/BeatData.html new file mode 100644 index 0000000..ce4acce --- /dev/null +++ b/docs/interfaces/BeatData.html @@ -0,0 +1,96 @@ +BeatData | StageLinqJS
+
+ +
+
+
+
+ +

Interface BeatData

+
+

Hierarchy

+
    +
  • BeatData
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
clock: bigint
+
+ +
deck: deckBeatData[]
+
+ +
deckCount: number
+
+ +
deviceId: DeviceId
+
+ +
service: BeatInfo
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/BroadcastData.html b/docs/interfaces/BroadcastData.html new file mode 100644 index 0000000..8189f5c --- /dev/null +++ b/docs/interfaces/BroadcastData.html @@ -0,0 +1,93 @@ +BroadcastData | StageLinqJS
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/ConnectionInfo.html b/docs/interfaces/ConnectionInfo.html new file mode 100644 index 0000000..34f1e7e --- /dev/null +++ b/docs/interfaces/ConnectionInfo.html @@ -0,0 +1,140 @@ +ConnectionInfo | StageLinqJS
+
+ +
+
+
+
+ +

Interface ConnectionInfo

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+ +
action: string
+
+ +
address: string
+
+ +
addressPort?: string
+
+ +
deviceId: DeviceId
+
+ +
port: number
+
+ +
software: {
    name: string;
    version: string;
}
+
+

Type declaration

+
    +
  • +
    name: string
  • +
  • +
    version: string
+
+ +
source: string
+
+ +
unit?: {
    decks: number;
    name: string;
    type: string;
}
+
+

Type declaration

+
    +
  • +
    decks: number
  • +
  • +
    name: string
  • +
  • +
    type: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/DirectoryData.html b/docs/interfaces/DirectoryData.html new file mode 100644 index 0000000..94a135b --- /dev/null +++ b/docs/interfaces/DirectoryData.html @@ -0,0 +1,68 @@ +DirectoryData | StageLinqJS
+
+ +
+
+
+
+ +

Interface DirectoryData

+
+

Hierarchy

+
    +
  • DirectoryData
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
deviceId: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/DiscoveryMessage.html b/docs/interfaces/DiscoveryMessage.html new file mode 100644 index 0000000..5f683cb --- /dev/null +++ b/docs/interfaces/DiscoveryMessage.html @@ -0,0 +1,105 @@ +DiscoveryMessage | StageLinqJS
+
+ +
+
+
+
+ +

Interface DiscoveryMessage

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
action: string
+
+ +
deviceId: DeviceId
+
+ +
port: number
+
+ +
software: {
    name: string;
    version: string;
}
+
+

Type declaration

+
    +
  • +
    name: string
  • +
  • +
    version: string
+
+ +
source: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/DiscoveryMessageOptions.html b/docs/interfaces/DiscoveryMessageOptions.html new file mode 100644 index 0000000..0a56882 --- /dev/null +++ b/docs/interfaces/DiscoveryMessageOptions.html @@ -0,0 +1,96 @@ +DiscoveryMessageOptions | StageLinqJS
+
+ +
+
+
+
+ +

Interface DiscoveryMessageOptions

+
+

Hierarchy

+
    +
  • DiscoveryMessageOptions
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
deviceId: DeviceId
+
+ +
name: string
+
+ +
port?: number
+
+ +
source: string
+
+ +
version: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/FileTransferData.html b/docs/interfaces/FileTransferData.html new file mode 100644 index 0000000..396365b --- /dev/null +++ b/docs/interfaces/FileTransferData.html @@ -0,0 +1,110 @@ +FileTransferData | StageLinqJS
+
+ +
+
+
+
+ +

Interface FileTransferData

+
+

Hierarchy

+
    +
  • FileTransferData
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
data?: Buffer
+
+ +
deviceId: DeviceId
+
+ +
offset?: number
+
+ +
service: FileTransfer
+
+ +
size?: number
+
+ +
sources?: string[]
+
+ +
txid: number
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/FileTransferProgress.html b/docs/interfaces/FileTransferProgress.html new file mode 100644 index 0000000..668af2e --- /dev/null +++ b/docs/interfaces/FileTransferProgress.html @@ -0,0 +1,89 @@ +FileTransferProgress | StageLinqJS
+
+ +
+
+
+
+ +

Interface FileTransferProgress

+
+

Hierarchy

+
    +
  • FileTransferProgress
+
+
+
+ +
+
+

Properties

+
+ +
bytesDownloaded: number
+
+ +
percentComplete: number
+
+ +
sizeLeft: number
+
+ +
total: number
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/ServiceMessage.html b/docs/interfaces/ServiceMessage.html new file mode 100644 index 0000000..2a43353 --- /dev/null +++ b/docs/interfaces/ServiceMessage.html @@ -0,0 +1,80 @@ +ServiceMessage | StageLinqJS
+
+ +
+
+
+
+ +

Interface ServiceMessage<T>

+
+

Type Parameters

+
    +
  • +

    T

+
+

Hierarchy

+
    +
  • ServiceMessage
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
id: number
+
+ +
message: T
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/StageLinqOptions.html b/docs/interfaces/StageLinqOptions.html new file mode 100644 index 0000000..76d52eb --- /dev/null +++ b/docs/interfaces/StageLinqOptions.html @@ -0,0 +1,96 @@ +StageLinqOptions | StageLinqJS
+
+ +
+
+
+
+ +

Interface StageLinqOptions

+
+

Hierarchy

+
    +
  • StageLinqOptions
+
+
+
+ +
+
+

Properties

+
+ +
+
+ +
connectToMixer?: boolean
+
+ +
downloadDbSources?: boolean
+
+ +
maxRetries?: number
+
+ +
services?: Services[]
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/StateData.html b/docs/interfaces/StateData.html new file mode 100644 index 0000000..da04f91 --- /dev/null +++ b/docs/interfaces/StateData.html @@ -0,0 +1,107 @@ +StateData | StageLinqJS
+
+ +
+
+
+
+ +

Interface StateData

+
+

Hierarchy

+
    +
  • StateData
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
deviceId: DeviceId
+
+ +
interval?: number
+
+ +
json?: {
    state?: boolean;
    string?: string;
    type: number;
    value?: number;
}
+
+

Type declaration

+
    +
  • +
    Optional state?: boolean
  • +
  • +
    Optional string?: string
  • +
  • +
    type: number
  • +
  • +
    Optional value?: number
+
+ +
name?: string
+
+ +
service: StateMap
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/TimeSyncData.html b/docs/interfaces/TimeSyncData.html new file mode 100644 index 0000000..9c8f596 --- /dev/null +++ b/docs/interfaces/TimeSyncData.html @@ -0,0 +1,75 @@ +TimeSyncData | StageLinqJS
+
+ +
+
+
+
+ +

Interface TimeSyncData

+
+

Hierarchy

+
    +
  • TimeSyncData
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
msgs: bigint[]
+
+ +
timestamp: bigint
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/interfaces/TrackDBEntry.html b/docs/interfaces/TrackDBEntry.html new file mode 100644 index 0000000..a0087ea --- /dev/null +++ b/docs/interfaces/TrackDBEntry.html @@ -0,0 +1,397 @@ +TrackDBEntry | StageLinqJS
+
+ +
+
+
+
+ +

Interface TrackDBEntry

+
+

Hierarchy

+
    +
  • TrackDBEntry
+
+
+
+ +
+
+

Properties

+
+ +
activeOnLoadLoops: number
+
+ +
album: string
+
+ +
albumArt: string
+
+ +
albumArtId: number
+
+ +
artist: string
+
+ +
beatData: Buffer
+
+ +
bitrate: number
+
+ +
bpm: number
+
+ +
bpmAnalyzed: number
+
+ +
comment: string
+
+ +
composer: string
+
+ +
dateAdded: string
+
+ +
dateCreated: string
+
+ +
explicitLyrics: boolean
+
+ +
fileBytes: number
+
+ +
fileType: string
+
+ +
filename: string
+
+ +
genre: string
+
+ +
id: number
+
+ +
isAnalyzed: boolean
+
+ +
isAvailable: boolean
+
+ +
isBeatGridLocked: boolean
+
+ +
isMetadataImported: boolean
+
+ +
isMetadataOfPackedTrackChanged: boolean
+
+ +
isPerfomanceDataOfPackedTrackChanged: boolean
+
+ +
isPlayed: boolean
+
+ +
key: number
+
+ +
label: string
+
+ +
length: number
+
+ +
loops: Buffer
+
+ +
originDatabaseUuid: string
+
+ +
originTrackId: number
+
+ +
overviewWaveFormData: Buffer
+
+ +
path: string
+
+ +
pdbImportKey: number
+
+ +
playOrder: number
+
+ +
playedIndicator: number
+
+ +
quickCues: Buffer
+
+ +
rating: number
+
+ +
remixer: string
+
+ +
streamingFlags: number
+
+ +
streamingSource: string
+
+ +
thirdPartySourceId: number
+
+ +
timeLastPlayed: string
+
+ +
title: string
+
+ +
trackData: Buffer
+
+ +
uri: string
+
+ +
year: number
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/modules.html b/docs/modules.html new file mode 100644 index 0000000..5d325cd --- /dev/null +++ b/docs/modules.html @@ -0,0 +1,143 @@ +StageLinqJS
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/types/BroadcastMessage.html b/docs/types/BroadcastMessage.html new file mode 100644 index 0000000..1230da3 --- /dev/null +++ b/docs/types/BroadcastMessage.html @@ -0,0 +1,98 @@ +BroadcastMessage | StageLinqJS
+
+ +
+
+
+
+ +

Type alias BroadcastMessage

+
BroadcastMessage: {
    databaseUuid: string;
    listId?: number | string;
    sessionId?: number | string;
    trackId?: number | string;
}
+
+

Type declaration

+
    +
  • +
    databaseUuid: string
  • +
  • +
    Optional listId?: number | string
  • +
  • +
    Optional sessionId?: number | string
  • +
  • +
    Optional trackId?: number | string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/types/IpAddress.html b/docs/types/IpAddress.html new file mode 100644 index 0000000..8d671b5 --- /dev/null +++ b/docs/types/IpAddress.html @@ -0,0 +1,87 @@ +IpAddress | StageLinqJS
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/types/IpAddressPort.html b/docs/types/IpAddressPort.html new file mode 100644 index 0000000..94ad0c9 --- /dev/null +++ b/docs/types/IpAddressPort.html @@ -0,0 +1,87 @@ +IpAddressPort | StageLinqJS
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/variables/ActingAsDevice.html b/docs/variables/ActingAsDevice.html new file mode 100644 index 0000000..7dde04c --- /dev/null +++ b/docs/variables/ActingAsDevice.html @@ -0,0 +1,92 @@ +ActingAsDevice | StageLinqJS
+
+ +
+
+
+
+ +

Variable ActingAsDeviceConst

+
ActingAsDevice: {
    [name: string]: DiscoveryMessageOptions;
} = ...
+
+

Type declaration

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/variables/StateNames.html b/docs/variables/StateNames.html new file mode 100644 index 0000000..ed22257 --- /dev/null +++ b/docs/variables/StateNames.html @@ -0,0 +1,546 @@ +StateNames | StageLinqJS
+
+ +
+
+
+
+ +

Variable StateNamesConst

+
StateNames: {
    mixer: {
        MixerCH1faderPosition: string;
        MixerCH2faderPosition: string;
        MixerCH3faderPosition: string;
        MixerCH4faderPosition: string;
        MixerChannelAssignment1: string;
        MixerChannelAssignment2: string;
        MixerChannelAssignment3: string;
        MixerChannelAssignment4: string;
        MixerCrossfaderPosition: string;
        MixerNumberOfChannels: string;
    };
    player: {
        ClientLibrarianDevicesControllerCurrentDevice: string;
        ClientLibrarianDevicesControllerCurrentDeviceNetworkPath: string;
        ClientLibrarianDevicesControllerHasSDCardConnected: string;
        ClientLibrarianDevicesControllerHasUsbDeviceConnected: string;
        ClientPreferencesLayerA: string;
        ClientPreferencesLayerB: string;
        ClientPreferencesPlayer: string;
        ClientPreferencesPlayerJogColorA: string;
        ClientPreferencesPlayerJogColorB: string;
        ClientPreferencesProfileApplicationPlayerColor1: string;
        ClientPreferencesProfileApplicationPlayerColor1A: string;
        ClientPreferencesProfileApplicationPlayerColor1B: string;
        ClientPreferencesProfileApplicationPlayerColor2: string;
        ClientPreferencesProfileApplicationPlayerColor2A: string;
        ClientPreferencesProfileApplicationPlayerColor2B: string;
        ClientPreferencesProfileApplicationPlayerColor3: string;
        ClientPreferencesProfileApplicationPlayerColor3A: string;
        ClientPreferencesProfileApplicationPlayerColor3B: string;
        ClientPreferencesProfileApplicationPlayerColor4: string;
        ClientPreferencesProfileApplicationPlayerColor4A: string;
        ClientPreferencesProfileApplicationPlayerColor4B: string;
        ClientPreferencesProfileApplicationSyncMode: string;
        EngineDeck1CurrentBPM: string;
        EngineDeck1DeckIsMaster: string;
        EngineDeck1ExternalMixerVolume: string;
        EngineDeck1ExternalScratchWheelTouch: string;
        EngineDeck1PadsView: string;
        EngineDeck1Play: string;
        EngineDeck1PlayState: string;
        EngineDeck1PlayStatePath: string;
        EngineDeck1Speed: string;
        EngineDeck1SpeedNeutral: string;
        EngineDeck1SpeedOffsetDown: string;
        EngineDeck1SpeedOffsetUp: string;
        EngineDeck1SpeedRange: string;
        EngineDeck1SpeedState: string;
        EngineDeck1SyncMode: string;
        EngineDeck1SyncPlayState: string;
        EngineDeck1TrackArtistName: string;
        EngineDeck1TrackBleep: string;
        EngineDeck1TrackCuePosition: string;
        EngineDeck1TrackCurrentBPM: string;
        EngineDeck1TrackCurrentKeyIndex: string;
        EngineDeck1TrackCurrentLoopInPosition: string;
        EngineDeck1TrackCurrentLoopOutPosition: string;
        EngineDeck1TrackCurrentLoopSizeInBeats: string;
        EngineDeck1TrackKeyLock: string;
        EngineDeck1TrackLoopEnableState: string;
        EngineDeck1TrackLoopQuickLoop1: string;
        EngineDeck1TrackLoopQuickLoop2: string;
        EngineDeck1TrackLoopQuickLoop3: string;
        EngineDeck1TrackLoopQuickLoop4: string;
        EngineDeck1TrackLoopQuickLoop5: string;
        EngineDeck1TrackLoopQuickLoop6: string;
        EngineDeck1TrackLoopQuickLoop7: string;
        EngineDeck1TrackLoopQuickLoop8: string;
        EngineDeck1TrackPlayPauseLEDState: string;
        EngineDeck1TrackSampleRate: string;
        EngineDeck1TrackSongAnalyzed: string;
        EngineDeck1TrackSongLoaded: string;
        EngineDeck1TrackSongName: string;
        EngineDeck1TrackSoundSwitchGUID: string;
        EngineDeck1TrackTrackBytes: string;
        EngineDeck1TrackTrackData: string;
        EngineDeck1TrackTrackLength: string;
        EngineDeck1TrackTrackName: string;
        EngineDeck1TrackTrackNetworkPath: string;
        EngineDeck1TrackTrackURI: string;
        EngineDeck1TrackTrackWasPlayed: string;
        EngineDeck2CurrentBPM: string;
        EngineDeck2DeckIsMaster: string;
        EngineDeck2ExternalMixerVolume: string;
        EngineDeck2ExternalScratchWheelTouch: string;
        EngineDeck2PadsView: string;
        EngineDeck2Play: string;
        EngineDeck2PlayState: string;
        EngineDeck2PlayStatePath: string;
        EngineDeck2Speed: string;
        EngineDeck2SpeedNeutral: string;
        EngineDeck2SpeedOffsetDown: string;
        EngineDeck2SpeedOffsetUp: string;
        EngineDeck2SpeedRange: string;
        EngineDeck2SpeedState: string;
        EngineDeck2SyncMode: string;
        EngineDeck2SyncPlayState: string;
        EngineDeck2TrackArtistName: string;
        EngineDeck2TrackBleep: string;
        EngineDeck2TrackCuePosition: string;
        EngineDeck2TrackCurrentBPM: string;
        EngineDeck2TrackCurrentKeyIndex: string;
        EngineDeck2TrackCurrentLoopInPosition: string;
        EngineDeck2TrackCurrentLoopOutPosition: string;
        EngineDeck2TrackCurrentLoopSizeInBeats: string;
        EngineDeck2TrackKeyLock: string;
        EngineDeck2TrackLoopEnableState: string;
        EngineDeck2TrackLoopQuickLoop1: string;
        EngineDeck2TrackLoopQuickLoop2: string;
        EngineDeck2TrackLoopQuickLoop3: string;
        EngineDeck2TrackLoopQuickLoop4: string;
        EngineDeck2TrackLoopQuickLoop5: string;
        EngineDeck2TrackLoopQuickLoop6: string;
        EngineDeck2TrackLoopQuickLoop7: string;
        EngineDeck2TrackLoopQuickLoop8: string;
        EngineDeck2TrackPlayPauseLEDState: string;
        EngineDeck2TrackSampleRate: string;
        EngineDeck2TrackSongAnalyzed: string;
        EngineDeck2TrackSongLoaded: string;
        EngineDeck2TrackSongName: string;
        EngineDeck2TrackSoundSwitchGUID: string;
        EngineDeck2TrackTrackBytes: string;
        EngineDeck2TrackTrackData: string;
        EngineDeck2TrackTrackLength: string;
        EngineDeck2TrackTrackName: string;
        EngineDeck2TrackTrackNetworkPath: string;
        EngineDeck2TrackTrackURI: string;
        EngineDeck2TrackTrackWasPlayed: string;
        EngineDeck3CurrentBPM: string;
        EngineDeck3DeckIsMaster: string;
        EngineDeck3ExternalMixerVolume: string;
        EngineDeck3ExternalScratchWheelTouch: string;
        EngineDeck3PadsView: string;
        EngineDeck3Play: string;
        EngineDeck3PlayState: string;
        EngineDeck3PlayStatePath: string;
        EngineDeck3Speed: string;
        EngineDeck3SpeedNeutral: string;
        EngineDeck3SpeedOffsetDown: string;
        EngineDeck3SpeedOffsetUp: string;
        EngineDeck3SpeedRange: string;
        EngineDeck3SpeedState: string;
        EngineDeck3SyncMode: string;
        EngineDeck3SyncPlayState: string;
        EngineDeck3TrackArtistName: string;
        EngineDeck3TrackBleep: string;
        EngineDeck3TrackCuePosition: string;
        EngineDeck3TrackCurrentBPM: string;
        EngineDeck3TrackCurrentKeyIndex: string;
        EngineDeck3TrackCurrentLoopInPosition: string;
        EngineDeck3TrackCurrentLoopOutPosition: string;
        EngineDeck3TrackCurrentLoopSizeInBeats: string;
        EngineDeck3TrackKeyLock: string;
        EngineDeck3TrackLoopEnableState: string;
        EngineDeck3TrackLoopQuickLoop1: string;
        EngineDeck3TrackLoopQuickLoop2: string;
        EngineDeck3TrackLoopQuickLoop3: string;
        EngineDeck3TrackLoopQuickLoop4: string;
        EngineDeck3TrackLoopQuickLoop5: string;
        EngineDeck3TrackLoopQuickLoop6: string;
        EngineDeck3TrackLoopQuickLoop7: string;
        EngineDeck3TrackLoopQuickLoop8: string;
        EngineDeck3TrackPlayPauseLEDState: string;
        EngineDeck3TrackSampleRate: string;
        EngineDeck3TrackSongAnalyzed: string;
        EngineDeck3TrackSongLoaded: string;
        EngineDeck3TrackSongName: string;
        EngineDeck3TrackSoundSwitchGUID: string;
        EngineDeck3TrackTrackBytes: string;
        EngineDeck3TrackTrackData: string;
        EngineDeck3TrackTrackLength: string;
        EngineDeck3TrackTrackName: string;
        EngineDeck3TrackTrackNetworkPath: string;
        EngineDeck3TrackTrackURI: string;
        EngineDeck3TrackTrackWasPlayed: string;
        EngineDeck4CurrentBPM: string;
        EngineDeck4DeckIsMaster: string;
        EngineDeck4ExternalMixerVolume: string;
        EngineDeck4ExternalScratchWheelTouch: string;
        EngineDeck4PadsView: string;
        EngineDeck4Play: string;
        EngineDeck4PlayState: string;
        EngineDeck4PlayStatePath: string;
        EngineDeck4Speed: string;
        EngineDeck4SpeedNeutral: string;
        EngineDeck4SpeedOffsetDown: string;
        EngineDeck4SpeedOffsetUp: string;
        EngineDeck4SpeedRange: string;
        EngineDeck4SpeedState: string;
        EngineDeck4SyncMode: string;
        EngineDeck4SyncPlayState: string;
        EngineDeck4TrackArtistName: string;
        EngineDeck4TrackBleep: string;
        EngineDeck4TrackCuePosition: string;
        EngineDeck4TrackCurrentBPM: string;
        EngineDeck4TrackCurrentKeyIndex: string;
        EngineDeck4TrackCurrentLoopInPosition: string;
        EngineDeck4TrackCurrentLoopOutPosition: string;
        EngineDeck4TrackCurrentLoopSizeInBeats: string;
        EngineDeck4TrackKeyLock: string;
        EngineDeck4TrackLoopEnableState: string;
        EngineDeck4TrackLoopQuickLoop1: string;
        EngineDeck4TrackLoopQuickLoop2: string;
        EngineDeck4TrackLoopQuickLoop3: string;
        EngineDeck4TrackLoopQuickLoop4: string;
        EngineDeck4TrackLoopQuickLoop5: string;
        EngineDeck4TrackLoopQuickLoop6: string;
        EngineDeck4TrackLoopQuickLoop7: string;
        EngineDeck4TrackLoopQuickLoop8: string;
        EngineDeck4TrackPlayPauseLEDState: string;
        EngineDeck4TrackSampleRate: string;
        EngineDeck4TrackSongAnalyzed: string;
        EngineDeck4TrackSongLoaded: string;
        EngineDeck4TrackSongName: string;
        EngineDeck4TrackSoundSwitchGUID: string;
        EngineDeck4TrackTrackBytes: string;
        EngineDeck4TrackTrackData: string;
        EngineDeck4TrackTrackLength: string;
        EngineDeck4TrackTrackName: string;
        EngineDeck4TrackTrackNetworkPath: string;
        EngineDeck4TrackTrackURI: string;
        EngineDeck4TrackTrackWasPlayed: string;
        EngineDeckCount: string;
        EngineMasterMasterTempo: string;
        EngineSyncNetworkMasterStatus: string;
        EngineSyncNetworkSyncType: string;
        GUIDecksDeckActiveDeck: string;
    };
} = ...
+
+

Type declaration

+
    +
  • +
    mixer: {
        MixerCH1faderPosition: string;
        MixerCH2faderPosition: string;
        MixerCH3faderPosition: string;
        MixerCH4faderPosition: string;
        MixerChannelAssignment1: string;
        MixerChannelAssignment2: string;
        MixerChannelAssignment3: string;
        MixerChannelAssignment4: string;
        MixerCrossfaderPosition: string;
        MixerNumberOfChannels: string;
    }
    +
      +
    • +
      MixerCH1faderPosition: string
    • +
    • +
      MixerCH2faderPosition: string
    • +
    • +
      MixerCH3faderPosition: string
    • +
    • +
      MixerCH4faderPosition: string
    • +
    • +
      MixerChannelAssignment1: string
    • +
    • +
      MixerChannelAssignment2: string
    • +
    • +
      MixerChannelAssignment3: string
    • +
    • +
      MixerChannelAssignment4: string
    • +
    • +
      MixerCrossfaderPosition: string
    • +
    • +
      MixerNumberOfChannels: string
  • +
  • +
    player: {
        ClientLibrarianDevicesControllerCurrentDevice: string;
        ClientLibrarianDevicesControllerCurrentDeviceNetworkPath: string;
        ClientLibrarianDevicesControllerHasSDCardConnected: string;
        ClientLibrarianDevicesControllerHasUsbDeviceConnected: string;
        ClientPreferencesLayerA: string;
        ClientPreferencesLayerB: string;
        ClientPreferencesPlayer: string;
        ClientPreferencesPlayerJogColorA: string;
        ClientPreferencesPlayerJogColorB: string;
        ClientPreferencesProfileApplicationPlayerColor1: string;
        ClientPreferencesProfileApplicationPlayerColor1A: string;
        ClientPreferencesProfileApplicationPlayerColor1B: string;
        ClientPreferencesProfileApplicationPlayerColor2: string;
        ClientPreferencesProfileApplicationPlayerColor2A: string;
        ClientPreferencesProfileApplicationPlayerColor2B: string;
        ClientPreferencesProfileApplicationPlayerColor3: string;
        ClientPreferencesProfileApplicationPlayerColor3A: string;
        ClientPreferencesProfileApplicationPlayerColor3B: string;
        ClientPreferencesProfileApplicationPlayerColor4: string;
        ClientPreferencesProfileApplicationPlayerColor4A: string;
        ClientPreferencesProfileApplicationPlayerColor4B: string;
        ClientPreferencesProfileApplicationSyncMode: string;
        EngineDeck1CurrentBPM: string;
        EngineDeck1DeckIsMaster: string;
        EngineDeck1ExternalMixerVolume: string;
        EngineDeck1ExternalScratchWheelTouch: string;
        EngineDeck1PadsView: string;
        EngineDeck1Play: string;
        EngineDeck1PlayState: string;
        EngineDeck1PlayStatePath: string;
        EngineDeck1Speed: string;
        EngineDeck1SpeedNeutral: string;
        EngineDeck1SpeedOffsetDown: string;
        EngineDeck1SpeedOffsetUp: string;
        EngineDeck1SpeedRange: string;
        EngineDeck1SpeedState: string;
        EngineDeck1SyncMode: string;
        EngineDeck1SyncPlayState: string;
        EngineDeck1TrackArtistName: string;
        EngineDeck1TrackBleep: string;
        EngineDeck1TrackCuePosition: string;
        EngineDeck1TrackCurrentBPM: string;
        EngineDeck1TrackCurrentKeyIndex: string;
        EngineDeck1TrackCurrentLoopInPosition: string;
        EngineDeck1TrackCurrentLoopOutPosition: string;
        EngineDeck1TrackCurrentLoopSizeInBeats: string;
        EngineDeck1TrackKeyLock: string;
        EngineDeck1TrackLoopEnableState: string;
        EngineDeck1TrackLoopQuickLoop1: string;
        EngineDeck1TrackLoopQuickLoop2: string;
        EngineDeck1TrackLoopQuickLoop3: string;
        EngineDeck1TrackLoopQuickLoop4: string;
        EngineDeck1TrackLoopQuickLoop5: string;
        EngineDeck1TrackLoopQuickLoop6: string;
        EngineDeck1TrackLoopQuickLoop7: string;
        EngineDeck1TrackLoopQuickLoop8: string;
        EngineDeck1TrackPlayPauseLEDState: string;
        EngineDeck1TrackSampleRate: string;
        EngineDeck1TrackSongAnalyzed: string;
        EngineDeck1TrackSongLoaded: string;
        EngineDeck1TrackSongName: string;
        EngineDeck1TrackSoundSwitchGUID: string;
        EngineDeck1TrackTrackBytes: string;
        EngineDeck1TrackTrackData: string;
        EngineDeck1TrackTrackLength: string;
        EngineDeck1TrackTrackName: string;
        EngineDeck1TrackTrackNetworkPath: string;
        EngineDeck1TrackTrackURI: string;
        EngineDeck1TrackTrackWasPlayed: string;
        EngineDeck2CurrentBPM: string;
        EngineDeck2DeckIsMaster: string;
        EngineDeck2ExternalMixerVolume: string;
        EngineDeck2ExternalScratchWheelTouch: string;
        EngineDeck2PadsView: string;
        EngineDeck2Play: string;
        EngineDeck2PlayState: string;
        EngineDeck2PlayStatePath: string;
        EngineDeck2Speed: string;
        EngineDeck2SpeedNeutral: string;
        EngineDeck2SpeedOffsetDown: string;
        EngineDeck2SpeedOffsetUp: string;
        EngineDeck2SpeedRange: string;
        EngineDeck2SpeedState: string;
        EngineDeck2SyncMode: string;
        EngineDeck2SyncPlayState: string;
        EngineDeck2TrackArtistName: string;
        EngineDeck2TrackBleep: string;
        EngineDeck2TrackCuePosition: string;
        EngineDeck2TrackCurrentBPM: string;
        EngineDeck2TrackCurrentKeyIndex: string;
        EngineDeck2TrackCurrentLoopInPosition: string;
        EngineDeck2TrackCurrentLoopOutPosition: string;
        EngineDeck2TrackCurrentLoopSizeInBeats: string;
        EngineDeck2TrackKeyLock: string;
        EngineDeck2TrackLoopEnableState: string;
        EngineDeck2TrackLoopQuickLoop1: string;
        EngineDeck2TrackLoopQuickLoop2: string;
        EngineDeck2TrackLoopQuickLoop3: string;
        EngineDeck2TrackLoopQuickLoop4: string;
        EngineDeck2TrackLoopQuickLoop5: string;
        EngineDeck2TrackLoopQuickLoop6: string;
        EngineDeck2TrackLoopQuickLoop7: string;
        EngineDeck2TrackLoopQuickLoop8: string;
        EngineDeck2TrackPlayPauseLEDState: string;
        EngineDeck2TrackSampleRate: string;
        EngineDeck2TrackSongAnalyzed: string;
        EngineDeck2TrackSongLoaded: string;
        EngineDeck2TrackSongName: string;
        EngineDeck2TrackSoundSwitchGUID: string;
        EngineDeck2TrackTrackBytes: string;
        EngineDeck2TrackTrackData: string;
        EngineDeck2TrackTrackLength: string;
        EngineDeck2TrackTrackName: string;
        EngineDeck2TrackTrackNetworkPath: string;
        EngineDeck2TrackTrackURI: string;
        EngineDeck2TrackTrackWasPlayed: string;
        EngineDeck3CurrentBPM: string;
        EngineDeck3DeckIsMaster: string;
        EngineDeck3ExternalMixerVolume: string;
        EngineDeck3ExternalScratchWheelTouch: string;
        EngineDeck3PadsView: string;
        EngineDeck3Play: string;
        EngineDeck3PlayState: string;
        EngineDeck3PlayStatePath: string;
        EngineDeck3Speed: string;
        EngineDeck3SpeedNeutral: string;
        EngineDeck3SpeedOffsetDown: string;
        EngineDeck3SpeedOffsetUp: string;
        EngineDeck3SpeedRange: string;
        EngineDeck3SpeedState: string;
        EngineDeck3SyncMode: string;
        EngineDeck3SyncPlayState: string;
        EngineDeck3TrackArtistName: string;
        EngineDeck3TrackBleep: string;
        EngineDeck3TrackCuePosition: string;
        EngineDeck3TrackCurrentBPM: string;
        EngineDeck3TrackCurrentKeyIndex: string;
        EngineDeck3TrackCurrentLoopInPosition: string;
        EngineDeck3TrackCurrentLoopOutPosition: string;
        EngineDeck3TrackCurrentLoopSizeInBeats: string;
        EngineDeck3TrackKeyLock: string;
        EngineDeck3TrackLoopEnableState: string;
        EngineDeck3TrackLoopQuickLoop1: string;
        EngineDeck3TrackLoopQuickLoop2: string;
        EngineDeck3TrackLoopQuickLoop3: string;
        EngineDeck3TrackLoopQuickLoop4: string;
        EngineDeck3TrackLoopQuickLoop5: string;
        EngineDeck3TrackLoopQuickLoop6: string;
        EngineDeck3TrackLoopQuickLoop7: string;
        EngineDeck3TrackLoopQuickLoop8: string;
        EngineDeck3TrackPlayPauseLEDState: string;
        EngineDeck3TrackSampleRate: string;
        EngineDeck3TrackSongAnalyzed: string;
        EngineDeck3TrackSongLoaded: string;
        EngineDeck3TrackSongName: string;
        EngineDeck3TrackSoundSwitchGUID: string;
        EngineDeck3TrackTrackBytes: string;
        EngineDeck3TrackTrackData: string;
        EngineDeck3TrackTrackLength: string;
        EngineDeck3TrackTrackName: string;
        EngineDeck3TrackTrackNetworkPath: string;
        EngineDeck3TrackTrackURI: string;
        EngineDeck3TrackTrackWasPlayed: string;
        EngineDeck4CurrentBPM: string;
        EngineDeck4DeckIsMaster: string;
        EngineDeck4ExternalMixerVolume: string;
        EngineDeck4ExternalScratchWheelTouch: string;
        EngineDeck4PadsView: string;
        EngineDeck4Play: string;
        EngineDeck4PlayState: string;
        EngineDeck4PlayStatePath: string;
        EngineDeck4Speed: string;
        EngineDeck4SpeedNeutral: string;
        EngineDeck4SpeedOffsetDown: string;
        EngineDeck4SpeedOffsetUp: string;
        EngineDeck4SpeedRange: string;
        EngineDeck4SpeedState: string;
        EngineDeck4SyncMode: string;
        EngineDeck4SyncPlayState: string;
        EngineDeck4TrackArtistName: string;
        EngineDeck4TrackBleep: string;
        EngineDeck4TrackCuePosition: string;
        EngineDeck4TrackCurrentBPM: string;
        EngineDeck4TrackCurrentKeyIndex: string;
        EngineDeck4TrackCurrentLoopInPosition: string;
        EngineDeck4TrackCurrentLoopOutPosition: string;
        EngineDeck4TrackCurrentLoopSizeInBeats: string;
        EngineDeck4TrackKeyLock: string;
        EngineDeck4TrackLoopEnableState: string;
        EngineDeck4TrackLoopQuickLoop1: string;
        EngineDeck4TrackLoopQuickLoop2: string;
        EngineDeck4TrackLoopQuickLoop3: string;
        EngineDeck4TrackLoopQuickLoop4: string;
        EngineDeck4TrackLoopQuickLoop5: string;
        EngineDeck4TrackLoopQuickLoop6: string;
        EngineDeck4TrackLoopQuickLoop7: string;
        EngineDeck4TrackLoopQuickLoop8: string;
        EngineDeck4TrackPlayPauseLEDState: string;
        EngineDeck4TrackSampleRate: string;
        EngineDeck4TrackSongAnalyzed: string;
        EngineDeck4TrackSongLoaded: string;
        EngineDeck4TrackSongName: string;
        EngineDeck4TrackSoundSwitchGUID: string;
        EngineDeck4TrackTrackBytes: string;
        EngineDeck4TrackTrackData: string;
        EngineDeck4TrackTrackLength: string;
        EngineDeck4TrackTrackName: string;
        EngineDeck4TrackTrackNetworkPath: string;
        EngineDeck4TrackTrackURI: string;
        EngineDeck4TrackTrackWasPlayed: string;
        EngineDeckCount: string;
        EngineMasterMasterTempo: string;
        EngineSyncNetworkMasterStatus: string;
        EngineSyncNetworkSyncType: string;
        GUIDecksDeckActiveDeck: string;
    }
    +
      +
    • +
      ClientLibrarianDevicesControllerCurrentDevice: string
    • +
    • +
      ClientLibrarianDevicesControllerCurrentDeviceNetworkPath: string
    • +
    • +
      ClientLibrarianDevicesControllerHasSDCardConnected: string
    • +
    • +
      ClientLibrarianDevicesControllerHasUsbDeviceConnected: string
    • +
    • +
      ClientPreferencesLayerA: string
    • +
    • +
      ClientPreferencesLayerB: string
    • +
    • +
      ClientPreferencesPlayer: string
    • +
    • +
      ClientPreferencesPlayerJogColorA: string
    • +
    • +
      ClientPreferencesPlayerJogColorB: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor1: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor1A: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor1B: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor2: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor2A: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor2B: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor3: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor3A: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor3B: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor4: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor4A: string
    • +
    • +
      ClientPreferencesProfileApplicationPlayerColor4B: string
    • +
    • +
      ClientPreferencesProfileApplicationSyncMode: string
    • +
    • +
      EngineDeck1CurrentBPM: string
    • +
    • +
      EngineDeck1DeckIsMaster: string
    • +
    • +
      EngineDeck1ExternalMixerVolume: string
    • +
    • +
      EngineDeck1ExternalScratchWheelTouch: string
    • +
    • +
      EngineDeck1PadsView: string
    • +
    • +
      EngineDeck1Play: string
    • +
    • +
      EngineDeck1PlayState: string
    • +
    • +
      EngineDeck1PlayStatePath: string
    • +
    • +
      EngineDeck1Speed: string
    • +
    • +
      EngineDeck1SpeedNeutral: string
    • +
    • +
      EngineDeck1SpeedOffsetDown: string
    • +
    • +
      EngineDeck1SpeedOffsetUp: string
    • +
    • +
      EngineDeck1SpeedRange: string
    • +
    • +
      EngineDeck1SpeedState: string
    • +
    • +
      EngineDeck1SyncMode: string
    • +
    • +
      EngineDeck1SyncPlayState: string
    • +
    • +
      EngineDeck1TrackArtistName: string
    • +
    • +
      EngineDeck1TrackBleep: string
    • +
    • +
      EngineDeck1TrackCuePosition: string
    • +
    • +
      EngineDeck1TrackCurrentBPM: string
    • +
    • +
      EngineDeck1TrackCurrentKeyIndex: string
    • +
    • +
      EngineDeck1TrackCurrentLoopInPosition: string
    • +
    • +
      EngineDeck1TrackCurrentLoopOutPosition: string
    • +
    • +
      EngineDeck1TrackCurrentLoopSizeInBeats: string
    • +
    • +
      EngineDeck1TrackKeyLock: string
    • +
    • +
      EngineDeck1TrackLoopEnableState: string
    • +
    • +
      EngineDeck1TrackLoopQuickLoop1: string
    • +
    • +
      EngineDeck1TrackLoopQuickLoop2: string
    • +
    • +
      EngineDeck1TrackLoopQuickLoop3: string
    • +
    • +
      EngineDeck1TrackLoopQuickLoop4: string
    • +
    • +
      EngineDeck1TrackLoopQuickLoop5: string
    • +
    • +
      EngineDeck1TrackLoopQuickLoop6: string
    • +
    • +
      EngineDeck1TrackLoopQuickLoop7: string
    • +
    • +
      EngineDeck1TrackLoopQuickLoop8: string
    • +
    • +
      EngineDeck1TrackPlayPauseLEDState: string
    • +
    • +
      EngineDeck1TrackSampleRate: string
    • +
    • +
      EngineDeck1TrackSongAnalyzed: string
    • +
    • +
      EngineDeck1TrackSongLoaded: string
    • +
    • +
      EngineDeck1TrackSongName: string
    • +
    • +
      EngineDeck1TrackSoundSwitchGUID: string
    • +
    • +
      EngineDeck1TrackTrackBytes: string
    • +
    • +
      EngineDeck1TrackTrackData: string
    • +
    • +
      EngineDeck1TrackTrackLength: string
    • +
    • +
      EngineDeck1TrackTrackName: string
    • +
    • +
      EngineDeck1TrackTrackNetworkPath: string
    • +
    • +
      EngineDeck1TrackTrackURI: string
    • +
    • +
      EngineDeck1TrackTrackWasPlayed: string
    • +
    • +
      EngineDeck2CurrentBPM: string
    • +
    • +
      EngineDeck2DeckIsMaster: string
    • +
    • +
      EngineDeck2ExternalMixerVolume: string
    • +
    • +
      EngineDeck2ExternalScratchWheelTouch: string
    • +
    • +
      EngineDeck2PadsView: string
    • +
    • +
      EngineDeck2Play: string
    • +
    • +
      EngineDeck2PlayState: string
    • +
    • +
      EngineDeck2PlayStatePath: string
    • +
    • +
      EngineDeck2Speed: string
    • +
    • +
      EngineDeck2SpeedNeutral: string
    • +
    • +
      EngineDeck2SpeedOffsetDown: string
    • +
    • +
      EngineDeck2SpeedOffsetUp: string
    • +
    • +
      EngineDeck2SpeedRange: string
    • +
    • +
      EngineDeck2SpeedState: string
    • +
    • +
      EngineDeck2SyncMode: string
    • +
    • +
      EngineDeck2SyncPlayState: string
    • +
    • +
      EngineDeck2TrackArtistName: string
    • +
    • +
      EngineDeck2TrackBleep: string
    • +
    • +
      EngineDeck2TrackCuePosition: string
    • +
    • +
      EngineDeck2TrackCurrentBPM: string
    • +
    • +
      EngineDeck2TrackCurrentKeyIndex: string
    • +
    • +
      EngineDeck2TrackCurrentLoopInPosition: string
    • +
    • +
      EngineDeck2TrackCurrentLoopOutPosition: string
    • +
    • +
      EngineDeck2TrackCurrentLoopSizeInBeats: string
    • +
    • +
      EngineDeck2TrackKeyLock: string
    • +
    • +
      EngineDeck2TrackLoopEnableState: string
    • +
    • +
      EngineDeck2TrackLoopQuickLoop1: string
    • +
    • +
      EngineDeck2TrackLoopQuickLoop2: string
    • +
    • +
      EngineDeck2TrackLoopQuickLoop3: string
    • +
    • +
      EngineDeck2TrackLoopQuickLoop4: string
    • +
    • +
      EngineDeck2TrackLoopQuickLoop5: string
    • +
    • +
      EngineDeck2TrackLoopQuickLoop6: string
    • +
    • +
      EngineDeck2TrackLoopQuickLoop7: string
    • +
    • +
      EngineDeck2TrackLoopQuickLoop8: string
    • +
    • +
      EngineDeck2TrackPlayPauseLEDState: string
    • +
    • +
      EngineDeck2TrackSampleRate: string
    • +
    • +
      EngineDeck2TrackSongAnalyzed: string
    • +
    • +
      EngineDeck2TrackSongLoaded: string
    • +
    • +
      EngineDeck2TrackSongName: string
    • +
    • +
      EngineDeck2TrackSoundSwitchGUID: string
    • +
    • +
      EngineDeck2TrackTrackBytes: string
    • +
    • +
      EngineDeck2TrackTrackData: string
    • +
    • +
      EngineDeck2TrackTrackLength: string
    • +
    • +
      EngineDeck2TrackTrackName: string
    • +
    • +
      EngineDeck2TrackTrackNetworkPath: string
    • +
    • +
      EngineDeck2TrackTrackURI: string
    • +
    • +
      EngineDeck2TrackTrackWasPlayed: string
    • +
    • +
      EngineDeck3CurrentBPM: string
    • +
    • +
      EngineDeck3DeckIsMaster: string
    • +
    • +
      EngineDeck3ExternalMixerVolume: string
    • +
    • +
      EngineDeck3ExternalScratchWheelTouch: string
    • +
    • +
      EngineDeck3PadsView: string
    • +
    • +
      EngineDeck3Play: string
    • +
    • +
      EngineDeck3PlayState: string
    • +
    • +
      EngineDeck3PlayStatePath: string
    • +
    • +
      EngineDeck3Speed: string
    • +
    • +
      EngineDeck3SpeedNeutral: string
    • +
    • +
      EngineDeck3SpeedOffsetDown: string
    • +
    • +
      EngineDeck3SpeedOffsetUp: string
    • +
    • +
      EngineDeck3SpeedRange: string
    • +
    • +
      EngineDeck3SpeedState: string
    • +
    • +
      EngineDeck3SyncMode: string
    • +
    • +
      EngineDeck3SyncPlayState: string
    • +
    • +
      EngineDeck3TrackArtistName: string
    • +
    • +
      EngineDeck3TrackBleep: string
    • +
    • +
      EngineDeck3TrackCuePosition: string
    • +
    • +
      EngineDeck3TrackCurrentBPM: string
    • +
    • +
      EngineDeck3TrackCurrentKeyIndex: string
    • +
    • +
      EngineDeck3TrackCurrentLoopInPosition: string
    • +
    • +
      EngineDeck3TrackCurrentLoopOutPosition: string
    • +
    • +
      EngineDeck3TrackCurrentLoopSizeInBeats: string
    • +
    • +
      EngineDeck3TrackKeyLock: string
    • +
    • +
      EngineDeck3TrackLoopEnableState: string
    • +
    • +
      EngineDeck3TrackLoopQuickLoop1: string
    • +
    • +
      EngineDeck3TrackLoopQuickLoop2: string
    • +
    • +
      EngineDeck3TrackLoopQuickLoop3: string
    • +
    • +
      EngineDeck3TrackLoopQuickLoop4: string
    • +
    • +
      EngineDeck3TrackLoopQuickLoop5: string
    • +
    • +
      EngineDeck3TrackLoopQuickLoop6: string
    • +
    • +
      EngineDeck3TrackLoopQuickLoop7: string
    • +
    • +
      EngineDeck3TrackLoopQuickLoop8: string
    • +
    • +
      EngineDeck3TrackPlayPauseLEDState: string
    • +
    • +
      EngineDeck3TrackSampleRate: string
    • +
    • +
      EngineDeck3TrackSongAnalyzed: string
    • +
    • +
      EngineDeck3TrackSongLoaded: string
    • +
    • +
      EngineDeck3TrackSongName: string
    • +
    • +
      EngineDeck3TrackSoundSwitchGUID: string
    • +
    • +
      EngineDeck3TrackTrackBytes: string
    • +
    • +
      EngineDeck3TrackTrackData: string
    • +
    • +
      EngineDeck3TrackTrackLength: string
    • +
    • +
      EngineDeck3TrackTrackName: string
    • +
    • +
      EngineDeck3TrackTrackNetworkPath: string
    • +
    • +
      EngineDeck3TrackTrackURI: string
    • +
    • +
      EngineDeck3TrackTrackWasPlayed: string
    • +
    • +
      EngineDeck4CurrentBPM: string
    • +
    • +
      EngineDeck4DeckIsMaster: string
    • +
    • +
      EngineDeck4ExternalMixerVolume: string
    • +
    • +
      EngineDeck4ExternalScratchWheelTouch: string
    • +
    • +
      EngineDeck4PadsView: string
    • +
    • +
      EngineDeck4Play: string
    • +
    • +
      EngineDeck4PlayState: string
    • +
    • +
      EngineDeck4PlayStatePath: string
    • +
    • +
      EngineDeck4Speed: string
    • +
    • +
      EngineDeck4SpeedNeutral: string
    • +
    • +
      EngineDeck4SpeedOffsetDown: string
    • +
    • +
      EngineDeck4SpeedOffsetUp: string
    • +
    • +
      EngineDeck4SpeedRange: string
    • +
    • +
      EngineDeck4SpeedState: string
    • +
    • +
      EngineDeck4SyncMode: string
    • +
    • +
      EngineDeck4SyncPlayState: string
    • +
    • +
      EngineDeck4TrackArtistName: string
    • +
    • +
      EngineDeck4TrackBleep: string
    • +
    • +
      EngineDeck4TrackCuePosition: string
    • +
    • +
      EngineDeck4TrackCurrentBPM: string
    • +
    • +
      EngineDeck4TrackCurrentKeyIndex: string
    • +
    • +
      EngineDeck4TrackCurrentLoopInPosition: string
    • +
    • +
      EngineDeck4TrackCurrentLoopOutPosition: string
    • +
    • +
      EngineDeck4TrackCurrentLoopSizeInBeats: string
    • +
    • +
      EngineDeck4TrackKeyLock: string
    • +
    • +
      EngineDeck4TrackLoopEnableState: string
    • +
    • +
      EngineDeck4TrackLoopQuickLoop1: string
    • +
    • +
      EngineDeck4TrackLoopQuickLoop2: string
    • +
    • +
      EngineDeck4TrackLoopQuickLoop3: string
    • +
    • +
      EngineDeck4TrackLoopQuickLoop4: string
    • +
    • +
      EngineDeck4TrackLoopQuickLoop5: string
    • +
    • +
      EngineDeck4TrackLoopQuickLoop6: string
    • +
    • +
      EngineDeck4TrackLoopQuickLoop7: string
    • +
    • +
      EngineDeck4TrackLoopQuickLoop8: string
    • +
    • +
      EngineDeck4TrackPlayPauseLEDState: string
    • +
    • +
      EngineDeck4TrackSampleRate: string
    • +
    • +
      EngineDeck4TrackSongAnalyzed: string
    • +
    • +
      EngineDeck4TrackSongLoaded: string
    • +
    • +
      EngineDeck4TrackSongName: string
    • +
    • +
      EngineDeck4TrackSoundSwitchGUID: string
    • +
    • +
      EngineDeck4TrackTrackBytes: string
    • +
    • +
      EngineDeck4TrackTrackData: string
    • +
    • +
      EngineDeck4TrackTrackLength: string
    • +
    • +
      EngineDeck4TrackTrackName: string
    • +
    • +
      EngineDeck4TrackTrackNetworkPath: string
    • +
    • +
      EngineDeck4TrackTrackURI: string
    • +
    • +
      EngineDeck4TrackTrackWasPlayed: string
    • +
    • +
      EngineDeckCount: string
    • +
    • +
      EngineMasterMasterTempo: string
    • +
    • +
      EngineSyncNetworkMasterStatus: string
    • +
    • +
      EngineSyncNetworkSyncType: string
    • +
    • +
      GUIDecksDeckActiveDeck: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/variables/Units.html b/docs/variables/Units.html new file mode 100644 index 0000000..ad7485a --- /dev/null +++ b/docs/variables/Units.html @@ -0,0 +1,87 @@ +Units | StageLinqJS
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/index.ts b/index.ts index c9f1803..a17b384 100644 --- a/index.ts +++ b/index.ts @@ -1,5 +1,7 @@ -export * from './network'; +export * from './Discovery'; export * from './services'; export * from './StageLinq'; export * from './types'; export * from './utils'; +export * from './devices'; +export * from './Sources'; diff --git a/network-path-prototype.patch b/network-path-prototype.patch deleted file mode 100644 index 2d47b7c..0000000 --- a/network-path-prototype.patch +++ /dev/null @@ -1,181 +0,0 @@ -diff --git a/Databases/Databases.ts b/Databases/Databases.ts -index 10e0cba..4248e1e 100644 ---- a/Databases/Databases.ts -+++ b/Databases/Databases.ts -@@ -25,7 +25,11 @@ export class Databases extends EventEmitter { - const sources = await service.getSources(); - const output: string[] = []; - for (const source of sources) { -- const dbConnectionName = `${connectionInfo.address}_${connectionInfo.port}_${source.name}`; -+ const deviceId = /(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/i -+ .exec(Buffer.from(connectionInfo.token).toString('hex')).splice(1).join('-'); -+ -+ const dbConnectionName = `net://${deviceId}/${source.name}`; -+ Logger.debug(`DB network path: net://${deviceId}/${source.name}`) - if (this.sources.has(dbConnectionName)) { - Logger.debug(`Already seen ${source} on ${connectionInfo.address}:${connectionInfo.port}`); - } else { -diff --git a/Databases/DbConnection.ts b/Databases/DbConnection.ts -index 24ebd3a..6294024 100644 ---- a/Databases/DbConnection.ts -+++ b/Databases/DbConnection.ts -@@ -20,7 +20,7 @@ export class DbConnection { - * @returns - */ - querySource(query: string, ...params: any[]): T[] { -- console.debug(`Querying ${this.dbPath}: `); -+ console.debug(`Querying ${this.dbPath}: ${query}`); - const result = this.db.prepare(query); - return result.all(params); - } -@@ -32,7 +32,7 @@ export class DbConnection { - * @returns - */ - getTrackInfo(trackPath: string) { -- return this.querySource(`SELECT * FROM Track WHERE path = '${trackPath}'`); -+ return this.querySource(`SELECT * FROM Track WHERE path = ?`, trackPath); - } - - close() { -diff --git a/cli/index.ts b/cli/index.ts -index 8f532ca..5649037 100644 ---- a/cli/index.ts -+++ b/cli/index.ts -@@ -96,7 +96,7 @@ require('console-stamp')(console, { - // Example of how to download the actual track from the media. - try { - const tempfile = path.resolve(os.tmpdir(), 'media'); -- const data = await stageLinq.devices.downloadFile(status.address, status.trackPathAbsolute); -+ const data = await stageLinq.devices.downloadFile(status.deviceId, status.trackPathAbsolute); - if (data) { - fs.writeFileSync(tempfile, Buffer.from(data)); - console.log(`Downloaded ${status.trackPathAbsolute} to ${tempfile}`); -diff --git a/devices/Player.ts b/devices/Player.ts -index 64f0db0..c6193ca 100644 ---- a/devices/Player.ts -+++ b/devices/Player.ts -@@ -13,8 +13,9 @@ export declare interface Player { - - interface PlayerOptions { - stateMap: StateMap; -- address: string, -+ address: string; - port: number; -+ deviceId: string; - } - - interface SourceAndTrackPath { -@@ -48,6 +49,7 @@ export class Player extends EventEmitter { - private masterStatus: boolean; // If this device has the matser tempo - private decks: Map = new Map(); - private queue: {[layer: string]: PlayerMessageQueue} = {}; -+ private deviceId: string; - - /** - * Initialize a player device. -@@ -60,6 +62,8 @@ export class Player extends EventEmitter { - options.stateMap.on('message', this.messageHandler.bind(this)); - this.address = options.address; - this.port = options.port; -+ this.deviceId = options.deviceId; -+ - this.queue = { - A: new PlayerMessageQueue('A').onDataReady(this.handleUpdate.bind(this)), - B: new PlayerMessageQueue('B').onDataReady(this.handleUpdate.bind(this)), -@@ -150,22 +154,27 @@ export class Player extends EventEmitter { - port: this.port, - masterTempo: this.masterTempo, - masterStatus: this.masterStatus, -+ deviceId: `net://${this.deviceId}`, - ...result - }; - - // We're casting here because we originally built it up piecemeal. - const currentState = output as PlayerStatus; - -- if (/Unknown/.test(currentState.source)) { -+ if (currentState.trackNetworkPath && currentState.trackNetworkPath.startsWith('net:')) { -+ const pathParts = currentState.trackNetworkPath.split('net://')[1].split('/', 2) -+ currentState.dbSourceName = `net://${pathParts[0]}/${pathParts[1]}`; -+ currentState.deviceId = `net://${pathParts[0]}`; -+ } else if (!currentState.source || /Unknown/.test(currentState.source)) { - // Tracks from streaming sources won't be in the database. - currentState.dbSourceName = ''; - } else { -- currentState.dbSourceName = currentState.source -- ? `${this.address}_${this.port}_${currentState.source}` : ''; -+ currentState.dbSourceName = `net://${this.deviceId}/${currentState.source}`; - } - - // If a song is loaded and we have a location emit the trackLoaded event. -- if (songLoadedSignalPresent && currentState.trackNetworkPath) -+ // -+ if (/* songLoadedSignalPresent && */ currentState.trackNetworkPath) - this.emit('trackLoaded', currentState); - - // If the song is actually playing emit the nowPlaying event. -diff --git a/network/StageLinqDevices.ts b/network/StageLinqDevices.ts -index 949619a..6bdce8b 100644 ---- a/network/StageLinqDevices.ts -+++ b/network/StageLinqDevices.ts -@@ -106,8 +106,8 @@ export class StageLinqDevices extends EventEmitter { - return this._databases; - } - -- async downloadFile(ipAddress: string, path: string) { -- const device = this.devices.get(ipAddress); -+ async downloadFile(deviceId: string, path: string) { -+ const device = this.devices.get(deviceId); - const file = await device.fileTransferService.getFile(path); - return file; - } -@@ -123,10 +123,12 @@ export class StageLinqDevices extends EventEmitter { - const networkDevice = new NetworkDevice(connectionInfo); - await networkDevice.connect(); - -+ const deviceId = /(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/i -+ .exec(Buffer.from(connectionInfo.token).toString('hex')).splice(1).join('-'); - Logger.info(`Successfully connected to ${this.deviceId(connectionInfo)}`); - const fileTransfer = await networkDevice.connectToService(FileTransfer); - -- this.devices.set(connectionInfo.address, { -+ this.devices.set(`net://${deviceId}`, { - networkDevice: networkDevice, - fileTransferService: fileTransfer - }); -@@ -146,7 +148,8 @@ export class StageLinqDevices extends EventEmitter { - const player = new Player({ - stateMap: stateMap, - address: connectionInfo.address, -- port: connectionInfo.port -+ port: connectionInfo.port, -+ deviceId - }); - - player.on('trackLoaded', (status) => { -diff --git a/types/player.ts b/types/player.ts -index f672c6d..188d36e 100644 ---- a/types/player.ts -+++ b/types/player.ts -@@ -1,6 +1,7 @@ - - export interface PlayerStatus { - address: string; -+ deviceId: string; - artist: string; - currentBpm: number - deck: string; -diff --git a/utils/getTempFilePath.ts b/utils/getTempFilePath.ts -index c0d8bca..d737fe5 100644 ---- a/utils/getTempFilePath.ts -+++ b/utils/getTempFilePath.ts -@@ -9,7 +9,8 @@ import * as path from 'path'; - * @returns Absolute path - */ - export function getTempFilePath(p_path: string) { -- const tmpPath = `/${os.tmpdir()}/localdb/${p_path}`; -+ const tmpPath = `/${os.tmpdir()}/localdb/${p_path}` -+ .replace('net://', ''); - let paths = tmpPath.split(/[/\\]/).filter((e) => e.length > 0); - const isFolder = p_path.endsWith('/') || p_path.endsWith('\\'); - let filename = ''; diff --git a/network/NetworkDevice.ts b/network/NetworkDevice.ts deleted file mode 100644 index a672d4b..0000000 --- a/network/NetworkDevice.ts +++ /dev/null @@ -1,302 +0,0 @@ -import { Logger } from '../LogEmitter'; -import { ReadContext } from '../utils/ReadContext'; -import { ServicePorts, ConnectionInfo, LISTEN_TIMEOUT, MessageId, Tokens } from '../types'; -import { sleep } from '../utils/sleep'; -import { strict as assert } from 'assert'; -import { WriteContext } from '../utils/WriteContext'; -import * as FileType from 'file-type'; -import * as fs from 'fs'; -import * as services from '../services'; -import * as tcp from '../utils/tcp'; -import Database = require('better-sqlite3'); - - -interface SourceAndTrackPath { - source: string; - trackPath: string; -} - -export class NetworkDevice { - private connection: tcp.Connection = null; - //private source: string = null; - private serviceRequestAllowed = false; - private servicePorts: ServicePorts = {}; - private services: Record> = {}; - private timeAlive: number = 0; - private connectedSources: { - [key: string]: { - db: Database.Database; - albumArt: { - path: string; - extensions: { - [key: string]: string; - }; - }; - }; - } = {}; - - private connectionInfo: ConnectionInfo; - - constructor(info: ConnectionInfo) { - this.connectionInfo = info; - } - - private get address() { - return this.connectionInfo.address; - } - - private get port() { - return this.connectionInfo.port; - } - - /////////////////////////////////////////////////////////////////////////// - // Connect / Disconnect - - async connect(): Promise { - const info = this.connectionInfo; - Logger.debug(`Attempting to connect to ${info.address}:${info.port}`) - this.connection = await tcp.connect(info.address, info.port); - this.connection.socket.on('data', (p_message: Buffer) => { - this.messageHandler(p_message); - }); - await this.requestAllServicePorts(); - } - - disconnect(): void { - // Disconnect all services - for (const [key, service] of Object.entries(this.services)) { - service.disconnect(); - this.services[key] = null; - } - - assert(this.connection); - this.connection.destroy(); - this.connection = null; - } - - /////////////////////////////////////////////////////////////////////////// - // Message Handler - - messageHandler(p_message: Buffer): void { - const ctx = new ReadContext(p_message.buffer, false); - while (ctx.isEOF() === false) { - const id = ctx.readUInt32(); - // const deviceToken = ctx.read(16); - ctx.seek(16); - switch (id) { - case MessageId.TimeStamp: - ctx.seek(16); - // const secondToken = ctx.read(16); // should be 00.. - // we _shouldn't_ be receiving anything but blank tokens in the 2nd field - // assert(secondToken.every((x) => x === 0)); - - // Time Alive is in nanoseconds; convert back to seconds - this.timeAlive = Number(ctx.readUInt64() / (1000n * 1000n * 1000n)); - // this.sendTimeStampMsg(deviceToken, Tokens.SoundSwitch); - break; - case MessageId.ServicesAnnouncement: - const service = ctx.readNetworkStringUTF16(); - const port = ctx.readUInt16(); - this.servicePorts[service] = port; - break; - case MessageId.ServicesRequest: - this.serviceRequestAllowed = true; - break; - default: - assert.fail(`NetworkDevice Unhandled message id '${id}'`); - } - } - } - - /////////////////////////////////////////////////////////////////////////// - // Public methods - - getPort(): number { - return this.port; - } - getTimeAlive(): number { - return this.timeAlive; - } - - // Factory function - async connectToService>(ctor: { - new (p_address: string, p_port: number, p_controller: NetworkDevice): T; - }): Promise { - assert(this.connection); - // FIXME: find out why we need these waits before connecting to a service - await sleep(500); - - const serviceName = ctor.name; - - if (this.services[serviceName]) { - return this.services[serviceName] as T; - } - - assert(this.servicePorts.hasOwnProperty(serviceName)); - assert(this.servicePorts[serviceName] > 0); - const port = this.servicePorts[serviceName]; - - const service = new ctor(this.address, port, this); - - await service.connect(); - this.services[serviceName] = service; - return service; - } - - // TODO: Refactor this out of here. - async addSource(p_sourceName: string, p_localDbPath: string, p_localAlbumArtPath: string) { - if (this.connectedSources[p_sourceName]) { - return; - } - const db = new Database(p_localDbPath); - - // Get all album art extensions - const stmt = db.prepare('SELECT * FROM AlbumArt WHERE albumArt NOT NULL'); - const result = stmt.all(); - const albumArtExtensions: Record = {}; - for (const entry of result) { - const filetype = await FileType.fromBuffer(entry.albumArt); - albumArtExtensions[entry.id] = filetype ? filetype.ext : null; - } - - this.connectedSources[p_sourceName] = { - db: db, - albumArt: { - path: p_localAlbumArtPath, - extensions: albumArtExtensions, - }, - }; - } - - // TODO: Refactor this out of here. - async dumpAlbumArt(p_sourceName: string) { - if (!this.connectedSources[p_sourceName]) { - assert.fail(`Source '${p_sourceName}' not connected`); - return; - } - const path = this.connectedSources[p_sourceName].albumArt.path; - if (fs.existsSync(path) === false) { - fs.mkdirSync(path, { recursive: true }); - } - - const result = await this.querySource(p_sourceName, 'SELECT * FROM AlbumArt WHERE albumArt NOT NULL'); - for (const entry of result) { - const filetype = await FileType.fromBuffer(entry.albumArt); - const ext = filetype ? '.' + filetype.ext : ''; - const filepath = `${path}/${entry.id}${ext}`; - fs.writeFileSync(filepath, entry.albumArt); - } - Logger.info(`dumped ${result.length} albums arts in '${path}'`); - } - - // Database helpers - - querySource(p_sourceName: string, p_query: string, ...p_params: any[]): any[] { - if (!this.connectedSources[p_sourceName]) { - //assert.fail(`Source '${p_sourceName}' not connected`); - return []; - } - const db = this.connectedSources[p_sourceName].db; - const stmt = db.prepare(p_query); - - return stmt.all(p_params); - } - - getAlbumArtPath(p_networkPath: string): string { - const result = this.getSourceAndTrackFromNetworkPath(p_networkPath); - if (!result) { - return null; - } - - const sql = 'SELECT * FROM Track WHERE path = ?'; - const dbResult = this.querySource(result.source, sql, result.trackPath); - if (dbResult.length === 0) { - return null; - } - - assert(dbResult.length === 1); // there can only be one path - const id = dbResult[0].idAlbumArt; - const ext = this.connectedSources[result.source].albumArt.extensions[id]; - if (!ext) { - return null; - } - - return `${this.connectedSources[result.source].albumArt.path}${id}.${ext}`; - } - - /////////////////////////////////////////////////////////////////////////// - // Private methods - - private getSourceAndTrackFromNetworkPath(p_path: string): SourceAndTrackPath { - if (!p_path || p_path.length === 0) { - return null; - } - - const parts = p_path.split('/'); - //assert(parts.length > ) - assert(parts[0] === 'net:'); - assert(parts[1] === ''); - assert(parts[2].length === 36); - const source = parts[3]; - let trackPath = parts.slice(5).join('/'); - if (parts[4] !== 'Engine Library') { - // This probably occurs with RekordBox conversions; tracks are outside Engine Library folder - trackPath = `../${parts[4]}/${trackPath}`; - } - return { - source: source, - trackPath: trackPath, - }; - } - - private async requestAllServicePorts(): Promise { - assert(this.connection); - - return new Promise(async (resolve, reject) => { - setTimeout(() => { - reject(new Error(`Failed to requestServices for ` + - `${this.connectionInfo.source} ` + - `${this.connectionInfo.address}:${this.connectionInfo.port}`)); - }, LISTEN_TIMEOUT); - - // Wait for serviceRequestAllowed - while (true) { - if (this.serviceRequestAllowed) { - break; - } - await sleep(250); - } - - // FIXME: Refactor into message writer helper class - const ctx = new WriteContext(); - ctx.writeUInt32(MessageId.ServicesRequest); - ctx.write(Tokens.SoundSwitch); - const written = await this.connection.write(ctx.getBuffer()); - assert(written === ctx.tell()); - - while (true) { - // FIXME: How to determine when all services have been announced? - if (Object.keys(this.servicePorts).length > 3) { - Logger.debug(`Discovered the following services on ${this.address}:${this.port}`); - for (const [name, port] of Object.entries(this.servicePorts)) { - Logger.debug(`\tport: ${port} => ${name}`); - } - resolve(); - break; - } - await sleep(250); - } - }); - } - - // private async sendTimeStampMsg(deviceToken: Uint8Array, userToken: Uint8Array, timeAlive?: bigint) { - // const ctx = new WriteContext(); - // ctx.writeUInt32(MessageId.TimeStamp); - // ctx.write(deviceToken); - // ctx.write(userToken); - // const timeAliveNumber:bigint = (!!timeAlive) ? timeAlive : 0n; - // ctx.writeUInt64(timeAliveNumber); - // const written = await this.connection.write(ctx.getBuffer()); - // assert(written === ctx.tell()); - // } -} diff --git a/network/StageLinqDevices.ts b/network/StageLinqDevices.ts deleted file mode 100644 index 536aa5c..0000000 --- a/network/StageLinqDevices.ts +++ /dev/null @@ -1,326 +0,0 @@ -import { ConnectionInfo, IpAddress, PlayerStatus, ServiceMessage, StageLinqOptions } from '../types'; -import { EventEmitter } from 'events'; -import { NetworkDevice } from '.'; -import { Player } from '../devices/Player'; -import { sleep } from '../utils'; -import { FileTransfer, StateData, StateMap } from '../services'; -import { Logger } from '../LogEmitter'; -import { Databases } from '../Databases'; - -enum ConnectionStatus { CONNECTING, CONNECTED, FAILED }; - -interface StageLinqDevice { - networkDevice: NetworkDevice; - fileTransferService: FileTransfer | null; -}; - -// This time needs to be just long enough for discovery messages from all to -// come through. -const WAIT_FOR_DEVICES_TIMEOUT_MS = 3000; - -export declare interface StageLinqDevices { - on(event: 'trackLoaded', listener: (status: PlayerStatus) => void): this; - on(event: 'stateChanged', listener: (status: PlayerStatus) => void): this; - on(event: 'nowPlaying', listener: (status: PlayerStatus) => void): this; - on(event: 'connected', listener: (connectionInfo: ConnectionInfo) => void): this; - on(event: 'message', listener: (connectionInfo: ConnectionInfo, message: ServiceMessage) => void): this; - on(event: 'ready', listener: () => void): this; -} - -////////////////////////////////////////////////////////////////////////////// - -/** - * Handle connecting and disconnecting from discovered devices on the - * StageLinq network. - */ -export class StageLinqDevices extends EventEmitter { - - private _databases: Databases; - private devices: Map = new Map(); - private discoveryStatus: Map = new Map(); - private options: StageLinqOptions; - - private deviceWatchTimeout: NodeJS.Timeout | null = null; - private stateMapCallback: { connectionInfo: ConnectionInfo, networkDevice: NetworkDevice }[] = []; - - constructor(options: StageLinqOptions) { - super(); - this.options = options; - this._databases = new Databases(); - this.waitForAllDevices = this.waitForAllDevices.bind(this); - this.waitForAllDevices(); - } - - /** - * Handle incoming discovery messages from the StageLinq network - * - * @param connectionInfo Connection info. - */ - async handleDevice(connectionInfo: ConnectionInfo) { - Logger.silly(this.showDiscoveryStatus(connectionInfo)); - - // Ignore this discovery message if we've already connected to it, - // are still connecting, if it has failed, or if it's blacklisted. - if (this.isConnected(connectionInfo) - || this.isConnecting(connectionInfo) - || this.isFailed(connectionInfo) - || this.isIgnored(connectionInfo)) return; - - this.connectToDevice(connectionInfo); - } - - /** - * Disconnect from all connected devices - */ - disconnectAll() { - for (const device of this.devices.values()) { - device.networkDevice.disconnect(); - } - } - - get databases() { - return this._databases; - } - - async downloadFile(deviceId: string, path: string) { - if (this.options.enableFileTranfer) { - const device = this.devices.get(deviceId); - // Wait until FileTransfer.getFile is free - await device.fileTransferService.waitTillAvailable(); - const file = await device.fileTransferService.getFile(path); - return file; - } else { - const err = `File transfer service is not enabled. Cannot download ${path}` - Logger.error(err); - throw new Error(err); - } - } - - //////////////////////////////////////////////////////////////////////////// - - /** - * Waits for all devices to be connected with databases downloaded - * then connects to the StateMap. - * - * Explained: - * - * Why wait for all devices? Because a race condition exists when using the - * database methods. - * - * If there are two SC6000 players on the network both will be sending - * broadcast packets and so their StateMap can be initialized at any time - * in any order. - * - * Assume you have player 1 and player 2 linked. Player 2 has a track that - * is loaded from a USB drive plugged into player 1. Player 2 will be - * ready before Player 1 because Player 1 will still be downloading a large - * database. The race condition is if you try to read from the database on - * the track that is plugged into Player 1 that isn't ready yet. - * - * This method prevents that by waiting for both players to connect and - * have their databases loaded before initializing the StateMap. - * - */ - private waitForAllDevices() { - Logger.log('Start watching for devices ...'); - this.deviceWatchTimeout = setInterval(async () => { - // Check if any devices are still connecting. - const values = Array.from(this.discoveryStatus.values()); - const foundDevices = values.length >= 1; - const allConnected = !values.includes(ConnectionStatus.CONNECTING); - const entries = Array.from(this.discoveryStatus.entries()); - Logger.debug(`Waiting devices: ${JSON.stringify(entries)}`); - - if (foundDevices && allConnected) { - Logger.log('All devices found!'); - Logger.debug(`Devices found: ${values.length} ${JSON.stringify(entries)}`); - clearInterval(this.deviceWatchTimeout); - for (const cb of this.stateMapCallback) { - this.setupStateMap(cb.connectionInfo, cb.networkDevice); - } - this.emit('ready'); - } else { - Logger.log(`Waiting for devices ...`); - } - }, WAIT_FOR_DEVICES_TIMEOUT_MS); - } - - /** - * Attempt to connect to a device. Retry if necessary. - * - * @param connectionInfo Connection info - * @returns - */ - private async connectToDevice(connectionInfo: ConnectionInfo) { - - // Mark this device as connecting. - this.discoveryStatus.set(this.deviceId(connectionInfo), ConnectionStatus.CONNECTING); - - let attempt = 1; - while (attempt < this.options.maxRetries) { - try { - - // Connect to the device. - Logger.info(`Connecting to ${this.deviceId(connectionInfo)}. ` + - `Attempt ${attempt}/${this.options.maxRetries}`); - const networkDevice = new NetworkDevice(connectionInfo); - await networkDevice.connect(); - - // Setup file transfer service - await this.setupFileTransferService(networkDevice, connectionInfo); - - // Download the database - if (this.options.enableFileTranfer && this.options.downloadDbSources) { - await this.downloadDatabase(networkDevice, connectionInfo); - } - - // Setup other services that should be initialized before StateMap here. - - // StateMap will be initialized after all devices have completed - // this method. In other words, StateMap will initialize - // after all entries in this.discoveryStatus return - // ConnectionStatus.CONNECTED - - // Append to the list of states we need to setup later. - this.stateMapCallback.push({ connectionInfo, networkDevice }); - - // Mark this device as connected. - this.discoveryStatus.set(this.deviceId(connectionInfo), ConnectionStatus.CONNECTED); - this.emit('connected', connectionInfo); - - return; // Don't forget to return! - } catch(e) { - - // Failed connection. Sleep then retry. - Logger.warn(`Could not connect to ${this.deviceId(connectionInfo)} ` + - `(${attempt}/${this.options.maxRetries}): ${e}`); - attempt += 1; - sleep(500); - } - } - // We failed 3 times. Throw exception. - this.discoveryStatus.set(this.deviceId(connectionInfo), ConnectionStatus.FAILED); - throw new Error(`Could not connect to ${this.deviceId(connectionInfo)}`); - } - - private async setupFileTransferService(networkDevice: NetworkDevice, connectionInfo: ConnectionInfo) { - const sourceId = this.sourceId(connectionInfo); - - if (this.options.enableFileTranfer) { - Logger.info(`Starting file transfer for ${this.deviceId(connectionInfo)}`); - const fileTransferService = await networkDevice.connectToService(FileTransfer); - this.devices.set(`net://${sourceId}`, { - networkDevice: networkDevice, - fileTransferService: fileTransferService - }); - } else { - this.devices.set(`net://${sourceId}`, { - networkDevice: networkDevice, - fileTransferService: null - }); - } - - - } - - /** - * Download databases from the device. - * - * @param connectionInfo Connection info - * @returns - */ - private async downloadDatabase(networkDevice: NetworkDevice, connectionInfo: ConnectionInfo) { - const sources = await this.databases.downloadSourcesFromDevice(connectionInfo, networkDevice); - Logger.debug(`Database sources: ${sources.join(', ')}`); - Logger.debug(`Database download complete for ${connectionInfo.source}`); - } - - private sourceId(connectionInfo: ConnectionInfo) { - return /(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/i - .exec(Buffer.from(connectionInfo.token).toString('hex')).splice(1).join('-'); - } - - /** - * Setup stateMap. - * - * @param connectionInfo Connection info - * @param networkDevice Network device - */ - private async setupStateMap(connectionInfo: ConnectionInfo, networkDevice: NetworkDevice) { - // Setup StateMap - Logger.debug(`Setting up stateMap for ${connectionInfo.address}`); - - const stateMap = await networkDevice.connectToService(StateMap); - stateMap.on('message', (data) => { - this.emit('message', connectionInfo, data) - }); - - // Setup Player - const player = new Player({ - stateMap: stateMap, - address: connectionInfo.address, - port: connectionInfo.port, - deviceId: this.sourceId(connectionInfo) - }); - - player.on('trackLoaded', (status) => { - this.emit('trackLoaded', status); - }); - - player.on('stateChanged', (status) => { - this.emit('stateChanged', status); - }); - - player.on('nowPlaying', (status) => { - this.emit('nowPlaying', status); - }); - } - - private deviceId(device: ConnectionInfo) { - return `${device.address}:${device.port}:` + - `[${device.source}/${device.software.name}]`; - } - - private isConnecting(device: ConnectionInfo) { - return this.discoveryStatus.get(this.deviceId(device)) - === ConnectionStatus.CONNECTING; - } - - private isConnected(device: ConnectionInfo) { - return this.discoveryStatus.get(this.deviceId(device)) - === ConnectionStatus.CONNECTED; - } - - private isFailed(device: ConnectionInfo) { - return this.discoveryStatus.get(this.deviceId(device)) - === ConnectionStatus.FAILED; - } - - private isIgnored(device: ConnectionInfo) { - return ( - device.source === this.options.actingAs.source - || device.software.name === 'OfflineAnalyzer' - || /^SoundSwitch/i.test(device.software.name) - || /^Resolume/i.test(device.software.name) - || device.software.name === 'JM08' // Ignore X1800/X1850 mixers - || device.software.name === 'SSS0' // Ignore SoundSwitchEmbedded on players - ) - } - - private isDeviceSeen(device: ConnectionInfo) { - return this.discoveryStatus.has(device.address); - } - - private showDiscoveryStatus(device: ConnectionInfo) { - let msg = `Discovery: ${this.deviceId(device)} `; - - if (!this.isDeviceSeen) return msg += '(NEW)'; - if (this.isIgnored(device)) return msg += '(IGNORED)'; - return msg += ( - this.isConnecting(device) ? '(CONNECTING)' - : this.isConnected(device) ? '(CONNECTED)' - : this.isFailed(device) ? '(FAILED)' - : '(NEW)'); - } - -} \ No newline at end of file diff --git a/network/StageLinqListener.ts b/network/StageLinqListener.ts deleted file mode 100644 index 89dbea4..0000000 --- a/network/StageLinqListener.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ConnectionInfo } from '../types'; -import { createSocket, RemoteInfo } from 'dgram'; -import { LISTEN_PORT, DISCOVERY_MESSAGE_MARKER } from '../types/common'; -import { ReadContext } from '../utils/ReadContext'; -import { strict as assert } from 'assert'; - -type DeviceDiscoveryCallback = (info: ConnectionInfo) => void; - -/** - * Continuously listens for devices to announce themselves. When they do, - * execute a callback. - */ -export class StageLinqListener { - - /** - * Listen for new devices on the network and callback when a new one is found. - * @param callback Callback when new device is discovered. - */ - listenForDevices(callback: DeviceDiscoveryCallback) { - - const client = createSocket({type: 'udp4', reuseAddr: true}); - client.on('message', (p_announcement: Uint8Array, p_remote: RemoteInfo) => { - const ctx = new ReadContext(p_announcement.buffer, false); - const result = this.readConnectionInfo(ctx, p_remote.address); - assert(ctx.tell() === p_remote.size); - callback(result); - }); - client.bind(LISTEN_PORT); - } - - private readConnectionInfo(p_ctx: ReadContext, p_address: string): ConnectionInfo { - const magic = p_ctx.getString(4); - if (magic !== DISCOVERY_MESSAGE_MARKER) { - return null; - } - - const result: ConnectionInfo = { - token: p_ctx.read(16), - source: p_ctx.readNetworkStringUTF16(), - action: p_ctx.readNetworkStringUTF16(), - software: { - name: p_ctx.readNetworkStringUTF16(), - version: p_ctx.readNetworkStringUTF16(), - }, - port: p_ctx.readUInt16(), - address: p_address, - }; - assert(p_ctx.isEOF()); - return result; - } -} diff --git a/network/announce.ts b/network/announce.ts deleted file mode 100644 index 81da8a3..0000000 --- a/network/announce.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { - ANNOUNCEMENT_INTERVAL, - CONNECT_TIMEOUT, - DISCOVERY_MESSAGE_MARKER, - LISTEN_PORT, -} from '../types'; -import { createSocket, Socket as UDPSocket } from 'dgram'; -import { Logger } from '../LogEmitter'; -import { networkInterfaces } from 'os'; -import { strict as assert } from 'assert'; -import { subnet } from 'ip'; -import { WriteContext } from '../utils/WriteContext'; -import type { DiscoveryMessage } from '../types'; - -function findBroadcastIPs(): string[] { - const interfaces = Object.values(networkInterfaces()); - assert(interfaces.length); - const ips = []; - for (const i of interfaces) { - assert(i && i.length); - for (const entry of i) { - if (entry.family === 'IPv4' && entry.internal === false) { - const info = subnet(entry.address, entry.netmask); - ips.push(info.broadcastAddress); - } - } - } - return ips; -} - - -let announceClient: UDPSocket | null = null; -let announceTimer: NodeJS.Timer | null = null; - -function writeDiscoveryMessage(p_ctx: WriteContext, p_message: DiscoveryMessage): number { - let written = 0; - written += p_ctx.writeFixedSizedString(DISCOVERY_MESSAGE_MARKER); - written += p_ctx.write(p_message.token); - written += p_ctx.writeNetworkStringUTF16(p_message.source); - written += p_ctx.writeNetworkStringUTF16(p_message.action); - written += p_ctx.writeNetworkStringUTF16(p_message.software.name); - written += p_ctx.writeNetworkStringUTF16(p_message.software.version); - written += p_ctx.writeUInt16(p_message.port); - return written; -} - -async function initUdpSocket(): Promise { - return new Promise((resolve, reject) => { - try { - const client = createSocket({type: 'udp4', reuseAddr: true}); - client.bind(); // we need to bind to a random port in order to enable broadcasting - client.on('listening', () => { - client.setBroadcast(true); // needs to be true in order to UDP multicast on MacOS - resolve(client); - }); - } catch (err) { - Logger.error(`Failed to create UDP socket for announcing: ${err}`); - reject(err); - } - }); -} - -async function broadcastMessage(p_message: Uint8Array): Promise { - const ips = findBroadcastIPs(); - assert(ips.length > 0, 'No broadcast IPs have been found'); - - const send = async function (p_ip: string): Promise { - return new Promise((resolve, reject) => { - setTimeout(() => { - reject(new Error('Failed to send announcement')); - }, CONNECT_TIMEOUT); - - announceClient.send(p_message, LISTEN_PORT, p_ip, () => { - // Logger.log('UDP message sent to ' + p_ip); - resolve(); - }); - }); - }; - - const promises = ips.map((ip) => send(ip)); - await Promise.all(promises); -} - -export async function unannounce(message: DiscoveryMessage): Promise { - if (!announceTimer) { - Logger.warn('Announce timer has not started.'); - return; - } - assert(announceTimer); - clearInterval(announceTimer); - announceTimer = null; - const ctx = new WriteContext(); - writeDiscoveryMessage(ctx, message); - const msg = new Uint8Array(ctx.getBuffer()); - await broadcastMessage(msg); - // Logger.info("Unannounced myself"); -} - -export async function announce(message: DiscoveryMessage): Promise { - if (announceTimer) { - Logger.log('Already has an announce timer.') - return; - } - - if (!announceClient) announceClient = await initUdpSocket(); - - const ctx = new WriteContext(); - writeDiscoveryMessage(ctx, message); - const msg = new Uint8Array(ctx.getBuffer()); - - // Immediately announce myself - await broadcastMessage(msg); - - announceTimer = setInterval(broadcastMessage, ANNOUNCEMENT_INTERVAL, msg); - Logger.info("Announced myself"); -} - -export interface DiscoveryMessageOptions { - name: string; - version: string; - source: string; - token: Uint8Array; -}; - -export function createDiscoveryMessage(action: string, discoveryMessageOptions: DiscoveryMessageOptions) { - const msg: DiscoveryMessage = { - action: action, - port: 0, - software: { - name: discoveryMessageOptions.name, - version: discoveryMessageOptions.version - }, - source: discoveryMessageOptions.source, - token: discoveryMessageOptions.token - }; - return msg; -} diff --git a/network/index.ts b/network/index.ts deleted file mode 100644 index 25d4180..0000000 --- a/network/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './announce'; -export * from './NetworkDevice'; -export * from './StageLinqDevices' -export * from './StageLinqListener'; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8a55b8f..23cc7a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,47 +1,58 @@ { - "name": "stagelinq", - "version": "1.0.7", - "lockfileVersion": 2, + "name": "StageLinqJS", + "version": "2.0.0-Beta", + "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "stagelinq", - "version": "1.0.7", + "name": "StageLinqJS", + "version": "2.0.0-Beta", "license": "GNU GPLv3", "dependencies": { - "better-sqlite3": "^7.5.0", + "@types/filesystem": "^0.0.32", + "@types/uuid": "^9.0.1", + "better-sqlite3": "^7.6.2", "console-stamp": "^3.0.3", - "file-type": "^16.5.3", "ip": "^1.1.5", - "minimist": "^1.2.5", - "promise-socket": "^7.0.0" + "minimist": "^1.2.5" }, "devDependencies": { "@types/assert": "^1.5.5", - "@types/better-sqlite3": "^7.4.0", + "@types/better-sqlite3": "^7.6.3", "@types/ip": "^1.1.0", - "@types/minimist": "^1.2.2", - "@types/node": "^16.4.0", + "@types/node": "^18.15.11", "prettier": "^2.5.1", - "typescript": "^4.6.2" + "typedoc": "^0.23.28", + "typescript": "^5.0.3" } }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, "node_modules/@types/assert": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.5.5.tgz", - "integrity": "sha512-myz5KWf6ox66Ou1m0KiLZpitk7W6Vly2LFRx7AXHSLeMUM6bmDIStIBk0xd7I2vXcAQEuhegdpjPuypmP5ui0Q==", + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.5.6.tgz", + "integrity": "sha512-Y7gDJiIqb9qKUHfBQYOWGngUpLORtirAVPuj/CWJrU2C6ZM4/y3XLwuwfGMF8s7QzW746LQZx23m0+1FSgjfug==", "dev": true }, "node_modules/@types/better-sqlite3": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.4.0.tgz", - "integrity": "sha512-tmSORlztb2cdWZDy4V81mRDgL+q7bd+ext4pI+Wj8EtJ5EHIZ6v7yiWbJ6A5eKVtoz77EsBEm7amwAzfqR/kAw==", - "dev": true + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.3.tgz", + "integrity": "sha512-YS64N9SNDT/NAvou3QNdzAu3E2om/W/0dhORimtPGLef+zSK5l1vDzfsWb4xgXOgfhtOI5ZDTRxnvRPb22AIVQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/filesystem": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.32.tgz", + "integrity": "sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ==", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.29.tgz", + "integrity": "sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==" }, "node_modules/@types/ip": { "version": "1.1.0", @@ -52,25 +63,22 @@ "@types/node": "*" } }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, "node_modules/@types/node": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.0.tgz", - "integrity": "sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg==", + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", "dev": true }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } + "node_modules/@types/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==" + }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", + "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", + "dev": true }, "node_modules/ansi-styles": { "version": "4.3.0", @@ -86,19 +94,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "node_modules/are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/base64-js": { "version": "1.5.1", @@ -120,13 +120,13 @@ ] }, "node_modules/better-sqlite3": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.5.0.tgz", - "integrity": "sha512-6FdG9DoytYGDhLW7VWW1vxjEz7xHkqK6LnaUQYA8d6GHNgZhu9PFX2xwKEEnSBRoT1J4PjTUPeg217ShxNmuPg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.6.2.tgz", + "integrity": "sha512-S5zIU1Hink2AH4xPsN0W43T1/AJ5jrPh7Oy07ocuW/AKYYY02GWzz9NH0nbSMn/gw6fDZ5jZ1QsHt1BXAwJ6Lg==", "hasInstallScript": true, "dependencies": { "bindings": "^1.5.0", - "prebuild-install": "^7.0.0" + "prebuild-install": "^7.1.0" } }, "node_modules/bindings": { @@ -147,17 +147,13 @@ "readable-stream": "^3.4.0" } }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "balanced-match": "^1.0.0" } }, "node_modules/buffer": { @@ -184,9 +180,9 @@ } }, "node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -203,14 +199,6 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -227,42 +215,22 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, "node_modules/console-stamp": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-3.0.3.tgz", - "integrity": "sha512-6ltMcMEVDHb1bqb+qaVfCX7Vf3vEkfZEeKyReG1ny45Rv6YJynCcdv94j7whNVfxj/4/3Ji/QBHY6p4JI51Ucw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-3.1.1.tgz", + "integrity": "sha512-NTbqQ9X57xffQKTJbAm4h/ro7JNR2uD3369NeTjmRdfPJ2QmkmCUnMvC1QSxZPQOof3WPrkuA6DQV5+n35ZiIA==", "dependencies": { - "chalk": "^4.1.1", - "dateformat": "^4.5.1" + "chalk": "^4.1.2", + "dateformat": "^4.6.3" }, "engines": { - "node": ">=10" - } - }, - "node_modules/core-js": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.15.2.tgz", - "integrity": "sha512-tKs41J7NJVuaya8DxIOCnl8QuPHx5/ZVbFo1oKgVl1qHFBBrDctzQGtuLjPpRdNTWmKPH6oEvgN/MUID+l485Q==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "node": ">=12" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, "node_modules/dateformat": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.5.1.tgz", - "integrity": "sha512-OD0TZ+B7yP7ZgpJf5K2DIbj3FZvFvxgFUuaqA/V5zTjAtAAXZ1E8bktHxmAGs4x5b7PflqA9LeQ84Og7wYtF7Q==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", "engines": { "node": "*" } @@ -289,11 +257,6 @@ "node": ">=4.0.0" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, "node_modules/detect-libc": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", @@ -318,22 +281,6 @@ "node": ">=6" } }, - "node_modules/file-type": { - "version": "16.5.3", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.3.tgz", - "integrity": "sha512-uVsl7iFhHSOY4bEONLlTK47iAHtNsFHWP5YE4xJfZ4rnX7S1Q3wce09XgqSC7E/xh8Ncv/be1lNoyprlUH/x6A==", - "dependencies": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -344,25 +291,10 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" }, "node_modules/has-flag": { "version": "4.0.0", @@ -372,11 +304,6 @@ "node": ">=8" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -407,25 +334,15 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true }, "node_modules/lru-cache": { "version": "6.0.0", @@ -438,6 +355,24 @@ "node": ">=10" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -449,10 +384,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/minimatch": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.5.tgz", + "integrity": "sha512-OzOamaOmNBJZUv2qqY1OSWa+++4YPpOkLgkc0w30Oov5ufKlWWXnFUl0l4dgmSv5Shq/zRVkEOXAe2NaqO4l5Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mkdirp-classic": { "version": "0.5.3", @@ -465,9 +418,9 @@ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, "node_modules/node-abi": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz", - "integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.34.0.tgz", + "integrity": "sha512-O5sNsdgxptez/bSXk2CfpTcVu4yTiFW1YcMHIVn2uAY8MksXWQeReMx63krFrj/QSyjRJ5/jIBkWvJ3/ZimdcA==", "dependencies": { "semver": "^7.3.5" }, @@ -475,57 +428,18 @@ "node": ">=10" } }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dependencies": { "wrappy": "1" } }, - "node_modules/peek-readable": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.0.1.tgz", - "integrity": "sha512-7qmhptnR0WMSpxT5rMHG9bW/mYSR1uqaPFj2MHvT+y/aOUu6msJijpKt5SkTDKySwg65OWG2JwTMBlgcbwMHrQ==", - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/prebuild-install": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz", - "integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -534,7 +448,6 @@ "mkdirp-classic": "^0.5.3", "napi-build-utils": "^1.0.1", "node-abi": "^3.3.0", - "npmlog": "^4.0.1", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", @@ -549,64 +462,18 @@ } }, "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/promise-duplex": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-duplex/-/promise-duplex-6.0.0.tgz", - "integrity": "sha512-ZL7rquzjTFzInDBeWYcsT+qddolNvzigahk6MI6qLSbQvlyRRCJkU3JztgaVunzvkH28smRa2Qu/cY9RXtSkgA==", - "dependencies": { - "core-js": "^3.6.5", - "promise-readable": "^6.0.0", - "promise-writable": "^6.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/promise-readable": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-readable/-/promise-readable-6.0.0.tgz", - "integrity": "sha512-5NxtmUswijvX5cAM0zPSy6yiCXH/eKBpiiBq6JfAUrmngMquMbzcBhF2qA+ocs4rYYKdvAfv3cOvZxADLtL1CA==", - "dependencies": { - "core-js": "^3.6.5" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/promise-socket": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/promise-socket/-/promise-socket-7.0.0.tgz", - "integrity": "sha512-Oic9BrxmcHOPEnzKp2Js+ehFyvsbd0WxsE5khweCTHuRvdzbXjHUZmSDT6F9TW8SIkAJ0lCzoHjMYnb0WQJPiw==", - "dependencies": { - "promise-duplex": "^6.0.0", - "tslib": "^2.0.1" }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/promise-writable": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-writable/-/promise-writable-6.0.0.tgz", - "integrity": "sha512-b81zre/itgJFS7dwWzIdKNVVqvLiUxYRS/wolUB0H1YY/tAaS146XGKa4Q/5wCbsnXLyn0MCeV6f8HHe4iUHLg==", - "engines": { - "node": ">=10.0.0" + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/pump": { @@ -633,38 +500,9 @@ } }, "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -675,14 +513,28 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -693,15 +545,17 @@ "node": ">=10" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "node_modules/shiki": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.1.tgz", + "integrity": "sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } }, "node_modules/simple-concat": { "version": "1.0.1", @@ -747,61 +601,21 @@ } }, "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "safe-buffer": "~5.2.0" } }, "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "engines": { "node": ">=0.10.0" } }, - "node_modules/strtok3": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.2.4.tgz", - "integrity": "sha512-GO8IcFF9GmFDvqduIspUBwCzCbqzegyVKIsSymcMgiZKeCfrN9SowtUoi8+b59WZMAjIzVZic/Ft97+pynR3Iw==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -839,745 +653,77 @@ "node": ">=6" } }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "safe-buffer": "^5.0.1" }, "engines": { - "node": ">= 6" + "node": "*" } }, - "node_modules/token-types": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.1.1.tgz", - "integrity": "sha512-hD+QyuUAyI2spzsI0B7gf/jJ2ggR4RjkAo37j3StuePhApJUwcWDjnHDOFdIWYSwNR28H14hpwm4EI+V1Ted1w==", + "node_modules/typedoc": { + "version": "0.23.28", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.28.tgz", + "integrity": "sha512-9x1+hZWTHEQcGoP7qFmlo4unUoVJLB0H/8vfO/7wqTnZxg4kPuji9y3uRzEu0ZKez63OJAUmiGhUrtukC6Uj3w==", + "dev": true, "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=10" + "lunr": "^2.3.9", + "marked": "^4.2.12", + "minimatch": "^7.1.3", + "shiki": "^0.14.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dependencies": { - "safe-buffer": "^5.0.1" + "bin": { + "typedoc": "bin/typedoc" }, "engines": { - "node": "*" + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x" } }, "node_modules/typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", + "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } - }, - "dependencies": { - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, - "@types/assert": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.5.5.tgz", - "integrity": "sha512-myz5KWf6ox66Ou1m0KiLZpitk7W6Vly2LFRx7AXHSLeMUM6bmDIStIBk0xd7I2vXcAQEuhegdpjPuypmP5ui0Q==", - "dev": true - }, - "@types/better-sqlite3": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.4.0.tgz", - "integrity": "sha512-tmSORlztb2cdWZDy4V81mRDgL+q7bd+ext4pI+Wj8EtJ5EHIZ6v7yiWbJ6A5eKVtoz77EsBEm7amwAzfqR/kAw==", - "dev": true - }, - "@types/ip": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.0.tgz", - "integrity": "sha512-dwNe8gOoF70VdL6WJBwVHtQmAX4RMd62M+mAB9HQFjG1/qiCLM/meRy95Pd14FYBbEDwCq7jgJs89cHpLBu4HQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, - "@types/node": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.0.tgz", - "integrity": "sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "better-sqlite3": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.5.0.tgz", - "integrity": "sha512-6FdG9DoytYGDhLW7VWW1vxjEz7xHkqK6LnaUQYA8d6GHNgZhu9PFX2xwKEEnSBRoT1J4PjTUPeg217ShxNmuPg==", - "requires": { - "bindings": "^1.5.0", - "prebuild-install": "^7.0.0" - } - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, - "console-stamp": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-3.0.3.tgz", - "integrity": "sha512-6ltMcMEVDHb1bqb+qaVfCX7Vf3vEkfZEeKyReG1ny45Rv6YJynCcdv94j7whNVfxj/4/3Ji/QBHY6p4JI51Ucw==", - "requires": { - "chalk": "^4.1.1", - "dateformat": "^4.5.1" - } - }, - "core-js": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.15.2.tgz", - "integrity": "sha512-tKs41J7NJVuaya8DxIOCnl8QuPHx5/ZVbFo1oKgVl1qHFBBrDctzQGtuLjPpRdNTWmKPH6oEvgN/MUID+l485Q==" - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "dateformat": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.5.1.tgz", - "integrity": "sha512-OD0TZ+B7yP7ZgpJf5K2DIbj3FZvFvxgFUuaqA/V5zTjAtAAXZ1E8bktHxmAGs4x5b7PflqA9LeQ84Og7wYtF7Q==" - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "requires": { - "mimic-response": "^3.1.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - }, - "file-type": { - "version": "16.5.3", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.3.tgz", - "integrity": "sha512-uVsl7iFhHSOY4bEONLlTK47iAHtNsFHWP5YE4xJfZ4rnX7S1Q3wce09XgqSC7E/xh8Ncv/be1lNoyprlUH/x6A==", - "requires": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, - "node-abi": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz", - "integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==", - "requires": { - "semver": "^7.3.5" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "peek-readable": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.0.1.tgz", - "integrity": "sha512-7qmhptnR0WMSpxT5rMHG9bW/mYSR1uqaPFj2MHvT+y/aOUu6msJijpKt5SkTDKySwg65OWG2JwTMBlgcbwMHrQ==" - }, - "prebuild-install": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz", - "integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==", - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "promise-duplex": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-duplex/-/promise-duplex-6.0.0.tgz", - "integrity": "sha512-ZL7rquzjTFzInDBeWYcsT+qddolNvzigahk6MI6qLSbQvlyRRCJkU3JztgaVunzvkH28smRa2Qu/cY9RXtSkgA==", - "requires": { - "core-js": "^3.6.5", - "promise-readable": "^6.0.0", - "promise-writable": "^6.0.0" - } - }, - "promise-readable": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-readable/-/promise-readable-6.0.0.tgz", - "integrity": "sha512-5NxtmUswijvX5cAM0zPSy6yiCXH/eKBpiiBq6JfAUrmngMquMbzcBhF2qA+ocs4rYYKdvAfv3cOvZxADLtL1CA==", - "requires": { - "core-js": "^3.6.5" - } - }, - "promise-socket": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/promise-socket/-/promise-socket-7.0.0.tgz", - "integrity": "sha512-Oic9BrxmcHOPEnzKp2Js+ehFyvsbd0WxsE5khweCTHuRvdzbXjHUZmSDT6F9TW8SIkAJ0lCzoHjMYnb0WQJPiw==", - "requires": { - "promise-duplex": "^6.0.0", - "tslib": "^2.0.1" - } - }, - "promise-writable": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-writable/-/promise-writable-6.0.0.tgz", - "integrity": "sha512-b81zre/itgJFS7dwWzIdKNVVqvLiUxYRS/wolUB0H1YY/tAaS146XGKa4Q/5wCbsnXLyn0MCeV6f8HHe4iUHLg==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "requires": { - "readable-stream": "^3.6.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "strtok3": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.2.4.tgz", - "integrity": "sha512-GO8IcFF9GmFDvqduIspUBwCzCbqzegyVKIsSymcMgiZKeCfrN9SowtUoi8+b59WZMAjIzVZic/Ft97+pynR3Iw==", - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "token-types": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.1.1.tgz", - "integrity": "sha512-hD+QyuUAyI2spzsI0B7gf/jJ2ggR4RjkAo37j3StuePhApJUwcWDjnHDOFdIWYSwNR28H14hpwm4EI+V1Ted1w==", - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - } - }, - "tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } } } diff --git a/package.json b/package.json index e82b3da..43b04c6 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "stagelinq", - "version": "1.0.9", + "name": "StageLinqJS", + "version": "2.0.0-Beta", "description": "Typescript library to connect to Denon StageLinq devices", - "homepage": "https://github.com/chrisle/StageLinq", + "homepage": "https://github.com/honusz/StageLinq", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node dist/cli/index.js", @@ -10,26 +10,26 @@ "watch": "tsc --build tsconfig.json -w", "prepublish": "tsc --build tsconfig.json" }, - "author": "Chris Le (TRIODE)", + "author": "honusz", "license": "GNU GPLv3", "main": "dist/index.js", "types": "dist/index.d.ts", "files": ["/dist"], "dependencies": { - "better-sqlite3": "^7.5.0", + "@types/filesystem": "^0.0.32", + "@types/uuid": "^9.0.1", + "better-sqlite3": "^7.6.2", "console-stamp": "^3.0.3", - "file-type": "^16.5.3", "ip": "^1.1.5", - "minimist": "^1.2.5", - "promise-socket": "^7.0.0" + "minimist": "^1.2.5" }, "devDependencies": { "@types/assert": "^1.5.5", - "@types/better-sqlite3": "^7.4.0", + "@types/better-sqlite3": "^7.6.3", "@types/ip": "^1.1.0", - "@types/minimist": "^1.2.2", - "@types/node": "^16.4.0", + "@types/node": "^18.15.11", "prettier": "^2.5.1", - "typescript": "^4.6.2" + "typedoc": "^0.23.28", + "typescript": "^5.0.3" } } diff --git a/services/BeatInfo.ts b/services/BeatInfo.ts new file mode 100644 index 0000000..970c64b --- /dev/null +++ b/services/BeatInfo.ts @@ -0,0 +1,179 @@ +import { strict as assert } from 'assert'; +import { ReadContext, WriteContext } from '../utils'; +import { Service } from './Service'; +import type { ServiceMessage, DeviceId } from '../types'; +import { EventEmitter } from 'events'; + + +type BeatCallback = (n: BeatData) => void; + +type BeatOptions = { + everyNBeats: number, +} + +interface deckBeatData { + beat: number; + totalBeats: number; + BPM: number; + samples?: number; +} + +export interface BeatData { + service: BeatInfo; + deviceId: DeviceId; + clock: bigint; + deckCount: number; + deck: deckBeatData[]; +} + +export declare interface BeatInfo { + on(event: 'beatMessage', listener: (message: ServiceMessage) => void): this; +} + +export class BeatInfo extends Service { + public readonly name = "BeatInfo"; + static #instances: Map = new Map() + static readonly emitter: EventEmitter = new EventEmitter(); + + #userBeatCallback: BeatCallback = null; + #userBeatOptions: BeatOptions = null; + #currentBeatData: BeatData = null; + protected isBufferedService: boolean = true; + + /** + * BeatInfo Service Class + * @constructor + * @param {DeviceId} [deviceId] + */ + + constructor(deviceId: DeviceId) { + super(deviceId) + BeatInfo.#instances.set(this.deviceId.string, this) + this.addListener('connection', () => this.instanceListener('newDevice', this)); + this.addListener('beatMessage', (data: BeatData) => this.instanceListener('beatMessage', data)); + this.addListener(`data`, (ctx: ReadContext) => this.parseData(ctx)); + this.addListener(`message`, (message: ServiceMessage) => this.messageHandler(message)); + } + + protected instanceListener(eventName: string, ...args: any) { + BeatInfo.emitter.emit(eventName, ...args) + } + + static getInstances(): string[] { + return [...BeatInfo.#instances.keys()] + } + + deleteDevice(deviceId: DeviceId) { + BeatInfo.#instances.delete(deviceId.string) + } + /** + * Get current BeatData + * @returns {BeatData} + */ + getBeatData(): BeatData { + return this.#currentBeatData; + } + + /** + * Start BeatInfo + * @param {BeatOptions} options + * @param {BeatCallback} [beatCB] Optional User callback + */ + public startBeatInfo(options: BeatOptions, beatCB?: BeatCallback) { + if (beatCB) { + this.#userBeatCallback = beatCB; + } + this.#userBeatOptions = options; + this.sendBeatInfoRequest(); + } + + /** + * Send Subscribe to BeatInfo message to Device + * @param {Socket} socket + */ + private async sendBeatInfoRequest() { + const ctx = new WriteContext(); + ctx.write(new Uint8Array([0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0])) + await this.write(ctx); + } + + private parseData(ctx: ReadContext): ServiceMessage { + assert(ctx.sizeLeft() > 72); + let id = ctx.readUInt32() + const clock = ctx.readUInt64(); + const deckCount = ctx.readUInt32(); + let deck: deckBeatData[] = []; + for (let i = 0; i < deckCount; i++) { + let deckData: deckBeatData = { + beat: ctx.readFloat64(), + totalBeats: ctx.readFloat64(), + BPM: ctx.readFloat64(), + } + deck.push(deckData); + } + for (let i = 0; i < deckCount; i++) { + deck[i].samples = ctx.readFloat64(); + } + assert(ctx.isEOF()) + const message = { + id: id, + message: { + service: this, + deviceId: this.deviceId, + clock: clock, + deckCount: deckCount, + deck: deck, + } + } + this.emit(`message`, message); + return message + } + + private messageHandler(data: ServiceMessage): void { + + function resCheck(res: number, prevBeat: number, currentBeat: number): boolean { + if (res === 0) { + return true + } + return (Math.floor(currentBeat / res) - Math.floor(prevBeat / res) >= 1) + || (Math.floor(prevBeat / res) - Math.floor(currentBeat / res) >= 1) + } + + if (!data || !data.message) { + return + } + + if (!this.#currentBeatData) { + this.#currentBeatData = data.message; + if (this.listenerCount('beatMessage')) { + this.emit('beatMessage', data.message); + } + if (this.#userBeatCallback) { + this.#userBeatCallback(data.message); + } + + } + + let hasUpdated = false; + + for (let i = 0; i < data.message.deckCount; i++) { + if (resCheck( + this.#userBeatOptions.everyNBeats, + this.#currentBeatData.deck[i].beat, + data.message.deck[i].beat)) { + hasUpdated = true; + } + } + + if (hasUpdated) { + if (this.listenerCount('beatMessage')) { + this.emit('beatMessage', data); + } + if (this.#userBeatCallback) { + this.#userBeatCallback(data.message); + } + } + this.#currentBeatData = data.message; + } + +} \ No newline at end of file diff --git a/services/Broadcast.ts b/services/Broadcast.ts new file mode 100644 index 0000000..78fc8e9 --- /dev/null +++ b/services/Broadcast.ts @@ -0,0 +1,80 @@ +import { EventEmitter } from 'events'; +import { ReadContext } from '../utils'; +import { ServiceMessage, DeviceId } from '../types'; +import { Service } from './Service'; +import { StageLinq } from '../StageLinq'; + +export type BroadcastMessage = { + databaseUuid: string; + trackId?: number | string; + listId?: number | string; + sessionId?: number | string; +}; + +export interface BroadcastData { + [key: string]: any; +} + +export class Broadcast extends Service { + public readonly name = 'Broadcast'; + protected readonly isBufferedService: boolean = false; + static readonly emitter: EventEmitter = new EventEmitter(); + + /** + * Broadcast Service Class + * @tag Experimental + * @param {DeviceId} deviceId + */ + constructor(deviceId: DeviceId) { + super(deviceId); + this.addListener(`data`, (ctx: ReadContext) => this.parseData(ctx)); + this.addListener(`message`, (message: ServiceMessage) => this.messageHandler(message)); + } + + private parseData(ctx: ReadContext): ServiceMessage { + const length = ctx.readUInt32(); + if (!length && ctx.sizeLeft()) { + const message = { + id: length, + message: { + deviceId: new DeviceId(ctx.read(16)), + name: ctx.readNetworkStringUTF16(), + port: ctx.readUInt16(), + sizeLeft: ctx.sizeLeft(), + }, + }; + this.emit(`message`, message); + return message; + } else { + const message = { + id: length, + message: { + json: ctx.getString(length), + sizeLeft: ctx.sizeLeft(), + }, + }; + this.emit(`message`, message); + return message; + } + } + + private messageHandler(data: ServiceMessage): void { + if (data?.id === 0) { + StageLinq.devices.emit('newService', this.device, this); + } + + if (data?.message?.json) { + const msg = JSON.parse(data.message.json.replace(/\./g, '')); + const key = Object.keys(msg).shift(); + const value = Object.values(msg).shift() as BroadcastMessage; + Broadcast.emitter.emit('message', this.deviceId, key, value); + if (Broadcast.emitter.listenerCount(value.databaseUuid)) { + Broadcast.emitter.emit(value.databaseUuid, key, value); + } + } + } + + protected instanceListener(eventName: string, ...args: any) { + Broadcast.emitter.emit(eventName, ...args); + } +} diff --git a/services/Directory.ts b/services/Directory.ts new file mode 100644 index 0000000..6a7161c --- /dev/null +++ b/services/Directory.ts @@ -0,0 +1,171 @@ +import { strict as assert } from 'assert'; +import { Logger } from '../LogEmitter'; +import { ReadContext, WriteContext } from '../utils'; +import { ServiceMessage, Units, DeviceId } from '../types'; +import { Socket } from 'net'; +import { StageLinq } from '../StageLinq'; +import { + Service, + StateMap, + FileTransfer, + BeatInfo, + TimeSynchronization, + Broadcast, +} from '../services' + + +enum MessageId { + ServicesAnnouncement = 0x0, + TimeStamp = 0x1, + ServicesRequest = 0x2, +} + +export interface DirectoryData { + deviceId: string; +} + + +export class Directory extends Service { + public readonly name = 'Directory'; + + protected readonly isBufferedService = false; + protected timeAlive: number; + + /** + * Directory Service Class + * @internal + */ + constructor() { + super() + this.addListener(`data`, (ctx: ReadContext, socket: Socket) => this.parseData(ctx, socket)); + this.addListener(`message`, (message: ServiceMessage) => this.messageHandler(message)); + } + + private parseData(ctx: ReadContext, socket: Socket): ServiceMessage { + if (ctx.sizeLeft() < 20) { + return + } + const id = ctx.readUInt32(); + const token = ctx.read(16); + if (!token) { + return + } + + this.deviceId = new DeviceId(token); + const deviceInfo = StageLinq.devices.device(this.deviceId)?.info + + + try { + switch (id) { + case MessageId.TimeStamp: + ctx.seek(16); + let timeAlive: bigint = 1n + if (ctx.sizeLeft() >= 8) { + timeAlive = ctx.readUInt64(); + this.timeAlive = Number(timeAlive / (1000n * 1000n * 1000n)); + } + + if (deviceInfo && deviceInfo.unit && deviceInfo.unit.type === 'MIXER') { + setTimeout(this.sendTimeStampReply, 1400, token, socket); + } + break; + case MessageId.ServicesAnnouncement: + const service = ctx.readNetworkStringUTF16(); + const port = ctx.readUInt16(); + Logger.silent(this.name, 'received ', service, port); + break; + case MessageId.ServicesRequest: + Logger.debug(`service request from ${this.deviceId.string}`) + this.sendServiceAnnouncement(this.deviceId, socket); + break; + default: + ctx.rewind() + Logger.silent(`${this.name} possible malformed data: ${ctx.readRemainingAsNewBuffer().toString('hex')}`); + break; + } + } catch (err) { + ctx.rewind(); + Logger.silent(`${this.name} possible malformed data: ${ctx.readRemainingAsNewBuffer().toString('hex')}`) + } + + const directoryData = { + id: id, + socket: socket, + deviceId: this.deviceId, + message: { + deviceId: this.deviceId.string + }, + }; + this.emit(`message`, directoryData); + return directoryData + } + + private messageHandler(directoryMsg: ServiceMessage): void { + if (!directoryMsg) { + Logger.silent(`${this.name} Empty Directory Message`) + } + } + + /////////// Private Methods + + private async getNewService(serviceName: string, deviceId: DeviceId): Promise> { + if (serviceName == "FileTransfer") return await StageLinq.startServiceListener(FileTransfer, deviceId) + if (serviceName == "StateMap") return await StageLinq.startServiceListener(StateMap, deviceId) + if (serviceName == "FileTransfer") return await StageLinq.startServiceListener(FileTransfer, deviceId) + if (serviceName == "BeatInfo") return await StageLinq.startServiceListener(BeatInfo, deviceId) + if (serviceName == "Broadcast") return await StageLinq.startServiceListener(Broadcast, deviceId) + if (serviceName == "TimeSynchronization") return await StageLinq.startServiceListener(TimeSynchronization, deviceId) + } + + /** + * Send Service announcement with list of Service:Port + * @param {DeviceId} deviceId + * @param {Socket} socket + */ + + private async sendServiceAnnouncement(deviceId: DeviceId, socket: Socket): Promise { + const ctx = new WriteContext(); + ctx.writeUInt32(MessageId.ServicesRequest); + ctx.write(StageLinq.options.actingAs.deviceId.array); + let services: InstanceType[] = [] + const device = await StageLinq.devices.getDevice(deviceId); + for (const serviceName of StageLinq.options.services) { + if (device && !!Units[device.info?.software?.name]) { + const service = await this.getNewService(serviceName, deviceId); + this.emit('newService', service); + services.push(service) + } + } + + for (const service of services) { + ctx.writeUInt32(MessageId.ServicesAnnouncement); + ctx.write(StageLinq.options.actingAs.deviceId.array); + ctx.writeNetworkStringUTF16(service.name); + ctx.writeUInt16(service.serverInfo.port); + Logger.debug(`${deviceId.string} Created new ${service.name} on port ${service.serverInfo.port}`); + } + + const msg = ctx.getBuffer(); + await socket.write(msg); + Logger.debug(`[${this.name}] sent ServiceAnnouncement to ${socket.remoteAddress}:${socket.remotePort}`); + } + + /** + * Send TimeStamp reply to Device + * @param {Uint8Array} token Token from recepient Device + */ + private async sendTimeStampReply(token: Uint8Array, socket: Socket) { + const ctx = new WriteContext(); + ctx.writeUInt32(MessageId.TimeStamp); + ctx.write(token); + ctx.write(StageLinq.options.actingAs.deviceId.array); + ctx.writeUInt64(0n); + const message = ctx.getBuffer(); + assert(message.length === 44); + await socket.write(message); + Logger.silly(`sent TimeStamp to ${socket.remoteAddress}:${socket.remotePort}`); + } + + protected instanceListener() { + } +} diff --git a/services/FileTransfer.ts b/services/FileTransfer.ts index cae797c..d7e9c9a 100644 --- a/services/FileTransfer.ts +++ b/services/FileTransfer.ts @@ -1,327 +1,650 @@ -import { DOWNLOAD_TIMEOUT } from '../types'; +import { EventEmitter } from 'events'; +import { strict as assert } from 'assert'; import { Logger } from '../LogEmitter'; -import { ReadContext } from '../utils/ReadContext'; +import { ReadContext, WriteContext, sleep } from '../utils'; import { Service } from './Service'; -import { sleep } from '../utils/sleep'; -import { strict as assert } from 'assert'; -import { WriteContext } from '../utils/WriteContext'; -import type { ServiceMessage, Source } from '../types'; +import type { ServiceMessage, DeviceId } from '../types'; +import { Source } from '../Sources' +import { StageLinq } from '../StageLinq'; +const MESSAGE_TIMEOUT = 5000; // in ms +const DOWNLOAD_TIMEOUT = 60000; // in ms const MAGIC_MARKER = 'fltx'; -export const CHUNK_SIZE = 4096; - -// FIXME: Strongly type this for all possible messages? -type FileTransferData = any; +const CHUNK_SIZE = 4096; + +export interface FileTransferData { + service: FileTransfer; + deviceId: DeviceId; + txid: number; + size?: number; + offset?: number; + sources?: string[]; + data?: Buffer; + signOff?: Uint8Array; +} enum MessageId { - TimeCode = 0x0, - FileStat = 0x1, - EndOfMessage = 0x2, - SourceLocations = 0x3, - FileTransferId = 0x4, - FileTransferChunk = 0x5, - Unknown0 = 0x8, - ServiceDisconnect = 0x9, + TimeCode = 0x0, + FileStat = 0x1, + EndOfMessage = 0x2, + SourceLocations = 0x3, + FileTransferId = 0x4, + FileTransferChunk = 0x5, + DataUpdate = 0x6, + Unknown0 = 0x8, + DeviceShutdown = 0x9, + RequestSources = 0x7d2, } -interface FileTransferProgress { - sizeLeft: number; - total: number; - bytesDownloaded: number; - percentComplete: number; +enum Action { + RequestStat = 0x7d1, + RequestSources = 0x7d2, + Unknown1 = 0x7d3, + RequestFileTransferId = 0x7d4, + RequestChunkRange = 0x7d5, + TransferComplete = 0x7d6, + WalMode = 0x7d9, +} + +export interface FileTransferProgress { + sizeLeft: number; + total: number; + bytesDownloaded: number; + percentComplete: number; } export declare interface FileTransfer { - on(event: 'fileTransferProgress', listener: (progress: FileTransferProgress) => void): this; + on(event: 'fileTransferProgress', listener: (source: Source, fileName: string, txid: number, progress: FileTransferProgress) => void): this; + on(event: 'fileTransferComplete', listener: (source: Source, fileName: string, txid: number) => void): this; } -export class FileTransfer extends Service { - private receivedFile: WriteContext = null; - private _available: boolean = true; - - async init() {} - - protected parseData(p_ctx: ReadContext): ServiceMessage { - const check = p_ctx.getString(4); - assert(check === MAGIC_MARKER); - const code = p_ctx.readUInt32(); - - // If first 4 bytes are non-zero, a timecode is sent - if (code > 0) { - assert(p_ctx.sizeLeft() === 8); - const id = p_ctx.readUInt32(); - assert(id === 0x07d2); - assert(p_ctx.readUInt32() === 0); - return { - id: MessageId.TimeCode, - message: { - timecode: code, - }, - }; - } - - // Else - const messageId: MessageId = p_ctx.readUInt32(); - switch (messageId) { - case MessageId.SourceLocations: { - const sources: string[] = []; - const sourceCount = p_ctx.readUInt32(); - for (let i = 0; i < sourceCount; ++i) { - // We get a location - const location = p_ctx.readNetworkStringUTF16(); - sources.push(location); - } - // Final three bytes should be 0x1 0x1 0x1 - assert(p_ctx.readUInt8() === 0x1); - assert(p_ctx.readUInt8() === 0x1); - assert(p_ctx.readUInt8() === 0x1); - assert(p_ctx.isEOF()); - return { - id: messageId, - message: { - sources: sources, - }, - }; - } - - case MessageId.FileStat: { - assert(p_ctx.sizeLeft() === 53); - // Last 4 bytes (FAT32) indicate size of file - p_ctx.seek(49); - const size = p_ctx.readUInt32(); - return { - id: messageId, - message: { - size: size, - }, - }; - } - - case MessageId.EndOfMessage: { - // End of result indication? - return { - id: messageId, - message: null, - }; - } - - case MessageId.FileTransferId: { - assert(p_ctx.sizeLeft() === 12); - assert(p_ctx.readUInt32() === 0x0); - const filesize = p_ctx.readUInt32(); - const id = p_ctx.readUInt32(); - - return { - id: messageId, - message: { - size: filesize, - txid: id, - }, - }; - } - - case MessageId.FileTransferChunk: { - assert(p_ctx.readUInt32() === 0x0); - const offset = p_ctx.readUInt32(); - const chunksize = p_ctx.readUInt32(); - assert(chunksize === p_ctx.sizeLeft()); - assert(p_ctx.sizeLeft() <= CHUNK_SIZE); - - return { - id: messageId, - message: { - data: p_ctx.readRemainingAsNewBuffer(), - offset: offset, - size: chunksize, - }, - }; - } - - case MessageId.Unknown0: { - return { - id: messageId, - message: null, - }; - } - - case MessageId.ServiceDisconnect: { - //This message is received when the player that FileTransfer is connected to shuts down - this.disconnect(); - return { - id: messageId, - message: null, - }; - } - - default: - { - assert.fail(`File Transfer Unhandled message id '${messageId}'`); - } - break; - } - } - - protected messageHandler(p_data: ServiceMessage): void { - if (p_data.id === MessageId.FileTransferChunk && this.receivedFile) { - assert(this.receivedFile.sizeLeft() >= p_data.message.size); - this.receivedFile.write(p_data.message.data); - } else { - // Logger.log(p_data); - } - } - - async getFile(p_location: string): Promise { - assert(this.receivedFile === null); - - if (this._available) { - this._available = false; - } - await this.requestFileTransferId(p_location); - const txinfo = await this.waitForMessage(MessageId.FileTransferId); - - if (txinfo) { - this.receivedFile = new WriteContext({ size: txinfo.size }); - - const totalChunks = Math.ceil(txinfo.size / CHUNK_SIZE); - const total = parseInt(txinfo.size); - - if (total === 0) { - Logger.warn(`${p_location} doesn't exist or is a streaming file`); - return; - } - - await this.requestChunkRange(txinfo.txid, 0, totalChunks - 1); - - try { - await new Promise(async (resolve, reject) => { - setTimeout(() => { - reject(new Error(`Failed to download '${p_location}'`)); - }, DOWNLOAD_TIMEOUT); - - while (this.receivedFile.isEOF() === false) { - const bytesDownloaded = total - this.receivedFile.sizeLeft(); - const percentComplete = (bytesDownloaded / total) * 100; - this.emit('fileTransferProgress', { - sizeLeft: this.receivedFile.sizeLeft(), - total: txinfo.size, - bytesDownloaded: bytesDownloaded, - percentComplete: percentComplete - }) - Logger.debug(`Reading ${p_location} progressComplete=${Math.ceil(percentComplete)}% ${bytesDownloaded}/${total}`); - await sleep(200); - } - Logger.debug(`Download complete.`); - resolve(true); - }); - } catch (err) { - const msg = `Could not read database from ${p_location}: ${err.message}` - Logger.error(msg); - this._available = true; - throw new Error(msg); - } - - Logger.debug(`Signaling transfer complete.`); - await this.signalTransferComplete(); - this._available = true; - } - - const buf = this.receivedFile ? this.receivedFile.getBuffer() : null; - this.receivedFile = null; - - return buf; - } - - async getSources(): Promise { - const result: Source[] = []; - - await this.requestSources(); - const message = await this.waitForMessage(MessageId.SourceLocations); - if (message) { - for (const source of message.sources) { - //try to retrieve V2.x Database2/m.db first. If file doesn't exist or 0 size, retrieve V1.x /m.db - const databases = [`/${source}/Engine Library/Database2/m.db`, `/${source}/Engine Library/m.db`]; - for (const database of databases) { - await this.requestStat(database); - const fstatMessage = await this.waitForMessage(MessageId.FileStat); - if (fstatMessage.size > 0) { - result.push({ - name: source, - database: { - location: database, - size: fstatMessage.size, - }, - }); - break; - } - } - } - } - - return result; - } - - /////////////////////////////////////////////////////////////////////////// - // Private methods - - private async requestStat(p_filepath: string): Promise { - // 0x7d1: seems to request some sort of fstat on a file - const ctx = new WriteContext(); - ctx.writeFixedSizedString(MAGIC_MARKER); - ctx.writeUInt32(0x0); - ctx.writeUInt32(0x7d1); - ctx.writeNetworkStringUTF16(p_filepath); - await this.writeWithLength(ctx); - } - - private async requestSources(): Promise { - // 0x7d2: Request available sources - const ctx = new WriteContext(); - ctx.writeFixedSizedString(MAGIC_MARKER); - ctx.writeUInt32(0x0); - ctx.writeUInt32(0x7d2); // Database query - ctx.writeUInt32(0x0); - await this.writeWithLength(ctx); - } - - private async requestFileTransferId(p_filepath: string): Promise { - // 0x7d4: Request transfer id? - const ctx = new WriteContext(); - ctx.writeFixedSizedString(MAGIC_MARKER); - ctx.writeUInt32(0x0); - ctx.writeUInt32(0x7d4); - ctx.writeNetworkStringUTF16(p_filepath); - ctx.writeUInt32(0x0); // Not sure why we need 0x0 here - await this.writeWithLength(ctx); - } - - private async requestChunkRange(p_txid: number, p_chunkStartId: number, p_chunkEndId: number): Promise { - // 0x7d5: seems to be the code to request chunk range - const ctx = new WriteContext(); - ctx.writeFixedSizedString(MAGIC_MARKER); - ctx.writeUInt32(0x0); - ctx.writeUInt32(0x7d5); - ctx.writeUInt32(0x0); - ctx.writeUInt32(p_txid); // I assume this is the transferid - ctx.writeUInt32(0x0); - ctx.writeUInt32(p_chunkStartId); - ctx.writeUInt32(0x0); - ctx.writeUInt32(p_chunkEndId); - await this.writeWithLength(ctx); - } - - private async signalTransferComplete(): Promise { - // 0x7d6: seems to be the code to signal transfer completed - const ctx = new WriteContext(); - ctx.writeFixedSizedString(MAGIC_MARKER); - ctx.writeUInt32(0x0); - ctx.writeUInt32(0x7d6); - await this.writeWithLength(ctx); - } - - public async waitTillAvailable(): Promise { - while (!this._available) { - await sleep(250); - } - } -} +export class FileTransfer extends Service { + public name: string = "FileTransfer"; + private receivedFile: WriteContext = null; + static readonly emitter: EventEmitter = new EventEmitter(); + static #txid: number = 2; + #isAvailable: boolean = true; + + /** + * FileTransfer Service Class + * @constructor + * @param {DeviceId} deviceId + */ + constructor(deviceId?: DeviceId) { + super(deviceId) + this.addListener('newDevice', (service: FileTransfer) => this.instanceListener('newDevice', service)) + this.addListener('newSource', (source: Source) => this.instanceListener('newSource', source)) + this.addListener('sourceRemoved', (name: string, deviceId: DeviceId) => this.instanceListener('newSource', name, deviceId)) + this.addListener('fileTransferProgress', (source: Source, fileName: string, txid: number, progress: FileTransferProgress) => this.instanceListener('fileTransferProgress', source, fileName, txid, progress)) + this.addListener('fileTransferComplete', (source: Source, fileName: string, txid: number) => this.instanceListener('fileTransferComplete', source, fileName, txid)); + this.addListener(`data`, (ctx: ReadContext) => this.parseData(ctx)); + this.addListener(`message`, (message: ServiceMessage) => this.messageHandler(message)); + } + + /** + * get a new, exclusive, Transfer ID + * @returns {number} + */ + private newTxid(): number { + FileTransfer.#txid++ + const txid = parseInt(FileTransfer.#txid.toString()) + return txid; + } + + protected instanceListener(eventName: string, ...args: any) { + FileTransfer.emitter.emit(eventName, ...args) + } + + private parseData(ctx: ReadContext): ServiceMessage { + + const check = ctx.getString(4); + if (check !== MAGIC_MARKER) { + Logger.error(assert(check === MAGIC_MARKER)) + } + + const txId = ctx.readUInt32(); + const messageId: MessageId = ctx.readUInt32(); + + switch (messageId) { + case MessageId.RequestSources: { + assert(ctx.readUInt32() === 0x0) + assert(ctx.isEOF()); + + const message = { + id: MessageId.RequestSources, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + }, + }; + this.emit(`message`, message); + return message + } + + case MessageId.SourceLocations: { + const sources: string[] = []; + const sourceCount = ctx.readUInt32(); + for (let i = 0; i < sourceCount; ++i) { + // We get a location + const location = ctx.readNetworkStringUTF16(); + sources.push(location); + } + + // Final three bytes should be 0x1 0x1 0x1 for Sources, 0x1 0x1 0x0 for dir/ls + const signOff = ctx.read(3); + assert(ctx.isEOF()); + + const message = { + id: messageId, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + sources: sources, + signOff: signOff, + }, + }; + this.emit(`message`, message); + return message + } + + case MessageId.FileStat: { + assert(ctx.sizeLeft() === 53); + // Last 4 bytes (FAT32) indicate size of file + ctx.seek(49) + const size = ctx.readUInt32(); + + const message = { + id: messageId, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + size: size, + }, + }; + this.emit(`message`, message); + return message + } + + case MessageId.EndOfMessage: { + // End of result indication? + const message = { + id: messageId, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + }, + }; + this.emit(`message`, message); + return message + } + + case MessageId.FileTransferId: { + assert(ctx.sizeLeft() === 12); + assert(ctx.readUInt32() === 0x0); + const filesize = ctx.readUInt32(); + const id = ctx.readUInt32(); + assert(id === 1) + const message = { + id: messageId, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + size: filesize, + }, + }; + this.emit(`message`, message); + return message + } + + case MessageId.FileTransferChunk: { + assert(ctx.readUInt32() === 0x0); + const offset = ctx.readUInt32(); + const chunksize = ctx.readUInt32(); + assert(chunksize === ctx.sizeLeft()); + assert(ctx.sizeLeft() <= CHUNK_SIZE); + + const message = { + id: messageId, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + data: ctx.readRemainingAsNewBuffer(), + offset: offset, + size: chunksize, + }, + }; + this.emit(`message`, message); + return message + } + + case MessageId.DataUpdate: { + const message = { + id: messageId, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + data: ctx.readRemainingAsNewBuffer(), + }, + }; + this.emit(`message`, message); + return message + } + + case MessageId.Unknown0: { + // sizeLeft() of 6 means its not an offline analyzer + // TODO name Unknown0 and finalize this + const message = { + id: messageId, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + data: ctx.readRemainingAsNewBuffer(), + }, + }; + this.emit(`message`, message); + return message + } + + case MessageId.DeviceShutdown: { + // This message seems to be sent from connected devices when shutdown is started + if (ctx.sizeLeft() > 0) { + const msg = ctx.readRemainingAsNewBuffer().toString('hex'); + Logger.debug(msg) + } + + const message = { + id: messageId, + message: { + service: this, + deviceId: this.deviceId, + txid: txId, + }, + }; + this.emit(`message`, message); + return message + } + + default: + { + const remaining = ctx.readRemainingAsNewBuffer() + Logger.error(`File Transfer Unhandled message id '${messageId}'`, remaining.toString('hex')); + } + return + } + } + + private messageHandler(data: ServiceMessage): void { + if (data && data.id && data.id !== MessageId.FileTransferChunk) { + const msgData = { ...data.message } + delete msgData.service + delete msgData.deviceId + Logger.debug(data.message.deviceId.string, MessageId[data.id], msgData) + } + + this.emit('fileMessage', data); + + /** + * Emit event message for txid if there is a listener + */ + if (data.message?.txid && this.listenerCount(data.message.txid.toString())) { + this.emit(data.message.txid.toString(), data); + } + + /** + * Save incoming chunk data to file buffer + */ + if (data && data.id === MessageId.FileTransferChunk && this.receivedFile) { + this.receivedFile.write(data.message.data); + } + + /** + * reply that we offer no sources. + */ + if (data && data.id === Action.RequestSources) { + this.sendNoSourcesReply(data.message); + } + + /** + * Request Sources + */ + if (data && data.id === MessageId.Unknown0) { + this.requestSources(1); + } + + /** + * If sources are changed, send updateSources request + */ + if (data && data.id === MessageId.SourceLocations && data.message.signOff[2] === 1) { + Logger.silly(`getting sources for `, this.deviceId.string); + this.updateSources(data.message.sources); + } + } + + /** + * Reads a file on the device and returns a buffer. + * + * >> USE WITH CAUTION! << + * + * Downloading seems eat a lot of CPU on the device and might cause it to + * be unresponsive while downloading big files. Also, it seems that transfers + * top out at around 10MB/sec. + * + * @param {string} filePath Location of the file on the device. + * @returns {Promise} Contents of the file. + */ + async getFile(source: Source, filePath: string): Promise { + const transfer = { + txid: this.newTxid(), + filePath: filePath + } + + await this.requestService(); + assert(this.receivedFile === null); + await this.requestFileTransferId(transfer.filePath, transfer.txid); + const txinfo = await this.waitForFileMessage('fileMessage', MessageId.FileTransferId, transfer.txid); + if (txinfo) { + this.receivedFile = new WriteContext({ size: txinfo.size }); + const totalChunks = Math.ceil(txinfo.size / CHUNK_SIZE); + const total = txinfo.size; + + if (total === 0) { + Logger.warn(`${transfer.filePath} doesn't exist or is a streaming file`); + this.receivedFile = null + this.releaseService(); + return; + } + await this.requestChunkRange(transfer.txid, 0, totalChunks - 1); + + try { + await new Promise(async (resolve, reject) => { + setTimeout(() => { + reject(new Error(`Failed to download '${transfer.filePath}'`)); + }, DOWNLOAD_TIMEOUT); + + while (this.receivedFile.isEOF() === false) { + const bytesDownloaded = total - this.receivedFile.sizeLeft(); + const percentComplete = (bytesDownloaded / total) * 100; + this.emit('fileTransferProgress', source, transfer.filePath.split('/').pop(), transfer.txid, { + sizeLeft: this.receivedFile.sizeLeft(), + total: txinfo.size, + bytesDownloaded: bytesDownloaded, + percentComplete: percentComplete + }) + Logger.silly(`sizeleft ${this.receivedFile.sizeLeft()} total ${txinfo.size} total ${total}`); + Logger.silly(`Reading ${transfer.filePath} progressComplete=${Math.ceil(percentComplete)}% ${bytesDownloaded}/${total}`); + await sleep(200); + } + Logger.debug(`Download complete.`); + this.emit('fileTransferComplete', source, transfer.filePath.split('/').pop(), transfer.txid) + resolve(true); + }); + } catch (err) { + const msg = `Could not read database from ${transfer.filePath}: ${err.message}` + this.receivedFile = null + this.releaseService(); + Logger.error(msg); + throw new Error(msg); + } + Logger.info(`Signaling transfer complete.`); + await this.signalTransferComplete(transfer.txid); + } + + const buf = this.receivedFile ? this.receivedFile.getBuffer() : null; + this.receivedFile = null; + this.releaseService(); + return buf; + } + + /** + * Gets new sources and deletes those which have been removed + * @param {string[]} sources an array of current sources from device + */ + private async updateSources(sources: string[]) { + const currentSources = StageLinq.sources.getSources(this.deviceId); + const currentSourceNames = currentSources.map(source => source.name); + + //When a source is disconnected, devices send a new SourceLocations message that excludes the removed source + const markedForDelete = currentSources.filter(item => !sources.includes(item.name)); + const newSources = sources.filter(source => !currentSourceNames.includes(source)); + for (const source of markedForDelete) { + StageLinq.sources.deleteSource(source.name, source.deviceId) + + } + if (newSources.length) { + this.getSources(newSources); + } + } + + /** + * Get Sources from Device + * @param {string[]} sources Array of sourceNames + */ + private async getSources(sources: string[]) { + const result: Source[] = []; + + for (const source of sources) { + const dbFiles = ['m.db']; + const thisSource = new Source(source, this.deviceId) + + for (const database of dbFiles) { + const dbPath = `/${source}/Engine Library/Database2` + const _transfer = { + txid: this.newTxid(), + filepath: `${dbPath}/${database}` + } + await this.requestStat(_transfer.filepath, _transfer.txid); + const fstatMessage = await this.waitForFileMessage('fileMessage', MessageId.FileStat, _transfer.txid); + + if (fstatMessage.size > 126976) { + const db = thisSource.newDatabase(database, fstatMessage.size, dbPath) + Logger.debug(`{${_transfer.txid}} file: ${db.remoteDBPath} size: ${db.size}`) + await this.signalMessageComplete(_transfer.txid) + } else { + await this.signalMessageComplete(_transfer.txid) + } + } + StageLinq.sources.setSource(thisSource); + + this.emit('newSource', thisSource) + result.push(thisSource); + + if (StageLinq.options.downloadDbSources) { + await StageLinq.sources.downloadDbs(thisSource); + } + } + } + + async getSourceDirInfo(source: Source) { + const dbPath = `/${source.name}/Engine Library/Database2` + const transfer = { + txid: this.newTxid(), + filepath: `${dbPath}` + } + + + let returnList: string[][] = []; + try { + await this.requestPathInfo(transfer.filepath, transfer.txid); + const dbFileList = await this.waitForFileMessage('fileMessage', MessageId.SourceLocations, transfer.txid); + console.log(`Contents of ${transfer.filepath}`, dbFileList.sources); + for (const file of dbFileList.sources) { + const _transfer = { + txid: this.newTxid(), + filepath: `${dbPath}/${file}` + } + await this.requestStat(_transfer.filepath, _transfer.txid); + const fstatMessage = await this.waitForFileMessage('fileMessage', MessageId.FileStat, _transfer.txid); + returnList.push([_transfer.txid.toString(), file, fstatMessage.size.toString()]) + } + } catch (err) { + console.log(err) + } + console.log(returnList); + } + + /** + * Promise will resolve when service is available + */ + public async isAvailable(): Promise { + while (!this.#isAvailable) { + await sleep(250) + } + } + + /** + * Promise will resolve when service is available + * and will set service as unavailable. + */ + public async requestService(): Promise { + while (!this.#isAvailable) { + await sleep(250) + } + this.#isAvailable = false; + } + + /** + * Releases service after transfer + */ + public async releaseService(): Promise { + this.#isAvailable = true; + } + + + /////////////////////////////////////////////////////////////////////////// + // Private methods + + private async waitForFileMessage(eventMessage: string, messageId: number, txid: number): Promise { + return await new Promise((resolve, reject) => { + const listener = (message: ServiceMessage) => { + if (message.id === messageId && message.message?.txid === txid) { + this.removeListener(eventMessage, listener); + resolve(message.message); + } + }; + this.addListener(eventMessage, listener); + setTimeout(() => { + reject(new Error(`Failed to receive message '${messageId}' on time`)); + }, MESSAGE_TIMEOUT); + }); + } + + + /** + * Request fstat on file from Device + * @param {string} filepath + */ + private async requestStat(filepath: string, txid: number): Promise { + // 0x7d1: seems to request some sort of fstat on a file + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(txid); + ctx.writeUInt32(0x7d1); + ctx.writeNetworkStringUTF16(filepath); + await this.writeWithLength(ctx); + } + + /** + * Request current sources attached to device + */ + private async requestSources(txid: number): Promise { + // 0x7d2: Request available sources + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(txid); + ctx.writeUInt32(0x7d2); // Database query + ctx.writeUInt32(0x0); + await this.writeWithLength(ctx); + } + + async requestPathInfo(path: string, txid: number): Promise { + // 0x7d2: Request available sources + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(txid); + ctx.writeUInt32(0x7d2); // Database query + ctx.writeNetworkStringUTF16(path) + await this.writeWithLength(ctx); + } + + /** + * Request TxId for file + * @param {string} filepath + */ + private async requestFileTransferId(filepath: string, txid: number): Promise { + // 0x7d4: Request transfer id? + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(txid); + ctx.writeUInt32(0x7d4); + ctx.writeNetworkStringUTF16(filepath); + ctx.writeUInt32(0x0); // Not sure why we need 0x0 here + await this.writeWithLength(ctx); + } + + /** + * + * @param {number} txid Transfer ID for this session + * @param {number} chunkStartId + * @param {number} chunkEndId + */ + private async requestChunkRange(txid: number, chunkStartId: number, chunkEndId: number): Promise { + // 0x7d5: seems to be the code to request chunk range + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(txid); + ctx.writeUInt32(0x7d5); + ctx.writeUInt32(0x0); + ctx.writeUInt32(0x1); + ctx.writeUInt32(0x0); + ctx.writeUInt32(chunkStartId); + ctx.writeUInt32(0x0); + ctx.writeUInt32(chunkEndId); + await this.writeWithLength(ctx); + } + + /** + * Signal Transfer Completed + */ + private async signalTransferComplete(txid: number): Promise { + // 0x7d6: seems to be the code to signal transfer completed + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(txid); + ctx.writeUInt32(0x7d6); + await this.writeWithLength(ctx); + } + + private async signalMessageComplete(txid: number): Promise { + // 0x7d6: seems to be the code to signal transfer completed + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(txid); + ctx.writeUInt32(0x7d3); + await this.writeWithLength(ctx); + } + /** + * Reply to Devices requesting our sources + * @param {FileTransferData} data + */ + private async sendNoSourcesReply(message: FileTransferData) { + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(message.txid); + ctx.writeUInt32(0x3); + ctx.writeUInt32(0x0); + ctx.writeUInt16(257); + ctx.writeUInt8(0x0); + await this.writeWithLength(ctx); + } + + +} \ No newline at end of file diff --git a/services/Service.ts b/services/Service.ts index bf8278a..427fb89 100644 --- a/services/Service.ts +++ b/services/Service.ts @@ -1,145 +1,233 @@ -//import { hex } from '../utils/hex'; import { EventEmitter } from 'events'; -import { Logger } from '../LogEmitter'; -import { MessageId, MESSAGE_TIMEOUT, Tokens } from '../types'; -import { NetworkDevice } from '../network/NetworkDevice'; -import { ReadContext } from '../utils/ReadContext'; import { strict as assert } from 'assert'; -import { WriteContext } from '../utils/WriteContext'; -import * as tcp from '../utils/tcp'; -import type { ServiceMessage } from '../types'; +import { Logger } from '../LogEmitter'; +import { ServiceMessage, DeviceId } from '../types'; +import { Device } from '../devices'; +import { ReadContext, WriteContext } from '../utils'; +import { Server, Socket, AddressInfo, createServer as CreateServer } from 'net'; +import { StageLinq } from '../StageLinq'; + + +const MESSAGE_TIMEOUT = 3000; // in ms -export abstract class Service extends EventEmitter { - private address: string; - private port: number; - public readonly name: string; - protected controller: NetworkDevice; - protected connection: tcp.Connection = null; - constructor(p_address: string, p_port: number, p_controller: NetworkDevice) { +export abstract class Service extends EventEmitter { + public readonly name: string = "Service"; + public readonly device: Device; + public deviceId: DeviceId = null; + public socket: Socket = null; + + protected isBufferedService: boolean = true; + protected timeout: NodeJS.Timer; + private messageBuffer: Buffer = null; + private server: Server = null; + + /** + * Service Abstract Class + * @param {DeviceId} [deviceId] + */ + constructor(deviceId?: DeviceId) { super(); - this.address = p_address; - this.port = p_port; - this.name = this.constructor.name; - this.controller = p_controller; + this.deviceId = deviceId || null; + this.device = (deviceId ? StageLinq.devices.device(deviceId) : null); } - async connect(): Promise { - assert(!this.connection); - this.connection = await tcp.connect(this.address, this.port); - let queue: Buffer = null; + get serverInfo(): AddressInfo { + return this.server.address() as AddressInfo + } - this.connection.socket.on('data', (p_data: Buffer) => { - let buffer: Buffer = null; - if (queue && queue.length > 0) { - buffer = Buffer.concat([queue, p_data]); - } else { - buffer = p_data; - } + /** + * Creates a new Server for Service + * @returns {Server} + */ + private async startServer(): Promise { + return await new Promise((resolve, reject) => { - // FIXME: Clean up this arraybuffer confusion mess - const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); - const ctx = new ReadContext(arrayBuffer, false); - queue = null; - - try { - while (ctx.isEOF() === false) { - if (ctx.sizeLeft() < 4) { - queue = ctx.readRemainingAsNewBuffer(); - break; - } - - const length = ctx.readUInt32(); - if (length <= ctx.sizeLeft()) { - const message = ctx.read(length); - // Use slice to get an actual copy of the message instead of working on the shared underlying ArrayBuffer - const data = message.buffer.slice(message.byteOffset, message.byteOffset + length); - // Logger.info("RECV", length); - //hex(message); - const parsedData = this.parseData(new ReadContext(data, false)); - - // Forward parsed data to message handler - this.messageHandler(parsedData); - this.emit('message', parsedData); - } else { - ctx.seek(-4); // Rewind 4 bytes to include the length again - queue = ctx.readRemainingAsNewBuffer(); - break; - } - } - } catch (err) { - // FIXME: Rethrow based on the severity? - Logger.error(err); - } + const server = CreateServer((socket) => { + Logger.debug(`[${this.name}] connection from ${socket.remoteAddress}:${socket.remotePort}`) + + clearTimeout(this.timeout); + this.socket = socket; + if (this.name !== "Directory") this.emit('connection', this.name, this.deviceId) + + socket.on('error', (err) => reject(err)); + socket.on('data', async (data) => await this.dataHandler(data, socket)); + + }).listen(0, '0.0.0.0', () => { + this.server = server; + Logger.silly(`opened ${this.name} server on ${this.serverInfo.port}`); + if (this.deviceId) { + Logger.silly(`started timer for ${this.name} for ${this.deviceId.string}`) + this.timeout = setTimeout(this.closeService, 8000, this); + }; + resolve(server); + }); }); + } + + /** + * Start Service Listener + * @returns {Promise} + */ + async start(): Promise { + const server = await this.startServer(); + return server.address() as AddressInfo; + } + + /** + * Close Server + */ + async stop() { + assert(this.server); + try { + this.server.close(); + } catch (e) { + Logger.error('Error closing server', e); + } + } - // FIXME: Is this required for all Services? - const ctx = new WriteContext(); - ctx.writeUInt32(MessageId.ServicesAnnouncement); - ctx.write(Tokens.SoundSwitch); - ctx.writeNetworkStringUTF16(this.name); - ctx.writeUInt16(this.connection.socket.localPort); // FIXME: In the Go code this is the local TCP port, but 0 or any other 16 bit value seems to work fine as well - await this.write(ctx); + private async subMessageTest(buff: Buffer): Promise { + try { + const msg = buff.readInt32BE(); + const deviceId = buff.slice(4); + if (msg === 0 && deviceId.length === 16) { + return true + } else { + return false + } + } catch { + return false + } + } - await this.init(); - Logger.debug(`Connected to service '${this.name}' at port ${this.port}`); + private concantenateBuffer(data: Buffer): ReadContext { + let buffer: Buffer = null; + if (this.messageBuffer && this.messageBuffer.length > 0) { + buffer = Buffer.concat([this.messageBuffer, data]); + } else { + buffer = data; + } + this.messageBuffer = null + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); + return new ReadContext(arrayBuffer, false) } - disconnect() { - assert(this.connection); + /** + * Handle incoming Data from Server Socket + * @param {Buffer} data + * @param {Socket} socket + */ + private async dataHandler(data: Buffer, socket: Socket) { + + const ctx = this.concantenateBuffer(data); + + if (!this.isBufferedService) { + this.emit(`data`, new ReadContext(ctx.readRemainingAsNewArrayBuffer(), false), socket) + }; + + if (await this.subMessageTest(ctx.peek(20))) { + const messageId = ctx.readUInt32(); + const token = ctx.read(16) // DeviceID + if (!this.deviceId) { + const deviceId = new DeviceId(token); + Logger.silent(`${this.name} adding DeviceId: ${deviceId.string}`) + this.deviceId = deviceId + } + const serviceName = ctx.readNetworkStringUTF16(); + ctx.seek(2); + Logger.silent(`${messageId} request to ${serviceName} from ${this.deviceId.string}`); + if (this.device) { + StageLinq.devices.emit('newService', this.device, this) + } + this.emit('newDevice', this); + } + try { - Logger.debug(`Disconnecting ${this.name} Service on ${this.address}`); - this.connection.destroy(); - } catch (e) { - Logger.error('Error disconnecting', e); - } finally { - this.connection = null; + while (ctx.isEOF() === false) { + if (ctx.sizeLeft() < 4) { + this.messageBuffer = ctx.readRemainingAsNewBuffer(); + break; + } + + const length = ctx.readUInt32(); + if (length <= ctx.sizeLeft()) { + const message = ctx.read(length); + const data = message.buffer.slice(message.byteOffset, message.byteOffset + length); + this.emit(`data`, new ReadContext(data, false), socket) + } else { + ctx.seek(-4); // Rewind 4 bytes to include the length again + this.messageBuffer = ctx.readRemainingAsNewBuffer(); + break; + } + } + } catch (err) { + Logger.error(this.name, this.deviceId.string, err); } } - async waitForMessage(p_messageId: number): Promise { + /** + * Wait for a message from the wire + * @param {string} eventMessage + * @param {number} messageId + * @returns {Promise} + */ + protected async waitForMessage(eventMessage: string, messageId: number): Promise { return await new Promise((resolve, reject) => { - const listener = (p_message: ServiceMessage) => { - if (p_message.id === p_messageId) { - this.removeListener('message', listener); - resolve(p_message.message); + const listener = (message: ServiceMessage) => { + if (message.id === messageId) { + this.removeListener(eventMessage, listener); + resolve(message.message); } }; - this.addListener('message', listener); + this.addListener(eventMessage, listener); setTimeout(() => { - reject(new Error(`Failed to receive message '${p_messageId}' on time`)); + reject(new Error(`Failed to receive message '${messageId}' on time`)); }, MESSAGE_TIMEOUT); }); } - async write(p_ctx: WriteContext) { - assert(p_ctx.isLittleEndian() === false); - assert(this.connection); - const buf = p_ctx.getBuffer(); - // Logger.info("SEND"); - //hex(buf); - const written = await this.connection.write(buf); - assert(written === buf.byteLength); - return written; + /** + * Write a Context message to the socket + * @param {WriteContext} ctx + * @returns {Promise} true if data written + */ + protected async write(ctx: WriteContext): Promise { + assert(ctx.isLittleEndian() === false); + const buf = ctx.getBuffer(); + const written = await this.socket.write(buf); + return await written; } - async writeWithLength(p_ctx: WriteContext) { - assert(p_ctx.isLittleEndian() === false); - assert(this.connection); - const newCtx = new WriteContext({ size: p_ctx.tell() + 4, autoGrow: false }); - newCtx.writeUInt32(p_ctx.tell()); - newCtx.write(p_ctx.getBuffer()); + /** + * Write a length-prefixed Context message to the socket + * @param {WriteContext} ctx + * @returns {Promise} true if data written + */ + protected async writeWithLength(ctx: WriteContext): Promise { + assert(ctx.isLittleEndian() === false); + const newCtx = new WriteContext({ size: ctx.tell() + 4, autoGrow: false }); + newCtx.writeUInt32(ctx.tell()); + newCtx.write(ctx.getBuffer()); assert(newCtx.isEOF()); return await this.write(newCtx); } - // FIXME: Cannot use abstract because of async; is there another way to get this? - protected async init() { - assert.fail('Implement this'); + // + /** + * Callback for server timeout timer + * Runs if device doesn't conect to service server + * @param {DeviceId} deviceId + * @param {string} serviceName + * @param {Server} server + * @param {StageLinq} parent + * @param {ServiceHandler} handler + */ + protected async closeService(service: Service) { + Logger.info(`closing ${service.name} server for ${service.deviceId.string} due to timeout`); + service.emit('closingService', service) + service.server.close(); } - protected abstract parseData(p_ctx: ReadContext): ServiceMessage; - - protected abstract messageHandler(p_data: ServiceMessage): void; + protected abstract instanceListener(eventName: string, ...args: any): void } diff --git a/services/StateMap.ts b/services/StateMap.ts index 91f069d..80347a2 100644 --- a/services/StateMap.ts +++ b/services/StateMap.ts @@ -1,170 +1,248 @@ +import { EventEmitter } from 'events'; +import { Logger } from '../LogEmitter'; import { strict as assert } from 'assert'; -import { StageLinqValue } from '../types'; -import { ReadContext } from '../utils/ReadContext'; -import { WriteContext } from '../utils/WriteContext'; -import { Service } from './Service'; -import type { ServiceMessage } from '../types'; -// import { Logger } from '../LogEmitter'; - -export const States = [ - // Mixer - StageLinqValue.MixerCH1faderPosition, - StageLinqValue.MixerCH2faderPosition, - StageLinqValue.MixerCrossfaderPosition, - - // Decks - StageLinqValue.EngineDeck1Play, - StageLinqValue.EngineDeck1PlayState, - StageLinqValue.EngineDeck1PlayStatePath, - StageLinqValue.EngineDeck1TrackArtistName, - StageLinqValue.EngineDeck1TrackTrackNetworkPath, - StageLinqValue.EngineDeck1TrackSongLoaded, - StageLinqValue.EngineDeck1TrackSongName, - StageLinqValue.EngineDeck1TrackTrackData, - StageLinqValue.EngineDeck1TrackTrackName, - StageLinqValue.EngineDeck1CurrentBPM, - StageLinqValue.EngineDeck1ExternalMixerVolume, - - StageLinqValue.EngineDeck2Play, - StageLinqValue.EngineDeck2PlayState, - StageLinqValue.EngineDeck2PlayStatePath, - StageLinqValue.EngineDeck2TrackArtistName, - StageLinqValue.EngineDeck2TrackTrackNetworkPath, - StageLinqValue.EngineDeck2TrackSongLoaded, - StageLinqValue.EngineDeck2TrackSongName, - StageLinqValue.EngineDeck2TrackTrackData, - StageLinqValue.EngineDeck2TrackTrackName, - StageLinqValue.EngineDeck2CurrentBPM, - StageLinqValue.EngineDeck2ExternalMixerVolume, - - StageLinqValue.EngineDeck3Play, - StageLinqValue.EngineDeck3PlayState, - StageLinqValue.EngineDeck3PlayStatePath, - StageLinqValue.EngineDeck3TrackArtistName, - StageLinqValue.EngineDeck3TrackTrackNetworkPath, - StageLinqValue.EngineDeck3TrackSongLoaded, - StageLinqValue.EngineDeck3TrackSongName, - StageLinqValue.EngineDeck3TrackTrackData, - StageLinqValue.EngineDeck3TrackTrackName, - StageLinqValue.EngineDeck3CurrentBPM, - StageLinqValue.EngineDeck3ExternalMixerVolume, - - StageLinqValue.EngineDeck4Play, - StageLinqValue.EngineDeck4PlayState, - StageLinqValue.EngineDeck4PlayStatePath, - StageLinqValue.EngineDeck4TrackArtistName, - StageLinqValue.EngineDeck4TrackTrackNetworkPath, - StageLinqValue.EngineDeck4TrackSongLoaded, - StageLinqValue.EngineDeck4TrackSongName, - StageLinqValue.EngineDeck4TrackTrackData, - StageLinqValue.EngineDeck4TrackTrackName, - StageLinqValue.EngineDeck4CurrentBPM, - StageLinqValue.EngineDeck4ExternalMixerVolume, - - StageLinqValue.ClientPreferencesLayerA, - StageLinqValue.ClientPreferencesPlayer, - StageLinqValue.ClientPreferencesPlayerJogColorA, - StageLinqValue.ClientPreferencesPlayerJogColorB, - StageLinqValue.EngineDeck1DeckIsMaster, - StageLinqValue.EngineDeck2DeckIsMaster, - StageLinqValue.EngineMasterMasterTempo, - StageLinqValue.EngineSyncNetworkMasterStatus, - StageLinqValue.MixerChannelAssignment1, - StageLinqValue.MixerChannelAssignment2, - StageLinqValue.MixerChannelAssignment3, - StageLinqValue.MixerChannelAssignment4, - StageLinqValue.MixerNumberOfChannels, - -]; +import { ReadContext, WriteContext } from '../utils'; +import { ServiceMessage, StateNames, DeviceId } from '../types'; +import { Socket } from 'net'; +import { Service } from '../services'; +import { StageLinq } from '../StageLinq'; + const MAGIC_MARKER = 'smaa'; -// FIXME: Is this thing really an interval? const MAGIC_MARKER_INTERVAL = 0x000007d2; const MAGIC_MARKER_JSON = 0x00000000; +enum Action { + request = 0x000007d2, + response = 0x00000000, +} + +enum Result { + accept = 0x00000000, + reject = 0xffffffff, + inquire = 0x00000064 +} + + +// import * as stagelinqConfig from '../stagelinqConfig.json'; + +// export type Player = typeof stagelinqConfig.player; +// export type PlayerDeck = typeof stagelinqConfig.playerDeck; +// export type Mixer = typeof stagelinqConfig.mixer; +// function stateReducer(obj: any, prefix: string): string[] { +// const entries = Object.entries(obj) +// const retArr = entries.map(([key, value]) => { +// return (typeof value === 'object' ? [...stateReducer(value, `${prefix}${key}/`)] : `${prefix}${key}`) +// }) +// return retArr.flat() +// } + +// const playerStateValues = stateReducer(stagelinqConfig.player, '/'); +// const mixerStateValues = stateReducer(stagelinqConfig.mixer, '/'); +// const controllerStateValues = [...playerStateValues, ...mixerStateValues]; + +const playerStateValues = Object.values(StateNames.player); +const mixerStateValues = Object.values(StateNames.mixer); +const controllerStateValues = [...playerStateValues, ...mixerStateValues]; + + export interface StateData { - name: string; - json?: { - type: number; - string?: string; - value?: number; - }; - interval?: number; + service: StateMap; + deviceId: DeviceId; + name?: string; + json?: { + type: number; + string?: string; + value?: number; + state?: boolean; + }; + interval?: number; } +/** + * StateMap Class + */ export class StateMap extends Service { - async init() { - for (const state of States) { - await this.subscribeState(state, 0); - } - } - - protected parseData(p_ctx: ReadContext): ServiceMessage { - const marker = p_ctx.getString(4); - assert(marker === MAGIC_MARKER); - - const type = p_ctx.readUInt32(); - switch (type) { - case MAGIC_MARKER_JSON: { - const name = p_ctx.readNetworkStringUTF16(); - const json = JSON.parse(p_ctx.readNetworkStringUTF16()); - return { - id: MAGIC_MARKER_JSON, - message: { - name: name, - json: json, - }, - }; - } - - case MAGIC_MARKER_INTERVAL: { - const name = p_ctx.readNetworkStringUTF16(); - const interval = p_ctx.readInt32(); - return { - id: MAGIC_MARKER_INTERVAL, - message: { - name: name, - interval: interval, - }, - }; - } - - default: - break; - } - assert.fail(`Unhandled type ${type}`); - return null; - } - - protected messageHandler(_: ServiceMessage): void { - // Logger.debug( - // `${p_data.message.name} => ${ - // p_data.message.json ? JSON.stringify(p_data.message.json) : p_data.message.interval - // }` - // ); - } - - private async subscribeState(p_state: string, p_interval: number) { - // Logger.log(`Subscribe to state '${p_state}'`); - const getMessage = function (): Buffer { - const ctx = new WriteContext(); - ctx.writeFixedSizedString(MAGIC_MARKER); - ctx.writeUInt32(MAGIC_MARKER_INTERVAL); - ctx.writeNetworkStringUTF16(p_state); - ctx.writeUInt32(p_interval); - return ctx.getBuffer(); - }; - - const message = getMessage(); - { - const ctx = new WriteContext(); - ctx.writeUInt32(message.length); - const written = await this.connection.write(ctx.getBuffer()); - assert(written === 4); - } - { - const written = await this.connection.write(message); - assert(written === message.length); - } - } -} + public readonly name = "StateMap"; + static readonly emitter: EventEmitter = new EventEmitter(); + static #instances: Map = new Map() + + /** + * StateMap Service Class + * @constructor + * @param {StageLinq} parent + * @param {StateMapHandler} serviceHandler + * @param {DeviceId} deviceId + */ + constructor(deviceId: DeviceId) { + super(deviceId) + StateMap.#instances.set(this.deviceId.string, this) + this.addListener('newDevice', (service: StateMap) => this.instanceListener('newDevice', service)) + this.addListener('newDevice', (service: StateMap) => StageLinq.status.addDecks(service)) + this.addListener('stateMessage', (data: StateData) => this.instanceListener('stateMessage', data)) + this.addListener(`data`, (ctx: ReadContext) => this.parseData(ctx)); + this.addListener(`message`, (message: ServiceMessage) => this.messageHandler(message)); + } + + protected instanceListener(eventName: string, ...args: any) { + StateMap.emitter.emit(eventName, ...args) + } + + /** + * Subscribe to StateMap States + */ + public async subscribe() { + const socket = this.socket; + + Logger.silly(`Sending Statemap subscriptions to ${socket.remoteAddress}:${socket.remotePort} ${this.deviceId.string}`); + + + switch (this.device.info.unit?.type) { + case "PLAYER": { + for (let state of playerStateValues) { + await this.subscribeState(state, 0, socket); + } + break; + } + case "CONTROLLER": { + for (let state of controllerStateValues) { + await this.subscribeState(state, 0, socket); + } + break; + } + case "MIXER": { + for (let state of mixerStateValues) { + await this.subscribeState(state, 0, socket); + } + break; + } + default: + break; + } + } + + + protected parseData(ctx: ReadContext): ServiceMessage { + assert(this.deviceId); + + const marker = ctx.getString(4); + if (marker !== MAGIC_MARKER) { + Logger.error(assert(marker !== MAGIC_MARKER)); + } + assert(marker === MAGIC_MARKER); + + const type = ctx.readUInt32(); + switch (type) { + case MAGIC_MARKER_JSON: { + const name = ctx.readNetworkStringUTF16(); + let jsonString = ""; + try { + jsonString = ctx.readNetworkStringUTF16(); + const json = JSON.parse(jsonString); + const message: ServiceMessage = { + id: MAGIC_MARKER_JSON, + message: { + name: name, + json: json, + service: this, + deviceId: this.deviceId, + }, + }; + this.emit(`message`, message); + return message + } catch (err) { + Logger.error(this.name, jsonString, err); + } + break; + } + + case MAGIC_MARKER_INTERVAL: { + const name = ctx.readNetworkStringUTF16(); + const interval = ctx.readInt32(); + ctx.seek(-4); + + const message: ServiceMessage = { + id: MAGIC_MARKER_INTERVAL, + message: { + service: this, + deviceId: this.deviceId, + name: name, + interval: interval, + }, + }; + this.emit(`message`, message); + return message + break; + } + default: { + assert.fail(`Unhandled type ${type}`); + break; + } + } + } + + protected messageHandler(data: ServiceMessage): void { + + if (this.listenerCount(data?.message?.name) && data?.message?.json) { + this.emit(data.message.name, data.message) + } + + if (data?.message?.interval) { + this.sendStateResponse(data.message.name, data.message.service.socket); + } + if (data?.message?.json) { + this.emit('stateMessage', data.message); + } + } + + /** + * Respond to StateMap request with rejection + * @param {string} state + * @param {Socket} socket + */ + private async sendStateResponse(state: string, socket: Socket) { + + const getMessage = function (): Buffer { + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(Action.response); + ctx.writeNetworkStringUTF16(state); + ctx.writeUInt32(Result.reject); + return ctx.getBuffer(); + }; + + const message = getMessage(); + + const ctx = new WriteContext(); + ctx.writeUInt32(message.length); + ctx.write(message) + const buffer = ctx.getBuffer(); + await socket.write(buffer); + } + + /** + * Send subcribe to state message to device + * @param {string} state Path/Name of the State + * @param {number} interval TODO clear this up + * @param {Socket} socket + */ + private async subscribeState(state: string, interval: number, socket: Socket) { + + const getMessage = function (): Buffer { + const ctx = new WriteContext(); + ctx.writeFixedSizedString(MAGIC_MARKER); + ctx.writeUInt32(MAGIC_MARKER_INTERVAL); + ctx.writeNetworkStringUTF16(state); + ctx.writeUInt32(interval); + return ctx.getBuffer(); + }; + + const message = getMessage(); + + const ctx = new WriteContext(); + ctx.writeUInt32(message.length); + ctx.write(message) + const buffer = ctx.getBuffer(); + await socket.write(buffer); + } +} \ No newline at end of file diff --git a/services/TimeSync.ts b/services/TimeSync.ts new file mode 100644 index 0000000..b891393 --- /dev/null +++ b/services/TimeSync.ts @@ -0,0 +1,142 @@ + +import { Logger } from '../LogEmitter'; +import { performance } from 'perf_hooks'; +import { ReadContext, WriteContext } from '../utils'; +import { ServiceMessage, DeviceId } from '../types'; +import { } from '../devices' +import { Service } from './Service'; +import { StageLinq } from '../StageLinq'; + + +export interface TimeSyncData { + msgs: bigint[], + timestamp: bigint, +} + +export class TimeSynchronization extends Service { + public readonly name = "TimeSynchronization" + protected readonly isBufferedService: boolean = false; + private localTime: bigint; + private remoteTime: bigint; + private avgTimeArray: bigint[] = []; + + /** + * TimeSynchronization Service Class + * @tag Experimental + * @constructor + * @param deviceId + */ + constructor(deviceId: DeviceId) { + super(deviceId); + this.addListener(`data`, (ctx: ReadContext) => this.parseData(ctx)); + this.addListener(`message`, (message: ServiceMessage) => this.messageHandler(message)); + } + + public async sendTimeSyncRequest() { + const ctx = new WriteContext(); + ctx.write(new Uint8Array([0x0, 0x0, 0x0, 0x0])); + ctx.write(StageLinq.options.actingAs.deviceId.array); + ctx.write(new Uint8Array([0x0])); + ctx.writeFixedSizedString('TimeSynchronization'); + await this.write(ctx); + } + + private timeSyncMsgHelper(msgId: number, msgs: bigint[]): Buffer { + const getMessage = function (): Buffer { + const ctx = new WriteContext(); + ctx.writeUInt32(msgId); + while (msgs.length) { + ctx.writeUInt64(msgs.shift()) + } + return ctx.getBuffer() + } + const message = getMessage(); + + const ctx = new WriteContext(); + ctx.writeUInt32(message.length); + ctx.write(message); + return ctx.getBuffer() + } + + private getTimeStamp(): bigint { + return (BigInt(Math.floor(performance.now()))) + } + + + private sendTimeSyncQuery(localTime: bigint, remoteTime: bigint) { + this.localTime = localTime; + const buffMsg = this.timeSyncMsgHelper(1, [this.localTime]); + const ctx = new WriteContext() + ctx.write(buffMsg) + this.remoteTime = remoteTime; + this.write(ctx); + }; + + // private async sendTimeSyncReply(interval: bigint, timeReceived: bigint): Promise { + // const buffMsg = this.timeSyncMsgHelper(2,[interval,timeReceived]); + // const ctx = new WriteContext() + // ctx.write(buffMsg) + // await this.write(ctx, this.socket); + // }; + + protected parseData(ctx: ReadContext): ServiceMessage { + const timestamp = this.getTimeStamp(); + const size = ctx.readUInt32(); + + if (size === 0) { + const deviceId = new DeviceId(ctx.read(16)) + const svcName = ctx.readNetworkStringUTF16(); + const svcPort = ctx.readUInt16(); + console.log(deviceId.string, svcName, svcPort) + } else { + const id = ctx.readUInt32(); + const msgs: bigint[] = [] + while (ctx.sizeLeft()) { + msgs.push(ctx.readUInt64()) + }; + const message = { + id: id, + message: { + msgs: msgs, + timestamp: timestamp, + } + } + this.emit(`message`, message); + return message + } + } + + private timeAvg(time: bigint) { + if (this.avgTimeArray.length > 100) { + this.avgTimeArray.shift(); + this.avgTimeArray.push(time); + const sum = this.avgTimeArray.reduce((a, b) => a + b, 0n); + const avg = (sum / BigInt(this.avgTimeArray.length)) || 0n; + Logger.silly(`${this.deviceId.string} Average time ${avg}`) + } else { + this.avgTimeArray.push(time); + } + } + + protected messageHandler(msg: ServiceMessage): void { + if (!msg?.message) { + return + } + switch (msg.id) { + case 1: + this.sendTimeSyncQuery(msg.message.timestamp, msg.message.msgs.shift()); + break; + case 2: + Logger.silly(msg.message) + //const localClock = msg.message.timestamp - msg.message.msgs[0] + const remoteClock = msg.message.msgs[1] - this.remoteTime + //Logger.silly(msg.deviceId.string, localClock, remoteClock, (localClock - remoteClock)) + this.timeAvg(remoteClock) + break; + default: + break; + } + } + + protected instanceListener() { } +} diff --git a/services/index.ts b/services/index.ts index d54d535..08d5e0e 100644 --- a/services/index.ts +++ b/services/index.ts @@ -1,3 +1,7 @@ export * from './FileTransfer'; export * from './Service'; export * from './StateMap'; +export * from './Directory'; +export * from './BeatInfo'; +export * from './TimeSync'; +export * from './Broadcast'; \ No newline at end of file diff --git a/stagelinq.code-workspace b/stagelinq.code-workspace deleted file mode 100644 index 60bfae3..0000000 --- a/stagelinq.code-workspace +++ /dev/null @@ -1,16 +0,0 @@ -{ - "folders": [ - { - "path": "." - }, - { - "path": "../stagelinq-pcap" - }, - { - "path": "../go-stagelinq" - } - ], - "settings": { - "task.allowAutomaticTasks": "on" - } -} \ No newline at end of file diff --git a/stagelinqConfig.json b/stagelinqConfig.json new file mode 100644 index 0000000..a940a70 --- /dev/null +++ b/stagelinqConfig.json @@ -0,0 +1,113 @@ +{ + "player": { + "Engine": { + "DeckCount": 0, + "Sync": { + "Network": { + "MasterStatus": false + } + }, + "Master": { + "MasterTempo": 120 + } + }, + "Client": { + "Librarian": { + "DevicesController": { + "CurrentDevice": "", + "HasSDCardConnected": false, + "HasUsbDeviceConnected": false + } + }, + "Preferences": { + "LayerB": false, + "Player": "", + "PlayerJogColorA": "#FFFFFF", + "PlayerJogColorB": "#FFFFFF", + "Profile": { + "Application": { + "PlayerColor1": "#FFFFFF", + "PlayerColor1A": "#FFFFFF", + "PlayerColor1B": "#FFFFFF", + "PlayerColor2": "#FFFFFF", + "PlayerColor2A": "#FFFFFF", + "PlayerColor2B": "#FFFFFF", + "PlayerColor3": "#FFFFFF", + "PlayerColor3A": "#FFFFFF", + "PlayerColor3B": "#FFFFFF", + "PlayerColor4": "#FFFFFF", + "PlayerColor4A": "#FFFFFF", + "PlayerColor4B": "#FFFFFF", + "SyncMode": "" + } + } + } + } + }, + "playerDeck": { + "CurrentBPM": 120, + "ExternalMixerVolume": 1, + "ExternalScratchWheelTouch": false, + "Pads": { + "View": "" + }, + "Play": false, + "PlayState": false, + "Speed": 1, + "SpeedNeutral": false, + "SpeedOffsetDown": false, + "SpeedOffsetUp": false, + "SpeedRange": "8", + "SpeedState": 1, + "SyncMode": "Off", + "DeckIsMaster": false, + "Track": { + "ArtistName": "", + "Bleep": false, + "CuePosition": 156, + "CurrentBPM": 120, + "CurrentKeyIndex": 0, + "CurrentLoopInPosition": 156, + "CurrentLoopOutPosition": 156, + "CurrentLoopSizeInBeats": 0, + "KeyLock": false, + "LoopEnableState": false, + "Loop": { + "QuickLoop1": false, + "QuickLoop2": false, + "QuickLoop3": false, + "QuickLoop4": false, + "QuickLoop5": false, + "QuickLoop6": false, + "QuickLoop7": false, + "QuickLoop8": false + }, + "PlayPauseLEDState": false, + "SampleRate": 44100, + "SongAnalyzed": false, + "SongLoaded": false, + "SongName": "", + "SoundSwitchGUID": "", + "TrackBytes": 1, + "TrackData": false, + "TrackLength": 1, + "TrackName": "", + "TrackNetworkPath": "", + "TrackURI": "", + "TrackWasPlayed": false + } + }, + "mixer": { + "Mixer": { + "CH1faderPosition": 1.27, + "CH2faderPosition": 0, + "CH3faderPosition": 0, + "CH4faderPosition": 0, + "CrossfaderPosition": 0.5, + "ChannelAssignment1": "", + "ChannelAssignment2": "", + "ChannelAssignment3": "", + "ChannelAssignment4": "" + } + } +} \ No newline at end of file diff --git a/status/index.ts b/status/index.ts new file mode 100644 index 0000000..13e9e6f --- /dev/null +++ b/status/index.ts @@ -0,0 +1,62 @@ +import { EventEmitter } from 'events'; +import { StageLinq } from '../StageLinq'; +import { StateData, StateMap } from '../services'; +import { Track, DeviceId } from '../types'; + + +export class Status extends EventEmitter { + private tracks: Map = new Map(); + + /** + * Status EndPoint Class + */ + + /** + * Get Track Info from Status + * @param {DeviceId} deviceId DeviceId of the player + * @param {deck} deck Deck (layer) number + * @returns {TrackData} + */ + getTrack(deviceId: DeviceId, deck: number): Track { + return this.tracks.get(`{${deviceId.string}},${deck}`); + } + + /** + * Add a Deck for Status to monitor + * @param {StateMap} service // Instance of StateMap Service + * @param {number} deck Deck (layer) number + */ + async addDeck(service: StateMap, deck: number) { + let track = new Track(`/Engine/Deck${deck}/Track/`) + this.tracks.set(`{${service.deviceId.string}},${deck}`, track) + for (let item of Object.keys(track)) { + service.addListener(`${track.prefix}${item}`, data => this.listener(data, this)) + } + } + + async addDecks(service: StateMap) { + for (let i = 1; i <= StageLinq.devices.device(service.deviceId).deckCount(); i++) { + this.addDeck(service, i); + } + } + + private listener(data: StateData, status: Status) { + const deck = parseInt(data.name.substring(12, 13)) + const property = data.name.split('/').pop() + const value = this.getTypedValue(data); + const track = status.tracks.get(`{${data.deviceId.string}},${deck}`) + this.tracks.set(`{${data.deviceId.string}},${deck}`, Object.assign(track, { [property]: value })); + } + + private getTypedValue(data: StateData): boolean | string | number { + if (data.json.state) { + return data.json.state as boolean + } + if (data.json.string) { + return data.json.string as string + } + if (data.json.value) { + return data.json.value as number + } + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 638ec68..1bf9c02 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,7 @@ "noImplicitAny": true, "noUnusedLocals": true, "noUnusedParameters": true, + "resolveJsonModule": true, "declaration": true } } diff --git a/types/DeviceId.ts b/types/DeviceId.ts new file mode 100644 index 0000000..b9b262b --- /dev/null +++ b/types/DeviceId.ts @@ -0,0 +1,58 @@ + +class InvalidDeviceIdError extends Error { + constructor(m?: string) { + super(m || 'Error: invalid DeviceId !'); + + // Set the prototype explicitly. + Object.setPrototypeOf(this, InvalidDeviceIdError.prototype); + } +} + + +export class DeviceId { + protected m_str: string; + protected m_array: Uint8Array; + /** + * DeviceId + * @constructor + * @param {(string | Uint8Array)} deviceId string or Uint8Array to initialize new DeviceId + */ + constructor(deviceId: string | Uint8Array) { + switch (typeof deviceId) { + case "string": { + const reg: RegExp = new RegExp('[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}', 'i'); + if (!reg.test(deviceId)) throw new InvalidDeviceIdError(); + this.m_str = deviceId; + this.m_array = Buffer.from(deviceId.split('-').join(), 'hex') as Uint8Array; + break; + } + case "object": { + this.m_array = deviceId; + this.m_str = /(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/i + .exec(Buffer.from(deviceId as Uint8Array).toString('hex')) + .splice(1) + .join('-') as string; + break; + } + default: { + throw new InvalidDeviceIdError(); + break; + } + } + } + + /** + * Return DeviceId as string + */ + get string() { + return this.m_str + } + + /** + * Return DeviceId as Uint8Array + */ + get array() { + return this.m_array + } + +} \ No newline at end of file diff --git a/types/common.ts b/types/common.ts deleted file mode 100644 index 1b37ba8..0000000 --- a/types/common.ts +++ /dev/null @@ -1,240 +0,0 @@ -export const ANNOUNCEMENT_INTERVAL = 1000; // in ms -export const LISTEN_PORT = 51337; -export const LISTEN_TIMEOUT = 5000; // in ms -export const MESSAGE_TIMEOUT = 3000; // in ms -export const CONNECT_TIMEOUT = 5000; // in ms -export const DOWNLOAD_TIMEOUT = 60000; // in ms -export const DISCOVERY_MESSAGE_MARKER = 'airD'; - -export enum Action { - Login = 'DISCOVERER_HOWDY_', - Logout = 'DISCOVERER_EXIT_', -} - -export enum MessageId { - ServicesAnnouncement = 0x0, - TimeStamp = 0x1, - ServicesRequest = 0x2, -} - -export enum StageLinqValue { - ClientLibrarianDevicesControllerCurrentDevice = '/Client/Librarian/DevicesController/CurrentDevice', - ClientLibrarianDevicesControllerHasSDCardConnected = '/Client/Librarian/DevicesController/HasSDCardConnected', - ClientLibrarianDevicesControllerHasUsbDeviceConnected = '/Client/Librarian/DevicesController/HasUsbDeviceConnected', - ClientPreferencesLayerB = '/Client/Preferences/LayerB', - ClientPreferencesPlayer = '/Client/Preferences/Player', - ClientPreferencesProfileApplicationPlayerColor1 = '/Client/Preferences/Profile/Application/PlayerColor1', - ClientPreferencesProfileApplicationPlayerColor1A = '/Client/Preferences/Profile/Application/PlayerColor1A', - ClientPreferencesProfileApplicationPlayerColor1B = '/Client/Preferences/Profile/Application/PlayerColor1B', - ClientPreferencesProfileApplicationPlayerColor2 = '/Client/Preferences/Profile/Application/PlayerColor2', - ClientPreferencesProfileApplicationPlayerColor2A = '/Client/Preferences/Profile/Application/PlayerColor2A', - ClientPreferencesProfileApplicationPlayerColor2B = '/Client/Preferences/Profile/Application/PlayerColor2B', - ClientPreferencesProfileApplicationPlayerColor3 = '/Client/Preferences/Profile/Application/PlayerColor3', - ClientPreferencesProfileApplicationPlayerColor3A = '/Client/Preferences/Profile/Application/PlayerColor3A', - ClientPreferencesProfileApplicationPlayerColor3B = '/Client/Preferences/Profile/Application/PlayerColor3B', - ClientPreferencesProfileApplicationPlayerColor4 = '/Client/Preferences/Profile/Application/PlayerColor4', - ClientPreferencesProfileApplicationPlayerColor4A = '/Client/Preferences/Profile/Application/PlayerColor4A', - ClientPreferencesProfileApplicationPlayerColor4B = '/Client/Preferences/Profile/Application/PlayerColor4B', - ClientPreferencesProfileApplicationSyncMode = '/Client/Preferences/Profile/Application/SyncMode', - EngineDeck1CurrentBPM = '/Engine/Deck1/CurrentBPM', - EngineDeck1ExternalMixerVolume = '/Engine/Deck1/ExternalMixerVolume', - EngineDeck1ExternalScratchWheelTouch = '/Engine/Deck1/ExternalScratchWheelTouch', - EngineDeck1PadsView = '/Engine/Deck1/Pads/View', - EngineDeck1Play = '/Engine/Deck1/Play', - EngineDeck1PlayState = '/Engine/Deck1/PlayState', - EngineDeck1PlayStatePath = '/Engine/Deck1/PlayStatePath', - EngineDeck1Speed = '/Engine/Deck1/Speed', - EngineDeck1SpeedNeutral = '/Engine/Deck1/SpeedNeutral', - EngineDeck1SpeedOffsetDown = '/Engine/Deck1/SpeedOffsetDown', - EngineDeck1SpeedOffsetUp = '/Engine/Deck1/SpeedOffsetUp', - EngineDeck1SpeedRange = '/Engine/Deck1/SpeedRange', - EngineDeck1SpeedState = '/Engine/Deck1/SpeedState', - EngineDeck1SyncMode = '/Engine/Deck1/SyncMode', - EngineDeck1TrackArtistName = '/Engine/Deck1/Track/ArtistName', - EngineDeck1TrackBleep = '/Engine/Deck1/Track/Bleep', - EngineDeck1TrackCuePosition = '/Engine/Deck1/Track/CuePosition', - EngineDeck1TrackCurrentBPM = '/Engine/Deck1/Track/CurrentBPM', - EngineDeck1TrackCurrentKeyIndex = '/Engine/Deck1/Track/CurrentKeyIndex', - EngineDeck1TrackCurrentLoopInPosition = '/Engine/Deck1/Track/CurrentLoopInPosition', - EngineDeck1TrackCurrentLoopOutPosition = '/Engine/Deck1/Track/CurrentLoopOutPosition', - EngineDeck1TrackCurrentLoopSizeInBeats = '/Engine/Deck1/Track/CurrentLoopSizeInBeats', - EngineDeck1TrackKeyLock = '/Engine/Deck1/Track/KeyLock', - EngineDeck1TrackLoopEnableState = '/Engine/Deck1/Track/LoopEnableState', - EngineDeck1TrackLoopQuickLoop1 = '/Engine/Deck1/Track/Loop/QuickLoop1', - EngineDeck1TrackLoopQuickLoop2 = '/Engine/Deck1/Track/Loop/QuickLoop2', - EngineDeck1TrackLoopQuickLoop3 = '/Engine/Deck1/Track/Loop/QuickLoop3', - EngineDeck1TrackLoopQuickLoop4 = '/Engine/Deck1/Track/Loop/QuickLoop4', - EngineDeck1TrackLoopQuickLoop5 = '/Engine/Deck1/Track/Loop/QuickLoop5', - EngineDeck1TrackLoopQuickLoop6 = '/Engine/Deck1/Track/Loop/QuickLoop6', - EngineDeck1TrackLoopQuickLoop7 = '/Engine/Deck1/Track/Loop/QuickLoop7', - EngineDeck1TrackLoopQuickLoop8 = '/Engine/Deck1/Track/Loop/QuickLoop8', - EngineDeck1TrackPlayPauseLEDState = '/Engine/Deck1/Track/PlayPauseLEDState', - EngineDeck1TrackSampleRate = '/Engine/Deck1/Track/SampleRate', - EngineDeck1TrackSongAnalyzed = '/Engine/Deck1/Track/SongAnalyzed', - EngineDeck1TrackSongLoaded = '/Engine/Deck1/Track/SongLoaded', - EngineDeck1TrackSongName = '/Engine/Deck1/Track/SongName', - EngineDeck1TrackSoundSwitchGUID = '/Engine/Deck1/Track/SoundSwitchGuid', - EngineDeck1TrackTrackBytes = '/Engine/Deck1/Track/TrackBytes', - EngineDeck1TrackTrackData = '/Engine/Deck1/Track/TrackData', - EngineDeck1TrackTrackLength = '/Engine/Deck1/Track/TrackLength', - EngineDeck1TrackTrackName = '/Engine/Deck1/Track/TrackName', - EngineDeck1TrackTrackNetworkPath = '/Engine/Deck1/Track/TrackNetworkPath', - EngineDeck1TrackTrackURI = '/Engine/Deck1/Track/TrackUri', - EngineDeck1TrackTrackWasPlayed = '/Engine/Deck1/Track/TrackWasPlayed', - EngineDeck2CurrentBPM = '/Engine/Deck2/CurrentBPM', - EngineDeck2ExternalMixerVolume = '/Engine/Deck2/ExternalMixerVolume', - EngineDeck2ExternalScratchWheelTouch = '/Engine/Deck2/ExternalScratchWheelTouch', - EngineDeck2PadsView = '/Engine/Deck2/Pads/View', - EngineDeck2Play = '/Engine/Deck2/Play', - EngineDeck2PlayState = '/Engine/Deck2/PlayState', - EngineDeck2PlayStatePath = '/Engine/Deck2/PlayStatePath', - EngineDeck2Speed = '/Engine/Deck2/Speed', - EngineDeck2SpeedNeutral = '/Engine/Deck2/SpeedNeutral', - EngineDeck2SpeedOffsetDown = '/Engine/Deck2/SpeedOffsetDown', - EngineDeck2SpeedOffsetUp = '/Engine/Deck2/SpeedOffsetUp', - EngineDeck2SpeedRange = '/Engine/Deck2/SpeedRange', - EngineDeck2SpeedState = '/Engine/Deck2/SpeedState', - EngineDeck2SyncMode = '/Engine/Deck2/SyncMode', - EngineDeck2TrackArtistName = '/Engine/Deck2/Track/ArtistName', - EngineDeck2TrackBleep = '/Engine/Deck2/Track/Bleep', - EngineDeck2TrackCuePosition = '/Engine/Deck2/Track/CuePosition', - EngineDeck2TrackCurrentBPM = '/Engine/Deck2/Track/CurrentBPM', - EngineDeck2TrackCurrentKeyIndex = '/Engine/Deck2/Track/CurrentKeyIndex', - EngineDeck2TrackCurrentLoopInPosition = '/Engine/Deck2/Track/CurrentLoopInPosition', - EngineDeck2TrackCurrentLoopOutPosition = '/Engine/Deck2/Track/CurrentLoopOutPosition', - EngineDeck2TrackCurrentLoopSizeInBeats = '/Engine/Deck2/Track/CurrentLoopSizeInBeats', - EngineDeck2TrackKeyLock = '/Engine/Deck2/Track/KeyLock', - EngineDeck2TrackLoopEnableState = '/Engine/Deck2/Track/LoopEnableState', - EngineDeck2TrackLoopQuickLoop1 = '/Engine/Deck2/Track/Loop/QuickLoop1', - EngineDeck2TrackLoopQuickLoop2 = '/Engine/Deck2/Track/Loop/QuickLoop2', - EngineDeck2TrackLoopQuickLoop3 = '/Engine/Deck2/Track/Loop/QuickLoop3', - EngineDeck2TrackLoopQuickLoop4 = '/Engine/Deck2/Track/Loop/QuickLoop4', - EngineDeck2TrackLoopQuickLoop5 = '/Engine/Deck2/Track/Loop/QuickLoop5', - EngineDeck2TrackLoopQuickLoop6 = '/Engine/Deck2/Track/Loop/QuickLoop6', - EngineDeck2TrackLoopQuickLoop7 = '/Engine/Deck2/Track/Loop/QuickLoop7', - EngineDeck2TrackLoopQuickLoop8 = '/Engine/Deck2/Track/Loop/QuickLoop8', - EngineDeck2TrackPlayPauseLEDState = '/Engine/Deck2/Track/PlayPauseLEDState', - EngineDeck2TrackSampleRate = '/Engine/Deck2/Track/SampleRate', - EngineDeck2TrackSongAnalyzed = '/Engine/Deck2/Track/SongAnalyzed', - EngineDeck2TrackSongLoaded = '/Engine/Deck2/Track/SongLoaded', - EngineDeck2TrackSongName = '/Engine/Deck2/Track/SongName', - EngineDeck2TrackSoundSwitchGUID = '/Engine/Deck2/Track/SoundSwitchGuid', - EngineDeck2TrackTrackBytes = '/Engine/Deck2/Track/TrackBytes', - EngineDeck2TrackTrackData = '/Engine/Deck2/Track/TrackData', - EngineDeck2TrackTrackLength = '/Engine/Deck2/Track/TrackLength', - EngineDeck2TrackTrackName = '/Engine/Deck2/Track/TrackName', - EngineDeck2TrackTrackNetworkPath = '/Engine/Deck2/Track/TrackNetworkPath', - EngineDeck2TrackTrackURI = '/Engine/Deck2/Track/TrackUri', - EngineDeck2TrackTrackWasPlayed = '/Engine/Deck2/Track/TrackWasPlayed', - EngineDeck3CurrentBPM = '/Engine/Deck3/CurrentBPM', - EngineDeck3ExternalMixerVolume = '/Engine/Deck3/ExternalMixerVolume', - EngineDeck3ExternalScratchWheelTouch = '/Engine/Deck3/ExternalScratchWheelTouch', - EngineDeck3PadsView = '/Engine/Deck3/Pads/View', - EngineDeck3Play = '/Engine/Deck3/Play', - EngineDeck3PlayState = '/Engine/Deck3/PlayState', - EngineDeck3PlayStatePath = '/Engine/Deck3/PlayStatePath', - EngineDeck3Speed = '/Engine/Deck3/Speed', - EngineDeck3SpeedNeutral = '/Engine/Deck3/SpeedNeutral', - EngineDeck3SpeedOffsetDown = '/Engine/Deck3/SpeedOffsetDown', - EngineDeck3SpeedOffsetUp = '/Engine/Deck3/SpeedOffsetUp', - EngineDeck3SpeedRange = '/Engine/Deck3/SpeedRange', - EngineDeck3SpeedState = '/Engine/Deck3/SpeedState', - EngineDeck3SyncMode = '/Engine/Deck3/SyncMode', - EngineDeck3TrackArtistName = '/Engine/Deck3/Track/ArtistName', - EngineDeck3TrackBleep = '/Engine/Deck3/Track/Bleep', - EngineDeck3TrackCuePosition = '/Engine/Deck3/Track/CuePosition', - EngineDeck3TrackCurrentBPM = '/Engine/Deck3/Track/CurrentBPM', - EngineDeck3TrackCurrentKeyIndex = '/Engine/Deck3/Track/CurrentKeyIndex', - EngineDeck3TrackCurrentLoopInPosition = '/Engine/Deck3/Track/CurrentLoopInPosition', - EngineDeck3TrackCurrentLoopOutPosition = '/Engine/Deck3/Track/CurrentLoopOutPosition', - EngineDeck3TrackCurrentLoopSizeInBeats = '/Engine/Deck3/Track/CurrentLoopSizeInBeats', - EngineDeck3TrackKeyLock = '/Engine/Deck3/Track/KeyLock', - EngineDeck3TrackLoopEnableState = '/Engine/Deck3/Track/LoopEnableState', - EngineDeck3TrackLoopQuickLoop1 = '/Engine/Deck3/Track/Loop/QuickLoop1', - EngineDeck3TrackLoopQuickLoop2 = '/Engine/Deck3/Track/Loop/QuickLoop2', - EngineDeck3TrackLoopQuickLoop3 = '/Engine/Deck3/Track/Loop/QuickLoop3', - EngineDeck3TrackLoopQuickLoop4 = '/Engine/Deck3/Track/Loop/QuickLoop4', - EngineDeck3TrackLoopQuickLoop5 = '/Engine/Deck3/Track/Loop/QuickLoop5', - EngineDeck3TrackLoopQuickLoop6 = '/Engine/Deck3/Track/Loop/QuickLoop6', - EngineDeck3TrackLoopQuickLoop7 = '/Engine/Deck3/Track/Loop/QuickLoop7', - EngineDeck3TrackLoopQuickLoop8 = '/Engine/Deck3/Track/Loop/QuickLoop8', - EngineDeck3TrackPlayPauseLEDState = '/Engine/Deck3/Track/PlayPauseLEDState', - EngineDeck3TrackSampleRate = '/Engine/Deck3/Track/SampleRate', - EngineDeck3TrackSongAnalyzed = '/Engine/Deck3/Track/SongAnalyzed', - EngineDeck3TrackSongLoaded = '/Engine/Deck3/Track/SongLoaded', - EngineDeck3TrackSongName = '/Engine/Deck3/Track/SongName', - EngineDeck3TrackSoundSwitchGUID = '/Engine/Deck3/Track/SoundSwitchGuid', - EngineDeck3TrackTrackBytes = '/Engine/Deck3/Track/TrackBytes', - EngineDeck3TrackTrackData = '/Engine/Deck3/Track/TrackData', - EngineDeck3TrackTrackLength = '/Engine/Deck3/Track/TrackLength', - EngineDeck3TrackTrackName = '/Engine/Deck3/Track/TrackName', - EngineDeck3TrackTrackNetworkPath = '/Engine/Deck3/Track/TrackNetworkPath', - EngineDeck3TrackTrackURI = '/Engine/Deck3/Track/TrackUri', - EngineDeck3TrackTrackWasPlayed = '/Engine/Deck3/Track/TrackWasPlayed', - EngineDeck4CurrentBPM = '/Engine/Deck4/CurrentBPM', - EngineDeck4ExternalMixerVolume = '/Engine/Deck4/ExternalMixerVolume', - EngineDeck4ExternalScratchWheelTouch = '/Engine/Deck4/ExternalScratchWheelTouch', - EngineDeck4PadsView = '/Engine/Deck4/Pads/View', - EngineDeck4Play = '/Engine/Deck4/Play', - EngineDeck4PlayState = '/Engine/Deck4/PlayState', - EngineDeck4PlayStatePath = '/Engine/Deck4/PlayStatePath', - EngineDeck4Speed = '/Engine/Deck4/Speed', - EngineDeck4SpeedNeutral = '/Engine/Deck4/SpeedNeutral', - EngineDeck4SpeedOffsetDown = '/Engine/Deck4/SpeedOffsetDown', - EngineDeck4SpeedOffsetUp = '/Engine/Deck4/SpeedOffsetUp', - EngineDeck4SpeedRange = '/Engine/Deck4/SpeedRange', - EngineDeck4SpeedState = '/Engine/Deck4/SpeedState', - EngineDeck4SyncMode = '/Engine/Deck4/SyncMode', - EngineDeck4TrackArtistName = '/Engine/Deck4/Track/ArtistName', - EngineDeck4TrackBleep = '/Engine/Deck4/Track/Bleep', - EngineDeck4TrackCuePosition = '/Engine/Deck4/Track/CuePosition', - EngineDeck4TrackCurrentBPM = '/Engine/Deck4/Track/CurrentBPM', - EngineDeck4TrackCurrentKeyIndex = '/Engine/Deck4/Track/CurrentKeyIndex', - EngineDeck4TrackCurrentLoopInPosition = '/Engine/Deck4/Track/CurrentLoopInPosition', - EngineDeck4TrackCurrentLoopOutPosition = '/Engine/Deck4/Track/CurrentLoopOutPosition', - EngineDeck4TrackCurrentLoopSizeInBeats = '/Engine/Deck4/Track/CurrentLoopSizeInBeats', - EngineDeck4TrackKeyLock = '/Engine/Deck4/Track/KeyLock', - EngineDeck4TrackLoopEnableState = '/Engine/Deck4/Track/LoopEnableState', - EngineDeck4TrackLoopQuickLoop1 = '/Engine/Deck4/Track/Loop/QuickLoop1', - EngineDeck4TrackLoopQuickLoop2 = '/Engine/Deck4/Track/Loop/QuickLoop2', - EngineDeck4TrackLoopQuickLoop3 = '/Engine/Deck4/Track/Loop/QuickLoop3', - EngineDeck4TrackLoopQuickLoop4 = '/Engine/Deck4/Track/Loop/QuickLoop4', - EngineDeck4TrackLoopQuickLoop5 = '/Engine/Deck4/Track/Loop/QuickLoop5', - EngineDeck4TrackLoopQuickLoop6 = '/Engine/Deck4/Track/Loop/QuickLoop6', - EngineDeck4TrackLoopQuickLoop7 = '/Engine/Deck4/Track/Loop/QuickLoop7', - EngineDeck4TrackLoopQuickLoop8 = '/Engine/Deck4/Track/Loop/QuickLoop8', - EngineDeck4TrackPlayPauseLEDState = '/Engine/Deck4/Track/PlayPauseLEDState', - EngineDeck4TrackSampleRate = '/Engine/Deck4/Track/SampleRate', - EngineDeck4TrackSongAnalyzed = '/Engine/Deck4/Track/SongAnalyzed', - EngineDeck4TrackSongLoaded = '/Engine/Deck4/Track/SongLoaded', - EngineDeck4TrackSongName = '/Engine/Deck4/Track/SongName', - EngineDeck4TrackSoundSwitchGUID = '/Engine/Deck4/Track/SoundSwitchGuid', - EngineDeck4TrackTrackBytes = '/Engine/Deck4/Track/TrackBytes', - EngineDeck4TrackTrackData = '/Engine/Deck4/Track/TrackData', - EngineDeck4TrackTrackLength = '/Engine/Deck4/Track/TrackLength', - EngineDeck4TrackTrackName = '/Engine/Deck4/Track/TrackName', - EngineDeck4TrackTrackNetworkPath = '/Engine/Deck4/Track/TrackNetworkPath', - EngineDeck4TrackTrackURI = '/Engine/Deck4/Track/TrackUri', - EngineDeck4TrackTrackWasPlayed = '/Engine/Deck4/Track/TrackWasPlayed', - EngineDeckCount = '/Engine/DeckCount', - GUIDecksDeckActiveDeck = '/GUI/Decks/Deck/ActiveDeck', - GUIViewLayerLayerB = '/GUI/ViewLayer/LayerB', - MixerCH1faderPosition = '/Mixer/CH1faderPosition', - MixerCH2faderPosition = '/Mixer/CH2faderPosition', - MixerCH3faderPosition = '/Mixer/CH3faderPosition', - MixerCH4faderPosition = '/Mixer/CH4faderPosition', - MixerCrossfaderPosition = '/Mixer/CrossfaderPosition', - - MixerNumberOfChannels = '/Mixer/NumberOfChannels', - ClientPreferencesPlayerJogColorA = '/Client/Preferences/PlayerJogColorA', - ClientPreferencesPlayerJogColorB = '/Client/Preferences/PlayerJogColorB', - EngineDeck1DeckIsMaster = '/Client/Deck1/DeckIsMaster', - EngineDeck2DeckIsMaster = '/Client/Deck2/DeckIsMaster', - ClientPreferencesLayerA = '/Client/Preferences/LayerA', - EngineSyncNetworkMasterStatus = '/Engine/Sync/Network/MasterStatus', - EngineMasterMasterTempo = '/Engine/Master/MasterTempo', - MixerChannelAssignment1 = '/Mixer/ChannelAssignment1', - MixerChannelAssignment2 = '/Mixer/ChannelAssignment2', - MixerChannelAssignment3 = '/Mixer/ChannelAssignment3', - MixerChannelAssignment4 = '/Mixer/ChannelAssignment4', -} diff --git a/types/index.ts b/types/index.ts index 3858ee2..54b8799 100644 --- a/types/index.ts +++ b/types/index.ts @@ -1,54 +1,4 @@ -import { DiscoveryMessageOptions } from '../network'; - -export * from './common'; -export * from './player'; -export * from './tokens'; export * from './models'; - -export interface DiscoveryMessage { - token: Uint8Array; - source: string; - action: string; - software: { - name: string; - version: string; - }; - port: number; -} - -export interface ServicePorts { - [key: string]: number; -} - -export interface ServiceMessage { - id: number; - message: T; -} - -export interface Source { - name: string; - database: { - location: string; - size: number; - }; -} - -export interface FileTransferInfo { - txid: number; - size: number; -} - -// TODO: Maybe some kind of validation? -export type IpAddress = string; - -export interface ConnectionInfo extends DiscoveryMessage { - address: IpAddress; -} - - -export interface StageLinqOptions { - maxRetries?: number; - actingAs?: DiscoveryMessageOptions; - downloadDbSources?: boolean; - enableFileTranfer?: boolean; -} \ No newline at end of file +export * from './messages'; +export * from './options'; +export * from './DeviceId'; diff --git a/types/messages.ts b/types/messages.ts new file mode 100644 index 0000000..68d69e2 --- /dev/null +++ b/types/messages.ts @@ -0,0 +1,32 @@ +import { DeviceId } from './DeviceId'; + + +export interface DiscoveryMessage { + deviceId: DeviceId; + source: string; + action: string; + software: { + name: string; + version: string; + }; + port: number; +} + +export interface ConnectionInfo extends DiscoveryMessage { + address: IpAddress; + unit?: { + name: string, + type: string, + decks: number + }; +} + +export interface ServiceMessage { + id: number; + message: T; +} + + +// TODO: Maybe some kind of validation? +export type IpAddress = string; +export type IpAddressPort = string; \ No newline at end of file diff --git a/types/models/State.ts b/types/models/State.ts new file mode 100644 index 0000000..507f1a3 --- /dev/null +++ b/types/models/State.ts @@ -0,0 +1,246 @@ +export const StateNames = { + player: { + ClientLibrarianDevicesControllerCurrentDevice: '/Client/Librarian/DevicesController/CurrentDevice', + ClientLibrarianDevicesControllerCurrentDeviceNetworkPath: '/Client/Librarian/DevicesController/CurrentDeviceNetworkPath', + ClientLibrarianDevicesControllerHasSDCardConnected: '/Client/Librarian/DevicesController/HasSDCardConnected', + ClientLibrarianDevicesControllerHasUsbDeviceConnected: '/Client/Librarian/DevicesController/HasUsbDeviceConnected', + ClientPreferencesLayerA: '/Client/Preferences/LayerA', + ClientPreferencesLayerB: '/Client/Preferences/LayerB', + ClientPreferencesPlayer: '/Client/Preferences/Player', + ClientPreferencesPlayerJogColorA: '/Client/Preferences/PlayerJogColorA', + ClientPreferencesPlayerJogColorB: '/Client/Preferences/PlayerJogColorB', + ClientPreferencesProfileApplicationPlayerColor1: '/Client/Preferences/Profile/Application/PlayerColor1', + ClientPreferencesProfileApplicationPlayerColor1A: '/Client/Preferences/Profile/Application/PlayerColor1A', + ClientPreferencesProfileApplicationPlayerColor1B: '/Client/Preferences/Profile/Application/PlayerColor1B', + ClientPreferencesProfileApplicationPlayerColor2: '/Client/Preferences/Profile/Application/PlayerColor2', + ClientPreferencesProfileApplicationPlayerColor2A: '/Client/Preferences/Profile/Application/PlayerColor2A', + ClientPreferencesProfileApplicationPlayerColor2B: '/Client/Preferences/Profile/Application/PlayerColor2B', + ClientPreferencesProfileApplicationPlayerColor3: '/Client/Preferences/Profile/Application/PlayerColor3', + ClientPreferencesProfileApplicationPlayerColor3A: '/Client/Preferences/Profile/Application/PlayerColor3A', + ClientPreferencesProfileApplicationPlayerColor3B: '/Client/Preferences/Profile/Application/PlayerColor3B', + ClientPreferencesProfileApplicationPlayerColor4: '/Client/Preferences/Profile/Application/PlayerColor4', + ClientPreferencesProfileApplicationPlayerColor4A: '/Client/Preferences/Profile/Application/PlayerColor4A', + ClientPreferencesProfileApplicationPlayerColor4B: '/Client/Preferences/Profile/Application/PlayerColor4B', + ClientPreferencesProfileApplicationSyncMode: '/Client/Preferences/Profile/Application/SyncMode', + EngineDeckCount: '/Engine/DeckCount', + EngineMasterMasterTempo: '/Engine/Master/MasterTempo', + EngineSyncNetworkMasterStatus: '/Engine/Sync/Network/MasterStatus', + EngineSyncNetworkSyncType: '/Engine/Sync/Network/SyncType', + EngineSyncAnchoredBeatGridStateAnyLocalAnchoredTrackLoaded: '/Engine/Sync/AnchoredBeatGridState/AnyLocalAnchoredTrackLoaded', + GUIDecksDeckActiveDeck: '/GUI/Decks/Deck/ActiveDeck', + GUIViewLayerLayerB: '/GUI/ViewLayer/LayerB', + + EngineDeck1Color: '/Engine/Deck1/Color', + EngineDeck1CurrentBPM: '/Engine/Deck1/CurrentBPM', + EngineDeck1DeckIsMaster: '/Engine/Deck1/DeckIsMaster', + EngineDeck1ExternalMixerVolume: '/Engine/Deck1/ExternalMixerVolume', + EngineDeck1ExternalScratchWheelTouch: '/Engine/Deck1/ExternalScratchWheelTouch', + EngineDeck1PadsView: '/Engine/Deck1/Pads/View', + EngineDeck1Play: '/Engine/Deck1/Play', + EngineDeck1PlayState: '/Engine/Deck1/PlayState', + EngineDeck1PlayStatePath: '/Engine/Deck1/PlayStatePath', + EngineDeck1RequestUnsetSyncLead: '/Engine/Deck1/RequestUnsetSyncLead', + EngineDeck1Speed: '/Engine/Deck1/Speed', + EngineDeck1SpeedNeutral: '/Engine/Deck1/SpeedNeutral', + EngineDeck1SpeedOffsetDown: '/Engine/Deck1/SpeedOffsetDown', + EngineDeck1SpeedOffsetUp: '/Engine/Deck1/SpeedOffsetUp', + EngineDeck1SpeedRange: '/Engine/Deck1/SpeedRange', + EngineDeck1SpeedState: '/Engine/Deck1/SpeedState', + EngineDeck1SyncMode: '/Engine/Deck1/SyncMode', + EngineDeck1SyncPlayState: '/Engine/Deck1/SyncPlayState', + EngineDeck1TrackArtistName: '/Engine/Deck1/Track/ArtistName', + EngineDeck1TrackBleep: '/Engine/Deck1/Track/Bleep', + EngineDeck1TrackCuePosition: '/Engine/Deck1/Track/CuePosition', + EngineDeck1TrackCurrentBPM: '/Engine/Deck1/Track/CurrentBPM', + EngineDeck1TrackCurrentKeyIndex: '/Engine/Deck1/Track/CurrentKeyIndex', + EngineDeck1TrackCurrentLoopInPosition: '/Engine/Deck1/Track/CurrentLoopInPosition', + EngineDeck1TrackCurrentLoopOutPosition: '/Engine/Deck1/Track/CurrentLoopOutPosition', + EngineDeck1TrackCurrentLoopSizeInBeats: '/Engine/Deck1/Track/CurrentLoopSizeInBeats', + EngineDeck1TrackKeyLock: '/Engine/Deck1/Track/KeyLock', + EngineDeck1TrackLoopEnableState: '/Engine/Deck1/Track/LoopEnableState', + EngineDeck1TrackLoopQuickLoop1: '/Engine/Deck1/Track/Loop/QuickLoop1', + EngineDeck1TrackLoopQuickLoop2: '/Engine/Deck1/Track/Loop/QuickLoop2', + EngineDeck1TrackLoopQuickLoop3: '/Engine/Deck1/Track/Loop/QuickLoop3', + EngineDeck1TrackLoopQuickLoop4: '/Engine/Deck1/Track/Loop/QuickLoop4', + EngineDeck1TrackLoopQuickLoop5: '/Engine/Deck1/Track/Loop/QuickLoop5', + EngineDeck1TrackLoopQuickLoop6: '/Engine/Deck1/Track/Loop/QuickLoop6', + EngineDeck1TrackLoopQuickLoop7: '/Engine/Deck1/Track/Loop/QuickLoop7', + EngineDeck1TrackLoopQuickLoop8: '/Engine/Deck1/Track/Loop/QuickLoop8', + EngineDeck1TrackPlayPauseLEDState: '/Engine/Deck1/Track/PlayPauseLEDState', + EngineDeck1TrackSampleRate: '/Engine/Deck1/Track/SampleRate', + EngineDeck1TrackSongAnalyzed: '/Engine/Deck1/Track/SongAnalyzed', + EngineDeck1TrackSongLoaded: '/Engine/Deck1/Track/SongLoaded', + EngineDeck1TrackSongName: '/Engine/Deck1/Track/SongName', + EngineDeck1TrackSoundSwitchGUID: '/Engine/Deck1/Track/SoundSwitchGuid', + EngineDeck1TrackTrackBytes: '/Engine/Deck1/Track/TrackBytes', + EngineDeck1TrackTrackData: '/Engine/Deck1/Track/TrackData', + EngineDeck1TrackTrackLength: '/Engine/Deck1/Track/TrackLength', + EngineDeck1TrackTrackName: '/Engine/Deck1/Track/TrackName', + EngineDeck1TrackTrackNetworkPath: '/Engine/Deck1/Track/TrackNetworkPath', + EngineDeck1TrackTrackURI: '/Engine/Deck1/Track/TrackUri', + EngineDeck1TrackTrackWasPlayed: '/Engine/Deck1/Track/TrackWasPlayed', + + EngineDeck2Color: '/Engine/Deck2/Color', + EngineDeck2CurrentBPM: '/Engine/Deck2/CurrentBPM', + EngineDeck2DeckIsMaster: '/Engine/Deck2/DeckIsMaster', + EngineDeck2ExternalMixerVolume: '/Engine/Deck2/ExternalMixerVolume', + EngineDeck2ExternalScratchWheelTouch: '/Engine/Deck2/ExternalScratchWheelTouch', + EngineDeck2PadsView: '/Engine/Deck2/Pads/View', + EngineDeck2Play: '/Engine/Deck2/Play', + EngineDeck2PlayState: '/Engine/Deck2/PlayState', + EngineDeck2PlayStatePath: '/Engine/Deck2/PlayStatePath', + EngineDeck2RequestUnsetSyncLead: '/Engine/Deck2/RequestUnsetSyncLead', + EngineDeck2Speed: '/Engine/Deck2/Speed', + EngineDeck2SpeedNeutral: '/Engine/Deck2/SpeedNeutral', + EngineDeck2SpeedOffsetDown: '/Engine/Deck2/SpeedOffsetDown', + EngineDeck2SpeedOffsetUp: '/Engine/Deck2/SpeedOffsetUp', + EngineDeck2SpeedRange: '/Engine/Deck2/SpeedRange', + EngineDeck2SpeedState: '/Engine/Deck2/SpeedState', + EngineDeck2SyncMode: '/Engine/Deck2/SyncMode', + EngineDeck2SyncPlayState: '/Engine/Deck2/SyncPlayState', + EngineDeck2TrackArtistName: '/Engine/Deck2/Track/ArtistName', + EngineDeck2TrackBleep: '/Engine/Deck2/Track/Bleep', + EngineDeck2TrackCuePosition: '/Engine/Deck2/Track/CuePosition', + EngineDeck2TrackCurrentBPM: '/Engine/Deck2/Track/CurrentBPM', + EngineDeck2TrackCurrentKeyIndex: '/Engine/Deck2/Track/CurrentKeyIndex', + EngineDeck2TrackCurrentLoopInPosition: '/Engine/Deck2/Track/CurrentLoopInPosition', + EngineDeck2TrackCurrentLoopOutPosition: '/Engine/Deck2/Track/CurrentLoopOutPosition', + EngineDeck2TrackCurrentLoopSizeInBeats: '/Engine/Deck2/Track/CurrentLoopSizeInBeats', + EngineDeck2TrackKeyLock: '/Engine/Deck2/Track/KeyLock', + EngineDeck2TrackLoopEnableState: '/Engine/Deck2/Track/LoopEnableState', + EngineDeck2TrackLoopQuickLoop1: '/Engine/Deck2/Track/Loop/QuickLoop1', + EngineDeck2TrackLoopQuickLoop2: '/Engine/Deck2/Track/Loop/QuickLoop2', + EngineDeck2TrackLoopQuickLoop3: '/Engine/Deck2/Track/Loop/QuickLoop3', + EngineDeck2TrackLoopQuickLoop4: '/Engine/Deck2/Track/Loop/QuickLoop4', + EngineDeck2TrackLoopQuickLoop5: '/Engine/Deck2/Track/Loop/QuickLoop5', + EngineDeck2TrackLoopQuickLoop6: '/Engine/Deck2/Track/Loop/QuickLoop6', + EngineDeck2TrackLoopQuickLoop7: '/Engine/Deck2/Track/Loop/QuickLoop7', + EngineDeck2TrackLoopQuickLoop8: '/Engine/Deck2/Track/Loop/QuickLoop8', + EngineDeck2TrackPlayPauseLEDState: '/Engine/Deck2/Track/PlayPauseLEDState', + EngineDeck2TrackSampleRate: '/Engine/Deck2/Track/SampleRate', + EngineDeck2TrackSongAnalyzed: '/Engine/Deck2/Track/SongAnalyzed', + EngineDeck2TrackSongLoaded: '/Engine/Deck2/Track/SongLoaded', + EngineDeck2TrackSongName: '/Engine/Deck2/Track/SongName', + EngineDeck2TrackSoundSwitchGUID: '/Engine/Deck2/Track/SoundSwitchGuid', + EngineDeck2TrackTrackBytes: '/Engine/Deck2/Track/TrackBytes', + EngineDeck2TrackTrackData: '/Engine/Deck2/Track/TrackData', + EngineDeck2TrackTrackLength: '/Engine/Deck2/Track/TrackLength', + EngineDeck2TrackTrackName: '/Engine/Deck2/Track/TrackName', + EngineDeck2TrackTrackNetworkPath: '/Engine/Deck2/Track/TrackNetworkPath', + EngineDeck2TrackTrackURI: '/Engine/Deck2/Track/TrackUri', + EngineDeck2TrackTrackWasPlayed: '/Engine/Deck2/Track/TrackWasPlayed', + + EngineDeck3Color: '/Engine/Deck3/Color', + EngineDeck3CurrentBPM: '/Engine/Deck3/CurrentBPM', + EngineDeck3DeckIsMaster: '/Engine/Deck3/DeckIsMaster', + EngineDeck3ExternalMixerVolume: '/Engine/Deck3/ExternalMixerVolume', + EngineDeck3ExternalScratchWheelTouch: '/Engine/Deck3/ExternalScratchWheelTouch', + EngineDeck3PadsView: '/Engine/Deck3/Pads/View', + EngineDeck3Play: '/Engine/Deck3/Play', + EngineDeck3PlayState: '/Engine/Deck3/PlayState', + EngineDeck3PlayStatePath: '/Engine/Deck3/PlayStatePath', + EngineDeck3RequestUnsetSyncLead: '/Engine/Deck3/RequestUnsetSyncLead', + EngineDeck3Speed: '/Engine/Deck3/Speed', + EngineDeck3SpeedNeutral: '/Engine/Deck3/SpeedNeutral', + EngineDeck3SpeedOffsetDown: '/Engine/Deck3/SpeedOffsetDown', + EngineDeck3SpeedOffsetUp: '/Engine/Deck3/SpeedOffsetUp', + EngineDeck3SpeedRange: '/Engine/Deck3/SpeedRange', + EngineDeck3SpeedState: '/Engine/Deck3/SpeedState', + EngineDeck3SyncMode: '/Engine/Deck3/SyncMode', + EngineDeck3SyncPlayState: '/Engine/Deck3/SyncPlayState', + EngineDeck3TrackArtistName: '/Engine/Deck3/Track/ArtistName', + EngineDeck3TrackBleep: '/Engine/Deck3/Track/Bleep', + EngineDeck3TrackCuePosition: '/Engine/Deck3/Track/CuePosition', + EngineDeck3TrackCurrentBPM: '/Engine/Deck3/Track/CurrentBPM', + EngineDeck3TrackCurrentKeyIndex: '/Engine/Deck3/Track/CurrentKeyIndex', + EngineDeck3TrackCurrentLoopInPosition: '/Engine/Deck3/Track/CurrentLoopInPosition', + EngineDeck3TrackCurrentLoopOutPosition: '/Engine/Deck3/Track/CurrentLoopOutPosition', + EngineDeck3TrackCurrentLoopSizeInBeats: '/Engine/Deck3/Track/CurrentLoopSizeInBeats', + EngineDeck3TrackKeyLock: '/Engine/Deck3/Track/KeyLock', + EngineDeck3TrackLoopEnableState: '/Engine/Deck3/Track/LoopEnableState', + EngineDeck3TrackLoopQuickLoop1: '/Engine/Deck3/Track/Loop/QuickLoop1', + EngineDeck3TrackLoopQuickLoop2: '/Engine/Deck3/Track/Loop/QuickLoop2', + EngineDeck3TrackLoopQuickLoop3: '/Engine/Deck3/Track/Loop/QuickLoop3', + EngineDeck3TrackLoopQuickLoop4: '/Engine/Deck3/Track/Loop/QuickLoop4', + EngineDeck3TrackLoopQuickLoop5: '/Engine/Deck3/Track/Loop/QuickLoop5', + EngineDeck3TrackLoopQuickLoop6: '/Engine/Deck3/Track/Loop/QuickLoop6', + EngineDeck3TrackLoopQuickLoop7: '/Engine/Deck3/Track/Loop/QuickLoop7', + EngineDeck3TrackLoopQuickLoop8: '/Engine/Deck3/Track/Loop/QuickLoop8', + EngineDeck3TrackPlayPauseLEDState: '/Engine/Deck3/Track/PlayPauseLEDState', + EngineDeck3TrackSampleRate: '/Engine/Deck3/Track/SampleRate', + EngineDeck3TrackSongAnalyzed: '/Engine/Deck3/Track/SongAnalyzed', + EngineDeck3TrackSongLoaded: '/Engine/Deck3/Track/SongLoaded', + EngineDeck3TrackSongName: '/Engine/Deck3/Track/SongName', + EngineDeck3TrackSoundSwitchGUID: '/Engine/Deck3/Track/SoundSwitchGuid', + EngineDeck3TrackTrackBytes: '/Engine/Deck3/Track/TrackBytes', + EngineDeck3TrackTrackData: '/Engine/Deck3/Track/TrackData', + EngineDeck3TrackTrackLength: '/Engine/Deck3/Track/TrackLength', + EngineDeck3TrackTrackName: '/Engine/Deck3/Track/TrackName', + EngineDeck3TrackTrackNetworkPath: '/Engine/Deck3/Track/TrackNetworkPath', + EngineDeck3TrackTrackURI: '/Engine/Deck3/Track/TrackUri', + EngineDeck3TrackTrackWasPlayed: '/Engine/Deck3/Track/TrackWasPlayed', + + EngineDeck4Color: '/Engine/Deck4/Color', + EngineDeck4CurrentBPM: '/Engine/Deck4/CurrentBPM', + EngineDeck4DeckIsMaster: '/Engine/Deck4/DeckIsMaster', + EngineDeck4ExternalMixerVolume: '/Engine/Deck4/ExternalMixerVolume', + EngineDeck4ExternalScratchWheelTouch: '/Engine/Deck4/ExternalScratchWheelTouch', + EngineDeck4PadsView: '/Engine/Deck4/Pads/View', + EngineDeck4Play: '/Engine/Deck4/Play', + EngineDeck4PlayState: '/Engine/Deck4/PlayState', + EngineDeck4PlayStatePath: '/Engine/Deck4/PlayStatePath', + EngineDeck4RequestUnsetSyncLead: '/Engine/Deck4/RequestUnsetSyncLead', + EngineDeck4Speed: '/Engine/Deck4/Speed', + EngineDeck4SpeedNeutral: '/Engine/Deck4/SpeedNeutral', + EngineDeck4SpeedOffsetDown: '/Engine/Deck4/SpeedOffsetDown', + EngineDeck4SpeedOffsetUp: '/Engine/Deck4/SpeedOffsetUp', + EngineDeck4SpeedRange: '/Engine/Deck4/SpeedRange', + EngineDeck4SpeedState: '/Engine/Deck4/SpeedState', + EngineDeck4SyncMode: '/Engine/Deck4/SyncMode', + EngineDeck4SyncPlayState: '/Engine/Deck4/SyncPlayState', + EngineDeck4TrackArtistName: '/Engine/Deck4/Track/ArtistName', + EngineDeck4TrackBleep: '/Engine/Deck4/Track/Bleep', + EngineDeck4TrackCuePosition: '/Engine/Deck4/Track/CuePosition', + EngineDeck4TrackCurrentBPM: '/Engine/Deck4/Track/CurrentBPM', + EngineDeck4TrackCurrentKeyIndex: '/Engine/Deck4/Track/CurrentKeyIndex', + EngineDeck4TrackCurrentLoopInPosition: '/Engine/Deck4/Track/CurrentLoopInPosition', + EngineDeck4TrackCurrentLoopOutPosition: '/Engine/Deck4/Track/CurrentLoopOutPosition', + EngineDeck4TrackCurrentLoopSizeInBeats: '/Engine/Deck4/Track/CurrentLoopSizeInBeats', + EngineDeck4TrackKeyLock: '/Engine/Deck4/Track/KeyLock', + EngineDeck4TrackLoopEnableState: '/Engine/Deck4/Track/LoopEnableState', + EngineDeck4TrackLoopQuickLoop1: '/Engine/Deck4/Track/Loop/QuickLoop1', + EngineDeck4TrackLoopQuickLoop2: '/Engine/Deck4/Track/Loop/QuickLoop2', + EngineDeck4TrackLoopQuickLoop3: '/Engine/Deck4/Track/Loop/QuickLoop3', + EngineDeck4TrackLoopQuickLoop4: '/Engine/Deck4/Track/Loop/QuickLoop4', + EngineDeck4TrackLoopQuickLoop5: '/Engine/Deck4/Track/Loop/QuickLoop5', + EngineDeck4TrackLoopQuickLoop6: '/Engine/Deck4/Track/Loop/QuickLoop6', + EngineDeck4TrackLoopQuickLoop7: '/Engine/Deck4/Track/Loop/QuickLoop7', + EngineDeck4TrackLoopQuickLoop8: '/Engine/Deck4/Track/Loop/QuickLoop8', + EngineDeck4TrackPlayPauseLEDState: '/Engine/Deck4/Track/PlayPauseLEDState', + EngineDeck4TrackSampleRate: '/Engine/Deck4/Track/SampleRate', + EngineDeck4TrackSongAnalyzed: '/Engine/Deck4/Track/SongAnalyzed', + EngineDeck4TrackSongLoaded: '/Engine/Deck4/Track/SongLoaded', + EngineDeck4TrackSongName: '/Engine/Deck4/Track/SongName', + EngineDeck4TrackSoundSwitchGUID: '/Engine/Deck4/Track/SoundSwitchGuid', + EngineDeck4TrackTrackBytes: '/Engine/Deck4/Track/TrackBytes', + EngineDeck4TrackTrackData: '/Engine/Deck4/Track/TrackData', + EngineDeck4TrackTrackLength: '/Engine/Deck4/Track/TrackLength', + EngineDeck4TrackTrackName: '/Engine/Deck4/Track/TrackName', + EngineDeck4TrackTrackNetworkPath: '/Engine/Deck4/Track/TrackNetworkPath', + EngineDeck4TrackTrackURI: '/Engine/Deck4/Track/TrackUri', + EngineDeck4TrackTrackWasPlayed: '/Engine/Deck4/Track/TrackWasPlayed', + }, + mixer: { + MixerCH1faderPosition: '/Mixer/CH1faderPosition', + MixerCH2faderPosition: '/Mixer/CH2faderPosition', + MixerCH3faderPosition: '/Mixer/CH3faderPosition', + MixerCH4faderPosition: '/Mixer/CH4faderPosition', + MixerCrossfaderPosition: '/Mixer/CrossfaderPosition', + MixerChannelAssignment1: '/Mixer/ChannelAssignment1', + MixerChannelAssignment2: '/Mixer/ChannelAssignment2', + MixerChannelAssignment3: '/Mixer/ChannelAssignment3', + MixerChannelAssignment4: '/Mixer/ChannelAssignment4', + MixerNumberOfChannels: '/Mixer/NumberOfChannels', + + }, +} diff --git a/types/models/Track.ts b/types/models/Track.ts index c8da51e..edeefa9 100644 --- a/types/models/Track.ts +++ b/types/models/Track.ts @@ -1,50 +1,148 @@ -export interface Track { - id: number, - playOrder: number, - length: number, - bpm: number, - year: number, - path: string, - filename: string, - bitrate: number, - bpmAnalyzed: number, - albumArtId: number, - fileBytes: number, - title: string, - artist: string, - album: string, - genre: string, - comment: string, - label: string, - composer: string, - remixer: string, - key: number, - rating: number, - albumArt: string, - timeLastPlayed: string, - isPlayed: boolean, - fileType: string, - isAnalyzed: boolean, - dateCreated: string, - dateAdded: string, - isAvailable: boolean, - isMetadataOfPackedTrackChanged: boolean, - isPerfomanceDataOfPackedTrackChanged: boolean, - playedIndicator: number, - isMetadataImported: boolean, - pdbImportKey: number, - streamingSource: string, - uri: string, - isBeatGridLocked: boolean, - originDatabaseUuid: string, - originTrackId: number, - trackData: Buffer, - overviewWaveFormData: Buffer, - beatData: Buffer, - quickCues: Buffer, - loops: Buffer, - thirdPartySourceId: number, - streamingFlags: number, - explicitLyrics: boolean, - activeOnLoadLoops: number +import { DeviceId } from "../DeviceId"; + +interface ITrackData { + source: { + name: string; + location: DeviceId; + path: string; + } + ArtistName: string; + Bleep: boolean; + CuePosition: number; + CurrentBPM: number; + CurrentKeyIndex: number; + CurrentLoopInPosition: number; + CurrentLoopOutPosition: number; + CurrentLoopSizeInBeats: number; + KeyLock: boolean; + LoopEnableState: boolean; + Loop: { + QuickLoop1: boolean; + QuickLoop2: boolean; + QuickLoop3: boolean; + QuickLoop4: boolean; + QuickLoop5: boolean; + QuickLoop6: boolean; + QuickLoop7: boolean; + QuickLoop8: boolean; + }, + PlayPauseLEDState: boolean; + SampleRate: number; + SongAnalyzed: boolean; + SongLoaded: boolean; + SongName: string; + SoundSwitchGUID: string; + TrackBytes: number; + TrackData: boolean; + TrackLength: number; + TrackName: string; + TrackNetworkPath: string; + TrackURI: string; + TrackWasPlayed: boolean; +} + +export class Track implements Partial { + #prefix: string; + #source: { + name: string; + location: DeviceId; + path: string; + } = null; + + ArtistName: string = "" + CurrentBPM: number = 0; + SampleRate: number = 0; + SongAnalyzed: boolean = false; + SongLoaded: boolean = false; + SongName: string = ""; + SoundSwitchGUID: string = ""; + TrackBytes: number = 0; + TrackLength: number = 0; + TrackName: string = ""; + TrackNetworkPath: string = ""; + TrackURI: string = ""; + + /** + * Track Type Class + * @constructor + * @param {string} prefix State prefix that should proceed the property + */ + constructor(prefix: string) { + this.#prefix = prefix; + } + + /** + * Get State Prefix + */ + get prefix() { + return this.#prefix; + } + + get source() { + if (this.TrackNetworkPath) { + const split = this.TrackNetworkPath.substring(6).split('/') + const deviceId = new DeviceId(split.shift()); + const sourceName = split.shift(); + const path = `/${sourceName}/${split.join('/')}` + this.#source = { + name: sourceName, + location: deviceId, + path: path, + } + } + return this.#source + } +} + + + +export interface TrackDBEntry { + id: number, + playOrder: number, + length: number, + bpm: number, + year: number, + path: string, + filename: string, + bitrate: number, + bpmAnalyzed: number, + albumArtId: number, + fileBytes: number, + title: string, + artist: string, + album: string, + genre: string, + comment: string, + label: string, + composer: string, + remixer: string, + key: number, + rating: number, + albumArt: string, + timeLastPlayed: string, + isPlayed: boolean, + fileType: string, + isAnalyzed: boolean, + dateCreated: string, + dateAdded: string, + isAvailable: boolean, + isMetadataOfPackedTrackChanged: boolean, + isPerfomanceDataOfPackedTrackChanged: boolean, + playedIndicator: number, + isMetadataImported: boolean, + pdbImportKey: number, + streamingSource: string, + uri: string, + isBeatGridLocked: boolean, + originDatabaseUuid: string, + originTrackId: number, + trackData: Buffer, + overviewWaveFormData: Buffer, + beatData: Buffer, + quickCues: Buffer, + loops: Buffer, + thirdPartySourceId: number, + streamingFlags: number, + explicitLyrics: boolean, + activeOnLoadLoops: number } \ No newline at end of file diff --git a/types/models/Unit.ts b/types/models/Unit.ts new file mode 100644 index 0000000..aef36cc --- /dev/null +++ b/types/models/Unit.ts @@ -0,0 +1,26 @@ + +type Unit = { + [key: string]: { + name: string, + type: string, + decks: number, + } +} + +export const Units: Unit = { + JC11: { name: 'PRIME4', type: 'CONTROLLER', decks: 4 }, + JC16: { name: 'PRIME2', type: 'CONTROLLER', decks: 2 }, + JC20: { name: 'LC6000', type: 'OTHER', decks: 0 }, + JP07: { name: 'SC5000', type: 'PLAYER', decks: 2 }, + JP08: { name: 'SC5000M', type: 'PLAYER', decks: 2 }, + JP11: { name: 'PRIMEGO', type: 'CONTROLLER', decks: 2 }, + JP13: { name: 'SC6000', type: 'PLAYER', decks: 2 }, + JP14: { name: 'SC6000M', type: 'PLAYER', decks: 2 }, + JP20: { name: 'SCLIVE2', type: 'CONTROLLER', decks: 2 }, + JP21: { name: 'SCLIVE4', type: 'CONTROLLER', decks: 4 }, + NH08: { name: 'MIXSTREAMPRO', type: 'CONTROLLER', decks: 2 }, + NH09: { name: 'MIXSTREAMPROPLUS', type: 'CONTROLLER', decks: 2 }, + NH10: { name: 'MIXSTREAMPROGO', type: 'CONTROLLER', decks: 2 }, + JM08: { name: 'DN-X1800Prime', type: 'MIXER', decks: 0 }, + JM10: { name: 'DN-X1850Prime', type: 'MIXER', decks: 0 }, +} diff --git a/types/models/index.ts b/types/models/index.ts index d694080..eaeb81d 100644 --- a/types/models/index.ts +++ b/types/models/index.ts @@ -1 +1,3 @@ -export * from './track'; \ No newline at end of file +export * from './Track'; +export * from './State'; +export * from './Unit'; \ No newline at end of file diff --git a/types/options.ts b/types/options.ts new file mode 100644 index 0000000..b0e2269 --- /dev/null +++ b/types/options.ts @@ -0,0 +1,75 @@ +import { version } from '../package.json'; +import { DeviceId } from './DeviceId'; +//import * as Services from '../services' + +export interface DiscoveryMessageOptions { + name: string; + version: string; + source: string; + deviceId: DeviceId; + port?: number +}; + +export interface StageLinqOptions { + maxRetries?: number; + actingAs?: DiscoveryMessageOptions; + downloadDbSources?: boolean; + services?: Services[]; + connectToMixer?: boolean +} + +export enum Services { + StateMap = "StateMap", + FileTransfer = "FileTransfer", + BeatInfo = "BeatInfo", + Broadcast = "Broadcast", + TimeSynchronization = "TimeSynchronization", + Directory = "Directory", +} + +const Tokens = { + SoundSwitch: new Uint8Array([82, 253, 252, 7, 33, 130, 101, 79, 22, 63, 95, 15, 154, 98, 29, 114]), + Sc6000_1: new Uint8Array([130, 139, 235, 2, 218, 31, 78, 104, 166, 175, 176, 177, 103, 234, 240, 162]), + Sc6000_2: new Uint8Array([38, 210, 56, 103, 28, 214, 78, 63, 128, 161, 17, 130, 106, 196, 17, 32]), + Resolume: new Uint8Array([136, 250, 32, 153, 172, 122, 79, 63, 188, 22, 169, 149, 219, 218, 42, 66]), + Listen: new Uint8Array([255, 255, 255, 255, 255, 255, 74, 28, 155, 186, 136, 180, 190, 25, 163, 209]) +} + +export const ActingAsDevice: { [name: string]: DiscoveryMessageOptions } = { + + StageLinqJS: { + name: 'stagelinqjs', + version: version, + source: 'SLJS', + deviceId: new DeviceId(Tokens.Listen) + }, + + NowPlaying: { + name: 'nowplaying', + version: '2.2.0', + source: 'np2', + deviceId: new DeviceId(Tokens.Listen) + }, + + Sc6000_1: { + name: 'sc6000', + version: '2.3.1', + source: 'JP13', + deviceId: new DeviceId(Tokens.Sc6000_1) + }, + + Sc6000_2: { + name: 'sc6000', + version: '2.3.1', + source: 'JP13', + deviceId: new DeviceId(Tokens.Sc6000_2) + }, + + Resolume: { + name: 'resolume', + version: '10.0.0', + source: 'res', + deviceId: new DeviceId(Tokens.Resolume) + } + +} \ No newline at end of file diff --git a/types/player.ts b/types/player.ts index 7ccb99f..10defab 100644 --- a/types/player.ts +++ b/types/player.ts @@ -1,43 +1,45 @@ +// import { DeviceId } from "../devices/DeviceId"; -export interface PlayerStatus { - address: string; - artist: string; - currentBpm: number - deck: string; - deviceId: string; - externalMixerVolume: number; - fileLocation: string; - hasTrackData: boolean; - jogColor: string; - layer: string; - masterStatus: boolean; - masterTempo: number; - play: boolean; - player: number; - playState: boolean; - port: number; - songLoaded: boolean; - title: string; - trackNetworkPath: string; +// export interface PlayerStatus { +// address: string; +// artist: string; +// currentBpm: number +// deck: string; +// deviceId: DeviceId; +// externalMixerVolume: number; +// fileLocation: string; +// hasTrackData: boolean; +// jogColor: string; +// layer: string; +// masterStatus: boolean; +// masterTempo: number; +// play: boolean; +// player: number; +// playState: boolean; +// port: number; +// songLoaded: boolean; +// title: string; +// trackNetworkPath: string; - source: string; - dbSourceName: string; - trackPath: string; - trackPathAbsolute: string; -} +// source: string; +// dbSourceName: string; +// trackPath: string; +// trackPathAbsolute: string; +// } -export interface PlayerLayerState { - layer: string; - artist?: string; - currentBpm?: number; - externalMixerVolume?: number; - fileLocation?: string; - hasTrackData?: boolean; - jogColor?: string; - play?: boolean; - player?: string; - playState?: boolean; - songLoaded?: boolean; - title?: string; - trackNetworkPath?: string; -} +// export interface PlayerLayerState { +// layer: string; +// artist?: string; +// currentBpm?: number; +// externalMixerVolume?: number; +// fileLocation?: string; +// hasTrackData?: boolean; +// jogColor?: string; +// play?: boolean; +// player?: string; +// playState?: boolean; +// songLoaded?: boolean; +// title?: string; +// trackNetworkPath?: string; +// deckIsMaster?: boolean; +// } diff --git a/types/tokens.ts b/types/tokens.ts deleted file mode 100644 index 393ece9..0000000 --- a/types/tokens.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { DiscoveryMessageOptions } from '../network'; - -export const Tokens = { - SoundSwitch: new Uint8Array([82, 253, 252, 7, 33, 130, 101, 79, 22, 63, 95, 15, 154, 98, 29, 114]), - Sc6000_1: new Uint8Array([ 130, 139, 235, 2, 218, 31, 78, 104, 166, 175, 176, 177, 103, 234, 240, 162 ]), - Sc6000_2: new Uint8Array([ 38, 210, 56, 103, 28, 214, 78, 63, 128, 161, 17, 130, 106, 196, 17, 32 ]), - Resolume: new Uint8Array([ 136, 250, 32, 153, 172, 122, 79, 63, 188, 22, 169, 149, 219, 218, 42, 66 ]) -} - -export const ActingAsDevice: {[name: string]: DiscoveryMessageOptions} = { - NowPlaying: { - name: 'nowplaying', - version: '2.2.0', - source: 'np2', - token: Tokens.SoundSwitch - }, - - Sc6000_1: { - name: 'sc6000', - version: '2.3.1', - source: 'JP13', - token: Tokens.Sc6000_1 - }, - - Sc6000_2: { - name: 'sc6000', - version: '2.3.1', - source: 'JP13', - token: Tokens.Sc6000_2 - }, - - Resolume: { - name: 'resolume', - version: '10.0.0', - source: 'res', - token: Tokens.Resolume - } - -} diff --git a/utils/ReadContext.ts b/utils/ReadContext.ts index 59d2628..648530d 100644 --- a/utils/ReadContext.ts +++ b/utils/ReadContext.ts @@ -8,6 +8,13 @@ function fromCString(p_buffer: Uint8Array): string { } export class ReadContext extends Context { + + /** + * ReadContext Utility Class + * @internal + * @param p_buffer + * @param p_littleEndian + */ constructor(p_buffer: ArrayBuffer, p_littleEndian = false) { super(p_buffer, p_littleEndian); } @@ -24,6 +31,18 @@ export class ReadContext extends Context { return view; } + peek(p_bytes: number): Buffer { + const bytesToRead = Math.min(this.sizeLeft(), p_bytes); + if (bytesToRead <= 0) { + return null; + } + + const view = new Uint8Array(this.buffer, this.pos, bytesToRead); // Buffer.from(this.buffer.slice(this.pos, this.pos + p_bytes)) + //this.pos += bytesToRead; + assert(view.byteLength === bytesToRead); + return Buffer.from(view) + } + readRemaining(): Uint8Array { return this.read(this.sizeLeft()); } @@ -34,6 +53,18 @@ export class ReadContext extends Context { return Buffer.from(newArrayBuffer); } + readRemainingAsNewArrayBuffer(): ArrayBuffer { + const view = this.readRemaining(); + const newArrayBuffer = view.buffer.slice(view.byteOffset, view.byteOffset + view.length); + return newArrayBuffer; + } + + readRemainingAsNewCtx(): ReadContext { + + const newArrayBuffer = this.buffer.slice(this.pos, this.pos + this.sizeLeft()); + return new ReadContext(newArrayBuffer, false); + } + getString(p_bytes: number): string { const buf = this.read(p_bytes); return fromCString(buf); @@ -52,6 +83,18 @@ export class ReadContext extends Context { return result; } + readFloat64(): number { + const offset = this.pos; + if (offset + 8 <= this.buffer.byteLength) { + const value = new DataView(this.buffer).getFloat64(this.pos, this.littleEndian); + this.pos += 8; + return value; + } + + assert.fail(`Read outside buffer`); + return null; + } + readUInt64(): bigint { const offset = this.pos; if (offset + 8 <= this.buffer.byteLength) { @@ -111,4 +154,40 @@ export class ReadContext extends Context { assert.fail(`Read outside buffer`); return null; } + + /* + fastForward(ctx: ReadContext, targetString: string, msgId: number): ReadContext { + + assert(targetString.length % 2 === 0); + const shiftLeft = (collection:Uint8Array, value:any) => { + for (let i = 0; i < collection.length - 1; i++) { + collection[i] = collection[i + 1]; // Shift left + } + collection[collection.length - 1] = value; // Place new value at tail + return collection; + } + + const ctxSize = ctx.sizeLeft(); + const bufferSize = (targetString.length / 2); + let checkBufferArray = new Uint8Array(bufferSize); + checkBufferArray.fill(0); + let count = 0; + + while (Buffer.from(checkBufferArray).toString('hex') !== targetString) { + shiftLeft(checkBufferArray, ctx.read(1)); + count++ + if (ctx.isEOF()) { + ctx.seek(0-ctxSize) + Logger.debug(`[${msgId}] fastForwarded checked ${count} bytes, returned original`); + return ctx + } + } + ctx.seek(0-bufferSize); + if (count !== bufferSize) { + Logger.debug(`[${msgId}] fastForwarded ${count} bytes`); + } + return ctx + }; + */ } + diff --git a/utils/WriteContext.ts b/utils/WriteContext.ts index 91467ec..30b0358 100644 --- a/utils/WriteContext.ts +++ b/utils/WriteContext.ts @@ -11,6 +11,11 @@ interface WriteContextConstructOptions { export class WriteContext extends Context { autoGrow: boolean; + /** + * WriteContext Utility Class + * @internal + * @param {WriteContextConstructOptions} p_options + */ constructor(p_options?: WriteContextConstructOptions) { const buffer = new ArrayBuffer(p_options && p_options.size > 0 ? p_options.size : 128); super(buffer, !p_options ? false : !!p_options.littleEndian); @@ -89,6 +94,13 @@ export class WriteContext extends Context { return 4; } + writeInt32(p_value: number): number { + this.checkSize(4); + new DataView(this.buffer).setInt32(this.pos, p_value, this.littleEndian); + this.pos += 4; + return 4; + } + writeUInt16(p_value: number): number { this.checkSize(2); new DataView(this.buffer).setUint16(this.pos, p_value, this.littleEndian); diff --git a/utils/getTempFilePath.ts b/utils/getTempFilePath.ts index cbc7d91..542b173 100644 --- a/utils/getTempFilePath.ts +++ b/utils/getTempFilePath.ts @@ -4,11 +4,10 @@ import * as path from 'path'; /** * Recursively create a directory under the OS's temp path. - * - * @param p_path Directory to create including filename - * @returns Absolute path + * @param {string} p_path Directory to create including filename + * @returns {string} Absolute path */ -export function getTempFilePath(p_path: string) { +export function getTempFilePath(p_path: string): string { const tmpPath = `/${os.tmpdir()}/localdb/${p_path}`.replace('net://', ''); let paths = tmpPath.split(/[/\\]/).filter((e) => e.length > 0); const isFolder = p_path.endsWith('/') || p_path.endsWith('\\'); diff --git a/utils/hex.ts b/utils/hex.ts deleted file mode 100644 index c2bce50..0000000 --- a/utils/hex.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Based on https://www.npmjs.com/package/hex -const zero = function (n: number, max: number) { - let str = n.toString(16).toUpperCase(); - while (str.length < max) { - str = '0' + str; - } - return str; -}; - -export function hex(p_buffer: Uint8Array, p_columns: number = 16) { - const rows = Math.ceil(p_buffer.length / p_columns); - const last = p_buffer.length % p_columns || p_columns; - let offsetLength = p_buffer.length.toString(16).length; - if (offsetLength < 6) offsetLength = 6; - - let str = 'Offset'; - while (str.length < offsetLength) { - str += ' '; - } - - str = '\u001b[36m' + str + ' '; - - for (let i = 0; i < p_columns; i++) { - str += ' ' + zero(i, 2); - } - - str += '\u001b[0m'; - if (p_buffer.length) str += '\n'; - - let b = 0; - let lastBytes: number; - let lastSpaces: number; - let v: number; - - for (let i = 0; i < rows; i++) { - str += '\u001b[36m' + zero(b, offsetLength) + '\u001b[0m '; - lastBytes = i === rows - 1 ? last : p_columns; - lastSpaces = p_columns - lastBytes; - - for (let j = 0; j < lastBytes; j++) { - str += ' ' + zero(p_buffer[b], 2); - b++; - } - - for (let j = 0; j < lastSpaces; j++) { - str += ' '; - } - - b -= lastBytes; - str += ' '; - - for (let j = 0; j < lastBytes; j++) { - v = p_buffer[b]; - str += (v > 31 && v < 127) || v > 159 ? String.fromCharCode(v) : '.'; - b++; - } - - str += '\n'; - } - - process.stdout.write(str); -} diff --git a/utils/index.ts b/utils/index.ts index 4395054..53b1559 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -1,7 +1,5 @@ export * from './Context'; export * from './getTempFilePath'; -export * from './hex'; export * from './ReadContext'; -export * from './sleep'; -export * from './tcp'; export * from './WriteContext'; +export * from './sleep'; diff --git a/utils/log.ts b/utils/log.ts deleted file mode 100644 index e69de29..0000000 diff --git a/utils/sleep.ts b/utils/sleep.ts index 541e851..9b8f3f4 100644 --- a/utils/sleep.ts +++ b/utils/sleep.ts @@ -1,3 +1,8 @@ -export function sleep(p_ms: number) { +/** + * Sleep Utility Function + * @param {number} p_ms //time in ms to sleep + * @returns {Promise} + */ +export function sleep(p_ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, p_ms)); } diff --git a/utils/tcp.ts b/utils/tcp.ts deleted file mode 100644 index 635862a..0000000 --- a/utils/tcp.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Socket as TCPSocket } from 'net'; -import { PromiseSocket } from 'promise-socket'; -import { CONNECT_TIMEOUT } from '../types'; -import { Logger } from '../LogEmitter'; - -export type Connection = PromiseSocket; - -export async function connect(p_ip: string, p_port: number): Promise { - const socket = new TCPSocket(); - socket.setTimeout(CONNECT_TIMEOUT); - const promiseSocket = new PromiseSocket(socket); - await promiseSocket.connect(p_port, p_ip).catch((e) => { - throw new Error(`Failed to connect to '${p_ip}:${p_port}': ${e}`); - }); - Logger.debug(`TCP connection to '${p_ip}:${p_port}' local port: ${promiseSocket.socket.localPort}`); - return promiseSocket; -}