diff --git a/.dockerignore b/.dockerignore index 3f978aa..e48d5ca 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,34 @@ -.git -**/.gitignore +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# Deployed apps should consider commenting this line out: +# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git +node_modules + +### + +.git* +.docker* Dockerfile -src/node_modules **/*.log **/*.ini **/*.md diff --git a/src/.gitignore b/.gitignore similarity index 67% rename from src/.gitignore rename to .gitignore index dd55084..ad29cd3 100644 --- a/src/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ # Logs logs *.log -npm-debug.log* # Runtime data pids @@ -17,12 +16,14 @@ coverage # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt -# node-waf configuration -.lock-wscript - # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directory -# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git -node_modules \ No newline at end of file +# Deployed apps should consider commenting this line out: +# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git +node_modules + +# Built files +src.js +dist diff --git a/Dockerfile b/Dockerfile index 0090a81..62df88d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:6.3.1 +FROM node:7.10.0 ARG TS3CLIENT_VERSION=3.0.19.4 diff --git a/src/package.json b/package.json similarity index 53% rename from src/package.json rename to package.json index d1b3295..49a87e4 100644 --- a/src/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "ts3bot", - "version": "0.3.0", + "version": "0.4.0", "description": "Allows running TeamSpeak3 as a bot for all kinds of media (local music/videos/streams/YouTube/...) without the need for a real GUI to exist.", - "main": "app.js", + "main": "dist/node7/index.js", "bin": { - "ts3bot": "app.js" + "ts3bot": "dist/node7/index.js" }, "keywords": [ "teamspeak", @@ -20,15 +20,22 @@ "media", "musicbot" ], - "author": "Carl Kittelberger ", + "scripts": { + "iced2es": "iced3 -I none -b --no-header -o src.js -c src && lebab -t let,multi-var,for-each,arg-rest,arg-spread,obj-method,obj-shorthand,no-strict,exponent,template,default-param,includes,class --replace src.js", + "es2017-node7": "babel src.js --presets es2017-node7 --source-maps --out-dir ./dist/node7", + "build": "npm run iced2es && npm run es2017-node7", + "prepublish": "npm run build", + "start": "node .", + "start-coffee": "node ./src/index.js" + }, + "author": "Carl Kittelberger ", "license": "GPL-3.0+", "repository": { "type": "git", - "url": "https://github.com/icedream/ts3bot-control.git" + "url": "https://github.com/icedream/ts3bot.git" }, "dependencies": { "express": "^4.13.3", - "iced-coffee-script": "^108.0.8", "merge": "^1.2.0", "mkdirp": "^0.5.1", "named-regexp": "^0.1.1", @@ -49,7 +56,17 @@ "webchimera.js": "^0.2.7", "which": "^1.1.2", "winston": "^2.3.1", - "xvfb": "git://github.com/icedream/node-xvfb.git", + "xvfb": "^0.2.3", "youtube-dl": "^1.10.5" + }, + "devDependencies": { + "babel-cli": "^6.24.1", + "babel-preset-es2017-node7": "^0.5.2", + "iced-coffee-script-3": "^111.1.1", + "lebab": "^2.7.2" + }, + "engineStrict": true, + "engines": { + "node": ">= 7.6.0" } } diff --git a/src/app.coffee b/src/app.coffee new file mode 100644 index 0000000..55f4fbc --- /dev/null +++ b/src/app.coffee @@ -0,0 +1,382 @@ +import { track as tempTrack } from 'temp' +import fs from 'fs' +import path from 'path' +import prettyMs from 'pretty-ms' +import qs from 'querystring' +import request from 'request' +import Sync from 'sync' +import validUrl from 'valid-url' +import youtubedl from 'youtube-dl' + +import config from './config' +import getLogger from './logger' +import services from './services' +import parseDuration from './parse_duration.iced' + +isValidUrl = validUrl.isWebUri +track = tempTrack() +log = getLogger "Main" + +# http://stackoverflow.com/a/7117336 +removeBB = (str) -> str.replace /\[(\w+)[^\]]*](.*?)\[\/\1]/g, "$2" + +shutdown = (cb) -> + ts3clientService = services.find("ts3client") + if ts3clientService and ts3clientService.state == "started" + await ts3clientService.stop defer(err) + if err + cb? new Error "Could not stop TeamSpeak3" + return + + log.debug "Shutting down services..." + await services.shutdown defer(err) + if err + cb? new Error "Error while shutting down rest of services." + log.debug "Services shut down." + + cb?() + +module.exports = + shutdown: shutdown + shutdownSync: => Sync @shutdown + +run = -> + # Separate our own PulseAudio from any system one by using our own custom XDG directories. + process.env.XDG_RUNTIME_DIR = temp.mkdirSync "ts3bot-xdg" + + # Xvfb for isolated graphical interfaces! + xvfbService = services.find("xvfb") + await xvfbService.start defer(err, vlc) + if err + if not process.env.DISPLAY? or process.env.DISPLAY.trim() == "" + log.error "Xvfb could not start up and no display is available!", err + await shutdown defer() + process.exit 1 + log.warn "Xvfb could not start up - will use existing display!", err + + # PulseAudio daemon + await services.find("pulseaudio").start defer err + if err + log.warn "PulseAudio could not start up, audio may not act as expected!", err + + # VLC via WebChimera.js + vlcService = services.find("vlc") + await vlcService.start defer(err, vlc) + if err + log.warn "VLC could not start up!", err + await shutdown defer() + process.exit 1 + + # This is where we keep track of the volume + vlcVolume = 50 + + # Cached information for tracks in playlist + vlcMediaInfo = {} + + # TeamSpeak3 + ts3clientService = services.find("ts3client") + + ts3clientService.on "started", (ts3proc) -> + ts3query = ts3clientService.query + + ts3clientService.once "stopped", () -> + ts3query = undefined + + # VLC event handling + vlc.onPlaying = () -> + try + # TODO: Check why info is sometimes null, something must be wrong with the "add"/"play" commands here! + # TODO: Do not format as URL in text message if MRL points to local file + + item = vlc.playlist.items[vlc.playlist.currentItem] + info = vlcMediaInfo[item.mrl] + url = info?.originalUrl or item.mrl + title = info?.title or item.mrl + ts3query?.sendtextmessage 2, 0, "Now playing [URL=#{url}]#{title}[/URL]." + + # Restore audio volume + vlc.audio.volume = vlcVolume + catch e + log.warn "Error in VLC onPlaying handler", e + + vlc.onPaused = () -> ts3query?.sendtextmessage 2, 0, "Paused." + vlc.onForward = () -> ts3query?.sendtextmessage 2, 0, "Fast-forwarding..." + vlc.onBackward = () -> ts3query?.sendtextmessage 2, 0, "Rewinding..." + vlc.onEncounteredError = () -> log.error "VLC has encountered an error! You will need to restart the bot.", arguments + vlc.onStopped = () -> ts3query?.sendtextmessage 2, 0, "Stopped." + + ts3query.currentScHandlerID = 1 + ts3query.mydata = {} + + ts3query.on "open", -> + log.info "TS3 query now ready." + + attempts = 0 + err = null + init = true + while init or err != null + init = false + if err + attempts++ + if attempts == 10 + log.error "Could not register to TeamSpeak3 client events, giving up!" + break + else + log.warn "Could not register to TeamSpeak3 client events!", err + + [ + "notifytalkstatuschange" + "notifyconnectstatuschange" + "notifytextmessage" + "notifyclientupdated" + "notifycliententerview" + "notifyclientleftview" + "notifyclientchatclosed" + "notifyclientchatcomposing" + "notifyclientchannelgroupchanged" + "notifyclientmoved" + ].every(eventName -> + await ts3query.clientnotifyregister ts3query.currentScHandlerID, eventName, defer(err) + if err + return false + return true + ) + + ts3query.on "message.selected", (args) -> + if args["schandlerid"] + ts3query.currentScHandlerID = parseInt args["schandlerid"] + + ts3query.on "message.notifytalkstatuschange", (args) -> + await ts3query.use args.schandlerid, defer(err, data) + + ts3query.on "message.notifyconnectstatuschange", (args) -> + await ts3query.use args.schandlerid, defer(err, data) + + if args.status == "disconnected" and ts3clientService.state != "stopping" + log.warn "Disconnected from TeamSpeak server, reconnecting in a few seconds..." + ts3clientService.stopSync() + setTimeout (() -> ts3clientService.restartSync()), 8000 + + if args.status == "connecting" + log.info "Connecting to TeamSpeak server..." + + if args.status == "connection_established" + log.info "Connected to TeamSpeak server." + + ts3query.on "message.notifyclientupdated", (args) -> + await ts3query.use args.schandlerid, defer(err, data) + await ts3query.whoami defer(err, data) + if not err + ts3query.mydata = data + + ts3query.on "message.notifytextmessage", (args) -> + await ts3query.use args.schandlerid, defer(err, data) + + if not args.msg? + return + + msg = args.msg + invoker = { name: args.invokername, uid: args.invokeruid, id: args.invokerid } + targetmode = args.targetmode # 1 = private, 2 = channel + + log.info "<#{invoker.name}> #{msg}" + + # cheap argument parsing here + firstSpacePos = msg.indexOf " " + if firstSpacePos == 0 + return + if firstSpacePos > 0 + name = msg.substring 0, firstSpacePos + paramline = msg.substring firstSpacePos + 1 + params = paramline.match(/'[^']*'|"[^"]*"|[^ ]+/g) || [] + else + name = msg + paramline = "" + params = [] + + switch name.toLowerCase() + when "current" + item = vlc.playlist.items[vlc.playlist.currentItem] + if not item? + ts3query?.sendtextmessage args.targetmode, invoker.id, "Not playing anything at the moment." + return + + info = vlcMediaInfo[item.mrl] + url = info?.originalUrl or item.mrl + title = info?.title or item.mrl + ts3query?.sendtextmessage args.targetmode, invoker.id, "Currently playing [URL=#{url}]#{title}[/URL]." + + # Restore audio volume + vlc.audio.volume = vlcVolume + when "pause" + # now we can toggle-pause playback this easily! yay! + vlc.togglePause() + return + when "play" + inputBB = paramline.trim() + input = (removeBB paramline).trim() + + # we gonna interpret play without a url as an attempt to unpause the current song + if input.length <= 0 + vlc.play() + return + + # only allow playback from file if it's a preconfigured alias + if isValidUrl input + log.debug "Got input URL:", input + else + input = config.get "aliases:#{input}" + if not(isValidUrl input) and not(fs.existsSync input) + log.debug "Got neither valid URL nor valid alias:", input + ts3query.sendtextmessage args.targetmode, invoker.id, "Sorry, you're not allowed to play #{inputBB} via the bot." + return + + # TODO: permission system to check if uid is allowed to play this url or alias + + vlc.playlist.clear() + + # let's give youtube-dl a shot! + await youtubedl.getInfo input, ["--format=bestaudio"], defer(err, info) + if err or not info? + log.debug "There is no audio-only download for #{inputBB}, downloading full video instead." + await youtubedl.getInfo input, ["--format=best"], defer(err, info) + if err or not info? + info = + url: input + if not info.url? + info.url = input + info.title = input # URL as title + info.originalUrl = input + vlcMediaInfo[info.url] = info + + # play it in VLC + vlc.play info.url + when "time", "seek", "pos", "position" + inputBB = paramline.trim() + input = (removeBB paramline).trim() + + # we gonna interpret no argument as us needing to return the current position + if input.length <= 0 + ts3query.sendtextmessage args.targetmode, invoker.id, "Currently position is #{prettyMs vlc.input.time}." + return + + ts3query.sendtextmessage args.targetmode, invoker.id, "Seeking to #{prettyMs vlc.input.time}." + vlc.input.time = parseDuration input + + return + when "stop-after" + vlc.playlist.mode = vlc.playlist.Single + ts3query.sendtextmessage args.targetmode, invoker.id, "Playback will stop after the current playlist item." + when "loop" + inputBB = paramline + input = null + switch (removeBB paramline).toLowerCase().trim() + when "" + # just show current mode + ts3query.sendtextmessage args.targetmode, invoker.id, "Playlist looping is #{if vlc.playlist.mode == vlc.playlist.Loop then "on" else "off"}." + when "on" + # enable looping + vlc.playlist.mode = vlc.playlist.Loop + ts3query.sendtextmessage args.targetmode, invoker.id, "Playlist looping is now on." + when "off" + # disable looping + vlc.playlist.mode = vlc.playlist.Normal + ts3query.sendtextmessage args.targetmode, invoker.id, "Playlist looping is now off." + else + ts3query.sendtextmessage args.targetmode, invoker.id, "[B]#{name} on|off[/B] - Turns playlist looping on or off" + return + when "next" + if vlc.playlist.items.count == 0 + ts3query.sendtextmessage args.targetmode, invoker.id, "The playlist is empty." + return + if vlc.playlist.mode != vlc.playlist.Loop and vlc.playlist.currentItem == vlc.playlist.items.count - 1 + ts3query.sendtextmessage args.targetmode, invoker.id, "Can't jump to next playlist item, this is the last one!" + return + vlc.playlist.next() + when "prev", "previous" + if vlc.playlist.items.count == 0 + ts3query.sendtextmessage args.targetmode, invoker.id, "The playlist is empty." + return + if vlc.playlist.mode != vlc.playlist.Loop and vlc.playlist.currentItem <= 0 + ts3query.sendtextmessage args.targetmode, invoker.id, "Can't jump to previous playlist item, this is the first one!" + return + vlc.playlist.prev() + when "empty", "clear" + vlc.playlist.clear() + ts3query.sendtextmessage args.targetmode, invoker.id, "Cleared the playlist." + when "enqueue", "add", "append" + inputBB = paramline.trim() + input = (removeBB paramline).trim() + + if inputBB.length <= 0 + ts3query.sendtextmessage args.targetmode, invoker.id, "[B]#{name} [/B] - Adds the specified URL to the current playlist" + return + + # only allow playback from file if it's a preconfigured alias + if isValidUrl input + log.debug "Got input URL:", input + else + input = config.get "aliases:#{input}" + if not(isValidUrl input) and not(fs.existsSync input) + log.debug "Got neither valid URL nor valid alias:", input + ts3query.sendtextmessage args.targetmode, invoker.id, "Sorry, you're not allowed to play #{inputBB} via the bot." + return + + # TODO: permission system to check if uid is allowed to play this url or alias + + # let's give youtube-dl a shot! + await youtubedl.getInfo input, ["--format=bestaudio"], defer(err, info) + if err or not info? + log.debug "There is no audio-only download for #{inputBB}, downloading full video instead." + await youtubedl.getInfo input, ["--format=best"], defer(err, info) + if err or not info? + info = + url: input + if not info.url? + info.url = input + info.title = input # URL as title + info.originalUrl = input + vlcMediaInfo[info.url] = info + + # add it in VLC + vlc.playlist.add info.url + ts3query.sendtextmessage args.targetmode, invoker.id, "Added [URL=#{input}]#{info.title}[/URL] to the playlist." + + # TODO: Do we need to make sure that vlc.playlist.mode is not set to "Single" here or is that handled automatically? + when "stop" + vlc.stop() + when "vol" + inputBB = paramline.trim() + input = (removeBB paramline).trim() + + if inputBB.length <= 0 + ts3query.sendtextmessage args.targetmode, invoker.id, "Volume is currently set to #{vlcVolume}%." + return + + vol = parseInt input + + if paramline.trim().length <= 0 or isNaN(vol) or vol > 200 or vol < 0 + ts3query.sendtextmessage args.targetmode, invoker.id, "[B]vol [/B] - takes a number between 0 (0%) and 200 (200%) to set the volume. 100% is 100. Defaults to 50 (50%) on startup." + return + + vlc.audio.volume = vlcVolume = vol + ts3query.sendtextmessage args.targetmode, invoker.id, "Volume set to #{vol}%." + when "changenick" + nick = paramline + Sync -> + try + ts3query.clientupdate.sync ts3query, { client_nickname: nick } + catch err + log.warn "ChangeNick failed, error information:", err + switch err.id + when 513 then ts3query.sendtextmessage args.targetmode, invoker.id, "That nickname is already in use." + when 1541 then ts3query.sendtextmessage args.targetmode, invoker.id, "That nickname is too short or too long." + else ts3query.sendtextmessage args.targetmode, invoker.id, "That unfortunately didn't work out." + + await ts3clientService.start [ config.get("ts3-server") ], defer(err, ts3proc) + if err + log.error "TeamSpeak3 could not start, shutting down.", err + await shutdown defer() + process.exit 1 + +run() diff --git a/src/app.iced b/src/app.iced deleted file mode 100644 index 4ab6673..0000000 --- a/src/app.iced +++ /dev/null @@ -1,381 +0,0 @@ -Sync = require "sync" - -config = require("./config") -getLogger = require("./logger") -services = require("./services") -sync = require "sync" -request = require "request" -fs = require("fs") -path = require("path") -qs = require "querystring" -temp = require("temp").track() -youtubedl = require "youtube-dl" -isValidUrl = (require "valid-url").isWebUri -parseDuration = require "./parse_duration.iced" -prettyMs = require "pretty-ms" - -log = getLogger "Main" - -# http://stackoverflow.com/a/7117336 -removeBB = (str) -> str.replace /\[(\w+)[^\]]*](.*?)\[\/\1]/g, "$2" - -module.exports = - shutdown: (cb) => - ts3clientService = services.find("ts3client") - if ts3clientService and ts3clientService.state == "started" - await ts3clientService.stop defer(err) - if err - cb? new Error "Could not stop TeamSpeak3" - return - - log.debug "Shutting down services..." - await services.shutdown defer(err) - if err - cb? new Error "Error while shutting down rest of services." - log.debug "Services shut down." - - cb?() - shutdownSync: => Sync @shutdown - -# Separate our own PulseAudio from any system one by using our own custom XDG directories. -process.env.XDG_RUNTIME_DIR = temp.mkdirSync "ts3bot-xdg" - -# Xvfb for isolated graphical interfaces! -xvfbService = services.find("xvfb") -await xvfbService.start defer err, vlc -if err - if not process.env.DISPLAY? or process.env.DISPLAY.trim() == "" - log.error "Xvfb could not start up and no display is available!", err - await module.exports.shutdown defer() - process.exit 1 - log.warn "Xvfb could not start up - will use existing display!", err - -# PulseAudio daemon -await services.find("pulseaudio").start defer err -if err - log.warn "PulseAudio could not start up, audio may not act as expected!", err - -# VLC via WebChimera.js -vlcService = services.find("vlc") -await vlcService.start defer err, vlc -if err - log.warn "VLC could not start up!", err - await module.exports.shutdown defer() - process.exit 1 - -# This is where we keep track of the volume -vlcVolume = 50 - -# Cached information for tracks in playlist -vlcMediaInfo = {} - -# TeamSpeak3 -ts3clientService = services.find("ts3client") - -ts3clientService.on "started", (ts3proc) => - ts3query = ts3clientService.query - - ts3clientService.once "stopped", () => - ts3query = undefined - - # VLC event handling - vlc.onPlaying = () => - try - # TODO: Check why info is sometimes null, something must be wrong with the "add"/"play" commands here! - # TODO: Do not format as URL in text message if MRL points to local file - - item = vlc.playlist.items[vlc.playlist.currentItem] - info = vlcMediaInfo[item.mrl] - url = info?.originalUrl or item.mrl - title = info?.title or item.mrl - ts3query?.sendtextmessage 2, 0, "Now playing [URL=#{url}]#{title}[/URL]." - - # Restore audio volume - vlc.audio.volume = vlcVolume - catch e - log.warn "Error in VLC onPlaying handler", e - - vlc.onPaused = () => ts3query?.sendtextmessage 2, 0, "Paused." - vlc.onForward = () => ts3query?.sendtextmessage 2, 0, "Fast-forwarding..." - vlc.onBackward = () => ts3query?.sendtextmessage 2, 0, "Rewinding..." - vlc.onEncounteredError = () => log.error "VLC has encountered an error! You will need to restart the bot.", arguments - vlc.onStopped = () => ts3query?.sendtextmessage 2, 0, "Stopped." - - ts3query.currentScHandlerID = 1 - ts3query.mydata = {} - - ts3query.on "open", => - log.info "TS3 query now ready." - - attempts = 0 - err = null - init = true - while init or err != null - init = false - if err - attempts++ - if attempts == 10 - log.error "Could not register to TeamSpeak3 client events, giving up!" - break - else - log.warn "Could not register to TeamSpeak3 client events!", err - for eventName in [ - "notifytalkstatuschange" - "notifyconnectstatuschange" - "notifytextmessage" - "notifyclientupdated" - "notifycliententerview" - "notifyclientleftview" - "notifyclientchatclosed" - "notifyclientchatcomposing" - "notifyclientchannelgroupchanged" - "notifyclientmoved" - ] - await ts3query.clientnotifyregister ts3query.currentScHandlerID, eventName, defer(err) - if err - break - - ts3query.on "message.selected", (args) => - if args["schandlerid"] - ts3query.currentScHandlerID = parseInt args["schandlerid"] - - ts3query.on "message.notifytalkstatuschange", (args) => - await ts3query.use args.schandlerid, defer(err, data) - - ts3query.on "message.notifyconnectstatuschange", (args) => - await ts3query.use args.schandlerid, defer(err, data) - - if args.status == "disconnected" and ts3clientService.state != "stopping" - log.warn "Disconnected from TeamSpeak server, reconnecting in a few seconds..." - ts3clientService.stopSync() - setTimeout (() => ts3clientService.restartSync()), 8000 - - if args.status == "connecting" - log.info "Connecting to TeamSpeak server..." - - if args.status == "connection_established" - log.info "Connected to TeamSpeak server." - - ts3query.on "message.notifyclientupdated", (args) => - await ts3query.use args.schandlerid, defer(err, data) - await ts3query.whoami defer(err, data) - if not err - ts3query.mydata = data - - ts3query.on "message.notifytextmessage", (args) => - await ts3query.use args.schandlerid, defer(err, data) - - if not args.msg? - return - - msg = args.msg - invoker = { name: args.invokername, uid: args.invokeruid, id: args.invokerid } - targetmode = args.targetmode # 1 = private, 2 = channel - - log.info "<#{invoker.name}> #{msg}" - - # cheap argument parsing here - firstSpacePos = msg.indexOf " " - if firstSpacePos == 0 - return - if firstSpacePos > 0 - name = msg.substring 0, firstSpacePos - paramline = msg.substring firstSpacePos + 1 - params = paramline.match(/'[^']*'|"[^"]*"|[^ ]+/g) || []; - else - name = msg - paramline = "" - params = [] - - switch name.toLowerCase() - when "current" - item = vlc.playlist.items[vlc.playlist.currentItem] - if not item? - ts3query?.sendtextmessage args.targetmode, invoker.id, "Not playing anything at the moment." - return - - info = vlcMediaInfo[item.mrl] - url = info?.originalUrl or item.mrl - title = info?.title or item.mrl - ts3query?.sendtextmessage args.targetmode, invoker.id, "Currently playing [URL=#{url}]#{title}[/URL]." - - # Restore audio volume - vlc.audio.volume = vlcVolume - when "pause" - # now we can toggle-pause playback this easily! yay! - vlc.togglePause() - return - when "play" - inputBB = paramline.trim() - input = (removeBB paramline).trim() - - # we gonna interpret play without a url as an attempt to unpause the current song - if input.length <= 0 - vlc.play() - return - - # only allow playback from file if it's a preconfigured alias - if isValidUrl input - log.debug "Got input URL:", input - else - input = config.get "aliases:#{input}" - if not(isValidUrl input) and not(fs.existsSync input) - log.debug "Got neither valid URL nor valid alias:", input - ts3query.sendtextmessage args.targetmode, invoker.id, "Sorry, you're not allowed to play #{inputBB} via the bot." - return - - # TODO: permission system to check if uid is allowed to play this url or alias - - vlc.playlist.clear() - - # let's give youtube-dl a shot! - await youtubedl.getInfo input, [ - "--format=bestaudio" - ], defer(err, info) - if err or not info? - log.debug "There is no audio-only download for #{inputBB}, downloading full video instead." - await youtubedl.getInfo input, [ - "--format=best" - ], defer(err, info) - if err or not info? - info = - url: input - if not info.url? - info.url = input - info.title = input # URL as title - info.originalUrl = input - vlcMediaInfo[info.url] = info - - # play it in VLC - vlc.play info.url - when "time", "seek", "pos", "position" - inputBB = paramline.trim() - input = (removeBB paramline).trim() - - # we gonna interpret no argument as us needing to return the current position - if input.length <= 0 - ts3query.sendtextmessage args.targetmode, invoker.id, "Currently position is #{prettyMs vlc.input.time}." - return - - ts3query.sendtextmessage args.targetmode, invoker.id, "Seeking to #{prettyMs vlc.input.time}." - vlc.input.time = parseDuration input - - return - when "stop-after" - vlc.playlist.mode = vlc.playlist.Single - ts3query.sendtextmessage args.targetmode, invoker.id, "Playback will stop after the current playlist item." - when "loop" - inputBB = paramline - input = null - switch (removeBB paramline).toLowerCase().trim() - when "" - # just show current mode - ts3query.sendtextmessage args.targetmode, invoker.id, "Playlist looping is #{if vlc.playlist.mode == vlc.playlist.Loop then "on" else "off"}." - when "on" - # enable looping - vlc.playlist.mode = vlc.playlist.Loop - ts3query.sendtextmessage args.targetmode, invoker.id, "Playlist looping is now on." - when "off" - # disable looping - vlc.playlist.mode = vlc.playlist.Normal - ts3query.sendtextmessage args.targetmode, invoker.id, "Playlist looping is now off." - else - ts3query.sendtextmessage args.targetmode, invoker.id, "[B]#{name} on|off[/B] - Turns playlist looping on or off" - return - when "next" - if vlc.playlist.items.count == 0 - ts3query.sendtextmessage args.targetmode, invoker.id, "The playlist is empty." - return - if vlc.playlist.mode != vlc.playlist.Loop and vlc.playlist.currentItem == vlc.playlist.items.count - 1 - ts3query.sendtextmessage args.targetmode, invoker.id, "Can't jump to next playlist item, this is the last one!" - return - vlc.playlist.next() - when "prev", "previous" - if vlc.playlist.items.count == 0 - ts3query.sendtextmessage args.targetmode, invoker.id, "The playlist is empty." - return - if vlc.playlist.mode != vlc.playlist.Loop and vlc.playlist.currentItem <= 0 - ts3query.sendtextmessage args.targetmode, invoker.id, "Can't jump to previous playlist item, this is the first one!" - return - vlc.playlist.prev() - when "empty", "clear" - vlc.playlist.clear() - ts3query.sendtextmessage args.targetmode, invoker.id, "Cleared the playlist." - when "enqueue", "add", "append" - inputBB = paramline.trim() - input = (removeBB paramline).trim() - - if inputBB.length <= 0 - ts3query.sendtextmessage args.targetmode, invoker.id, "[B]#{name} [/B] - Adds the specified URL to the current playlist" - return - - # only allow playback from file if it's a preconfigured alias - if isValidUrl input - log.debug "Got input URL:", input - else - input = config.get "aliases:#{input}" - if not(isValidUrl input) and not(fs.existsSync input) - log.debug "Got neither valid URL nor valid alias:", input - ts3query.sendtextmessage args.targetmode, invoker.id, "Sorry, you're not allowed to play #{inputBB} via the bot." - return - - # TODO: permission system to check if uid is allowed to play this url or alias - - # let's give youtube-dl a shot! - await youtubedl.getInfo input, [ - "--format=bestaudio" - ], defer(err, info) - if err or not info? - log.debug "There is no audio-only download for #{inputBB}, downloading full video instead." - await youtubedl.getInfo input, [ - "--format=best" - ], defer(err, info) - if err or not info? - info = - url: input - if not info.url? - info.url = input - info.title = input # URL as title - info.originalUrl = input - vlcMediaInfo[info.url] = info - - # add it in VLC - vlc.playlist.add info.url - ts3query.sendtextmessage args.targetmode, invoker.id, "Added [URL=#{input}]#{info.title}[/URL] to the playlist." - - # TODO: Do we need to make sure that vlc.playlist.mode is not set to "Single" here or is that handled automatically? - when "stop" - vlc.stop() - when "vol" - inputBB = paramline.trim() - input = (removeBB paramline).trim() - - if inputBB.length <= 0 - ts3query.sendtextmessage args.targetmode, invoker.id, "Volume is currently set to #{vlcVolume}%." - return - - vol = parseInt input - - if paramline.trim().length <= 0 or isNaN(vol) or vol > 200 or vol < 0 - ts3query.sendtextmessage args.targetmode, invoker.id, "[B]vol [/B] - takes a number between 0 (0%) and 200 (200%) to set the volume. 100% is 100. Defaults to 50 (50%) on startup." - return - - vlc.audio.volume = vlcVolume = vol - ts3query.sendtextmessage args.targetmode, invoker.id, "Volume set to #{vol}%." - when "changenick" - nick = paramline - Sync () => - try - ts3query.clientupdate.sync ts3query, { client_nickname: nick } - catch err - log.warn "ChangeNick failed, error information:", err - switch err.id - when 513 then ts3query.sendtextmessage args.targetmode, invoker.id, "That nickname is already in use." - when 1541 then ts3query.sendtextmessage args.targetmode, invoker.id, "That nickname is too short or too long." - else ts3query.sendtextmessage args.targetmode, invoker.id, "That unfortunately didn't work out." - -await ts3clientService.start [ config.get("ts3-server") ], defer(err, ts3proc) -if err - log.error "TeamSpeak3 could not start, shutting down.", err - await module.exports.shutdown defer() - process.exit 1 diff --git a/src/config.iced b/src/config.coffee similarity index 91% rename from src/config.iced rename to src/config.coffee index 5cddbfd..79aa69d 100644 --- a/src/config.iced +++ b/src/config.coffee @@ -1,7 +1,7 @@ -nconf = require "nconf" -path = require "path" -merge = require "merge" -pwgen = require "password-generator" +import nconf from 'nconf' +import path from 'path' +import merge from 'merge' +import pwgen from 'password-generator' console.log "Loading configuration..." diff --git a/src/index.coffee b/src/index.coffee new file mode 100644 index 0000000..1ae56af --- /dev/null +++ b/src/index.coffee @@ -0,0 +1,73 @@ +import Sync from 'sync' +import readline from 'readline' + +import services from './services' +import getLogger from './logger' +import app from './app.iced' + +log = getLogger('app') + +# compatibility with Windows for interrupt signal +if process.platform == 'win32' + rl = readline.createInterface( + input: process.stdin + output: process.stdout) + rl.on 'SIGINT', -> + process.emit 'SIGINT' + +doShutdownAsync = (cb) -> + log.info 'App shutdown starting...' + app.shutdown -> + log.info 'Services shutdown starting...' + services.shutdown -> + if cb and typeof cb == 'function' + cb() + return + return + return + +process.on 'uncaughtException', (err) -> + log.error 'Shutting down due to an uncaught exception!', err + app.shutdownSync() + process.exit 0xFF + return + +process.on 'exit', (e) -> + log.debug 'Triggered exit', e + app.shutdownSync() + return + +process.on 'SIGTERM', (e) -> + log.debug 'Caught SIGTERM signal' + app.shutdown -> + process.exit 0 + return + return + +process.on 'SIGINT', -> + log.debug 'Caught SIGINT signal' + app.shutdown -> + process.exit 0 + return + return + +process.on 'SIGHUP', -> + log.debug 'Caught SIGHUP signal' + app.shutdown -> + process.exit 0 + return + return + +process.on 'SIGQUIT', -> + log.debug 'Caught SIGQUIT signal' + app.shutdown -> + process.exit 0 + return + return + +process.on 'SIGABRT', -> + log.debug 'Caught SIGABRT signal' + app.shutdown -> + process.exit 0 + return + return diff --git a/src/app.js b/src/index.js similarity index 94% rename from src/app.js rename to src/index.js index 26af737..9f46e85 100644 --- a/src/app.js +++ b/src/index.js @@ -1,6 +1,4 @@ -#!/usr/bin/env node - -require("iced-coffee-script/register"); +require("iced-coffee-script-3/register"); Sync = require("sync"); var services = require("./services"); @@ -19,7 +17,7 @@ if (process.platform === "win32") { }); } -app = require("./app.iced"); +app = require("./app"); doShutdownAsync = function(cb) { log.info("App shutdown starting..."); diff --git a/src/logger.iced b/src/logger.coffee similarity index 83% rename from src/logger.iced rename to src/logger.coffee index 29e72a8..4b65097 100644 --- a/src/logger.iced +++ b/src/logger.coffee @@ -1,8 +1,9 @@ -winston = require "winston" -path = require "path" -config = require "./config" -merge = require "merge" -winstonCommon = require "winston/lib/winston/common" +import winston from 'winston' +import path from 'path' +import merge from 'merge' +import winstonCommon from 'winston/lib/winston/common' + +import config from './config' winston.emitErrs = true @@ -40,10 +41,10 @@ container = new (winston.Container) initialized_loggers = [] -module.exports = (name, options) => +module.exports = (name, options) -> if not(name in initialized_loggers) logger = container.add name - logger.filters.push (level, msg, meta) => "[#{name}] #{msg}" + logger.filters.push (level, msg, meta) -> "[#{name}] #{msg}" initialized_loggers.push name return logger diff --git a/src/parse_duration.iced b/src/parse_duration.coffee similarity index 75% rename from src/parse_duration.iced rename to src/parse_duration.coffee index bf4b563..0938738 100644 --- a/src/parse_duration.iced +++ b/src/parse_duration.coffee @@ -1,5 +1,5 @@ -parseDuration = require "parse-duration" -namedRegex = require("named-regexp").named +import parseDuration from 'parse-duration' +import { named as namedRegex } from 'named-regexp' durationRegex = namedRegex /^(((:[0-9]{0,2}):)?(:[0-9]{0,2}):)?(:[0-9]{0,2})(:\.[0-9]*)?$/ @@ -9,4 +9,4 @@ module.exports = (str) -> m = durationRegex.exec(str).matches return m["ms"] + m["s"]*60 + m["m"]*(60*60) + m["h"]*(60*60*60) - parseDuration str \ No newline at end of file + parseDuration str diff --git a/src/require_bin.iced b/src/require_bin.coffee similarity index 74% rename from src/require_bin.iced rename to src/require_bin.coffee index 1a6a77f..fc75b6f 100644 --- a/src/require_bin.iced +++ b/src/require_bin.coffee @@ -1,8 +1,11 @@ -which = require("which").sync -path = require "path" -log = require("./logger")("RequireBin") +import { sync as which } from 'which' +import path from 'path' -module.exports = (binName, doErrorIfNotFound) => +import getLogger from './logger' + +log = getLogger "RequireBin" + +module.exports = (binName, doErrorIfNotFound) -> doErrorIfNotFound = true unless doErrorIfNotFound? # check if xvfb is findable from here diff --git a/src/service_depcomparer.iced b/src/service_depcomparer.coffee similarity index 84% rename from src/service_depcomparer.iced rename to src/service_depcomparer.coffee index 18621a3..bce3f69 100644 --- a/src/service_depcomparer.iced +++ b/src/service_depcomparer.coffee @@ -3,4 +3,4 @@ module.exports = (a, b) -> return -1; # a before b if b.dependencies.indexOf(a.name) >= 0 return 1; # a after b - return 0; # does not matter \ No newline at end of file + return 0 # does not matter diff --git a/src/service_template.iced b/src/service_template.coffee similarity index 94% rename from src/service_template.iced rename to src/service_template.coffee index 5ad2630..02363dd 100644 --- a/src/service_template.iced +++ b/src/service_template.coffee @@ -1,11 +1,11 @@ -Sync = require "sync" +import Sync from 'sync' +import { EventEmitter } from 'events' +import merge from 'merge' -getLogger = require "./logger" -EventEmitter = require("events").EventEmitter -merge = require "merge" -services = require "./services" +import getLogger from './logger' +import services from './services' -module.exports = class Service extends EventEmitter +class Service extends EventEmitter constructor: (@name, funcs) -> @log = getLogger @name @_funcs = funcs @@ -152,3 +152,5 @@ module.exports = class Service extends EventEmitter cb? err restartSync: () => Sync () => @restart.sync @ + +module.exports = Service diff --git a/src/services.iced b/src/services.coffee similarity index 82% rename from src/services.iced rename to src/services.coffee index f3e8399..309ae3c 100644 --- a/src/services.iced +++ b/src/services.coffee @@ -1,12 +1,16 @@ # At this point I feel like I'm writing my own init system. Phew... -merge = require "merge" -getLogger = require("./logger") -EventEmitter = require("events").EventEmitter -log = getLogger("ServiceMgr") -Sync = require "sync" +import merge from 'merge' +import { EventEmitter } from 'events' +import Sync from 'sync' -getLegacyServiceName = (serviceName) -> serviceName.toLowerCase().replace(/[^A-z0-9]/g, "_") +import getLogger from './logger' +import { Service } from './service_template' + +log = getLogger("ServiceMgr") + +getLegacyServiceName = (serviceName) -> + serviceName.toLowerCase().replace(/[^A-z0-9]/g, "_") module.exports = services: [] @@ -52,7 +56,7 @@ module.exports = shutdownSync: () -> Sync () => @shutdown.sync @ # base class for all services -module.exports.Service = require "./service_template" +module.exports.Service = Service # register services services = [ @@ -66,4 +70,4 @@ services.sort require("./service_depcomparer") # sort services by dependency for service in services module.exports.register service -module.exports.services = services \ No newline at end of file +module.exports.services = services diff --git a/src/services/pulseaudio.iced b/src/services/pulseaudio.coffee similarity index 84% rename from src/services/pulseaudio.iced rename to src/services/pulseaudio.coffee index 29139c2..9d2915c 100644 --- a/src/services/pulseaudio.iced +++ b/src/services/pulseaudio.coffee @@ -1,10 +1,12 @@ -spawn = require("child_process").spawn -log = require("../logger")("PulseAudio") -services = require("../services") -config = require("../config") -StreamSplitter = require("stream-splitter") -require_bin = require("../require_bin") +import { spawn } from 'child_process' +import StreamSplitter from 'stream-splitter' +import getLogger from '../logger' +import services from '../services' +import config from '../config' +import require_bin from '../require_bin' + +log = getLogger "PulseAudio" pulseaudioPath = require_bin config.get("PULSE_BINARY") pacmdPath = require_bin "pacmd" @@ -18,7 +20,7 @@ module.exports = class PulseAudioService extends services.Service return # logging - forwardLog = (token) => + forwardLog = (token) -> token = token.trim() # get rid of \r level = token.substring(0, 1).toUpperCase() msg = token.substring token.indexOf("]") + 2 @@ -41,7 +43,7 @@ module.exports = class PulseAudioService extends services.Service # check if there is already a daemon running proc = spawn pulseaudioPath, [ "--check" ], opts stderrTokenizer = proc.stderr.pipe StreamSplitter "\n" - stderrTokenizer.encoding = "utf8"; + stderrTokenizer.encoding = "utf8" stderrTokenizer.on "token", forwardLog await proc.once "exit", defer(code, signal) @log.silly "PulseAudio daemon check returned that #{if code == 0 then "a daemon is already running" else "no daemon is running"}" @@ -74,7 +76,7 @@ module.exports = class PulseAudioService extends services.Service stderrTokenizer.encoding = "utf8" stderrTokenizer.on "token", tokenHandler - proc.on "exit", () => + proc.on "exit", () -> if not calledCallback calledCallback = true cb? new Error "PulseAudio daemon terminated unexpectedly." @@ -89,11 +91,11 @@ module.exports = class PulseAudioService extends services.Service cb?() - findIndexForProcessId: (pid, cb) => throw new Error "Not implemented yet" + findIndexForProcessId: (pid, cb) -> throw new Error "Not implemented yet" findIndexForProcessIdSync: (pid) => Sync () => @findIndexForProcessId @, pid - setSinkInputMute: (index, value, cb) => throw new Error "Not implemented yet" + setSinkInputMute: (index, value, cb) -> throw new Error "Not implemented yet" setSinkInputMuteSync: (index, value) => Sync () => @setSinkInputMute @, index, value diff --git a/src/services/ts3client.iced b/src/services/ts3client.coffee similarity index 94% rename from src/services/ts3client.iced rename to src/services/ts3client.coffee index d9cfd9f..5cf74c3 100644 --- a/src/services/ts3client.iced +++ b/src/services/ts3client.coffee @@ -1,17 +1,20 @@ -xvfb = require("xvfb") -log = require("../logger")("TS3Client") -config = require("../config") -services = require("../services") -x11tools = require("../x11") -TS3Settings = require("../ts3settings") -TS3ClientQuery = require("../ts3query") -path = require "path" -merge = require "merge" -fs = require "fs" -url = require "url" -spawn = require("child_process").spawn -StreamSplitter = require("stream-splitter") -require_bin = require("../require_bin") +import xvfb from 'xvfb' +import path from 'path' +import merge from 'merge' +import fs from 'fs' +import url from 'url' +import { spawn } from 'child_process' +import StreamSplitter from 'stream-splitter' + +import getLogger from '../logger' +import config from '../config' +import services from '../services' +import x11tools from '../x11' +import TS3Settings from '../ts3settings' +import TS3ClientQuery from '../ts3query' +import require_bin from '../require_bin' + +log = getLogger "TS3Client" ts3client_binpath = require_bin path.join(config.get("ts3-install-path"), "ts3client_linux_" + (if process.arch == "x64" then "amd64" else process.arch)) @@ -57,7 +60,7 @@ module.exports = class TS3ClientService extends services.Service # spawn process proc = null doStart = null - forwardLog = (token) => + forwardLog = (token) -> token = token.trim() # get rid of \r if token.indexOf("|") > 0 token = token.split("|") @@ -92,7 +95,7 @@ module.exports = class TS3ClientService extends services.Service LD_LIBRARY_PATH: config.get("ts3-install-path") if process.env.LD_LIBRARY_PATH env.LD_LIBRARY_PATH += ":#{process.env.LD_LIBRARY_PATH}" - + @log.silly "Environment variables:", env @log.silly "Arguments:", JSON.stringify args @@ -106,11 +109,11 @@ module.exports = class TS3ClientService extends services.Service # logging stdoutTokenizer = proc.stdout.pipe StreamSplitter "\n" - stdoutTokenizer.encoding = "utf8"; + stdoutTokenizer.encoding = "utf8" stdoutTokenizer.on "token", forwardLog stderrTokenizer = proc.stderr.pipe StreamSplitter "\n" - stderrTokenizer.encoding = "utf8"; + stderrTokenizer.encoding = "utf8" stderrTokenizer.on "token", forwardLog # connect to client query plugin when it's loaded diff --git a/src/services/vlc.iced b/src/services/vlc.coffee similarity index 78% rename from src/services/vlc.iced rename to src/services/vlc.coffee index e5e1762..71081ba 100644 --- a/src/services/vlc.iced +++ b/src/services/vlc.coffee @@ -1,8 +1,9 @@ -spawn = require("child_process").spawn -services = require("../services") -config = require("../config") -wc = require("webchimera.js") -StreamSplitter = require("stream-splitter") +import { spawn } from 'child_process' +import wc from 'webchimera.js' +import StreamSplitter from 'stream-splitter' + +import services from '../services' +import config from '../config' module.exports = class VLCService extends services.Service dependencies: [ @@ -42,4 +43,3 @@ module.exports = class VLCService extends services.Service @_instance = null cb?() - diff --git a/src/services/xvfb.iced b/src/services/xvfb.coffee similarity index 79% rename from src/services/xvfb.iced rename to src/services/xvfb.coffee index 4edc696..a35a5b6 100644 --- a/src/services/xvfb.iced +++ b/src/services/xvfb.coffee @@ -1,9 +1,10 @@ -Xvfb = require("xvfb") -log = require("../logger")("Xvfb") -config = require("../config") -services = require("../services") -require_bin = require("../require_bin") +import Xvfb from 'xvfb' +import getLogger from '../logger' +import config from '../config' +import services from '../services' +import require_bin from '../require_bin' +log = getLogger "Xvfb" xvfbPath = require_bin "Xvfb", false module.exports = class XvfbService extends services.Service diff --git a/src/services/xwm.iced b/src/services/xwm.coffee similarity index 86% rename from src/services/xwm.iced rename to src/services/xwm.coffee index 6114e2b..a993d4d 100644 --- a/src/services/xwm.iced +++ b/src/services/xwm.coffee @@ -1,8 +1,11 @@ -spawn = require("child_process").spawn -log = require("../logger")("XWindowManager") -services = require("../services") -StreamSplitter = require("stream-splitter") -require_bin = require("../require_bin") +import { spawn } from 'child_process' +import StreamSplitter from 'stream-splitter' + +import getLogger from '../logger' +import services from '../services' +import require_bin from '../require_bin' + +log = getLogger "XWindowManager" xwmBinPath = require_bin "x-window-manager", false @@ -42,13 +45,13 @@ module.exports = class XWindowManagerService extends services.Service # logging stdoutTokenizer = proc.stdout.pipe StreamSplitter "\n" - stdoutTokenizer.encoding = "utf8"; + stdoutTokenizer.encoding = "utf8" stdoutTokenizer.on "token", (token) => token = token.trim() # get rid of \r @log.debug token stderrTokenizer = proc.stderr.pipe StreamSplitter "\n" - stderrTokenizer.encoding = "utf8"; + stderrTokenizer.encoding = "utf8" stderrTokenizer.on "token", (token) => token = token.trim() # get rid of \r @log.warn token diff --git a/src/sugar_property.iced b/src/sugar_property.coffee similarity index 51% rename from src/sugar_property.iced rename to src/sugar_property.coffee index d4790f3..290c7ab 100644 --- a/src/sugar_property.iced +++ b/src/sugar_property.coffee @@ -1,13 +1,16 @@ # @property "prop", { desc... } -Function::property = (prop, desc) -> Object.defineProperty @prototype, prop, desc +Function::property = (prop, desc) -> + Object.defineProperty @prototype, prop, desc # defineProperty "prop", { desc... } #Object::defineProperty = (prop, desc) -> Object.defineProperty @, prop, desc # propertiesof obj -#global.propertiesof = (obj) -> Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertyNames(obj.constructor.prototype or {})) +#global.propertiesof = (obj) -> +# Object.getOwnPropertyNames(obj).concat( +# Object.getOwnPropertyNames(obj.constructor.prototype or {})) # descriptorof obj, name #global.descriptorof = (obj, name) -> Object.getOwnPropertyDescriptor obj, name -module.exports = exports = {} \ No newline at end of file +module.exports = exports = {} diff --git a/src/ts3query.iced b/src/ts3query.coffee similarity index 79% rename from src/ts3query.iced rename to src/ts3query.coffee index 3f07864..c878337 100644 --- a/src/ts3query.iced +++ b/src/ts3query.coffee @@ -1,16 +1,16 @@ -require "string.prototype.startswith" +import 'string.prototype.startswith' -net = require "net" -getLogger = require "./logger" -StringDecoder = require("string_decoder").StringDecoder -StreamSplitter = require "stream-splitter" -events = require "events" -EventEmitter = events.EventEmitter -merge = require "merge" +import net from 'net' +import { StringDecoder } from 'string_decoder' +import StreamSplitter from 'stream-splitter' +import { EventEmitter } from 'events' +import merge from 'merge' + +import getLogger from './logger' parserLog = getLogger "parser" -escape = (value) => value.toString()\ +escape = (value) -> value.toString()\ .replace(/\\/g, "\\\\")\ .replace(/\//g, "\\/")\ .replace(/\|/g, "\\p")\ @@ -19,7 +19,7 @@ escape = (value) => value.toString()\ .replace(/\t/g, "\\t")\ .replace(/\ /g, "\\s") -unescape = (value) => value.toString()\ +unescape = (value) -> value.toString()\ .replace(/\\s/g, " ")\ .replace(/\\t/g, "\t")\ .replace(/\\r/g, "\r")\ @@ -28,7 +28,7 @@ unescape = (value) => value.toString()\ .replace(/\\\//g, "/")\ .replace(/\\\\/g, "\\") -buildCmd = (name, namedArgs, posArgs) => +buildCmd = (name, namedArgs, posArgs) -> # TODO: Add support for collected arguments (aka lists) if not name throw new Error "Need command name" @@ -52,7 +52,7 @@ buildCmd = (name, namedArgs, posArgs) => param += "#{escape(v)}" param + "\n\r" -parseCmd = (str) => +parseCmd = (str) -> params = str.split " " startIndex = 0 @@ -92,7 +92,7 @@ parseCmd = (str) => args: collectedArgs } -checkError = (err) => +checkError = (err) -> err.id = parseInt err.id if err.id == 0 return null @@ -150,7 +150,7 @@ module.exports = class TS3ClientQuery extends EventEmitter _sendKeepalive: (cb) => @_log.silly "Send: " - @_tcpClient.write "\n\r", "utf8", () => cb?() + @_tcpClient.write "\n\r", "utf8", () -> cb?() _stopKeepalive: () => if @_keepaliveInt? @@ -191,37 +191,37 @@ module.exports = class TS3ClientQuery extends EventEmitter @_log.silly "Send:", text.trim() - @_tcpClient.write text, "utf8", () => cb?() + @_tcpClient.write text, "utf8", () -> cb?() @_resetKeepalive() - banadd: (cb) => + banadd: (cb) -> throw new Error "Not implemented yet" - banclient: (cb) => + banclient: (cb) -> throw new Error "Not implemented yet" - bandel: (cb) => + bandel: (cb) -> throw new Error "Not implemented yet" - bandelall: (cb) => + bandelall: (cb) -> throw new Error "Not implemented yet" - banlist: (cb) => + banlist: (cb) -> throw new Error "Not implemented yet" - channeladdperm: (cb) => + channeladdperm: (cb) -> throw new Error "Not implemented yet" - channelclientaddperm: (cb) => + channelclientaddperm: (cb) -> throw new Error "Not implemented yet" - channelclientdelperm: (cb) => + channelclientdelperm: (cb) -> throw new Error "Not implemented yet" - channelclientlist: (cb) => + channelclientlist: (cb) -> throw new Error "Not implemented yet" - channelclientpermlist: (cb) => + channelclientpermlist: (cb) -> throw new Error "Not implemented yet" ### @@ -234,8 +234,8 @@ module.exports = class TS3ClientQuery extends EventEmitter cb = cid cid = null retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "channelconnectinfo", cid: cid @@ -254,70 +254,70 @@ module.exports = class TS3ClientQuery extends EventEmitter channel_properties = {} channel_properties["channel_name"] = channel_name retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "channelcreate", channel_properties - channeldelete: (cb) => + channeldelete: (cb) -> throw new Error "Not implemented yet" - channeldelperm: (cb) => + channeldelperm: (cb) -> throw new Error "Not implemented yet" ### Changes a channels configuration using given properties. ### channeledit: (cid, channel_properties, cb) => - @once "message.error", (args) => cb? checkError(args) + @once "message.error", (args) -> cb? checkError(args) @send "channeledit", merge true, channel_properties, cid: cid - channelgroupadd: (cb) => + channelgroupadd: (cb) -> throw new Error "Not implemented yet" - channelgroupaddperm: (cb) => + channelgroupaddperm: (cb) -> throw new Error "Not implemented yet" - channelgroupclientlist: (cb) => + channelgroupclientlist: (cb) -> throw new Error "Not implemented yet" - channelgroupdel: (cb) => + channelgroupdel: (cb) -> throw new Error "Not implemented yet" - channelgroupdelperm: (cb) => + channelgroupdelperm: (cb) -> throw new Error "Not implemented yet" - channelgrouplist: (cb) => + channelgrouplist: (cb) -> throw new Error "Not implemented yet" - channelgrouppermlist: (cb) => + channelgrouppermlist: (cb) -> throw new Error "Not implemented yet" - channellist: (cb) => + channellist: (cb) -> throw new Error "Not implemented yet" - channelmove: (cb) => + channelmove: (cb) -> throw new Error "Not implemented yet" - channelpermlist: (cb) => + channelpermlist: (cb) -> throw new Error "Not implemented yet" - channelvariable: (cb) => + channelvariable: (cb) -> throw new Error "Not implemented yet" - clientaddperm: (cb) => + clientaddperm: (cb) -> throw new Error "Not implemented yet" - clientdbdelete: (cb) => + clientdbdelete: (cb) -> throw new Error "Not implemented yet" - clientdbedit: (cb) => + clientdbedit: (cb) -> throw new Error "Not implemented yet" - clientdblist: (cb) => + clientdblist: (cb) -> throw new Error "Not implemented yet" - clientdelperm: (cb) => + clientdelperm: (cb) -> throw new Error "Not implemented yet" ### @@ -325,8 +325,8 @@ module.exports = class TS3ClientQuery extends EventEmitter ### clientgetdbidfromuid: (cluid, cb) => retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "clientgetdbidfromuid", cluid: cluid @@ -335,30 +335,30 @@ module.exports = class TS3ClientQuery extends EventEmitter ### clientgetids: (cb) => retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "clientgetids", cluid: cluid ### - Displays the unique identifier and nickname matching the database ID specified + Displays the unique identifier and nickname matching the database ID specified by cldbid. ### clientgetnamefromdbid: (cldbid, cb) => retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "clientgetnamefromdbid", cldbid: cldbid ### - Displays the database ID and nickname matching the unique identifier specified + Displays the database ID and nickname matching the unique identifier specified by cluid. ### clientgetnamefromuid: (cluid, cb) => retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "clientgetnamefromuid", cluid: cluid @@ -368,15 +368,15 @@ module.exports = class TS3ClientQuery extends EventEmitter ### clientgetuidfromclid: (clid, cb) => retval = { } - @once "notifyclientuidfromclid", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "notifyclientuidfromclid", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "clientgetuidfromclid", clid: clid ### - Kicks one or more clients specified with clid from their currently joined - channel or from the server, depending on reasonid. The reasonmsg parameter - specifies a text message sent to the kicked clients. This parameter is optional + Kicks one or more clients specified with clid from their currently joined + channel or from the server, depending on reasonid. The reasonmsg parameter + specifies a text message sent to the kicked clients. This parameter is optional and may only have a maximum of 40 characters. Available reasonid values are: @@ -391,7 +391,7 @@ module.exports = class TS3ClientQuery extends EventEmitter if typeof clid == "function" cb = clid clid = null - @once "message.error", (args) => cb? checkError(args), retval + @once "message.error", (args) -> cb? checkError(args), retval @send "clientkick", reasonid: reasonid reasonmsg: reasonmsg @@ -449,14 +449,14 @@ module.exports = class TS3ClientQuery extends EventEmitter cleanedModifiers.push v retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "clientlist", cleanedModifiers - clientmove: (cb) => + clientmove: (cb) -> throw new Error "Not implemented yet" - clientmute: (cb) => + clientmute: (cb) -> throw new Error "Not implemented yet" ### @@ -501,7 +501,7 @@ module.exports = class TS3ClientQuery extends EventEmitter notifyconnectstatuschange ### clientnotifyregister: (schandlerid, event, cb) => - @once "message.error", (args) => cb? checkError(args) + @once "message.error", (args) -> cb? checkError(args) @send "clientnotifyregister", schandlerid: schandlerid event: event @@ -510,7 +510,7 @@ module.exports = class TS3ClientQuery extends EventEmitter Unregisters from all previously registered client notifications. ### clientnotifyunregister: (cb) => - @once "message.error", (args) => cb? checkError(args) + @once "message.error", (args) -> cb? checkError(args) @send "clientnotifyunregister" ### @@ -518,8 +518,8 @@ module.exports = class TS3ClientQuery extends EventEmitter ### clientpermlist: (cldbid, cb) => retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "clientpermlist", cldbid: cldbid @@ -530,12 +530,12 @@ module.exports = class TS3ClientQuery extends EventEmitter if typeof msg == "function" cb = msg msg = null - @once "message.error", (args) => cb? checkError(args) + @once "message.error", (args) -> cb? checkError(args) @send "clientpoke", msg: msg clid: clid - clientunmute: (cb) => + clientunmute: (cb) -> throw new Error "Not implemented yet" ### @@ -558,7 +558,7 @@ module.exports = class TS3ClientQuery extends EventEmitter connect ### clientupdate: (idents, cb) => - @once "message.error", (args) => cb? checkError(args) + @once "message.error", (args) -> cb? checkError(args) @send "clientupdate", idents ### @@ -624,20 +624,20 @@ module.exports = class TS3ClientQuery extends EventEmitter if not Array.isArray variables throw new Error "variables needs to be an array of requested client variables." retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "clientvariable", { clid: clid }, variables - complainadd: (cb) => + complainadd: (cb) -> throw new Error "Not implemented yet" - complaindel: (cb) => + complaindel: (cb) -> throw new Error "Not implemented yet" - complaindelall: (cb) => + complaindelall: (cb) -> throw new Error "Not implemented yet" - complainlist: (cb) => + complainlist: (cb) -> throw new Error "Not implemented yet" ### @@ -645,70 +645,70 @@ module.exports = class TS3ClientQuery extends EventEmitter ### currentschandlerid: (cb) => retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "currentschandlerid" - disconnect: (cb) => close(cb) + disconnect: (cb) -> close(cb) - exam: (cb) => + exam: (cb) -> throw new Error "Not implemented yet" - ftcreatedir: (cb) => + ftcreatedir: (cb) -> throw new Error "Not implemented yet" - ftdeletefile: (cb) => + ftdeletefile: (cb) -> throw new Error "Not implemented yet" - ftgetfileinfo: (cb) => + ftgetfileinfo: (cb) -> throw new Error "Not implemented yet" - ftgetfilelist: (cb) => + ftgetfilelist: (cb) -> throw new Error "Not implemented yet" - ftinitdownload: (cb) => + ftinitdownload: (cb) -> throw new Error "Not implemented yet" - ftinitupload: (cb) => + ftinitupload: (cb) -> throw new Error "Not implemented yet" - ftlist: (cb) => + ftlist: (cb) -> throw new Error "Not implemented yet" - ftrenamefile: (cb) => + ftrenamefile: (cb) -> throw new Error "Not implemented yet" - ftstop: (cb) => + ftstop: (cb) -> throw new Error "Not implemented yet" - hashpassword: (cb) => + hashpassword: (cb) -> throw new Error "Not implemented yet" - help: (cb) => + help: (cb) -> throw new Error "Not implemented yet" - messageadd: (cb) => + messageadd: (cb) -> throw new Error "Not implemented yet" - messagedel: (cb) => + messagedel: (cb) -> throw new Error "Not implemented yet" - messageget: (cb) => + messageget: (cb) -> throw new Error "Not implemented yet" - messagelist: (cb) => + messagelist: (cb) -> throw new Error "Not implemented yet" - messageupdateflag: (cb) => + messageupdateflag: (cb) -> throw new Error "Not implemented yet" - permoverview: (cb) => + permoverview: (cb) -> throw new Error "Not implemented yet" - quit: (cb) => close(cb) + quit: (cb) -> close(cb) ### - Sends a text message a specified target. The type of the target is determined + Sends a text message a specified target. The type of the target is determined by targetmode. Available targetmodes are: 1: Send private text message to a client. You must specify the target parameter @@ -720,61 +720,61 @@ module.exports = class TS3ClientQuery extends EventEmitter cb = msg msg = target target = null - @once "message.error", (args) => cb? checkError(args) + @once "message.error", (args) -> cb? checkError(args) @send "sendtextmessage", targetmode: targetmode target: target msg: msg - serverconnectinfo: (cb) => + serverconnectinfo: (cb) -> throw new Error "Not implemented yet" - serverconnectionhandlerlist: (cb) => + serverconnectionhandlerlist: (cb) -> throw new Error "Not implemented yet" - servergroupadd: (cb) => + servergroupadd: (cb) -> throw new Error "Not implemented yet" - servergroupaddclient: (cb) => + servergroupaddclient: (cb) -> throw new Error "Not implemented yet" - servergroupaddperm: (cb) => + servergroupaddperm: (cb) -> throw new Error "Not implemented yet" - servergroupclientlist: (cb) => + servergroupclientlist: (cb) -> throw new Error "Not implemented yet" - servergroupdel: (cb) => + servergroupdel: (cb) -> throw new Error "Not implemented yet" - servergroupdelclient: (cb) => + servergroupdelclient: (cb) -> throw new Error "Not implemented yet" - servergroupdelperm: (cb) => + servergroupdelperm: (cb) -> throw new Error "Not implemented yet" - servergrouplist: (cb) => + servergrouplist: (cb) -> throw new Error "Not implemented yet" - servergrouppermlist: (cb) => + servergrouppermlist: (cb) -> throw new Error "Not implemented yet" - servergroupsbyclientid: (cb) => + servergroupsbyclientid: (cb) -> throw new Error "Not implemented yet" - servervariable: (cb) => + servervariable: (cb) -> throw new Error "Not implemented yet" - setclientchannelgroup: (cb) => + setclientchannelgroup: (cb) -> throw new Error "Not implemented yet" - tokenadd: (cb) => + tokenadd: (cb) -> throw new Error "Not implemented yet" - tokendelete: (cb) => + tokendelete: (cb) -> throw new Error "Not implemented yet" - tokenlist: (cb) => + tokenlist: (cb) -> throw new Error "Not implemented yet" ### @@ -782,7 +782,7 @@ module.exports = class TS3ClientQuery extends EventEmitter server will automatically delete the token after it has been used. ### tokenuse: (token, cb) => - @once "message.error", (args) => cb? checkError(args) + @once "message.error", (args) -> cb? checkError(args) @send "tokenuse", token: token @@ -792,12 +792,12 @@ module.exports = class TS3ClientQuery extends EventEmitter ### use: (schandlerid, cb) => retval = { } - @once "message.selected", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "message.selected", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "use", schandlerid: schandlerid - verifychannelpassword: (cb) => + verifychannelpassword: (cb) -> throw new Error "Not implemented yet" ### @@ -805,7 +805,7 @@ module.exports = class TS3ClientQuery extends EventEmitter incorrect. ### verifyserverpassword: (password, cb) => - @once "message.error", (args) => cb? checkError(args) + @once "message.error", (args) -> cb? checkError(args) @send "verifyserverpassword", password: password @@ -818,6 +818,6 @@ module.exports = class TS3ClientQuery extends EventEmitter ### whoami: (cb) => retval = { } - @once "vars", (args) => merge retval, args - @once "message.error", (args) => cb? checkError(args), retval + @once "vars", (args) -> merge retval, args + @once "message.error", (args) -> cb? checkError(args), retval @send "whoami" diff --git a/src/ts3settings.iced b/src/ts3settings.coffee similarity index 83% rename from src/ts3settings.iced rename to src/ts3settings.coffee index db03705..7cc5c5f 100644 --- a/src/ts3settings.iced +++ b/src/ts3settings.coffee @@ -1,17 +1,17 @@ -sqlite3 = require("sqlite3") #.verbose() -SQLite3Database = sqlite3.Database -path = require "path" -mkdirp = require "mkdirp" -SimpleIni = require "simple-ini" -fs = require "fs" -merge = require "merge" -getLogger = require "./logger" +import sqlite3, { Database as SQLite3Database } from 'sqlite3' +import path from 'path' +import mkdirp from 'mkdirp' +import SimpleIni from 'simple-ini' +import fs from 'fs' +import merge from 'merge' + +import getLogger from './logger' # some properties sugar from http://bl.ocks.org/joyrexus/65cb3780a24ecd50f6df Function::getter = (prop, get) -> - Object.defineProperty @prototype, prop, {get, configurable: yes} + Object.defineProperty @prototype, prop, {get, configurable: yes} Function::setter = (prop, set) -> - Object.defineProperty @prototype, prop, {set, configurable: yes} + Object.defineProperty @prototype, prop, {set, configurable: yes} module.exports = class SettingsFile db: null @@ -26,21 +26,28 @@ module.exports = class SettingsFile catch err throw new Error "Could not create TS3 config directory." - @getter "isInitialized", -> () => fs.existsSync(path.join(@configPath, "settings.db")) and fs.existsSync(path.join(@configPath, "ts3clientui_qt.secrets.conf")) - @getter "isReady", -> () => @db != null + @getter "isInitialized", -> + () => + fs.existsSync(path.join(@configPath, "settings.db")) and + fs.existsSync(path.join(@configPath, "ts3clientui_qt.secrets.conf")) + @getter "isReady", -> + () => + @db != null open: (cb) => # settings database @db = new SQLite3Database path.join(@configPath, "settings.db") await @db.serialize defer() - await @query "CREATE TABLE IF NOT EXISTS TS3Tables (key varchar NOT NULL UNIQUE,timestamp integer unsigned NOT NULL)", defer() + await @query "CREATE TABLE IF NOT EXISTS TS3Tables "+ + "(key varchar NOT NULL UNIQUE,timestamp integer unsigned NOT NULL)", + defer() # secrets file @identities = [] @defaultIdentity = null secretsPath = path.join(@configPath, "ts3clientui_qt.secrets.conf") if fs.existsSync(secretsPath) - secrets = new SimpleIni (() => fs.readFileSync(secretsPath, "utf-8")), + secrets = new SimpleIni (-> fs.readFileSync(secretsPath, "utf-8")), quotedValues: false for i in [1 .. secrets.Identities.size] @identities.push @@ -75,7 +82,8 @@ module.exports = class SettingsFile # Generate INI content await secrets.save defer(iniText) - fs.writeFileSync path.join(@configPath, "ts3clientui_qt.secrets.conf"), iniText + fs.writeFileSync path.join(@configPath, "ts3clientui_qt.secrets.conf"), + iniText @identities = null @defaultIdentity = null @@ -98,7 +106,9 @@ module.exports = class SettingsFile if not table throw new Error "Need table" - await @query "create table if not exists #{table} (timestamp integer unsigned NOT NULL, key varchar NOT NULL UNIQUE, value varchar)", defer() + await @query "create table if not exists #{table} "+ + "(timestamp integer unsigned NOT NULL, key varchar NOT NULL UNIQUE, "+ + "value varchar)", defer() if not key return @@ -112,11 +122,13 @@ module.exports = class SettingsFile timestamp = Math.round (new Date).getTime() / 1000 - stmt = @db.prepare "insert or replace into TS3Tables (key, timestamp) values (?, ?)" + stmt = @db.prepare "insert or replace into TS3Tables (key, timestamp) "+ + "values (?, ?)" stmt.run table, timestamp await stmt.finalize defer() - stmt = @db.prepare "insert or replace into #{table} (timestamp, key, value) values (?, ?, ?)" + stmt = @db.prepare "insert or replace into #{table} (timestamp, key, value) "+ + "values (?, ?, ?)" stmt.run timestamp, key, value await stmt.finalize defer() @@ -141,7 +153,7 @@ module.exports = class SettingsFile @log.info "Importing identity from #{identityFilePath}..." # open identity file - idFile = new SimpleIni (() => fs.readFileSync(identityFilePath, "utf-8")), + idFile = new SimpleIni (-> fs.readFileSync(identityFilePath, "utf-8")), quotedValues: true importedIdentity = {} for own k, v of idFile.Identity diff --git a/src/x11.iced b/src/x11.coffee similarity index 63% rename from src/x11.iced rename to src/x11.coffee index 948916f..6e8a91c 100644 --- a/src/x11.iced +++ b/src/x11.coffee @@ -1,16 +1,17 @@ -Sync = require "sync" +import Sync from 'sync' +import { spawn } from 'child_process' +import StreamSplitter from 'stream-splitter' -log = require("./logger")("X11tools") -spawn = require("child_process").spawn -services = require("./services") -StreamSplitter = require("stream-splitter") -require_bin = require("./require_bin") +import getLogger from './logger' +import services from './services' +import require_bin from './require_bin' +log = getLogger "X11tools" xdotoolBinPath = require_bin "xdotool", false # Just some tools to work with the X11 windows module.exports = - getWindowIdByProcessId: (pid, cb) => + getWindowIdByProcessId: (pid, cb) -> wid = null # Return null instantly if xdotool is not available @@ -18,21 +19,23 @@ module.exports = cb? new Error "xdotool is not available" return - # We provide --name due to the bug mentioned at https://github.com/jordansissel/xdotool/issues/14 - xdoproc = spawn xdotoolBinPath, [ "search", "--any", "--pid", pid, "--name", "xdosearch" ], + # We provide --name due to the bug mentioned at + # https://github.com/jordansissel/xdotool/issues/14 + xdoproc = spawn xdotoolBinPath, [ + "search", "--any", "--pid", pid, "--name", "xdosearch" ], env: DISPLAY: process.env.DISPLAY XDG_RUNTIME_DIR: process.env.XDG_RUNTIME_DIR stdoutTokenizer = xdoproc.stdout.pipe StreamSplitter "\n" - stdoutTokenizer.encoding = "utf8"; - stdoutTokenizer.on "token", (token) => + stdoutTokenizer.encoding = "utf8" + stdoutTokenizer.on "token", (token) -> token = token.trim() # get rid of \r newWid = parseInt(token) if newWid != 0 and wid == null wid = newWid stderrTokenizer = xdoproc.stderr.pipe StreamSplitter "\n" - stderrTokenizer.encoding = "utf8"; - stderrTokenizer.on "token", (token) => + stderrTokenizer.encoding = "utf8" + stderrTokenizer.on "token", (token) -> token = token.trim() # get rid of \r log.warn token await xdoproc.on "exit", defer(e) @@ -45,9 +48,10 @@ module.exports = cb? null, parseInt(wid) - getWindowIdByProcessIdSync: (pid) => Sync() => @getWindowIdByProcessId.sync @, pid + getWindowIdByProcessIdSync: (pid) -> + Sync() -> @getWindowIdByProcessId.sync @, pid - sendKeys: (wid, keys, cb) => + sendKeys: (wid, keys, cb) -> # Do not bother trying if xdotool is not available if not xdotoolBinPath? cb? new Error "xdotool not available." @@ -61,18 +65,24 @@ module.exports = cb? new Error "Could not start a window manager." return - xdoproc = spawn xdotoolBinPath, [ "windowactivate", "--sync", wid, "key", "--clearmodifiers", "--delay", "100" ].concat(keys), + xdoproc = spawn xdotoolBinPath, [ + "windowactivate", + "--sync", + wid, + "key", + "--clearmodifiers", + "--delay", "100" ].concat(keys), env: DISPLAY: process.env.DISPLAY XDG_RUNTIME_DIR: process.env.XDG_RUNTIME_DIR stdoutTokenizer = xdoproc.stdout.pipe StreamSplitter "\n" - stdoutTokenizer.encoding = "utf8"; - stdoutTokenizer.on "token", (token) => + stdoutTokenizer.encoding = "utf8" + stdoutTokenizer.on "token", (token) -> token = token.trim() # get rid of \r log.debug token stderrTokenizer = xdoproc.stderr.pipe StreamSplitter "\n" - stderrTokenizer.encoding = "utf8"; - stderrTokenizer.on "token", (token) => + stderrTokenizer.encoding = "utf8" + stderrTokenizer.on "token", (token) -> token = token.trim() # get rid of \r log.warn token await xdoproc.on "exit", defer(e) diff --git a/src/yarn.lock b/src/yarn.lock deleted file mode 100644 index 4e3074b..0000000 --- a/src/yarn.lock +++ /dev/null @@ -1,1457 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -abbrev@1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" - -accepts@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" - dependencies: - mime-types "~2.1.11" - negotiator "0.6.1" - -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi@^0.3.0, ansi@~0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" - -aproba@^1.0.3: - version "1.1.1" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" - -are-we-there-yet@~1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.0.6.tgz#a2d28c93102aa6cc96245a26cb954de06ec53f0c" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.0 || ^1.1.13" - -are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -async@^1.4.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - -async@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - -"binary@>= 0.3.0 < 1": - version "0.3.0" - resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" - dependencies: - buffers "~0.1.1" - chainsaw "~0.1.0" - -bindings@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - -bluebird@^2.9.15: - version "2.11.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - -brace-expansion@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" - dependencies: - balanced-match "^0.4.1" - concat-map "0.0.1" - -buffer-shims@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" - -buffers@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" - -camelcase@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -chainsaw@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" - dependencies: - traverse ">=0.3.0 <0.4" - -cliui@^3.0.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - -cmake-js@*: - version "3.4.1" - resolved "https://registry.yarnpkg.com/cmake-js/-/cmake-js-3.4.1.tgz#29b57d6e5417b3a395e549b86cb9dc1f3cd97f90" - dependencies: - bluebird "^2.9.15" - debug "^2.1.3" - fs-extra "1" - is-iojs "^1.0.1" - lodash "^3.6.0" - memory-stream "0" - npmconf "^2.1.2" - npmlog "^1.2.0" - request "^2.54.0" - semver "^5.0.3" - splitargs "0" - tar "^1.0.3" - traceur "0.0.x" - unzip "^0.1.11" - url-join "0" - which "^1.0.9" - yargs "^3.6.0" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -colors@1.0.x: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - dependencies: - delayed-stream "~1.0.0" - -commander@2.9.x, commander@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -config-chain@~1.1.8: - version "1.1.11" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - -content-type@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - -cookie@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - -cycle@1.0.x: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -debug@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" - dependencies: - ms "0.7.2" - -debug@2.6.4, debug@^2.1.3, debug@^2.2.0: - version "2.6.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" - dependencies: - ms "0.7.3" - -decamelize@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -deep-extend@~0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - -depd@1.1.0, depd@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - -encodeurl@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - -etag@~1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" - -express@^4.13.3: - version "4.15.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" - dependencies: - accepts "~1.3.3" - array-flatten "1.1.1" - content-disposition "0.5.2" - content-type "~1.0.2" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "2.6.1" - depd "~1.1.0" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.8.0" - finalhandler "~1.0.0" - fresh "0.5.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.1" - path-to-regexp "0.1.7" - proxy-addr "~1.1.3" - qs "6.4.0" - range-parser "~1.2.0" - send "0.15.1" - serve-static "1.12.1" - setprototypeof "1.0.3" - statuses "~1.3.1" - type-is "~1.6.14" - utils-merge "1.0.0" - vary "~1.1.0" - -extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -extsprintf@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" - -eyes@0.1.x: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - -fibers@>=0.6: - version "1.0.15" - resolved "https://registry.yarnpkg.com/fibers/-/fibers-1.0.15.tgz#22f039c8f18b856190fbbe4decf056154c1eae9c" - -finalhandler@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a" - dependencies: - debug "2.6.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.1" - statuses "~1.3.1" - unpipe "~1.0.0" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -forwarded@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" - -fresh@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" - -fs-extra@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -"fstream@>= 0.1.30 < 1": - version "0.1.31" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-0.1.31.tgz#7337f058fbbbbefa8c9f561a28cab0849202c988" - dependencies: - graceful-fs "~3.0.2" - inherits "~2.0.0" - mkdirp "0.5" - rimraf "2" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -gauge@~1.2.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-1.2.7.tgz#e9cec5483d3d4ee0ef44b60a7d99e4935e136d93" - dependencies: - ansi "^0.3.0" - has-unicode "^2.0.0" - lodash.pad "^4.1.0" - lodash.padend "^4.1.0" - lodash.padstart "^4.1.0" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - 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" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -glob@5.0.x: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.5: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -graceful-fs@~3.0.2: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - dependencies: - natives "^1.1.0" - -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - -hashish@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/hashish/-/hashish-0.0.4.tgz#6d60bc6ffaf711b6afd60e426d077988014e6554" - dependencies: - traverse ">=0.2.4" - -hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -http-errors@~1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" - dependencies: - depd "1.1.0" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" - -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -iced-coffee-script@^108.0.8: - version "108.0.11" - resolved "https://registry.yarnpkg.com/iced-coffee-script/-/iced-coffee-script-108.0.11.tgz#1d71ff93c9049728a6468385aa9bc891fd74c58f" - dependencies: - iced-runtime ">=0.0.1" - -iced-runtime@>=0.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/iced-runtime/-/iced-runtime-1.0.3.tgz#2d4f4fb999ab7aa5430b193c77a7fce4118319ce" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.3, inherits@~2.0.0, inherits@~2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -ini@^1.2.0, ini@^1.3.0, ini@^1.3.4, ini@~1.3.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - -ipaddr.js@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" - -is-finite@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-iojs@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-iojs/-/is-iojs-1.1.0.tgz#4c11033b5d5d94d6eab3775dedc9be7d008325f1" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - -isstream@0.1.x, isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -jodid25519@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" - dependencies: - jsbn "~0.1.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsprim@^1.2.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" - dependencies: - assert-plus "1.0.0" - extsprintf "1.0.2" - json-schema "0.2.3" - verror "1.3.6" - -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - optionalDependencies: - graceful-fs "^4.1.9" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - dependencies: - invert-kv "^1.0.0" - -lodash.pad@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" - -lodash.padend@^4.1.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" - -lodash.padstart@^4.1.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" - -lodash@^3.6.0: - version "3.10.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" - -"match-stream@>= 0.0.2 < 1": - version "0.0.2" - resolved "https://registry.yarnpkg.com/match-stream/-/match-stream-0.0.2.tgz#99eb050093b34dffade421b9ac0b410a9cfa17cf" - dependencies: - buffers "~0.1.1" - readable-stream "~1.0.0" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - -memory-stream@0: - version "0.0.3" - resolved "https://registry.yarnpkg.com/memory-stream/-/memory-stream-0.0.3.tgz#ebe8dd1c3b8bc38c0e7941e9ddd5aebe6b4de83f" - dependencies: - readable-stream "~1.0.26-2" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - -merge@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - -mime-db@~1.27.0: - version "1.27.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" - -mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: - version "2.1.15" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" - dependencies: - mime-db "~1.27.0" - -mime@1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" - -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8, minimist@~0.0.1: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -mkdirp@0.5, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -ms@0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" - -ms@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" - -named-regexp@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/named-regexp/-/named-regexp-0.1.1.tgz#cd9c5383245fa5cbc712a73d669b1e4e2aef590d" - -nan@~2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" - -natives@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" - -nconf@^0.8.4: - version "0.8.4" - resolved "https://registry.yarnpkg.com/nconf/-/nconf-0.8.4.tgz#9502234f7ad6238cab7f92d7c068c20434d3ff93" - dependencies: - async "^1.4.0" - ini "^1.3.0" - secure-keys "^1.0.0" - yargs "^3.19.0" - -negotiator@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - -node-pre-gyp@~0.6.31: - version "0.6.34" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz#94ad1c798a11d7fc67381b50d47f8cc18d9799f7" - dependencies: - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.0.2" - rc "^1.1.7" - request "^2.81.0" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" - -nopt@~3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - dependencies: - abbrev "1" - -npm-path@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.3.tgz#15cff4e1c89a38da77f56f6055b24f975dfb2bbe" - dependencies: - which "^1.2.10" - -npm-which@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" - dependencies: - commander "^2.9.0" - npm-path "^2.0.2" - which "^1.2.10" - -npmconf@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/npmconf/-/npmconf-2.1.2.tgz#66606a4a736f1e77a059aa071a79c94ab781853a" - dependencies: - config-chain "~1.1.8" - inherits "~2.0.0" - ini "^1.2.0" - mkdirp "^0.5.0" - nopt "~3.0.1" - once "~1.3.0" - osenv "^0.1.0" - semver "2 || 3 || 4" - uid-number "0.0.5" - -npmlog@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-1.2.1.tgz#28e7be619609b53f7ad1dd300a10d64d716268b6" - dependencies: - ansi "~0.3.0" - are-we-there-yet "~1.0.0" - gauge "~1.2.0" - -npmlog@^4.0.2: - version "4.1.0" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5" - dependencies: - 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@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - -object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - dependencies: - ee-first "1.1.1" - -once@^1.3.0, once@^1.3.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -once@~1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - dependencies: - wrappy "1" - -optimist@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - dependencies: - lcid "^1.0.0" - -os-tmpdir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -osenv@^0.1.0, osenv@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -"over@>= 0.0.5 < 1": - version "0.0.5" - resolved "https://registry.yarnpkg.com/over/-/over-0.0.5.tgz#f29852e70fd7e25f360e013a8ec44c82aedb5708" - -parse-duration@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/parse-duration/-/parse-duration-0.1.1.tgz#13114ddc9891c1ecd280036244554de43647a226" - -parse-ms@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" - -parseurl@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" - -password-generator@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/password-generator/-/password-generator-2.1.0.tgz#d7580432951b69851e3d8d0a98fb1dc60b5c56da" - dependencies: - optimist "0.6.1" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - -plur@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156" - -pretty-ms@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-2.1.0.tgz#4257c256df3fb0b451d6affaab021884126981dc" - dependencies: - is-finite "^1.0.1" - parse-ms "^1.0.0" - plur "^1.0.0" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - -proxy-addr@~1.1.3: - version "1.1.4" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" - dependencies: - forwarded "~0.1.0" - ipaddr.js "1.3.0" - -"pullstream@>= 0.4.1 < 1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/pullstream/-/pullstream-0.4.1.tgz#d6fb3bf5aed697e831150eb1002c25a3f8ae1314" - dependencies: - over ">= 0.0.5 < 1" - readable-stream "~1.0.31" - setimmediate ">= 1.0.2 < 2" - slice-stream ">= 1.0.0 < 2" - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - -qs@6.4.0, qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - -querystring@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - -range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - -rc@^1.1.7: - version "1.2.1" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.6, readable-stream@^2.1.4: - version "2.2.9" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" - dependencies: - buffer-shims "~1.0.0" - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~1.0.0" - util-deprecate "~1.0.1" - -readable-stream@~1.0.0, readable-stream@~1.0.26-2, readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -request@^2.54.0, request@^2.61.0, request@^2.69.0, request@^2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - -rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" - dependencies: - glob "^7.0.5" - -rimraf@~2.2.6: - version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - -rsvp@^3.0.13: - version "3.5.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" - -safe-buffer@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" - -secure-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/secure-keys/-/secure-keys-1.0.0.tgz#f0c82d98a3b139a8776a8808050b824431087fca" - -"semver@2 || 3 || 4", semver@^4.3.3: - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - -semver@^5.0.3, semver@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - -send@0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" - dependencies: - debug "2.6.1" - depd "~1.1.0" - destroy "~1.0.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.8.0" - fresh "0.5.0" - http-errors "~1.6.1" - mime "1.3.4" - ms "0.7.2" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.3.1" - -serve-static@1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" - dependencies: - encodeurl "~1.0.1" - escape-html "~1.0.3" - parseurl "~1.3.1" - send "0.15.1" - -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -"setimmediate@>= 1.0.1 < 2", "setimmediate@>= 1.0.2 < 2": - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -simple-ini@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/simple-ini/-/simple-ini-1.0.4.tgz#a5b426643f52035d6c8b594959afbd4c6fcdb0f1" - -"slice-stream@>= 1.0.0 < 2": - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-stream/-/slice-stream-1.0.0.tgz#5b33bd66f013b1a7f86460b03d463dec39ad3ea0" - dependencies: - readable-stream "~1.0.31" - -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - -source-map-support@~0.2.8: - version "0.2.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" - dependencies: - source-map "0.1.32" - -source-map@0.1.32: - version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - dependencies: - amdefine ">=0.0.4" - -splitargs@0: - version "0.0.7" - resolved "https://registry.yarnpkg.com/splitargs/-/splitargs-0.0.7.tgz#fe9f7ae657371b33b10cb80da143cf8249cf6b3b" - -sqlite3@^3.1.0: - version "3.1.8" - resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-3.1.8.tgz#4cbcf965d8b901d1b1015cbc7fc415aae157dfaa" - dependencies: - nan "~2.4.0" - node-pre-gyp "~0.6.31" - -sshpk@^1.7.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jodid25519 "^1.0.0" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - -stack-trace@0.0.x: - version "0.0.9" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" - -"statuses@>= 1.3.1 < 2", statuses@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" - -stream-splitter@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/stream-splitter/-/stream-splitter-0.3.2.tgz#e2f28262e53c2d8bbc492e72f2960fc19857984d" - dependencies: - buffers "~0.1.1" - -streamify@~0.2.3: - version "0.2.8" - resolved "https://registry.yarnpkg.com/streamify/-/streamify-0.2.8.tgz#aa8133ecf41f72073dc956111ef23bae1cd0fbad" - dependencies: - hashish "~0.0.4" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string.prototype.startswith@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/string.prototype.startswith/-/string.prototype.startswith-0.2.0.tgz#da68982e353a4e9ac4a43b450a2045d1c445ae7b" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -string_decoder@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667" - dependencies: - buffer-shims "~1.0.0" - -stringstream@~0.0.4: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -sync@0.2.x, sync@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/sync/-/sync-0.2.5.tgz#3910bb9b66abee56542e2e70f0ce549031252df6" - dependencies: - fibers ">=0.6" - -tar-pack@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tar/-/tar-1.0.3.tgz#15bcdab244fa4add44e4244a0176edb8aa9a2b44" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -temp@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" - dependencies: - os-tmpdir "^1.0.0" - rimraf "~2.2.6" - -tough-cookie@~2.3.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" - dependencies: - punycode "^1.4.1" - -traceur@0.0.x: - version "0.0.111" - resolved "https://registry.yarnpkg.com/traceur/-/traceur-0.0.111.tgz#c04de74d14696c3373427de4fc08ecaf913fc3a1" - dependencies: - commander "2.9.x" - glob "5.0.x" - rsvp "^3.0.13" - semver "^4.3.3" - source-map-support "~0.2.8" - -traverse@>=0.2.4: - version "0.6.6" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" - -"traverse@>=0.3.0 <0.4": - version "0.3.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -type-is@~1.6.14: - version "1.6.15" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" - dependencies: - media-typer "0.3.0" - mime-types "~2.1.15" - -uid-number@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.5.tgz#5a3db23ef5dbd55b81fce0ec9a2ac6fccdebb81e" - -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - -unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - -unzip@^0.1.11: - version "0.1.11" - resolved "https://registry.yarnpkg.com/unzip/-/unzip-0.1.11.tgz#89749c63b058d7d90d619f86b98aa1535d3b97f0" - dependencies: - binary ">= 0.3.0 < 1" - fstream ">= 0.1.30 < 1" - match-stream ">= 0.0.2 < 1" - pullstream ">= 0.4.1 < 1" - readable-stream "~1.0.31" - setimmediate ">= 1.0.1 < 2" - -url-join@0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-0.0.1.tgz#1db48ad422d3402469a87f7d97bdebfe4fb1e3c8" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -utils-merge@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" - -uuid@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" - -valid-url@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" - -vary@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" - -verror@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" - dependencies: - extsprintf "1.0.2" - -webchimera.js@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/webchimera.js/-/webchimera.js-0.2.7.tgz#b254e861723dc0c072308990c48577616cc1ac54" - dependencies: - bindings "~1.2.1" - cmake-js "*" - -which@^1.0.9, which@^1.1.2, which@^1.2.10: - version "1.2.14" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" - dependencies: - string-width "^1.0.1" - -window-size@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" - -winston@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/winston/-/winston-2.3.1.tgz#0b48420d978c01804cf0230b648861598225a119" - dependencies: - async "~1.0.0" - colors "1.0.x" - cycle "1.0.x" - eyes "0.1.x" - isstream "0.1.x" - stack-trace "0.0.x" - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -"xvfb@git://github.com/icedream/node-xvfb.git": - version "0.2.3" - resolved "git://github.com/icedream/node-xvfb.git#76a183c3027542fbe36e11727a5f0a42bfde09df" - dependencies: - sync "0.2.x" - -y18n@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - -yargs@^3.19.0, yargs@^3.6.0: - version "3.32.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" - dependencies: - camelcase "^2.0.1" - cliui "^3.0.3" - decamelize "^1.1.1" - os-locale "^1.4.0" - string-width "^1.0.1" - window-size "^0.1.4" - y18n "^3.2.0" - -youtube-dl@^1.10.5: - version "1.11.1" - resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-1.11.1.tgz#c8e3b74951182dc5c58a0d1cd5be54b356271bd2" - dependencies: - mkdirp "^0.5.1" - request "^2.69.0" - streamify "~0.2.3"