]> defiant.homedns.org Git - ros_wild_thumper.git/blob - www/assets/javascripts/roslib.js
Merge branch 'master' of ssh://defiant.homedns.org/home/erik_alt/git/ros_wild_thumper
[ros_wild_thumper.git] / www / assets / javascripts / roslib.js
1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2 /*!\r
3  * EventEmitter2\r
4  * https://github.com/hij1nx/EventEmitter2\r
5  *\r
6  * Copyright (c) 2013 hij1nx\r
7  * Licensed under the MIT license.\r
8  */\r
9 ;!function(undefined) {\r
10 \r
11   var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {\r
12     return Object.prototype.toString.call(obj) === "[object Array]";\r
13   };\r
14   var defaultMaxListeners = 10;\r
15 \r
16   function init() {\r
17     this._events = {};\r
18     if (this._conf) {\r
19       configure.call(this, this._conf);\r
20     }\r
21   }\r
22 \r
23   function configure(conf) {\r
24     if (conf) {\r
25       this._conf = conf;\r
26 \r
27       conf.delimiter && (this.delimiter = conf.delimiter);\r
28       this._events.maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners;\r
29       conf.wildcard && (this.wildcard = conf.wildcard);\r
30       conf.newListener && (this.newListener = conf.newListener);\r
31       conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak);\r
32 \r
33       if (this.wildcard) {\r
34         this.listenerTree = {};\r
35       }\r
36     } else {\r
37       this._events.maxListeners = defaultMaxListeners;\r
38     }\r
39   }\r
40 \r
41   function logPossibleMemoryLeak(count, eventName) {\r
42     var errorMsg = '(node) warning: possible EventEmitter memory ' +\r
43         'leak detected. %d listeners added. ' +\r
44         'Use emitter.setMaxListeners() to increase limit.';\r
45 \r
46     if(this.verboseMemoryLeak){\r
47       errorMsg += ' Event name: %s.';\r
48       console.error(errorMsg, count, eventName);\r
49     } else {\r
50       console.error(errorMsg, count);\r
51     }\r
52 \r
53     if (console.trace){\r
54       console.trace();\r
55     }\r
56   }\r
57 \r
58   function EventEmitter(conf) {\r
59     this._events = {};\r
60     this.newListener = false;\r
61     this.verboseMemoryLeak = false;\r
62     configure.call(this, conf);\r
63   }\r
64   EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property\r
65 \r
66   //\r
67   // Attention, function return type now is array, always !\r
68   // It has zero elements if no any matches found and one or more\r
69   // elements (leafs) if there are matches\r
70   //\r
71   function searchListenerTree(handlers, type, tree, i) {\r
72     if (!tree) {\r
73       return [];\r
74     }\r
75     var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached,\r
76         typeLength = type.length, currentType = type[i], nextType = type[i+1];\r
77     if (i === typeLength && tree._listeners) {\r
78       //\r
79       // If at the end of the event(s) list and the tree has listeners\r
80       // invoke those listeners.\r
81       //\r
82       if (typeof tree._listeners === 'function') {\r
83         handlers && handlers.push(tree._listeners);\r
84         return [tree];\r
85       } else {\r
86         for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) {\r
87           handlers && handlers.push(tree._listeners[leaf]);\r
88         }\r
89         return [tree];\r
90       }\r
91     }\r
92 \r
93     if ((currentType === '*' || currentType === '**') || tree[currentType]) {\r
94       //\r
95       // If the event emitted is '*' at this part\r
96       // or there is a concrete match at this patch\r
97       //\r
98       if (currentType === '*') {\r
99         for (branch in tree) {\r
100           if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {\r
101             listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1));\r
102           }\r
103         }\r
104         return listeners;\r
105       } else if(currentType === '**') {\r
106         endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*'));\r
107         if(endReached && tree._listeners) {\r
108           // The next element has a _listeners, add it to the handlers.\r
109           listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength));\r
110         }\r
111 \r
112         for (branch in tree) {\r
113           if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {\r
114             if(branch === '*' || branch === '**') {\r
115               if(tree[branch]._listeners && !endReached) {\r
116                 listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength));\r
117               }\r
118               listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));\r
119             } else if(branch === nextType) {\r
120               listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2));\r
121             } else {\r
122               // No match on this one, shift into the tree but not in the type array.\r
123               listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));\r
124             }\r
125           }\r
126         }\r
127         return listeners;\r
128       }\r
129 \r
130       listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1));\r
131     }\r
132 \r
133     xTree = tree['*'];\r
134     if (xTree) {\r
135       //\r
136       // If the listener tree will allow any match for this part,\r
137       // then recursively explore all branches of the tree\r
138       //\r
139       searchListenerTree(handlers, type, xTree, i+1);\r
140     }\r
141 \r
142     xxTree = tree['**'];\r
143     if(xxTree) {\r
144       if(i < typeLength) {\r
145         if(xxTree._listeners) {\r
146           // If we have a listener on a '**', it will catch all, so add its handler.\r
147           searchListenerTree(handlers, type, xxTree, typeLength);\r
148         }\r
149 \r
150         // Build arrays of matching next branches and others.\r
151         for(branch in xxTree) {\r
152           if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) {\r
153             if(branch === nextType) {\r
154               // We know the next element will match, so jump twice.\r
155               searchListenerTree(handlers, type, xxTree[branch], i+2);\r
156             } else if(branch === currentType) {\r
157               // Current node matches, move into the tree.\r
158               searchListenerTree(handlers, type, xxTree[branch], i+1);\r
159             } else {\r
160               isolatedBranch = {};\r
161               isolatedBranch[branch] = xxTree[branch];\r
162               searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1);\r
163             }\r
164           }\r
165         }\r
166       } else if(xxTree._listeners) {\r
167         // We have reached the end and still on a '**'\r
168         searchListenerTree(handlers, type, xxTree, typeLength);\r
169       } else if(xxTree['*'] && xxTree['*']._listeners) {\r
170         searchListenerTree(handlers, type, xxTree['*'], typeLength);\r
171       }\r
172     }\r
173 \r
174     return listeners;\r
175   }\r
176 \r
177   function growListenerTree(type, listener) {\r
178 \r
179     type = typeof type === 'string' ? type.split(this.delimiter) : type.slice();\r
180 \r
181     //\r
182     // Looks for two consecutive '**', if so, don't add the event at all.\r
183     //\r
184     for(var i = 0, len = type.length; i+1 < len; i++) {\r
185       if(type[i] === '**' && type[i+1] === '**') {\r
186         return;\r
187       }\r
188     }\r
189 \r
190     var tree = this.listenerTree;\r
191     var name = type.shift();\r
192 \r
193     while (name !== undefined) {\r
194 \r
195       if (!tree[name]) {\r
196         tree[name] = {};\r
197       }\r
198 \r
199       tree = tree[name];\r
200 \r
201       if (type.length === 0) {\r
202 \r
203         if (!tree._listeners) {\r
204           tree._listeners = listener;\r
205         }\r
206         else {\r
207           if (typeof tree._listeners === 'function') {\r
208             tree._listeners = [tree._listeners];\r
209           }\r
210 \r
211           tree._listeners.push(listener);\r
212 \r
213           if (\r
214             !tree._listeners.warned &&\r
215             this._events.maxListeners > 0 &&\r
216             tree._listeners.length > this._events.maxListeners\r
217           ) {\r
218             tree._listeners.warned = true;\r
219             logPossibleMemoryLeak.call(this, tree._listeners.length, name);\r
220           }\r
221         }\r
222         return true;\r
223       }\r
224       name = type.shift();\r
225     }\r
226     return true;\r
227   }\r
228 \r
229   // By default EventEmitters will print a warning if more than\r
230   // 10 listeners are added to it. This is a useful default which\r
231   // helps finding memory leaks.\r
232   //\r
233   // Obviously not all Emitters should be limited to 10. This function allows\r
234   // that to be increased. Set to zero for unlimited.\r
235 \r
236   EventEmitter.prototype.delimiter = '.';\r
237 \r
238   EventEmitter.prototype.setMaxListeners = function(n) {\r
239     if (n !== undefined) {\r
240       this._events || init.call(this);\r
241       this._events.maxListeners = n;\r
242       if (!this._conf) this._conf = {};\r
243       this._conf.maxListeners = n;\r
244     }\r
245   };\r
246 \r
247   EventEmitter.prototype.event = '';\r
248 \r
249   EventEmitter.prototype.once = function(event, fn) {\r
250     this.many(event, 1, fn);\r
251     return this;\r
252   };\r
253 \r
254   EventEmitter.prototype.many = function(event, ttl, fn) {\r
255     var self = this;\r
256 \r
257     if (typeof fn !== 'function') {\r
258       throw new Error('many only accepts instances of Function');\r
259     }\r
260 \r
261     function listener() {\r
262       if (--ttl === 0) {\r
263         self.off(event, listener);\r
264       }\r
265       fn.apply(this, arguments);\r
266     }\r
267 \r
268     listener._origin = fn;\r
269 \r
270     this.on(event, listener);\r
271 \r
272     return self;\r
273   };\r
274 \r
275   EventEmitter.prototype.emit = function() {\r
276 \r
277     this._events || init.call(this);\r
278 \r
279     var type = arguments[0];\r
280 \r
281     if (type === 'newListener' && !this.newListener) {\r
282       if (!this._events.newListener) {\r
283         return false;\r
284       }\r
285     }\r
286 \r
287     var al = arguments.length;\r
288     var args,l,i,j;\r
289     var handler;\r
290 \r
291     if (this._all && this._all.length) {\r
292       handler = this._all.slice();\r
293       if (al > 3) {\r
294         args = new Array(al);\r
295         for (j = 0; j < al; j++) args[j] = arguments[j];\r
296       }\r
297 \r
298       for (i = 0, l = handler.length; i < l; i++) {\r
299         this.event = type;\r
300         switch (al) {\r
301         case 1:\r
302           handler[i].call(this, type);\r
303           break;\r
304         case 2:\r
305           handler[i].call(this, type, arguments[1]);\r
306           break;\r
307         case 3:\r
308           handler[i].call(this, type, arguments[1], arguments[2]);\r
309           break;\r
310         default:\r
311           handler[i].apply(this, args);\r
312         }\r
313       }\r
314     }\r
315 \r
316     if (this.wildcard) {\r
317       handler = [];\r
318       var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();\r
319       searchListenerTree.call(this, handler, ns, this.listenerTree, 0);\r
320     } else {\r
321       handler = this._events[type];\r
322       if (typeof handler === 'function') {\r
323         this.event = type;\r
324         switch (al) {\r
325         case 1:\r
326           handler.call(this);\r
327           break;\r
328         case 2:\r
329           handler.call(this, arguments[1]);\r
330           break;\r
331         case 3:\r
332           handler.call(this, arguments[1], arguments[2]);\r
333           break;\r
334         default:\r
335           args = new Array(al - 1);\r
336           for (j = 1; j < al; j++) args[j - 1] = arguments[j];\r
337           handler.apply(this, args);\r
338         }\r
339         return true;\r
340       } else if (handler) {\r
341         // need to make copy of handlers because list can change in the middle\r
342         // of emit call\r
343         handler = handler.slice();\r
344       }\r
345     }\r
346 \r
347     if (handler && handler.length) {\r
348       if (al > 3) {\r
349         args = new Array(al - 1);\r
350         for (j = 1; j < al; j++) args[j - 1] = arguments[j];\r
351       }\r
352       for (i = 0, l = handler.length; i < l; i++) {\r
353         this.event = type;\r
354         switch (al) {\r
355         case 1:\r
356           handler[i].call(this);\r
357           break;\r
358         case 2:\r
359           handler[i].call(this, arguments[1]);\r
360           break;\r
361         case 3:\r
362           handler[i].call(this, arguments[1], arguments[2]);\r
363           break;\r
364         default:\r
365           handler[i].apply(this, args);\r
366         }\r
367       }\r
368       return true;\r
369     } else if (!this._all && type === 'error') {\r
370       if (arguments[1] instanceof Error) {\r
371         throw arguments[1]; // Unhandled 'error' event\r
372       } else {\r
373         throw new Error("Uncaught, unspecified 'error' event.");\r
374       }\r
375       return false;\r
376     }\r
377 \r
378     return !!this._all;\r
379   };\r
380 \r
381   EventEmitter.prototype.emitAsync = function() {\r
382 \r
383     this._events || init.call(this);\r
384 \r
385     var type = arguments[0];\r
386 \r
387     if (type === 'newListener' && !this.newListener) {\r
388         if (!this._events.newListener) { return Promise.resolve([false]); }\r
389     }\r
390 \r
391     var promises= [];\r
392 \r
393     var al = arguments.length;\r
394     var args,l,i,j;\r
395     var handler;\r
396 \r
397     if (this._all) {\r
398       if (al > 3) {\r
399         args = new Array(al);\r
400         for (j = 1; j < al; j++) args[j] = arguments[j];\r
401       }\r
402       for (i = 0, l = this._all.length; i < l; i++) {\r
403         this.event = type;\r
404         switch (al) {\r
405         case 1:\r
406           promises.push(this._all[i].call(this, type));\r
407           break;\r
408         case 2:\r
409           promises.push(this._all[i].call(this, type, arguments[1]));\r
410           break;\r
411         case 3:\r
412           promises.push(this._all[i].call(this, type, arguments[1], arguments[2]));\r
413           break;\r
414         default:\r
415           promises.push(this._all[i].apply(this, args));\r
416         }\r
417       }\r
418     }\r
419 \r
420     if (this.wildcard) {\r
421       handler = [];\r
422       var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();\r
423       searchListenerTree.call(this, handler, ns, this.listenerTree, 0);\r
424     } else {\r
425       handler = this._events[type];\r
426     }\r
427 \r
428     if (typeof handler === 'function') {\r
429       this.event = type;\r
430       switch (al) {\r
431       case 1:\r
432         promises.push(handler.call(this));\r
433         break;\r
434       case 2:\r
435         promises.push(handler.call(this, arguments[1]));\r
436         break;\r
437       case 3:\r
438         promises.push(handler.call(this, arguments[1], arguments[2]));\r
439         break;\r
440       default:\r
441         args = new Array(al - 1);\r
442         for (j = 1; j < al; j++) args[j - 1] = arguments[j];\r
443         promises.push(handler.apply(this, args));\r
444       }\r
445     } else if (handler && handler.length) {\r
446       if (al > 3) {\r
447         args = new Array(al - 1);\r
448         for (j = 1; j < al; j++) args[j - 1] = arguments[j];\r
449       }\r
450       for (i = 0, l = handler.length; i < l; i++) {\r
451         this.event = type;\r
452         switch (al) {\r
453         case 1:\r
454           promises.push(handler[i].call(this));\r
455           break;\r
456         case 2:\r
457           promises.push(handler[i].call(this, arguments[1]));\r
458           break;\r
459         case 3:\r
460           promises.push(handler[i].call(this, arguments[1], arguments[2]));\r
461           break;\r
462         default:\r
463           promises.push(handler[i].apply(this, args));\r
464         }\r
465       }\r
466     } else if (!this._all && type === 'error') {\r
467       if (arguments[1] instanceof Error) {\r
468         return Promise.reject(arguments[1]); // Unhandled 'error' event\r
469       } else {\r
470         return Promise.reject("Uncaught, unspecified 'error' event.");\r
471       }\r
472     }\r
473 \r
474     return Promise.all(promises);\r
475   };\r
476 \r
477   EventEmitter.prototype.on = function(type, listener) {\r
478     if (typeof type === 'function') {\r
479       this.onAny(type);\r
480       return this;\r
481     }\r
482 \r
483     if (typeof listener !== 'function') {\r
484       throw new Error('on only accepts instances of Function');\r
485     }\r
486     this._events || init.call(this);\r
487 \r
488     // To avoid recursion in the case that type == "newListeners"! Before\r
489     // adding it to the listeners, first emit "newListeners".\r
490     this.emit('newListener', type, listener);\r
491 \r
492     if (this.wildcard) {\r
493       growListenerTree.call(this, type, listener);\r
494       return this;\r
495     }\r
496 \r
497     if (!this._events[type]) {\r
498       // Optimize the case of one listener. Don't need the extra array object.\r
499       this._events[type] = listener;\r
500     }\r
501     else {\r
502       if (typeof this._events[type] === 'function') {\r
503         // Change to array.\r
504         this._events[type] = [this._events[type]];\r
505       }\r
506 \r
507       // If we've already got an array, just append.\r
508       this._events[type].push(listener);\r
509 \r
510       // Check for listener leak\r
511       if (\r
512         !this._events[type].warned &&\r
513         this._events.maxListeners > 0 &&\r
514         this._events[type].length > this._events.maxListeners\r
515       ) {\r
516         this._events[type].warned = true;\r
517         logPossibleMemoryLeak.call(this, this._events[type].length, type);\r
518       }\r
519     }\r
520 \r
521     return this;\r
522   };\r
523 \r
524   EventEmitter.prototype.onAny = function(fn) {\r
525     if (typeof fn !== 'function') {\r
526       throw new Error('onAny only accepts instances of Function');\r
527     }\r
528 \r
529     if (!this._all) {\r
530       this._all = [];\r
531     }\r
532 \r
533     // Add the function to the event listener collection.\r
534     this._all.push(fn);\r
535     return this;\r
536   };\r
537 \r
538   EventEmitter.prototype.addListener = EventEmitter.prototype.on;\r
539 \r
540   EventEmitter.prototype.off = function(type, listener) {\r
541     if (typeof listener !== 'function') {\r
542       throw new Error('removeListener only takes instances of Function');\r
543     }\r
544 \r
545     var handlers,leafs=[];\r
546 \r
547     if(this.wildcard) {\r
548       var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();\r
549       leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);\r
550     }\r
551     else {\r
552       // does not use listeners(), so no side effect of creating _events[type]\r
553       if (!this._events[type]) return this;\r
554       handlers = this._events[type];\r
555       leafs.push({_listeners:handlers});\r
556     }\r
557 \r
558     for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {\r
559       var leaf = leafs[iLeaf];\r
560       handlers = leaf._listeners;\r
561       if (isArray(handlers)) {\r
562 \r
563         var position = -1;\r
564 \r
565         for (var i = 0, length = handlers.length; i < length; i++) {\r
566           if (handlers[i] === listener ||\r
567             (handlers[i].listener && handlers[i].listener === listener) ||\r
568             (handlers[i]._origin && handlers[i]._origin === listener)) {\r
569             position = i;\r
570             break;\r
571           }\r
572         }\r
573 \r
574         if (position < 0) {\r
575           continue;\r
576         }\r
577 \r
578         if(this.wildcard) {\r
579           leaf._listeners.splice(position, 1);\r
580         }\r
581         else {\r
582           this._events[type].splice(position, 1);\r
583         }\r
584 \r
585         if (handlers.length === 0) {\r
586           if(this.wildcard) {\r
587             delete leaf._listeners;\r
588           }\r
589           else {\r
590             delete this._events[type];\r
591           }\r
592         }\r
593 \r
594         this.emit("removeListener", type, listener);\r
595 \r
596         return this;\r
597       }\r
598       else if (handlers === listener ||\r
599         (handlers.listener && handlers.listener === listener) ||\r
600         (handlers._origin && handlers._origin === listener)) {\r
601         if(this.wildcard) {\r
602           delete leaf._listeners;\r
603         }\r
604         else {\r
605           delete this._events[type];\r
606         }\r
607 \r
608         this.emit("removeListener", type, listener);\r
609       }\r
610     }\r
611 \r
612     function recursivelyGarbageCollect(root) {\r
613       if (root === undefined) {\r
614         return;\r
615       }\r
616       var keys = Object.keys(root);\r
617       for (var i in keys) {\r
618         var key = keys[i];\r
619         var obj = root[key];\r
620         if ((obj instanceof Function) || (typeof obj !== "object") || (obj === null))\r
621           continue;\r
622         if (Object.keys(obj).length > 0) {\r
623           recursivelyGarbageCollect(root[key]);\r
624         }\r
625         if (Object.keys(obj).length === 0) {\r
626           delete root[key];\r
627         }\r
628       }\r
629     }\r
630     recursivelyGarbageCollect(this.listenerTree);\r
631 \r
632     return this;\r
633   };\r
634 \r
635   EventEmitter.prototype.offAny = function(fn) {\r
636     var i = 0, l = 0, fns;\r
637     if (fn && this._all && this._all.length > 0) {\r
638       fns = this._all;\r
639       for(i = 0, l = fns.length; i < l; i++) {\r
640         if(fn === fns[i]) {\r
641           fns.splice(i, 1);\r
642           this.emit("removeListenerAny", fn);\r
643           return this;\r
644         }\r
645       }\r
646     } else {\r
647       fns = this._all;\r
648       for(i = 0, l = fns.length; i < l; i++)\r
649         this.emit("removeListenerAny", fns[i]);\r
650       this._all = [];\r
651     }\r
652     return this;\r
653   };\r
654 \r
655   EventEmitter.prototype.removeListener = EventEmitter.prototype.off;\r
656 \r
657   EventEmitter.prototype.removeAllListeners = function(type) {\r
658     if (arguments.length === 0) {\r
659       !this._events || init.call(this);\r
660       return this;\r
661     }\r
662 \r
663     if (this.wildcard) {\r
664       var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();\r
665       var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);\r
666 \r
667       for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {\r
668         var leaf = leafs[iLeaf];\r
669         leaf._listeners = null;\r
670       }\r
671     }\r
672     else if (this._events) {\r
673       this._events[type] = null;\r
674     }\r
675     return this;\r
676   };\r
677 \r
678   EventEmitter.prototype.listeners = function(type) {\r
679     if (this.wildcard) {\r
680       var handlers = [];\r
681       var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();\r
682       searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);\r
683       return handlers;\r
684     }\r
685 \r
686     this._events || init.call(this);\r
687 \r
688     if (!this._events[type]) this._events[type] = [];\r
689     if (!isArray(this._events[type])) {\r
690       this._events[type] = [this._events[type]];\r
691     }\r
692     return this._events[type];\r
693   };\r
694 \r
695   EventEmitter.prototype.listenerCount = function(type) {\r
696     return this.listeners(type).length;\r
697   };\r
698 \r
699   EventEmitter.prototype.listenersAny = function() {\r
700 \r
701     if(this._all) {\r
702       return this._all;\r
703     }\r
704     else {\r
705       return [];\r
706     }\r
707 \r
708   };\r
709 \r
710   if (typeof define === 'function' && define.amd) {\r
711      // AMD. Register as an anonymous module.\r
712     define(function() {\r
713       return EventEmitter;\r
714     });\r
715   } else if (typeof exports === 'object') {\r
716     // CommonJS\r
717     module.exports = EventEmitter;\r
718   }\r
719   else {\r
720     // Browser global.\r
721     window.EventEmitter2 = EventEmitter;\r
722   }\r
723 }();\r
724
725 },{}],2:[function(require,module,exports){
726 /*
727 object-assign
728 (c) Sindre Sorhus
729 @license MIT
730 */
731
732 'use strict';
733 /* eslint-disable no-unused-vars */
734 var getOwnPropertySymbols = Object.getOwnPropertySymbols;
735 var hasOwnProperty = Object.prototype.hasOwnProperty;
736 var propIsEnumerable = Object.prototype.propertyIsEnumerable;
737
738 function toObject(val) {
739         if (val === null || val === undefined) {
740                 throw new TypeError('Object.assign cannot be called with null or undefined');
741         }
742
743         return Object(val);
744 }
745
746 function shouldUseNative() {
747         try {
748                 if (!Object.assign) {
749                         return false;
750                 }
751
752                 // Detect buggy property enumeration order in older V8 versions.
753
754                 // https://bugs.chromium.org/p/v8/issues/detail?id=4118
755                 var test1 = new String('abc');  // eslint-disable-line no-new-wrappers
756                 test1[5] = 'de';
757                 if (Object.getOwnPropertyNames(test1)[0] === '5') {
758                         return false;
759                 }
760
761                 // https://bugs.chromium.org/p/v8/issues/detail?id=3056
762                 var test2 = {};
763                 for (var i = 0; i < 10; i++) {
764                         test2['_' + String.fromCharCode(i)] = i;
765                 }
766                 var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
767                         return test2[n];
768                 });
769                 if (order2.join('') !== '0123456789') {
770                         return false;
771                 }
772
773                 // https://bugs.chromium.org/p/v8/issues/detail?id=3056
774                 var test3 = {};
775                 'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
776                         test3[letter] = letter;
777                 });
778                 if (Object.keys(Object.assign({}, test3)).join('') !==
779                                 'abcdefghijklmnopqrst') {
780                         return false;
781                 }
782
783                 return true;
784         } catch (err) {
785                 // We don't expect any of the above to throw, but better to be safe.
786                 return false;
787         }
788 }
789
790 module.exports = shouldUseNative() ? Object.assign : function (target, source) {
791         var from;
792         var to = toObject(target);
793         var symbols;
794
795         for (var s = 1; s < arguments.length; s++) {
796                 from = Object(arguments[s]);
797
798                 for (var key in from) {
799                         if (hasOwnProperty.call(from, key)) {
800                                 to[key] = from[key];
801                         }
802                 }
803
804                 if (getOwnPropertySymbols) {
805                         symbols = getOwnPropertySymbols(from);
806                         for (var i = 0; i < symbols.length; i++) {
807                                 if (propIsEnumerable.call(from, symbols[i])) {
808                                         to[symbols[i]] = from[symbols[i]];
809                                 }
810                         }
811                 }
812         }
813
814         return to;
815 };
816
817 },{}],3:[function(require,module,exports){
818 /**
819  * @fileOverview
820  * @author Russell Toris - rctoris@wpi.edu
821  */
822
823 /**
824  * If you use roslib in a browser, all the classes will be exported to a global variable called ROSLIB.
825  *
826  * If you use nodejs, this is the variable you get when you require('roslib')
827  */
828 var ROSLIB = this.ROSLIB || {
829   REVISION : '0.20.0'
830 };
831
832 var assign = require('object-assign');
833
834 // Add core components
835 assign(ROSLIB, require('./core'));
836
837 assign(ROSLIB, require('./actionlib'));
838
839 assign(ROSLIB, require('./math'));
840
841 assign(ROSLIB, require('./tf'));
842
843 assign(ROSLIB, require('./urdf'));
844
845 module.exports = ROSLIB;
846
847 },{"./actionlib":9,"./core":18,"./math":23,"./tf":26,"./urdf":38,"object-assign":2}],4:[function(require,module,exports){
848 (function (global){
849 global.ROSLIB = require('./RosLib');
850 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
851 },{"./RosLib":3}],5:[function(require,module,exports){
852 /**
853  * @fileOverview
854  * @author Russell Toris - rctoris@wpi.edu
855  */
856
857 var Topic = require('../core/Topic');
858 var Message = require('../core/Message');
859 var EventEmitter2 = require('eventemitter2').EventEmitter2;
860
861 /**
862  * An actionlib action client.
863  *
864  * Emits the following events:
865  *  * 'timeout' - if a timeout occurred while sending a goal
866  *  * 'status' - the status messages received from the action server
867  *  * 'feedback' -  the feedback messages received from the action server
868  *  * 'result' - the result returned from the action server
869  *
870  *  @constructor
871  *  @param options - object with following keys:
872  *   * ros - the ROSLIB.Ros connection handle
873  *   * serverName - the action server name, like /fibonacci
874  *   * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction'
875  *   * timeout - the timeout length when connecting to the action server
876  */
877 function ActionClient(options) {
878   var that = this;
879   options = options || {};
880   this.ros = options.ros;
881   this.serverName = options.serverName;
882   this.actionName = options.actionName;
883   this.timeout = options.timeout;
884   this.omitFeedback = options.omitFeedback;
885   this.omitStatus = options.omitStatus;
886   this.omitResult = options.omitResult;
887   this.goals = {};
888
889   // flag to check if a status has been received
890   var receivedStatus = false;
891
892   // create the topics associated with actionlib
893   this.feedbackListener = new Topic({
894     ros : this.ros,
895     name : this.serverName + '/feedback',
896     messageType : this.actionName + 'Feedback'
897   });
898
899   this.statusListener = new Topic({
900     ros : this.ros,
901     name : this.serverName + '/status',
902     messageType : 'actionlib_msgs/GoalStatusArray'
903   });
904
905   this.resultListener = new Topic({
906     ros : this.ros,
907     name : this.serverName + '/result',
908     messageType : this.actionName + 'Result'
909   });
910
911   this.goalTopic = new Topic({
912     ros : this.ros,
913     name : this.serverName + '/goal',
914     messageType : this.actionName + 'Goal'
915   });
916
917   this.cancelTopic = new Topic({
918     ros : this.ros,
919     name : this.serverName + '/cancel',
920     messageType : 'actionlib_msgs/GoalID'
921   });
922
923   // advertise the goal and cancel topics
924   this.goalTopic.advertise();
925   this.cancelTopic.advertise();
926
927   // subscribe to the status topic
928   if (!this.omitStatus) {
929     this.statusListener.subscribe(function(statusMessage) {
930       receivedStatus = true;
931       statusMessage.status_list.forEach(function(status) {
932         var goal = that.goals[status.goal_id.id];
933         if (goal) {
934           goal.emit('status', status);
935         }
936       });
937     });
938   }
939
940   // subscribe the the feedback topic
941   if (!this.omitFeedback) {
942     this.feedbackListener.subscribe(function(feedbackMessage) {
943       var goal = that.goals[feedbackMessage.status.goal_id.id];
944       if (goal) {
945         goal.emit('status', feedbackMessage.status);
946         goal.emit('feedback', feedbackMessage.feedback);
947       }
948     });
949   }
950
951   // subscribe to the result topic
952   if (!this.omitResult) {
953     this.resultListener.subscribe(function(resultMessage) {
954       var goal = that.goals[resultMessage.status.goal_id.id];
955
956       if (goal) {
957         goal.emit('status', resultMessage.status);
958         goal.emit('result', resultMessage.result);
959       }
960     });
961   }
962
963   // If timeout specified, emit a 'timeout' event if the action server does not respond
964   if (this.timeout) {
965     setTimeout(function() {
966       if (!receivedStatus) {
967         that.emit('timeout');
968       }
969     }, this.timeout);
970   }
971 }
972
973 ActionClient.prototype.__proto__ = EventEmitter2.prototype;
974
975 /**
976  * Cancel all goals associated with this ActionClient.
977  */
978 ActionClient.prototype.cancel = function() {
979   var cancelMessage = new Message();
980   this.cancelTopic.publish(cancelMessage);
981 };
982
983 /**
984  * Unsubscribe and unadvertise all topics associated with this ActionClient.
985  */
986 ActionClient.prototype.dispose = function() {
987   this.goalTopic.unadvertise();
988   this.cancelTopic.unadvertise();
989   if (!this.omitStatus) {this.statusListener.unsubscribe();}
990   if (!this.omitFeedback) {this.feedbackListener.unsubscribe();}
991   if (!this.omitResult) {this.resultListener.unsubscribe();}
992 };
993
994 module.exports = ActionClient;
995
996 },{"../core/Message":10,"../core/Topic":17,"eventemitter2":1}],6:[function(require,module,exports){
997 /**
998  * @fileOverview
999  * @author Justin Young - justin@oodar.com.au
1000  * @author Russell Toris - rctoris@wpi.edu
1001  */
1002
1003 var Topic = require('../core/Topic');
1004 var Message = require('../core/Message');
1005 var EventEmitter2 = require('eventemitter2').EventEmitter2;
1006
1007 /**
1008  * An actionlib action listener
1009  *
1010  * Emits the following events:
1011  *  * 'status' - the status messages received from the action server
1012  *  * 'feedback' -  the feedback messages received from the action server
1013  *  * 'result' - the result returned from the action server
1014  *
1015  *  @constructor
1016  *  @param options - object with following keys:
1017  *   * ros - the ROSLIB.Ros connection handle
1018  *   * serverName - the action server name, like /fibonacci
1019  *   * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction'
1020  */
1021 function ActionListener(options) {
1022   var that = this;
1023   options = options || {};
1024   this.ros = options.ros;
1025   this.serverName = options.serverName;
1026   this.actionName = options.actionName;
1027   this.timeout = options.timeout;
1028   this.omitFeedback = options.omitFeedback;
1029   this.omitStatus = options.omitStatus;
1030   this.omitResult = options.omitResult;
1031
1032
1033   // create the topics associated with actionlib
1034   var goalListener = new Topic({
1035     ros : this.ros,
1036     name : this.serverName + '/goal',
1037     messageType : this.actionName + 'Goal'
1038   });
1039
1040   var feedbackListener = new Topic({
1041     ros : this.ros,
1042     name : this.serverName + '/feedback',
1043     messageType : this.actionName + 'Feedback'
1044   });
1045
1046   var statusListener = new Topic({
1047     ros : this.ros,
1048     name : this.serverName + '/status',
1049     messageType : 'actionlib_msgs/GoalStatusArray'
1050   });
1051
1052   var resultListener = new Topic({
1053     ros : this.ros,
1054     name : this.serverName + '/result',
1055     messageType : this.actionName + 'Result'
1056   });
1057
1058   goalListener.subscribe(function(goalMessage) {
1059       that.emit('goal', goalMessage);
1060   });
1061
1062   statusListener.subscribe(function(statusMessage) {
1063       statusMessage.status_list.forEach(function(status) {
1064           that.emit('status', status);
1065       });
1066   });
1067
1068   feedbackListener.subscribe(function(feedbackMessage) {
1069       that.emit('status', feedbackMessage.status);
1070       that.emit('feedback', feedbackMessage.feedback);
1071   });
1072
1073   // subscribe to the result topic
1074   resultListener.subscribe(function(resultMessage) {
1075       that.emit('status', resultMessage.status);
1076       that.emit('result', resultMessage.result);
1077   });
1078
1079 }
1080
1081 ActionListener.prototype.__proto__ = EventEmitter2.prototype;
1082
1083 module.exports = ActionListener;
1084
1085 },{"../core/Message":10,"../core/Topic":17,"eventemitter2":1}],7:[function(require,module,exports){
1086 /**
1087  * @fileOverview
1088  * @author Russell Toris - rctoris@wpi.edu
1089  */
1090
1091 var Message = require('../core/Message');
1092 var EventEmitter2 = require('eventemitter2').EventEmitter2;
1093
1094 /**
1095  * An actionlib goal goal is associated with an action server.
1096  *
1097  * Emits the following events:
1098  *  * 'timeout' - if a timeout occurred while sending a goal
1099  *
1100  *  @constructor
1101  *  @param object with following keys:
1102  *   * actionClient - the ROSLIB.ActionClient to use with this goal
1103  *   * goalMessage - The JSON object containing the goal for the action server
1104  */
1105 function Goal(options) {
1106   var that = this;
1107   this.actionClient = options.actionClient;
1108   this.goalMessage = options.goalMessage;
1109   this.isFinished = false;
1110
1111   // Used to create random IDs
1112   var date = new Date();
1113
1114   // Create a random ID
1115   this.goalID = 'goal_' + Math.random() + '_' + date.getTime();
1116   // Fill in the goal message
1117   this.goalMessage = new Message({
1118     goal_id : {
1119       stamp : {
1120         secs : 0,
1121         nsecs : 0
1122       },
1123       id : this.goalID
1124     },
1125     goal : this.goalMessage
1126   });
1127
1128   this.on('status', function(status) {
1129     that.status = status;
1130   });
1131
1132   this.on('result', function(result) {
1133     that.isFinished = true;
1134     that.result = result;
1135   });
1136
1137   this.on('feedback', function(feedback) {
1138     that.feedback = feedback;
1139   });
1140
1141   // Add the goal
1142   this.actionClient.goals[this.goalID] = this;
1143 }
1144
1145 Goal.prototype.__proto__ = EventEmitter2.prototype;
1146
1147 /**
1148  * Send the goal to the action server.
1149  *
1150  * @param timeout (optional) - a timeout length for the goal's result
1151  */
1152 Goal.prototype.send = function(timeout) {
1153   var that = this;
1154   that.actionClient.goalTopic.publish(that.goalMessage);
1155   if (timeout) {
1156     setTimeout(function() {
1157       if (!that.isFinished) {
1158         that.emit('timeout');
1159       }
1160     }, timeout);
1161   }
1162 };
1163
1164 /**
1165  * Cancel the current goal.
1166  */
1167 Goal.prototype.cancel = function() {
1168   var cancelMessage = new Message({
1169     id : this.goalID
1170   });
1171   this.actionClient.cancelTopic.publish(cancelMessage);
1172 };
1173
1174 module.exports = Goal;
1175 },{"../core/Message":10,"eventemitter2":1}],8:[function(require,module,exports){
1176 /**
1177  * @fileOverview
1178  * @author Laura Lindzey - lindzey@gmail.com
1179  */
1180
1181 var Topic = require('../core/Topic');
1182 var Message = require('../core/Message');
1183 var EventEmitter2 = require('eventemitter2').EventEmitter2;
1184
1185 /**
1186  * An actionlib action server client.
1187  *
1188  * Emits the following events:
1189  *  * 'goal' - goal sent by action client
1190  *  * 'cancel' - action client has canceled the request
1191  *
1192  *  @constructor
1193  *  @param options - object with following keys:
1194  *   * ros - the ROSLIB.Ros connection handle
1195  *   * serverName - the action server name, like /fibonacci
1196  *   * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction'
1197  */
1198
1199 function SimpleActionServer(options) {
1200     var that = this;
1201     options = options || {};
1202     this.ros = options.ros;
1203     this.serverName = options.serverName;
1204     this.actionName = options.actionName;
1205
1206     // create and advertise publishers
1207     this.feedbackPublisher = new Topic({
1208         ros : this.ros,
1209         name : this.serverName + '/feedback',
1210         messageType : this.actionName + 'Feedback'
1211     });
1212     this.feedbackPublisher.advertise();
1213
1214     var statusPublisher = new Topic({
1215         ros : this.ros,
1216         name : this.serverName + '/status',
1217         messageType : 'actionlib_msgs/GoalStatusArray'
1218     });
1219     statusPublisher.advertise();
1220
1221     this.resultPublisher = new Topic({
1222         ros : this.ros,
1223         name : this.serverName + '/result',
1224         messageType : this.actionName + 'Result'
1225     });
1226     this.resultPublisher.advertise();
1227
1228     // create and subscribe to listeners
1229     var goalListener = new Topic({
1230         ros : this.ros,
1231         name : this.serverName + '/goal',
1232         messageType : this.actionName + 'Goal'
1233     });
1234
1235     var cancelListener = new Topic({
1236         ros : this.ros,
1237         name : this.serverName + '/cancel',
1238         messageType : 'actionlib_msgs/GoalID'
1239     });
1240
1241     // Track the goals and their status in order to publish status...
1242     this.statusMessage = new Message({
1243         header : {
1244             stamp : {secs : 0, nsecs : 100},
1245             frame_id : ''
1246         },
1247         status_list : []
1248     });
1249
1250     // needed for handling preemption prompted by a new goal being received
1251     this.currentGoal = null; // currently tracked goal
1252     this.nextGoal = null; // the one that'll be preempting
1253
1254     goalListener.subscribe(function(goalMessage) {
1255         
1256     if(that.currentGoal) {
1257             that.nextGoal = goalMessage;
1258             // needs to happen AFTER rest is set up
1259             that.emit('cancel');
1260     } else {
1261             that.statusMessage.status_list = [{goal_id : goalMessage.goal_id, status : 1}];
1262             that.currentGoal = goalMessage;
1263             that.emit('goal', goalMessage.goal);
1264     }
1265     });
1266
1267     // helper function for determing ordering of timestamps
1268     // returns t1 < t2
1269     var isEarlier = function(t1, t2) {
1270         if(t1.secs > t2.secs) {
1271             return false;
1272         } else if(t1.secs < t2.secs) {
1273             return true;
1274         } else if(t1.nsecs < t2.nsecs) {
1275             return true;
1276         } else {
1277             return false;
1278         }
1279     };
1280
1281     // TODO: this may be more complicated than necessary, since I'm
1282     // not sure if the callbacks can ever wind up with a scenario
1283     // where we've been preempted by a next goal, it hasn't finished
1284     // processing, and then we get a cancel message
1285     cancelListener.subscribe(function(cancelMessage) {
1286
1287         // cancel ALL goals if both empty
1288         if(cancelMessage.stamp.secs === 0 && cancelMessage.stamp.secs === 0 && cancelMessage.id === '') {
1289             that.nextGoal = null;
1290             if(that.currentGoal) {
1291                 that.emit('cancel');
1292             }
1293         } else { // treat id and stamp independently
1294             if(that.currentGoal && cancelMessage.id === that.currentGoal.goal_id.id) {
1295                 that.emit('cancel');
1296             } else if(that.nextGoal && cancelMessage.id === that.nextGoal.goal_id.id) {
1297                 that.nextGoal = null;
1298             }
1299
1300             if(that.nextGoal && isEarlier(that.nextGoal.goal_id.stamp,
1301                                           cancelMessage.stamp)) {
1302                 that.nextGoal = null;
1303             }
1304             if(that.currentGoal && isEarlier(that.currentGoal.goal_id.stamp,
1305                                              cancelMessage.stamp)) {
1306                 
1307                 that.emit('cancel');
1308             }
1309         }
1310     });
1311
1312     // publish status at pseudo-fixed rate; required for clients to know they've connected
1313     var statusInterval = setInterval( function() {
1314         var currentTime = new Date();
1315         var secs = Math.floor(currentTime.getTime()/1000);
1316         var nsecs = Math.round(1000000000*(currentTime.getTime()/1000-secs));
1317         that.statusMessage.header.stamp.secs = secs;
1318         that.statusMessage.header.stamp.nsecs = nsecs;
1319         statusPublisher.publish(that.statusMessage);
1320     }, 500); // publish every 500ms
1321
1322 }
1323
1324 SimpleActionServer.prototype.__proto__ = EventEmitter2.prototype;
1325
1326 /**
1327 *  Set action state to succeeded and return to client
1328 */
1329
1330 SimpleActionServer.prototype.setSucceeded = function(result2) {
1331     
1332
1333     var resultMessage = new Message({
1334         status : {goal_id : this.currentGoal.goal_id, status : 3},
1335         result : result2
1336     });
1337     this.resultPublisher.publish(resultMessage);
1338
1339     this.statusMessage.status_list = [];
1340     if(this.nextGoal) {
1341         this.currentGoal = this.nextGoal;
1342         this.nextGoal = null;
1343         this.emit('goal', this.currentGoal.goal);
1344     } else {
1345         this.currentGoal = null;
1346     }
1347 };
1348
1349 /**
1350 *  Function to send feedback
1351 */
1352
1353 SimpleActionServer.prototype.sendFeedback = function(feedback2) {
1354
1355     var feedbackMessage = new Message({
1356         status : {goal_id : this.currentGoal.goal_id, status : 1},
1357         feedback : feedback2
1358     });
1359     this.feedbackPublisher.publish(feedbackMessage);
1360 };
1361
1362 /**
1363 *  Handle case where client requests preemption
1364 */
1365
1366 SimpleActionServer.prototype.setPreempted = function() {
1367
1368     this.statusMessage.status_list = [];
1369     var resultMessage = new Message({
1370         status : {goal_id : this.currentGoal.goal_id, status : 2},
1371     });
1372     this.resultPublisher.publish(resultMessage);
1373
1374     if(this.nextGoal) {
1375         this.currentGoal = this.nextGoal;
1376         this.nextGoal = null;
1377         this.emit('goal', this.currentGoal.goal);
1378     } else {
1379         this.currentGoal = null;
1380     }
1381 };
1382
1383 module.exports = SimpleActionServer;
1384 },{"../core/Message":10,"../core/Topic":17,"eventemitter2":1}],9:[function(require,module,exports){
1385 var Ros = require('../core/Ros');
1386 var mixin = require('../mixin');
1387
1388 var action = module.exports = {
1389     ActionClient: require('./ActionClient'),
1390     ActionListener: require('./ActionListener'),
1391     Goal: require('./Goal'),
1392     SimpleActionServer: require('./SimpleActionServer')
1393 };
1394
1395 mixin(Ros, ['ActionClient', 'SimpleActionServer'], action);
1396
1397 },{"../core/Ros":12,"../mixin":24,"./ActionClient":5,"./ActionListener":6,"./Goal":7,"./SimpleActionServer":8}],10:[function(require,module,exports){
1398 /**
1399  * @fileoverview
1400  * @author Brandon Alexander - baalexander@gmail.com
1401  */
1402
1403 var assign = require('object-assign');
1404
1405 /**
1406  * Message objects are used for publishing and subscribing to and from topics.
1407  *
1408  * @constructor
1409  * @param values - object matching the fields defined in the .msg definition file
1410  */
1411 function Message(values) {
1412   assign(this, values);
1413 }
1414
1415 module.exports = Message;
1416 },{"object-assign":2}],11:[function(require,module,exports){
1417 /**
1418  * @fileoverview
1419  * @author Brandon Alexander - baalexander@gmail.com
1420  */
1421
1422 var Service = require('./Service');
1423 var ServiceRequest = require('./ServiceRequest');
1424
1425 /**
1426  * A ROS parameter.
1427  *
1428  * @constructor
1429  * @param options - possible keys include:
1430  *   * ros - the ROSLIB.Ros connection handle
1431  *   * name - the param name, like max_vel_x
1432  */
1433 function Param(options) {
1434   options = options || {};
1435   this.ros = options.ros;
1436   this.name = options.name;
1437 }
1438
1439 /**
1440  * Fetches the value of the param.
1441  *
1442  * @param callback - function with the following params:
1443  *  * value - the value of the param from ROS.
1444  */
1445 Param.prototype.get = function(callback) {
1446   var paramClient = new Service({
1447     ros : this.ros,
1448     name : '/rosapi/get_param',
1449     serviceType : 'rosapi/GetParam'
1450   });
1451
1452   var request = new ServiceRequest({
1453     name : this.name
1454   });
1455
1456   paramClient.callService(request, function(result) {
1457     var value = JSON.parse(result.value);
1458     callback(value);
1459   });
1460 };
1461
1462 /**
1463  * Sets the value of the param in ROS.
1464  *
1465  * @param value - value to set param to.
1466  */
1467 Param.prototype.set = function(value, callback) {
1468   var paramClient = new Service({
1469     ros : this.ros,
1470     name : '/rosapi/set_param',
1471     serviceType : 'rosapi/SetParam'
1472   });
1473
1474   var request = new ServiceRequest({
1475     name : this.name,
1476     value : JSON.stringify(value)
1477   });
1478
1479   paramClient.callService(request, callback);
1480 };
1481
1482 /**
1483  * Delete this parameter on the ROS server.
1484  */
1485 Param.prototype.delete = function(callback) {
1486   var paramClient = new Service({
1487     ros : this.ros,
1488     name : '/rosapi/delete_param',
1489     serviceType : 'rosapi/DeleteParam'
1490   });
1491
1492   var request = new ServiceRequest({
1493     name : this.name
1494   });
1495
1496   paramClient.callService(request, callback);
1497 };
1498
1499 module.exports = Param;
1500 },{"./Service":13,"./ServiceRequest":14}],12:[function(require,module,exports){
1501 /**
1502  * @fileoverview
1503  * @author Brandon Alexander - baalexander@gmail.com
1504  */
1505
1506 var WebSocket = require('ws');
1507 var socketAdapter = require('./SocketAdapter.js');
1508
1509 var Service = require('./Service');
1510 var ServiceRequest = require('./ServiceRequest');
1511
1512 var assign = require('object-assign');
1513 var EventEmitter2 = require('eventemitter2').EventEmitter2;
1514
1515 /**
1516  * Manages connection to the server and all interactions with ROS.
1517  *
1518  * Emits the following events:
1519  *  * 'error' - there was an error with ROS
1520  *  * 'connection' - connected to the WebSocket server
1521  *  * 'close' - disconnected to the WebSocket server
1522  *  * <topicName> - a message came from rosbridge with the given topic name
1523  *  * <serviceID> - a service response came from rosbridge with the given ID
1524  *
1525  * @constructor
1526  * @param options - possible keys include: <br>
1527  *   * 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) <br>
1528  *   * groovyCompatibility - don't use interfaces that changed after the last groovy release or rosbridge_suite and related tools (defaults to true)
1529  *   * transportLibrary (optional) - one of 'websocket' (default), 'socket.io' or RTCPeerConnection instance controlling how the connection is created in `connect`.
1530  *   * transportOptions (optional) - the options to use use when creating a connection. Currently only used if `transportLibrary` is RTCPeerConnection.
1531  */
1532 function Ros(options) {
1533   options = options || {};
1534   this.socket = null;
1535   this.idCounter = 0;
1536   this.isConnected = false;
1537   this.transportLibrary = options.transportLibrary || 'websocket';
1538   this.transportOptions = options.transportOptions || {};
1539
1540   if (typeof options.groovyCompatibility === 'undefined') {
1541     this.groovyCompatibility = true;
1542   }
1543   else {
1544     this.groovyCompatibility = options.groovyCompatibility;
1545   }
1546
1547   // Sets unlimited event listeners.
1548   this.setMaxListeners(0);
1549
1550   // begin by checking if a URL was given
1551   if (options.url) {
1552     this.connect(options.url);
1553   }
1554 }
1555
1556 Ros.prototype.__proto__ = EventEmitter2.prototype;
1557
1558 /**
1559  * Connect to the specified WebSocket.
1560  *
1561  * @param url - WebSocket URL or RTCDataChannel label for Rosbridge
1562  */
1563 Ros.prototype.connect = function(url) {
1564   if (this.transportLibrary === 'socket.io') {
1565     this.socket = assign(io(url, {'force new connection': true}), socketAdapter(this));
1566     this.socket.on('connect', this.socket.onopen);
1567     this.socket.on('data', this.socket.onmessage);
1568     this.socket.on('close', this.socket.onclose);
1569     this.socket.on('error', this.socket.onerror);
1570   } else if (this.transportLibrary.constructor.name === 'RTCPeerConnection') {
1571     this.socket = assign(this.transportLibrary.createDataChannel(url, this.transportOptions), socketAdapter(this));
1572   }else {
1573     this.socket = assign(new WebSocket(url), socketAdapter(this));
1574   }
1575
1576 };
1577
1578 /**
1579  * Disconnect from the WebSocket server.
1580  */
1581 Ros.prototype.close = function() {
1582   if (this.socket) {
1583     this.socket.close();
1584   }
1585 };
1586
1587 /**
1588  * Sends an authorization request to the server.
1589  *
1590  * @param mac - MAC (hash) string given by the trusted source.
1591  * @param client - IP of the client.
1592  * @param dest - IP of the destination.
1593  * @param rand - Random string given by the trusted source.
1594  * @param t - Time of the authorization request.
1595  * @param level - User level as a string given by the client.
1596  * @param end - End time of the client's session.
1597  */
1598 Ros.prototype.authenticate = function(mac, client, dest, rand, t, level, end) {
1599   // create the request
1600   var auth = {
1601     op : 'auth',
1602     mac : mac,
1603     client : client,
1604     dest : dest,
1605     rand : rand,
1606     t : t,
1607     level : level,
1608     end : end
1609   };
1610   // send the request
1611   this.callOnConnection(auth);
1612 };
1613
1614 /**
1615  * Sends the message over the WebSocket, but queues the message up if not yet
1616  * connected.
1617  */
1618 Ros.prototype.callOnConnection = function(message) {
1619   var that = this;
1620   var messageJson = JSON.stringify(message);
1621   var emitter = null;
1622   if (this.transportLibrary === 'socket.io') {
1623     emitter = function(msg){that.socket.emit('operation', msg);};
1624   } else {
1625     emitter = function(msg){that.socket.send(msg);};
1626   }
1627
1628   if (!this.isConnected) {
1629     that.once('connection', function() {
1630       emitter(messageJson);
1631     });
1632   } else {
1633     emitter(messageJson);
1634   }
1635 };
1636
1637 /**
1638  * Sends a set_level request to the server
1639  *
1640  * @param level - Status level (none, error, warning, info)
1641  * @param id - Optional: Operation ID to change status level on
1642  */
1643 Ros.prototype.setStatusLevel = function(level, id){
1644   var levelMsg = {
1645     op: 'set_level',
1646     level: level,
1647     id: id
1648   };
1649
1650   this.callOnConnection(levelMsg);
1651 };
1652
1653 /**
1654  * Retrieves Action Servers in ROS as an array of string
1655  *
1656  *   * actionservers - Array of action server names
1657  */
1658 Ros.prototype.getActionServers = function(callback, failedCallback) {
1659   var getActionServers = new Service({
1660     ros : this,
1661     name : '/rosapi/action_servers',
1662     serviceType : 'rosapi/GetActionServers'
1663   });
1664
1665   var request = new ServiceRequest({});
1666   if (typeof failedCallback === 'function'){
1667     getActionServers.callService(request,
1668       function(result) {
1669         callback(result.action_servers);
1670       },
1671       function(message){
1672         failedCallback(message);
1673       }
1674     );
1675   }else{
1676     getActionServers.callService(request, function(result) {
1677       callback(result.action_servers);
1678     });
1679   }
1680 };
1681
1682 /**
1683  * Retrieves list of topics in ROS as an array.
1684  *
1685  * @param callback function with params:
1686  *   * topics - Array of topic names
1687  */
1688 Ros.prototype.getTopics = function(callback, failedCallback) {
1689   var topicsClient = new Service({
1690     ros : this,
1691     name : '/rosapi/topics',
1692     serviceType : 'rosapi/Topics'
1693   });
1694
1695   var request = new ServiceRequest();
1696   if (typeof failedCallback === 'function'){
1697     topicsClient.callService(request,
1698       function(result) {
1699         callback(result);
1700       },
1701       function(message){
1702         failedCallback(message);
1703       }
1704     );
1705   }else{
1706     topicsClient.callService(request, function(result) {
1707       callback(result);
1708     });
1709   }
1710 };
1711
1712 /**
1713  * Retrieves Topics in ROS as an array as specific type
1714  *
1715  * @param topicType topic type to find:
1716  * @param callback function with params:
1717  *   * topics - Array of topic names
1718  */
1719 Ros.prototype.getTopicsForType = function(topicType, callback, failedCallback) {
1720   var topicsForTypeClient = new Service({
1721     ros : this,
1722     name : '/rosapi/topics_for_type',
1723     serviceType : 'rosapi/TopicsForType'
1724   });
1725
1726   var request = new ServiceRequest({
1727     type: topicType
1728   });
1729   if (typeof failedCallback === 'function'){
1730     topicsForTypeClient.callService(request,
1731       function(result) {
1732         callback(result.topics);
1733       },
1734       function(message){
1735         failedCallback(message);
1736       }
1737     );
1738   }else{
1739     topicsForTypeClient.callService(request, function(result) {
1740       callback(result.topics);
1741     });
1742   }
1743 };
1744
1745 /**
1746  * Retrieves list of active service names in ROS.
1747  *
1748  * @param callback - function with the following params:
1749  *   * services - array of service names
1750  */
1751 Ros.prototype.getServices = function(callback, failedCallback) {
1752   var servicesClient = new Service({
1753     ros : this,
1754     name : '/rosapi/services',
1755     serviceType : 'rosapi/Services'
1756   });
1757
1758   var request = new ServiceRequest();
1759   if (typeof failedCallback === 'function'){
1760     servicesClient.callService(request,
1761       function(result) {
1762         callback(result.services);
1763       },
1764       function(message) {
1765         failedCallback(message);
1766       }
1767     );
1768   }else{
1769     servicesClient.callService(request, function(result) {
1770       callback(result.services);
1771     });
1772   }
1773 };
1774
1775 /**
1776  * Retrieves list of services in ROS as an array as specific type
1777  *
1778  * @param serviceType service type to find:
1779  * @param callback function with params:
1780  *   * topics - Array of service names
1781  */
1782 Ros.prototype.getServicesForType = function(serviceType, callback, failedCallback) {
1783   var servicesForTypeClient = new Service({
1784     ros : this,
1785     name : '/rosapi/services_for_type',
1786     serviceType : 'rosapi/ServicesForType'
1787   });
1788
1789   var request = new ServiceRequest({
1790     type: serviceType
1791   });
1792   if (typeof failedCallback === 'function'){
1793     servicesForTypeClient.callService(request,
1794       function(result) {
1795         callback(result.services);
1796       },
1797       function(message) {
1798         failedCallback(message);
1799       }
1800     );
1801   }else{
1802     servicesForTypeClient.callService(request, function(result) {
1803       callback(result.services);
1804     });
1805   }
1806 };
1807
1808 /**
1809  * Retrieves a detail of ROS service request.
1810  *
1811  * @param service name of service:
1812  * @param callback - function with params:
1813  *   * type - String of the service type
1814  */
1815 Ros.prototype.getServiceRequestDetails = function(type, callback, failedCallback) {
1816   var serviceTypeClient = new Service({
1817     ros : this,
1818     name : '/rosapi/service_request_details',
1819     serviceType : 'rosapi/ServiceRequestDetails'
1820   });
1821   var request = new ServiceRequest({
1822     type: type
1823   });
1824
1825   if (typeof failedCallback === 'function'){
1826     serviceTypeClient.callService(request,
1827       function(result) {
1828         callback(result);
1829       },
1830       function(message){
1831         failedCallback(message);
1832       }
1833     );
1834   }else{
1835     serviceTypeClient.callService(request, function(result) {
1836       callback(result);
1837     });
1838   }
1839 };
1840
1841 /**
1842  * Retrieves a detail of ROS service request.
1843  *
1844  * @param service name of service:
1845  * @param callback - function with params:
1846  *   * type - String of the service type
1847  */
1848 Ros.prototype.getServiceResponseDetails = function(type, callback, failedCallback) {
1849   var serviceTypeClient = new Service({
1850     ros : this,
1851     name : '/rosapi/service_response_details',
1852     serviceType : 'rosapi/ServiceResponseDetails'
1853   });
1854   var request = new ServiceRequest({
1855     type: type
1856   });
1857
1858   if (typeof failedCallback === 'function'){
1859     serviceTypeClient.callService(request,
1860       function(result) {
1861         callback(result);
1862       },
1863       function(message){
1864         failedCallback(message);
1865       }
1866     );
1867   }else{
1868     serviceTypeClient.callService(request, function(result) {
1869       callback(result);
1870     });
1871   }
1872 };
1873
1874 /**
1875  * Retrieves list of active node names in ROS.
1876  *
1877  * @param callback - function with the following params:
1878  *   * nodes - array of node names
1879  */
1880 Ros.prototype.getNodes = function(callback, failedCallback) {
1881   var nodesClient = new Service({
1882     ros : this,
1883     name : '/rosapi/nodes',
1884     serviceType : 'rosapi/Nodes'
1885   });
1886
1887   var request = new ServiceRequest();
1888   if (typeof failedCallback === 'function'){
1889     nodesClient.callService(request,
1890       function(result) {
1891         callback(result.nodes);
1892       },
1893       function(message) {
1894         failedCallback(message);
1895       }
1896     );
1897   }else{
1898     nodesClient.callService(request, function(result) {
1899       callback(result.nodes);
1900     });
1901   }
1902 };
1903
1904 /**
1905   * Retrieves list subscribed topics, publishing topics and services of a specific node
1906   *
1907   * @param node name of the node:
1908   * @param callback - function with params:
1909   *   * publications - array of published topic names
1910   *   * subscriptions - array of subscribed topic names
1911   *   * services - array of service names hosted
1912   */
1913 Ros.prototype.getNodeDetails = function(node, callback, failedCallback) {
1914   var nodesClient = new Service({
1915     ros : this,
1916     name : '/rosapi/node_details',
1917     serviceType : 'rosapi/NodeDetails'
1918   });
1919
1920   var request = new ServiceRequest({
1921     node: node
1922   });
1923   if (typeof failedCallback === 'function'){
1924     nodesClient.callService(request,
1925       function(result) {
1926         callback(result.subscribing, result.publishing, result.services);
1927       },
1928       function(message) {
1929         failedCallback(message);
1930       }
1931     );
1932   } else {
1933     nodesClient.callService(request, function(result) {
1934       callback(result);
1935     });
1936   }
1937 };
1938
1939 /**
1940  * Retrieves list of param names from the ROS Parameter Server.
1941  *
1942  * @param callback function with params:
1943  *  * params - array of param names.
1944  */
1945 Ros.prototype.getParams = function(callback, failedCallback) {
1946   var paramsClient = new Service({
1947     ros : this,
1948     name : '/rosapi/get_param_names',
1949     serviceType : 'rosapi/GetParamNames'
1950   });
1951   var request = new ServiceRequest();
1952   if (typeof failedCallback === 'function'){
1953     paramsClient.callService(request,
1954       function(result) {
1955         callback(result.names);
1956       },
1957       function(message){
1958         failedCallback(message);
1959       }
1960     );
1961   }else{
1962     paramsClient.callService(request, function(result) {
1963       callback(result.names);
1964     });
1965   }
1966 };
1967
1968 /**
1969  * Retrieves a type of ROS topic.
1970  *
1971  * @param topic name of the topic:
1972  * @param callback - function with params:
1973  *   * type - String of the topic type
1974  */
1975 Ros.prototype.getTopicType = function(topic, callback, failedCallback) {
1976   var topicTypeClient = new Service({
1977     ros : this,
1978     name : '/rosapi/topic_type',
1979     serviceType : 'rosapi/TopicType'
1980   });
1981   var request = new ServiceRequest({
1982     topic: topic
1983   });
1984
1985   if (typeof failedCallback === 'function'){
1986     topicTypeClient.callService(request,
1987       function(result) {
1988         callback(result.type);
1989       },
1990       function(message){
1991         failedCallback(message);
1992       }
1993     );
1994   }else{
1995     topicTypeClient.callService(request, function(result) {
1996       callback(result.type);
1997     });
1998   }
1999 };
2000
2001 /**
2002  * Retrieves a type of ROS service.
2003  *
2004  * @param service name of service:
2005  * @param callback - function with params:
2006  *   * type - String of the service type
2007  */
2008 Ros.prototype.getServiceType = function(service, callback, failedCallback) {
2009   var serviceTypeClient = new Service({
2010     ros : this,
2011     name : '/rosapi/service_type',
2012     serviceType : 'rosapi/ServiceType'
2013   });
2014   var request = new ServiceRequest({
2015     service: service
2016   });
2017
2018   if (typeof failedCallback === 'function'){
2019     serviceTypeClient.callService(request,
2020       function(result) {
2021         callback(result.type);
2022       },
2023       function(message){
2024         failedCallback(message);
2025       }
2026     );
2027   }else{
2028     serviceTypeClient.callService(request, function(result) {
2029       callback(result.type);
2030     });
2031   }
2032 };
2033
2034 /**
2035  * Retrieves a detail of ROS message.
2036  *
2037  * @param callback - function with params:
2038  *   * details - Array of the message detail
2039  * @param message - String of a topic type
2040  */
2041 Ros.prototype.getMessageDetails = function(message, callback, failedCallback) {
2042   var messageDetailClient = new Service({
2043     ros : this,
2044     name : '/rosapi/message_details',
2045     serviceType : 'rosapi/MessageDetails'
2046   });
2047   var request = new ServiceRequest({
2048     type: message
2049   });
2050
2051   if (typeof failedCallback === 'function'){
2052     messageDetailClient.callService(request,
2053       function(result) {
2054         callback(result.typedefs);
2055       },
2056       function(message){
2057         failedCallback(message);
2058       }
2059     );
2060   }else{
2061     messageDetailClient.callService(request, function(result) {
2062       callback(result.typedefs);
2063     });
2064   }
2065 };
2066
2067 /**
2068  * Decode a typedefs into a dictionary like `rosmsg show foo/bar`
2069  *
2070  * @param defs - array of type_def dictionary
2071  */
2072 Ros.prototype.decodeTypeDefs = function(defs) {
2073   var that = this;
2074
2075   // calls itself recursively to resolve type definition using hints.
2076   var decodeTypeDefsRec = function(theType, hints) {
2077     var typeDefDict = {};
2078     for (var i = 0; i < theType.fieldnames.length; i++) {
2079       var arrayLen = theType.fieldarraylen[i];
2080       var fieldName = theType.fieldnames[i];
2081       var fieldType = theType.fieldtypes[i];
2082       if (fieldType.indexOf('/') === -1) { // check the fieldType includes '/' or not
2083         if (arrayLen === -1) {
2084           typeDefDict[fieldName] = fieldType;
2085         }
2086         else {
2087           typeDefDict[fieldName] = [fieldType];
2088         }
2089       }
2090       else {
2091         // lookup the name
2092         var sub = false;
2093         for (var j = 0; j < hints.length; j++) {
2094           if (hints[j].type.toString() === fieldType.toString()) {
2095             sub = hints[j];
2096             break;
2097           }
2098         }
2099         if (sub) {
2100           var subResult = decodeTypeDefsRec(sub, hints);
2101           if (arrayLen === -1) {
2102           }
2103           else {
2104             typeDefDict[fieldName] = [subResult];
2105           }
2106         }
2107         else {
2108           that.emit('error', 'Cannot find ' + fieldType + ' in decodeTypeDefs');
2109         }
2110       }
2111     }
2112     return typeDefDict;
2113   };
2114
2115   return decodeTypeDefsRec(defs[0], defs);
2116 };
2117
2118
2119 module.exports = Ros;
2120
2121 },{"./Service":13,"./ServiceRequest":14,"./SocketAdapter.js":16,"eventemitter2":1,"object-assign":2,"ws":39}],13:[function(require,module,exports){
2122 /**
2123  * @fileoverview
2124  * @author Brandon Alexander - baalexander@gmail.com
2125  */
2126
2127 var ServiceResponse = require('./ServiceResponse');
2128 var ServiceRequest = require('./ServiceRequest');
2129 var EventEmitter2 = require('eventemitter2').EventEmitter2;
2130
2131 /**
2132  * A ROS service client.
2133  *
2134  * @constructor
2135  * @params options - possible keys include:
2136  *   * ros - the ROSLIB.Ros connection handle
2137  *   * name - the service name, like /add_two_ints
2138  *   * serviceType - the service type, like 'rospy_tutorials/AddTwoInts'
2139  */
2140 function Service(options) {
2141   options = options || {};
2142   this.ros = options.ros;
2143   this.name = options.name;
2144   this.serviceType = options.serviceType;
2145   this.isAdvertised = false;
2146
2147   this._serviceCallback = null;
2148 }
2149 Service.prototype.__proto__ = EventEmitter2.prototype;
2150 /**
2151  * Calls the service. Returns the service response in the callback.
2152  *
2153  * @param request - the ROSLIB.ServiceRequest to send
2154  * @param callback - function with params:
2155  *   * response - the response from the service request
2156  * @param failedCallback - the callback function when the service call failed (optional). Params:
2157  *   * error - the error message reported by ROS
2158  */
2159 Service.prototype.callService = function(request, callback, failedCallback) {
2160   if (this.isAdvertised) {
2161     return;
2162   }
2163
2164   var serviceCallId = 'call_service:' + this.name + ':' + (++this.ros.idCounter);
2165
2166   if (callback || failedCallback) {
2167     this.ros.once(serviceCallId, function(message) {
2168       if (message.result !== undefined && message.result === false) {
2169         if (typeof failedCallback === 'function') {
2170           failedCallback(message.values);
2171         }
2172       } else if (typeof callback === 'function') {
2173         callback(new ServiceResponse(message.values));
2174       }
2175     });
2176   }
2177
2178   var call = {
2179     op : 'call_service',
2180     id : serviceCallId,
2181     service : this.name,
2182     args : request
2183   };
2184   this.ros.callOnConnection(call);
2185 };
2186
2187 /**
2188  * Every time a message is published for the given topic, the callback
2189  * will be called with the message object.
2190  *
2191  * @param callback - function with the following params:
2192  *   * message - the published message
2193  */
2194 Service.prototype.advertise = function(callback) {
2195   if (this.isAdvertised || typeof callback !== 'function') {
2196     return;
2197   }
2198
2199   this._serviceCallback = callback;
2200   this.ros.on(this.name, this._serviceResponse.bind(this));
2201   this.ros.callOnConnection({
2202     op: 'advertise_service',
2203     type: this.serviceType,
2204     service: this.name
2205   });
2206   this.isAdvertised = true;
2207 };
2208
2209 Service.prototype.unadvertise = function() {
2210   if (!this.isAdvertised) {
2211     return;
2212   }
2213   this.ros.callOnConnection({
2214     op: 'unadvertise_service',
2215     service: this.name
2216   });
2217   this.isAdvertised = false;
2218 };
2219
2220 Service.prototype._serviceResponse = function(rosbridgeRequest) {
2221   var response = {};
2222   var success = this._serviceCallback(rosbridgeRequest.args, response);
2223
2224   var call = {
2225     op: 'service_response',
2226     service: this.name,
2227     values: new ServiceResponse(response),
2228     result: success
2229   };
2230
2231   if (rosbridgeRequest.id) {
2232     call.id = rosbridgeRequest.id;
2233   }
2234
2235   this.ros.callOnConnection(call);
2236 };
2237
2238 module.exports = Service;
2239 },{"./ServiceRequest":14,"./ServiceResponse":15,"eventemitter2":1}],14:[function(require,module,exports){
2240 /**
2241  * @fileoverview
2242  * @author Brandon Alexander - balexander@willowgarage.com
2243  */
2244
2245 var assign = require('object-assign');
2246
2247 /**
2248  * A ServiceRequest is passed into the service call.
2249  *
2250  * @constructor
2251  * @param values - object matching the fields defined in the .srv definition file
2252  */
2253 function ServiceRequest(values) {
2254   assign(this, values);
2255 }
2256
2257 module.exports = ServiceRequest;
2258 },{"object-assign":2}],15:[function(require,module,exports){
2259 /**
2260  * @fileoverview
2261  * @author Brandon Alexander - balexander@willowgarage.com
2262  */
2263
2264 var assign = require('object-assign');
2265
2266 /**
2267  * A ServiceResponse is returned from the service call.
2268  *
2269  * @constructor
2270  * @param values - object matching the fields defined in the .srv definition file
2271  */
2272 function ServiceResponse(values) {
2273   assign(this, values);
2274 }
2275
2276 module.exports = ServiceResponse;
2277 },{"object-assign":2}],16:[function(require,module,exports){
2278 /**
2279  * Socket event handling utilities for handling events on either
2280  * WebSocket and TCP sockets
2281  *
2282  * Note to anyone reviewing this code: these functions are called
2283  * in the context of their parent object, unless bound
2284  * @fileOverview
2285  */
2286 'use strict';
2287
2288 var decompressPng = require('../util/decompressPng');
2289 var WebSocket = require('ws');
2290 var BSON = null;
2291 if(typeof bson !== 'undefined'){
2292     BSON = bson().BSON;
2293 }
2294
2295 /**
2296  * Events listeners for a WebSocket or TCP socket to a JavaScript
2297  * ROS Client. Sets up Messages for a given topic to trigger an
2298  * event on the ROS client.
2299  *
2300  * @namespace SocketAdapter
2301  * @private
2302  */
2303 function SocketAdapter(client) {
2304   function handleMessage(message) {
2305     if (message.op === 'publish') {
2306       client.emit(message.topic, message.msg);
2307     } else if (message.op === 'service_response') {
2308       client.emit(message.id, message);
2309     } else if (message.op === 'call_service') {
2310       client.emit(message.service, message);
2311     } else if(message.op === 'status'){
2312       if(message.id){
2313         client.emit('status:'+message.id, message);
2314       } else {
2315         client.emit('status', message);
2316       }
2317     }
2318   }
2319
2320   function handlePng(message, callback) {
2321     if (message.op === 'png') {
2322       decompressPng(message.data, callback);
2323     } else {
2324       callback(message);
2325     }
2326   }
2327
2328   function decodeBSON(data, callback) {
2329     if (!BSON) {
2330       throw 'Cannot process BSON encoded message without BSON header.';
2331     }
2332     var reader = new FileReader();
2333     reader.onload  = function() {
2334       var uint8Array = new Uint8Array(this.result);
2335       var msg = BSON.deserialize(uint8Array);
2336       callback(msg);
2337     };
2338     reader.readAsArrayBuffer(data);
2339   }
2340
2341   return {
2342     /**
2343      * Emits a 'connection' event on WebSocket connection.
2344      *
2345      * @param event - the argument to emit with the event.
2346      * @memberof SocketAdapter
2347      */
2348     onopen: function onOpen(event) {
2349       client.isConnected = true;
2350       client.emit('connection', event);
2351     },
2352
2353     /**
2354      * Emits a 'close' event on WebSocket disconnection.
2355      *
2356      * @param event - the argument to emit with the event.
2357      * @memberof SocketAdapter
2358      */
2359     onclose: function onClose(event) {
2360       client.isConnected = false;
2361       client.emit('close', event);
2362     },
2363
2364     /**
2365      * Emits an 'error' event whenever there was an error.
2366      *
2367      * @param event - the argument to emit with the event.
2368      * @memberof SocketAdapter
2369      */
2370     onerror: function onError(event) {
2371       client.emit('error', event);
2372     },
2373
2374     /**
2375      * Parses message responses from rosbridge and sends to the appropriate
2376      * topic, service, or param.
2377      *
2378      * @param message - the raw JSON message from rosbridge.
2379      * @memberof SocketAdapter
2380      */
2381     onmessage: function onMessage(data) {
2382       if (typeof Blob !== 'undefined' && data.data instanceof Blob) {
2383         decodeBSON(data.data, function (message) {
2384           handlePng(message, handleMessage);
2385         });
2386       } else {
2387         var message = JSON.parse(typeof data === 'string' ? data : data.data);
2388         handlePng(message, handleMessage);
2389       }
2390     }
2391   };
2392 }
2393
2394 module.exports = SocketAdapter;
2395
2396 },{"../util/decompressPng":41,"ws":39}],17:[function(require,module,exports){
2397 /**
2398  * @fileoverview
2399  * @author Brandon Alexander - baalexander@gmail.com
2400  */
2401
2402 var EventEmitter2 = require('eventemitter2').EventEmitter2;
2403 var Message = require('./Message');
2404
2405 /**
2406  * Publish and/or subscribe to a topic in ROS.
2407  *
2408  * Emits the following events:
2409  *  * 'warning' - if there are any warning during the Topic creation
2410  *  * 'message' - the message data from rosbridge
2411  *
2412  * @constructor
2413  * @param options - object with following keys:
2414  *   * ros - the ROSLIB.Ros connection handle
2415  *   * name - the topic name, like /cmd_vel
2416  *   * messageType - the message type, like 'std_msgs/String'
2417  *   * compression - the type of compression to use, like 'png'
2418  *   * throttle_rate - the rate (in ms in between messages) at which to throttle the topics
2419  *   * queue_size - the queue created at bridge side for re-publishing webtopics (defaults to 100)
2420  *   * latch - latch the topic when publishing
2421  *   * queue_length - the queue length at bridge side used when subscribing (defaults to 0, no queueing).
2422  *   * reconnect_on_close - the flag to enable resubscription and readvertisement on close event(defaults to true).
2423  */
2424 function Topic(options) {
2425   options = options || {};
2426   this.ros = options.ros;
2427   this.name = options.name;
2428   this.messageType = options.messageType;
2429   this.isAdvertised = false;
2430   this.compression = options.compression || 'none';
2431   this.throttle_rate = options.throttle_rate || 0;
2432   this.latch = options.latch || false;
2433   this.queue_size = options.queue_size || 100;
2434   this.queue_length = options.queue_length || 0;
2435   this.reconnect_on_close = options.reconnect_on_close || true;
2436
2437   // Check for valid compression types
2438   if (this.compression && this.compression !== 'png' &&
2439     this.compression !== 'none') {
2440     this.emit('warning', this.compression +
2441       ' compression is not supported. No compression will be used.');
2442   }
2443
2444   // Check if throttle rate is negative
2445   if (this.throttle_rate < 0) {
2446     this.emit('warning', this.throttle_rate + ' is not allowed. Set to 0');
2447     this.throttle_rate = 0;
2448   }
2449
2450   var that = this;
2451   if (this.reconnect_on_close) {
2452     this.callForSubscribeAndAdvertise = function(message) {
2453       that.ros.callOnConnection(message);
2454
2455       that.waitForReconnect = false;
2456       that.reconnectFunc = function() {
2457         if(!that.waitForReconnect) {
2458           that.waitForReconnect = true;
2459           that.ros.callOnConnection(message);
2460           that.ros.once('connection', function() {
2461             that.waitForReconnect = false;
2462           });
2463         }
2464       };
2465       that.ros.on('close', that.reconnectFunc);
2466     };
2467   }
2468   else {
2469     this.callForSubscribeAndAdvertise = this.ros.callOnConnection;
2470   }
2471
2472   this._messageCallback = function(data) {
2473     that.emit('message', new Message(data));
2474   };
2475 }
2476 Topic.prototype.__proto__ = EventEmitter2.prototype;
2477
2478 /**
2479  * Every time a message is published for the given topic, the callback
2480  * will be called with the message object.
2481  *
2482  * @param callback - function with the following params:
2483  *   * message - the published message
2484  */
2485 Topic.prototype.subscribe = function(callback) {
2486   if (typeof callback === 'function') {
2487     this.on('message', callback);
2488   }
2489
2490   if (this.subscribeId) { return; }
2491   this.ros.on(this.name, this._messageCallback);
2492   this.subscribeId = 'subscribe:' + this.name + ':' + (++this.ros.idCounter);
2493
2494   this.callForSubscribeAndAdvertise({
2495     op: 'subscribe',
2496     id: this.subscribeId,
2497     type: this.messageType,
2498     topic: this.name,
2499     compression: this.compression,
2500     throttle_rate: this.throttle_rate,
2501     queue_length: this.queue_length
2502   });
2503 };
2504
2505 /**
2506  * Unregisters as a subscriber for the topic. Unsubscribing stop remove
2507  * all subscribe callbacks. To remove a call back, you must explicitly
2508  * pass the callback function in.
2509  *
2510  * @param callback - the optional callback to unregister, if
2511  *     * provided and other listeners are registered the topic won't
2512  *     * unsubscribe, just stop emitting to the passed listener
2513  */
2514 Topic.prototype.unsubscribe = function(callback) {
2515   if (callback) {
2516     this.off('message', callback);
2517     // If there is any other callbacks still subscribed don't unsubscribe
2518     if (this.listeners('message').length) { return; }
2519   }
2520   if (!this.subscribeId) { return; }
2521   // Note: Don't call this.removeAllListeners, allow client to handle that themselves
2522   this.ros.off(this.name, this._messageCallback);
2523   if(this.reconnect_on_close) {
2524     this.ros.off('close', this.reconnectFunc);
2525   }
2526   this.emit('unsubscribe');
2527   this.ros.callOnConnection({
2528     op: 'unsubscribe',
2529     id: this.subscribeId,
2530     topic: this.name
2531   });
2532   this.subscribeId = null;
2533 };
2534
2535
2536 /**
2537  * Registers as a publisher for the topic.
2538  */
2539 Topic.prototype.advertise = function() {
2540   if (this.isAdvertised) {
2541     return;
2542   }
2543   this.advertiseId = 'advertise:' + this.name + ':' + (++this.ros.idCounter);
2544   this.callForSubscribeAndAdvertise({
2545     op: 'advertise',
2546     id: this.advertiseId,
2547     type: this.messageType,
2548     topic: this.name,
2549     latch: this.latch,
2550     queue_size: this.queue_size
2551   });
2552   this.isAdvertised = true;
2553
2554   if(!this.reconnect_on_close) {
2555     var that = this;
2556     this.ros.on('close', function() {
2557       that.isAdvertised = false;
2558     });
2559   }
2560 };
2561
2562 /**
2563  * Unregisters as a publisher for the topic.
2564  */
2565 Topic.prototype.unadvertise = function() {
2566   if (!this.isAdvertised) {
2567     return;
2568   }
2569   if(this.reconnect_on_close) {
2570     this.ros.off('close', this.reconnectFunc);
2571   }
2572   this.emit('unadvertise');
2573   this.ros.callOnConnection({
2574     op: 'unadvertise',
2575     id: this.advertiseId,
2576     topic: this.name
2577   });
2578   this.isAdvertised = false;
2579 };
2580
2581 /**
2582  * Publish the message.
2583  *
2584  * @param message - A ROSLIB.Message object.
2585  */
2586 Topic.prototype.publish = function(message) {
2587   if (!this.isAdvertised) {
2588     this.advertise();
2589   }
2590
2591   this.ros.idCounter++;
2592   var call = {
2593     op: 'publish',
2594     id: 'publish:' + this.name + ':' + this.ros.idCounter,
2595     topic: this.name,
2596     msg: message,
2597     latch: this.latch
2598   };
2599   this.ros.callOnConnection(call);
2600 };
2601
2602 module.exports = Topic;
2603
2604 },{"./Message":10,"eventemitter2":1}],18:[function(require,module,exports){
2605 var mixin = require('../mixin');
2606
2607 var core = module.exports = {
2608     Ros: require('./Ros'),
2609     Topic: require('./Topic'),
2610     Message: require('./Message'),
2611     Param: require('./Param'),
2612     Service: require('./Service'),
2613     ServiceRequest: require('./ServiceRequest'),
2614     ServiceResponse: require('./ServiceResponse')
2615 };
2616
2617 mixin(core.Ros, ['Param', 'Service', 'Topic'], core);
2618
2619 },{"../mixin":24,"./Message":10,"./Param":11,"./Ros":12,"./Service":13,"./ServiceRequest":14,"./ServiceResponse":15,"./Topic":17}],19:[function(require,module,exports){
2620 /**
2621  * @fileoverview
2622  * @author David Gossow - dgossow@willowgarage.com
2623  */
2624
2625 var Vector3 = require('./Vector3');
2626 var Quaternion = require('./Quaternion');
2627
2628 /**
2629  * A Pose in 3D space. Values are copied into this object.
2630  *
2631  *  @constructor
2632  *  @param options - object with following keys:
2633  *   * position - the Vector3 describing the position
2634  *   * orientation - the ROSLIB.Quaternion describing the orientation
2635  */
2636 function Pose(options) {
2637   options = options || {};
2638   // copy the values into this object if they exist
2639   this.position = new Vector3(options.position);
2640   this.orientation = new Quaternion(options.orientation);
2641 }
2642
2643 /**
2644  * Apply a transform against this pose.
2645  *
2646  * @param tf the transform
2647  */
2648 Pose.prototype.applyTransform = function(tf) {
2649   this.position.multiplyQuaternion(tf.rotation);
2650   this.position.add(tf.translation);
2651   var tmp = tf.rotation.clone();
2652   tmp.multiply(this.orientation);
2653   this.orientation = tmp;
2654 };
2655
2656 /**
2657  * Clone a copy of this pose.
2658  *
2659  * @returns the cloned pose
2660  */
2661 Pose.prototype.clone = function() {
2662   return new Pose(this);
2663 };
2664
2665 module.exports = Pose;
2666 },{"./Quaternion":20,"./Vector3":22}],20:[function(require,module,exports){
2667 /**
2668  * @fileoverview
2669  * @author David Gossow - dgossow@willowgarage.com
2670  */
2671
2672 /**
2673  * A Quaternion.
2674  *
2675  *  @constructor
2676  *  @param options - object with following keys:
2677  *   * x - the x value
2678  *   * y - the y value
2679  *   * z - the z value
2680  *   * w - the w value
2681  */
2682 function Quaternion(options) {
2683   options = options || {};
2684   this.x = options.x || 0;
2685   this.y = options.y || 0;
2686   this.z = options.z || 0;
2687   this.w = (typeof options.w === 'number') ? options.w : 1;
2688 }
2689
2690 /**
2691  * Perform a conjugation on this quaternion.
2692  */
2693 Quaternion.prototype.conjugate = function() {
2694   this.x *= -1;
2695   this.y *= -1;
2696   this.z *= -1;
2697 };
2698
2699 /**
2700  * Return the norm of this quaternion.
2701  */
2702 Quaternion.prototype.norm = function() {
2703   return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
2704 };
2705
2706 /**
2707  * Perform a normalization on this quaternion.
2708  */
2709 Quaternion.prototype.normalize = function() {
2710   var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
2711   if (l === 0) {
2712     this.x = 0;
2713     this.y = 0;
2714     this.z = 0;
2715     this.w = 1;
2716   } else {
2717     l = 1 / l;
2718     this.x = this.x * l;
2719     this.y = this.y * l;
2720     this.z = this.z * l;
2721     this.w = this.w * l;
2722   }
2723 };
2724
2725 /**
2726  * Convert this quaternion into its inverse.
2727  */
2728 Quaternion.prototype.invert = function() {
2729   this.conjugate();
2730   this.normalize();
2731 };
2732
2733 /**
2734  * Set the values of this quaternion to the product of itself and the given quaternion.
2735  *
2736  * @param q the quaternion to multiply with
2737  */
2738 Quaternion.prototype.multiply = function(q) {
2739   var newX = this.x * q.w + this.y * q.z - this.z * q.y + this.w * q.x;
2740   var newY = -this.x * q.z + this.y * q.w + this.z * q.x + this.w * q.y;
2741   var newZ = this.x * q.y - this.y * q.x + this.z * q.w + this.w * q.z;
2742   var newW = -this.x * q.x - this.y * q.y - this.z * q.z + this.w * q.w;
2743   this.x = newX;
2744   this.y = newY;
2745   this.z = newZ;
2746   this.w = newW;
2747 };
2748
2749 /**
2750  * Clone a copy of this quaternion.
2751  *
2752  * @returns the cloned quaternion
2753  */
2754 Quaternion.prototype.clone = function() {
2755   return new Quaternion(this);
2756 };
2757
2758 module.exports = Quaternion;
2759
2760 },{}],21:[function(require,module,exports){
2761 /**
2762  * @fileoverview
2763  * @author David Gossow - dgossow@willowgarage.com
2764  */
2765
2766 var Vector3 = require('./Vector3');
2767 var Quaternion = require('./Quaternion');
2768
2769 /**
2770  * A Transform in 3-space. Values are copied into this object.
2771  *
2772  *  @constructor
2773  *  @param options - object with following keys:
2774  *   * translation - the Vector3 describing the translation
2775  *   * rotation - the ROSLIB.Quaternion describing the rotation
2776  */
2777 function Transform(options) {
2778   options = options || {};
2779   // Copy the values into this object if they exist
2780   this.translation = new Vector3(options.translation);
2781   this.rotation = new Quaternion(options.rotation);
2782 }
2783
2784 /**
2785  * Clone a copy of this transform.
2786  *
2787  * @returns the cloned transform
2788  */
2789 Transform.prototype.clone = function() {
2790   return new Transform(this);
2791 };
2792
2793 module.exports = Transform;
2794 },{"./Quaternion":20,"./Vector3":22}],22:[function(require,module,exports){
2795 /**
2796  * @fileoverview
2797  * @author David Gossow - dgossow@willowgarage.com
2798  */
2799
2800 /**
2801  * A 3D vector.
2802  *
2803  *  @constructor
2804  *  @param options - object with following keys:
2805  *   * x - the x value
2806  *   * y - the y value
2807  *   * z - the z value
2808  */
2809 function Vector3(options) {
2810   options = options || {};
2811   this.x = options.x || 0;
2812   this.y = options.y || 0;
2813   this.z = options.z || 0;
2814 }
2815
2816 /**
2817  * Set the values of this vector to the sum of itself and the given vector.
2818  *
2819  * @param v the vector to add with
2820  */
2821 Vector3.prototype.add = function(v) {
2822   this.x += v.x;
2823   this.y += v.y;
2824   this.z += v.z;
2825 };
2826
2827 /**
2828  * Set the values of this vector to the difference of itself and the given vector.
2829  *
2830  * @param v the vector to subtract with
2831  */
2832 Vector3.prototype.subtract = function(v) {
2833   this.x -= v.x;
2834   this.y -= v.y;
2835   this.z -= v.z;
2836 };
2837
2838 /**
2839  * Multiply the given Quaternion with this vector.
2840  *
2841  * @param q - the quaternion to multiply with
2842  */
2843 Vector3.prototype.multiplyQuaternion = function(q) {
2844   var ix = q.w * this.x + q.y * this.z - q.z * this.y;
2845   var iy = q.w * this.y + q.z * this.x - q.x * this.z;
2846   var iz = q.w * this.z + q.x * this.y - q.y * this.x;
2847   var iw = -q.x * this.x - q.y * this.y - q.z * this.z;
2848   this.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;
2849   this.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;
2850   this.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;
2851 };
2852
2853 /**
2854  * Clone a copy of this vector.
2855  *
2856  * @returns the cloned vector
2857  */
2858 Vector3.prototype.clone = function() {
2859   return new Vector3(this);
2860 };
2861
2862 module.exports = Vector3;
2863 },{}],23:[function(require,module,exports){
2864 module.exports = {
2865     Pose: require('./Pose'),
2866     Quaternion: require('./Quaternion'),
2867     Transform: require('./Transform'),
2868     Vector3: require('./Vector3')
2869 };
2870
2871 },{"./Pose":19,"./Quaternion":20,"./Transform":21,"./Vector3":22}],24:[function(require,module,exports){
2872 /**
2873  * Mixin a feature to the core/Ros prototype.
2874  * For example, mixin(Ros, ['Topic'], {Topic: <Topic>})
2875  * will add a topic bound to any Ros instances so a user
2876  * can call `var topic = ros.Topic({name: '/foo'});`
2877  *
2878  * @author Graeme Yeates - github.com/megawac
2879  */
2880 module.exports = function(Ros, classes, features) {
2881     classes.forEach(function(className) {
2882         var Class = features[className];
2883         Ros.prototype[className] = function(options) {
2884             options.ros = this;
2885             return new Class(options);
2886         };
2887     });
2888 };
2889
2890 },{}],25:[function(require,module,exports){
2891 /**
2892  * @fileoverview
2893  * @author David Gossow - dgossow@willowgarage.com
2894  */
2895
2896 var ActionClient = require('../actionlib/ActionClient');
2897 var Goal = require('../actionlib/Goal');
2898
2899 var Service = require('../core/Service.js');
2900 var ServiceRequest = require('../core/ServiceRequest.js');
2901
2902 var Transform = require('../math/Transform');
2903
2904 /**
2905  * A TF Client that listens to TFs from tf2_web_republisher.
2906  *
2907  *  @constructor
2908  *  @param options - object with following keys:
2909  *   * ros - the ROSLIB.Ros connection handle
2910  *   * fixedFrame - the fixed frame, like /base_link
2911  *   * angularThres - the angular threshold for the TF republisher
2912  *   * transThres - the translation threshold for the TF republisher
2913  *   * rate - the rate for the TF republisher
2914  *   * updateDelay - the time (in ms) to wait after a new subscription
2915  *                   to update the TF republisher's list of TFs
2916  *   * topicTimeout - the timeout parameter for the TF republisher
2917  *   * serverName (optional) - the name of the tf2_web_republisher server
2918  *   * repubServiceName (optional) - the name of the republish_tfs service (non groovy compatibility mode only)
2919  *                                                                                                                               default: '/republish_tfs'
2920  */
2921 function TFClient(options) {
2922   options = options || {};
2923   this.ros = options.ros;
2924   this.fixedFrame = options.fixedFrame || '/base_link';
2925   this.angularThres = options.angularThres || 2.0;
2926   this.transThres = options.transThres || 0.01;
2927   this.rate = options.rate || 10.0;
2928   this.updateDelay = options.updateDelay || 50;
2929   var seconds = options.topicTimeout || 2.0;
2930   var secs = Math.floor(seconds);
2931   var nsecs = Math.floor((seconds - secs) * 1000000000);
2932   this.topicTimeout = {
2933     secs: secs,
2934     nsecs: nsecs
2935   };
2936   this.serverName = options.serverName || '/tf2_web_republisher';
2937   this.repubServiceName = options.repubServiceName || '/republish_tfs';
2938
2939   this.currentGoal = false;
2940   this.currentTopic = false;
2941   this.frameInfos = {};
2942   this.republisherUpdateRequested = false;
2943
2944   // Create an Action client
2945   this.actionClient = this.ros.ActionClient({
2946     serverName : this.serverName,
2947     actionName : 'tf2_web_republisher/TFSubscriptionAction',
2948     omitStatus : true,
2949     omitResult : true
2950   });
2951
2952   // Create a Service client
2953   this.serviceClient = this.ros.Service({
2954     name: this.repubServiceName,
2955     serviceType: 'tf2_web_republisher/RepublishTFs'
2956   });
2957 }
2958
2959 /**
2960  * Process the incoming TF message and send them out using the callback
2961  * functions.
2962  *
2963  * @param tf - the TF message from the server
2964  */
2965 TFClient.prototype.processTFArray = function(tf) {
2966   var that = this;
2967   tf.transforms.forEach(function(transform) {
2968     var frameID = transform.child_frame_id;
2969     if (frameID[0] === '/')
2970     {
2971       frameID = frameID.substring(1);
2972     }
2973     var info = this.frameInfos[frameID];
2974     if (info) {
2975       info.transform = new Transform({
2976         translation : transform.transform.translation,
2977         rotation : transform.transform.rotation
2978       });
2979       info.cbs.forEach(function(cb) {
2980         cb(info.transform);
2981       });
2982     }
2983   }, this);
2984 };
2985
2986 /**
2987  * Create and send a new goal (or service request) to the tf2_web_republisher
2988  * based on the current list of TFs.
2989  */
2990 TFClient.prototype.updateGoal = function() {
2991   var goalMessage = {
2992     source_frames : Object.keys(this.frameInfos),
2993     target_frame : this.fixedFrame,
2994     angular_thres : this.angularThres,
2995     trans_thres : this.transThres,
2996     rate : this.rate
2997   };
2998
2999   // if we're running in groovy compatibility mode (the default)
3000   // then use the action interface to tf2_web_republisher
3001   if(this.ros.groovyCompatibility) {
3002     if (this.currentGoal) {
3003       this.currentGoal.cancel();
3004     }
3005     this.currentGoal = new Goal({
3006       actionClient : this.actionClient,
3007       goalMessage : goalMessage
3008     });
3009
3010     this.currentGoal.on('feedback', this.processTFArray.bind(this));
3011     this.currentGoal.send();
3012   }
3013   else {
3014     // otherwise, use the service interface
3015     // The service interface has the same parameters as the action,
3016     // plus the timeout
3017     goalMessage.timeout = this.topicTimeout;
3018     var request = new ServiceRequest(goalMessage);
3019
3020     this.serviceClient.callService(request, this.processResponse.bind(this));
3021   }
3022
3023   this.republisherUpdateRequested = false;
3024 };
3025
3026 /**
3027  * Process the service response and subscribe to the tf republisher
3028  * topic
3029  *
3030  * @param response the service response containing the topic name
3031  */
3032 TFClient.prototype.processResponse = function(response) {
3033   // if we subscribed to a topic before, unsubscribe so
3034   // the republisher stops publishing it
3035   if (this.currentTopic) {
3036     this.currentTopic.unsubscribe();
3037   }
3038
3039   this.currentTopic = this.ros.Topic({
3040     name: response.topic_name,
3041     messageType: 'tf2_web_republisher/TFArray'
3042   });
3043   this.currentTopic.subscribe(this.processTFArray.bind(this));
3044 };
3045
3046 /**
3047  * Subscribe to the given TF frame.
3048  *
3049  * @param frameID - the TF frame to subscribe to
3050  * @param callback - function with params:
3051  *   * transform - the transform data
3052  */
3053 TFClient.prototype.subscribe = function(frameID, callback) {
3054   // remove leading slash, if it's there
3055   if (frameID[0] === '/')
3056   {
3057     frameID = frameID.substring(1);
3058   }
3059   // if there is no callback registered for the given frame, create emtpy callback list
3060   if (!this.frameInfos[frameID]) {
3061     this.frameInfos[frameID] = {
3062       cbs: []
3063     };
3064     if (!this.republisherUpdateRequested) {
3065       setTimeout(this.updateGoal.bind(this), this.updateDelay);
3066       this.republisherUpdateRequested = true;
3067     }
3068   }
3069   // if we already have a transform, call back immediately
3070   else if (this.frameInfos[frameID].transform) {
3071     callback(this.frameInfos[frameID].transform);
3072   }
3073   this.frameInfos[frameID].cbs.push(callback);
3074 };
3075
3076 /**
3077  * Unsubscribe from the given TF frame.
3078  *
3079  * @param frameID - the TF frame to unsubscribe from
3080  * @param callback - the callback function to remove
3081  */
3082 TFClient.prototype.unsubscribe = function(frameID, callback) {
3083   // remove leading slash, if it's there
3084   if (frameID[0] === '/')
3085   {
3086     frameID = frameID.substring(1);
3087   }
3088   var info = this.frameInfos[frameID];
3089   for (var cbs = info && info.cbs || [], idx = cbs.length; idx--;) {
3090     if (cbs[idx] === callback) {
3091       cbs.splice(idx, 1);
3092     }
3093   }
3094   if (!callback || cbs.length === 0) {
3095     delete this.frameInfos[frameID];
3096   }
3097 };
3098
3099 /**
3100  * Unsubscribe and unadvertise all topics associated with this TFClient.
3101  */
3102 TFClient.prototype.dispose = function() {
3103   this.actionClient.dispose();
3104   if (this.currentTopic) {
3105     this.currentTopic.unsubscribe();
3106   }
3107 };
3108
3109 module.exports = TFClient;
3110
3111 },{"../actionlib/ActionClient":5,"../actionlib/Goal":7,"../core/Service.js":13,"../core/ServiceRequest.js":14,"../math/Transform":21}],26:[function(require,module,exports){
3112 var Ros = require('../core/Ros');
3113 var mixin = require('../mixin');
3114
3115 var tf = module.exports = {
3116     TFClient: require('./TFClient')
3117 };
3118
3119 mixin(Ros, ['TFClient'], tf);
3120 },{"../core/Ros":12,"../mixin":24,"./TFClient":25}],27:[function(require,module,exports){
3121 /**
3122  * @fileOverview 
3123  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3124  * @author Russell Toris - rctoris@wpi.edu
3125  */
3126
3127 var Vector3 = require('../math/Vector3');
3128 var UrdfTypes = require('./UrdfTypes');
3129
3130 /**
3131  * A Box element in a URDF.
3132  *
3133  * @constructor
3134  * @param options - object with following keys:
3135  *  * xml - the XML element to parse
3136  */
3137 function UrdfBox(options) {
3138   this.dimension = null;
3139   this.type = UrdfTypes.URDF_BOX;
3140
3141   // Parse the xml string
3142   var xyz = options.xml.getAttribute('size').split(' ');
3143   this.dimension = new Vector3({
3144     x : parseFloat(xyz[0]),
3145     y : parseFloat(xyz[1]),
3146     z : parseFloat(xyz[2])
3147   });
3148 }
3149
3150 module.exports = UrdfBox;
3151 },{"../math/Vector3":22,"./UrdfTypes":36}],28:[function(require,module,exports){
3152 /**
3153  * @fileOverview 
3154  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3155  * @author Russell Toris - rctoris@wpi.edu
3156  */
3157
3158 /**
3159  * A Color element in a URDF.
3160  *
3161  * @constructor
3162  * @param options - object with following keys:
3163  *  * xml - the XML element to parse
3164  */
3165 function UrdfColor(options) {
3166   // Parse the xml string
3167   var rgba = options.xml.getAttribute('rgba').split(' ');
3168   this.r = parseFloat(rgba[0]);
3169   this.g = parseFloat(rgba[1]);
3170   this.b = parseFloat(rgba[2]);
3171   this.a = parseFloat(rgba[3]);
3172 }
3173
3174 module.exports = UrdfColor;
3175 },{}],29:[function(require,module,exports){
3176 /**
3177  * @fileOverview 
3178  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3179  * @author Russell Toris - rctoris@wpi.edu
3180  */
3181
3182 var UrdfTypes = require('./UrdfTypes');
3183
3184 /**
3185  * A Cylinder element in a URDF.
3186  *
3187  * @constructor
3188  * @param options - object with following keys:
3189  *  * xml - the XML element to parse
3190  */
3191 function UrdfCylinder(options) {
3192   this.type = UrdfTypes.URDF_CYLINDER;
3193   this.length = parseFloat(options.xml.getAttribute('length'));
3194   this.radius = parseFloat(options.xml.getAttribute('radius'));
3195 }
3196
3197 module.exports = UrdfCylinder;
3198 },{"./UrdfTypes":36}],30:[function(require,module,exports){
3199 /**
3200  * @fileOverview
3201  * @author David V. Lu!!  davidvlu@gmail.com
3202  */
3203
3204 /**
3205  * A Joint element in a URDF.
3206  *
3207  * @constructor
3208  * @param options - object with following keys:
3209  *  * xml - the XML element to parse
3210  */
3211 function UrdfJoint(options) {
3212   this.name = options.xml.getAttribute('name');
3213   this.type = options.xml.getAttribute('type');
3214
3215   var parents = options.xml.getElementsByTagName('parent');
3216   if(parents.length > 0) {
3217     this.parent = parents[0].getAttribute('link');
3218   }
3219
3220   var children = options.xml.getElementsByTagName('child');
3221   if(children.length > 0) {
3222     this.child = children[0].getAttribute('link');
3223   }
3224
3225   var limits = options.xml.getElementsByTagName('limit');
3226   if (limits.length > 0) {
3227     this.minval = parseFloat( limits[0].getAttribute('lower') );
3228     this.maxval = parseFloat( limits[0].getAttribute('upper') );
3229   }
3230 }
3231
3232 module.exports = UrdfJoint;
3233
3234 },{}],31:[function(require,module,exports){
3235 /**
3236  * @fileOverview 
3237  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3238  * @author Russell Toris - rctoris@wpi.edu
3239  */
3240
3241 var UrdfVisual = require('./UrdfVisual');
3242
3243 /**
3244  * A Link element in a URDF.
3245  *
3246  * @constructor
3247  * @param options - object with following keys:
3248  *  * xml - the XML element to parse
3249  */
3250 function UrdfLink(options) {
3251   this.name = options.xml.getAttribute('name');
3252   this.visuals = [];
3253   var visuals = options.xml.getElementsByTagName('visual');
3254
3255   for( var i=0; i<visuals.length; i++ ) {
3256     this.visuals.push( new UrdfVisual({
3257       xml : visuals[i]
3258     }) );
3259   }
3260 }
3261
3262 module.exports = UrdfLink;
3263 },{"./UrdfVisual":37}],32:[function(require,module,exports){
3264 /**
3265  * @fileOverview 
3266  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3267  * @author Russell Toris - rctoris@wpi.edu
3268  */
3269
3270 var UrdfColor = require('./UrdfColor');
3271
3272 /**
3273  * A Material element in a URDF.
3274  *
3275  * @constructor
3276  * @param options - object with following keys:
3277  *  * xml - the XML element to parse
3278  */
3279 function UrdfMaterial(options) {
3280   this.textureFilename = null;
3281   this.color = null;
3282
3283   this.name = options.xml.getAttribute('name');
3284
3285   // Texture
3286   var textures = options.xml.getElementsByTagName('texture');
3287   if (textures.length > 0) {
3288     this.textureFilename = textures[0].getAttribute('filename');
3289   }
3290
3291   // Color
3292   var colors = options.xml.getElementsByTagName('color');
3293   if (colors.length > 0) {
3294     // Parse the RBGA string
3295     this.color = new UrdfColor({
3296       xml : colors[0]
3297     });
3298   }
3299 }
3300
3301 UrdfMaterial.prototype.isLink = function() {
3302   return this.color === null && this.textureFilename === null;
3303 };
3304
3305 var assign = require('object-assign');
3306
3307 UrdfMaterial.prototype.assign = function(obj) {
3308     return assign(this, obj);
3309 };
3310
3311 module.exports = UrdfMaterial;
3312
3313 },{"./UrdfColor":28,"object-assign":2}],33:[function(require,module,exports){
3314 /**
3315  * @fileOverview 
3316  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3317  * @author Russell Toris - rctoris@wpi.edu
3318  */
3319
3320 var Vector3 = require('../math/Vector3');
3321 var UrdfTypes = require('./UrdfTypes');
3322
3323 /**
3324  * A Mesh element in a URDF.
3325  *
3326  * @constructor
3327  * @param options - object with following keys:
3328  *  * xml - the XML element to parse
3329  */
3330 function UrdfMesh(options) {
3331   this.scale = null;
3332
3333   this.type = UrdfTypes.URDF_MESH;
3334   this.filename = options.xml.getAttribute('filename');
3335
3336   // Check for a scale
3337   var scale = options.xml.getAttribute('scale');
3338   if (scale) {
3339     // Get the XYZ
3340     var xyz = scale.split(' ');
3341     this.scale = new Vector3({
3342       x : parseFloat(xyz[0]),
3343       y : parseFloat(xyz[1]),
3344       z : parseFloat(xyz[2])
3345     });
3346   }
3347 }
3348
3349 module.exports = UrdfMesh;
3350 },{"../math/Vector3":22,"./UrdfTypes":36}],34:[function(require,module,exports){
3351 /**
3352  * @fileOverview 
3353  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3354  * @author Russell Toris - rctoris@wpi.edu
3355  */
3356
3357 var UrdfMaterial = require('./UrdfMaterial');
3358 var UrdfLink = require('./UrdfLink');
3359 var UrdfJoint = require('./UrdfJoint');
3360 var DOMParser = require('xmldom').DOMParser;
3361
3362 // See https://developer.mozilla.org/docs/XPathResult#Constants
3363 var XPATH_FIRST_ORDERED_NODE_TYPE = 9;
3364
3365 /**
3366  * A URDF Model can be used to parse a given URDF into the appropriate elements.
3367  *
3368  * @constructor
3369  * @param options - object with following keys:
3370  *  * xml - the XML element to parse
3371  *  * string - the XML element to parse as a string
3372  */
3373 function UrdfModel(options) {
3374   options = options || {};
3375   var xmlDoc = options.xml;
3376   var string = options.string;
3377   this.materials = {};
3378   this.links = {};
3379   this.joints = {};
3380
3381   // Check if we are using a string or an XML element
3382   if (string) {
3383     // Parse the string
3384     var parser = new DOMParser();
3385     xmlDoc = parser.parseFromString(string, 'text/xml');
3386   }
3387
3388   // Initialize the model with the given XML node.
3389   // Get the robot tag
3390   var robotXml = xmlDoc.documentElement;
3391
3392   // Get the robot name
3393   this.name = robotXml.getAttribute('name');
3394
3395   // Parse all the visual elements we need
3396   for (var nodes = robotXml.childNodes, i = 0; i < nodes.length; i++) {
3397     var node = nodes[i];
3398     if (node.tagName === 'material') {
3399       var material = new UrdfMaterial({
3400         xml : node
3401       });
3402       // Make sure this is unique
3403       if (this.materials[material.name] !== void 0) {
3404         if( this.materials[material.name].isLink() ) {
3405           this.materials[material.name].assign( material );
3406         } else {
3407           console.warn('Material ' + material.name + 'is not unique.');
3408         }
3409       } else {
3410         this.materials[material.name] = material;
3411       }
3412     } else if (node.tagName === 'link') {
3413       var link = new UrdfLink({
3414         xml : node
3415       });
3416       // Make sure this is unique
3417       if (this.links[link.name] !== void 0) {
3418         console.warn('Link ' + link.name + ' is not unique.');
3419       } else {
3420         // Check for a material
3421         for( var j=0; j<link.visuals.length; j++ )
3422         {
3423           var mat = link.visuals[j].material; 
3424           if ( mat !== null ) {
3425             if (this.materials[mat.name] !== void 0) {
3426               link.visuals[j].material = this.materials[mat.name];
3427             } else {
3428               this.materials[mat.name] = mat;
3429             }
3430           }
3431         }
3432
3433         // Add the link
3434         this.links[link.name] = link;
3435       }
3436     } else if (node.tagName === 'joint') {
3437       var joint = new UrdfJoint({
3438         xml : node
3439       });
3440       this.joints[joint.name] = joint;
3441     }
3442   }
3443 }
3444
3445 module.exports = UrdfModel;
3446
3447 },{"./UrdfJoint":30,"./UrdfLink":31,"./UrdfMaterial":32,"xmldom":42}],35:[function(require,module,exports){
3448 /**
3449  * @fileOverview 
3450  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3451  * @author Russell Toris - rctoris@wpi.edu
3452  */
3453
3454 var UrdfTypes = require('./UrdfTypes');
3455
3456 /**
3457  * A Sphere element in a URDF.
3458  *
3459  * @constructor
3460  * @param options - object with following keys:
3461  *  * xml - the XML element to parse
3462  */
3463 function UrdfSphere(options) {
3464   this.type = UrdfTypes.URDF_SPHERE;
3465   this.radius = parseFloat(options.xml.getAttribute('radius'));
3466 }
3467
3468 module.exports = UrdfSphere;
3469 },{"./UrdfTypes":36}],36:[function(require,module,exports){
3470 module.exports = {
3471         URDF_SPHERE : 0,
3472         URDF_BOX : 1,
3473         URDF_CYLINDER : 2,
3474         URDF_MESH : 3
3475 };
3476
3477 },{}],37:[function(require,module,exports){
3478 /**
3479  * @fileOverview 
3480  * @author Benjamin Pitzer - ben.pitzer@gmail.com
3481  * @author Russell Toris - rctoris@wpi.edu
3482  */
3483
3484 var Pose = require('../math/Pose');
3485 var Vector3 = require('../math/Vector3');
3486 var Quaternion = require('../math/Quaternion');
3487
3488 var UrdfCylinder = require('./UrdfCylinder');
3489 var UrdfBox = require('./UrdfBox');
3490 var UrdfMaterial = require('./UrdfMaterial');
3491 var UrdfMesh = require('./UrdfMesh');
3492 var UrdfSphere = require('./UrdfSphere');
3493
3494 /**
3495  * A Visual element in a URDF.
3496  *
3497  * @constructor
3498  * @param options - object with following keys:
3499  *  * xml - the XML element to parse
3500  */
3501 function UrdfVisual(options) {
3502   var xml = options.xml;
3503   this.origin = null;
3504   this.geometry = null;
3505   this.material = null;
3506
3507   // Origin
3508   var origins = xml.getElementsByTagName('origin');
3509   if (origins.length === 0) {
3510     // use the identity as the default
3511     this.origin = new Pose();
3512   } else {
3513     // Check the XYZ
3514     var xyz = origins[0].getAttribute('xyz');
3515     var position = new Vector3();
3516     if (xyz) {
3517       xyz = xyz.split(' ');
3518       position = new Vector3({
3519         x : parseFloat(xyz[0]),
3520         y : parseFloat(xyz[1]),
3521         z : parseFloat(xyz[2])
3522       });
3523     }
3524
3525     // Check the RPY
3526     var rpy = origins[0].getAttribute('rpy');
3527     var orientation = new Quaternion();
3528     if (rpy) {
3529       rpy = rpy.split(' ');
3530       // Convert from RPY
3531       var roll = parseFloat(rpy[0]);
3532       var pitch = parseFloat(rpy[1]);
3533       var yaw = parseFloat(rpy[2]);
3534       var phi = roll / 2.0;
3535       var the = pitch / 2.0;
3536       var psi = yaw / 2.0;
3537       var x = Math.sin(phi) * Math.cos(the) * Math.cos(psi) - Math.cos(phi) * Math.sin(the)
3538           * Math.sin(psi);
3539       var y = Math.cos(phi) * Math.sin(the) * Math.cos(psi) + Math.sin(phi) * Math.cos(the)
3540           * Math.sin(psi);
3541       var z = Math.cos(phi) * Math.cos(the) * Math.sin(psi) - Math.sin(phi) * Math.sin(the)
3542           * Math.cos(psi);
3543       var w = Math.cos(phi) * Math.cos(the) * Math.cos(psi) + Math.sin(phi) * Math.sin(the)
3544           * Math.sin(psi);
3545
3546       orientation = new Quaternion({
3547         x : x,
3548         y : y,
3549         z : z,
3550         w : w
3551       });
3552       orientation.normalize();
3553     }
3554     this.origin = new Pose({
3555       position : position,
3556       orientation : orientation
3557     });
3558   }
3559
3560   // Geometry
3561   var geoms = xml.getElementsByTagName('geometry');
3562   if (geoms.length > 0) {
3563     var geom = geoms[0];
3564     var shape = null;
3565     // Check for the shape
3566     for (var i = 0; i < geom.childNodes.length; i++) {
3567       var node = geom.childNodes[i];
3568       if (node.nodeType === 1) {
3569         shape = node;
3570         break;
3571       }
3572     }
3573     // Check the type
3574     var type = shape.nodeName;
3575     if (type === 'sphere') {
3576       this.geometry = new UrdfSphere({
3577         xml : shape
3578       });
3579     } else if (type === 'box') {
3580       this.geometry = new UrdfBox({
3581         xml : shape
3582       });
3583     } else if (type === 'cylinder') {
3584       this.geometry = new UrdfCylinder({
3585         xml : shape
3586       });
3587     } else if (type === 'mesh') {
3588       this.geometry = new UrdfMesh({
3589         xml : shape
3590       });
3591     } else {
3592       console.warn('Unknown geometry type ' + type);
3593     }
3594   }
3595
3596   // Material
3597   var materials = xml.getElementsByTagName('material');
3598   if (materials.length > 0) {
3599     this.material = new UrdfMaterial({
3600       xml : materials[0]
3601     });
3602   }
3603 }
3604
3605 module.exports = UrdfVisual;
3606 },{"../math/Pose":19,"../math/Quaternion":20,"../math/Vector3":22,"./UrdfBox":27,"./UrdfCylinder":29,"./UrdfMaterial":32,"./UrdfMesh":33,"./UrdfSphere":35}],38:[function(require,module,exports){
3607 module.exports = require('object-assign')({
3608     UrdfBox: require('./UrdfBox'),
3609     UrdfColor: require('./UrdfColor'),
3610     UrdfCylinder: require('./UrdfCylinder'),
3611     UrdfLink: require('./UrdfLink'),
3612     UrdfMaterial: require('./UrdfMaterial'),
3613     UrdfMesh: require('./UrdfMesh'),
3614     UrdfModel: require('./UrdfModel'),
3615     UrdfSphere: require('./UrdfSphere'),
3616     UrdfVisual: require('./UrdfVisual')
3617 }, require('./UrdfTypes'));
3618
3619 },{"./UrdfBox":27,"./UrdfColor":28,"./UrdfCylinder":29,"./UrdfLink":31,"./UrdfMaterial":32,"./UrdfMesh":33,"./UrdfModel":34,"./UrdfSphere":35,"./UrdfTypes":36,"./UrdfVisual":37,"object-assign":2}],39:[function(require,module,exports){
3620 (function (global){
3621 module.exports = global.WebSocket;
3622 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
3623 },{}],40:[function(require,module,exports){
3624 /* global document */
3625 module.exports = function Canvas() {
3626         return document.createElement('canvas');
3627 };
3628 },{}],41:[function(require,module,exports){
3629 (function (global){
3630 /**
3631  * @fileOverview
3632  * @author Graeme Yeates - github.com/megawac
3633  */
3634
3635 'use strict';
3636
3637 var Canvas = require('canvas');
3638 var Image = Canvas.Image || global.Image;
3639
3640 /**
3641  * If a message was compressed as a PNG image (a compression hack since
3642  * gzipping over WebSockets * is not supported yet), this function places the
3643  * "image" in a canvas element then decodes the * "image" as a Base64 string.
3644  *
3645  * @private
3646  * @param data - object containing the PNG data.
3647  * @param callback - function with params:
3648  *   * data - the uncompressed data
3649  */
3650 function decompressPng(data, callback) {
3651   // Uncompresses the data before sending it through (use image/canvas to do so).
3652   var image = new Image();
3653   // When the image loads, extracts the raw data (JSON message).
3654   image.onload = function() {
3655     // Creates a local canvas to draw on.
3656     var canvas = new Canvas();
3657     var context = canvas.getContext('2d');
3658
3659     // Sets width and height.
3660     canvas.width = image.width;
3661     canvas.height = image.height;
3662
3663     // Prevents anti-aliasing and loosing data
3664     context.imageSmoothingEnabled = false;
3665     context.webkitImageSmoothingEnabled = false;
3666     context.mozImageSmoothingEnabled = false;
3667
3668     // Puts the data into the image.
3669     context.drawImage(image, 0, 0);
3670     // Grabs the raw, uncompressed data.
3671     var imageData = context.getImageData(0, 0, image.width, image.height).data;
3672
3673     // Constructs the JSON.
3674     var jsonData = '';
3675     for (var i = 0; i < imageData.length; i += 4) {
3676       // RGB
3677       jsonData += String.fromCharCode(imageData[i], imageData[i + 1], imageData[i + 2]);
3678     }
3679     callback(JSON.parse(jsonData));
3680   };
3681   // Sends the image data to load.
3682   image.src = 'data:image/png;base64,' + data;
3683 }
3684
3685 module.exports = decompressPng;
3686 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
3687 },{"canvas":40}],42:[function(require,module,exports){
3688 (function (global){
3689 exports.DOMImplementation = global.DOMImplementation;
3690 exports.XMLSerializer = global.XMLSerializer;
3691 exports.DOMParser = global.DOMParser;
3692 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
3693 },{}]},{},[4]);