diff --git a/.gitignore b/.gitignore index e0d3627..604c2d8 100644 --- a/.gitignore +++ b/.gitignore @@ -70,4 +70,7 @@ typings/ .vuepress/dist # Serverless directories -.serverless \ No newline at end of file +.serverless + +#Custom +credentials.json \ No newline at end of file diff --git a/README.md b/README.md index b4f0c89..749e2b1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # node-polyglot -Rails server to run alongside https://github.com/beatriceo/polyglot +Node server to run alongside https://github.com/beatriceo/polyglot diff --git a/app.js b/app.js index b0d5dce..2d01d30 100644 --- a/app.js +++ b/app.js @@ -1,148 +1,67 @@ -"use strict"; - require("dotenv").config(); -const WebSocket = require("ws"); +const http = require('http'); +const Speech = require('./google-cloud/Speech'); +const Translate = require('./google-cloud/Translate'); /** - * Client responsible for communicating with ActionCable Websocket. - * @param {string} url - URL of Websocket (starts with ws:// or wss://) - * @param {string} channel - Name of ActionCable Channel. + * HTTP Server with Websocket which is responsible for: + * - Recieving User Audio Media + * - Recieving Data relating to which users are in what channel */ -class ActionCable { - constructor(url, channel) { - /** @type {string} */ - this.url = url; - /** @type {string} */ - this.channel = channel; - /** @type {boolean} */ - this.connected = false; +class WebSocketServer { + constructor() { + const server = http.createServer(); - /** @type {WebSocket} */ - this.io = new WebSocket(url, [ - "actioncable-v1-json", - "actioncable-unsupported" - ]); + /** @type {Server} */ + this.io = require('socket.io')(server); - /** @type {WebRTC} */ - this.rtc = new WebRTC("NodeServer"); + this.google = { + /** @type {Speech} */ + speech: null, + /** @type {Translate} */ + translate: null + } - this.setUpEventListeners(); + server.listen(process.env.PORT || 1337); + + this.listen(); } - /** - * Sets up the Websocket event listeners. - */ - setUpEventListeners() { - this.io.on("open", data => { - console.log("Connected to " + this.url); - this.connected = true; - this.subscribe(); - }); + listen() { + this.io.on('connection', (client) => { + console.log("User Connected to Server."); - this.io.on("close", data => { - console.log("Disconnected from ActionCable Server"); - this.connected = false; - }); + client.on('disconnect', () => { + console.log("Client Disconnected."); + }); - this.io.on("message", data => { - data = JSON.parse(data); - console.log(data); + client.on('join', () => { + client.emit("welcome", "Welcome to The Polyglot NodeJS Server"); + }); - if (data.message && data.message.type) { - switch (data.message.type) { - case "JOIN_ROOM": - this.rtc.handleJoin(data.message); - break; - case "REMOVE_USER": - console.log("User has Left Room"); - this.rtc.handleLeave(data.message); - break; - default: - // console.log("Pinged"); + client.on('binary', (data) => { + if (this.google.speech.enabled) { + this.google.speech.getStream().write(data); } - } + }); + + client.on('startRecognition', (lang) => { + if (this.google.speech) { + this.google.speech.stopRecognition(); + this.google.speech = null; + } + + console.log("Speech Recognition Started"); + this.google.speech = new Speech() + this.google.speech.startRecognition(lang); + }) + + client.on('stopRecognition', () => { + // Close Speech Class + console.log("Command given to close Speech Class"); + }) }); } - - /** - * Send Stringified Object to Websocket Server to be processed - * @param {string} command - * @param {Object} identifier - */ - send(command, identifier) { - this.io.send(JSON.stringify({ command, identifier })); - } - - /** - * Send Stringified Object to Websocket server asking to subscribe to channel - */ - subscribe() { - this.io.send( - JSON.stringify({ - command: "subscribe", - identifier: JSON.stringify({ channel: this.channel }) - }) - ); - } } -/** - * The Class Responsible for Handling the data from the WebSocket and Getting the MediaStream. - * @param {string} username - The name of this server when joining the WebRTC Ecosystem. - */ -class WebRTC { - constructor(username) { - /** @type {Array} Array of Connected Users */ - this.users = []; - /** @type {string} */ - this.username = username; - } - - /** - * Handles onmessage event when message contains JOIN - * @param {JSON} data - Objectified (???) JSON - */ - handleJoin(data) { - console.log("User " + data.from + " has joined the room"); - this.users.push(new User(data.from)); - - //Try and Exchange Data with the person - } - - /** - * Handles onmessage event when message contains REMOVE - * @param {JSON} data - Stringified JSON - */ - handleLeave(data) { - console.log("User " + data.from + " has left the room."); - this.users - } -} - -const ac = new ActionCable( - "ws://0.0.0.0:3000/cable", - process.env.DEFAULT_CHANNEL -); - - -class User { - constructor(id) { - this.id = id; - } -} - - -(function addDeleteMethodToArrayPrototype() { - Array.prototype.delete = function(toRemove) { - let i = this.indexOf(toRemove); - - if (i !== -1) this.splice(i, 1); - - //return this; - } -})(); - -const arr = ["Brave", "New", "World"]; - -console.log(arr.delete("New")); -console.log("Length: " + arr.length); +const wss = new WebSocketServer(); diff --git a/app.old.js b/app.old.js new file mode 100644 index 0000000..3770cbb --- /dev/null +++ b/app.old.js @@ -0,0 +1,170 @@ +"use strict"; + +require("dotenv").config(); +const WebSocket = require("ws"); + +/** + * Client responsible for communicating with ActionCable Websocket. + * @param {string} url - URL of Websocket (starts with ws:// or wss://) + * @param {string} channel - Name of ActionCable Channel. + */ +class ActionCable { + constructor(url, channel) { + /** @type {string} */ + this.url = url; + /** @type {string} */ + this.channel = channel; + /** @type {boolean} */ + this.connected = false; + + /** @type {WebSocket} */ + this.io = new WebSocket(url, [ + "actioncable-v1-json", + "actioncable-unsupported" + ]); + + /** @type {WebRTC} */ + // this.rtc = new WebRTC(~~(Math.random() * 1000), this.channel, this.io); + this.rtc = new WebRTC("3929", this.channel, this.io); + + this.setUpEventListeners(); + } + + /** + * Sets up the Websocket event listeners. + */ + setUpEventListeners() { + this.io.on("open", data => { + console.log("Connected to " + this.url); + this.connected = true; + this.subscribe(); + + setTimeout(() => { + console.log("Joining Room"); + this.rtc.joinRoom() + }, 5000); + }); + + this.io.on("close", data => { + console.log("Disconnected from ActionCable Server"); + this.connected = false; + }); + + this.io.on("message", data => { + data = JSON.parse(data); + console.log(data); + + if (data.message && data.message.type) { + switch (data.message.type) { + case "JOIN_ROOM": + this.rtc.handleJoin(data.message); + break; + case "REMOVE_USER": + console.log("User has Left Room"); + this.rtc.handleLeave(data.message); + break; + default: + // console.log("Pinged"); + } + } + }); + } + + /** + * Send Stringified Object to Websocket Server to be processed + * @param {string} command + * @param {Object} identifier + */ + send(command, identifier) { + this.io.send(JSON.stringify({ command, identifier })); + } + + /** + * Send Stringified Object to Websocket server asking to subscribe to channel + */ + subscribe() { + this.io.send( + JSON.stringify({ + command: "subscribe", + identifier: JSON.stringify({ channel: this.channel }) + }) + ); + } +} + +/** + * The Class Responsible for Handling the data from the WebSocket and Getting the MediaStream. + * @param {string} username - The name of this server when joining the WebRTC Ecosystem. + * @param {string} channel + */ +class WebRTC { + constructor(username, channel, webSocket) { + /** @type {Array} Array of Connected Users */ + this.users = []; + /** @type {string} */ + this.username = username; + /** @type {string} */ + this.channel = channel + /** @type {WebSocket} */ + this.io = webSocket; + } + + /** + * Handles onmessage event when message contains JOIN + * @param {JSON} data - Objectified (???) JSON + */ + handleJoin(data) { + console.log("User " + data.from + " has joined the room"); + this.users.push(new User(data.from)); + + //Try and Exchange Data with the person + } + + joinRoom() { + this.io.send(JSON.stringify({ + command: "message", + identifier: JSON.stringify({ + channel: this.channel + }), + message: { + type: "JOIN_ROOM", from: `${this.username}` + } + })); + } + + /** + * Handles onmessage event when message contains REMOVE + * @param {JSON} data - Stringified JSON + */ + handleLeave(data) { + console.log("User " + data.from + " has left the room."); + this.users + } +} + +const ac = new ActionCable( + "ws://0.0.0.0:3000/cable", + process.env.DEFAULT_CHANNEL +); + +class User { + constructor(id) { + this.id = id; + } +} + + +(function addDeleteMethodToArrayPrototype() { + Array.prototype.delete = function(toRemove) { + let i = this.indexOf(toRemove); + + if (i !== -1) this.splice(i, 1); + + //return this; + } +})(); + +const arr = ["Brave", "New", "World"]; + +console.log(arr.delete("New")); +console.log("Length: " + arr.length); diff --git a/google-cloud/Speech.js b/google-cloud/Speech.js new file mode 100644 index 0000000..c83f14e --- /dev/null +++ b/google-cloud/Speech.js @@ -0,0 +1,98 @@ +const speech = require("@google-cloud/speech"); +const Translate = require('./Translate'); +const translate = new Translate('node-polyglot'); + +/** + * Class Responsible for dealing with Google's Speech Recognition API + */ +class Speech { + constructor() { + /** @type {speech.SpeechClient} */ + this.client = new speech.SpeechClient(); + /** @type {Stream} */ + this.recognize = null; + /** @type {boolean} */ + this.enabled = false; + } + + /** + * Getter for the Google API Stream we can write to. + * @returns {Stream} - this.recognize + */ + getStream() { + return this.recognize; + } + + /** + * Stops the GoogleAPI Stream. + */ + stopRecognition() { + if (this.recognize) this.recognize.end(); + this.recognize = null; + this.enabled = false; + } + + /** + * Starts the Google API Stream + * @param {string} lang - Language Code e.g en-CA + */ + startRecognition(lang) { + this.lang = lang; + this.enabled = true; + + const request = { + config: { + encoding: "LINEAR16", + sampleRateHertz: 16000, + languageCode: lang, + profanityFilter: false, + enableWordTimeOffsets: true + }, + interimResults: true // If you want interim results, set this to true + }; + + this.recognize = this.client + .streamingRecognize(request) + .on("error", console.error) + .on("data", data => { + process.stdout.write( + data.results[0] && data.results[0].alternatives[0] + ? `Transcription: ${data.results[0].alternatives[0].transcript}\n` + : `\n\nReached transcription time limit, press Ctrl+C\n` + ); + //client.emit("speechData", data); + + if (data.results[0].alternatives[0] !== undefined) { + let text = data.results[0].alternatives[0].transcript; + + translate.speech(text, "fr").then(translation => { + console.log("Translation: " + translation); + + }).catch(err => console.error(err)); + + // translate + // .translate(text, target) + // .then(results => { + // const translation = results[0]; + // //client.emit("translateData", translation); + + // console.log(`Text: ${text}`); + // console.log(`Translation: ${translation}`); + // }) + // .catch(err => { + // console.error("ERROR:", err); + // }); + } + + // if end of utterance, let's restart stream + // this is a small hack. After 65 seconds of silence, the stream will still throw an error for speech length limit + if (data.results[0] && data.results[0].isFinal) { + this.stopRecognition(); + this.startRecognition(this.lang); + // console.log('restarted stream serverside'); + } + }); + } +} + +module.exports = Speech; diff --git a/google-cloud/Translate.js b/google-cloud/Translate.js new file mode 100644 index 0000000..7f0457d --- /dev/null +++ b/google-cloud/Translate.js @@ -0,0 +1,29 @@ +const Trans = require('@google-cloud/translate'); + +class Translate { + /** @param {string} id - ID of Project for Google Translate */ + constructor(id) { + this.id = id; + this.client = new Trans({ + projectId: id + }) + } + + /** + * As in Translate.speech() + * @param {string} text - Text to Translate + * @param {string} lang - Target Language + * @returns {Promise|Error>} + * @async + */ + async speech(text, lang) { + return new Promise((res, rej) => { + this.client.translate(text, lang).then(results => { + res(results[0]); // Translation + + }).catch(err => rej(err)); + }); + } +} + +module.exports = Translate; \ No newline at end of file diff --git a/package.json b/package.json index 40eea1d..537ee14 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "polyglot", "version": "1.0.0", - "description": "Rails server to run alongside https://github.com/beatriceo/polyglot", + "description": "Node server to run alongside https://github.com/beatriceo/polyglot", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", @@ -21,6 +21,6 @@ "@google-cloud/speech": "^2.0.0", "@google-cloud/translate": "^1.1.0", "dotenv": "^6.0.0", - "ws": "^6.0.0" + "socket.io": "^2.1.1" } } diff --git a/yarn.lock b/yarn.lock index d090918..8750fa8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -115,6 +115,13 @@ abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" +accepts@~1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + acorn-es7-plugin@^1.0.12: version "1.1.7" resolved "https://registry.yarnpkg.com/acorn-es7-plugin/-/acorn-es7-plugin-1.1.7.tgz#f2ee1f3228a90eead1245f9ab1922eb2e71d336b" @@ -123,6 +130,10 @@ acorn@^5.0.0: version "5.7.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.2.tgz#91fa871883485d06708800318404e72bfb26dcc5" +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" @@ -181,6 +192,10 @@ array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -239,10 +254,22 @@ axios@^0.18.0: follow-redirects "^1.3.0" is-buffer "^1.1.5" +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -261,6 +288,16 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + +blob@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -319,6 +356,10 @@ call-signature@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/call-signature/-/call-signature-0.0.2.tgz#a84abc825a55ef4cb2b028bd74e205a65b9a4996" +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + camelcase@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -377,10 +418,18 @@ combined-stream@1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -component-emitter@^1.2.1: +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + +component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -398,6 +447,10 @@ 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" +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" @@ -428,7 +481,7 @@ debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^3.1.0: +debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -544,6 +597,43 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~3.3.1" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.4" + has-binary2 "~1.0.2" + +engine.io@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~3.3.1" + ent@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" @@ -852,6 +942,16 @@ har-validator@~5.1.0: ajv "^5.3.0" har-schema "^2.0.0" +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -1052,6 +1152,10 @@ isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -1207,7 +1311,7 @@ mime-db@~1.36.0: version "1.36.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" -mime-types@^2.1.12, mime-types@~2.1.19: +mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.19: version "2.1.20" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" dependencies: @@ -1297,6 +1401,10 @@ needle@^2.2.1: iconv-lite "^0.4.4" sax "^1.2.4" +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + node-forge@^0.7.1, node-forge@^0.7.4: version "0.7.6" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" @@ -1355,6 +1463,10 @@ object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -1410,6 +1522,18 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + dependencies: + better-assert "~1.0.0" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -1765,6 +1889,48 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +socket.io-adapter@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.2.0" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.2.0" + to-array "0.1.4" + +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + dependencies: + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" + source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" @@ -1900,6 +2066,10 @@ through2@^2.0.0, through2@^2.0.3: readable-stream "^2.1.5" xtend "~4.0.1" +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -1951,6 +2121,10 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -2020,11 +2194,17 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -ws@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.0.0.tgz#eaa494aded00ac4289d455bac8d84c7c651cef35" +ws@~3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" dependencies: async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" xtend@^4.0.0, xtend@~4.0.1: version "4.0.1" @@ -2053,3 +2233,7 @@ yargs@^3.10.0: string-width "^1.0.1" window-size "^0.1.4" y18n "^3.2.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"