(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ (function(global, undefined) { "use strict"; var POW_2_24 = Math.pow(2, -24), POW_2_32 = Math.pow(2, 32), POW_2_53 = Math.pow(2, 53); function encode(value) { var data = new ArrayBuffer(256); var dataView = new DataView(data); var lastLength; var offset = 0; function ensureSpace(length) { var newByteLength = data.byteLength; var requiredLength = offset + length; while (newByteLength < requiredLength) newByteLength *= 2; if (newByteLength !== data.byteLength) { var oldDataView = dataView; data = new ArrayBuffer(newByteLength); dataView = new DataView(data); var uint32count = (offset + 3) >> 2; for (var i = 0; i < uint32count; ++i) dataView.setUint32(i * 4, oldDataView.getUint32(i * 4)); } lastLength = length; return dataView; } function write() { offset += lastLength; } function writeFloat64(value) { write(ensureSpace(8).setFloat64(offset, value)); } function writeUint8(value) { write(ensureSpace(1).setUint8(offset, value)); } function writeUint8Array(value) { var dataView = ensureSpace(value.length); for (var i = 0; i < value.length; ++i) dataView.setUint8(offset + i, value[i]); write(); } function writeUint16(value) { write(ensureSpace(2).setUint16(offset, value)); } function writeUint32(value) { write(ensureSpace(4).setUint32(offset, value)); } function writeUint64(value) { var low = value % POW_2_32; var high = (value - low) / POW_2_32; var dataView = ensureSpace(8); dataView.setUint32(offset, high); dataView.setUint32(offset + 4, low); write(); } function writeTypeAndLength(type, length) { if (length < 24) { writeUint8(type << 5 | length); } else if (length < 0x100) { writeUint8(type << 5 | 24); writeUint8(length); } else if (length < 0x10000) { writeUint8(type << 5 | 25); writeUint16(length); } else if (length < 0x100000000) { writeUint8(type << 5 | 26); writeUint32(length); } else { writeUint8(type << 5 | 27); writeUint64(length); } } function encodeItem(value) { var i; if (value === false) return writeUint8(0xf4); if (value === true) return writeUint8(0xf5); if (value === null) return writeUint8(0xf6); if (value === undefined) return writeUint8(0xf7); switch (typeof value) { case "number": if (Math.floor(value) === value) { if (0 <= value && value <= POW_2_53) return writeTypeAndLength(0, value); if (-POW_2_53 <= value && value < 0) return writeTypeAndLength(1, -(value + 1)); } writeUint8(0xfb); return writeFloat64(value); case "string": var utf8data = []; for (i = 0; i < value.length; ++i) { var charCode = value.charCodeAt(i); if (charCode < 0x80) { utf8data.push(charCode); } else if (charCode < 0x800) { utf8data.push(0xc0 | charCode >> 6); utf8data.push(0x80 | charCode & 0x3f); } else if (charCode < 0xd800) { utf8data.push(0xe0 | charCode >> 12); utf8data.push(0x80 | (charCode >> 6) & 0x3f); utf8data.push(0x80 | charCode & 0x3f); } else { charCode = (charCode & 0x3ff) << 10; charCode |= value.charCodeAt(++i) & 0x3ff; charCode += 0x10000; utf8data.push(0xf0 | charCode >> 18); utf8data.push(0x80 | (charCode >> 12) & 0x3f); utf8data.push(0x80 | (charCode >> 6) & 0x3f); utf8data.push(0x80 | charCode & 0x3f); } } writeTypeAndLength(3, utf8data.length); return writeUint8Array(utf8data); default: var length; if (Array.isArray(value)) { length = value.length; writeTypeAndLength(4, length); for (i = 0; i < length; ++i) encodeItem(value[i]); } else if (value instanceof Uint8Array) { writeTypeAndLength(2, value.length); writeUint8Array(value); } else { var keys = Object.keys(value); length = keys.length; writeTypeAndLength(5, length); for (i = 0; i < length; ++i) { var key = keys[i]; encodeItem(key); encodeItem(value[key]); } } } } encodeItem(value); if ("slice" in data) return data.slice(0, offset); var ret = new ArrayBuffer(offset); var retView = new DataView(ret); for (var i = 0; i < offset; ++i) retView.setUint8(i, dataView.getUint8(i)); return ret; } function decode(data, tagger, simpleValue) { var dataView = new DataView(data); var offset = 0; if (typeof tagger !== "function") tagger = function(value) { return value; }; if (typeof simpleValue !== "function") simpleValue = function() { return undefined; }; function read(value, length) { offset += length; return value; } function readArrayBuffer(length) { return read(new Uint8Array(data, offset, length), length); } function readFloat16() { var tempArrayBuffer = new ArrayBuffer(4); var tempDataView = new DataView(tempArrayBuffer); var value = readUint16(); var sign = value & 0x8000; var exponent = value & 0x7c00; var fraction = value & 0x03ff; if (exponent === 0x7c00) exponent = 0xff << 10; else if (exponent !== 0) exponent += (127 - 15) << 10; else if (fraction !== 0) return fraction * POW_2_24; tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); return tempDataView.getFloat32(0); } function readFloat32() { return read(dataView.getFloat32(offset), 4); } function readFloat64() { return read(dataView.getFloat64(offset), 8); } function readUint8() { return read(dataView.getUint8(offset), 1); } function readUint16() { return read(dataView.getUint16(offset), 2); } function readUint32() { return read(dataView.getUint32(offset), 4); } function readUint64() { return readUint32() * POW_2_32 + readUint32(); } function readBreak() { if (dataView.getUint8(offset) !== 0xff) return false; offset += 1; return true; } function readLength(additionalInformation) { if (additionalInformation < 24) return additionalInformation; if (additionalInformation === 24) return readUint8(); if (additionalInformation === 25) return readUint16(); if (additionalInformation === 26) return readUint32(); if (additionalInformation === 27) return readUint64(); if (additionalInformation === 31) return -1; throw "Invalid length encoding"; } function readIndefiniteStringLength(majorType) { var initialByte = readUint8(); if (initialByte === 0xff) return -1; var length = readLength(initialByte & 0x1f); if (length < 0 || (initialByte >> 5) !== majorType) throw "Invalid indefinite length element"; return length; } function appendUtf16data(utf16data, length) { for (var i = 0; i < length; ++i) { var value = readUint8(); if (value & 0x80) { if (value < 0xe0) { value = (value & 0x1f) << 6 | (readUint8() & 0x3f); length -= 1; } else if (value < 0xf0) { value = (value & 0x0f) << 12 | (readUint8() & 0x3f) << 6 | (readUint8() & 0x3f); length -= 2; } else { value = (value & 0x0f) << 18 | (readUint8() & 0x3f) << 12 | (readUint8() & 0x3f) << 6 | (readUint8() & 0x3f); length -= 3; } } if (value < 0x10000) { utf16data.push(value); } else { value -= 0x10000; utf16data.push(0xd800 | (value >> 10)); utf16data.push(0xdc00 | (value & 0x3ff)); } } } function decodeItem() { var initialByte = readUint8(); var majorType = initialByte >> 5; var additionalInformation = initialByte & 0x1f; var i; var length; if (majorType === 7) { switch (additionalInformation) { case 25: return readFloat16(); case 26: return readFloat32(); case 27: return readFloat64(); } } length = readLength(additionalInformation); if (length < 0 && (majorType < 2 || 6 < majorType)) throw "Invalid length"; switch (majorType) { case 0: return length; case 1: return -1 - length; case 2: if (length < 0) { var elements = []; var fullArrayLength = 0; while ((length = readIndefiniteStringLength(majorType)) >= 0) { fullArrayLength += length; elements.push(readArrayBuffer(length)); } var fullArray = new Uint8Array(fullArrayLength); var fullArrayOffset = 0; for (i = 0; i < elements.length; ++i) { fullArray.set(elements[i], fullArrayOffset); fullArrayOffset += elements[i].length; } return fullArray; } return readArrayBuffer(length); case 3: var utf16data = []; if (length < 0) { while ((length = readIndefiniteStringLength(majorType)) >= 0) appendUtf16data(utf16data, length); } else appendUtf16data(utf16data, length); return String.fromCharCode.apply(null, utf16data); case 4: var retArray; if (length < 0) { retArray = []; while (!readBreak()) retArray.push(decodeItem()); } else { retArray = new Array(length); for (i = 0; i < length; ++i) retArray[i] = decodeItem(); } return retArray; case 5: var retObject = {}; for (i = 0; i < length || length < 0 && !readBreak(); ++i) { var key = decodeItem(); retObject[key] = decodeItem(); } return retObject; case 6: return tagger(decodeItem(), length); case 7: switch (length) { case 20: return false; case 21: return true; case 22: return null; case 23: return undefined; default: return simpleValue(length); } } } var ret = decodeItem(); if (offset !== data.byteLength) throw "Remaining bytes"; return ret; } var obj = { encode: encode, decode: decode }; if (typeof define === "function" && define.amd) define("cbor/cbor", obj); else if (typeof module !== 'undefined' && module.exports) module.exports = obj; else if (!global.CBOR) global.CBOR = obj; })(this); },{}],2:[function(require,module,exports){ (function (process){ /*! * EventEmitter2 * https://github.com/hij1nx/EventEmitter2 * * Copyright (c) 2013 hij1nx * Licensed under the MIT license. */ ;!function(undefined) { var isArray = Array.isArray ? Array.isArray : function _isArray(obj) { return Object.prototype.toString.call(obj) === "[object Array]"; }; var defaultMaxListeners = 10; function init() { this._events = {}; if (this._conf) { configure.call(this, this._conf); } } function configure(conf) { if (conf) { this._conf = conf; conf.delimiter && (this.delimiter = conf.delimiter); this._maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners; conf.wildcard && (this.wildcard = conf.wildcard); conf.newListener && (this.newListener = conf.newListener); conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak); if (this.wildcard) { this.listenerTree = {}; } } else { this._maxListeners = defaultMaxListeners; } } function logPossibleMemoryLeak(count, eventName) { var errorMsg = '(node) warning: possible EventEmitter memory ' + 'leak detected. ' + count + ' listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.'; if(this.verboseMemoryLeak){ errorMsg += ' Event name: ' + eventName + '.'; } if(typeof process !== 'undefined' && process.emitWarning){ var e = new Error(errorMsg); e.name = 'MaxListenersExceededWarning'; e.emitter = this; e.count = count; process.emitWarning(e); } else { console.error(errorMsg); if (console.trace){ console.trace(); } } } function EventEmitter(conf) { this._events = {}; this.newListener = false; this.verboseMemoryLeak = false; configure.call(this, conf); } EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property // // Attention, function return type now is array, always ! // It has zero elements if no any matches found and one or more // elements (leafs) if there are matches // function searchListenerTree(handlers, type, tree, i) { if (!tree) { return []; } var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached, typeLength = type.length, currentType = type[i], nextType = type[i+1]; if (i === typeLength && tree._listeners) { // // If at the end of the event(s) list and the tree has listeners // invoke those listeners. // if (typeof tree._listeners === 'function') { handlers && handlers.push(tree._listeners); return [tree]; } else { for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) { handlers && handlers.push(tree._listeners[leaf]); } return [tree]; } } if ((currentType === '*' || currentType === '**') || tree[currentType]) { // // If the event emitted is '*' at this part // or there is a concrete match at this patch // if (currentType === '*') { for (branch in tree) { if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1)); } } return listeners; } else if(currentType === '**') { endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*')); if(endReached && tree._listeners) { // The next element has a _listeners, add it to the handlers. listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength)); } for (branch in tree) { if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { if(branch === '*' || branch === '**') { if(tree[branch]._listeners && !endReached) { listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength)); } listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); } else if(branch === nextType) { listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2)); } else { // No match on this one, shift into the tree but not in the type array. listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); } } } return listeners; } listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1)); } xTree = tree['*']; if (xTree) { // // If the listener tree will allow any match for this part, // then recursively explore all branches of the tree // searchListenerTree(handlers, type, xTree, i+1); } xxTree = tree['**']; if(xxTree) { if(i < typeLength) { if(xxTree._listeners) { // If we have a listener on a '**', it will catch all, so add its handler. searchListenerTree(handlers, type, xxTree, typeLength); } // Build arrays of matching next branches and others. for(branch in xxTree) { if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) { if(branch === nextType) { // We know the next element will match, so jump twice. searchListenerTree(handlers, type, xxTree[branch], i+2); } else if(branch === currentType) { // Current node matches, move into the tree. searchListenerTree(handlers, type, xxTree[branch], i+1); } else { isolatedBranch = {}; isolatedBranch[branch] = xxTree[branch]; searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1); } } } } else if(xxTree._listeners) { // We have reached the end and still on a '**' searchListenerTree(handlers, type, xxTree, typeLength); } else if(xxTree['*'] && xxTree['*']._listeners) { searchListenerTree(handlers, type, xxTree['*'], typeLength); } } return listeners; } function growListenerTree(type, listener) { type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); // // Looks for two consecutive '**', if so, don't add the event at all. // for(var i = 0, len = type.length; i+1 < len; i++) { if(type[i] === '**' && type[i+1] === '**') { return; } } var tree = this.listenerTree; var name = type.shift(); while (name !== undefined) { if (!tree[name]) { tree[name] = {}; } tree = tree[name]; if (type.length === 0) { if (!tree._listeners) { tree._listeners = listener; } else { if (typeof tree._listeners === 'function') { tree._listeners = [tree._listeners]; } tree._listeners.push(listener); if ( !tree._listeners.warned && this._maxListeners > 0 && tree._listeners.length > this._maxListeners ) { tree._listeners.warned = true; logPossibleMemoryLeak.call(this, tree._listeners.length, name); } } return true; } name = type.shift(); } return true; } // By default EventEmitters will print a warning if more than // 10 listeners are added to it. This is a useful default which // helps finding memory leaks. // // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.delimiter = '.'; EventEmitter.prototype.setMaxListeners = function(n) { if (n !== undefined) { this._maxListeners = n; if (!this._conf) this._conf = {}; this._conf.maxListeners = n; } }; EventEmitter.prototype.event = ''; EventEmitter.prototype.once = function(event, fn) { return this._once(event, fn, false); }; EventEmitter.prototype.prependOnceListener = function(event, fn) { return this._once(event, fn, true); }; EventEmitter.prototype._once = function(event, fn, prepend) { this._many(event, 1, fn, prepend); return this; }; EventEmitter.prototype.many = function(event, ttl, fn) { return this._many(event, ttl, fn, false); } EventEmitter.prototype.prependMany = function(event, ttl, fn) { return this._many(event, ttl, fn, true); } EventEmitter.prototype._many = function(event, ttl, fn, prepend) { var self = this; if (typeof fn !== 'function') { throw new Error('many only accepts instances of Function'); } function listener() { if (--ttl === 0) { self.off(event, listener); } return fn.apply(this, arguments); } listener._origin = fn; this._on(event, listener, prepend); return self; }; EventEmitter.prototype.emit = function() { this._events || init.call(this); var type = arguments[0]; if (type === 'newListener' && !this.newListener) { if (!this._events.newListener) { return false; } } var al = arguments.length; var args,l,i,j; var handler; if (this._all && this._all.length) { handler = this._all.slice(); if (al > 3) { args = new Array(al); for (j = 0; j < al; j++) args[j] = arguments[j]; } for (i = 0, l = handler.length; i < l; i++) { this.event = type; switch (al) { case 1: handler[i].call(this, type); break; case 2: handler[i].call(this, type, arguments[1]); break; case 3: handler[i].call(this, type, arguments[1], arguments[2]); break; default: handler[i].apply(this, args); } } } if (this.wildcard) { handler = []; var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); searchListenerTree.call(this, handler, ns, this.listenerTree, 0); } else { handler = this._events[type]; if (typeof handler === 'function') { this.event = type; switch (al) { case 1: handler.call(this); break; case 2: handler.call(this, arguments[1]); break; case 3: handler.call(this, arguments[1], arguments[2]); break; default: args = new Array(al - 1); for (j = 1; j < al; j++) args[j - 1] = arguments[j]; handler.apply(this, args); } return true; } else if (handler) { // need to make copy of handlers because list can change in the middle // of emit call handler = handler.slice(); } } if (handler && handler.length) { if (al > 3) { args = new Array(al - 1); for (j = 1; j < al; j++) args[j - 1] = arguments[j]; } for (i = 0, l = handler.length; i < l; i++) { this.event = type; switch (al) { case 1: handler[i].call(this); break; case 2: handler[i].call(this, arguments[1]); break; case 3: handler[i].call(this, arguments[1], arguments[2]); break; default: handler[i].apply(this, args); } } return true; } else if (!this._all && type === 'error') { if (arguments[1] instanceof Error) { throw arguments[1]; // Unhandled 'error' event } else { throw new Error("Uncaught, unspecified 'error' event."); } return false; } return !!this._all; }; EventEmitter.prototype.emitAsync = function() { this._events || init.call(this); var type = arguments[0]; if (type === 'newListener' && !this.newListener) { if (!this._events.newListener) { return Promise.resolve([false]); } } var promises= []; var al = arguments.length; var args,l,i,j; var handler; if (this._all) { if (al > 3) { args = new Array(al); for (j = 1; j < al; j++) args[j] = arguments[j]; } for (i = 0, l = this._all.length; i < l; i++) { this.event = type; switch (al) { case 1: promises.push(this._all[i].call(this, type)); break; case 2: promises.push(this._all[i].call(this, type, arguments[1])); break; case 3: promises.push(this._all[i].call(this, type, arguments[1], arguments[2])); break; default: promises.push(this._all[i].apply(this, args)); } } } if (this.wildcard) { handler = []; var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); searchListenerTree.call(this, handler, ns, this.listenerTree, 0); } else { handler = this._events[type]; } if (typeof handler === 'function') { this.event = type; switch (al) { case 1: promises.push(handler.call(this)); break; case 2: promises.push(handler.call(this, arguments[1])); break; case 3: promises.push(handler.call(this, arguments[1], arguments[2])); break; default: args = new Array(al - 1); for (j = 1; j < al; j++) args[j - 1] = arguments[j]; promises.push(handler.apply(this, args)); } } else if (handler && handler.length) { handler = handler.slice(); if (al > 3) { args = new Array(al - 1); for (j = 1; j < al; j++) args[j - 1] = arguments[j]; } for (i = 0, l = handler.length; i < l; i++) { this.event = type; switch (al) { case 1: promises.push(handler[i].call(this)); break; case 2: promises.push(handler[i].call(this, arguments[1])); break; case 3: promises.push(handler[i].call(this, arguments[1], arguments[2])); break; default: promises.push(handler[i].apply(this, args)); } } } else if (!this._all && type === 'error') { if (arguments[1] instanceof Error) { return Promise.reject(arguments[1]); // Unhandled 'error' event } else { return Promise.reject("Uncaught, unspecified 'error' event."); } } return Promise.all(promises); }; EventEmitter.prototype.on = function(type, listener) { return this._on(type, listener, false); }; EventEmitter.prototype.prependListener = function(type, listener) { return this._on(type, listener, true); }; EventEmitter.prototype.onAny = function(fn) { return this._onAny(fn, false); }; EventEmitter.prototype.prependAny = function(fn) { return this._onAny(fn, true); }; EventEmitter.prototype.addListener = EventEmitter.prototype.on; EventEmitter.prototype._onAny = function(fn, prepend){ if (typeof fn !== 'function') { throw new Error('onAny only accepts instances of Function'); } if (!this._all) { this._all = []; } // Add the function to the event listener collection. if(prepend){ this._all.unshift(fn); }else{ this._all.push(fn); } return this; } EventEmitter.prototype._on = function(type, listener, prepend) { if (typeof type === 'function') { this._onAny(type, listener); return this; } if (typeof listener !== 'function') { throw new Error('on only accepts instances of Function'); } this._events || init.call(this); // To avoid recursion in the case that type == "newListeners"! Before // adding it to the listeners, first emit "newListeners". this.emit('newListener', type, listener); if (this.wildcard) { growListenerTree.call(this, type, listener); return this; } if (!this._events[type]) { // Optimize the case of one listener. Don't need the extra array object. this._events[type] = listener; } else { if (typeof this._events[type] === 'function') { // Change to array. this._events[type] = [this._events[type]]; } // If we've already got an array, just add if(prepend){ this._events[type].unshift(listener); }else{ this._events[type].push(listener); } // Check for listener leak if ( !this._events[type].warned && this._maxListeners > 0 && this._events[type].length > this._maxListeners ) { this._events[type].warned = true; logPossibleMemoryLeak.call(this, this._events[type].length, type); } } return this; } EventEmitter.prototype.off = function(type, listener) { if (typeof listener !== 'function') { throw new Error('removeListener only takes instances of Function'); } var handlers,leafs=[]; if(this.wildcard) { var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); } else { // does not use listeners(), so no side effect of creating _events[type] if (!this._events[type]) return this; handlers = this._events[type]; leafs.push({_listeners:handlers}); } for (var iLeaf=0; iLeaf 0) { recursivelyGarbageCollect(root[key]); } if (Object.keys(obj).length === 0) { delete root[key]; } } } recursivelyGarbageCollect(this.listenerTree); return this; }; EventEmitter.prototype.offAny = function(fn) { var i = 0, l = 0, fns; if (fn && this._all && this._all.length > 0) { fns = this._all; for(i = 0, l = fns.length; i < l; i++) { if(fn === fns[i]) { fns.splice(i, 1); this.emit("removeListenerAny", fn); return this; } } } else { fns = this._all; for(i = 0, l = fns.length; i < l; i++) this.emit("removeListenerAny", fns[i]); this._all = []; } return this; }; EventEmitter.prototype.removeListener = EventEmitter.prototype.off; EventEmitter.prototype.removeAllListeners = function(type) { if (arguments.length === 0) { !this._events || init.call(this); return this; } if (this.wildcard) { var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); for (var iLeaf=0; iLeaf 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { runTimeout(drainQueue); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.prependListener = noop; process.prependOnceListener = noop; process.listeners = function (name) { return [] } process.binding = function (name) { throw new Error('process.binding is not supported'); }; process.cwd = function () { return '/' }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function() { return 0; }; },{}],5:[function(require,module,exports){ /** * @fileOverview * @author Russell Toris - rctoris@wpi.edu */ /** * If you use roslib in a browser, all the classes will be exported to a global variable called ROSLIB. * * If you use nodejs, this is the variable you get when you require('roslib') */ var ROSLIB = this.ROSLIB || { REVISION : '1.0.1' }; var assign = require('object-assign'); // Add core components assign(ROSLIB, require('./core')); assign(ROSLIB, require('./actionlib')); assign(ROSLIB, require('./math')); assign(ROSLIB, require('./tf')); assign(ROSLIB, require('./urdf')); module.exports = ROSLIB; },{"./actionlib":11,"./core":20,"./math":25,"./tf":28,"./urdf":40,"object-assign":3}],6:[function(require,module,exports){ (function (global){ global.ROSLIB = require('./RosLib'); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./RosLib":5}],7:[function(require,module,exports){ /** * @fileOverview * @author Russell Toris - rctoris@wpi.edu */ var Topic = require('../core/Topic'); var Message = require('../core/Message'); var EventEmitter2 = require('eventemitter2').EventEmitter2; /** * An actionlib action client. * * Emits the following events: * * 'timeout' - if a timeout occurred while sending a goal * * 'status' - the status messages received from the action server * * 'feedback' - the feedback messages received from the action server * * 'result' - the result returned from the action server * * @constructor * @param options - object with following keys: * * ros - the ROSLIB.Ros connection handle * * serverName - the action server name, like /fibonacci * * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction' * * timeout - the timeout length when connecting to the action server */ function ActionClient(options) { var that = this; options = options || {}; this.ros = options.ros; this.serverName = options.serverName; this.actionName = options.actionName; this.timeout = options.timeout; this.omitFeedback = options.omitFeedback; this.omitStatus = options.omitStatus; this.omitResult = options.omitResult; this.goals = {}; // flag to check if a status has been received var receivedStatus = false; // create the topics associated with actionlib this.feedbackListener = new Topic({ ros : this.ros, name : this.serverName + '/feedback', messageType : this.actionName + 'Feedback' }); this.statusListener = new Topic({ ros : this.ros, name : this.serverName + '/status', messageType : 'actionlib_msgs/GoalStatusArray' }); this.resultListener = new Topic({ ros : this.ros, name : this.serverName + '/result', messageType : this.actionName + 'Result' }); this.goalTopic = new Topic({ ros : this.ros, name : this.serverName + '/goal', messageType : this.actionName + 'Goal' }); this.cancelTopic = new Topic({ ros : this.ros, name : this.serverName + '/cancel', messageType : 'actionlib_msgs/GoalID' }); // advertise the goal and cancel topics this.goalTopic.advertise(); this.cancelTopic.advertise(); // subscribe to the status topic if (!this.omitStatus) { this.statusListener.subscribe(function(statusMessage) { receivedStatus = true; statusMessage.status_list.forEach(function(status) { var goal = that.goals[status.goal_id.id]; if (goal) { goal.emit('status', status); } }); }); } // subscribe the the feedback topic if (!this.omitFeedback) { this.feedbackListener.subscribe(function(feedbackMessage) { var goal = that.goals[feedbackMessage.status.goal_id.id]; if (goal) { goal.emit('status', feedbackMessage.status); goal.emit('feedback', feedbackMessage.feedback); } }); } // subscribe to the result topic if (!this.omitResult) { this.resultListener.subscribe(function(resultMessage) { var goal = that.goals[resultMessage.status.goal_id.id]; if (goal) { goal.emit('status', resultMessage.status); goal.emit('result', resultMessage.result); } }); } // If timeout specified, emit a 'timeout' event if the action server does not respond if (this.timeout) { setTimeout(function() { if (!receivedStatus) { that.emit('timeout'); } }, this.timeout); } } ActionClient.prototype.__proto__ = EventEmitter2.prototype; /** * Cancel all goals associated with this ActionClient. */ ActionClient.prototype.cancel = function() { var cancelMessage = new Message(); this.cancelTopic.publish(cancelMessage); }; /** * Unsubscribe and unadvertise all topics associated with this ActionClient. */ ActionClient.prototype.dispose = function() { this.goalTopic.unadvertise(); this.cancelTopic.unadvertise(); if (!this.omitStatus) {this.statusListener.unsubscribe();} if (!this.omitFeedback) {this.feedbackListener.unsubscribe();} if (!this.omitResult) {this.resultListener.unsubscribe();} }; module.exports = ActionClient; },{"../core/Message":12,"../core/Topic":19,"eventemitter2":2}],8:[function(require,module,exports){ /** * @fileOverview * @author Justin Young - justin@oodar.com.au * @author Russell Toris - rctoris@wpi.edu */ var Topic = require('../core/Topic'); var Message = require('../core/Message'); var EventEmitter2 = require('eventemitter2').EventEmitter2; /** * An actionlib action listener * * Emits the following events: * * 'status' - the status messages received from the action server * * 'feedback' - the feedback messages received from the action server * * 'result' - the result returned from the action server * * @constructor * @param options - object with following keys: * * ros - the ROSLIB.Ros connection handle * * serverName - the action server name, like /fibonacci * * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction' */ function ActionListener(options) { var that = this; options = options || {}; this.ros = options.ros; this.serverName = options.serverName; this.actionName = options.actionName; this.timeout = options.timeout; this.omitFeedback = options.omitFeedback; this.omitStatus = options.omitStatus; this.omitResult = options.omitResult; // create the topics associated with actionlib var goalListener = new Topic({ ros : this.ros, name : this.serverName + '/goal', messageType : this.actionName + 'Goal' }); var feedbackListener = new Topic({ ros : this.ros, name : this.serverName + '/feedback', messageType : this.actionName + 'Feedback' }); var statusListener = new Topic({ ros : this.ros, name : this.serverName + '/status', messageType : 'actionlib_msgs/GoalStatusArray' }); var resultListener = new Topic({ ros : this.ros, name : this.serverName + '/result', messageType : this.actionName + 'Result' }); goalListener.subscribe(function(goalMessage) { that.emit('goal', goalMessage); }); statusListener.subscribe(function(statusMessage) { statusMessage.status_list.forEach(function(status) { that.emit('status', status); }); }); feedbackListener.subscribe(function(feedbackMessage) { that.emit('status', feedbackMessage.status); that.emit('feedback', feedbackMessage.feedback); }); // subscribe to the result topic resultListener.subscribe(function(resultMessage) { that.emit('status', resultMessage.status); that.emit('result', resultMessage.result); }); } ActionListener.prototype.__proto__ = EventEmitter2.prototype; module.exports = ActionListener; },{"../core/Message":12,"../core/Topic":19,"eventemitter2":2}],9:[function(require,module,exports){ /** * @fileOverview * @author Russell Toris - rctoris@wpi.edu */ var Message = require('../core/Message'); var EventEmitter2 = require('eventemitter2').EventEmitter2; /** * An actionlib goal goal is associated with an action server. * * Emits the following events: * * 'timeout' - if a timeout occurred while sending a goal * * @constructor * @param object with following keys: * * actionClient - the ROSLIB.ActionClient to use with this goal * * goalMessage - The JSON object containing the goal for the action server */ function Goal(options) { var that = this; this.actionClient = options.actionClient; this.goalMessage = options.goalMessage; this.isFinished = false; // Used to create random IDs var date = new Date(); // Create a random ID this.goalID = 'goal_' + Math.random() + '_' + date.getTime(); // Fill in the goal message this.goalMessage = new Message({ goal_id : { stamp : { secs : 0, nsecs : 0 }, id : this.goalID }, goal : this.goalMessage }); this.on('status', function(status) { that.status = status; }); this.on('result', function(result) { that.isFinished = true; that.result = result; }); this.on('feedback', function(feedback) { that.feedback = feedback; }); // Add the goal this.actionClient.goals[this.goalID] = this; } Goal.prototype.__proto__ = EventEmitter2.prototype; /** * Send the goal to the action server. * * @param timeout (optional) - a timeout length for the goal's result */ Goal.prototype.send = function(timeout) { var that = this; that.actionClient.goalTopic.publish(that.goalMessage); if (timeout) { setTimeout(function() { if (!that.isFinished) { that.emit('timeout'); } }, timeout); } }; /** * Cancel the current goal. */ Goal.prototype.cancel = function() { var cancelMessage = new Message({ id : this.goalID }); this.actionClient.cancelTopic.publish(cancelMessage); }; module.exports = Goal; },{"../core/Message":12,"eventemitter2":2}],10:[function(require,module,exports){ /** * @fileOverview * @author Laura Lindzey - lindzey@gmail.com */ var Topic = require('../core/Topic'); var Message = require('../core/Message'); var EventEmitter2 = require('eventemitter2').EventEmitter2; /** * An actionlib action server client. * * Emits the following events: * * 'goal' - goal sent by action client * * 'cancel' - action client has canceled the request * * @constructor * @param options - object with following keys: * * ros - the ROSLIB.Ros connection handle * * serverName - the action server name, like /fibonacci * * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction' */ function SimpleActionServer(options) { var that = this; options = options || {}; this.ros = options.ros; this.serverName = options.serverName; this.actionName = options.actionName; // create and advertise publishers this.feedbackPublisher = new Topic({ ros : this.ros, name : this.serverName + '/feedback', messageType : this.actionName + 'Feedback' }); this.feedbackPublisher.advertise(); var statusPublisher = new Topic({ ros : this.ros, name : this.serverName + '/status', messageType : 'actionlib_msgs/GoalStatusArray' }); statusPublisher.advertise(); this.resultPublisher = new Topic({ ros : this.ros, name : this.serverName + '/result', messageType : this.actionName + 'Result' }); this.resultPublisher.advertise(); // create and subscribe to listeners var goalListener = new Topic({ ros : this.ros, name : this.serverName + '/goal', messageType : this.actionName + 'Goal' }); var cancelListener = new Topic({ ros : this.ros, name : this.serverName + '/cancel', messageType : 'actionlib_msgs/GoalID' }); // Track the goals and their status in order to publish status... this.statusMessage = new Message({ header : { stamp : {secs : 0, nsecs : 100}, frame_id : '' }, status_list : [] }); // needed for handling preemption prompted by a new goal being received this.currentGoal = null; // currently tracked goal this.nextGoal = null; // the one that'll be preempting goalListener.subscribe(function(goalMessage) { if(that.currentGoal) { that.nextGoal = goalMessage; // needs to happen AFTER rest is set up that.emit('cancel'); } else { that.statusMessage.status_list = [{goal_id : goalMessage.goal_id, status : 1}]; that.currentGoal = goalMessage; that.emit('goal', goalMessage.goal); } }); // helper function for determing ordering of timestamps // returns t1 < t2 var isEarlier = function(t1, t2) { if(t1.secs > t2.secs) { return false; } else if(t1.secs < t2.secs) { return true; } else if(t1.nsecs < t2.nsecs) { return true; } else { return false; } }; // TODO: this may be more complicated than necessary, since I'm // not sure if the callbacks can ever wind up with a scenario // where we've been preempted by a next goal, it hasn't finished // processing, and then we get a cancel message cancelListener.subscribe(function(cancelMessage) { // cancel ALL goals if both empty if(cancelMessage.stamp.secs === 0 && cancelMessage.stamp.secs === 0 && cancelMessage.id === '') { that.nextGoal = null; if(that.currentGoal) { that.emit('cancel'); } } else { // treat id and stamp independently if(that.currentGoal && cancelMessage.id === that.currentGoal.goal_id.id) { that.emit('cancel'); } else if(that.nextGoal && cancelMessage.id === that.nextGoal.goal_id.id) { that.nextGoal = null; } if(that.nextGoal && isEarlier(that.nextGoal.goal_id.stamp, cancelMessage.stamp)) { that.nextGoal = null; } if(that.currentGoal && isEarlier(that.currentGoal.goal_id.stamp, cancelMessage.stamp)) { that.emit('cancel'); } } }); // publish status at pseudo-fixed rate; required for clients to know they've connected var statusInterval = setInterval( function() { var currentTime = new Date(); var secs = Math.floor(currentTime.getTime()/1000); var nsecs = Math.round(1000000000*(currentTime.getTime()/1000-secs)); that.statusMessage.header.stamp.secs = secs; that.statusMessage.header.stamp.nsecs = nsecs; statusPublisher.publish(that.statusMessage); }, 500); // publish every 500ms } SimpleActionServer.prototype.__proto__ = EventEmitter2.prototype; /** * Set action state to succeeded and return to client */ SimpleActionServer.prototype.setSucceeded = function(result2) { var resultMessage = new Message({ status : {goal_id : this.currentGoal.goal_id, status : 3}, result : result2 }); this.resultPublisher.publish(resultMessage); this.statusMessage.status_list = []; if(this.nextGoal) { this.currentGoal = this.nextGoal; this.nextGoal = null; this.emit('goal', this.currentGoal.goal); } else { this.currentGoal = null; } }; /** * Function to send feedback */ SimpleActionServer.prototype.sendFeedback = function(feedback2) { var feedbackMessage = new Message({ status : {goal_id : this.currentGoal.goal_id, status : 1}, feedback : feedback2 }); this.feedbackPublisher.publish(feedbackMessage); }; /** * Handle case where client requests preemption */ SimpleActionServer.prototype.setPreempted = function() { this.statusMessage.status_list = []; var resultMessage = new Message({ status : {goal_id : this.currentGoal.goal_id, status : 2}, }); this.resultPublisher.publish(resultMessage); if(this.nextGoal) { this.currentGoal = this.nextGoal; this.nextGoal = null; this.emit('goal', this.currentGoal.goal); } else { this.currentGoal = null; } }; module.exports = SimpleActionServer; },{"../core/Message":12,"../core/Topic":19,"eventemitter2":2}],11:[function(require,module,exports){ var Ros = require('../core/Ros'); var mixin = require('../mixin'); var action = module.exports = { ActionClient: require('./ActionClient'), ActionListener: require('./ActionListener'), Goal: require('./Goal'), SimpleActionServer: require('./SimpleActionServer') }; mixin(Ros, ['ActionClient', 'SimpleActionServer'], action); },{"../core/Ros":14,"../mixin":26,"./ActionClient":7,"./ActionListener":8,"./Goal":9,"./SimpleActionServer":10}],12:[function(require,module,exports){ /** * @fileoverview * @author Brandon Alexander - baalexander@gmail.com */ var assign = require('object-assign'); /** * Message objects are used for publishing and subscribing to and from topics. * * @constructor * @param values - object matching the fields defined in the .msg definition file */ function Message(values) { assign(this, values); } module.exports = Message; },{"object-assign":3}],13:[function(require,module,exports){ /** * @fileoverview * @author Brandon Alexander - baalexander@gmail.com */ var Service = require('./Service'); var ServiceRequest = require('./ServiceRequest'); /** * A ROS parameter. * * @constructor * @param options - possible keys include: * * ros - the ROSLIB.Ros connection handle * * name - the param name, like max_vel_x */ function Param(options) { options = options || {}; this.ros = options.ros; this.name = options.name; } /** * Fetches the value of the param. * * @param callback - function with the following params: * * value - the value of the param from ROS. */ Param.prototype.get = function(callback) { var paramClient = new Service({ ros : this.ros, name : '/rosapi/get_param', serviceType : 'rosapi/GetParam' }); var request = new ServiceRequest({ name : this.name }); paramClient.callService(request, function(result) { var value = JSON.parse(result.value); callback(value); }); }; /** * Sets the value of the param in ROS. * * @param value - value to set param to. */ Param.prototype.set = function(value, callback) { var paramClient = new Service({ ros : this.ros, name : '/rosapi/set_param', serviceType : 'rosapi/SetParam' }); var request = new ServiceRequest({ name : this.name, value : JSON.stringify(value) }); paramClient.callService(request, callback); }; /** * Delete this parameter on the ROS server. */ Param.prototype.delete = function(callback) { var paramClient = new Service({ ros : this.ros, name : '/rosapi/delete_param', serviceType : 'rosapi/DeleteParam' }); var request = new ServiceRequest({ name : this.name }); paramClient.callService(request, callback); }; module.exports = Param; },{"./Service":15,"./ServiceRequest":16}],14:[function(require,module,exports){ /** * @fileoverview * @author Brandon Alexander - baalexander@gmail.com */ var WebSocket = require('ws'); var socketAdapter = require('./SocketAdapter.js'); var Service = require('./Service'); var ServiceRequest = require('./ServiceRequest'); var assign = require('object-assign'); var EventEmitter2 = require('eventemitter2').EventEmitter2; /** * Manages connection to the server and all interactions with ROS. * * Emits the following events: * * 'error' - there was an error with ROS * * 'connection' - connected to the WebSocket server * * 'close' - disconnected to the WebSocket server * * - a message came from rosbridge with the given topic name * * - a service response came from rosbridge with the given ID * * @constructor * @param options - possible keys include:
* * url (optional) - (can be specified later with `connect`) the WebSocket URL for rosbridge or the node server url to connect using socket.io (if socket.io exists in the page)
* * groovyCompatibility - don't use interfaces that changed after the last groovy release or rosbridge_suite and related tools (defaults to true) * * transportLibrary (optional) - one of 'websocket' (default), 'socket.io' or RTCPeerConnection instance controlling how the connection is created in `connect`. * * transportOptions (optional) - the options to use use when creating a connection. Currently only used if `transportLibrary` is RTCPeerConnection. */ function Ros(options) { options = options || {}; this.socket = null; this.idCounter = 0; this.isConnected = false; this.transportLibrary = options.transportLibrary || 'websocket'; this.transportOptions = options.transportOptions || {}; if (typeof options.groovyCompatibility === 'undefined') { this.groovyCompatibility = true; } else { this.groovyCompatibility = options.groovyCompatibility; } // Sets unlimited event listeners. this.setMaxListeners(0); // begin by checking if a URL was given if (options.url) { this.connect(options.url); } } Ros.prototype.__proto__ = EventEmitter2.prototype; /** * Connect to the specified WebSocket. * * @param url - WebSocket URL or RTCDataChannel label for Rosbridge */ Ros.prototype.connect = function(url) { if (this.transportLibrary === 'socket.io') { this.socket = assign(io(url, {'force new connection': true}), socketAdapter(this)); this.socket.on('connect', this.socket.onopen); this.socket.on('data', this.socket.onmessage); this.socket.on('close', this.socket.onclose); this.socket.on('error', this.socket.onerror); } else if (this.transportLibrary.constructor.name === 'RTCPeerConnection') { this.socket = assign(this.transportLibrary.createDataChannel(url, this.transportOptions), socketAdapter(this)); } else { if (!this.socket || this.socket.readyState === WebSocket.CLOSED) { var sock = new WebSocket(url); sock.binaryType = 'arraybuffer'; this.socket = assign(sock, socketAdapter(this)); } } }; /** * Disconnect from the WebSocket server. */ Ros.prototype.close = function() { if (this.socket) { this.socket.close(); } }; /** * Sends an authorization request to the server. * * @param mac - MAC (hash) string given by the trusted source. * @param client - IP of the client. * @param dest - IP of the destination. * @param rand - Random string given by the trusted source. * @param t - Time of the authorization request. * @param level - User level as a string given by the client. * @param end - End time of the client's session. */ Ros.prototype.authenticate = function(mac, client, dest, rand, t, level, end) { // create the request var auth = { op : 'auth', mac : mac, client : client, dest : dest, rand : rand, t : t, level : level, end : end }; // send the request this.callOnConnection(auth); }; /** * Sends the message over the WebSocket, but queues the message up if not yet * connected. */ Ros.prototype.callOnConnection = function(message) { var that = this; var messageJson = JSON.stringify(message); var emitter = null; if (this.transportLibrary === 'socket.io') { emitter = function(msg){that.socket.emit('operation', msg);}; } else { emitter = function(msg){that.socket.send(msg);}; } if (!this.isConnected) { that.once('connection', function() { emitter(messageJson); }); } else { emitter(messageJson); } }; /** * Sends a set_level request to the server * * @param level - Status level (none, error, warning, info) * @param id - Optional: Operation ID to change status level on */ Ros.prototype.setStatusLevel = function(level, id){ var levelMsg = { op: 'set_level', level: level, id: id }; this.callOnConnection(levelMsg); }; /** * Retrieves Action Servers in ROS as an array of string * * * actionservers - Array of action server names */ Ros.prototype.getActionServers = function(callback, failedCallback) { var getActionServers = new Service({ ros : this, name : '/rosapi/action_servers', serviceType : 'rosapi/GetActionServers' }); var request = new ServiceRequest({}); if (typeof failedCallback === 'function'){ getActionServers.callService(request, function(result) { callback(result.action_servers); }, function(message){ failedCallback(message); } ); }else{ getActionServers.callService(request, function(result) { callback(result.action_servers); }); } }; /** * Retrieves list of topics in ROS as an array. * * @param callback function with params: * * topics - Array of topic names */ Ros.prototype.getTopics = function(callback, failedCallback) { var topicsClient = new Service({ ros : this, name : '/rosapi/topics', serviceType : 'rosapi/Topics' }); var request = new ServiceRequest(); if (typeof failedCallback === 'function'){ topicsClient.callService(request, function(result) { callback(result); }, function(message){ failedCallback(message); } ); }else{ topicsClient.callService(request, function(result) { callback(result); }); } }; /** * Retrieves Topics in ROS as an array as specific type * * @param topicType topic type to find: * @param callback function with params: * * topics - Array of topic names */ Ros.prototype.getTopicsForType = function(topicType, callback, failedCallback) { var topicsForTypeClient = new Service({ ros : this, name : '/rosapi/topics_for_type', serviceType : 'rosapi/TopicsForType' }); var request = new ServiceRequest({ type: topicType }); if (typeof failedCallback === 'function'){ topicsForTypeClient.callService(request, function(result) { callback(result.topics); }, function(message){ failedCallback(message); } ); }else{ topicsForTypeClient.callService(request, function(result) { callback(result.topics); }); } }; /** * Retrieves list of active service names in ROS. * * @param callback - function with the following params: * * services - array of service names */ Ros.prototype.getServices = function(callback, failedCallback) { var servicesClient = new Service({ ros : this, name : '/rosapi/services', serviceType : 'rosapi/Services' }); var request = new ServiceRequest(); if (typeof failedCallback === 'function'){ servicesClient.callService(request, function(result) { callback(result.services); }, function(message) { failedCallback(message); } ); }else{ servicesClient.callService(request, function(result) { callback(result.services); }); } }; /** * Retrieves list of services in ROS as an array as specific type * * @param serviceType service type to find: * @param callback function with params: * * topics - Array of service names */ Ros.prototype.getServicesForType = function(serviceType, callback, failedCallback) { var servicesForTypeClient = new Service({ ros : this, name : '/rosapi/services_for_type', serviceType : 'rosapi/ServicesForType' }); var request = new ServiceRequest({ type: serviceType }); if (typeof failedCallback === 'function'){ servicesForTypeClient.callService(request, function(result) { callback(result.services); }, function(message) { failedCallback(message); } ); }else{ servicesForTypeClient.callService(request, function(result) { callback(result.services); }); } }; /** * Retrieves a detail of ROS service request. * * @param service name of service: * @param callback - function with params: * * type - String of the service type */ Ros.prototype.getServiceRequestDetails = function(type, callback, failedCallback) { var serviceTypeClient = new Service({ ros : this, name : '/rosapi/service_request_details', serviceType : 'rosapi/ServiceRequestDetails' }); var request = new ServiceRequest({ type: type }); if (typeof failedCallback === 'function'){ serviceTypeClient.callService(request, function(result) { callback(result); }, function(message){ failedCallback(message); } ); }else{ serviceTypeClient.callService(request, function(result) { callback(result); }); } }; /** * Retrieves a detail of ROS service request. * * @param service name of service: * @param callback - function with params: * * type - String of the service type */ Ros.prototype.getServiceResponseDetails = function(type, callback, failedCallback) { var serviceTypeClient = new Service({ ros : this, name : '/rosapi/service_response_details', serviceType : 'rosapi/ServiceResponseDetails' }); var request = new ServiceRequest({ type: type }); if (typeof failedCallback === 'function'){ serviceTypeClient.callService(request, function(result) { callback(result); }, function(message){ failedCallback(message); } ); }else{ serviceTypeClient.callService(request, function(result) { callback(result); }); } }; /** * Retrieves list of active node names in ROS. * * @param callback - function with the following params: * * nodes - array of node names */ Ros.prototype.getNodes = function(callback, failedCallback) { var nodesClient = new Service({ ros : this, name : '/rosapi/nodes', serviceType : 'rosapi/Nodes' }); var request = new ServiceRequest(); if (typeof failedCallback === 'function'){ nodesClient.callService(request, function(result) { callback(result.nodes); }, function(message) { failedCallback(message); } ); }else{ nodesClient.callService(request, function(result) { callback(result.nodes); }); } }; /** * Retrieves list subscribed topics, publishing topics and services of a specific node * * @param node name of the node: * @param callback - function with params: * * publications - array of published topic names * * subscriptions - array of subscribed topic names * * services - array of service names hosted */ Ros.prototype.getNodeDetails = function(node, callback, failedCallback) { var nodesClient = new Service({ ros : this, name : '/rosapi/node_details', serviceType : 'rosapi/NodeDetails' }); var request = new ServiceRequest({ node: node }); if (typeof failedCallback === 'function'){ nodesClient.callService(request, function(result) { callback(result.subscribing, result.publishing, result.services); }, function(message) { failedCallback(message); } ); } else { nodesClient.callService(request, function(result) { callback(result); }); } }; /** * Retrieves list of param names from the ROS Parameter Server. * * @param callback function with params: * * params - array of param names. */ Ros.prototype.getParams = function(callback, failedCallback) { var paramsClient = new Service({ ros : this, name : '/rosapi/get_param_names', serviceType : 'rosapi/GetParamNames' }); var request = new ServiceRequest(); if (typeof failedCallback === 'function'){ paramsClient.callService(request, function(result) { callback(result.names); }, function(message){ failedCallback(message); } ); }else{ paramsClient.callService(request, function(result) { callback(result.names); }); } }; /** * Retrieves a type of ROS topic. * * @param topic name of the topic: * @param callback - function with params: * * type - String of the topic type */ Ros.prototype.getTopicType = function(topic, callback, failedCallback) { var topicTypeClient = new Service({ ros : this, name : '/rosapi/topic_type', serviceType : 'rosapi/TopicType' }); var request = new ServiceRequest({ topic: topic }); if (typeof failedCallback === 'function'){ topicTypeClient.callService(request, function(result) { callback(result.type); }, function(message){ failedCallback(message); } ); }else{ topicTypeClient.callService(request, function(result) { callback(result.type); }); } }; /** * Retrieves a type of ROS service. * * @param service name of service: * @param callback - function with params: * * type - String of the service type */ Ros.prototype.getServiceType = function(service, callback, failedCallback) { var serviceTypeClient = new Service({ ros : this, name : '/rosapi/service_type', serviceType : 'rosapi/ServiceType' }); var request = new ServiceRequest({ service: service }); if (typeof failedCallback === 'function'){ serviceTypeClient.callService(request, function(result) { callback(result.type); }, function(message){ failedCallback(message); } ); }else{ serviceTypeClient.callService(request, function(result) { callback(result.type); }); } }; /** * Retrieves a detail of ROS message. * * @param callback - function with params: * * details - Array of the message detail * @param message - String of a topic type */ Ros.prototype.getMessageDetails = function(message, callback, failedCallback) { var messageDetailClient = new Service({ ros : this, name : '/rosapi/message_details', serviceType : 'rosapi/MessageDetails' }); var request = new ServiceRequest({ type: message }); if (typeof failedCallback === 'function'){ messageDetailClient.callService(request, function(result) { callback(result.typedefs); }, function(message){ failedCallback(message); } ); }else{ messageDetailClient.callService(request, function(result) { callback(result.typedefs); }); } }; /** * Decode a typedefs into a dictionary like `rosmsg show foo/bar` * * @param defs - array of type_def dictionary */ Ros.prototype.decodeTypeDefs = function(defs) { var that = this; // calls itself recursively to resolve type definition using hints. var decodeTypeDefsRec = function(theType, hints) { var typeDefDict = {}; for (var i = 0; i < theType.fieldnames.length; i++) { var arrayLen = theType.fieldarraylen[i]; var fieldName = theType.fieldnames[i]; var fieldType = theType.fieldtypes[i]; if (fieldType.indexOf('/') === -1) { // check the fieldType includes '/' or not if (arrayLen === -1) { typeDefDict[fieldName] = fieldType; } else { typeDefDict[fieldName] = [fieldType]; } } else { // lookup the name var sub = false; for (var j = 0; j < hints.length; j++) { if (hints[j].type.toString() === fieldType.toString()) { sub = hints[j]; break; } } if (sub) { var subResult = decodeTypeDefsRec(sub, hints); if (arrayLen === -1) { } else { typeDefDict[fieldName] = [subResult]; } } else { that.emit('error', 'Cannot find ' + fieldType + ' in decodeTypeDefs'); } } } return typeDefDict; }; return decodeTypeDefsRec(defs[0], defs); }; module.exports = Ros; },{"./Service":15,"./ServiceRequest":16,"./SocketAdapter.js":18,"eventemitter2":2,"object-assign":3,"ws":42}],15:[function(require,module,exports){ /** * @fileoverview * @author Brandon Alexander - baalexander@gmail.com */ var ServiceResponse = require('./ServiceResponse'); var ServiceRequest = require('./ServiceRequest'); var EventEmitter2 = require('eventemitter2').EventEmitter2; /** * A ROS service client. * * @constructor * @params options - possible keys include: * * ros - the ROSLIB.Ros connection handle * * name - the service name, like /add_two_ints * * serviceType - the service type, like 'rospy_tutorials/AddTwoInts' */ function Service(options) { options = options || {}; this.ros = options.ros; this.name = options.name; this.serviceType = options.serviceType; this.isAdvertised = false; this._serviceCallback = null; } Service.prototype.__proto__ = EventEmitter2.prototype; /** * Calls the service. Returns the service response in the * callback. Does nothing if this service is currently advertised. * * @param request - the ROSLIB.ServiceRequest to send * @param callback - function with params: * * response - the response from the service request * @param failedCallback - the callback function when the service call failed (optional). Params: * * error - the error message reported by ROS */ Service.prototype.callService = function(request, callback, failedCallback) { if (this.isAdvertised) { return; } var serviceCallId = 'call_service:' + this.name + ':' + (++this.ros.idCounter); if (callback || failedCallback) { this.ros.once(serviceCallId, function(message) { if (message.result !== undefined && message.result === false) { if (typeof failedCallback === 'function') { failedCallback(message.values); } } else if (typeof callback === 'function') { callback(new ServiceResponse(message.values)); } }); } var call = { op : 'call_service', id : serviceCallId, service : this.name, type: this.serviceType, args : request }; this.ros.callOnConnection(call); }; /** * Advertise the service. This turns the Service object from a client * into a server. The callback will be called with every request * that's made on this service. * * @param callback - This works similarly to the callback for a C++ service and should take the following params: * * request - the service request * * response - an empty dictionary. Take care not to overwrite this. Instead, only modify the values within. * It should return true if the service has finished successfully, * i.e. without any fatal errors. */ Service.prototype.advertise = function(callback) { if (this.isAdvertised || typeof callback !== 'function') { return; } this._serviceCallback = callback; this.ros.on(this.name, this._serviceResponse.bind(this)); this.ros.callOnConnection({ op: 'advertise_service', type: this.serviceType, service: this.name }); this.isAdvertised = true; }; Service.prototype.unadvertise = function() { if (!this.isAdvertised) { return; } this.ros.callOnConnection({ op: 'unadvertise_service', service: this.name }); this.isAdvertised = false; }; Service.prototype._serviceResponse = function(rosbridgeRequest) { var response = {}; var success = this._serviceCallback(rosbridgeRequest.args, response); var call = { op: 'service_response', service: this.name, values: new ServiceResponse(response), result: success }; if (rosbridgeRequest.id) { call.id = rosbridgeRequest.id; } this.ros.callOnConnection(call); }; module.exports = Service; },{"./ServiceRequest":16,"./ServiceResponse":17,"eventemitter2":2}],16:[function(require,module,exports){ /** * @fileoverview * @author Brandon Alexander - balexander@willowgarage.com */ var assign = require('object-assign'); /** * A ServiceRequest is passed into the service call. * * @constructor * @param values - object matching the fields defined in the .srv definition file */ function ServiceRequest(values) { assign(this, values); } module.exports = ServiceRequest; },{"object-assign":3}],17:[function(require,module,exports){ /** * @fileoverview * @author Brandon Alexander - balexander@willowgarage.com */ var assign = require('object-assign'); /** * A ServiceResponse is returned from the service call. * * @constructor * @param values - object matching the fields defined in the .srv definition file */ function ServiceResponse(values) { assign(this, values); } module.exports = ServiceResponse; },{"object-assign":3}],18:[function(require,module,exports){ /** * Socket event handling utilities for handling events on either * WebSocket and TCP sockets * * Note to anyone reviewing this code: these functions are called * in the context of their parent object, unless bound * @fileOverview */ 'use strict'; var decompressPng = require('../util/decompressPng'); var CBOR = require('cbor-js'); var typedArrayTagger = require('../util/cborTypedArrayTags'); var WebSocket = require('ws'); var BSON = null; if(typeof bson !== 'undefined'){ BSON = bson().BSON; } /** * Events listeners for a WebSocket or TCP socket to a JavaScript * ROS Client. Sets up Messages for a given topic to trigger an * event on the ROS client. * * @namespace SocketAdapter * @private */ function SocketAdapter(client) { function handleMessage(message) { if (message.op === 'publish') { client.emit(message.topic, message.msg); } else if (message.op === 'service_response') { client.emit(message.id, message); } else if (message.op === 'call_service') { client.emit(message.service, message); } else if(message.op === 'status'){ if(message.id){ client.emit('status:'+message.id, message); } else { client.emit('status', message); } } } function handlePng(message, callback) { if (message.op === 'png') { decompressPng(message.data, callback); } else { callback(message); } } function decodeBSON(data, callback) { if (!BSON) { throw 'Cannot process BSON encoded message without BSON header.'; } var reader = new FileReader(); reader.onload = function() { var uint8Array = new Uint8Array(this.result); var msg = BSON.deserialize(uint8Array); callback(msg); }; reader.readAsArrayBuffer(data); } return { /** * Emits a 'connection' event on WebSocket connection. * * @param event - the argument to emit with the event. * @memberof SocketAdapter */ onopen: function onOpen(event) { client.isConnected = true; client.emit('connection', event); }, /** * Emits a 'close' event on WebSocket disconnection. * * @param event - the argument to emit with the event. * @memberof SocketAdapter */ onclose: function onClose(event) { client.isConnected = false; client.emit('close', event); }, /** * Emits an 'error' event whenever there was an error. * * @param event - the argument to emit with the event. * @memberof SocketAdapter */ onerror: function onError(event) { client.emit('error', event); }, /** * Parses message responses from rosbridge and sends to the appropriate * topic, service, or param. * * @param message - the raw JSON message from rosbridge. * @memberof SocketAdapter */ onmessage: function onMessage(data) { if (typeof Blob !== 'undefined' && data.data instanceof Blob) { decodeBSON(data.data, function (message) { handlePng(message, handleMessage); }); } else if (data.data instanceof ArrayBuffer) { var decoded = CBOR.decode(data.data, typedArrayTagger); handleMessage(decoded); } else { var message = JSON.parse(typeof data === 'string' ? data : data.data); handlePng(message, handleMessage); } } }; } module.exports = SocketAdapter; },{"../util/cborTypedArrayTags":41,"../util/decompressPng":44,"cbor-js":1,"ws":42}],19:[function(require,module,exports){ /** * @fileoverview * @author Brandon Alexander - baalexander@gmail.com */ var EventEmitter2 = require('eventemitter2').EventEmitter2; var Message = require('./Message'); /** * Publish and/or subscribe to a topic in ROS. * * Emits the following events: * * 'warning' - if there are any warning during the Topic creation * * 'message' - the message data from rosbridge * * @constructor * @param options - object with following keys: * * ros - the ROSLIB.Ros connection handle * * name - the topic name, like /cmd_vel * * messageType - the message type, like 'std_msgs/String' * * compression - the type of compression to use, like 'png' or 'cbor' * * throttle_rate - the rate (in ms in between messages) at which to throttle the topics * * queue_size - the queue created at bridge side for re-publishing webtopics (defaults to 100) * * latch - latch the topic when publishing * * queue_length - the queue length at bridge side used when subscribing (defaults to 0, no queueing). * * reconnect_on_close - the flag to enable resubscription and readvertisement on close event(defaults to true). */ function Topic(options) { options = options || {}; this.ros = options.ros; this.name = options.name; this.messageType = options.messageType; this.isAdvertised = false; this.compression = options.compression || 'none'; this.throttle_rate = options.throttle_rate || 0; this.latch = options.latch || false; this.queue_size = options.queue_size || 100; this.queue_length = options.queue_length || 0; this.reconnect_on_close = options.reconnect_on_close || true; // Check for valid compression types if (this.compression && this.compression !== 'png' && this.compression !== 'cbor' && this.compression !== 'none') { this.emit('warning', this.compression + ' compression is not supported. No compression will be used.'); this.compression = 'none'; } // Check if throttle rate is negative if (this.throttle_rate < 0) { this.emit('warning', this.throttle_rate + ' is not allowed. Set to 0'); this.throttle_rate = 0; } var that = this; if (this.reconnect_on_close) { this.callForSubscribeAndAdvertise = function(message) { that.ros.callOnConnection(message); that.waitForReconnect = false; that.reconnectFunc = function() { if(!that.waitForReconnect) { that.waitForReconnect = true; that.ros.callOnConnection(message); that.ros.once('connection', function() { that.waitForReconnect = false; }); } }; that.ros.on('close', that.reconnectFunc); }; } else { this.callForSubscribeAndAdvertise = this.ros.callOnConnection; } this._messageCallback = function(data) { that.emit('message', new Message(data)); }; } Topic.prototype.__proto__ = EventEmitter2.prototype; /** * Every time a message is published for the given topic, the callback * will be called with the message object. * * @param callback - function with the following params: * * message - the published message */ Topic.prototype.subscribe = function(callback) { if (typeof callback === 'function') { this.on('message', callback); } if (this.subscribeId) { return; } this.ros.on(this.name, this._messageCallback); this.subscribeId = 'subscribe:' + this.name + ':' + (++this.ros.idCounter); this.callForSubscribeAndAdvertise({ op: 'subscribe', id: this.subscribeId, type: this.messageType, topic: this.name, compression: this.compression, throttle_rate: this.throttle_rate, queue_length: this.queue_length }); }; /** * Unregisters as a subscriber for the topic. Unsubscribing stop remove * all subscribe callbacks. To remove a call back, you must explicitly * pass the callback function in. * * @param callback - the optional callback to unregister, if * * provided and other listeners are registered the topic won't * * unsubscribe, just stop emitting to the passed listener */ Topic.prototype.unsubscribe = function(callback) { if (callback) { this.off('message', callback); // If there is any other callbacks still subscribed don't unsubscribe if (this.listeners('message').length) { return; } } if (!this.subscribeId) { return; } // Note: Don't call this.removeAllListeners, allow client to handle that themselves this.ros.off(this.name, this._messageCallback); if(this.reconnect_on_close) { this.ros.off('close', this.reconnectFunc); } this.emit('unsubscribe'); this.ros.callOnConnection({ op: 'unsubscribe', id: this.subscribeId, topic: this.name }); this.subscribeId = null; }; /** * Registers as a publisher for the topic. */ Topic.prototype.advertise = function() { if (this.isAdvertised) { return; } this.advertiseId = 'advertise:' + this.name + ':' + (++this.ros.idCounter); this.callForSubscribeAndAdvertise({ op: 'advertise', id: this.advertiseId, type: this.messageType, topic: this.name, latch: this.latch, queue_size: this.queue_size }); this.isAdvertised = true; if(!this.reconnect_on_close) { var that = this; this.ros.on('close', function() { that.isAdvertised = false; }); } }; /** * Unregisters as a publisher for the topic. */ Topic.prototype.unadvertise = function() { if (!this.isAdvertised) { return; } if(this.reconnect_on_close) { this.ros.off('close', this.reconnectFunc); } this.emit('unadvertise'); this.ros.callOnConnection({ op: 'unadvertise', id: this.advertiseId, topic: this.name }); this.isAdvertised = false; }; /** * Publish the message. * * @param message - A ROSLIB.Message object. */ Topic.prototype.publish = function(message) { if (!this.isAdvertised) { this.advertise(); } this.ros.idCounter++; var call = { op: 'publish', id: 'publish:' + this.name + ':' + this.ros.idCounter, topic: this.name, msg: message, latch: this.latch }; this.ros.callOnConnection(call); }; module.exports = Topic; },{"./Message":12,"eventemitter2":2}],20:[function(require,module,exports){ var mixin = require('../mixin'); var core = module.exports = { Ros: require('./Ros'), Topic: require('./Topic'), Message: require('./Message'), Param: require('./Param'), Service: require('./Service'), ServiceRequest: require('./ServiceRequest'), ServiceResponse: require('./ServiceResponse') }; mixin(core.Ros, ['Param', 'Service', 'Topic'], core); },{"../mixin":26,"./Message":12,"./Param":13,"./Ros":14,"./Service":15,"./ServiceRequest":16,"./ServiceResponse":17,"./Topic":19}],21:[function(require,module,exports){ /** * @fileoverview * @author David Gossow - dgossow@willowgarage.com */ var Vector3 = require('./Vector3'); var Quaternion = require('./Quaternion'); /** * A Pose in 3D space. Values are copied into this object. * * @constructor * @param options - object with following keys: * * position - the Vector3 describing the position * * orientation - the ROSLIB.Quaternion describing the orientation */ function Pose(options) { options = options || {}; // copy the values into this object if they exist this.position = new Vector3(options.position); this.orientation = new Quaternion(options.orientation); } /** * Apply a transform against this pose. * * @param tf the transform */ Pose.prototype.applyTransform = function(tf) { this.position.multiplyQuaternion(tf.rotation); this.position.add(tf.translation); var tmp = tf.rotation.clone(); tmp.multiply(this.orientation); this.orientation = tmp; }; /** * Clone a copy of this pose. * * @returns the cloned pose */ Pose.prototype.clone = function() { return new Pose(this); }; /** * Multiplies this pose with another pose without altering this pose. * * @returns Result of multiplication. */ Pose.prototype.multiply = function(pose) { var p = pose.clone(); p.applyTransform({ rotation: this.orientation, translation: this.position }); return p; }; /** * Computes the inverse of this pose. * * @returns Inverse of pose. */ Pose.prototype.getInverse = function() { var inverse = this.clone(); inverse.orientation.invert(); inverse.position.multiplyQuaternion(inverse.orientation); inverse.position.x *= -1; inverse.position.y *= -1; inverse.position.z *= -1; return inverse; }; module.exports = Pose; },{"./Quaternion":22,"./Vector3":24}],22:[function(require,module,exports){ /** * @fileoverview * @author David Gossow - dgossow@willowgarage.com */ /** * A Quaternion. * * @constructor * @param options - object with following keys: * * x - the x value * * y - the y value * * z - the z value * * w - the w value */ function Quaternion(options) { options = options || {}; this.x = options.x || 0; this.y = options.y || 0; this.z = options.z || 0; this.w = (typeof options.w === 'number') ? options.w : 1; } /** * Perform a conjugation on this quaternion. */ Quaternion.prototype.conjugate = function() { this.x *= -1; this.y *= -1; this.z *= -1; }; /** * Return the norm of this quaternion. */ Quaternion.prototype.norm = function() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); }; /** * Perform a normalization on this quaternion. */ Quaternion.prototype.normalize = function() { var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); if (l === 0) { this.x = 0; this.y = 0; this.z = 0; this.w = 1; } else { l = 1 / l; this.x = this.x * l; this.y = this.y * l; this.z = this.z * l; this.w = this.w * l; } }; /** * Convert this quaternion into its inverse. */ Quaternion.prototype.invert = function() { this.conjugate(); this.normalize(); }; /** * Set the values of this quaternion to the product of itself and the given quaternion. * * @param q the quaternion to multiply with */ Quaternion.prototype.multiply = function(q) { var newX = this.x * q.w + this.y * q.z - this.z * q.y + this.w * q.x; var newY = -this.x * q.z + this.y * q.w + this.z * q.x + this.w * q.y; var newZ = this.x * q.y - this.y * q.x + this.z * q.w + this.w * q.z; var newW = -this.x * q.x - this.y * q.y - this.z * q.z + this.w * q.w; this.x = newX; this.y = newY; this.z = newZ; this.w = newW; }; /** * Clone a copy of this quaternion. * * @returns the cloned quaternion */ Quaternion.prototype.clone = function() { return new Quaternion(this); }; module.exports = Quaternion; },{}],23:[function(require,module,exports){ /** * @fileoverview * @author David Gossow - dgossow@willowgarage.com */ var Vector3 = require('./Vector3'); var Quaternion = require('./Quaternion'); /** * A Transform in 3-space. Values are copied into this object. * * @constructor * @param options - object with following keys: * * translation - the Vector3 describing the translation * * rotation - the ROSLIB.Quaternion describing the rotation */ function Transform(options) { options = options || {}; // Copy the values into this object if they exist this.translation = new Vector3(options.translation); this.rotation = new Quaternion(options.rotation); } /** * Clone a copy of this transform. * * @returns the cloned transform */ Transform.prototype.clone = function() { return new Transform(this); }; module.exports = Transform; },{"./Quaternion":22,"./Vector3":24}],24:[function(require,module,exports){ /** * @fileoverview * @author David Gossow - dgossow@willowgarage.com */ /** * A 3D vector. * * @constructor * @param options - object with following keys: * * x - the x value * * y - the y value * * z - the z value */ function Vector3(options) { options = options || {}; this.x = options.x || 0; this.y = options.y || 0; this.z = options.z || 0; } /** * Set the values of this vector to the sum of itself and the given vector. * * @param v the vector to add with */ Vector3.prototype.add = function(v) { this.x += v.x; this.y += v.y; this.z += v.z; }; /** * Set the values of this vector to the difference of itself and the given vector. * * @param v the vector to subtract with */ Vector3.prototype.subtract = function(v) { this.x -= v.x; this.y -= v.y; this.z -= v.z; }; /** * Multiply the given Quaternion with this vector. * * @param q - the quaternion to multiply with */ Vector3.prototype.multiplyQuaternion = function(q) { var ix = q.w * this.x + q.y * this.z - q.z * this.y; var iy = q.w * this.y + q.z * this.x - q.x * this.z; var iz = q.w * this.z + q.x * this.y - q.y * this.x; var iw = -q.x * this.x - q.y * this.y - q.z * this.z; this.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y; this.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z; this.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x; }; /** * Clone a copy of this vector. * * @returns the cloned vector */ Vector3.prototype.clone = function() { return new Vector3(this); }; module.exports = Vector3; },{}],25:[function(require,module,exports){ module.exports = { Pose: require('./Pose'), Quaternion: require('./Quaternion'), Transform: require('./Transform'), Vector3: require('./Vector3') }; },{"./Pose":21,"./Quaternion":22,"./Transform":23,"./Vector3":24}],26:[function(require,module,exports){ /** * Mixin a feature to the core/Ros prototype. * For example, mixin(Ros, ['Topic'], {Topic: }) * will add a topic bound to any Ros instances so a user * can call `var topic = ros.Topic({name: '/foo'});` * * @author Graeme Yeates - github.com/megawac */ module.exports = function(Ros, classes, features) { classes.forEach(function(className) { var Class = features[className]; Ros.prototype[className] = function(options) { options.ros = this; return new Class(options); }; }); }; },{}],27:[function(require,module,exports){ /** * @fileoverview * @author David Gossow - dgossow@willowgarage.com */ var ActionClient = require('../actionlib/ActionClient'); var Goal = require('../actionlib/Goal'); var Service = require('../core/Service.js'); var ServiceRequest = require('../core/ServiceRequest.js'); var Transform = require('../math/Transform'); /** * A TF Client that listens to TFs from tf2_web_republisher. * * @constructor * @param options - object with following keys: * * ros - the ROSLIB.Ros connection handle * * fixedFrame - the fixed frame, like /base_link * * angularThres - the angular threshold for the TF republisher * * transThres - the translation threshold for the TF republisher * * rate - the rate for the TF republisher * * updateDelay - the time (in ms) to wait after a new subscription * to update the TF republisher's list of TFs * * topicTimeout - the timeout parameter for the TF republisher * * serverName (optional) - the name of the tf2_web_republisher server * * repubServiceName (optional) - the name of the republish_tfs service (non groovy compatibility mode only) * default: '/republish_tfs' */ function TFClient(options) { options = options || {}; this.ros = options.ros; this.fixedFrame = options.fixedFrame || '/base_link'; this.angularThres = options.angularThres || 2.0; this.transThres = options.transThres || 0.01; this.rate = options.rate || 10.0; this.updateDelay = options.updateDelay || 50; var seconds = options.topicTimeout || 2.0; var secs = Math.floor(seconds); var nsecs = Math.floor((seconds - secs) * 1000000000); this.topicTimeout = { secs: secs, nsecs: nsecs }; this.serverName = options.serverName || '/tf2_web_republisher'; this.repubServiceName = options.repubServiceName || '/republish_tfs'; this.currentGoal = false; this.currentTopic = false; this.frameInfos = {}; this.republisherUpdateRequested = false; // Create an Action client this.actionClient = this.ros.ActionClient({ serverName : this.serverName, actionName : 'tf2_web_republisher/TFSubscriptionAction', omitStatus : true, omitResult : true }); // Create a Service client this.serviceClient = this.ros.Service({ name: this.repubServiceName, serviceType: 'tf2_web_republisher/RepublishTFs' }); } /** * Process the incoming TF message and send them out using the callback * functions. * * @param tf - the TF message from the server */ TFClient.prototype.processTFArray = function(tf) { var that = this; tf.transforms.forEach(function(transform) { var frameID = transform.child_frame_id; if (frameID[0] === '/') { frameID = frameID.substring(1); } var info = this.frameInfos[frameID]; if (info) { info.transform = new Transform({ translation : transform.transform.translation, rotation : transform.transform.rotation }); info.cbs.forEach(function(cb) { cb(info.transform); }); } }, this); }; /** * Create and send a new goal (or service request) to the tf2_web_republisher * based on the current list of TFs. */ TFClient.prototype.updateGoal = function() { var goalMessage = { source_frames : Object.keys(this.frameInfos), target_frame : this.fixedFrame, angular_thres : this.angularThres, trans_thres : this.transThres, rate : this.rate }; // if we're running in groovy compatibility mode (the default) // then use the action interface to tf2_web_republisher if(this.ros.groovyCompatibility) { if (this.currentGoal) { this.currentGoal.cancel(); } this.currentGoal = new Goal({ actionClient : this.actionClient, goalMessage : goalMessage }); this.currentGoal.on('feedback', this.processTFArray.bind(this)); this.currentGoal.send(); } else { // otherwise, use the service interface // The service interface has the same parameters as the action, // plus the timeout goalMessage.timeout = this.topicTimeout; var request = new ServiceRequest(goalMessage); this.serviceClient.callService(request, this.processResponse.bind(this)); } this.republisherUpdateRequested = false; }; /** * Process the service response and subscribe to the tf republisher * topic * * @param response the service response containing the topic name */ TFClient.prototype.processResponse = function(response) { // if we subscribed to a topic before, unsubscribe so // the republisher stops publishing it if (this.currentTopic) { this.currentTopic.unsubscribe(); } this.currentTopic = this.ros.Topic({ name: response.topic_name, messageType: 'tf2_web_republisher/TFArray' }); this.currentTopic.subscribe(this.processTFArray.bind(this)); }; /** * Subscribe to the given TF frame. * * @param frameID - the TF frame to subscribe to * @param callback - function with params: * * transform - the transform data */ TFClient.prototype.subscribe = function(frameID, callback) { // remove leading slash, if it's there if (frameID[0] === '/') { frameID = frameID.substring(1); } // if there is no callback registered for the given frame, create emtpy callback list if (!this.frameInfos[frameID]) { this.frameInfos[frameID] = { cbs: [] }; if (!this.republisherUpdateRequested) { setTimeout(this.updateGoal.bind(this), this.updateDelay); this.republisherUpdateRequested = true; } } // if we already have a transform, call back immediately else if (this.frameInfos[frameID].transform) { callback(this.frameInfos[frameID].transform); } this.frameInfos[frameID].cbs.push(callback); }; /** * Unsubscribe from the given TF frame. * * @param frameID - the TF frame to unsubscribe from * @param callback - the callback function to remove */ TFClient.prototype.unsubscribe = function(frameID, callback) { // remove leading slash, if it's there if (frameID[0] === '/') { frameID = frameID.substring(1); } var info = this.frameInfos[frameID]; for (var cbs = info && info.cbs || [], idx = cbs.length; idx--;) { if (cbs[idx] === callback) { cbs.splice(idx, 1); } } if (!callback || cbs.length === 0) { delete this.frameInfos[frameID]; } }; /** * Unsubscribe and unadvertise all topics associated with this TFClient. */ TFClient.prototype.dispose = function() { this.actionClient.dispose(); if (this.currentTopic) { this.currentTopic.unsubscribe(); } }; module.exports = TFClient; },{"../actionlib/ActionClient":7,"../actionlib/Goal":9,"../core/Service.js":15,"../core/ServiceRequest.js":16,"../math/Transform":23}],28:[function(require,module,exports){ var Ros = require('../core/Ros'); var mixin = require('../mixin'); var tf = module.exports = { TFClient: require('./TFClient') }; mixin(Ros, ['TFClient'], tf); },{"../core/Ros":14,"../mixin":26,"./TFClient":27}],29:[function(require,module,exports){ /** * @fileOverview * @author Benjamin Pitzer - ben.pitzer@gmail.com * @author Russell Toris - rctoris@wpi.edu */ var Vector3 = require('../math/Vector3'); var UrdfTypes = require('./UrdfTypes'); /** * A Box element in a URDF. * * @constructor * @param options - object with following keys: * * xml - the XML element to parse */ function UrdfBox(options) { this.dimension = null; this.type = UrdfTypes.URDF_BOX; // Parse the xml string var xyz = options.xml.getAttribute('size').split(' '); this.dimension = new Vector3({ x : parseFloat(xyz[0]), y : parseFloat(xyz[1]), z : parseFloat(xyz[2]) }); } module.exports = UrdfBox; },{"../math/Vector3":24,"./UrdfTypes":38}],30:[function(require,module,exports){ /** * @fileOverview * @author Benjamin Pitzer - ben.pitzer@gmail.com * @author Russell Toris - rctoris@wpi.edu */ /** * A Color element in a URDF. * * @constructor * @param options - object with following keys: * * xml - the XML element to parse */ function UrdfColor(options) { // Parse the xml string var rgba = options.xml.getAttribute('rgba').split(' '); this.r = parseFloat(rgba[0]); this.g = parseFloat(rgba[1]); this.b = parseFloat(rgba[2]); this.a = parseFloat(rgba[3]); } module.exports = UrdfColor; },{}],31:[function(require,module,exports){ /** * @fileOverview * @author Benjamin Pitzer - ben.pitzer@gmail.com * @author Russell Toris - rctoris@wpi.edu */ var UrdfTypes = require('./UrdfTypes'); /** * A Cylinder element in a URDF. * * @constructor * @param options - object with following keys: * * xml - the XML element to parse */ function UrdfCylinder(options) { this.type = UrdfTypes.URDF_CYLINDER; this.length = parseFloat(options.xml.getAttribute('length')); this.radius = parseFloat(options.xml.getAttribute('radius')); } module.exports = UrdfCylinder; },{"./UrdfTypes":38}],32:[function(require,module,exports){ /** * @fileOverview * @author David V. Lu!! davidvlu@gmail.com */ var Pose = require('../math/Pose'); var Vector3 = require('../math/Vector3'); var Quaternion = require('../math/Quaternion'); /** * A Joint element in a URDF. * * @constructor * @param options - object with following keys: * * xml - the XML element to parse */ function UrdfJoint(options) { this.name = options.xml.getAttribute('name'); this.type = options.xml.getAttribute('type'); var parents = options.xml.getElementsByTagName('parent'); if(parents.length > 0) { this.parent = parents[0].getAttribute('link'); } var children = options.xml.getElementsByTagName('child'); if(children.length > 0) { this.child = children[0].getAttribute('link'); } var limits = options.xml.getElementsByTagName('limit'); if (limits.length > 0) { this.minval = parseFloat( limits[0].getAttribute('lower') ); this.maxval = parseFloat( limits[0].getAttribute('upper') ); } // Origin var origins = options.xml.getElementsByTagName('origin'); if (origins.length === 0) { // use the identity as the default this.origin = new Pose(); } else { // Check the XYZ var xyz = origins[0].getAttribute('xyz'); var position = new Vector3(); if (xyz) { xyz = xyz.split(' '); position = new Vector3({ x : parseFloat(xyz[0]), y : parseFloat(xyz[1]), z : parseFloat(xyz[2]) }); } // Check the RPY var rpy = origins[0].getAttribute('rpy'); var orientation = new Quaternion(); if (rpy) { rpy = rpy.split(' '); // Convert from RPY var roll = parseFloat(rpy[0]); var pitch = parseFloat(rpy[1]); var yaw = parseFloat(rpy[2]); var phi = roll / 2.0; var the = pitch / 2.0; var psi = yaw / 2.0; var x = Math.sin(phi) * Math.cos(the) * Math.cos(psi) - Math.cos(phi) * Math.sin(the) * Math.sin(psi); var y = Math.cos(phi) * Math.sin(the) * Math.cos(psi) + Math.sin(phi) * Math.cos(the) * Math.sin(psi); var z = Math.cos(phi) * Math.cos(the) * Math.sin(psi) - Math.sin(phi) * Math.sin(the) * Math.cos(psi); var w = Math.cos(phi) * Math.cos(the) * Math.cos(psi) + Math.sin(phi) * Math.sin(the) * Math.sin(psi); orientation = new Quaternion({ x : x, y : y, z : z, w : w }); orientation.normalize(); } this.origin = new Pose({ position : position, orientation : orientation }); } } module.exports = UrdfJoint; },{"../math/Pose":21,"../math/Quaternion":22,"../math/Vector3":24}],33:[function(require,module,exports){ /** * @fileOverview * @author Benjamin Pitzer - ben.pitzer@gmail.com * @author Russell Toris - rctoris@wpi.edu */ var UrdfVisual = require('./UrdfVisual'); /** * A Link element in a URDF. * * @constructor * @param options - object with following keys: * * xml - the XML element to parse */ function UrdfLink(options) { this.name = options.xml.getAttribute('name'); this.visuals = []; var visuals = options.xml.getElementsByTagName('visual'); for( var i=0; i 0) { this.textureFilename = textures[0].getAttribute('filename'); } // Color var colors = options.xml.getElementsByTagName('color'); if (colors.length > 0) { // Parse the RBGA string this.color = new UrdfColor({ xml : colors[0] }); } } UrdfMaterial.prototype.isLink = function() { return this.color === null && this.textureFilename === null; }; var assign = require('object-assign'); UrdfMaterial.prototype.assign = function(obj) { return assign(this, obj); }; module.exports = UrdfMaterial; },{"./UrdfColor":30,"object-assign":3}],35:[function(require,module,exports){ /** * @fileOverview * @author Benjamin Pitzer - ben.pitzer@gmail.com * @author Russell Toris - rctoris@wpi.edu */ var Vector3 = require('../math/Vector3'); var UrdfTypes = require('./UrdfTypes'); /** * A Mesh element in a URDF. * * @constructor * @param options - object with following keys: * * xml - the XML element to parse */ function UrdfMesh(options) { this.scale = null; this.type = UrdfTypes.URDF_MESH; this.filename = options.xml.getAttribute('filename'); // Check for a scale var scale = options.xml.getAttribute('scale'); if (scale) { // Get the XYZ var xyz = scale.split(' '); this.scale = new Vector3({ x : parseFloat(xyz[0]), y : parseFloat(xyz[1]), z : parseFloat(xyz[2]) }); } } module.exports = UrdfMesh; },{"../math/Vector3":24,"./UrdfTypes":38}],36:[function(require,module,exports){ /** * @fileOverview * @author Benjamin Pitzer - ben.pitzer@gmail.com * @author Russell Toris - rctoris@wpi.edu */ var UrdfMaterial = require('./UrdfMaterial'); var UrdfLink = require('./UrdfLink'); var UrdfJoint = require('./UrdfJoint'); var DOMParser = require('xmldom').DOMParser; // See https://developer.mozilla.org/docs/XPathResult#Constants var XPATH_FIRST_ORDERED_NODE_TYPE = 9; /** * A URDF Model can be used to parse a given URDF into the appropriate elements. * * @constructor * @param options - object with following keys: * * xml - the XML element to parse * * string - the XML element to parse as a string */ function UrdfModel(options) { options = options || {}; var xmlDoc = options.xml; var string = options.string; this.materials = {}; this.links = {}; this.joints = {}; // Check if we are using a string or an XML element if (string) { // Parse the string var parser = new DOMParser(); xmlDoc = parser.parseFromString(string, 'text/xml'); } // Initialize the model with the given XML node. // Get the robot tag var robotXml = xmlDoc.documentElement; // Get the robot name this.name = robotXml.getAttribute('name'); // Parse all the visual elements we need for (var nodes = robotXml.childNodes, i = 0; i < nodes.length; i++) { var node = nodes[i]; if (node.tagName === 'material') { var material = new UrdfMaterial({ xml : node }); // Make sure this is unique if (this.materials[material.name] !== void 0) { if( this.materials[material.name].isLink() ) { this.materials[material.name].assign( material ); } else { console.warn('Material ' + material.name + 'is not unique.'); } } else { this.materials[material.name] = material; } } else if (node.tagName === 'link') { var link = new UrdfLink({ xml : node }); // Make sure this is unique if (this.links[link.name] !== void 0) { console.warn('Link ' + link.name + ' is not unique.'); } else { // Check for a material for( var j=0; j 0) { var geom = geoms[0]; var shape = null; // Check for the shape for (var i = 0; i < geom.childNodes.length; i++) { var node = geom.childNodes[i]; if (node.nodeType === 1) { shape = node; break; } } // Check the type var type = shape.nodeName; if (type === 'sphere') { this.geometry = new UrdfSphere({ xml : shape }); } else if (type === 'box') { this.geometry = new UrdfBox({ xml : shape }); } else if (type === 'cylinder') { this.geometry = new UrdfCylinder({ xml : shape }); } else if (type === 'mesh') { this.geometry = new UrdfMesh({ xml : shape }); } else { console.warn('Unknown geometry type ' + type); } } // Material var materials = xml.getElementsByTagName('material'); if (materials.length > 0) { this.material = new UrdfMaterial({ xml : materials[0] }); } } module.exports = UrdfVisual; },{"../math/Pose":21,"../math/Quaternion":22,"../math/Vector3":24,"./UrdfBox":29,"./UrdfCylinder":31,"./UrdfMaterial":34,"./UrdfMesh":35,"./UrdfSphere":37}],40:[function(require,module,exports){ module.exports = require('object-assign')({ UrdfBox: require('./UrdfBox'), UrdfColor: require('./UrdfColor'), UrdfCylinder: require('./UrdfCylinder'), UrdfLink: require('./UrdfLink'), UrdfMaterial: require('./UrdfMaterial'), UrdfMesh: require('./UrdfMesh'), UrdfModel: require('./UrdfModel'), UrdfSphere: require('./UrdfSphere'), UrdfVisual: require('./UrdfVisual') }, require('./UrdfTypes')); },{"./UrdfBox":29,"./UrdfColor":30,"./UrdfCylinder":31,"./UrdfLink":33,"./UrdfMaterial":34,"./UrdfMesh":35,"./UrdfModel":36,"./UrdfSphere":37,"./UrdfTypes":38,"./UrdfVisual":39,"object-assign":3}],41:[function(require,module,exports){ 'use strict'; var UPPER32 = Math.pow(2, 32); var warnedPrecision = false; function warnPrecision() { if (!warnedPrecision) { warnedPrecision = true; console.warn('CBOR 64-bit integer array values may lose precision. No further warnings.'); } } /** * Unpacks 64-bit unsigned integer from byte array. * @param {Uint8Array} bytes */ function decodeUint64LE(bytes) { warnPrecision(); var byteLen = bytes.byteLength; var offset = bytes.byteOffset; var arrLen = byteLen / 8; var buffer = bytes.buffer.slice(offset, offset + byteLen); var uint32View = new Uint32Array(buffer); var arr = new Array(arrLen); for (var i = 0; i < arrLen; i++) { var si = i * 2; var lo = uint32View[si]; var hi = uint32View[si+1]; arr[i] = lo + UPPER32 * hi; } return arr; } /** * Unpacks 64-bit signed integer from byte array. * @param {Uint8Array} bytes */ function decodeInt64LE(bytes) { warnPrecision(); var byteLen = bytes.byteLength; var offset = bytes.byteOffset; var arrLen = byteLen / 8; var buffer = bytes.buffer.slice(offset, offset + byteLen); var uint32View = new Uint32Array(buffer); var int32View = new Int32Array(buffer); var arr = new Array(arrLen); for (var i = 0; i < arrLen; i++) { var si = i * 2; var lo = uint32View[si]; var hi = int32View[si+1]; arr[i] = lo + UPPER32 * hi; } return arr; } /** * Unpacks typed array from byte array. * @param {Uint8Array} bytes * @param {type} ArrayType - desired output array type */ function decodeNativeArray(bytes, ArrayType) { var byteLen = bytes.byteLength; var offset = bytes.byteOffset; var buffer = bytes.buffer.slice(offset, offset + byteLen); return new ArrayType(buffer); } /** * Support a subset of draft CBOR typed array tags: * * Only support little-endian tags for now. */ var nativeArrayTypes = { 64: Uint8Array, 69: Uint16Array, 70: Uint32Array, 72: Int8Array, 77: Int16Array, 78: Int32Array, 85: Float32Array, 86: Float64Array }; /** * We can also decode 64-bit integer arrays, since ROS has these types. */ var conversionArrayTypes = { 71: decodeUint64LE, 79: decodeInt64LE }; /** * Handles CBOR typed array tags during decoding. * @param {Uint8Array} data * @param {Number} tag */ function cborTypedArrayTagger(data, tag) { if (tag in nativeArrayTypes) { var arrayType = nativeArrayTypes[tag]; return decodeNativeArray(data, arrayType); } if (tag in conversionArrayTypes) { return conversionArrayTypes[tag](data); } return data; } if (typeof module !== 'undefined' && module.exports) { module.exports = cborTypedArrayTagger; } },{}],42:[function(require,module,exports){ module.exports = window.WebSocket; },{}],43:[function(require,module,exports){ /* global document */ module.exports = function Canvas() { return document.createElement('canvas'); }; },{}],44:[function(require,module,exports){ /** * @fileOverview * @author Graeme Yeates - github.com/megawac */ 'use strict'; var Canvas = require('canvas'); var Image = Canvas.Image || window.Image; /** * If a message was compressed as a PNG image (a compression hack since * gzipping over WebSockets * is not supported yet), this function places the * "image" in a canvas element then decodes the * "image" as a Base64 string. * * @private * @param data - object containing the PNG data. * @param callback - function with params: * * data - the uncompressed data */ function decompressPng(data, callback) { // Uncompresses the data before sending it through (use image/canvas to do so). var image = new Image(); // When the image loads, extracts the raw data (JSON message). image.onload = function() { // Creates a local canvas to draw on. var canvas = new Canvas(); var context = canvas.getContext('2d'); // Sets width and height. canvas.width = image.width; canvas.height = image.height; // Prevents anti-aliasing and loosing data context.imageSmoothingEnabled = false; context.webkitImageSmoothingEnabled = false; context.mozImageSmoothingEnabled = false; // Puts the data into the image. context.drawImage(image, 0, 0); // Grabs the raw, uncompressed data. var imageData = context.getImageData(0, 0, image.width, image.height).data; // Constructs the JSON. var jsonData = ''; for (var i = 0; i < imageData.length; i += 4) { // RGB jsonData += String.fromCharCode(imageData[i], imageData[i + 1], imageData[i + 2]); } callback(JSON.parse(jsonData)); }; // Sends the image data to load. image.src = 'data:image/png;base64,' + data; } module.exports = decompressPng; },{"canvas":43}],45:[function(require,module,exports){ exports.DOMImplementation = window.DOMImplementation; exports.XMLSerializer = window.XMLSerializer; exports.DOMParser = window.DOMParser; },{}]},{},[6]);