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