.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / estraverse / estraverse.js
1 /*
2   Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
3   Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are met:
7
8     * Redistributions of source code must retain the above copyright
9       notice, this list of conditions and the following disclaimer.
10     * Redistributions in binary form must reproduce the above copyright
11       notice, this list of conditions and the following disclaimer in the
12       documentation and/or other materials provided with the distribution.
13
14   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17   ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
18   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25 /*jslint vars:false, bitwise:true*/
26 /*jshint indent:4*/
27 /*global exports:true*/
28 (function clone(exports) {
29     'use strict';
30
31     var Syntax,
32         VisitorOption,
33         VisitorKeys,
34         BREAK,
35         SKIP,
36         REMOVE;
37
38     function deepCopy(obj) {
39         var ret = {}, key, val;
40         for (key in obj) {
41             if (obj.hasOwnProperty(key)) {
42                 val = obj[key];
43                 if (typeof val === 'object' && val !== null) {
44                     ret[key] = deepCopy(val);
45                 } else {
46                     ret[key] = val;
47                 }
48             }
49         }
50         return ret;
51     }
52
53     // based on LLVM libc++ upper_bound / lower_bound
54     // MIT License
55
56     function upperBound(array, func) {
57         var diff, len, i, current;
58
59         len = array.length;
60         i = 0;
61
62         while (len) {
63             diff = len >>> 1;
64             current = i + diff;
65             if (func(array[current])) {
66                 len = diff;
67             } else {
68                 i = current + 1;
69                 len -= diff + 1;
70             }
71         }
72         return i;
73     }
74
75     Syntax = {
76         AssignmentExpression: 'AssignmentExpression',
77         AssignmentPattern: 'AssignmentPattern',
78         ArrayExpression: 'ArrayExpression',
79         ArrayPattern: 'ArrayPattern',
80         ArrowFunctionExpression: 'ArrowFunctionExpression',
81         AwaitExpression: 'AwaitExpression', // CAUTION: It's deferred to ES7.
82         BlockStatement: 'BlockStatement',
83         BinaryExpression: 'BinaryExpression',
84         BreakStatement: 'BreakStatement',
85         CallExpression: 'CallExpression',
86         CatchClause: 'CatchClause',
87         ClassBody: 'ClassBody',
88         ClassDeclaration: 'ClassDeclaration',
89         ClassExpression: 'ClassExpression',
90         ComprehensionBlock: 'ComprehensionBlock',  // CAUTION: It's deferred to ES7.
91         ComprehensionExpression: 'ComprehensionExpression',  // CAUTION: It's deferred to ES7.
92         ConditionalExpression: 'ConditionalExpression',
93         ContinueStatement: 'ContinueStatement',
94         DebuggerStatement: 'DebuggerStatement',
95         DirectiveStatement: 'DirectiveStatement',
96         DoWhileStatement: 'DoWhileStatement',
97         EmptyStatement: 'EmptyStatement',
98         ExportAllDeclaration: 'ExportAllDeclaration',
99         ExportDefaultDeclaration: 'ExportDefaultDeclaration',
100         ExportNamedDeclaration: 'ExportNamedDeclaration',
101         ExportSpecifier: 'ExportSpecifier',
102         ExpressionStatement: 'ExpressionStatement',
103         ForStatement: 'ForStatement',
104         ForInStatement: 'ForInStatement',
105         ForOfStatement: 'ForOfStatement',
106         FunctionDeclaration: 'FunctionDeclaration',
107         FunctionExpression: 'FunctionExpression',
108         GeneratorExpression: 'GeneratorExpression',  // CAUTION: It's deferred to ES7.
109         Identifier: 'Identifier',
110         IfStatement: 'IfStatement',
111         ImportExpression: 'ImportExpression',
112         ImportDeclaration: 'ImportDeclaration',
113         ImportDefaultSpecifier: 'ImportDefaultSpecifier',
114         ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
115         ImportSpecifier: 'ImportSpecifier',
116         Literal: 'Literal',
117         LabeledStatement: 'LabeledStatement',
118         LogicalExpression: 'LogicalExpression',
119         MemberExpression: 'MemberExpression',
120         MetaProperty: 'MetaProperty',
121         MethodDefinition: 'MethodDefinition',
122         ModuleSpecifier: 'ModuleSpecifier',
123         NewExpression: 'NewExpression',
124         ObjectExpression: 'ObjectExpression',
125         ObjectPattern: 'ObjectPattern',
126         Program: 'Program',
127         Property: 'Property',
128         RestElement: 'RestElement',
129         ReturnStatement: 'ReturnStatement',
130         SequenceExpression: 'SequenceExpression',
131         SpreadElement: 'SpreadElement',
132         Super: 'Super',
133         SwitchStatement: 'SwitchStatement',
134         SwitchCase: 'SwitchCase',
135         TaggedTemplateExpression: 'TaggedTemplateExpression',
136         TemplateElement: 'TemplateElement',
137         TemplateLiteral: 'TemplateLiteral',
138         ThisExpression: 'ThisExpression',
139         ThrowStatement: 'ThrowStatement',
140         TryStatement: 'TryStatement',
141         UnaryExpression: 'UnaryExpression',
142         UpdateExpression: 'UpdateExpression',
143         VariableDeclaration: 'VariableDeclaration',
144         VariableDeclarator: 'VariableDeclarator',
145         WhileStatement: 'WhileStatement',
146         WithStatement: 'WithStatement',
147         YieldExpression: 'YieldExpression'
148     };
149
150     VisitorKeys = {
151         AssignmentExpression: ['left', 'right'],
152         AssignmentPattern: ['left', 'right'],
153         ArrayExpression: ['elements'],
154         ArrayPattern: ['elements'],
155         ArrowFunctionExpression: ['params', 'body'],
156         AwaitExpression: ['argument'], // CAUTION: It's deferred to ES7.
157         BlockStatement: ['body'],
158         BinaryExpression: ['left', 'right'],
159         BreakStatement: ['label'],
160         CallExpression: ['callee', 'arguments'],
161         CatchClause: ['param', 'body'],
162         ClassBody: ['body'],
163         ClassDeclaration: ['id', 'superClass', 'body'],
164         ClassExpression: ['id', 'superClass', 'body'],
165         ComprehensionBlock: ['left', 'right'],  // CAUTION: It's deferred to ES7.
166         ComprehensionExpression: ['blocks', 'filter', 'body'],  // CAUTION: It's deferred to ES7.
167         ConditionalExpression: ['test', 'consequent', 'alternate'],
168         ContinueStatement: ['label'],
169         DebuggerStatement: [],
170         DirectiveStatement: [],
171         DoWhileStatement: ['body', 'test'],
172         EmptyStatement: [],
173         ExportAllDeclaration: ['source'],
174         ExportDefaultDeclaration: ['declaration'],
175         ExportNamedDeclaration: ['declaration', 'specifiers', 'source'],
176         ExportSpecifier: ['exported', 'local'],
177         ExpressionStatement: ['expression'],
178         ForStatement: ['init', 'test', 'update', 'body'],
179         ForInStatement: ['left', 'right', 'body'],
180         ForOfStatement: ['left', 'right', 'body'],
181         FunctionDeclaration: ['id', 'params', 'body'],
182         FunctionExpression: ['id', 'params', 'body'],
183         GeneratorExpression: ['blocks', 'filter', 'body'],  // CAUTION: It's deferred to ES7.
184         Identifier: [],
185         IfStatement: ['test', 'consequent', 'alternate'],
186         ImportExpression: ['source'],
187         ImportDeclaration: ['specifiers', 'source'],
188         ImportDefaultSpecifier: ['local'],
189         ImportNamespaceSpecifier: ['local'],
190         ImportSpecifier: ['imported', 'local'],
191         Literal: [],
192         LabeledStatement: ['label', 'body'],
193         LogicalExpression: ['left', 'right'],
194         MemberExpression: ['object', 'property'],
195         MetaProperty: ['meta', 'property'],
196         MethodDefinition: ['key', 'value'],
197         ModuleSpecifier: [],
198         NewExpression: ['callee', 'arguments'],
199         ObjectExpression: ['properties'],
200         ObjectPattern: ['properties'],
201         Program: ['body'],
202         Property: ['key', 'value'],
203         RestElement: [ 'argument' ],
204         ReturnStatement: ['argument'],
205         SequenceExpression: ['expressions'],
206         SpreadElement: ['argument'],
207         Super: [],
208         SwitchStatement: ['discriminant', 'cases'],
209         SwitchCase: ['test', 'consequent'],
210         TaggedTemplateExpression: ['tag', 'quasi'],
211         TemplateElement: [],
212         TemplateLiteral: ['quasis', 'expressions'],
213         ThisExpression: [],
214         ThrowStatement: ['argument'],
215         TryStatement: ['block', 'handler', 'finalizer'],
216         UnaryExpression: ['argument'],
217         UpdateExpression: ['argument'],
218         VariableDeclaration: ['declarations'],
219         VariableDeclarator: ['id', 'init'],
220         WhileStatement: ['test', 'body'],
221         WithStatement: ['object', 'body'],
222         YieldExpression: ['argument']
223     };
224
225     // unique id
226     BREAK = {};
227     SKIP = {};
228     REMOVE = {};
229
230     VisitorOption = {
231         Break: BREAK,
232         Skip: SKIP,
233         Remove: REMOVE
234     };
235
236     function Reference(parent, key) {
237         this.parent = parent;
238         this.key = key;
239     }
240
241     Reference.prototype.replace = function replace(node) {
242         this.parent[this.key] = node;
243     };
244
245     Reference.prototype.remove = function remove() {
246         if (Array.isArray(this.parent)) {
247             this.parent.splice(this.key, 1);
248             return true;
249         } else {
250             this.replace(null);
251             return false;
252         }
253     };
254
255     function Element(node, path, wrap, ref) {
256         this.node = node;
257         this.path = path;
258         this.wrap = wrap;
259         this.ref = ref;
260     }
261
262     function Controller() { }
263
264     // API:
265     // return property path array from root to current node
266     Controller.prototype.path = function path() {
267         var i, iz, j, jz, result, element;
268
269         function addToPath(result, path) {
270             if (Array.isArray(path)) {
271                 for (j = 0, jz = path.length; j < jz; ++j) {
272                     result.push(path[j]);
273                 }
274             } else {
275                 result.push(path);
276             }
277         }
278
279         // root node
280         if (!this.__current.path) {
281             return null;
282         }
283
284         // first node is sentinel, second node is root element
285         result = [];
286         for (i = 2, iz = this.__leavelist.length; i < iz; ++i) {
287             element = this.__leavelist[i];
288             addToPath(result, element.path);
289         }
290         addToPath(result, this.__current.path);
291         return result;
292     };
293
294     // API:
295     // return type of current node
296     Controller.prototype.type = function () {
297         var node = this.current();
298         return node.type || this.__current.wrap;
299     };
300
301     // API:
302     // return array of parent elements
303     Controller.prototype.parents = function parents() {
304         var i, iz, result;
305
306         // first node is sentinel
307         result = [];
308         for (i = 1, iz = this.__leavelist.length; i < iz; ++i) {
309             result.push(this.__leavelist[i].node);
310         }
311
312         return result;
313     };
314
315     // API:
316     // return current node
317     Controller.prototype.current = function current() {
318         return this.__current.node;
319     };
320
321     Controller.prototype.__execute = function __execute(callback, element) {
322         var previous, result;
323
324         result = undefined;
325
326         previous  = this.__current;
327         this.__current = element;
328         this.__state = null;
329         if (callback) {
330             result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node);
331         }
332         this.__current = previous;
333
334         return result;
335     };
336
337     // API:
338     // notify control skip / break
339     Controller.prototype.notify = function notify(flag) {
340         this.__state = flag;
341     };
342
343     // API:
344     // skip child nodes of current node
345     Controller.prototype.skip = function () {
346         this.notify(SKIP);
347     };
348
349     // API:
350     // break traversals
351     Controller.prototype['break'] = function () {
352         this.notify(BREAK);
353     };
354
355     // API:
356     // remove node
357     Controller.prototype.remove = function () {
358         this.notify(REMOVE);
359     };
360
361     Controller.prototype.__initialize = function(root, visitor) {
362         this.visitor = visitor;
363         this.root = root;
364         this.__worklist = [];
365         this.__leavelist = [];
366         this.__current = null;
367         this.__state = null;
368         this.__fallback = null;
369         if (visitor.fallback === 'iteration') {
370             this.__fallback = Object.keys;
371         } else if (typeof visitor.fallback === 'function') {
372             this.__fallback = visitor.fallback;
373         }
374
375         this.__keys = VisitorKeys;
376         if (visitor.keys) {
377             this.__keys = Object.assign(Object.create(this.__keys), visitor.keys);
378         }
379     };
380
381     function isNode(node) {
382         if (node == null) {
383             return false;
384         }
385         return typeof node === 'object' && typeof node.type === 'string';
386     }
387
388     function isProperty(nodeType, key) {
389         return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key;
390     }
391
392     Controller.prototype.traverse = function traverse(root, visitor) {
393         var worklist,
394             leavelist,
395             element,
396             node,
397             nodeType,
398             ret,
399             key,
400             current,
401             current2,
402             candidates,
403             candidate,
404             sentinel;
405
406         this.__initialize(root, visitor);
407
408         sentinel = {};
409
410         // reference
411         worklist = this.__worklist;
412         leavelist = this.__leavelist;
413
414         // initialize
415         worklist.push(new Element(root, null, null, null));
416         leavelist.push(new Element(null, null, null, null));
417
418         while (worklist.length) {
419             element = worklist.pop();
420
421             if (element === sentinel) {
422                 element = leavelist.pop();
423
424                 ret = this.__execute(visitor.leave, element);
425
426                 if (this.__state === BREAK || ret === BREAK) {
427                     return;
428                 }
429                 continue;
430             }
431
432             if (element.node) {
433
434                 ret = this.__execute(visitor.enter, element);
435
436                 if (this.__state === BREAK || ret === BREAK) {
437                     return;
438                 }
439
440                 worklist.push(sentinel);
441                 leavelist.push(element);
442
443                 if (this.__state === SKIP || ret === SKIP) {
444                     continue;
445                 }
446
447                 node = element.node;
448                 nodeType = node.type || element.wrap;
449                 candidates = this.__keys[nodeType];
450                 if (!candidates) {
451                     if (this.__fallback) {
452                         candidates = this.__fallback(node);
453                     } else {
454                         throw new Error('Unknown node type ' + nodeType + '.');
455                     }
456                 }
457
458                 current = candidates.length;
459                 while ((current -= 1) >= 0) {
460                     key = candidates[current];
461                     candidate = node[key];
462                     if (!candidate) {
463                         continue;
464                     }
465
466                     if (Array.isArray(candidate)) {
467                         current2 = candidate.length;
468                         while ((current2 -= 1) >= 0) {
469                             if (!candidate[current2]) {
470                                 continue;
471                             }
472                             if (isProperty(nodeType, candidates[current])) {
473                                 element = new Element(candidate[current2], [key, current2], 'Property', null);
474                             } else if (isNode(candidate[current2])) {
475                                 element = new Element(candidate[current2], [key, current2], null, null);
476                             } else {
477                                 continue;
478                             }
479                             worklist.push(element);
480                         }
481                     } else if (isNode(candidate)) {
482                         worklist.push(new Element(candidate, key, null, null));
483                     }
484                 }
485             }
486         }
487     };
488
489     Controller.prototype.replace = function replace(root, visitor) {
490         var worklist,
491             leavelist,
492             node,
493             nodeType,
494             target,
495             element,
496             current,
497             current2,
498             candidates,
499             candidate,
500             sentinel,
501             outer,
502             key;
503
504         function removeElem(element) {
505             var i,
506                 key,
507                 nextElem,
508                 parent;
509
510             if (element.ref.remove()) {
511                 // When the reference is an element of an array.
512                 key = element.ref.key;
513                 parent = element.ref.parent;
514
515                 // If removed from array, then decrease following items' keys.
516                 i = worklist.length;
517                 while (i--) {
518                     nextElem = worklist[i];
519                     if (nextElem.ref && nextElem.ref.parent === parent) {
520                         if  (nextElem.ref.key < key) {
521                             break;
522                         }
523                         --nextElem.ref.key;
524                     }
525                 }
526             }
527         }
528
529         this.__initialize(root, visitor);
530
531         sentinel = {};
532
533         // reference
534         worklist = this.__worklist;
535         leavelist = this.__leavelist;
536
537         // initialize
538         outer = {
539             root: root
540         };
541         element = new Element(root, null, null, new Reference(outer, 'root'));
542         worklist.push(element);
543         leavelist.push(element);
544
545         while (worklist.length) {
546             element = worklist.pop();
547
548             if (element === sentinel) {
549                 element = leavelist.pop();
550
551                 target = this.__execute(visitor.leave, element);
552
553                 // node may be replaced with null,
554                 // so distinguish between undefined and null in this place
555                 if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) {
556                     // replace
557                     element.ref.replace(target);
558                 }
559
560                 if (this.__state === REMOVE || target === REMOVE) {
561                     removeElem(element);
562                 }
563
564                 if (this.__state === BREAK || target === BREAK) {
565                     return outer.root;
566                 }
567                 continue;
568             }
569
570             target = this.__execute(visitor.enter, element);
571
572             // node may be replaced with null,
573             // so distinguish between undefined and null in this place
574             if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) {
575                 // replace
576                 element.ref.replace(target);
577                 element.node = target;
578             }
579
580             if (this.__state === REMOVE || target === REMOVE) {
581                 removeElem(element);
582                 element.node = null;
583             }
584
585             if (this.__state === BREAK || target === BREAK) {
586                 return outer.root;
587             }
588
589             // node may be null
590             node = element.node;
591             if (!node) {
592                 continue;
593             }
594
595             worklist.push(sentinel);
596             leavelist.push(element);
597
598             if (this.__state === SKIP || target === SKIP) {
599                 continue;
600             }
601
602             nodeType = node.type || element.wrap;
603             candidates = this.__keys[nodeType];
604             if (!candidates) {
605                 if (this.__fallback) {
606                     candidates = this.__fallback(node);
607                 } else {
608                     throw new Error('Unknown node type ' + nodeType + '.');
609                 }
610             }
611
612             current = candidates.length;
613             while ((current -= 1) >= 0) {
614                 key = candidates[current];
615                 candidate = node[key];
616                 if (!candidate) {
617                     continue;
618                 }
619
620                 if (Array.isArray(candidate)) {
621                     current2 = candidate.length;
622                     while ((current2 -= 1) >= 0) {
623                         if (!candidate[current2]) {
624                             continue;
625                         }
626                         if (isProperty(nodeType, candidates[current])) {
627                             element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2));
628                         } else if (isNode(candidate[current2])) {
629                             element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2));
630                         } else {
631                             continue;
632                         }
633                         worklist.push(element);
634                     }
635                 } else if (isNode(candidate)) {
636                     worklist.push(new Element(candidate, key, null, new Reference(node, key)));
637                 }
638             }
639         }
640
641         return outer.root;
642     };
643
644     function traverse(root, visitor) {
645         var controller = new Controller();
646         return controller.traverse(root, visitor);
647     }
648
649     function replace(root, visitor) {
650         var controller = new Controller();
651         return controller.replace(root, visitor);
652     }
653
654     function extendCommentRange(comment, tokens) {
655         var target;
656
657         target = upperBound(tokens, function search(token) {
658             return token.range[0] > comment.range[0];
659         });
660
661         comment.extendedRange = [comment.range[0], comment.range[1]];
662
663         if (target !== tokens.length) {
664             comment.extendedRange[1] = tokens[target].range[0];
665         }
666
667         target -= 1;
668         if (target >= 0) {
669             comment.extendedRange[0] = tokens[target].range[1];
670         }
671
672         return comment;
673     }
674
675     function attachComments(tree, providedComments, tokens) {
676         // At first, we should calculate extended comment ranges.
677         var comments = [], comment, len, i, cursor;
678
679         if (!tree.range) {
680             throw new Error('attachComments needs range information');
681         }
682
683         // tokens array is empty, we attach comments to tree as 'leadingComments'
684         if (!tokens.length) {
685             if (providedComments.length) {
686                 for (i = 0, len = providedComments.length; i < len; i += 1) {
687                     comment = deepCopy(providedComments[i]);
688                     comment.extendedRange = [0, tree.range[0]];
689                     comments.push(comment);
690                 }
691                 tree.leadingComments = comments;
692             }
693             return tree;
694         }
695
696         for (i = 0, len = providedComments.length; i < len; i += 1) {
697             comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
698         }
699
700         // This is based on John Freeman's implementation.
701         cursor = 0;
702         traverse(tree, {
703             enter: function (node) {
704                 var comment;
705
706                 while (cursor < comments.length) {
707                     comment = comments[cursor];
708                     if (comment.extendedRange[1] > node.range[0]) {
709                         break;
710                     }
711
712                     if (comment.extendedRange[1] === node.range[0]) {
713                         if (!node.leadingComments) {
714                             node.leadingComments = [];
715                         }
716                         node.leadingComments.push(comment);
717                         comments.splice(cursor, 1);
718                     } else {
719                         cursor += 1;
720                     }
721                 }
722
723                 // already out of owned node
724                 if (cursor === comments.length) {
725                     return VisitorOption.Break;
726                 }
727
728                 if (comments[cursor].extendedRange[0] > node.range[1]) {
729                     return VisitorOption.Skip;
730                 }
731             }
732         });
733
734         cursor = 0;
735         traverse(tree, {
736             leave: function (node) {
737                 var comment;
738
739                 while (cursor < comments.length) {
740                     comment = comments[cursor];
741                     if (node.range[1] < comment.extendedRange[0]) {
742                         break;
743                     }
744
745                     if (node.range[1] === comment.extendedRange[0]) {
746                         if (!node.trailingComments) {
747                             node.trailingComments = [];
748                         }
749                         node.trailingComments.push(comment);
750                         comments.splice(cursor, 1);
751                     } else {
752                         cursor += 1;
753                     }
754                 }
755
756                 // already out of owned node
757                 if (cursor === comments.length) {
758                     return VisitorOption.Break;
759                 }
760
761                 if (comments[cursor].extendedRange[0] > node.range[1]) {
762                     return VisitorOption.Skip;
763                 }
764             }
765         });
766
767         return tree;
768     }
769
770     exports.version = require('./package.json').version;
771     exports.Syntax = Syntax;
772     exports.traverse = traverse;
773     exports.replace = replace;
774     exports.attachComments = attachComments;
775     exports.VisitorKeys = VisitorKeys;
776     exports.VisitorOption = VisitorOption;
777     exports.Controller = Controller;
778     exports.cloneEnvironment = function () { return clone({}); };
779
780     return exports;
781 }(exports));
782 /* vim: set sw=4 ts=4 et tw=80 : */