diff options
Diffstat (limited to 'app/js/superagent.js')
-rw-r--r-- | app/js/superagent.js | 1383 |
1 files changed, 0 insertions, 1383 deletions
diff --git a/app/js/superagent.js b/app/js/superagent.js deleted file mode 100644 index 140bc4d..0000000 --- a/app/js/superagent.js +++ /dev/null | |||
@@ -1,1383 +0,0 @@ | |||
1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.superagent=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
2 | |||
3 | /** | ||
4 | * Expose `Emitter`. | ||
5 | */ | ||
6 | |||
7 | module.exports = Emitter; | ||
8 | |||
9 | /** | ||
10 | * Initialize a new `Emitter`. | ||
11 | * | ||
12 | * @api public | ||
13 | */ | ||
14 | |||
15 | function Emitter(obj) { | ||
16 | if (obj) return mixin(obj); | ||
17 | }; | ||
18 | |||
19 | /** | ||
20 | * Mixin the emitter properties. | ||
21 | * | ||
22 | * @param {Object} obj | ||
23 | * @return {Object} | ||
24 | * @api private | ||
25 | */ | ||
26 | |||
27 | function mixin(obj) { | ||
28 | for (var key in Emitter.prototype) { | ||
29 | obj[key] = Emitter.prototype[key]; | ||
30 | } | ||
31 | return obj; | ||
32 | } | ||
33 | |||
34 | /** | ||
35 | * Listen on the given `event` with `fn`. | ||
36 | * | ||
37 | * @param {String} event | ||
38 | * @param {Function} fn | ||
39 | * @return {Emitter} | ||
40 | * @api public | ||
41 | */ | ||
42 | |||
43 | Emitter.prototype.on = | ||
44 | Emitter.prototype.addEventListener = function(event, fn){ | ||
45 | this._callbacks = this._callbacks || {}; | ||
46 | (this._callbacks['$' + event] = this._callbacks['$' + event] || []) | ||
47 | .push(fn); | ||
48 | return this; | ||
49 | }; | ||
50 | |||
51 | /** | ||
52 | * Adds an `event` listener that will be invoked a single | ||
53 | * time then automatically removed. | ||
54 | * | ||
55 | * @param {String} event | ||
56 | * @param {Function} fn | ||
57 | * @return {Emitter} | ||
58 | * @api public | ||
59 | */ | ||
60 | |||
61 | Emitter.prototype.once = function(event, fn){ | ||
62 | function on() { | ||
63 | this.off(event, on); | ||
64 | fn.apply(this, arguments); | ||
65 | } | ||
66 | |||
67 | on.fn = fn; | ||
68 | this.on(event, on); | ||
69 | return this; | ||
70 | }; | ||
71 | |||
72 | /** | ||
73 | * Remove the given callback for `event` or all | ||
74 | * registered callbacks. | ||
75 | * | ||
76 | * @param {String} event | ||
77 | * @param {Function} fn | ||
78 | * @return {Emitter} | ||
79 | * @api public | ||
80 | */ | ||
81 | |||
82 | Emitter.prototype.off = | ||
83 | Emitter.prototype.removeListener = | ||
84 | Emitter.prototype.removeAllListeners = | ||
85 | Emitter.prototype.removeEventListener = function(event, fn){ | ||
86 | this._callbacks = this._callbacks || {}; | ||
87 | |||
88 | // all | ||
89 | if (0 == arguments.length) { | ||
90 | this._callbacks = {}; | ||
91 | return this; | ||
92 | } | ||
93 | |||
94 | // specific event | ||
95 | var callbacks = this._callbacks['$' + event]; | ||
96 | if (!callbacks) return this; | ||
97 | |||
98 | // remove all handlers | ||
99 | if (1 == arguments.length) { | ||
100 | delete this._callbacks['$' + event]; | ||
101 | return this; | ||
102 | } | ||
103 | |||
104 | // remove specific handler | ||
105 | var cb; | ||
106 | for (var i = 0; i < callbacks.length; i++) { | ||
107 | cb = callbacks[i]; | ||
108 | if (cb === fn || cb.fn === fn) { | ||
109 | callbacks.splice(i, 1); | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | return this; | ||
114 | }; | ||
115 | |||
116 | /** | ||
117 | * Emit `event` with the given args. | ||
118 | * | ||
119 | * @param {String} event | ||
120 | * @param {Mixed} ... | ||
121 | * @return {Emitter} | ||
122 | */ | ||
123 | |||
124 | Emitter.prototype.emit = function(event){ | ||
125 | this._callbacks = this._callbacks || {}; | ||
126 | var args = [].slice.call(arguments, 1) | ||
127 | , callbacks = this._callbacks['$' + event]; | ||
128 | |||
129 | if (callbacks) { | ||
130 | callbacks = callbacks.slice(0); | ||
131 | for (var i = 0, len = callbacks.length; i < len; ++i) { | ||
132 | callbacks[i].apply(this, args); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | return this; | ||
137 | }; | ||
138 | |||
139 | /** | ||
140 | * Return array of callbacks for `event`. | ||
141 | * | ||
142 | * @param {String} event | ||
143 | * @return {Array} | ||
144 | * @api public | ||
145 | */ | ||
146 | |||
147 | Emitter.prototype.listeners = function(event){ | ||
148 | this._callbacks = this._callbacks || {}; | ||
149 | return this._callbacks['$' + event] || []; | ||
150 | }; | ||
151 | |||
152 | /** | ||
153 | * Check if this emitter has `event` handlers. | ||
154 | * | ||
155 | * @param {String} event | ||
156 | * @return {Boolean} | ||
157 | * @api public | ||
158 | */ | ||
159 | |||
160 | Emitter.prototype.hasListeners = function(event){ | ||
161 | return !! this.listeners(event).length; | ||
162 | }; | ||
163 | |||
164 | },{}],2:[function(require,module,exports){ | ||
165 | |||
166 | /** | ||
167 | * Reduce `arr` with `fn`. | ||
168 | * | ||
169 | * @param {Array} arr | ||
170 | * @param {Function} fn | ||
171 | * @param {Mixed} initial | ||
172 | * | ||
173 | * TODO: combatible error handling? | ||
174 | */ | ||
175 | |||
176 | module.exports = function(arr, fn, initial){ | ||
177 | var idx = 0; | ||
178 | var len = arr.length; | ||
179 | var curr = arguments.length == 3 | ||
180 | ? initial | ||
181 | : arr[idx++]; | ||
182 | |||
183 | while (idx < len) { | ||
184 | curr = fn.call(null, curr, arr[idx], ++idx, arr); | ||
185 | } | ||
186 | |||
187 | return curr; | ||
188 | }; | ||
189 | },{}],3:[function(require,module,exports){ | ||
190 | /** | ||
191 | * Module dependencies. | ||
192 | */ | ||
193 | |||
194 | var Emitter = require('emitter'); | ||
195 | var reduce = require('reduce'); | ||
196 | |||
197 | /** | ||
198 | * Root reference for iframes. | ||
199 | */ | ||
200 | |||
201 | var root; | ||
202 | if (typeof window !== 'undefined') { // Browser window | ||
203 | root = window; | ||
204 | } else if (typeof self !== 'undefined') { // Web Worker | ||
205 | root = self; | ||
206 | } else { // Other environments | ||
207 | root = this; | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * Noop. | ||
212 | */ | ||
213 | |||
214 | function noop(){}; | ||
215 | |||
216 | /** | ||
217 | * Check if `obj` is a host object, | ||
218 | * we don't want to serialize these :) | ||
219 | * | ||
220 | * TODO: future proof, move to compoent land | ||
221 | * | ||
222 | * @param {Object} obj | ||
223 | * @return {Boolean} | ||
224 | * @api private | ||
225 | */ | ||
226 | |||
227 | function isHost(obj) { | ||
228 | var str = {}.toString.call(obj); | ||
229 | |||
230 | switch (str) { | ||
231 | case '[object File]': | ||
232 | case '[object Blob]': | ||
233 | case '[object FormData]': | ||
234 | return true; | ||
235 | default: | ||
236 | return false; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * Determine XHR. | ||
242 | */ | ||
243 | |||
244 | request.getXHR = function () { | ||
245 | if (root.XMLHttpRequest | ||
246 | && (!root.location || 'file:' != root.location.protocol | ||
247 | || !root.ActiveXObject)) { | ||
248 | return new XMLHttpRequest; | ||
249 | } else { | ||
250 | try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} | ||
251 | try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} | ||
252 | try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} | ||
253 | try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} | ||
254 | } | ||
255 | return false; | ||
256 | }; | ||
257 | |||
258 | /** | ||
259 | * Removes leading and trailing whitespace, added to support IE. | ||
260 | * | ||
261 | * @param {String} s | ||
262 | * @return {String} | ||
263 | * @api private | ||
264 | */ | ||
265 | |||
266 | var trim = ''.trim | ||
267 | ? function(s) { return s.trim(); } | ||
268 | : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; | ||
269 | |||
270 | /** | ||
271 | * Check if `obj` is an object. | ||
272 | * | ||
273 | * @param {Object} obj | ||
274 | * @return {Boolean} | ||
275 | * @api private | ||
276 | */ | ||
277 | |||
278 | function isObject(obj) { | ||
279 | return obj === Object(obj); | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * Serialize the given `obj`. | ||
284 | * | ||
285 | * @param {Object} obj | ||
286 | * @return {String} | ||
287 | * @api private | ||
288 | */ | ||
289 | |||
290 | function serialize(obj) { | ||
291 | if (!isObject(obj)) return obj; | ||
292 | var pairs = []; | ||
293 | for (var key in obj) { | ||
294 | if (null != obj[key]) { | ||
295 | pushEncodedKeyValuePair(pairs, key, obj[key]); | ||
296 | } | ||
297 | } | ||
298 | return pairs.join('&'); | ||
299 | } | ||
300 | |||
301 | /** | ||
302 | * Helps 'serialize' with serializing arrays. | ||
303 | * Mutates the pairs array. | ||
304 | * | ||
305 | * @param {Array} pairs | ||
306 | * @param {String} key | ||
307 | * @param {Mixed} val | ||
308 | */ | ||
309 | |||
310 | function pushEncodedKeyValuePair(pairs, key, val) { | ||
311 | if (Array.isArray(val)) { | ||
312 | return val.forEach(function(v) { | ||
313 | pushEncodedKeyValuePair(pairs, key, v); | ||
314 | }); | ||
315 | } | ||
316 | pairs.push(encodeURIComponent(key) | ||
317 | + '=' + encodeURIComponent(val)); | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * Expose serialization method. | ||
322 | */ | ||
323 | |||
324 | request.serializeObject = serialize; | ||
325 | |||
326 | /** | ||
327 | * Parse the given x-www-form-urlencoded `str`. | ||
328 | * | ||
329 | * @param {String} str | ||
330 | * @return {Object} | ||
331 | * @api private | ||
332 | */ | ||
333 | |||
334 | function parseString(str) { | ||
335 | var obj = {}; | ||
336 | var pairs = str.split('&'); | ||
337 | var parts; | ||
338 | var pair; | ||
339 | |||
340 | for (var i = 0, len = pairs.length; i < len; ++i) { | ||
341 | pair = pairs[i]; | ||
342 | parts = pair.split('='); | ||
343 | obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); | ||
344 | } | ||
345 | |||
346 | return obj; | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * Expose parser. | ||
351 | */ | ||
352 | |||
353 | request.parseString = parseString; | ||
354 | |||
355 | /** | ||
356 | * Default MIME type map. | ||
357 | * | ||
358 | * superagent.types.xml = 'application/xml'; | ||
359 | * | ||
360 | */ | ||
361 | |||
362 | request.types = { | ||
363 | html: 'text/html', | ||
364 | json: 'application/json', | ||
365 | xml: 'application/xml', | ||
366 | urlencoded: 'application/x-www-form-urlencoded', | ||
367 | 'form': 'application/x-www-form-urlencoded', | ||
368 | 'form-data': 'application/x-www-form-urlencoded' | ||
369 | }; | ||
370 | |||
371 | /** | ||
372 | * Default serialization map. | ||
373 | * | ||
374 | * superagent.serialize['application/xml'] = function(obj){ | ||
375 | * return 'generated xml here'; | ||
376 | * }; | ||
377 | * | ||
378 | */ | ||
379 | |||
380 | request.serialize = { | ||
381 | 'application/x-www-form-urlencoded': serialize, | ||
382 | 'application/json': JSON.stringify | ||
383 | }; | ||
384 | |||
385 | /** | ||
386 | * Default parsers. | ||
387 | * | ||
388 | * superagent.parse['application/xml'] = function(str){ | ||
389 | * return { object parsed from str }; | ||
390 | * }; | ||
391 | * | ||
392 | */ | ||
393 | |||
394 | request.parse = { | ||
395 | 'application/x-www-form-urlencoded': parseString, | ||
396 | 'application/json': JSON.parse | ||
397 | }; | ||
398 | |||
399 | /** | ||
400 | * Parse the given header `str` into | ||
401 | * an object containing the mapped fields. | ||
402 | * | ||
403 | * @param {String} str | ||
404 | * @return {Object} | ||
405 | * @api private | ||
406 | */ | ||
407 | |||
408 | function parseHeader(str) { | ||
409 | var lines = str.split(/\r?\n/); | ||
410 | var fields = {}; | ||
411 | var index; | ||
412 | var line; | ||
413 | var field; | ||
414 | var val; | ||
415 | |||
416 | lines.pop(); // trailing CRLF | ||
417 | |||
418 | for (var i = 0, len = lines.length; i < len; ++i) { | ||
419 | line = lines[i]; | ||
420 | index = line.indexOf(':'); | ||
421 | field = line.slice(0, index).toLowerCase(); | ||
422 | val = trim(line.slice(index + 1)); | ||
423 | fields[field] = val; | ||
424 | } | ||
425 | |||
426 | return fields; | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * Check if `mime` is json or has +json structured syntax suffix. | ||
431 | * | ||
432 | * @param {String} mime | ||
433 | * @return {Boolean} | ||
434 | * @api private | ||
435 | */ | ||
436 | |||
437 | function isJSON(mime) { | ||
438 | return /[\/+]json\b/.test(mime); | ||
439 | } | ||
440 | |||
441 | /** | ||
442 | * Return the mime type for the given `str`. | ||
443 | * | ||
444 | * @param {String} str | ||
445 | * @return {String} | ||
446 | * @api private | ||
447 | */ | ||
448 | |||
449 | function type(str){ | ||
450 | return str.split(/ *; */).shift(); | ||
451 | }; | ||
452 | |||
453 | /** | ||
454 | * Return header field parameters. | ||
455 | * | ||
456 | * @param {String} str | ||
457 | * @return {Object} | ||
458 | * @api private | ||
459 | */ | ||
460 | |||
461 | function params(str){ | ||
462 | return reduce(str.split(/ *; */), function(obj, str){ | ||
463 | var parts = str.split(/ *= */) | ||
464 | , key = parts.shift() | ||
465 | , val = parts.shift(); | ||
466 | |||
467 | if (key && val) obj[key] = val; | ||
468 | return obj; | ||
469 | }, {}); | ||
470 | }; | ||
471 | |||
472 | /** | ||
473 | * Initialize a new `Response` with the given `xhr`. | ||
474 | * | ||
475 | * - set flags (.ok, .error, etc) | ||
476 | * - parse header | ||
477 | * | ||
478 | * Examples: | ||
479 | * | ||
480 | * Aliasing `superagent` as `request` is nice: | ||
481 | * | ||
482 | * request = superagent; | ||
483 | * | ||
484 | * We can use the promise-like API, or pass callbacks: | ||
485 | * | ||
486 | * request.get('/').end(function(res){}); | ||
487 | * request.get('/', function(res){}); | ||
488 | * | ||
489 | * Sending data can be chained: | ||
490 | * | ||
491 | * request | ||
492 | * .post('/user') | ||
493 | * .send({ name: 'tj' }) | ||
494 | * .end(function(res){}); | ||
495 | * | ||
496 | * Or passed to `.send()`: | ||
497 | * | ||
498 | * request | ||
499 | * .post('/user') | ||
500 | * .send({ name: 'tj' }, function(res){}); | ||
501 | * | ||
502 | * Or passed to `.post()`: | ||
503 | * | ||
504 | * request | ||
505 | * .post('/user', { name: 'tj' }) | ||
506 | * .end(function(res){}); | ||
507 | * | ||
508 | * Or further reduced to a single call for simple cases: | ||
509 | * | ||
510 | * request | ||
511 | * .post('/user', { name: 'tj' }, function(res){}); | ||
512 | * | ||
513 | * @param {XMLHTTPRequest} xhr | ||
514 | * @param {Object} options | ||
515 | * @api private | ||
516 | */ | ||
517 | |||
518 | function Response(req, options) { | ||
519 | options = options || {}; | ||
520 | this.req = req; | ||
521 | this.xhr = this.req.xhr; | ||
522 | // responseText is accessible only if responseType is '' or 'text' and on older browsers | ||
523 | this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined') | ||
524 | ? this.xhr.responseText | ||
525 | : null; | ||
526 | this.statusText = this.req.xhr.statusText; | ||
527 | this.setStatusProperties(this.xhr.status); | ||
528 | this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); | ||
529 | // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but | ||
530 | // getResponseHeader still works. so we get content-type even if getting | ||
531 | // other headers fails. | ||
532 | this.header['content-type'] = this.xhr.getResponseHeader('content-type'); | ||
533 | this.setHeaderProperties(this.header); | ||
534 | this.body = this.req.method != 'HEAD' | ||
535 | ? this.parseBody(this.text ? this.text : this.xhr.response) | ||
536 | : null; | ||
537 | } | ||
538 | |||
539 | /** | ||
540 | * Get case-insensitive `field` value. | ||
541 | * | ||
542 | * @param {String} field | ||
543 | * @return {String} | ||
544 | * @api public | ||
545 | */ | ||
546 | |||
547 | Response.prototype.get = function(field){ | ||
548 | return this.header[field.toLowerCase()]; | ||
549 | }; | ||
550 | |||
551 | /** | ||
552 | * Set header related properties: | ||
553 | * | ||
554 | * - `.type` the content type without params | ||
555 | * | ||
556 | * A response of "Content-Type: text/plain; charset=utf-8" | ||
557 | * will provide you with a `.type` of "text/plain". | ||
558 | * | ||
559 | * @param {Object} header | ||
560 | * @api private | ||
561 | */ | ||
562 | |||
563 | Response.prototype.setHeaderProperties = function(header){ | ||
564 | // content-type | ||
565 | var ct = this.header['content-type'] || ''; | ||
566 | this.type = type(ct); | ||
567 | |||
568 | // params | ||
569 | var obj = params(ct); | ||
570 | for (var key in obj) this[key] = obj[key]; | ||
571 | }; | ||
572 | |||
573 | /** | ||
574 | * Parse the given body `str`. | ||
575 | * | ||
576 | * Used for auto-parsing of bodies. Parsers | ||
577 | * are defined on the `superagent.parse` object. | ||
578 | * | ||
579 | * @param {String} str | ||
580 | * @return {Mixed} | ||
581 | * @api private | ||
582 | */ | ||
583 | |||
584 | Response.prototype.parseBody = function(str){ | ||
585 | var parse = request.parse[this.type]; | ||
586 | return parse && str && (str.length || str instanceof Object) | ||
587 | ? parse(str) | ||
588 | : null; | ||
589 | }; | ||
590 | |||
591 | /** | ||
592 | * Set flags such as `.ok` based on `status`. | ||
593 | * | ||
594 | * For example a 2xx response will give you a `.ok` of __true__ | ||
595 | * whereas 5xx will be __false__ and `.error` will be __true__. The | ||
596 | * `.clientError` and `.serverError` are also available to be more | ||
597 | * specific, and `.statusType` is the class of error ranging from 1..5 | ||
598 | * sometimes useful for mapping respond colors etc. | ||
599 | * | ||
600 | * "sugar" properties are also defined for common cases. Currently providing: | ||
601 | * | ||
602 | * - .noContent | ||
603 | * - .badRequest | ||
604 | * - .unauthorized | ||
605 | * - .notAcceptable | ||
606 | * - .notFound | ||
607 | * | ||
608 | * @param {Number} status | ||
609 | * @api private | ||
610 | */ | ||
611 | |||
612 | Response.prototype.setStatusProperties = function(status){ | ||
613 | // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request | ||
614 | if (status === 1223) { | ||
615 | status = 204; | ||
616 | } | ||
617 | |||
618 | var type = status / 100 | 0; | ||
619 | |||
620 | // status / class | ||
621 | this.status = this.statusCode = status; | ||
622 | this.statusType = type; | ||
623 | |||
624 | // basics | ||
625 | this.info = 1 == type; | ||
626 | this.ok = 2 == type; | ||
627 | this.clientError = 4 == type; | ||
628 | this.serverError = 5 == type; | ||
629 | this.error = (4 == type || 5 == type) | ||
630 | ? this.toError() | ||
631 | : false; | ||
632 | |||
633 | // sugar | ||
634 | this.accepted = 202 == status; | ||
635 | this.noContent = 204 == status; | ||
636 | this.badRequest = 400 == status; | ||
637 | this.unauthorized = 401 == status; | ||
638 | this.notAcceptable = 406 == status; | ||
639 | this.notFound = 404 == status; | ||
640 | this.forbidden = 403 == status; | ||
641 | }; | ||
642 | |||
643 | /** | ||
644 | * Return an `Error` representative of this response. | ||
645 | * | ||
646 | * @return {Error} | ||
647 | * @api public | ||
648 | */ | ||
649 | |||
650 | Response.prototype.toError = function(){ | ||
651 | var req = this.req; | ||
652 | var method = req.method; | ||
653 | var url = req.url; | ||
654 | |||
655 | var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')'; | ||
656 | var err = new Error(msg); | ||
657 | err.status = this.status; | ||
658 | err.method = method; | ||
659 | err.url = url; | ||
660 | |||
661 | return err; | ||
662 | }; | ||
663 | |||
664 | /** | ||
665 | * Expose `Response`. | ||
666 | */ | ||
667 | |||
668 | request.Response = Response; | ||
669 | |||
670 | /** | ||
671 | * Initialize a new `Request` with the given `method` and `url`. | ||
672 | * | ||
673 | * @param {String} method | ||
674 | * @param {String} url | ||
675 | * @api public | ||
676 | */ | ||
677 | |||
678 | function Request(method, url) { | ||
679 | var self = this; | ||
680 | Emitter.call(this); | ||
681 | this._query = this._query || []; | ||
682 | this.method = method; | ||
683 | this.url = url; | ||
684 | this.header = {}; | ||
685 | this._header = {}; | ||
686 | this.on('end', function(){ | ||
687 | var err = null; | ||
688 | var res = null; | ||
689 | |||
690 | try { | ||
691 | res = new Response(self); | ||
692 | } catch(e) { | ||
693 | err = new Error('Parser is unable to parse the response'); | ||
694 | err.parse = true; | ||
695 | err.original = e; | ||
696 | // issue #675: return the raw response if the response parsing fails | ||
697 | err.rawResponse = self.xhr && self.xhr.responseText ? self.xhr.responseText : null; | ||
698 | return self.callback(err); | ||
699 | } | ||
700 | |||
701 | self.emit('response', res); | ||
702 | |||
703 | if (err) { | ||
704 | return self.callback(err, res); | ||
705 | } | ||
706 | |||
707 | if (res.status >= 200 && res.status < 300) { | ||
708 | return self.callback(err, res); | ||
709 | } | ||
710 | |||
711 | var new_err = new Error(res.statusText || 'Unsuccessful HTTP response'); | ||
712 | new_err.original = err; | ||
713 | new_err.response = res; | ||
714 | new_err.status = res.status; | ||
715 | |||
716 | self.callback(new_err, res); | ||
717 | }); | ||
718 | } | ||
719 | |||
720 | /** | ||
721 | * Mixin `Emitter`. | ||
722 | */ | ||
723 | |||
724 | Emitter(Request.prototype); | ||
725 | |||
726 | /** | ||
727 | * Allow for extension | ||
728 | */ | ||
729 | |||
730 | Request.prototype.use = function(fn) { | ||
731 | fn(this); | ||
732 | return this; | ||
733 | } | ||
734 | |||
735 | /** | ||
736 | * Set timeout to `ms`. | ||
737 | * | ||
738 | * @param {Number} ms | ||
739 | * @return {Request} for chaining | ||
740 | * @api public | ||
741 | */ | ||
742 | |||
743 | Request.prototype.timeout = function(ms){ | ||
744 | this._timeout = ms; | ||
745 | return this; | ||
746 | }; | ||
747 | |||
748 | /** | ||
749 | * Clear previous timeout. | ||
750 | * | ||
751 | * @return {Request} for chaining | ||
752 | * @api public | ||
753 | */ | ||
754 | |||
755 | Request.prototype.clearTimeout = function(){ | ||
756 | this._timeout = 0; | ||
757 | clearTimeout(this._timer); | ||
758 | return this; | ||
759 | }; | ||
760 | |||
761 | /** | ||
762 | * Abort the request, and clear potential timeout. | ||
763 | * | ||
764 | * @return {Request} | ||
765 | * @api public | ||
766 | */ | ||
767 | |||
768 | Request.prototype.abort = function(){ | ||
769 | if (this.aborted) return; | ||
770 | this.aborted = true; | ||
771 | this.xhr.abort(); | ||
772 | this.clearTimeout(); | ||
773 | this.emit('abort'); | ||
774 | return this; | ||
775 | }; | ||
776 | |||
777 | /** | ||
778 | * Set header `field` to `val`, or multiple fields with one object. | ||
779 | * | ||
780 | * Examples: | ||
781 | * | ||
782 | * req.get('/') | ||
783 | * .set('Accept', 'application/json') | ||
784 | * .set('X-API-Key', 'foobar') | ||
785 | * .end(callback); | ||
786 | * | ||
787 | * req.get('/') | ||
788 | * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) | ||
789 | * .end(callback); | ||
790 | * | ||
791 | * @param {String|Object} field | ||
792 | * @param {String} val | ||
793 | * @return {Request} for chaining | ||
794 | * @api public | ||
795 | */ | ||
796 | |||
797 | Request.prototype.set = function(field, val){ | ||
798 | if (isObject(field)) { | ||
799 | for (var key in field) { | ||
800 | this.set(key, field[key]); | ||
801 | } | ||
802 | return this; | ||
803 | } | ||
804 | this._header[field.toLowerCase()] = val; | ||
805 | this.header[field] = val; | ||
806 | return this; | ||
807 | }; | ||
808 | |||
809 | /** | ||
810 | * Remove header `field`. | ||
811 | * | ||
812 | * Example: | ||
813 | * | ||
814 | * req.get('/') | ||
815 | * .unset('User-Agent') | ||
816 | * .end(callback); | ||
817 | * | ||
818 | * @param {String} field | ||
819 | * @return {Request} for chaining | ||
820 | * @api public | ||
821 | */ | ||
822 | |||
823 | Request.prototype.unset = function(field){ | ||
824 | delete this._header[field.toLowerCase()]; | ||
825 | delete this.header[field]; | ||
826 | return this; | ||
827 | }; | ||
828 | |||
829 | /** | ||
830 | * Get case-insensitive header `field` value. | ||
831 | * | ||
832 | * @param {String} field | ||
833 | * @return {String} | ||
834 | * @api private | ||
835 | */ | ||
836 | |||
837 | Request.prototype.getHeader = function(field){ | ||
838 | return this._header[field.toLowerCase()]; | ||
839 | }; | ||
840 | |||
841 | /** | ||
842 | * Set Content-Type to `type`, mapping values from `request.types`. | ||
843 | * | ||
844 | * Examples: | ||
845 | * | ||
846 | * superagent.types.xml = 'application/xml'; | ||
847 | * | ||
848 | * request.post('/') | ||
849 | * .type('xml') | ||
850 | * .send(xmlstring) | ||
851 | * .end(callback); | ||
852 | * | ||
853 | * request.post('/') | ||
854 | * .type('application/xml') | ||
855 | * .send(xmlstring) | ||
856 | * .end(callback); | ||
857 | * | ||
858 | * @param {String} type | ||
859 | * @return {Request} for chaining | ||
860 | * @api public | ||
861 | */ | ||
862 | |||
863 | Request.prototype.type = function(type){ | ||
864 | this.set('Content-Type', request.types[type] || type); | ||
865 | return this; | ||
866 | }; | ||
867 | |||
868 | /** | ||
869 | * Force given parser | ||
870 | * | ||
871 | * Sets the body parser no matter type. | ||
872 | * | ||
873 | * @param {Function} | ||
874 | * @api public | ||
875 | */ | ||
876 | |||
877 | Request.prototype.parse = function(fn){ | ||
878 | this._parser = fn; | ||
879 | return this; | ||
880 | }; | ||
881 | |||
882 | /** | ||
883 | * Set Accept to `type`, mapping values from `request.types`. | ||
884 | * | ||
885 | * Examples: | ||
886 | * | ||
887 | * superagent.types.json = 'application/json'; | ||
888 | * | ||
889 | * request.get('/agent') | ||
890 | * .accept('json') | ||
891 | * .end(callback); | ||
892 | * | ||
893 | * request.get('/agent') | ||
894 | * .accept('application/json') | ||
895 | * .end(callback); | ||
896 | * | ||
897 | * @param {String} accept | ||
898 | * @return {Request} for chaining | ||
899 | * @api public | ||
900 | */ | ||
901 | |||
902 | Request.prototype.accept = function(type){ | ||
903 | this.set('Accept', request.types[type] || type); | ||
904 | return this; | ||
905 | }; | ||
906 | |||
907 | /** | ||
908 | * Set Authorization field value with `user` and `pass`. | ||
909 | * | ||
910 | * @param {String} user | ||
911 | * @param {String} pass | ||
912 | * @return {Request} for chaining | ||
913 | * @api public | ||
914 | */ | ||
915 | |||
916 | Request.prototype.auth = function(user, pass){ | ||
917 | var str = btoa(user + ':' + pass); | ||
918 | this.set('Authorization', 'Basic ' + str); | ||
919 | return this; | ||
920 | }; | ||
921 | |||
922 | /** | ||
923 | * Add query-string `val`. | ||
924 | * | ||
925 | * Examples: | ||
926 | * | ||
927 | * request.get('/shoes') | ||
928 | * .query('size=10') | ||
929 | * .query({ color: 'blue' }) | ||
930 | * | ||
931 | * @param {Object|String} val | ||
932 | * @return {Request} for chaining | ||
933 | * @api public | ||
934 | */ | ||
935 | |||
936 | Request.prototype.query = function(val){ | ||
937 | if ('string' != typeof val) val = serialize(val); | ||
938 | if (val) this._query.push(val); | ||
939 | return this; | ||
940 | }; | ||
941 | |||
942 | /** | ||
943 | * Write the field `name` and `val` for "multipart/form-data" | ||
944 | * request bodies. | ||
945 | * | ||
946 | * ``` js | ||
947 | * request.post('/upload') | ||
948 | * .field('foo', 'bar') | ||
949 | * .end(callback); | ||
950 | * ``` | ||
951 | * | ||
952 | * @param {String} name | ||
953 | * @param {String|Blob|File} val | ||
954 | * @return {Request} for chaining | ||
955 | * @api public | ||
956 | */ | ||
957 | |||
958 | Request.prototype.field = function(name, val){ | ||
959 | if (!this._formData) this._formData = new root.FormData(); | ||
960 | this._formData.append(name, val); | ||
961 | return this; | ||
962 | }; | ||
963 | |||
964 | /** | ||
965 | * Queue the given `file` as an attachment to the specified `field`, | ||
966 | * with optional `filename`. | ||
967 | * | ||
968 | * ``` js | ||
969 | * request.post('/upload') | ||
970 | * .attach(new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"})) | ||
971 | * .end(callback); | ||
972 | * ``` | ||
973 | * | ||
974 | * @param {String} field | ||
975 | * @param {Blob|File} file | ||
976 | * @param {String} filename | ||
977 | * @return {Request} for chaining | ||
978 | * @api public | ||
979 | */ | ||
980 | |||
981 | Request.prototype.attach = function(field, file, filename){ | ||
982 | if (!this._formData) this._formData = new root.FormData(); | ||
983 | this._formData.append(field, file, filename || file.name); | ||
984 | return this; | ||
985 | }; | ||
986 | |||
987 | /** | ||
988 | * Send `data` as the request body, defaulting the `.type()` to "json" when | ||
989 | * an object is given. | ||
990 | * | ||
991 | * Examples: | ||
992 | * | ||
993 | * // manual json | ||
994 | * request.post('/user') | ||
995 | * .type('json') | ||
996 | * .send('{"name":"tj"}') | ||
997 | * .end(callback) | ||
998 | * | ||
999 | * // auto json | ||
1000 | * request.post('/user') | ||
1001 | * .send({ name: 'tj' }) | ||
1002 | * .end(callback) | ||
1003 | * | ||
1004 | * // manual x-www-form-urlencoded | ||
1005 | * request.post('/user') | ||
1006 | * .type('form') | ||
1007 | * .send('name=tj') | ||
1008 | * .end(callback) | ||
1009 | * | ||
1010 | * // auto x-www-form-urlencoded | ||
1011 | * request.post('/user') | ||
1012 | * .type('form') | ||
1013 | * .send({ name: 'tj' }) | ||
1014 | * .end(callback) | ||
1015 | * | ||
1016 | * // defaults to x-www-form-urlencoded | ||
1017 | * request.post('/user') | ||
1018 | * .send('name=tobi') | ||
1019 | * .send('species=ferret') | ||
1020 | * .end(callback) | ||
1021 | * | ||
1022 | * @param {String|Object} data | ||
1023 | * @return {Request} for chaining | ||
1024 | * @api public | ||
1025 | */ | ||
1026 | |||
1027 | Request.prototype.send = function(data){ | ||
1028 | var obj = isObject(data); | ||
1029 | var type = this.getHeader('Content-Type'); | ||
1030 | |||
1031 | // merge | ||
1032 | if (obj && isObject(this._data)) { | ||
1033 | for (var key in data) { | ||
1034 | this._data[key] = data[key]; | ||
1035 | } | ||
1036 | } else if ('string' == typeof data) { | ||
1037 | if (!type) this.type('form'); | ||
1038 | type = this.getHeader('Content-Type'); | ||
1039 | if ('application/x-www-form-urlencoded' == type) { | ||
1040 | this._data = this._data | ||
1041 | ? this._data + '&' + data | ||
1042 | : data; | ||
1043 | } else { | ||
1044 | this._data = (this._data || '') + data; | ||
1045 | } | ||
1046 | } else { | ||
1047 | this._data = data; | ||
1048 | } | ||
1049 | |||
1050 | if (!obj || isHost(data)) return this; | ||
1051 | if (!type) this.type('json'); | ||
1052 | return this; | ||
1053 | }; | ||
1054 | |||
1055 | /** | ||
1056 | * Invoke the callback with `err` and `res` | ||
1057 | * and handle arity check. | ||
1058 | * | ||
1059 | * @param {Error} err | ||
1060 | * @param {Response} res | ||
1061 | * @api private | ||
1062 | */ | ||
1063 | |||
1064 | Request.prototype.callback = function(err, res){ | ||
1065 | var fn = this._callback; | ||
1066 | this.clearTimeout(); | ||
1067 | fn(err, res); | ||
1068 | }; | ||
1069 | |||
1070 | /** | ||
1071 | * Invoke callback with x-domain error. | ||
1072 | * | ||
1073 | * @api private | ||
1074 | */ | ||
1075 | |||
1076 | Request.prototype.crossDomainError = function(){ | ||
1077 | var err = new Error('Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.'); | ||
1078 | err.crossDomain = true; | ||
1079 | |||
1080 | err.status = this.status; | ||
1081 | err.method = this.method; | ||
1082 | err.url = this.url; | ||
1083 | |||
1084 | this.callback(err); | ||
1085 | }; | ||
1086 | |||
1087 | /** | ||
1088 | * Invoke callback with timeout error. | ||
1089 | * | ||
1090 | * @api private | ||
1091 | */ | ||
1092 | |||
1093 | Request.prototype.timeoutError = function(){ | ||
1094 | var timeout = this._timeout; | ||
1095 | var err = new Error('timeout of ' + timeout + 'ms exceeded'); | ||
1096 | err.timeout = timeout; | ||
1097 | this.callback(err); | ||
1098 | }; | ||
1099 | |||
1100 | /** | ||
1101 | * Enable transmission of cookies with x-domain requests. | ||
1102 | * | ||
1103 | * Note that for this to work the origin must not be | ||
1104 | * using "Access-Control-Allow-Origin" with a wildcard, | ||
1105 | * and also must set "Access-Control-Allow-Credentials" | ||
1106 | * to "true". | ||
1107 | * | ||
1108 | * @api public | ||
1109 | */ | ||
1110 | |||
1111 | Request.prototype.withCredentials = function(){ | ||
1112 | this._withCredentials = true; | ||
1113 | return this; | ||
1114 | }; | ||
1115 | |||
1116 | /** | ||
1117 | * Initiate request, invoking callback `fn(res)` | ||
1118 | * with an instanceof `Response`. | ||
1119 | * | ||
1120 | * @param {Function} fn | ||
1121 | * @return {Request} for chaining | ||
1122 | * @api public | ||
1123 | */ | ||
1124 | |||
1125 | Request.prototype.end = function(fn){ | ||
1126 | var self = this; | ||
1127 | var xhr = this.xhr = request.getXHR(); | ||
1128 | var query = this._query.join('&'); | ||
1129 | var timeout = this._timeout; | ||
1130 | var data = this._formData || this._data; | ||
1131 | |||
1132 | // store callback | ||
1133 | this._callback = fn || noop; | ||
1134 | |||
1135 | // state change | ||
1136 | xhr.onreadystatechange = function(){ | ||
1137 | if (4 != xhr.readyState) return; | ||
1138 | |||
1139 | // In IE9, reads to any property (e.g. status) off of an aborted XHR will | ||
1140 | // result in the error "Could not complete the operation due to error c00c023f" | ||
1141 | var status; | ||
1142 | try { status = xhr.status } catch(e) { status = 0; } | ||
1143 | |||
1144 | if (0 == status) { | ||
1145 | if (self.timedout) return self.timeoutError(); | ||
1146 | if (self.aborted) return; | ||
1147 | return self.crossDomainError(); | ||
1148 | } | ||
1149 | self.emit('end'); | ||
1150 | }; | ||
1151 | |||
1152 | // progress | ||
1153 | var handleProgress = function(e){ | ||
1154 | if (e.total > 0) { | ||
1155 | e.percent = e.loaded / e.total * 100; | ||
1156 | } | ||
1157 | e.direction = 'download'; | ||
1158 | self.emit('progress', e); | ||
1159 | }; | ||
1160 | if (this.hasListeners('progress')) { | ||
1161 | xhr.onprogress = handleProgress; | ||
1162 | } | ||
1163 | try { | ||
1164 | if (xhr.upload && this.hasListeners('progress')) { | ||
1165 | xhr.upload.onprogress = handleProgress; | ||
1166 | } | ||
1167 | } catch(e) { | ||
1168 | // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist. | ||
1169 | // Reported here: | ||
1170 | // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context | ||
1171 | } | ||
1172 | |||
1173 | // timeout | ||
1174 | if (timeout && !this._timer) { | ||
1175 | this._timer = setTimeout(function(){ | ||
1176 | self.timedout = true; | ||
1177 | self.abort(); | ||
1178 | }, timeout); | ||
1179 | } | ||
1180 | |||
1181 | // querystring | ||
1182 | if (query) { | ||
1183 | query = request.serializeObject(query); | ||
1184 | this.url += ~this.url.indexOf('?') | ||
1185 | ? '&' + query | ||
1186 | : '?' + query; | ||
1187 | } | ||
1188 | |||
1189 | // initiate request | ||
1190 | xhr.open(this.method, this.url, true); | ||
1191 | |||
1192 | // CORS | ||
1193 | if (this._withCredentials) xhr.withCredentials = true; | ||
1194 | |||
1195 | // body | ||
1196 | if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) { | ||
1197 | // serialize stuff | ||
1198 | var contentType = this.getHeader('Content-Type'); | ||
1199 | var serialize = this._parser || request.serialize[contentType ? contentType.split(';')[0] : '']; | ||
1200 | if (!serialize && isJSON(contentType)) serialize = request.serialize['application/json']; | ||
1201 | if (serialize) data = serialize(data); | ||
1202 | } | ||
1203 | |||
1204 | // set header fields | ||
1205 | for (var field in this.header) { | ||
1206 | if (null == this.header[field]) continue; | ||
1207 | xhr.setRequestHeader(field, this.header[field]); | ||
1208 | } | ||
1209 | |||
1210 | // send stuff | ||
1211 | this.emit('request', this); | ||
1212 | |||
1213 | // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing) | ||
1214 | // We need null here if data is undefined | ||
1215 | xhr.send(typeof data !== 'undefined' ? data : null); | ||
1216 | return this; | ||
1217 | }; | ||
1218 | |||
1219 | /** | ||
1220 | * Faux promise support | ||
1221 | * | ||
1222 | * @param {Function} fulfill | ||
1223 | * @param {Function} reject | ||
1224 | * @return {Request} | ||
1225 | */ | ||
1226 | |||
1227 | Request.prototype.then = function (fulfill, reject) { | ||
1228 | return this.end(function(err, res) { | ||
1229 | err ? reject(err) : fulfill(res); | ||
1230 | }); | ||
1231 | } | ||
1232 | |||
1233 | /** | ||
1234 | * Expose `Request`. | ||
1235 | */ | ||
1236 | |||
1237 | request.Request = Request; | ||
1238 | |||
1239 | /** | ||
1240 | * Issue a request: | ||
1241 | * | ||
1242 | * Examples: | ||
1243 | * | ||
1244 | * request('GET', '/users').end(callback) | ||
1245 | * request('/users').end(callback) | ||
1246 | * request('/users', callback) | ||
1247 | * | ||
1248 | * @param {String} method | ||
1249 | * @param {String|Function} url or callback | ||
1250 | * @return {Request} | ||
1251 | * @api public | ||
1252 | */ | ||
1253 | |||
1254 | function request(method, url) { | ||
1255 | // callback | ||
1256 | if ('function' == typeof url) { | ||
1257 | return new Request('GET', method).end(url); | ||
1258 | } | ||
1259 | |||
1260 | // url first | ||
1261 | if (1 == arguments.length) { | ||
1262 | return new Request('GET', method); | ||
1263 | } | ||
1264 | |||
1265 | return new Request(method, url); | ||
1266 | } | ||
1267 | |||
1268 | /** | ||
1269 | * GET `url` with optional callback `fn(res)`. | ||
1270 | * | ||
1271 | * @param {String} url | ||
1272 | * @param {Mixed|Function} data or fn | ||
1273 | * @param {Function} fn | ||
1274 | * @return {Request} | ||
1275 | * @api public | ||
1276 | */ | ||
1277 | |||
1278 | request.get = function(url, data, fn){ | ||
1279 | var req = request('GET', url); | ||
1280 | if ('function' == typeof data) fn = data, data = null; | ||
1281 | if (data) req.query(data); | ||
1282 | if (fn) req.end(fn); | ||
1283 | return req; | ||
1284 | }; | ||
1285 | |||
1286 | /** | ||
1287 | * HEAD `url` with optional callback `fn(res)`. | ||
1288 | * | ||
1289 | * @param {String} url | ||
1290 | * @param {Mixed|Function} data or fn | ||
1291 | * @param {Function} fn | ||
1292 | * @return {Request} | ||
1293 | * @api public | ||
1294 | */ | ||
1295 | |||
1296 | request.head = function(url, data, fn){ | ||
1297 | var req = request('HEAD', url); | ||
1298 | if ('function' == typeof data) fn = data, data = null; | ||
1299 | if (data) req.send(data); | ||
1300 | if (fn) req.end(fn); | ||
1301 | return req; | ||
1302 | }; | ||
1303 | |||
1304 | /** | ||
1305 | * DELETE `url` with optional callback `fn(res)`. | ||
1306 | * | ||
1307 | * @param {String} url | ||
1308 | * @param {Function} fn | ||
1309 | * @return {Request} | ||
1310 | * @api public | ||
1311 | */ | ||
1312 | |||
1313 | function del(url, fn){ | ||
1314 | var req = request('DELETE', url); | ||
1315 | if (fn) req.end(fn); | ||
1316 | return req; | ||
1317 | }; | ||
1318 | |||
1319 | request['del'] = del; | ||
1320 | request['delete'] = del; | ||
1321 | |||
1322 | /** | ||
1323 | * PATCH `url` with optional `data` and callback `fn(res)`. | ||
1324 | * | ||
1325 | * @param {String} url | ||
1326 | * @param {Mixed} data | ||
1327 | * @param {Function} fn | ||
1328 | * @return {Request} | ||
1329 | * @api public | ||
1330 | */ | ||
1331 | |||
1332 | request.patch = function(url, data, fn){ | ||
1333 | var req = request('PATCH', url); | ||
1334 | if ('function' == typeof data) fn = data, data = null; | ||
1335 | if (data) req.send(data); | ||
1336 | if (fn) req.end(fn); | ||
1337 | return req; | ||
1338 | }; | ||
1339 | |||
1340 | /** | ||
1341 | * POST `url` with optional `data` and callback `fn(res)`. | ||
1342 | * | ||
1343 | * @param {String} url | ||
1344 | * @param {Mixed} data | ||
1345 | * @param {Function} fn | ||
1346 | * @return {Request} | ||
1347 | * @api public | ||
1348 | */ | ||
1349 | |||
1350 | request.post = function(url, data, fn){ | ||
1351 | var req = request('POST', url); | ||
1352 | if ('function' == typeof data) fn = data, data = null; | ||
1353 | if (data) req.send(data); | ||
1354 | if (fn) req.end(fn); | ||
1355 | return req; | ||
1356 | }; | ||
1357 | |||
1358 | /** | ||
1359 | * PUT `url` with optional `data` and callback `fn(res)`. | ||
1360 | * | ||
1361 | * @param {String} url | ||
1362 | * @param {Mixed|Function} data or fn | ||
1363 | * @param {Function} fn | ||
1364 | * @return {Request} | ||
1365 | * @api public | ||
1366 | */ | ||
1367 | |||
1368 | request.put = function(url, data, fn){ | ||
1369 | var req = request('PUT', url); | ||
1370 | if ('function' == typeof data) fn = data, data = null; | ||
1371 | if (data) req.send(data); | ||
1372 | if (fn) req.end(fn); | ||
1373 | return req; | ||
1374 | }; | ||
1375 | |||
1376 | /** | ||
1377 | * Expose `request`. | ||
1378 | */ | ||
1379 | |||
1380 | module.exports = request; | ||
1381 | |||
1382 | },{"emitter":1,"reduce":2}]},{},[3])(3) | ||
1383 | }); \ No newline at end of file | ||