diff options
| author | ruki <waruqi@gmail.com> | 2018-11-08 00:38:48 +0800 |
|---|---|---|
| committer | ruki <waruqi@gmail.com> | 2018-11-07 21:53:09 +0800 |
| commit | 26105034da4fcce7ac883c899d781f016559310d (patch) | |
| tree | c459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/algoliasearch/dist | |
| parent | 2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff) | |
| download | xmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip | |
switch to vuepress
Diffstat (limited to 'node_modules/algoliasearch/dist')
8 files changed, 25351 insertions, 0 deletions
diff --git a/node_modules/algoliasearch/dist/algoliasearch.angular.js b/node_modules/algoliasearch/dist/algoliasearch.angular.js new file mode 100644 index 00000000..00c1edb4 --- /dev/null +++ b/node_modules/algoliasearch/dist/algoliasearch.angular.js @@ -0,0 +1,7088 @@ +/*! algoliasearch 3.30.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +(function(f){var g;if(typeof window!=='undefined'){g=window}else if(typeof self!=='undefined'){g=self}g.ALGOLIA_MIGRATION_LAYER=f()})(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){ + +module.exports = function load (src, opts, cb) { + var head = document.head || document.getElementsByTagName('head')[0] + var script = document.createElement('script') + + if (typeof opts === 'function') { + cb = opts + opts = {} + } + + opts = opts || {} + cb = cb || function() {} + + script.type = opts.type || 'text/javascript' + script.charset = opts.charset || 'utf8'; + script.async = 'async' in opts ? !!opts.async : true + script.src = src + + if (opts.attrs) { + setAttributes(script, opts.attrs) + } + + if (opts.text) { + script.text = '' + opts.text + } + + var onend = 'onload' in script ? stdOnEnd : ieOnEnd + onend(script, cb) + + // some good legacy browsers (firefox) fail the 'in' detection above + // so as a fallback we always set onload + // old IE will ignore this and new IE will set onload + if (!script.onload) { + stdOnEnd(script, cb); + } + + head.appendChild(script) +} + +function setAttributes(script, attrs) { + for (var attr in attrs) { + script.setAttribute(attr, attrs[attr]); + } +} + +function stdOnEnd (script, cb) { + script.onload = function () { + this.onerror = this.onload = null + cb(null, script) + } + script.onerror = function () { + // this.onload = null here is necessary + // because even IE9 works not like others + this.onerror = this.onload = null + cb(new Error('Failed to load ' + this.src), script) + } +} + +function ieOnEnd (script, cb) { + script.onreadystatechange = function () { + if (this.readyState != 'complete' && this.readyState != 'loaded') return + this.onreadystatechange = null + cb(null, script) // there is no way to catch loading errors in IE8 + } +} + +},{}],2:[function(require,module,exports){ +'use strict'; + +// this module helps finding if the current page is using +// the cdn.jsdelivr.net/algoliasearch/latest/$BUILDNAME.min.js version + +module.exports = isUsingLatest; + +function isUsingLatest(buildName) { + var toFind = new RegExp('cdn\\.jsdelivr\\.net/algoliasearch/latest/' + + buildName.replace('.', '\\.') + // algoliasearch, algoliasearch.angular + '(?:\\.min)?\\.js$'); // [.min].js + + var scripts = document.getElementsByTagName('script'); + var found = false; + for (var currentScript = 0, nbScripts = scripts.length; currentScript < nbScripts; currentScript++) { + if (scripts[currentScript].src && toFind.test(scripts[currentScript].src)) { + found = true; + break; + } + } + + return found; +} + +},{}],3:[function(require,module,exports){ +'use strict'; + +module.exports = loadV2; + +function loadV2(buildName) { + var loadScript = require(1); + var v2ScriptUrl = '//cdn.jsdelivr.net/algoliasearch/2/' + buildName + '.min.js'; + + var message = '-- AlgoliaSearch `latest` warning --\n' + + 'Warning, you are using the `latest` version string from jsDelivr to load the AlgoliaSearch library.\n' + + 'Using `latest` is no more recommended, you should load //cdn.jsdelivr.net/algoliasearch/2/algoliasearch.min.js\n\n' + + 'Also, we updated the AlgoliaSearch JavaScript client to V3. If you want to upgrade,\n' + + 'please read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n' + + '-- /AlgoliaSearch `latest` warning --'; + + if (window.console) { + if (window.console.warn) { + window.console.warn(message); + } else if (window.console.log) { + window.console.log(message); + } + } + + // If current script loaded asynchronously, + // it will load the script with DOMElement + // otherwise, it will load the script with document.write + try { + // why \x3c? http://stackoverflow.com/a/236106/147079 + document.write('\x3Cscript>window.ALGOLIA_SUPPORTS_DOCWRITE = true\x3C/script>'); + + if (window.ALGOLIA_SUPPORTS_DOCWRITE === true) { + document.write('\x3Cscript src="' + v2ScriptUrl + '">\x3C/script>'); + scriptLoaded('document.write')(); + } else { + loadScript(v2ScriptUrl, scriptLoaded('DOMElement')); + } + } catch (e) { + loadScript(v2ScriptUrl, scriptLoaded('DOMElement')); + } +} + +function scriptLoaded(method) { + return function log() { + var message = 'AlgoliaSearch: loaded V2 script using ' + method; + + if (window.console && window.console.log) { + window.console.log(message); + } + }; +} + +},{"1":1}],4:[function(require,module,exports){ +'use strict'; + +/* eslint no-unused-vars: [2, {"vars": "local"}] */ + +module.exports = oldGlobals; + +// put old window.AlgoliaSearch.. into window. again so that +// users upgrading to V3 without changing their code, will be warned +function oldGlobals() { + var message = '-- AlgoliaSearch V2 => V3 error --\n' + + 'You are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\n' + + 'Please read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n' + + '-- /AlgoliaSearch V2 => V3 error --'; + + window.AlgoliaSearch = function() { + throw new Error(message); + }; + + window.AlgoliaSearchHelper = function() { + throw new Error(message); + }; + + window.AlgoliaExplainResults = function() { + throw new Error(message); + }; +} + +},{}],5:[function(require,module,exports){ +'use strict'; + +// This script will be browserified and prepended to the normal build +// directly in window, not wrapped in any module definition +// To avoid cases where we are loaded with /latest/ along with +migrationLayer("algoliasearch.angular"); + +// Now onto the V2 related code: +// If the client is using /latest/$BUILDNAME.min.js, load V2 of the library +// +// Otherwise, setup a migration layer that will throw on old constructors like +// new AlgoliaSearch(). +// So that users upgrading from v2 to v3 will have a clear information +// message on what to do if they did not read the migration guide +function migrationLayer(buildName) { + var isUsingLatest = require(2); + var loadV2 = require(3); + var oldGlobals = require(4); + + if (isUsingLatest(buildName)) { + loadV2(buildName); + } else { + oldGlobals(); + } +} + +},{"2":2,"3":3,"4":4}]},{},[5])(5) +});(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){ +(function (process){ +/** + * This is the web browser implementation of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = require(2); +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); + +/** + * Colors. + */ + +exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' +]; + +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ + +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; + } + + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} + +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; + } +}; + + +/** + * Colorize log arguments if enabled. + * + * @api public + */ + +function formatArgs(args) { + var useColors = this.useColors; + + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); + + if (!useColors) return; + + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit') + + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); + + args.splice(lastC, 0, c); +} + +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ + +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); +} + +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ + +function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + + return r; +} + +/** + * Enable namespaces listed in `localStorage.debug` initially. + */ + +exports.enable(load()); + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + return window.localStorage; + } catch (e) {} +} + +}).call(this,require(12)) +},{"12":12,"2":2}],2:[function(require,module,exports){ + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = require(9); + +/** + * The currently active debug mode names, and names to skip. + */ + +exports.names = []; +exports.skips = []; + +/** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + +exports.formatters = {}; + +/** + * Previous log timestamp. + */ + +var prevTime; + +/** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ + +function selectColor(namespace) { + var hash = 0, i; + + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return exports.colors[Math.abs(hash) % exports.colors.length]; +} + +/** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + +function createDebug(namespace) { + + function debug() { + // disabled? + if (!debug.enabled) return; + + var self = debug; + + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + + args[0] = exports.coerce(args[0]); + + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); + } + + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); + + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); + + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); + + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); + } + + return debug; +} + +/** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + +function enable(namespaces) { + exports.save(namespaces); + + exports.names = []; + exports.skips = []; + + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } + } +} + +/** + * Disable debug output. + * + * @api public + */ + +function disable() { + exports.enable(''); +} + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } + } + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } + } + return false; +} + +/** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + +},{"9":9}],3:[function(require,module,exports){ +(function (process,global){ +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE + * @version 4.1.1 + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.ES6Promise = factory()); +}(this, (function () { 'use strict'; + +function objectOrFunction(x) { + var type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} + +function isFunction(x) { + return typeof x === 'function'; +} + +var _isArray = undefined; +if (Array.isArray) { + _isArray = Array.isArray; +} else { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; +} + +var isArray = _isArray; + +var len = 0; +var vertxNext = undefined; +var customSchedulerFn = undefined; + +var asap = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (customSchedulerFn) { + customSchedulerFn(flush); + } else { + scheduleFlush(); + } + } +}; + +function setScheduler(scheduleFn) { + customSchedulerFn = scheduleFn; +} + +function setAsap(asapFn) { + asap = asapFn; +} + +var browserWindow = typeof window !== 'undefined' ? window : undefined; +var browserGlobal = browserWindow || {}; +var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; +var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]'; + +// test for web worker but not in IE10 +var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; + +// node +function useNextTick() { + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // see https://github.com/cujojs/when/issues/410 for details + return function () { + return process.nextTick(flush); + }; +} + +// vertx +function useVertxTimer() { + if (typeof vertxNext !== 'undefined') { + return function () { + vertxNext(flush); + }; + } + + return useSetTimeout(); +} + +function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function () { + node.data = iterations = ++iterations % 2; + }; +} + +// web worker +function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + return channel.port2.postMessage(0); + }; +} + +function useSetTimeout() { + // Store setTimeout reference so es6-promise will be unaffected by + // other code modifying setTimeout (like sinon.useFakeTimers()) + var globalSetTimeout = setTimeout; + return function () { + return globalSetTimeout(flush, 1); + }; +} + +var queue = new Array(1000); +function flush() { + for (var i = 0; i < len; i += 2) { + var callback = queue[i]; + var arg = queue[i + 1]; + + callback(arg); + + queue[i] = undefined; + queue[i + 1] = undefined; + } + + len = 0; +} + +function attemptVertx() { + try { + var r = require; + var vertx = r('vertx'); + vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch (e) { + return useSetTimeout(); + } +} + +var scheduleFlush = undefined; +// Decide what async method to use to triggering processing of queued callbacks: +if (isNode) { + scheduleFlush = useNextTick(); +} else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); +} else if (isWorker) { + scheduleFlush = useMessageChannel(); +} else if (browserWindow === undefined && typeof require === 'function') { + scheduleFlush = attemptVertx(); +} else { + scheduleFlush = useSetTimeout(); +} + +function then(onFulfillment, onRejection) { + var _arguments = arguments; + + var parent = this; + + var child = new this.constructor(noop); + + if (child[PROMISE_ID] === undefined) { + makePromise(child); + } + + var _state = parent._state; + + if (_state) { + (function () { + var callback = _arguments[_state - 1]; + asap(function () { + return invokeCallback(_state, child, callback, parent._result); + }); + })(); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; +} + +/** + `Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` +*/ +function resolve$1(object) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop); + resolve(promise, object); + return promise; +} + +var PROMISE_ID = Math.random().toString(36).substring(16); + +function noop() {} + +var PENDING = void 0; +var FULFILLED = 1; +var REJECTED = 2; + +var GET_THEN_ERROR = new ErrorObject(); + +function selfFulfillment() { + return new TypeError("You cannot resolve a promise with itself"); +} + +function cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); +} + +function getThen(promise) { + try { + return promise.then; + } catch (error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } +} + +function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) { + try { + then$$1.call(value, fulfillmentHandler, rejectionHandler); + } catch (e) { + return e; + } +} + +function handleForeignThenable(promise, thenable, then$$1) { + asap(function (promise) { + var sealed = false; + var error = tryThen(then$$1, thenable, function (value) { + if (sealed) { + return; + } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function (reason) { + if (sealed) { + return; + } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); +} + +function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (thenable._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function (value) { + return resolve(promise, value); + }, function (reason) { + return reject(promise, reason); + }); + } +} + +function handleMaybeThenable(promise, maybeThenable, then$$1) { + if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) { + handleOwnThenable(promise, maybeThenable); + } else { + if (then$$1 === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + GET_THEN_ERROR.error = null; + } else if (then$$1 === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then$$1)) { + handleForeignThenable(promise, maybeThenable, then$$1); + } else { + fulfill(promise, maybeThenable); + } + } +} + +function resolve(promise, value) { + if (promise === value) { + reject(promise, selfFulfillment()); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value, getThen(value)); + } else { + fulfill(promise, value); + } +} + +function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); +} + +function fulfill(promise, value) { + if (promise._state !== PENDING) { + return; + } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length !== 0) { + asap(publish, promise); + } +} + +function reject(promise, reason) { + if (promise._state !== PENDING) { + return; + } + promise._state = REJECTED; + promise._result = reason; + + asap(publishRejection, promise); +} + +function subscribe(parent, child, onFulfillment, onRejection) { + var _subscribers = parent._subscribers; + var length = _subscribers.length; + + parent._onerror = null; + + _subscribers[length] = child; + _subscribers[length + FULFILLED] = onFulfillment; + _subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + asap(publish, parent); + } +} + +function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (subscribers.length === 0) { + return; + } + + var child = undefined, + callback = undefined, + detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; +} + +function ErrorObject() { + this.error = null; +} + +var TRY_CATCH_ERROR = new ErrorObject(); + +function tryCatch(callback, detail) { + try { + return callback(detail); + } catch (e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } +} + +function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value = undefined, + error = undefined, + succeeded = undefined, + failed = undefined; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value.error = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, cannotReturnOwn()); + return; + } + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } +} + +function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value) { + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch (e) { + reject(promise, e); + } +} + +var id = 0; +function nextId() { + return id++; +} + +function makePromise(promise) { + promise[PROMISE_ID] = id++; + promise._state = undefined; + promise._result = undefined; + promise._subscribers = []; +} + +function Enumerator$1(Constructor, input) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop); + + if (!this.promise[PROMISE_ID]) { + makePromise(this.promise); + } + + if (isArray(input)) { + this.length = input.length; + this._remaining = input.length; + + this._result = new Array(this.length); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(input); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, validationError()); + } +} + +function validationError() { + return new Error('Array Methods must be provided an Array'); +} + +Enumerator$1.prototype._enumerate = function (input) { + for (var i = 0; this._state === PENDING && i < input.length; i++) { + this._eachEntry(input[i], i); + } +}; + +Enumerator$1.prototype._eachEntry = function (entry, i) { + var c = this._instanceConstructor; + var resolve$$1 = c.resolve; + + if (resolve$$1 === resolve$1) { + var _then = getThen(entry); + + if (_then === then && entry._state !== PENDING) { + this._settledAt(entry._state, i, entry._result); + } else if (typeof _then !== 'function') { + this._remaining--; + this._result[i] = entry; + } else if (c === Promise$2) { + var promise = new c(noop); + handleMaybeThenable(promise, entry, _then); + this._willSettleAt(promise, i); + } else { + this._willSettleAt(new c(function (resolve$$1) { + return resolve$$1(entry); + }), i); + } + } else { + this._willSettleAt(resolve$$1(entry), i); + } +}; + +Enumerator$1.prototype._settledAt = function (state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = value; + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } +}; + +Enumerator$1.prototype._willSettleAt = function (promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function (value) { + return enumerator._settledAt(FULFILLED, i, value); + }, function (reason) { + return enumerator._settledAt(REJECTED, i, reason); + }); +}; + +/** + `Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = resolve(2); + let promise3 = resolve(3); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = reject(new Error("2")); + let promise3 = reject(new Error("3")); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static +*/ +function all$1(entries) { + return new Enumerator$1(this, entries).promise; +} + +/** + `Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. +*/ +function race$1(entries) { + /*jshint validthis:true */ + var Constructor = this; + + if (!isArray(entries)) { + return new Constructor(function (_, reject) { + return reject(new TypeError('You must pass an array to race.')); + }); + } else { + return new Constructor(function (resolve, reject) { + var length = entries.length; + for (var i = 0; i < length; i++) { + Constructor.resolve(entries[i]).then(resolve, reject); + } + }); + } +} + +/** + `Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. +*/ +function reject$1(reason) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop); + reject(promise, reason); + return promise; +} + +function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); +} + +function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); +} + +/** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + let promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + let xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {function} resolver + Useful for tooling. + @constructor +*/ +function Promise$2(resolver) { + this[PROMISE_ID] = nextId(); + this._result = this._state = undefined; + this._subscribers = []; + + if (noop !== resolver) { + typeof resolver !== 'function' && needsResolver(); + this instanceof Promise$2 ? initializePromise(this, resolver) : needsNew(); + } +} + +Promise$2.all = all$1; +Promise$2.race = race$1; +Promise$2.resolve = resolve$1; +Promise$2.reject = reject$1; +Promise$2._setScheduler = setScheduler; +Promise$2._setAsap = setAsap; +Promise$2._asap = asap; + +Promise$2.prototype = { + constructor: Promise$2, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + let result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + let author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: then, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function _catch(onRejection) { + return this.then(null, onRejection); + } +}; + +/*global self*/ +function polyfill$1() { + var local = undefined; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } + + var P = local.Promise; + + if (P) { + var promiseToString = null; + try { + promiseToString = Object.prototype.toString.call(P.resolve()); + } catch (e) { + // silently ignored + } + + if (promiseToString === '[object Promise]' && !P.cast) { + return; + } + } + + local.Promise = Promise$2; +} + +// Strange compat.. +Promise$2.polyfill = polyfill$1; +Promise$2.Promise = Promise$2; + +return Promise$2; + +}))); + + + +}).call(this,require(12),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"12":12}],4:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); + err.context = er; + throw err; + } + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + args = Array.prototype.slice.call(arguments, 1); + handler.apply(this, args); + } + } else if (isObject(handler)) { + args = Array.prototype.slice.call(arguments, 1); + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.prototype.listenerCount = function(type) { + if (this._events) { + var evlistener = this._events[type]; + + if (isFunction(evlistener)) + return 1; + else if (evlistener) + return evlistener.length; + } + return 0; +}; + +EventEmitter.listenerCount = function(emitter, type) { + return emitter.listenerCount(type); +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],5:[function(require,module,exports){ + +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; + +module.exports = function forEach (obj, fn, ctx) { + if (toString.call(fn) !== '[object Function]') { + throw new TypeError('iterator must be a function'); + } + var l = obj.length; + if (l === +l) { + for (var i = 0; i < l; i++) { + fn.call(ctx, obj[i], i, obj); + } + } else { + for (var k in obj) { + if (hasOwn.call(obj, k)) { + fn.call(ctx, obj[k], k, obj); + } + } + } +}; + + +},{}],6:[function(require,module,exports){ +(function (global){ +var win; + +if (typeof window !== "undefined") { + win = window; +} else if (typeof global !== "undefined") { + win = global; +} else if (typeof self !== "undefined"){ + win = self; +} else { + win = {}; +} + +module.exports = win; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],7:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],8:[function(require,module,exports){ +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; + +},{}],9:[function(require,module,exports){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + if (ms >= d) { + return Math.round(ms / d) + 'd'; + } + if (ms >= h) { + return Math.round(ms / h) + 'h'; + } + if (ms >= m) { + return Math.round(ms / m) + 'm'; + } + if (ms >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + return plural(ms, d, 'day') || + plural(ms, h, 'hour') || + plural(ms, m, 'minute') || + plural(ms, s, 'second') || + ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) { + return; + } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; + } + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +},{}],10:[function(require,module,exports){ +'use strict'; + +// modified from https://github.com/es-shims/es5-shim +var has = Object.prototype.hasOwnProperty; +var toStr = Object.prototype.toString; +var slice = Array.prototype.slice; +var isArgs = require(11); +var isEnumerable = Object.prototype.propertyIsEnumerable; +var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); +var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); +var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' +]; +var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; +}; +var excludedKeys = { + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true +}; +var hasAutomationEqualityBug = (function () { + /* global window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; +}()); +var equalsConstructorPrototypeIfNotBuggy = function (o) { + /* global window */ + if (typeof window === 'undefined' || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } +}; + +var keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; + + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } + + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; +}; + +keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function () { + // Safari 5.0 bug + return (Object.keys(arguments) || '').length === 2; + }(1, 2)); + if (!keysWorksWithArguments) { + var originalKeys = Object.keys; + Object.keys = function keys(object) { + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } else { + return originalKeys(object); + } + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; +}; + +module.exports = keysShim; + +},{"11":11}],11:[function(require,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + toStr.call(value.callee) === '[object Function]'; + } + return isArgs; +}; + +},{}],12:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],13:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; + + case 'boolean': + return v ? 'true' : 'false'; + + case 'number': + return isFinite(v) ? v : ''; + + default: + return ''; + } +}; + +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; + } + + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); + } + }).join(sep); + + } + + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); + } + return res; +} + +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + return res; +}; + +},{}],14:[function(require,module,exports){ +module.exports = AlgoliaSearch; + +var Index = require(16); +var deprecate = require(27); +var deprecatedMessage = require(28); +var AlgoliaSearchCore = require(15); +var inherits = require(7); +var errors = require(29); + +function AlgoliaSearch() { + AlgoliaSearchCore.apply(this, arguments); +} + +inherits(AlgoliaSearch, AlgoliaSearchCore); + +/* + * Delete an index + * + * @param indexName the name of index to delete + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.deleteIndex = function(indexName, callback) { + return this._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexName), + hostType: 'write', + callback: callback + }); +}; + +/** + * Move an existing index. + * @param srcIndexName the name of index to copy. + * @param dstIndexName the new index name that will contains a copy of + * srcIndexName (destination will be overriten if it already exist). + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.moveIndex = function(srcIndexName, dstIndexName, callback) { + var postObj = { + operation: 'move', destination: dstIndexName + }; + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Copy an existing index. + * @param srcIndexName the name of index to copy. + * @param dstIndexName the new index name that will contains a copy + * of srcIndexName (destination will be overriten if it already exist). + * @param scope an array of scopes to copy: ['settings', 'synonyms', 'rules'] + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.copyIndex = function(srcIndexName, dstIndexName, scopeOrCallback, _callback) { + var postObj = { + operation: 'copy', + destination: dstIndexName + }; + var callback = _callback; + if (typeof scopeOrCallback === 'function') { + // oops, old behaviour of third argument being a function + callback = scopeOrCallback; + } else if (Array.isArray(scopeOrCallback) && scopeOrCallback.length > 0) { + postObj.scope = scopeOrCallback; + } else if (typeof scopeOrCallback !== 'undefined') { + throw new Error('the scope given to `copyIndex` was not an array with settings, synonyms or rules'); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Return last log entries. + * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry). + * @param length Specify the maximum number of entries to retrieve starting + * at offset. Maximum allowed value: 1000. + * @param type Specify the maximum number of entries to retrieve starting + * at offset. Maximum allowed value: 1000. + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.getLogs = function(offset, length, callback) { + var clone = require(25); + var params = {}; + if (typeof offset === 'object') { + // getLogs(params) + params = clone(offset); + callback = length; + } else if (arguments.length === 0 || typeof offset === 'function') { + // getLogs([cb]) + callback = offset; + } else if (arguments.length === 1 || typeof length === 'function') { + // getLogs(1, [cb)] + callback = length; + params.offset = offset; + } else { + // getLogs(1, 2, [cb]) + params.offset = offset; + params.length = length; + } + + if (params.offset === undefined) params.offset = 0; + if (params.length === undefined) params.length = 10; + + return this._jsonRequest({ + method: 'GET', + url: '/1/logs?' + this._getSearchParams(params, ''), + hostType: 'read', + callback: callback + }); +}; + +/* + * List all existing indexes (paginated) + * + * @param page The page to retrieve, starting at 0. + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with index list + */ +AlgoliaSearch.prototype.listIndexes = function(page, callback) { + var params = ''; + + if (page === undefined || typeof page === 'function') { + callback = page; + } else { + params = '?page=' + page; + } + + return this._jsonRequest({ + method: 'GET', + url: '/1/indexes' + params, + hostType: 'read', + callback: callback + }); +}; + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearch.prototype.initIndex = function(indexName) { + return new Index(this, indexName); +}; + +AlgoliaSearch.prototype.initAnalytics = function(opts) { + // the actual require must be inside the function, when put outside then you have a cyclic dependency + // not well resolved that ends up making the main "./index.js" (main module, the agloliasearch function) + // export an object instead of a function + // Other workarounds: + // - rewrite the lib in ES6, cyclic dependencies may be better supported + // - move initAnalytics to a property on the main module (algoliasearch.initAnalytics), + // same as places. + // The current API was made mostly to mimic the one made in PHP + var createAnalyticsClient = require(26); + return createAnalyticsClient(this.applicationID, this.apiKey, opts); +}; + +/* + * @deprecated use client.listApiKeys + */ +AlgoliaSearch.prototype.listUserKeys = deprecate(function(callback) { + return this.listApiKeys(callback); +}, deprecatedMessage('client.listUserKeys()', 'client.listApiKeys()')); + +/* + * List all existing api keys with their associated ACLs + * + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with api keys list + */ +AlgoliaSearch.prototype.listApiKeys = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/keys', + hostType: 'read', + callback: callback + }); +}; + +/* + * @deprecated see client.getApiKey + */ +AlgoliaSearch.prototype.getUserKeyACL = deprecate(function(key, callback) { + return this.getApiKey(key, callback); +}, deprecatedMessage('client.getUserKeyACL()', 'client.getApiKey()')); + +/* + * Get an API key + * + * @param key + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the right API key + */ +AlgoliaSearch.prototype.getApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/keys/' + key, + hostType: 'read', + callback: callback + }); +}; + +/* + * @deprecated see client.deleteApiKey + */ +AlgoliaSearch.prototype.deleteUserKey = deprecate(function(key, callback) { + return this.deleteApiKey(key, callback); +}, deprecatedMessage('client.deleteUserKey()', 'client.deleteApiKey()')); + +/* + * Delete an existing API key + * @param key + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the date of deletion + */ +AlgoliaSearch.prototype.deleteApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'DELETE', + url: '/1/keys/' + key, + hostType: 'write', + callback: callback + }); +}; + +/* + @deprecated see client.addApiKey + */ +AlgoliaSearch.prototype.addUserKey = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('client.addUserKey()', 'client.addApiKey()')); + +/* + * Add a new global API key + * + * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that + * can contains the following values: + * - search: allow to search (https and http) + * - addObject: allows to add/update an object in the index (https only) + * - deleteObject : allows to delete an existing object (https only) + * - deleteIndex : allows to delete index content (https only) + * - settings : allows to get index settings (https only) + * - editSettings : allows to change index settings (https only) + * @param {Object} [params] - Optionnal parameters to set for the key + * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key) + * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour + * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call + * @param {string[]} params.indexes - Allowed targeted indexes for this key + * @param {string} params.description - A description for your key + * @param {string[]} params.referers - A list of authorized referers + * @param {Object} params.queryParameters - Force the key to use specific query parameters + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the added API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.addApiKey(['search'], { + * validity: 300, + * maxQueriesPerIPPerHour: 2000, + * maxHitsPerQuery: 3, + * indexes: ['fruits'], + * description: 'Eat three fruits', + * referers: ['*.algolia.com'], + * queryParameters: { + * tagFilters: ['public'], + * } + * }) + * @see {@link https://www.algolia.com/doc/rest_api#AddKey|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.addApiKey = function(acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: client.addApiKey(arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = null; + } + + var postObj = { + acl: acls + }; + + if (params) { + postObj.validity = params.validity; + postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + postObj.maxHitsPerQuery = params.maxHitsPerQuery; + postObj.indexes = params.indexes; + postObj.description = params.description; + + if (params.queryParameters) { + postObj.queryParameters = this._getSearchParams(params.queryParameters, ''); + } + + postObj.referers = params.referers; + } + + return this._jsonRequest({ + method: 'POST', + url: '/1/keys', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * @deprecated Please use client.addApiKey() + */ +AlgoliaSearch.prototype.addUserKeyWithValidity = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('client.addUserKeyWithValidity()', 'client.addApiKey()')); + +/** + * @deprecated Please use client.updateApiKey() + */ +AlgoliaSearch.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { + return this.updateApiKey(key, acls, params, callback); +}, deprecatedMessage('client.updateUserKey()', 'client.updateApiKey()')); + +/** + * Update an existing API key + * @param {string} key - The key to update + * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that + * can contains the following values: + * - search: allow to search (https and http) + * - addObject: allows to add/update an object in the index (https only) + * - deleteObject : allows to delete an existing object (https only) + * - deleteIndex : allows to delete index content (https only) + * - settings : allows to get index settings (https only) + * - editSettings : allows to change index settings (https only) + * @param {Object} [params] - Optionnal parameters to set for the key + * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key) + * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour + * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call + * @param {string[]} params.indexes - Allowed targeted indexes for this key + * @param {string} params.description - A description for your key + * @param {string[]} params.referers - A list of authorized referers + * @param {Object} params.queryParameters - Force the key to use specific query parameters + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the modified API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.updateApiKey('APIKEY', ['search'], { + * validity: 300, + * maxQueriesPerIPPerHour: 2000, + * maxHitsPerQuery: 3, + * indexes: ['fruits'], + * description: 'Eat three fruits', + * referers: ['*.algolia.com'], + * queryParameters: { + * tagFilters: ['public'], + * } + * }) + * @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.updateApiKey = function(key, acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: client.updateApiKey(key, arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 2 || typeof params === 'function') { + callback = params; + params = null; + } + + var putObj = { + acl: acls + }; + + if (params) { + putObj.validity = params.validity; + putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + putObj.maxHitsPerQuery = params.maxHitsPerQuery; + putObj.indexes = params.indexes; + putObj.description = params.description; + + if (params.queryParameters) { + putObj.queryParameters = this._getSearchParams(params.queryParameters, ''); + } + + putObj.referers = params.referers; + } + + return this._jsonRequest({ + method: 'PUT', + url: '/1/keys/' + key, + body: putObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Initialize a new batch of search queries + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.startQueriesBatch = deprecate(function startQueriesBatchDeprecated() { + this._batch = []; +}, deprecatedMessage('client.startQueriesBatch()', 'client.search()')); + +/** + * Add a search query in the batch + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.addQueryInBatch = deprecate(function addQueryInBatchDeprecated(indexName, query, args) { + this._batch.push({ + indexName: indexName, + query: query, + params: args + }); +}, deprecatedMessage('client.addQueryInBatch()', 'client.search()')); + +/** + * Launch the batch of queries using XMLHttpRequest. + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.sendQueriesBatch = deprecate(function sendQueriesBatchDeprecated(callback) { + return this.search(this._batch, callback); +}, deprecatedMessage('client.sendQueriesBatch()', 'client.search()')); + +/** + * Perform write operations accross multiple indexes. + * + * To reduce the amount of time spent on network round trips, + * you can create, update, or delete several objects in one call, + * using the batch endpoint (all operations are done in the given order). + * + * Available actions: + * - addObject + * - updateObject + * - partialUpdateObject + * - partialUpdateObjectNoCreate + * - deleteObject + * + * https://www.algolia.com/doc/rest_api#Indexes + * @param {Object[]} operations An array of operations to perform + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.batch([{ + * action: 'addObject', + * indexName: 'clients', + * body: { + * name: 'Bill' + * } + * }, { + * action: 'udpateObject', + * indexName: 'fruits', + * body: { + * objectID: '29138', + * name: 'banana' + * } + * }], cb) + */ +AlgoliaSearch.prototype.batch = function(operations, callback) { + var isArray = require(8); + var usage = 'Usage: client.batch(operations[, callback])'; + + if (!isArray(operations)) { + throw new Error(usage); + } + + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/batch', + body: { + requests: operations + }, + hostType: 'write', + callback: callback + }); +}; + +/** + * Assign or Move a userID to a cluster + * + * @param {string} data.userID The userID to assign to a new cluster + * @param {string} data.cluster The cluster to assign the user to + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.assignUserID({ cluster: 'c1-test', userID: 'some-user' }); + */ +AlgoliaSearch.prototype.assignUserID = function(data, callback) { + if (!data.userID || !data.cluster) { + throw new errors.AlgoliaSearchError('You have to provide both a userID and cluster', data); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping', + hostType: 'write', + body: {cluster: data.cluster}, + callback: callback, + headers: { + 'x-algolia-user-id': data.userID + } + }); +}; + +/** + * Get the top userIDs + * + * (the callback is the second argument) + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getTopUserID(); + */ +AlgoliaSearch.prototype.getTopUserID = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping/top', + hostType: 'read', + callback: callback + }); +}; + +/** + * Get userID + * + * @param {string} data.userID The userID to get info about + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getUserID({ userID: 'some-user' }); + */ +AlgoliaSearch.prototype.getUserID = function(data, callback) { + if (!data.userID) { + throw new errors.AlgoliaSearchError('You have to provide a userID', {debugData: data}); + } + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping/' + data.userID, + hostType: 'read', + callback: callback + }); +}; + +/** + * List all the clusters + * + * (the callback is the second argument) + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.listClusters(); + */ +AlgoliaSearch.prototype.listClusters = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters', + hostType: 'read', + callback: callback + }); +}; + +/** + * List the userIDs + * + * (the callback is the second argument) + * + * @param {string} data.hitsPerPage How many hits on every page + * @param {string} data.page The page to retrieve + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.listClusters(); + * client.listClusters({ page: 3, hitsPerPage: 30}); + */ +AlgoliaSearch.prototype.listUserIDs = function(data, callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping', + body: data, + hostType: 'read', + callback: callback + }); +}; + +/** + * Remove an userID + * + * @param {string} data.userID The userID to assign to a new cluster + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.removeUserID({ userID: 'some-user' }); + */ +AlgoliaSearch.prototype.removeUserID = function(data, callback) { + if (!data.userID) { + throw new errors.AlgoliaSearchError('You have to provide a userID', {debugData: data}); + } + return this._jsonRequest({ + method: 'DELETE', + url: '/1/clusters/mapping', + hostType: 'write', + callback: callback, + headers: { + 'x-algolia-user-id': data.userID + } + }); +}; + +/** + * Search for userIDs + * + * @param {string} data.cluster The cluster to target + * @param {string} data.query The query to execute + * @param {string} data.hitsPerPage How many hits on every page + * @param {string} data.page The page to retrieve + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.searchUserIDs({ cluster: 'c1-test', query: 'some-user' }); + * client.searchUserIDs({ + * cluster: "c1-test", + * query: "some-user", + * page: 3, + * hitsPerPage: 2 + * }); + */ +AlgoliaSearch.prototype.searchUserIDs = function(data, callback) { + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping/search', + body: data, + hostType: 'read', + callback: callback + }); +}; + +// environment specific methods +AlgoliaSearch.prototype.destroy = notImplemented; +AlgoliaSearch.prototype.enableRateLimitForward = notImplemented; +AlgoliaSearch.prototype.disableRateLimitForward = notImplemented; +AlgoliaSearch.prototype.useSecuredAPIKey = notImplemented; +AlgoliaSearch.prototype.disableSecuredAPIKey = notImplemented; +AlgoliaSearch.prototype.generateSecuredApiKey = notImplemented; + +function notImplemented() { + var message = 'Not implemented in this environment.\n' + + 'If you feel this is a mistake, write to support@algolia.com'; + + throw new errors.AlgoliaSearchError(message); +} + +},{"15":15,"16":16,"25":25,"26":26,"27":27,"28":28,"29":29,"7":7,"8":8}],15:[function(require,module,exports){ +(function (process){ +module.exports = AlgoliaSearchCore; + +var errors = require(29); +var exitPromise = require(30); +var IndexCore = require(18); +var store = require(35); + +// We will always put the API KEY in the JSON body in case of too long API KEY, +// to avoid query string being too long and failing in various conditions (our server limit, browser limit, +// proxies limit) +var MAX_API_KEY_LENGTH = 500; +var RESET_APP_DATA_TIMER = + process.env.RESET_APP_DATA_TIMER && parseInt(process.env.RESET_APP_DATA_TIMER, 10) || + 60 * 2 * 1000; // after 2 minutes reset to first host + +/* + * Algolia Search library initialization + * https://www.algolia.com/ + * + * @param {string} applicationID - Your applicationID, found in your dashboard + * @param {string} apiKey - Your API key, found in your dashboard + * @param {Object} [opts] + * @param {number} [opts.timeout=2000] - The request timeout set in milliseconds, + * another request will be issued after this timeout + * @param {string} [opts.protocol='https:'] - The protocol used to query Algolia Search API. + * Set to 'http:' to force using http. + * @param {Object|Array} [opts.hosts={ + * read: [this.applicationID + '-dsn.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]), + * write: [this.applicationID + '.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]) - The hosts to use for Algolia Search API. + * If you provide them, you will less benefit from our HA implementation + */ +function AlgoliaSearchCore(applicationID, apiKey, opts) { + var debug = require(1)('algoliasearch'); + + var clone = require(25); + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: algoliasearch(applicationID, apiKey, opts)'; + + if (opts._allowEmptyCredentials !== true && !applicationID) { + throw new errors.AlgoliaSearchError('Please provide an application ID. ' + usage); + } + + if (opts._allowEmptyCredentials !== true && !apiKey) { + throw new errors.AlgoliaSearchError('Please provide an API key. ' + usage); + } + + this.applicationID = applicationID; + this.apiKey = apiKey; + + this.hosts = { + read: [], + write: [] + }; + + opts = opts || {}; + + this._timeouts = opts.timeouts || { + connect: 1 * 1000, // 500ms connect is GPRS latency + read: 2 * 1000, + write: 30 * 1000 + }; + + // backward compat, if opts.timeout is passed, we use it to configure all timeouts like before + if (opts.timeout) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = opts.timeout; + } + + var protocol = opts.protocol || 'https:'; + // while we advocate for colon-at-the-end values: 'http:' for `opts.protocol` + // we also accept `http` and `https`. It's a common error. + if (!/:$/.test(protocol)) { + protocol = protocol + ':'; + } + + if (protocol !== 'http:' && protocol !== 'https:') { + throw new errors.AlgoliaSearchError('protocol must be `http:` or `https:` (was `' + opts.protocol + '`)'); + } + + this._checkAppIdData(); + + if (!opts.hosts) { + var defaultHosts = map(this._shuffleResult, function(hostNumber) { + return applicationID + '-' + hostNumber + '.algolianet.com'; + }); + + // no hosts given, compute defaults + var mainSuffix = (opts.dsn === false ? '' : '-dsn') + '.algolia.net'; + this.hosts.read = [this.applicationID + mainSuffix].concat(defaultHosts); + this.hosts.write = [this.applicationID + '.algolia.net'].concat(defaultHosts); + } else if (isArray(opts.hosts)) { + // when passing custom hosts, we need to have a different host index if the number + // of write/read hosts are different. + this.hosts.read = clone(opts.hosts); + this.hosts.write = clone(opts.hosts); + } else { + this.hosts.read = clone(opts.hosts.read); + this.hosts.write = clone(opts.hosts.write); + } + + // add protocol and lowercase hosts + this.hosts.read = map(this.hosts.read, prepareHost(protocol)); + this.hosts.write = map(this.hosts.write, prepareHost(protocol)); + + this.extraHeaders = {}; + + // In some situations you might want to warm the cache + this.cache = opts._cache || {}; + + this._ua = opts._ua; + this._useCache = opts._useCache === undefined || opts._cache ? true : opts._useCache; + this._useRequestCache = this._useCache && opts._useRequestCache; + this._useFallback = opts.useFallback === undefined ? true : opts.useFallback; + + this._setTimeout = opts._setTimeout; + + debug('init done, %j', this); +} + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearchCore.prototype.initIndex = function(indexName) { + return new IndexCore(this, indexName); +}; + +/** +* Add an extra field to the HTTP request +* +* @param name the header field name +* @param value the header field value +*/ +AlgoliaSearchCore.prototype.setExtraHeader = function(name, value) { + this.extraHeaders[name.toLowerCase()] = value; +}; + +/** +* Get the value of an extra HTTP header +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.getExtraHeader = function(name) { + return this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Remove an extra field from the HTTP request +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.unsetExtraHeader = function(name) { + delete this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Augment sent x-algolia-agent with more data, each agent part +* is automatically separated from the others by a semicolon; +* +* @param algoliaAgent the agent to add +*/ +AlgoliaSearchCore.prototype.addAlgoliaAgent = function(algoliaAgent) { + if (this._ua.indexOf(';' + algoliaAgent) === -1) { + this._ua += ';' + algoliaAgent; + } +}; + +/* + * Wrapper that try all hosts to maximize the quality of service + */ +AlgoliaSearchCore.prototype._jsonRequest = function(initialOpts) { + this._checkAppIdData(); + + var requestDebug = require(1)('algoliasearch:' + initialOpts.url); + + + var body; + var cacheID; + var additionalUA = initialOpts.additionalUA || ''; + var cache = initialOpts.cache; + var client = this; + var tries = 0; + var usingFallback = false; + var hasFallback = client._useFallback && client._request.fallback && initialOpts.fallback; + var headers; + + if ( + this.apiKey.length > MAX_API_KEY_LENGTH && + initialOpts.body !== undefined && + (initialOpts.body.params !== undefined || // index.search() + initialOpts.body.requests !== undefined) // client.search() + ) { + initialOpts.body.apiKey = this.apiKey; + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + withApiKey: false, + headers: initialOpts.headers + }); + } else { + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + } + + if (initialOpts.body !== undefined) { + body = safeJSONStringify(initialOpts.body); + } + + requestDebug('request start'); + var debugData = []; + + + function doRequest(requester, reqOpts) { + client._checkAppIdData(); + + var startTime = new Date(); + + if (client._useCache && !client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && !client._useRequestCache && body) { + cacheID += '_body_' + reqOpts.body; + } + + // handle cache existence + if (isCacheValidWithCurrentID(!client._useRequestCache, cache, cacheID)) { + requestDebug('serving response from cache'); + + var responseText = cache[cacheID]; + + // Cache response must match the type of the original one + return client._promise.resolve({ + body: JSON.parse(responseText), + responseText: responseText + }); + } + + // if we reached max tries + if (tries >= client.hosts[initialOpts.hostType].length) { + if (!hasFallback || usingFallback) { + requestDebug('could not get any response'); + // then stop + return client._promise.reject(new errors.AlgoliaSearchError( + 'Cannot connect to the AlgoliaSearch API.' + + ' Send an email to support@algolia.com to report and resolve the issue.' + + ' Application id was: ' + client.applicationID, {debugData: debugData} + )); + } + + requestDebug('switching to fallback'); + + // let's try the fallback starting from here + tries = 0; + + // method, url and body are fallback dependent + reqOpts.method = initialOpts.fallback.method; + reqOpts.url = initialOpts.fallback.url; + reqOpts.jsonBody = initialOpts.fallback.body; + if (reqOpts.jsonBody) { + reqOpts.body = safeJSONStringify(reqOpts.jsonBody); + } + // re-compute headers, they could be omitting the API KEY + headers = client._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + client._setHostIndexByType(0, initialOpts.hostType); + usingFallback = true; // the current request is now using fallback + return doRequest(client._request.fallback, reqOpts); + } + + var currentHost = client._getHostByType(initialOpts.hostType); + + var url = currentHost + reqOpts.url; + var options = { + body: reqOpts.body, + jsonBody: reqOpts.jsonBody, + method: reqOpts.method, + headers: headers, + timeouts: reqOpts.timeouts, + debug: requestDebug, + forceAuthHeaders: reqOpts.forceAuthHeaders + }; + + requestDebug('method: %s, url: %s, headers: %j, timeouts: %d', + options.method, url, options.headers, options.timeouts); + + if (requester === client._request.fallback) { + requestDebug('using fallback'); + } + + // `requester` is any of this._request or this._request.fallback + // thus it needs to be called using the client as context + return requester.call(client, url, options).then(success, tryFallback); + + function success(httpResponse) { + // compute the status of the response, + // + // When in browser mode, using XDR or JSONP, we have no statusCode available + // So we rely on our API response `status` property. + // But `waitTask` can set a `status` property which is not the statusCode (it's the task status) + // So we check if there's a `message` along `status` and it means it's an error + // + // That's the only case where we have a response.status that's not the http statusCode + var status = httpResponse && httpResponse.body && httpResponse.body.message && httpResponse.body.status || + + // this is important to check the request statusCode AFTER the body eventual + // statusCode because some implementations (jQuery XDomainRequest transport) may + // send statusCode 200 while we had an error + httpResponse.statusCode || + + // When in browser mode, using XDR or JSONP + // we default to success when no error (no response.status && response.message) + // If there was a JSON.parse() error then body is null and it fails + httpResponse && httpResponse.body && 200; + + requestDebug('received response: statusCode: %s, computed statusCode: %d, headers: %j', + httpResponse.statusCode, status, httpResponse.headers); + + var httpResponseOk = Math.floor(status / 100) === 2; + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime, + statusCode: status + }); + + if (httpResponseOk) { + if (client._useCache && !client._useRequestCache && cache) { + cache[cacheID] = httpResponse.responseText; + } + + return { + responseText: httpResponse.responseText, + body: httpResponse.body + }; + } + + var shouldRetry = Math.floor(status / 100) !== 4; + + if (shouldRetry) { + tries += 1; + return retryRequest(); + } + + requestDebug('unrecoverable error'); + + // no success and no retry => fail + var unrecoverableError = new errors.AlgoliaSearchError( + httpResponse.body && httpResponse.body.message, {debugData: debugData, statusCode: status} + ); + + return client._promise.reject(unrecoverableError); + } + + function tryFallback(err) { + // error cases: + // While not in fallback mode: + // - CORS not supported + // - network error + // While in fallback mode: + // - timeout + // - network error + // - badly formatted JSONP (script loaded, did not call our callback) + // In both cases: + // - uncaught exception occurs (TypeError) + requestDebug('error: %s, stack: %s', err.message, err.stack); + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime + }); + + if (!(err instanceof errors.AlgoliaSearchError)) { + err = new errors.Unknown(err && err.message, err); + } + + tries += 1; + + // stop the request implementation when: + if ( + // we did not generate this error, + // it comes from a throw in some other piece of code + err instanceof errors.Unknown || + + // server sent unparsable JSON + err instanceof errors.UnparsableJSON || + + // max tries and already using fallback or no fallback + tries >= client.hosts[initialOpts.hostType].length && + (usingFallback || !hasFallback)) { + // stop request implementation for this command + err.debugData = debugData; + return client._promise.reject(err); + } + + // When a timeout occured, retry by raising timeout + if (err instanceof errors.RequestTimeout) { + return retryRequestWithHigherTimeout(); + } + + return retryRequest(); + } + + function retryRequest() { + requestDebug('retrying request'); + client._incrementHostIndex(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + + function retryRequestWithHigherTimeout() { + requestDebug('retrying request with higher timeout'); + client._incrementHostIndex(initialOpts.hostType); + client._incrementTimeoutMultipler(); + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + } + + function isCacheValidWithCurrentID( + useRequestCache, + currentCache, + currentCacheID + ) { + return ( + client._useCache && + useRequestCache && + currentCache && + currentCache[currentCacheID] !== undefined + ); + } + + + function interopCallbackReturn(request, callback) { + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + request.catch(function() { + // Release the cache on error + delete cache[cacheID]; + }); + } + + if (typeof initialOpts.callback === 'function') { + // either we have a callback + request.then(function okCb(content) { + exitPromise(function() { + initialOpts.callback(null, callback(content)); + }, client._setTimeout || setTimeout); + }, function nookCb(err) { + exitPromise(function() { + initialOpts.callback(err); + }, client._setTimeout || setTimeout); + }); + } else { + // either we are using promises + return request.then(callback); + } + } + + if (client._useCache && client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && client._useRequestCache && body) { + cacheID += '_body_' + body; + } + + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + requestDebug('serving request from cache'); + + var maybePromiseForCache = cache[cacheID]; + + // In case the cache is warmup with value that is not a promise + var promiseForCache = typeof maybePromiseForCache.then !== 'function' + ? client._promise.resolve({responseText: maybePromiseForCache}) + : maybePromiseForCache; + + return interopCallbackReturn(promiseForCache, function(content) { + // In case of the cache request, return the original value + return JSON.parse(content.responseText); + }); + } + + var request = doRequest( + client._request, { + url: initialOpts.url, + method: initialOpts.method, + body: body, + jsonBody: initialOpts.body, + timeouts: client._getTimeoutsForRequest(initialOpts.hostType), + forceAuthHeaders: initialOpts.forceAuthHeaders + } + ); + + if (client._useCache && client._useRequestCache && cache) { + cache[cacheID] = request; + } + + return interopCallbackReturn(request, function(content) { + // In case of the first request, return the JSON value + return content.body; + }); +}; + +/* +* Transform search param object in query string +* @param {object} args arguments to add to the current query string +* @param {string} params current query string +* @return {string} the final query string +*/ +AlgoliaSearchCore.prototype._getSearchParams = function(args, params) { + if (args === undefined || args === null) { + return params; + } + for (var key in args) { + if (key !== null && args[key] !== undefined && args.hasOwnProperty(key)) { + params += params === '' ? '' : '&'; + params += key + '=' + encodeURIComponent(Object.prototype.toString.call(args[key]) === '[object Array]' ? safeJSONStringify(args[key]) : args[key]); + } + } + return params; +}; + +/** + * Compute the headers for a request + * + * @param [string] options.additionalUA semi-colon separated string with other user agents to add + * @param [boolean=true] options.withApiKey Send the api key as a header + * @param [Object] options.headers Extra headers to send + */ +AlgoliaSearchCore.prototype._computeRequestHeaders = function(options) { + var forEach = require(5); + + var ua = options.additionalUA ? + this._ua + ';' + options.additionalUA : + this._ua; + + var requestHeaders = { + 'x-algolia-agent': ua, + 'x-algolia-application-id': this.applicationID + }; + + // browser will inline headers in the url, node.js will use http headers + // but in some situations, the API KEY will be too long (big secured API keys) + // so if the request is a POST and the KEY is very long, we will be asked to not put + // it into headers but in the JSON body + if (options.withApiKey !== false) { + requestHeaders['x-algolia-api-key'] = this.apiKey; + } + + if (this.userToken) { + requestHeaders['x-algolia-usertoken'] = this.userToken; + } + + if (this.securityTags) { + requestHeaders['x-algolia-tagfilters'] = this.securityTags; + } + + forEach(this.extraHeaders, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + + if (options.headers) { + forEach(options.headers, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + } + + return requestHeaders; +}; + +/** + * Search through multiple indices at the same time + * @param {Object[]} queries An array of queries you want to run. + * @param {string} queries[].indexName The index name you want to target + * @param {string} [queries[].query] The query to issue on this index. Can also be passed into `params` + * @param {Object} queries[].params Any search param like hitsPerPage, .. + * @param {Function} callback Callback to be called + * @return {Promise|undefined} Returns a promise if no callback given + */ +AlgoliaSearchCore.prototype.search = function(queries, opts, callback) { + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: client.search(arrayOfQueries[, callback])'; + + if (!isArray(queries)) { + throw new Error(usage); + } + + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var client = this; + + var postObj = { + requests: map(queries, function prepareRequest(query) { + var params = ''; + + // allow query.query + // so we are mimicing the index.search(query, params) method + // {indexName:, query:, params:} + if (query.query !== undefined) { + params += 'query=' + encodeURIComponent(query.query); + } + + return { + indexName: query.indexName, + params: client._getSearchParams(query.params, params) + }; + }) + }; + + var JSONPParams = map(postObj.requests, function prepareJSONPParams(request, requestId) { + return requestId + '=' + + encodeURIComponent( + '/1/indexes/' + encodeURIComponent(request.indexName) + '?' + + request.params + ); + }).join('&'); + + var url = '/1/indexes/*/queries'; + + if (opts.strategy !== undefined) { + postObj.strategy = opts.strategy; + } + + return this._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url, + body: postObj, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/*', + body: { + params: JSONPParams + } + }, + callback: callback + }); +}; + +/** +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* This is the top-level API for SFFV. +* +* @param {object[]} queries An array of queries to run. +* @param {string} queries[].indexName Index name, name of the index to search. +* @param {object} queries[].params Query parameters. +* @param {string} queries[].params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} queries[].params.facetQuery Query for the facet search +* @param {string} [queries[].params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +*/ +AlgoliaSearchCore.prototype.searchForFacetValues = function(queries) { + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])'; // eslint-disable-line max-len + + if (!isArray(queries)) { + throw new Error(usage); + } + + var client = this; + + return client._promise.all(map(queries, function performQuery(query) { + if ( + !query || + query.indexName === undefined || + query.params.facetName === undefined || + query.params.facetQuery === undefined + ) { + throw new Error(usage); + } + + var clone = require(25); + var omit = require(33); + + var indexName = query.indexName; + var params = query.params; + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = client._getSearchParams(filteredParams, ''); + + return client._jsonRequest({ + cache: client.cache, + method: 'POST', + url: + '/1/indexes/' + + encodeURIComponent(indexName) + + '/facets/' + + encodeURIComponent(facetName) + + '/query', + hostType: 'read', + body: {params: searchParameters} + }); + })); +}; + +/** + * Set the extra security tagFilters header + * @param {string|array} tags The list of tags defining the current security filters + */ +AlgoliaSearchCore.prototype.setSecurityTags = function(tags) { + if (Object.prototype.toString.call(tags) === '[object Array]') { + var strTags = []; + for (var i = 0; i < tags.length; ++i) { + if (Object.prototype.toString.call(tags[i]) === '[object Array]') { + var oredTags = []; + for (var j = 0; j < tags[i].length; ++j) { + oredTags.push(tags[i][j]); + } + strTags.push('(' + oredTags.join(',') + ')'); + } else { + strTags.push(tags[i]); + } + } + tags = strTags.join(','); + } + + this.securityTags = tags; +}; + +/** + * Set the extra user token header + * @param {string} userToken The token identifying a uniq user (used to apply rate limits) + */ +AlgoliaSearchCore.prototype.setUserToken = function(userToken) { + this.userToken = userToken; +}; + +/** + * Clear all queries in client's cache + * @return undefined + */ +AlgoliaSearchCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/** +* Set the number of milliseconds a request can take before automatically being terminated. +* @deprecated +* @param {Number} milliseconds +*/ +AlgoliaSearchCore.prototype.setRequestTimeout = function(milliseconds) { + if (milliseconds) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = milliseconds; + } +}; + +/** +* Set the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.setTimeouts = function(timeouts) { + this._timeouts = timeouts; +}; + +/** +* Get the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.getTimeouts = function() { + return this._timeouts; +}; + +AlgoliaSearchCore.prototype._getAppIdData = function() { + var data = store.get(this.applicationID); + if (data !== null) this._cacheAppIdData(data); + return data; +}; + +AlgoliaSearchCore.prototype._setAppIdData = function(data) { + data.lastChange = (new Date()).getTime(); + this._cacheAppIdData(data); + return store.set(this.applicationID, data); +}; + +AlgoliaSearchCore.prototype._checkAppIdData = function() { + var data = this._getAppIdData(); + var now = (new Date()).getTime(); + if (data === null || now - data.lastChange > RESET_APP_DATA_TIMER) { + return this._resetInitialAppIdData(data); + } + + return data; +}; + +AlgoliaSearchCore.prototype._resetInitialAppIdData = function(data) { + var newData = data || {}; + newData.hostIndexes = {read: 0, write: 0}; + newData.timeoutMultiplier = 1; + newData.shuffleResult = newData.shuffleResult || shuffle([1, 2, 3]); + return this._setAppIdData(newData); +}; + +AlgoliaSearchCore.prototype._cacheAppIdData = function(data) { + this._hostIndexes = data.hostIndexes; + this._timeoutMultiplier = data.timeoutMultiplier; + this._shuffleResult = data.shuffleResult; +}; + +AlgoliaSearchCore.prototype._partialAppIdDataUpdate = function(newData) { + var foreach = require(5); + var currentData = this._getAppIdData(); + foreach(newData, function(value, key) { + currentData[key] = value; + }); + + return this._setAppIdData(currentData); +}; + +AlgoliaSearchCore.prototype._getHostByType = function(hostType) { + return this.hosts[hostType][this._getHostIndexByType(hostType)]; +}; + +AlgoliaSearchCore.prototype._getTimeoutMultiplier = function() { + return this._timeoutMultiplier; +}; + +AlgoliaSearchCore.prototype._getHostIndexByType = function(hostType) { + return this._hostIndexes[hostType]; +}; + +AlgoliaSearchCore.prototype._setHostIndexByType = function(hostIndex, hostType) { + var clone = require(25); + var newHostIndexes = clone(this._hostIndexes); + newHostIndexes[hostType] = hostIndex; + this._partialAppIdDataUpdate({hostIndexes: newHostIndexes}); + return hostIndex; +}; + +AlgoliaSearchCore.prototype._incrementHostIndex = function(hostType) { + return this._setHostIndexByType( + (this._getHostIndexByType(hostType) + 1) % this.hosts[hostType].length, hostType + ); +}; + +AlgoliaSearchCore.prototype._incrementTimeoutMultipler = function() { + var timeoutMultiplier = Math.max(this._timeoutMultiplier + 1, 4); + return this._partialAppIdDataUpdate({timeoutMultiplier: timeoutMultiplier}); +}; + +AlgoliaSearchCore.prototype._getTimeoutsForRequest = function(hostType) { + return { + connect: this._timeouts.connect * this._timeoutMultiplier, + complete: this._timeouts[hostType] * this._timeoutMultiplier + }; +}; + +function prepareHost(protocol) { + return function prepare(host) { + return protocol + '//' + host.toLowerCase(); + }; +} + +// Prototype.js < 1.7, a widely used library, defines a weird +// Array.prototype.toJSON function that will fail to stringify our content +// appropriately +// refs: +// - https://groups.google.com/forum/#!topic/prototype-core/E-SAVvV_V9Q +// - https://github.com/sstephenson/prototype/commit/038a2985a70593c1a86c230fadbdfe2e4898a48c +// - http://stackoverflow.com/a/3148441/147079 +function safeJSONStringify(obj) { + /* eslint no-extend-native:0 */ + + if (Array.prototype.toJSON === undefined) { + return JSON.stringify(obj); + } + + var toJSON = Array.prototype.toJSON; + delete Array.prototype.toJSON; + var out = JSON.stringify(obj); + Array.prototype.toJSON = toJSON; + + return out; +} + +function shuffle(array) { + var currentIndex = array.length; + var temporaryValue; + var randomIndex; + + // While there remain elements to shuffle... + while (currentIndex !== 0) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + + return array; +} + +function removeCredentials(headers) { + var newHeaders = {}; + + for (var headerName in headers) { + if (Object.prototype.hasOwnProperty.call(headers, headerName)) { + var value; + + if (headerName === 'x-algolia-api-key' || headerName === 'x-algolia-application-id') { + value = '**hidden for security purposes**'; + } else { + value = headers[headerName]; + } + + newHeaders[headerName] = value; + } + } + + return newHeaders; +} + +}).call(this,require(12)) +},{"1":1,"12":12,"18":18,"25":25,"29":29,"30":30,"31":31,"33":33,"35":35,"5":5,"8":8}],16:[function(require,module,exports){ +var inherits = require(7); +var IndexCore = require(18); +var deprecate = require(27); +var deprecatedMessage = require(28); +var exitPromise = require(30); +var errors = require(29); + +var deprecateForwardToSlaves = deprecate( + function() {}, + deprecatedMessage('forwardToSlaves', 'forwardToReplicas') +); + +module.exports = Index; + +function Index() { + IndexCore.apply(this, arguments); +} + +inherits(Index, IndexCore); + +/* +* Add an object in this index +* +* @param content contains the javascript object to add inside the index +* @param objectID (optional) an objectID you want to attribute to this object +* (if the attribute already exist the old object will be overwrite) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.addObject = function(content, objectID, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof objectID === 'function') { + callback = objectID; + objectID = undefined; + } + + return this.as._jsonRequest({ + method: objectID !== undefined ? + 'PUT' : // update or create + 'POST', // create (API generates an objectID) + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + // create + (objectID !== undefined ? '/' + encodeURIComponent(objectID) : ''), // update or create + body: content, + hostType: 'write', + callback: callback + }); +}; + +/* +* Add several objects +* +* @param objects contains an array of objects to add +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.addObjects = function(objects, callback) { + var isArray = require(8); + var usage = 'Usage: index.addObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: 'addObject', + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Update partially an object (only update attributes passed in argument) +* +* @param partialObject contains the javascript attributes to override, the +* object must contains an objectID attribute +* @param createIfNotExists (optional) if false, avoid an automatic creation of the object +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.partialUpdateObject = function(partialObject, createIfNotExists, callback) { + if (arguments.length === 1 || typeof createIfNotExists === 'function') { + callback = createIfNotExists; + createIfNotExists = undefined; + } + + var indexObj = this; + var url = '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(partialObject.objectID) + '/partial'; + if (createIfNotExists === false) { + url += '?createIfNotExists=false'; + } + + return this.as._jsonRequest({ + method: 'POST', + url: url, + body: partialObject, + hostType: 'write', + callback: callback + }); +}; + +/* +* Partially Override the content of several objects +* +* @param objects contains an array of objects to update (each object must contains a objectID attribute) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.partialUpdateObjects = function(objects, createIfNotExists, callback) { + if (arguments.length === 1 || typeof createIfNotExists === 'function') { + callback = createIfNotExists; + createIfNotExists = true; + } + + var isArray = require(8); + var usage = 'Usage: index.partialUpdateObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: createIfNotExists === true ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate', + objectID: objects[i].objectID, + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Override the content of object +* +* @param object contains the javascript object to save, the object must contains an objectID attribute +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.saveObject = function(object, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(object.objectID), + body: object, + hostType: 'write', + callback: callback + }); +}; + +/* +* Override the content of several objects +* +* @param objects contains an array of objects to update (each object must contains a objectID attribute) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.saveObjects = function(objects, callback) { + var isArray = require(8); + var usage = 'Usage: index.saveObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: 'updateObject', + objectID: objects[i].objectID, + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete an object from the index +* +* @param objectID the unique identifier of object to delete +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.deleteObject = function(objectID, callback) { + if (typeof objectID === 'function' || typeof objectID !== 'string' && typeof objectID !== 'number') { + var err = new errors.AlgoliaSearchError( + objectID && typeof objectID !== 'function' + ? 'ObjectID must be a string' + : 'Cannot delete an object without an objectID' + ); + callback = objectID; + if (typeof callback === 'function') { + return callback(err); + } + + return this.as._promise.reject(err); + } + + var indexObj = this; + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID), + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete several objects from an index +* +* @param objectIDs contains an array of objectID to delete +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.deleteObjects = function(objectIDs, callback) { + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: index.deleteObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: map(objectIDs, function prepareRequest(objectID) { + return { + action: 'deleteObject', + objectID: objectID, + body: { + objectID: objectID + } + }; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete all objects matching a query +* +* @param query the query string +* @param params the optional query parameters +* @param callback (optional) the result callback called with one argument +* error: null or Error('message') +* @deprecated see index.deleteBy +*/ +Index.prototype.deleteByQuery = deprecate(function(query, params, callback) { + var clone = require(25); + var map = require(31); + + var indexObj = this; + var client = indexObj.as; + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = {}; + } else { + params = clone(params); + } + + params.attributesToRetrieve = 'objectID'; + params.hitsPerPage = 1000; + params.distinct = false; + + // when deleting, we should never use cache to get the + // search results + this.clearCache(); + + // there's a problem in how we use the promise chain, + // see how waitTask is done + var promise = this + .search(query, params) + .then(stopOrDelete); + + function stopOrDelete(searchContent) { + // stop here + if (searchContent.nbHits === 0) { + // return indexObj.as._request.resolve(); + return searchContent; + } + + // continue and do a recursive call + var objectIDs = map(searchContent.hits, function getObjectID(object) { + return object.objectID; + }); + + return indexObj + .deleteObjects(objectIDs) + .then(waitTask) + .then(doDeleteByQuery); + } + + function waitTask(deleteObjectsContent) { + return indexObj.waitTask(deleteObjectsContent.taskID); + } + + function doDeleteByQuery() { + return indexObj.deleteByQuery(query, params); + } + + if (!callback) { + return promise; + } + + promise.then(success, failure); + + function success() { + exitPromise(function exit() { + callback(null); + }, client._setTimeout || setTimeout); + } + + function failure(err) { + exitPromise(function exit() { + callback(err); + }, client._setTimeout || setTimeout); + } +}, deprecatedMessage('index.deleteByQuery()', 'index.deleteBy()')); + +/** +* Delete all objects matching a query +* +* the query parameters that can be used are: +* - filters (numeric, facet, tag) +* - geo +* +* you can not send an empty query or filters +* +* @param params the optional query parameters +* @param callback (optional) the result callback called with one argument +* error: null or Error('message') +*/ +Index.prototype.deleteBy = function(params, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/deleteByQuery', + body: {params: indexObj.as._getSearchParams(params, '')}, + hostType: 'write', + callback: callback + }); +}; + +/* +* Browse all content from an index using events. Basically this will do +* .browse() -> .browseFrom -> .browseFrom -> .. until all the results are returned +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @return {EventEmitter} +* @example +* var browser = index.browseAll('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }); +* +* browser.on('result', function resultCallback(content) { +* console.log(content.hits); +* }); +* +* // if any error occurs, you get it +* browser.on('error', function(err) { +* throw err; +* }); +* +* // when you have browsed the whole index, you get this event +* browser.on('end', function() { +* console.log('finished'); +* }); +* +* // at any point if you want to stop the browsing process, you can stop it manually +* // otherwise it will go on and on +* browser.stop(); +* +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +Index.prototype.browseAll = function(query, queryParameters) { + if (typeof query === 'object') { + queryParameters = query; + query = undefined; + } + + var merge = require(32); + + var IndexBrowser = require(17); + + var browser = new IndexBrowser(); + var client = this.as; + var index = this; + var params = client._getSearchParams( + merge({}, queryParameters || {}, { + query: query + }), '' + ); + + // start browsing + browseLoop(); + + function browseLoop(cursor) { + if (browser._stopped) { + return; + } + + var body; + + if (cursor !== undefined) { + body = { + cursor: cursor + }; + } else { + body = { + params: params + }; + } + + client._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(index.indexName) + '/browse', + hostType: 'read', + body: body, + callback: browseCallback + }); + } + + function browseCallback(err, content) { + if (browser._stopped) { + return; + } + + if (err) { + browser._error(err); + return; + } + + browser._result(content); + + // no cursor means we are finished browsing + if (content.cursor === undefined) { + browser._end(); + return; + } + + browseLoop(content.cursor); + } + + return browser; +}; + +/* +* Get a Typeahead.js adapter +* @param searchParams contains an object with query parameters (see search for details) +*/ +Index.prototype.ttAdapter = deprecate(function(params) { + var self = this; + return function ttAdapter(query, syncCb, asyncCb) { + var cb; + + if (typeof asyncCb === 'function') { + // typeahead 0.11 + cb = asyncCb; + } else { + // pre typeahead 0.11 + cb = syncCb; + } + + self.search(query, params, function searchDone(err, content) { + if (err) { + cb(err); + return; + } + + cb(content.hits); + }); + }; +}, +'ttAdapter is not necessary anymore and will be removed in the next version,\n' + +'have a look at autocomplete.js (https://github.com/algolia/autocomplete.js)'); + +/* +* Wait the publication of a task on the server. +* All server task are asynchronous and you can check with this method that the task is published. +* +* @param taskID the id of the task returned by server +* @param callback the result callback with with two arguments: +* error: null or Error('message') +* content: the server answer that contains the list of results +*/ +Index.prototype.waitTask = function(taskID, callback) { + // wait minimum 100ms before retrying + var baseDelay = 100; + // wait maximum 5s before retrying + var maxDelay = 5000; + var loop = 0; + + // waitTask() must be handled differently from other methods, + // it's a recursive method using a timeout + var indexObj = this; + var client = indexObj.as; + + var promise = retryLoop(); + + function retryLoop() { + return client._jsonRequest({ + method: 'GET', + hostType: 'read', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/task/' + taskID + }).then(function success(content) { + loop++; + var delay = baseDelay * loop * loop; + if (delay > maxDelay) { + delay = maxDelay; + } + + if (content.status !== 'published') { + return client._promise.delay(delay).then(retryLoop); + } + + return content; + }); + } + + if (!callback) { + return promise; + } + + promise.then(successCb, failureCb); + + function successCb(content) { + exitPromise(function exit() { + callback(null, content); + }, client._setTimeout || setTimeout); + } + + function failureCb(err) { + exitPromise(function exit() { + callback(err); + }, client._setTimeout || setTimeout); + } +}; + +/* +* This function deletes the index content. Settings and index specific API keys are kept untouched. +* +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the settings object or the error message if a failure occured +*/ +Index.prototype.clearIndex = function(callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/clear', + hostType: 'write', + callback: callback + }); +}; + +/* +* Get settings of this index +* +* @param opts an object of options to add +* @param opts.advanced get more settings like nbShards (useful for Enterprise) +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the settings object or the error message if a failure occurred +*/ +Index.prototype.getSettings = function(opts, callback) { + if (arguments.length === 1 && typeof opts === 'function') { + callback = opts; + opts = {}; + } + opts = opts || {}; + + var indexName = encodeURIComponent(this.indexName); + return this.as._jsonRequest({ + method: 'GET', + url: + '/1/indexes/' + + indexName + + '/settings?getVersion=2' + + (opts.advanced ? '&advanced=' + opts.advanced : ''), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.searchSynonyms = function(params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } else if (params === undefined) { + params = {}; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/search', + body: params, + hostType: 'read', + callback: callback + }); +}; + +function exportData(method, _hitsPerPage, callback) { + function search(page, _previous) { + var options = { + page: page || 0, + hitsPerPage: _hitsPerPage || 100 + }; + var previous = _previous || []; + + return method(options).then(function(result) { + var hits = result.hits; + var nbHits = result.nbHits; + var current = hits.map(function(s) { + delete s._highlightResult; + return s; + }); + var synonyms = previous.concat(current); + if (synonyms.length < nbHits) { + return search(options.page + 1, synonyms); + } + return synonyms; + }); + } + return search().then(function(data) { + if (typeof callback === 'function') { + callback(data); + return undefined; + } + return data; + }); +} + +/** + * Retrieve all the synonyms in an index + * @param [number=100] hitsPerPage The amount of synonyms to retrieve per batch + * @param [function] callback will be called after all synonyms are retrieved + */ +Index.prototype.exportSynonyms = function(hitsPerPage, callback) { + return exportData(this.searchSynonyms.bind(this), hitsPerPage, callback); +}; + +Index.prototype.saveSynonym = function(synonym, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(synonym.objectID) + + '?forwardToReplicas=' + forwardToReplicas, + body: synonym, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.getSynonym = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.deleteSynonym = function(objectID, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID) + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.clearSynonyms = function(opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/clear' + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.batchSynonyms = function(synonyms, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/batch' + + '?forwardToReplicas=' + forwardToReplicas + + '&replaceExistingSynonyms=' + (opts.replaceExistingSynonyms ? 'true' : 'false'), + hostType: 'write', + body: synonyms, + callback: callback + }); +}; + +Index.prototype.searchRules = function(params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } else if (params === undefined) { + params = {}; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/search', + body: params, + hostType: 'read', + callback: callback + }); +}; +/** + * Retrieve all the query rules in an index + * @param [number=100] hitsPerPage The amount of query rules to retrieve per batch + * @param [function] callback will be called after all query rules are retrieved + * error: null or Error('message') + */ +Index.prototype.exportRules = function(hitsPerPage, callback) { + return exportData(this.searchRules.bind(this), hitsPerPage, callback); +}; + +Index.prototype.saveRule = function(rule, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (!rule.objectID) { + throw new errors.AlgoliaSearchError('Missing or empty objectID field for rule'); + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(rule.objectID) + + '?forwardToReplicas=' + forwardToReplicas, + body: rule, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.getRule = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.deleteRule = function(objectID, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID) + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.clearRules = function(opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/clear' + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.batchRules = function(rules, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/batch' + + '?forwardToReplicas=' + forwardToReplicas + + '&clearExistingRules=' + (opts.clearExistingRules === true ? 'true' : 'false'), + hostType: 'write', + body: rules, + callback: callback + }); +}; + +/* +* Set settings for this index +* +* @param settigns the settings object that can contains : +* - minWordSizefor1Typo: (integer) the minimum number of characters to accept one typo (default = 3). +* - minWordSizefor2Typos: (integer) the minimum number of characters to accept two typos (default = 7). +* - hitsPerPage: (integer) the number of hits per page (default = 10). +* - attributesToRetrieve: (array of strings) default list of attributes to retrieve in objects. +* If set to null, all attributes are retrieved. +* - attributesToHighlight: (array of strings) default list of attributes to highlight. +* If set to null, all indexed attributes are highlighted. +* - attributesToSnippet**: (array of strings) default list of attributes to snippet alongside the number +* of words to return (syntax is attributeName:nbWords). +* By default no snippet is computed. If set to null, no snippet is computed. +* - attributesToIndex: (array of strings) the list of fields you want to index. +* If set to null, all textual and numerical attributes of your objects are indexed, +* but you should update it to get optimal results. +* This parameter has two important uses: +* - Limit the attributes to index: For example if you store a binary image in base64, +* you want to store it and be able to +* retrieve it but you don't want to search in the base64 string. +* - Control part of the ranking*: (see the ranking parameter for full explanation) +* Matches in attributes at the beginning of +* the list will be considered more important than matches in attributes further down the list. +* In one attribute, matching text at the beginning of the attribute will be +* considered more important than text after, you can disable +* this behavior if you add your attribute inside `unordered(AttributeName)`, +* for example attributesToIndex: ["title", "unordered(text)"]. +* - attributesForFaceting: (array of strings) The list of fields you want to use for faceting. +* All strings in the attribute selected for faceting are extracted and added as a facet. +* If set to null, no attribute is used for faceting. +* - attributeForDistinct: (string) The attribute name used for the Distinct feature. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in query with the distinct=1 parameter, all hits containing a duplicate +* value for this attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best one is kept and others are removed. +* - ranking: (array of strings) controls the way results are sorted. +* We have six available criteria: +* - typo: sort according to number of typos, +* - geo: sort according to decreassing distance when performing a geo-location based search, +* - proximity: sort according to the proximity of query words in hits, +* - attribute: sort according to the order of attributes defined by attributesToIndex, +* - exact: +* - if the user query contains one word: sort objects having an attribute +* that is exactly the query word before others. +* For example if you search for the "V" TV show, you want to find it +* with the "V" query and avoid to have all popular TV +* show starting by the v letter before it. +* - if the user query contains multiple words: sort according to the +* number of words that matched exactly (and not as a prefix). +* - custom: sort according to a user defined formula set in **customRanking** attribute. +* The standard order is ["typo", "geo", "proximity", "attribute", "exact", "custom"] +* - customRanking: (array of strings) lets you specify part of the ranking. +* The syntax of this condition is an array of strings containing attributes +* prefixed by asc (ascending order) or desc (descending order) operator. +* For example `"customRanking" => ["desc(population)", "asc(name)"]` +* - queryType: Select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - highlightPreTag: (string) Specify the string that is inserted before +* the highlighted parts in the query result (default to "<em>"). +* - highlightPostTag: (string) Specify the string that is inserted after +* the highlighted parts in the query result (default to "</em>"). +* - optionalWords: (array of strings) Specify a list of words that should +* be considered as optional when found in the query. +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the server answer or the error message if a failure occured +*/ +Index.prototype.setSettings = function(settings, opts, callback) { + if (arguments.length === 1 || typeof opts === 'function') { + callback = opts; + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + var indexObj = this; + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings?forwardToReplicas=' + + forwardToReplicas, + hostType: 'write', + body: settings, + callback: callback + }); +}; + +/* +* @deprecated see client.listApiKeys() +*/ +Index.prototype.listUserKeys = deprecate(function(callback) { + return this.listApiKeys(callback); +}, deprecatedMessage('index.listUserKeys()', 'client.listApiKeys()')); + +/* +* List all existing API keys to this index +* +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with API keys belonging to the index +* +* @deprecated see client.listApiKeys() +*/ +Index.prototype.listApiKeys = deprecate(function(callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys', + hostType: 'read', + callback: callback + }); +}, deprecatedMessage('index.listApiKeys()', 'client.listApiKeys()')); + +/* +* @deprecated see client.getApiKey() +*/ +Index.prototype.getUserKeyACL = deprecate(function(key, callback) { + return this.getApiKey(key, callback); +}, deprecatedMessage('index.getUserKeyACL()', 'client.getApiKey()')); + + +/* +* Get an API key from this index +* +* @param key +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the right API key +* +* @deprecated see client.getApiKey() +*/ +Index.prototype.getApiKey = deprecate(function(key, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, + hostType: 'read', + callback: callback + }); +}, deprecatedMessage('index.getApiKey()', 'client.getApiKey()')); + +/* +* @deprecated see client.deleteApiKey() +*/ +Index.prototype.deleteUserKey = deprecate(function(key, callback) { + return this.deleteApiKey(key, callback); +}, deprecatedMessage('index.deleteUserKey()', 'client.deleteApiKey()')); + +/* +* Delete an existing API key associated to this index +* +* @param key +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the deletion date +* +* @deprecated see client.deleteApiKey() +*/ +Index.prototype.deleteApiKey = deprecate(function(key, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.deleteApiKey()', 'client.deleteApiKey()')); + +/* +* @deprecated see client.addApiKey() +*/ +Index.prototype.addUserKey = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('index.addUserKey()', 'client.addApiKey()')); + +/* +* Add a new API key to this index +* +* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that +* can contains the following values: +* - search: allow to search (https and http) +* - addObject: allows to add/update an object in the index (https only) +* - deleteObject : allows to delete an existing object (https only) +* - deleteIndex : allows to delete index content (https only) +* - settings : allows to get index settings (https only) +* - editSettings : allows to change index settings (https only) +* @param {Object} [params] - Optionnal parameters to set for the key +* @param {number} params.validity - Number of seconds after which the key will +* be automatically removed (0 means no time limit for this key) +* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour +* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call +* @param {string} params.description - A description for your key +* @param {string[]} params.referers - A list of authorized referers +* @param {Object} params.queryParameters - Force the key to use specific query parameters +* @param {Function} callback - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the added API key +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.addUserKey(['search'], { +* validity: 300, +* maxQueriesPerIPPerHour: 2000, +* maxHitsPerQuery: 3, +* description: 'Eat three fruits', +* referers: ['*.algolia.com'], +* queryParameters: { +* tagFilters: ['public'], +* } +* }) +* @see {@link https://www.algolia.com/doc/rest_api#AddIndexKey|Algolia REST API Documentation} +* +* @deprecated see client.addApiKey() +*/ +Index.prototype.addApiKey = deprecate(function(acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: index.addApiKey(arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = null; + } + + var postObj = { + acl: acls + }; + + if (params) { + postObj.validity = params.validity; + postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + postObj.maxHitsPerQuery = params.maxHitsPerQuery; + postObj.description = params.description; + + if (params.queryParameters) { + postObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); + } + + postObj.referers = params.referers; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys', + body: postObj, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.addApiKey()', 'client.addApiKey()')); + +/** +* @deprecated use client.addApiKey() +*/ +Index.prototype.addUserKeyWithValidity = deprecate(function deprecatedAddUserKeyWithValidity(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('index.addUserKeyWithValidity()', 'client.addApiKey()')); + +/* +* @deprecated see client.updateApiKey() +*/ +Index.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { + return this.updateApiKey(key, acls, params, callback); +}, deprecatedMessage('index.updateUserKey()', 'client.updateApiKey()')); + +/** +* Update an existing API key of this index +* @param {string} key - The key to update +* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that +* can contains the following values: +* - search: allow to search (https and http) +* - addObject: allows to add/update an object in the index (https only) +* - deleteObject : allows to delete an existing object (https only) +* - deleteIndex : allows to delete index content (https only) +* - settings : allows to get index settings (https only) +* - editSettings : allows to change index settings (https only) +* @param {Object} [params] - Optionnal parameters to set for the key +* @param {number} params.validity - Number of seconds after which the key will +* be automatically removed (0 means no time limit for this key) +* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour +* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call +* @param {string} params.description - A description for your key +* @param {string[]} params.referers - A list of authorized referers +* @param {Object} params.queryParameters - Force the key to use specific query parameters +* @param {Function} callback - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with user keys list +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.updateApiKey('APIKEY', ['search'], { +* validity: 300, +* maxQueriesPerIPPerHour: 2000, +* maxHitsPerQuery: 3, +* description: 'Eat three fruits', +* referers: ['*.algolia.com'], +* queryParameters: { +* tagFilters: ['public'], +* } +* }) +* @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} +* +* @deprecated see client.updateApiKey() +*/ +Index.prototype.updateApiKey = deprecate(function(key, acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: index.updateApiKey(key, arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 2 || typeof params === 'function') { + callback = params; + params = null; + } + + var putObj = { + acl: acls + }; + + if (params) { + putObj.validity = params.validity; + putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + putObj.maxHitsPerQuery = params.maxHitsPerQuery; + putObj.description = params.description; + + if (params.queryParameters) { + putObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); + } + + putObj.referers = params.referers; + } + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys/' + key, + body: putObj, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.updateApiKey()', 'client.updateApiKey()')); + +},{"17":17,"18":18,"25":25,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"7":7,"8":8}],17:[function(require,module,exports){ +'use strict'; + +// This is the object returned by the `index.browseAll()` method + +module.exports = IndexBrowser; + +var inherits = require(7); +var EventEmitter = require(4).EventEmitter; + +function IndexBrowser() { +} + +inherits(IndexBrowser, EventEmitter); + +IndexBrowser.prototype.stop = function() { + this._stopped = true; + this._clean(); +}; + +IndexBrowser.prototype._end = function() { + this.emit('end'); + this._clean(); +}; + +IndexBrowser.prototype._error = function(err) { + this.emit('error', err); + this._clean(); +}; + +IndexBrowser.prototype._result = function(content) { + this.emit('result', content); +}; + +IndexBrowser.prototype._clean = function() { + this.removeAllListeners('stop'); + this.removeAllListeners('end'); + this.removeAllListeners('error'); + this.removeAllListeners('result'); +}; + +},{"4":4,"7":7}],18:[function(require,module,exports){ +var buildSearchMethod = require(24); +var deprecate = require(27); +var deprecatedMessage = require(28); + +module.exports = IndexCore; + +/* +* Index class constructor. +* You should not use this method directly but use initIndex() function +*/ +function IndexCore(algoliasearch, indexName) { + this.indexName = indexName; + this.as = algoliasearch; + this.typeAheadArgs = null; + this.typeAheadValueOption = null; + + // make sure every index instance has it's own cache + this.cache = {}; +} + +/* +* Clear all queries in cache +*/ +IndexCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/* +* Search inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the full text query +* @param {object} [args] (optional) if set, contains an object with query parameters: +* - page: (integer) Pagination parameter used to select the page to retrieve. +* Page is zero-based and defaults to 0. Thus, +* to retrieve the 10th page you need to set page=9 +* - hitsPerPage: (integer) Pagination parameter used to select the number of hits per page. Defaults to 20. +* - attributesToRetrieve: a string that contains the list of object attributes +* you want to retrieve (let you minimize the answer size). +* Attributes are separated with a comma (for example "name,address"). +* You can also use an array (for example ["name","address"]). +* By default, all attributes are retrieved. You can also use '*' to retrieve all +* values when an attributesToRetrieve setting is specified for your index. +* - attributesToHighlight: a string that contains the list of attributes you +* want to highlight according to the query. +* Attributes are separated by a comma. You can also use an array (for example ["name","address"]). +* If an attribute has no match for the query, the raw value is returned. +* By default all indexed text attributes are highlighted. +* You can use `*` if you want to highlight all textual attributes. +* Numerical attributes are not highlighted. +* A matchLevel is returned for each highlighted attribute and can contain: +* - full: if all the query terms were found in the attribute, +* - partial: if only some of the query terms were found, +* - none: if none of the query terms were found. +* - attributesToSnippet: a string that contains the list of attributes to snippet alongside +* the number of words to return (syntax is `attributeName:nbWords`). +* Attributes are separated by a comma (Example: attributesToSnippet=name:10,content:10). +* You can also use an array (Example: attributesToSnippet: ['name:10','content:10']). +* By default no snippet is computed. +* - minWordSizefor1Typo: the minimum number of characters in a query word to accept one typo in this word. +* Defaults to 3. +* - minWordSizefor2Typos: the minimum number of characters in a query word +* to accept two typos in this word. Defaults to 7. +* - getRankingInfo: if set to 1, the result hits will contain ranking +* information in _rankingInfo attribute. +* - aroundLatLng: search for entries around a given +* latitude/longitude (specified as two floats separated by a comma). +* For example aroundLatLng=47.316669,5.016670). +* You can specify the maximum distance in meters with the aroundRadius parameter (in meters) +* and the precision for ranking with aroundPrecision +* (for example if you set aroundPrecision=100, two objects that are distant of +* less than 100m will be considered as identical for "geo" ranking parameter). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - insideBoundingBox: search entries inside a given area defined by the two extreme points +* of a rectangle (defined by 4 floats: p1Lat,p1Lng,p2Lat,p2Lng). +* For example insideBoundingBox=47.3165,4.9665,47.3424,5.0201). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - numericFilters: a string that contains the list of numeric filters you want to +* apply separated by a comma. +* The syntax of one filter is `attributeName` followed by `operand` followed by `value`. +* Supported operands are `<`, `<=`, `=`, `>` and `>=`. +* You can have multiple conditions on one attribute like for example numericFilters=price>100,price<1000. +* You can also use an array (for example numericFilters: ["price>100","price<1000"]). +* - tagFilters: filter the query by a set of tags. You can AND tags by separating them by commas. +* To OR tags, you must add parentheses. For example, tags=tag1,(tag2,tag3) means tag1 AND (tag2 OR tag3). +* You can also use an array, for example tagFilters: ["tag1",["tag2","tag3"]] +* means tag1 AND (tag2 OR tag3). +* At indexing, tags should be added in the _tags** attribute +* of objects (for example {"_tags":["tag1","tag2"]}). +* - facetFilters: filter the query by a list of facets. +* Facets are separated by commas and each facet is encoded as `attributeName:value`. +* For example: `facetFilters=category:Book,author:John%20Doe`. +* You can also use an array (for example `["category:Book","author:John%20Doe"]`). +* - facets: List of object attributes that you want to use for faceting. +* Comma separated list: `"category,author"` or array `['category','author']` +* Only attributes that have been added in **attributesForFaceting** index setting +* can be used in this parameter. +* You can also use `*` to perform faceting on all attributes specified in **attributesForFaceting**. +* - queryType: select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - optionalWords: a string that contains the list of words that should +* be considered as optional when found in the query. +* Comma separated and array are accepted. +* - distinct: If set to 1, enable the distinct feature (disabled by default) +* if the attributeForDistinct index setting is set. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in a query with the distinct=1 parameter, +* all hits containing a duplicate value for the attributeForDistinct attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best +* one is kept and others are removed. +* - restrictSearchableAttributes: List of attributes you want to use for +* textual search (must be a subset of the attributesToIndex index setting) +* either comma separated or as an array +* @param {function} [callback] the result callback called with two arguments: +* error: null or Error('message'). If false, the content contains the error. +* content: the server answer that contains the list of results. +*/ +IndexCore.prototype.search = buildSearchMethod('query'); + +/* +* -- BETA -- +* Search a record similar to the query inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the similar query +* @param {object} [args] (optional) if set, contains an object with query parameters. +* All search parameters are supported (see search function), restrictSearchableAttributes and facetFilters +* are the two most useful to restrict the similar results and get more relevant content +*/ +IndexCore.prototype.similarSearch = buildSearchMethod('similarQuery'); + +/* +* Browse index content. The response content will have a `cursor` property that you can use +* to browse subsequent pages for this query. Use `index.browseFrom(cursor)` when you want. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browse('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }, callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browse = function(query, queryParameters, callback) { + var merge = require(32); + + var indexObj = this; + + var page; + var hitsPerPage; + + // we check variadic calls that are not the one defined + // .browse()/.browse(fn) + // => page = 0 + if (arguments.length === 0 || arguments.length === 1 && typeof arguments[0] === 'function') { + page = 0; + callback = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'number') { + // .browse(2)/.browse(2, 10)/.browse(2, fn)/.browse(2, 10, fn) + page = arguments[0]; + if (typeof arguments[1] === 'number') { + hitsPerPage = arguments[1]; + } else if (typeof arguments[1] === 'function') { + callback = arguments[1]; + hitsPerPage = undefined; + } + query = undefined; + queryParameters = undefined; + } else if (typeof arguments[0] === 'object') { + // .browse(queryParameters)/.browse(queryParameters, cb) + if (typeof arguments[1] === 'function') { + callback = arguments[1]; + } + queryParameters = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') { + // .browse(query, cb) + callback = arguments[1]; + queryParameters = undefined; + } + + // otherwise it's a .browse(query)/.browse(query, queryParameters)/.browse(query, queryParameters, cb) + + // get search query parameters combining various possible calls + // to .browse(); + queryParameters = merge({}, queryParameters || {}, { + page: page, + hitsPerPage: hitsPerPage, + query: query + }); + + var params = this.as._getSearchParams(queryParameters, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse', + body: {params: params}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Continue browsing from a previous position (cursor), obtained via a call to `.browse()`. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browseFrom('14lkfsakl32', callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browseFrom = function(cursor, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/browse', + body: {cursor: cursor}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* +* @param {string} params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} params.facetQuery Query for the facet search +* @param {string} [params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +* @param callback (optional) +*/ +IndexCore.prototype.searchForFacetValues = function(params, callback) { + var clone = require(25); + var omit = require(33); + var usage = 'Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])'; + + if (params.facetName === undefined || params.facetQuery === undefined) { + throw new Error(usage); + } + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = this.as._getSearchParams(filteredParams, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + + encodeURIComponent(this.indexName) + '/facets/' + encodeURIComponent(facetName) + '/query', + hostType: 'read', + body: {params: searchParameters}, + callback: callback + }); +}; + +IndexCore.prototype.searchFacet = deprecate(function(params, callback) { + return this.searchForFacetValues(params, callback); +}, deprecatedMessage( + 'index.searchFacet(params[, callback])', + 'index.searchForFacetValues(params[, callback])' +)); + +IndexCore.prototype._search = function(params, url, callback, additionalUA) { + return this.as._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url || '/1/indexes/' + encodeURIComponent(this.indexName) + '/query', + body: {params: params}, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName), + body: {params: params} + }, + callback: callback, + additionalUA: additionalUA + }); +}; + +/* +* Get an object from this index +* +* @param objectID the unique identifier of the object to retrieve +* @param attrs (optional) if set, contains the array of attribute names to retrieve +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the object to retrieve or the error message if a failure occured +*/ +IndexCore.prototype.getObject = function(objectID, attrs, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof attrs === 'function') { + callback = attrs; + attrs = undefined; + } + + var params = ''; + if (attrs !== undefined) { + params = '?attributes='; + for (var i = 0; i < attrs.length; ++i) { + if (i !== 0) { + params += ','; + } + params += attrs[i]; + } + } + + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID) + params, + hostType: 'read', + callback: callback + }); +}; + +/* +* Get several objects from this index +* +* @param objectIDs the array of unique identifier of objects to retrieve +*/ +IndexCore.prototype.getObjects = function(objectIDs, attributesToRetrieve, callback) { + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: index.getObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + + if (arguments.length === 1 || typeof attributesToRetrieve === 'function') { + callback = attributesToRetrieve; + attributesToRetrieve = undefined; + } + + var body = { + requests: map(objectIDs, function prepareRequest(objectID) { + var request = { + indexName: indexObj.indexName, + objectID: objectID + }; + + if (attributesToRetrieve) { + request.attributesToRetrieve = attributesToRetrieve.join(','); + } + + return request; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/objects', + hostType: 'read', + body: body, + callback: callback + }); +}; + +IndexCore.prototype.as = null; +IndexCore.prototype.indexName = null; +IndexCore.prototype.typeAheadArgs = null; +IndexCore.prototype.typeAheadValueOption = null; + +},{"24":24,"25":25,"27":27,"28":28,"31":31,"32":32,"33":33,"8":8}],19:[function(require,module,exports){ +(function (process){ +'use strict'; + +// This is the AngularJS Algolia Search module +// It's using $http to do requests with a JSONP fallback +// $q promises are returned + +var inherits = require(7); + +var forEach = require(5); + +var AlgoliaSearch = require(14); +var errors = require(29); +var inlineHeaders = require(22); +var jsonpRequest = require(23); +var places = require(34); + +// expose original algoliasearch fn in window +window.algoliasearch = require(20); + +if (process.env.NODE_ENV === 'debug') { + require(1).enable('algoliasearch*'); +} + +window.angular.module('algoliasearch', []) + .service('algolia', ['$http', '$q', '$timeout', function algoliaSearchService($http, $q, $timeout) { + function algoliasearch(applicationID, apiKey, opts) { + var cloneDeep = require(25); + + opts = cloneDeep(opts || {}); + + opts._ua = opts._ua || algoliasearch.ua; + + return new AlgoliaSearchAngular(applicationID, apiKey, opts); + } + + algoliasearch.version = require(36); + algoliasearch.ua = 'Algolia for AngularJS ' + algoliasearch.version; + algoliasearch.initPlaces = places(algoliasearch); + + // we expose into window no matter how we are used, this will allow + // us to easily debug any website running algolia + window.__algolia = { + debug: require(1), + algoliasearch: algoliasearch + }; + + function AlgoliaSearchAngular() { + // call AlgoliaSearch constructor + AlgoliaSearch.apply(this, arguments); + } + + inherits(AlgoliaSearchAngular, AlgoliaSearch); + + AlgoliaSearchAngular.prototype._request = function request(url, opts) { + // Support most Angular.js versions by using $q.defer() instead + // of the new $q() constructor everywhere we need a promise + var deferred = $q.defer(); + var resolve = deferred.resolve; + var reject = deferred.reject; + + var timedOut; + var body = opts.body; + + url = inlineHeaders(url, opts.headers); + + var timeoutDeferred = $q.defer(); + var timeoutPromise = timeoutDeferred.promise; + + $timeout(function timedout() { + timedOut = true; + // will cancel the xhr + timeoutDeferred.resolve('test'); + reject(new errors.RequestTimeout()); + }, opts.timeouts.complete); + + var requestHeaders = {}; + + // "remove" (set to undefined) possible globally set headers + // in $httpProvider.defaults.headers.common + // otherwise we might fail sometimes + // ref: https://github.com/algolia/algoliasearch-client-js/issues/135 + forEach( + $http.defaults.headers.common, + function removeIt(headerValue, headerName) { + requestHeaders[headerName] = undefined; + } + ); + + requestHeaders.accept = 'application/json'; + + if (body) { + if (opts.method === 'POST') { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests + requestHeaders['content-type'] = 'application/x-www-form-urlencoded'; + } else { + requestHeaders['content-type'] = 'application/json'; + } + } + + $http({ + url: url, + method: opts.method, + data: body, + cache: false, + timeout: timeoutPromise, + headers: requestHeaders, + transformResponse: transformResponse, + // if client uses $httpProvider.defaults.withCredentials = true, + // we revert it to false to avoid CORS failure + withCredentials: false + }).then(success, error); + + function success(response) { + resolve({ + statusCode: response.status, + headers: response.headers, + body: JSON.parse(response.data), + responseText: response.data + }); + } + + // we force getting the raw data because we need it so + // for cache keys + function transformResponse(data) { + return data; + } + + function error(response) { + if (timedOut) { + return; + } + + // network error + if (response.status === 0) { + reject( + new errors.Network({ + more: response + }) + ); + return; + } + + resolve({ + body: JSON.parse(response.data), + statusCode: response.status + }); + } + + return deferred.promise; + }; + + // using IE8 or IE9 we will always end up here + // AngularJS does not fallback to XDomainRequest + AlgoliaSearchAngular.prototype._request.fallback = function requestFallback(url, opts) { + url = inlineHeaders(url, opts.headers); + + var deferred = $q.defer(); + var resolve = deferred.resolve; + var reject = deferred.reject; + + jsonpRequest(url, opts, function jsonpRequestDone(err, content) { + if (err) { + reject(err); + return; + } + + resolve(content); + }); + + return deferred.promise; + }; + + AlgoliaSearchAngular.prototype._promise = { + reject: function(val) { + return $q.reject(val); + }, + resolve: function(val) { + // http://www.bennadel.com/blog/2735-q-when-is-the-missing-q-resolve-method-in-angularjs.htm + return $q.when(val); + }, + delay: function(ms) { + var deferred = $q.defer(); + var resolve = deferred.resolve; + + $timeout(resolve, ms); + + return deferred.promise; + }, + all: function(promises) { + return $q.all(promises); + } + }; + + return { + Client: function(applicationID, apiKey, options) { + return algoliasearch(applicationID, apiKey, options); + }, + ua: algoliasearch.ua, + version: algoliasearch.version + }; + }]); + +}).call(this,require(12)) +},{"1":1,"12":12,"14":14,"20":20,"22":22,"23":23,"25":25,"29":29,"34":34,"36":36,"5":5,"7":7}],20:[function(require,module,exports){ +'use strict'; + +var AlgoliaSearch = require(14); +var createAlgoliasearch = require(21); + +module.exports = createAlgoliasearch(AlgoliaSearch); + +},{"14":14,"21":21}],21:[function(require,module,exports){ +(function (process){ +'use strict'; + +var global = require(6); +var Promise = global.Promise || require(3).Promise; + +// This is the standalone browser build entry point +// Browser implementation of the Algolia Search JavaScript client, +// using XMLHttpRequest, XDomainRequest and JSONP as fallback +module.exports = function createAlgoliasearch(AlgoliaSearch, uaSuffix) { + var inherits = require(7); + var errors = require(29); + var inlineHeaders = require(22); + var jsonpRequest = require(23); + var places = require(34); + uaSuffix = uaSuffix || ''; + + if (process.env.NODE_ENV === 'debug') { + require(1).enable('algoliasearch*'); + } + + function algoliasearch(applicationID, apiKey, opts) { + var cloneDeep = require(25); + + opts = cloneDeep(opts || {}); + + opts._ua = opts._ua || algoliasearch.ua; + + return new AlgoliaSearchBrowser(applicationID, apiKey, opts); + } + + algoliasearch.version = require(36); + algoliasearch.ua = 'Algolia for vanilla JavaScript ' + uaSuffix + algoliasearch.version; + algoliasearch.initPlaces = places(algoliasearch); + + // we expose into window no matter how we are used, this will allow + // us to easily debug any website running algolia + global.__algolia = { + debug: require(1), + algoliasearch: algoliasearch + }; + + var support = { + hasXMLHttpRequest: 'XMLHttpRequest' in global, + hasXDomainRequest: 'XDomainRequest' in global + }; + + if (support.hasXMLHttpRequest) { + support.cors = 'withCredentials' in new XMLHttpRequest(); + } + + function AlgoliaSearchBrowser() { + // call AlgoliaSearch constructor + AlgoliaSearch.apply(this, arguments); + } + + inherits(AlgoliaSearchBrowser, AlgoliaSearch); + + AlgoliaSearchBrowser.prototype._request = function request(url, opts) { + return new Promise(function wrapRequest(resolve, reject) { + // no cors or XDomainRequest, no request + if (!support.cors && !support.hasXDomainRequest) { + // very old browser, not supported + reject(new errors.Network('CORS not supported')); + return; + } + + url = inlineHeaders(url, opts.headers); + + var body = opts.body; + var req = support.cors ? new XMLHttpRequest() : new XDomainRequest(); + var reqTimeout; + var timedOut; + var connected = false; + + reqTimeout = setTimeout(onTimeout, opts.timeouts.connect); + // we set an empty onprogress listener + // so that XDomainRequest on IE9 is not aborted + // refs: + // - https://github.com/algolia/algoliasearch-client-js/issues/76 + // - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment + req.onprogress = onProgress; + if ('onreadystatechange' in req) req.onreadystatechange = onReadyStateChange; + req.onload = onLoad; + req.onerror = onError; + + // do not rely on default XHR async flag, as some analytics code like hotjar + // breaks it and set it to false by default + if (req instanceof XMLHttpRequest) { + req.open(opts.method, url, true); + + // The Analytics API never accepts Auth headers as query string + // this option exists specifically for them. + if (opts.forceAuthHeaders) { + req.setRequestHeader( + 'x-algolia-application-id', + opts.headers['x-algolia-application-id'] + ); + req.setRequestHeader( + 'x-algolia-api-key', + opts.headers['x-algolia-api-key'] + ); + } + } else { + req.open(opts.method, url); + } + + // headers are meant to be sent after open + if (support.cors) { + if (body) { + if (opts.method === 'POST') { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests + req.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); + } else { + req.setRequestHeader('content-type', 'application/json'); + } + } + req.setRequestHeader('accept', 'application/json'); + } + + if (body) { + req.send(body); + } else { + req.send(); + } + + // event object not received in IE8, at least + // but we do not use it, still important to note + function onLoad(/* event */) { + // When browser does not supports req.timeout, we can + // have both a load and timeout event, since handled by a dumb setTimeout + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + var out; + + try { + out = { + body: JSON.parse(req.responseText), + responseText: req.responseText, + statusCode: req.status, + // XDomainRequest does not have any response headers + headers: req.getAllResponseHeaders && req.getAllResponseHeaders() || {} + }; + } catch (e) { + out = new errors.UnparsableJSON({ + more: req.responseText + }); + } + + if (out instanceof errors.UnparsableJSON) { + reject(out); + } else { + resolve(out); + } + } + + function onError(event) { + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + // error event is trigerred both with XDR/XHR on: + // - DNS error + // - unallowed cross domain request + reject( + new errors.Network({ + more: event + }) + ); + } + + function onTimeout() { + timedOut = true; + req.abort(); + + reject(new errors.RequestTimeout()); + } + + function onConnect() { + connected = true; + clearTimeout(reqTimeout); + reqTimeout = setTimeout(onTimeout, opts.timeouts.complete); + } + + function onProgress() { + if (!connected) onConnect(); + } + + function onReadyStateChange() { + if (!connected && req.readyState > 1) onConnect(); + } + }); + }; + + AlgoliaSearchBrowser.prototype._request.fallback = function requestFallback(url, opts) { + url = inlineHeaders(url, opts.headers); + + return new Promise(function wrapJsonpRequest(resolve, reject) { + jsonpRequest(url, opts, function jsonpRequestDone(err, content) { + if (err) { + reject(err); + return; + } + + resolve(content); + }); + }); + }; + + AlgoliaSearchBrowser.prototype._promise = { + reject: function rejectPromise(val) { + return Promise.reject(val); + }, + resolve: function resolvePromise(val) { + return Promise.resolve(val); + }, + delay: function delayPromise(ms) { + return new Promise(function resolveOnTimeout(resolve/* , reject*/) { + setTimeout(resolve, ms); + }); + }, + all: function all(promises) { + return Promise.all(promises); + } + }; + + return algoliasearch; +}; + +}).call(this,require(12)) +},{"1":1,"12":12,"22":22,"23":23,"25":25,"29":29,"3":3,"34":34,"36":36,"6":6,"7":7}],22:[function(require,module,exports){ +'use strict'; + +module.exports = inlineHeaders; + +var encode = require(13); + +function inlineHeaders(url, headers) { + if (/\?/.test(url)) { + url += '&'; + } else { + url += '?'; + } + + return url + encode(headers); +} + +},{"13":13}],23:[function(require,module,exports){ +'use strict'; + +module.exports = jsonpRequest; + +var errors = require(29); + +var JSONPCounter = 0; + +function jsonpRequest(url, opts, cb) { + if (opts.method !== 'GET') { + cb(new Error('Method ' + opts.method + ' ' + url + ' is not supported by JSONP.')); + return; + } + + opts.debug('JSONP: start'); + + var cbCalled = false; + var timedOut = false; + + JSONPCounter += 1; + var head = document.getElementsByTagName('head')[0]; + var script = document.createElement('script'); + var cbName = 'algoliaJSONP_' + JSONPCounter; + var done = false; + + window[cbName] = function(data) { + removeGlobals(); + + if (timedOut) { + opts.debug('JSONP: Late answer, ignoring'); + return; + } + + cbCalled = true; + + clean(); + + cb(null, { + body: data, + responseText: JSON.stringify(data)/* , + // We do not send the statusCode, there's no statusCode in JSONP, it will be + // computed using data.status && data.message like with XDR + statusCode*/ + }); + }; + + // add callback by hand + url += '&callback=' + cbName; + + // add body params manually + if (opts.jsonBody && opts.jsonBody.params) { + url += '&' + opts.jsonBody.params; + } + + var ontimeout = setTimeout(timeout, opts.timeouts.complete); + + // script onreadystatechange needed only for + // <= IE8 + // https://github.com/angular/angular.js/issues/4523 + script.onreadystatechange = readystatechange; + script.onload = success; + script.onerror = error; + + script.async = true; + script.defer = true; + script.src = url; + head.appendChild(script); + + function success() { + opts.debug('JSONP: success'); + + if (done || timedOut) { + return; + } + + done = true; + + // script loaded but did not call the fn => script loading error + if (!cbCalled) { + opts.debug('JSONP: Fail. Script loaded but did not call the callback'); + clean(); + cb(new errors.JSONPScriptFail()); + } + } + + function readystatechange() { + if (this.readyState === 'loaded' || this.readyState === 'complete') { + success(); + } + } + + function clean() { + clearTimeout(ontimeout); + script.onload = null; + script.onreadystatechange = null; + script.onerror = null; + head.removeChild(script); + } + + function removeGlobals() { + try { + delete window[cbName]; + delete window[cbName + '_loaded']; + } catch (e) { + window[cbName] = window[cbName + '_loaded'] = undefined; + } + } + + function timeout() { + opts.debug('JSONP: Script timeout'); + timedOut = true; + clean(); + cb(new errors.RequestTimeout()); + } + + function error() { + opts.debug('JSONP: Script error'); + + if (done || timedOut) { + return; + } + + clean(); + cb(new errors.JSONPScriptError()); + } +} + +},{"29":29}],24:[function(require,module,exports){ +module.exports = buildSearchMethod; + +var errors = require(29); + +/** + * Creates a search method to be used in clients + * @param {string} queryParam the name of the attribute used for the query + * @param {string} url the url + * @return {function} the search method + */ +function buildSearchMethod(queryParam, url) { + /** + * The search method. Prepares the data and send the query to Algolia. + * @param {string} query the string used for query search + * @param {object} args additional parameters to send with the search + * @param {function} [callback] the callback to be called with the client gets the answer + * @return {undefined|Promise} If the callback is not provided then this methods returns a Promise + */ + return function search(query, args, callback) { + // warn V2 users on how to search + if (typeof query === 'function' && typeof args === 'object' || + typeof callback === 'object') { + // .search(query, params, cb) + // .search(cb, params) + throw new errors.AlgoliaSearchError('index.search usage is index.search(query, params, cb)'); + } + + // Normalizing the function signature + if (arguments.length === 0 || typeof query === 'function') { + // Usage : .search(), .search(cb) + callback = query; + query = ''; + } else if (arguments.length === 1 || typeof args === 'function') { + // Usage : .search(query/args), .search(query, cb) + callback = args; + args = undefined; + } + // At this point we have 3 arguments with values + + // Usage : .search(args) // careful: typeof null === 'object' + if (typeof query === 'object' && query !== null) { + args = query; + query = undefined; + } else if (query === undefined || query === null) { // .search(undefined/null) + query = ''; + } + + var params = ''; + + if (query !== undefined) { + params += queryParam + '=' + encodeURIComponent(query); + } + + var additionalUA; + if (args !== undefined) { + if (args.additionalUA) { + additionalUA = args.additionalUA; + delete args.additionalUA; + } + // `_getSearchParams` will augment params, do not be fooled by the = versus += from previous if + params = this.as._getSearchParams(args, params); + } + + + return this._search(params, url, callback, additionalUA); + }; +} + +},{"29":29}],25:[function(require,module,exports){ +module.exports = function clone(obj) { + return JSON.parse(JSON.stringify(obj)); +}; + +},{}],26:[function(require,module,exports){ +module.exports = createAnalyticsClient; + +var algoliasearch = require(20); + +function createAnalyticsClient(appId, apiKey, opts) { + var analytics = {}; + + opts = opts || {}; + // there need to be 4 hosts, like on the client, since if requests fail, + // the counter goes up by 1, so we need to have the same amount of hosts + // 4 because: -dsn, -1, -2, -3 + // This is done because the APPID used for search will be the same for the analytics client created, + // and since the state of available hosts is shared by APPID globally for the module, we had issues + // where the hostIndex would be 1 while the array was only one entry (you got an empty host) + opts.hosts = opts.hosts || [ + 'analytics.algolia.com', + 'analytics.algolia.com', + 'analytics.algolia.com', + 'analytics.algolia.com' + ]; + opts.protocol = opts.protocol || 'https:'; + + analytics.as = algoliasearch(appId, apiKey, opts); + + analytics.getABTests = function(_params, callback) { + var params = params || {}; + var offset = params.offset || 0; + var limit = params.limit || 10; + + return this.as._jsonRequest({ + method: 'GET', + url: '/2/abtests?offset=' + encodeURIComponent(offset) + '&limit=' + encodeURIComponent(limit), + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.getABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/2/abtests/' + encodeURIComponent(abTestID), + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.addABTest = function(abTest, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/2/abtests', + body: abTest, + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.stopABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/2/abtests/' + encodeURIComponent(abTestID) + '/stop', + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.deleteABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'DELETE', + url: '/2/abtests/' + encodeURIComponent(abTestID), + hostType: 'write', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.waitTask = function(indexName, taskID, callback) { + return this.as.initIndex(indexName).waitTask(taskID, callback); + }; + + return analytics; +} + +},{"20":20}],27:[function(require,module,exports){ +module.exports = function deprecate(fn, message) { + var warned = false; + + function deprecated() { + if (!warned) { + /* eslint no-console:0 */ + console.warn(message); + warned = true; + } + + return fn.apply(this, arguments); + } + + return deprecated; +}; + +},{}],28:[function(require,module,exports){ +module.exports = function deprecatedMessage(previousUsage, newUsage) { + var githubAnchorLink = previousUsage.toLowerCase() + .replace(/[\.\(\)]/g, ''); + + return 'algoliasearch: `' + previousUsage + '` was replaced by `' + newUsage + + '`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#' + githubAnchorLink; +}; + +},{}],29:[function(require,module,exports){ +'use strict'; + +// This file hosts our error definitions +// We use custom error "types" so that we can act on them when we need it +// e.g.: if error instanceof errors.UnparsableJSON then.. + +var inherits = require(7); + +function AlgoliaSearchError(message, extraProperties) { + var forEach = require(5); + + var error = this; + + // try to get a stacktrace + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, this.constructor); + } else { + error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old'; + } + + this.name = 'AlgoliaSearchError'; + this.message = message || 'Unknown error'; + + if (extraProperties) { + forEach(extraProperties, function addToErrorObject(value, key) { + error[key] = value; + }); + } +} + +inherits(AlgoliaSearchError, Error); + +function createCustomError(name, message) { + function AlgoliaSearchCustomError() { + var args = Array.prototype.slice.call(arguments, 0); + + // custom message not set, use default + if (typeof args[0] !== 'string') { + args.unshift(message); + } + + AlgoliaSearchError.apply(this, args); + this.name = 'AlgoliaSearch' + name + 'Error'; + } + + inherits(AlgoliaSearchCustomError, AlgoliaSearchError); + + return AlgoliaSearchCustomError; +} + +// late exports to let various fn defs and inherits take place +module.exports = { + AlgoliaSearchError: AlgoliaSearchError, + UnparsableJSON: createCustomError( + 'UnparsableJSON', + 'Could not parse the incoming response as JSON, see err.more for details' + ), + RequestTimeout: createCustomError( + 'RequestTimeout', + 'Request timedout before getting a response' + ), + Network: createCustomError( + 'Network', + 'Network issue, see err.more for details' + ), + JSONPScriptFail: createCustomError( + 'JSONPScriptFail', + '<script> was loaded but did not call our provided callback' + ), + JSONPScriptError: createCustomError( + 'JSONPScriptError', + '<script> unable to load due to an `error` event on it' + ), + Unknown: createCustomError( + 'Unknown', + 'Unknown error occured' + ) +}; + +},{"5":5,"7":7}],30:[function(require,module,exports){ +// Parse cloud does not supports setTimeout +// We do not store a setTimeout reference in the client everytime +// We only fallback to a fake setTimeout when not available +// setTimeout cannot be override globally sadly +module.exports = function exitPromise(fn, _setTimeout) { + _setTimeout(fn, 0); +}; + +},{}],31:[function(require,module,exports){ +var foreach = require(5); + +module.exports = function map(arr, fn) { + var newArr = []; + foreach(arr, function(item, itemIndex) { + newArr.push(fn(item, itemIndex, arr)); + }); + return newArr; +}; + +},{"5":5}],32:[function(require,module,exports){ +var foreach = require(5); + +module.exports = function merge(destination/* , sources */) { + var sources = Array.prototype.slice.call(arguments); + + foreach(sources, function(source) { + for (var keyName in source) { + if (source.hasOwnProperty(keyName)) { + if (typeof destination[keyName] === 'object' && typeof source[keyName] === 'object') { + destination[keyName] = merge({}, destination[keyName], source[keyName]); + } else if (source[keyName] !== undefined) { + destination[keyName] = source[keyName]; + } + } + } + }); + + return destination; +}; + +},{"5":5}],33:[function(require,module,exports){ +module.exports = function omit(obj, test) { + var keys = require(10); + var foreach = require(5); + + var filtered = {}; + + foreach(keys(obj), function doFilter(keyName) { + if (test(keyName) !== true) { + filtered[keyName] = obj[keyName]; + } + }); + + return filtered; +}; + +},{"10":10,"5":5}],34:[function(require,module,exports){ +module.exports = createPlacesClient; + +var buildSearchMethod = require(24); + +function createPlacesClient(algoliasearch) { + return function places(appID, apiKey, opts) { + var cloneDeep = require(25); + + opts = opts && cloneDeep(opts) || {}; + opts.hosts = opts.hosts || [ + 'places-dsn.algolia.net', + 'places-1.algolianet.com', + 'places-2.algolianet.com', + 'places-3.algolianet.com' + ]; + + // allow initPlaces() no arguments => community rate limited + if (arguments.length === 0 || typeof appID === 'object' || appID === undefined) { + appID = ''; + apiKey = ''; + opts._allowEmptyCredentials = true; + } + + var client = algoliasearch(appID, apiKey, opts); + var index = client.initIndex('places'); + index.search = buildSearchMethod('query', '/1/places/query'); + index.getObject = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/places/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); + }; + return index; + }; +} + +},{"24":24,"25":25}],35:[function(require,module,exports){ +(function (global){ +var debug = require(1)('algoliasearch:src/hostIndexState.js'); +var localStorageNamespace = 'algoliasearch-client-js'; + +var store; +var moduleStore = { + state: {}, + set: function(key, data) { + this.state[key] = data; + return this.state[key]; + }, + get: function(key) { + return this.state[key] || null; + } +}; + +var localStorageStore = { + set: function(key, data) { + moduleStore.set(key, data); // always replicate localStorageStore to moduleStore in case of failure + + try { + var namespace = JSON.parse(global.localStorage[localStorageNamespace]); + namespace[key] = data; + global.localStorage[localStorageNamespace] = JSON.stringify(namespace); + return namespace[key]; + } catch (e) { + return localStorageFailure(key, e); + } + }, + get: function(key) { + try { + return JSON.parse(global.localStorage[localStorageNamespace])[key] || null; + } catch (e) { + return localStorageFailure(key, e); + } + } +}; + +function localStorageFailure(key, e) { + debug('localStorage failed with', e); + cleanup(); + store = moduleStore; + return store.get(key); +} + +store = supportsLocalStorage() ? localStorageStore : moduleStore; + +module.exports = { + get: getOrSet, + set: getOrSet, + supportsLocalStorage: supportsLocalStorage +}; + +function getOrSet(key, data) { + if (arguments.length === 1) { + return store.get(key); + } + + return store.set(key, data); +} + +function supportsLocalStorage() { + try { + if ('localStorage' in global && + global.localStorage !== null) { + if (!global.localStorage[localStorageNamespace]) { + // actual creation of the namespace + global.localStorage.setItem(localStorageNamespace, JSON.stringify({})); + } + return true; + } + + return false; + } catch (_) { + return false; + } +} + +// In case of any error on localStorage, we clean our own namespace, this should handle +// quota errors when a lot of keys + data are used +function cleanup() { + try { + global.localStorage.removeItem(localStorageNamespace); + } catch (_) { + // nothing to do + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"1":1}],36:[function(require,module,exports){ +'use strict'; + +module.exports = '3.30.0'; + +},{}]},{},[19]); diff --git a/node_modules/algoliasearch/dist/algoliasearch.angular.min.js b/node_modules/algoliasearch/dist/algoliasearch.angular.min.js new file mode 100644 index 00000000..edbed503 --- /dev/null +++ b/node_modules/algoliasearch/dist/algoliasearch.angular.min.js @@ -0,0 +1,4 @@ +/*! algoliasearch 3.30.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +!function(e){var t;"undefined"!=typeof window?t=window:"undefined"!=typeof self&&(t=self),t.ALGOLIA_MIGRATION_LAYER=e()}(function(){return function e(t,r,o){function n(s,a){if(!r[s]){if(!t[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};t[s][0].call(l.exports,function(e){var r=t[s][1][e];return n(r?r:e)},l,l.exports,e,t,r,o)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s<o.length;s++)n(o[s]);return n}({1:[function(e,t,r){function o(e,t){for(var r in t)e.setAttribute(r,t[r])}function n(e,t){e.onload=function(){this.onerror=this.onload=null,t(null,e)},e.onerror=function(){this.onerror=this.onload=null,t(new Error("Failed to load "+this.src),e)}}function i(e,t){e.onreadystatechange=function(){"complete"!=this.readyState&&"loaded"!=this.readyState||(this.onreadystatechange=null,t(null,e))}}t.exports=function(e,t,r){var s=document.head||document.getElementsByTagName("head")[0],a=document.createElement("script");"function"==typeof t&&(r=t,t={}),t=t||{},r=r||function(){},a.type=t.type||"text/javascript",a.charset=t.charset||"utf8",a.async=!("async"in t)||!!t.async,a.src=e,t.attrs&&o(a,t.attrs),t.text&&(a.text=""+t.text);var c="onload"in a?n:i;c(a,r),a.onload||n(a,r),s.appendChild(a)}},{}],2:[function(e,t,r){"use strict";function o(e){for(var t=new RegExp("cdn\\.jsdelivr\\.net/algoliasearch/latest/"+e.replace(".","\\.")+"(?:\\.min)?\\.js$"),r=document.getElementsByTagName("script"),o=!1,n=0,i=r.length;n<i;n++)if(r[n].src&&t.test(r[n].src)){o=!0;break}return o}t.exports=o},{}],3:[function(e,t,r){"use strict";function o(t){var r=e(1),o="//cdn.jsdelivr.net/algoliasearch/2/"+t+".min.js",i="-- AlgoliaSearch `latest` warning --\nWarning, you are using the `latest` version string from jsDelivr to load the AlgoliaSearch library.\nUsing `latest` is no more recommended, you should load //cdn.jsdelivr.net/algoliasearch/2/algoliasearch.min.js\n\nAlso, we updated the AlgoliaSearch JavaScript client to V3. If you want to upgrade,\nplease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch `latest` warning --";window.console&&(window.console.warn?window.console.warn(i):window.console.log&&window.console.log(i));try{document.write("<script>window.ALGOLIA_SUPPORTS_DOCWRITE = true</script>"),window.ALGOLIA_SUPPORTS_DOCWRITE===!0?(document.write('<script src="'+o+'"></script>'),n("document.write")()):r(o,n("DOMElement"))}catch(s){r(o,n("DOMElement"))}}function n(e){return function(){var t="AlgoliaSearch: loaded V2 script using "+e;window.console&&window.console.log&&window.console.log(t)}}t.exports=o},{1:1}],4:[function(e,t,r){"use strict";function o(){var e="-- AlgoliaSearch V2 => V3 error --\nYou are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\nPlease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch V2 => V3 error --";window.AlgoliaSearch=function(){throw new Error(e)},window.AlgoliaSearchHelper=function(){throw new Error(e)},window.AlgoliaExplainResults=function(){throw new Error(e)}}t.exports=o},{}],5:[function(e,t,r){"use strict";function o(t){var r=e(2),o=e(3),n=e(4);r(t)?o(t):n()}o("algoliasearch.angular")},{2:2,3:3,4:4}]},{},[5])(5)}),function e(t,r,o){function n(s,a){if(!r[s]){if(!t[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};t[s][0].call(l.exports,function(e){var r=t[s][1][e];return n(r?r:e)},l,l.exports,e,t,r,o)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s<o.length;s++)n(o[s]);return n}({1:[function(e,t,r){(function(o){function n(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function i(e){var t=this.useColors;if(e[0]=(t?"%c":"")+this.namespace+(t?" %c":" ")+e[0]+(t?"%c ":" ")+"+"+r.humanize(this.diff),t){var o="color: "+this.color;e.splice(1,0,o,"color: inherit");var n=0,i=0;e[0].replace(/%[a-zA-Z%]/g,function(e){"%%"!==e&&(n++,"%c"===e&&(i=n))}),e.splice(i,0,o)}}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?r.storage.removeItem("debug"):r.storage.debug=e}catch(t){}}function c(){var e;try{e=r.storage.debug}catch(t){}return!e&&"undefined"!=typeof o&&"env"in o&&(e=o.env.DEBUG),e}function u(){try{return window.localStorage}catch(e){}}r=t.exports=e(2),r.log=s,r.formatArgs=i,r.save=a,r.load=c,r.useColors=n,r.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:u(),r.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],r.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},r.enable(c())}).call(this,e(12))},{12:12,2:2}],2:[function(e,t,r){function o(e){var t,o=0;for(t in e)o=(o<<5)-o+e.charCodeAt(t),o|=0;return r.colors[Math.abs(o)%r.colors.length]}function n(e){function t(){if(t.enabled){var e=t,o=+new Date,n=o-(u||o);e.diff=n,e.prev=u,e.curr=o,u=o;for(var i=new Array(arguments.length),s=0;s<i.length;s++)i[s]=arguments[s];i[0]=r.coerce(i[0]),"string"!=typeof i[0]&&i.unshift("%O");var a=0;i[0]=i[0].replace(/%([a-zA-Z%])/g,function(t,o){if("%%"===t)return t;a++;var n=r.formatters[o];if("function"==typeof n){var s=i[a];t=n.call(e,s),i.splice(a,1),a--}return t}),r.formatArgs.call(e,i);var c=t.log||r.log||console.log.bind(console);c.apply(e,i)}}return t.namespace=e,t.enabled=r.enabled(e),t.useColors=r.useColors(),t.color=o(e),"function"==typeof r.init&&r.init(t),t}function i(e){r.save(e),r.names=[],r.skips=[];for(var t=("string"==typeof e?e:"").split(/[\s,]+/),o=t.length,n=0;n<o;n++)t[n]&&(e=t[n].replace(/\*/g,".*?"),"-"===e[0]?r.skips.push(new RegExp("^"+e.substr(1)+"$")):r.names.push(new RegExp("^"+e+"$")))}function s(){r.enable("")}function a(e){var t,o;for(t=0,o=r.skips.length;t<o;t++)if(r.skips[t].test(e))return!1;for(t=0,o=r.names.length;t<o;t++)if(r.names[t].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}r=t.exports=n.debug=n["default"]=n,r.coerce=c,r.disable=s,r.enable=i,r.enabled=a,r.humanize=e(9),r.names=[],r.skips=[],r.formatters={};var u},{9:9}],3:[function(e,t,r){(function(o,n){!function(e,o){"object"==typeof r&&"undefined"!=typeof t?t.exports=o():"function"==typeof define&&define.amd?define(o):e.ES6Promise=o()}(this,function(){"use strict";function t(e){var t=typeof e;return null!==e&&("object"===t||"function"===t)}function r(e){return"function"==typeof e}function i(e){X=e}function s(e){W=e}function a(){return function(){return o.nextTick(d)}}function c(){return"undefined"!=typeof V?function(){V(d)}:p()}function u(){var e=0,t=new Z(d),r=document.createTextNode("");return t.observe(r,{characterData:!0}),function(){r.data=e=++e%2}}function l(){var e=new MessageChannel;return e.port1.onmessage=d,function(){return e.port2.postMessage(0)}}function p(){var e=setTimeout;return function(){return e(d,1)}}function d(){for(var e=0;e<G;e+=2){var t=re[e],r=re[e+1];t(r),re[e]=void 0,re[e+1]=void 0}G=0}function h(){try{var t=e,r=t("vertx");return V=r.runOnLoop||r.runOnContext,c()}catch(o){return p()}}function f(e,t){var r=arguments,o=this,n=new this.constructor(m);void 0===n[ne]&&C(n);var i=o._state;return i?!function(){var e=r[i-1];W(function(){return E(i,n,e,o._result)})}():I(o,n,e,t),n}function y(e){var t=this;if(e&&"object"==typeof e&&e.constructor===t)return e;var r=new t(m);return R(r,e),r}function m(){}function v(){return new TypeError("You cannot resolve a promise with itself")}function g(){return new TypeError("A promises callback cannot return that same promise.")}function b(e){try{return e.then}catch(t){return ce.error=t,ce}}function w(e,t,r,o){try{e.call(t,r,o)}catch(n){return n}}function _(e,t,r){W(function(e){var o=!1,n=w(r,t,function(r){o||(o=!0,t!==r?R(e,r):j(e,r))},function(t){o||(o=!0,S(e,t))},"Settle: "+(e._label||" unknown promise"));!o&&n&&(o=!0,S(e,n))},e)}function T(e,t){t._state===se?j(e,t._result):t._state===ae?S(e,t._result):I(t,void 0,function(t){return R(e,t)},function(t){return S(e,t)})}function x(e,t,o){t.constructor===e.constructor&&o===f&&t.constructor.resolve===y?T(e,t):o===ce?(S(e,ce.error),ce.error=null):void 0===o?j(e,t):r(o)?_(e,t,o):j(e,t)}function R(e,r){e===r?S(e,v()):t(r)?x(e,r,b(r)):j(e,r)}function A(e){e._onerror&&e._onerror(e._result),k(e)}function j(e,t){e._state===ie&&(e._result=t,e._state=se,0!==e._subscribers.length&&W(k,e))}function S(e,t){e._state===ie&&(e._state=ae,e._result=t,W(A,e))}function I(e,t,r,o){var n=e._subscribers,i=n.length;e._onerror=null,n[i]=t,n[i+se]=r,n[i+ae]=o,0===i&&e._state&&W(k,e)}function k(e){var t=e._subscribers,r=e._state;if(0!==t.length){for(var o=void 0,n=void 0,i=e._result,s=0;s<t.length;s+=3)o=t[s],n=t[s+r],o?E(r,o,n,i):n(i);e._subscribers.length=0}}function O(){this.error=null}function q(e,t){try{return e(t)}catch(r){return ue.error=r,ue}}function E(e,t,o,n){var i=r(o),s=void 0,a=void 0,c=void 0,u=void 0;if(i){if(s=q(o,n),s===ue?(u=!0,a=s.error,s.error=null):c=!0,t===s)return void S(t,g())}else s=n,c=!0;t._state!==ie||(i&&c?R(t,s):u?S(t,a):e===se?j(t,s):e===ae&&S(t,s))}function U(e,t){try{t(function(t){R(e,t)},function(t){S(e,t)})}catch(r){S(e,r)}}function P(){return le++}function C(e){e[ne]=le++,e._state=void 0,e._result=void 0,e._subscribers=[]}function N(e,t){this._instanceConstructor=e,this.promise=new e(m),this.promise[ne]||C(this.promise),$(t)?(this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0===this.length?j(this.promise,this._result):(this.length=this.length||0,this._enumerate(t),0===this._remaining&&j(this.promise,this._result))):S(this.promise,D())}function D(){return new Error("Array Methods must be provided an Array")}function K(e){return new N(this,e).promise}function L(e){var t=this;return new t($(e)?function(r,o){for(var n=e.length,i=0;i<n;i++)t.resolve(e[i]).then(r,o)}:function(e,t){return t(new TypeError("You must pass an array to race."))})}function H(e){var t=this,r=new t(m);return S(r,e),r}function M(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function J(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function F(e){this[ne]=P(),this._result=this._state=void 0,this._subscribers=[],m!==e&&("function"!=typeof e&&M(),this instanceof F?U(this,e):J())}function B(){var e=void 0;if("undefined"!=typeof n)e=n;else if("undefined"!=typeof self)e=self;else try{e=Function("return this")()}catch(t){throw new Error("polyfill failed because global object is unavailable in this environment")}var r=e.Promise;if(r){var o=null;try{o=Object.prototype.toString.call(r.resolve())}catch(t){}if("[object Promise]"===o&&!r.cast)return}e.Promise=F}var Q=void 0;Q=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var $=Q,G=0,V=void 0,X=void 0,W=function(e,t){re[G]=e,re[G+1]=t,G+=2,2===G&&(X?X(d):oe())},Y="undefined"!=typeof window?window:void 0,z=Y||{},Z=z.MutationObserver||z.WebKitMutationObserver,ee="undefined"==typeof self&&"undefined"!=typeof o&&"[object process]"==={}.toString.call(o),te="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,re=new Array(1e3),oe=void 0;oe=ee?a():Z?u():te?l():void 0===Y&&"function"==typeof e?h():p();var ne=Math.random().toString(36).substring(16),ie=void 0,se=1,ae=2,ce=new O,ue=new O,le=0;return N.prototype._enumerate=function(e){for(var t=0;this._state===ie&&t<e.length;t++)this._eachEntry(e[t],t)},N.prototype._eachEntry=function(e,t){var r=this._instanceConstructor,o=r.resolve;if(o===y){var n=b(e);if(n===f&&e._state!==ie)this._settledAt(e._state,t,e._result);else if("function"!=typeof n)this._remaining--,this._result[t]=e;else if(r===F){var i=new r(m);x(i,e,n),this._willSettleAt(i,t)}else this._willSettleAt(new r(function(t){return t(e)}),t)}else this._willSettleAt(o(e),t)},N.prototype._settledAt=function(e,t,r){var o=this.promise;o._state===ie&&(this._remaining--,e===ae?S(o,r):this._result[t]=r),0===this._remaining&&j(o,this._result)},N.prototype._willSettleAt=function(e,t){var r=this;I(e,void 0,function(e){return r._settledAt(se,t,e)},function(e){return r._settledAt(ae,t,e)})},F.all=K,F.race=L,F.resolve=y,F.reject=H,F._setScheduler=i,F._setAsap=s,F._asap=W,F.prototype={constructor:F,then:f,"catch":function(e){return this.then(null,e)}},F.polyfill=B,F.Promise=F,F})}).call(this,e(12),"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{12:12}],4:[function(e,t,r){function o(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function n(e){return"function"==typeof e}function i(e){return"number"==typeof e}function s(e){return"object"==typeof e&&null!==e}function a(e){return void 0===e}t.exports=o,o.EventEmitter=o,o.prototype._events=void 0,o.prototype._maxListeners=void 0,o.defaultMaxListeners=10,o.prototype.setMaxListeners=function(e){if(!i(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},o.prototype.emit=function(e){var t,r,o,i,c,u;if(this._events||(this._events={}),"error"===e&&(!this._events.error||s(this._events.error)&&!this._events.error.length)){if(t=arguments[1],t instanceof Error)throw t;var l=new Error('Uncaught, unspecified "error" event. ('+t+")");throw l.context=t,l}if(r=this._events[e],a(r))return!1;if(n(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:i=Array.prototype.slice.call(arguments,1),r.apply(this,i)}else if(s(r))for(i=Array.prototype.slice.call(arguments,1),u=r.slice(),o=u.length,c=0;c<o;c++)u[c].apply(this,i);return!0},o.prototype.addListener=function(e,t){var r;if(!n(t))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,n(t.listener)?t.listener:t),this._events[e]?s(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,s(this._events[e])&&!this._events[e].warned&&(r=a(this._maxListeners)?o.defaultMaxListeners:this._maxListeners,r&&r>0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())),this},o.prototype.on=o.prototype.addListener,o.prototype.once=function(e,t){function r(){this.removeListener(e,r),o||(o=!0,t.apply(this,arguments))}if(!n(t))throw TypeError("listener must be a function");var o=!1;return r.listener=t,this.on(e,r),this},o.prototype.removeListener=function(e,t){var r,o,i,a;if(!n(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(r=this._events[e],i=r.length,o=-1,r===t||n(r.listener)&&r.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(s(r)){for(a=i;a-- >0;)if(r[a]===t||r[a].listener&&r[a].listener===t){o=a;break}if(o<0)return this;1===r.length?(r.length=0,delete this._events[e]):r.splice(o,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},o.prototype.removeAllListeners=function(e){var t,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[e],n(r))this.removeListener(e,r);else if(r)for(;r.length;)this.removeListener(e,r[r.length-1]);return delete this._events[e],this},o.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?n(this._events[e])?[this._events[e]]:this._events[e].slice():[]},o.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(n(t))return 1;if(t)return t.length}return 0},o.listenerCount=function(e,t){return e.listenerCount(t)}},{}],5:[function(e,t,r){var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString;t.exports=function(e,t,r){if("[object Function]"!==n.call(t))throw new TypeError("iterator must be a function");var i=e.length;if(i===+i)for(var s=0;s<i;s++)t.call(r,e[s],s,e);else for(var a in e)o.call(e,a)&&t.call(r,e[a],a,e)}},{}],6:[function(e,t,r){(function(e){var r;r="undefined"!=typeof window?window:"undefined"!=typeof e?e:"undefined"!=typeof self?self:{},t.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(e,t,r){"function"==typeof Object.create?t.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}},{}],8:[function(e,t,r){var o={}.toString;t.exports=Array.isArray||function(e){return"[object Array]"==o.call(e)}},{}],9:[function(e,t,r){function o(e){if(e=String(e),!(e.length>100)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var r=parseFloat(t[1]),o=(t[2]||"ms").toLowerCase();switch(o){case"years":case"year":case"yrs":case"yr":case"y":return r*p;case"days":case"day":case"d":return r*l;case"hours":case"hour":case"hrs":case"hr":case"h":return r*u;case"minutes":case"minute":case"mins":case"min":case"m":return r*c;case"seconds":case"second":case"secs":case"sec":case"s":return r*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function n(e){return e>=l?Math.round(e/l)+"d":e>=u?Math.round(e/u)+"h":e>=c?Math.round(e/c)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function i(e){return s(e,l,"day")||s(e,u,"hour")||s(e,c,"minute")||s(e,a,"second")||e+" ms"}function s(e,t,r){if(!(e<t))return e<1.5*t?Math.floor(e/t)+" "+r:Math.ceil(e/t)+" "+r+"s"}var a=1e3,c=60*a,u=60*c,l=24*u,p=365.25*l;t.exports=function(e,t){t=t||{};var r=typeof e;if("string"===r&&e.length>0)return o(e);if("number"===r&&isNaN(e)===!1)return t["long"]?i(e):n(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],10:[function(e,t,r){"use strict";var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString,i=Array.prototype.slice,s=e(11),a=Object.prototype.propertyIsEnumerable,c=!a.call({toString:null},"toString"),u=a.call(function(){},"prototype"),l=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],p=function(e){var t=e.constructor;return t&&t.prototype===e},d={$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},h=function(){if("undefined"==typeof window)return!1;for(var e in window)try{if(!d["$"+e]&&o.call(window,e)&&null!==window[e]&&"object"==typeof window[e])try{p(window[e])}catch(t){return!0}}catch(t){return!0}return!1}(),f=function(e){if("undefined"==typeof window||!h)return p(e);try{return p(e)}catch(t){return!1}},y=function(e){var t=null!==e&&"object"==typeof e,r="[object Function]"===n.call(e),i=s(e),a=t&&"[object String]"===n.call(e),p=[];if(!t&&!r&&!i)throw new TypeError("Object.keys called on a non-object");var d=u&&r;if(a&&e.length>0&&!o.call(e,0))for(var h=0;h<e.length;++h)p.push(String(h));if(i&&e.length>0)for(var y=0;y<e.length;++y)p.push(String(y));else for(var m in e)d&&"prototype"===m||!o.call(e,m)||p.push(String(m));if(c)for(var v=f(e),g=0;g<l.length;++g)v&&"constructor"===l[g]||!o.call(e,l[g])||p.push(l[g]);return p};y.shim=function(){if(Object.keys){var e=function(){return 2===(Object.keys(arguments)||"").length}(1,2);if(!e){var t=Object.keys;Object.keys=function(e){return t(s(e)?i.call(e):e)}}}else Object.keys=y;return Object.keys||y},t.exports=y},{11:11}],11:[function(e,t,r){"use strict";var o=Object.prototype.toString;t.exports=function(e){var t=o.call(e),r="[object Arguments]"===t;return r||(r="[object Array]"!==t&&null!==e&&"object"==typeof e&&"number"==typeof e.length&&e.length>=0&&"[object Function]"===o.call(e.callee)),r}},{}],12:[function(e,t,r){function o(){throw new Error("setTimeout has not been defined")}function n(){throw new Error("clearTimeout has not been defined")}function i(e){if(p===setTimeout)return setTimeout(e,0);if((p===o||!p)&&setTimeout)return p=setTimeout,setTimeout(e,0);try{return p(e,0)}catch(t){try{return p.call(null,e,0)}catch(t){return p.call(this,e,0)}}}function s(e){if(d===clearTimeout)return clearTimeout(e);if((d===n||!d)&&clearTimeout)return d=clearTimeout,clearTimeout(e);try{return d(e)}catch(t){try{return d.call(null,e)}catch(t){return d.call(this,e)}}}function a(){m&&f&&(m=!1,f.length?y=f.concat(y):v=-1,y.length&&c())}function c(){if(!m){var e=i(a);m=!0;for(var t=y.length;t;){for(f=y,y=[];++v<t;)f&&f[v].run();v=-1,t=y.length}f=null,m=!1,s(e)}}function u(e,t){this.fun=e,this.array=t}function l(){}var p,d,h=t.exports={};!function(){try{p="function"==typeof setTimeout?setTimeout:o}catch(e){p=o}try{d="function"==typeof clearTimeout?clearTimeout:n}catch(e){d=n}}();var f,y=[],m=!1,v=-1;h.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var r=1;r<arguments.length;r++)t[r-1]=arguments[r];y.push(new u(e,t)),1!==y.length||m||i(c)},u.prototype.run=function(){this.fun.apply(null,this.array)},h.title="browser",h.browser=!0,h.env={},h.argv=[],h.version="",h.versions={},h.on=l,h.addListener=l,h.once=l,h.off=l,h.removeListener=l,h.removeAllListeners=l,h.emit=l,h.binding=function(e){throw new Error("process.binding is not supported")},h.cwd=function(){return"/"},h.chdir=function(e){throw new Error("process.chdir is not supported")},h.umask=function(){return 0}},{}],13:[function(e,t,r){"use strict";function o(e,t){if(e.map)return e.map(t);for(var r=[],o=0;o<e.length;o++)r.push(t(e[o],o));return r}var n=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};t.exports=function(e,t,r,a){return t=t||"&",r=r||"=",null===e&&(e=void 0),"object"==typeof e?o(s(e),function(s){var a=encodeURIComponent(n(s))+r;return i(e[s])?o(e[s],function(e){return a+encodeURIComponent(n(e))}).join(t):a+encodeURIComponent(n(e[s]))}).join(t):a?encodeURIComponent(n(a))+r+encodeURIComponent(n(e)):""};var i=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},s=Object.keys||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.push(r);return t}},{}],14:[function(e,t,r){function o(){c.apply(this,arguments)}function n(){var e="Not implemented in this environment.\nIf you feel this is a mistake, write to support@algolia.com";throw new l.AlgoliaSearchError(e)}t.exports=o;var i=e(16),s=e(27),a=e(28),c=e(15),u=e(7),l=e(29);u(o,c),o.prototype.deleteIndex=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(e),hostType:"write",callback:t})},o.prototype.moveIndex=function(e,t,r){var o={operation:"move",destination:t};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:o,hostType:"write",callback:r})},o.prototype.copyIndex=function(e,t,r,o){var n={operation:"copy",destination:t},i=o;if("function"==typeof r)i=r;else if(Array.isArray(r)&&r.length>0)n.scope=r;else if("undefined"!=typeof r)throw new Error("the scope given to `copyIndex` was not an array with settings, synonyms or rules");return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:n,hostType:"write",callback:i})},o.prototype.getLogs=function(t,r,o){var n=e(25),i={};return"object"==typeof t?(i=n(t),o=r):0===arguments.length||"function"==typeof t?o=t:1===arguments.length||"function"==typeof r?(o=r,i.offset=t):(i.offset=t,i.length=r),void 0===i.offset&&(i.offset=0),void 0===i.length&&(i.length=10),this._jsonRequest({method:"GET",url:"/1/logs?"+this._getSearchParams(i,""),hostType:"read",callback:o})},o.prototype.listIndexes=function(e,t){var r="";return void 0===e||"function"==typeof e?t=e:r="?page="+e,this._jsonRequest({method:"GET",url:"/1/indexes"+r,hostType:"read",callback:t})},o.prototype.initIndex=function(e){return new i(this,e)},o.prototype.initAnalytics=function(t){var r=e(26);return r(this.applicationID,this.apiKey,t)},o.prototype.listUserKeys=s(function(e){return this.listApiKeys(e)},a("client.listUserKeys()","client.listApiKeys()")),o.prototype.listApiKeys=function(e){return this._jsonRequest({method:"GET",url:"/1/keys",hostType:"read",callback:e})},o.prototype.getUserKeyACL=s(function(e,t){return this.getApiKey(e,t)},a("client.getUserKeyACL()","client.getApiKey()")),o.prototype.getApiKey=function(e,t){return this._jsonRequest({method:"GET",url:"/1/keys/"+e,hostType:"read",callback:t})},o.prototype.deleteUserKey=s(function(e,t){return this.deleteApiKey(e,t)},a("client.deleteUserKey()","client.deleteApiKey()")),o.prototype.deleteApiKey=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/keys/"+e,hostType:"write",callback:t})},o.prototype.addUserKey=s(function(e,t,r){return this.addApiKey(e,t,r)},a("client.addUserKey()","client.addApiKey()")),o.prototype.addApiKey=function(t,r,o){var n=e(8),i="Usage: client.addApiKey(arrayOfAcls[, params, callback])";if(!n(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.indexes=r.indexes,s.description=r.description,r.queryParameters&&(s.queryParameters=this._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this._jsonRequest({method:"POST",url:"/1/keys",body:s,hostType:"write",callback:o})},o.prototype.addUserKeyWithValidity=s(function(e,t,r){return this.addApiKey(e,t,r)},a("client.addUserKeyWithValidity()","client.addApiKey()")),o.prototype.updateUserKey=s(function(e,t,r,o){return this.updateApiKey(e,t,r,o)},a("client.updateUserKey()","client.updateApiKey()")),o.prototype.updateApiKey=function(t,r,o,n){var i=e(8),s="Usage: client.updateApiKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof o||(n=o,o=null);var a={acl:r};return o&&(a.validity=o.validity,a.maxQueriesPerIPPerHour=o.maxQueriesPerIPPerHour,a.maxHitsPerQuery=o.maxHitsPerQuery,a.indexes=o.indexes,a.description=o.description,o.queryParameters&&(a.queryParameters=this._getSearchParams(o.queryParameters,"")),a.referers=o.referers),this._jsonRequest({method:"PUT",url:"/1/keys/"+t,body:a,hostType:"write",callback:n})},o.prototype.startQueriesBatch=s(function(){this._batch=[]},a("client.startQueriesBatch()","client.search()")),o.prototype.addQueryInBatch=s(function(e,t,r){this._batch.push({indexName:e,query:t,params:r})},a("client.addQueryInBatch()","client.search()")),o.prototype.sendQueriesBatch=s(function(e){return this.search(this._batch,e)},a("client.sendQueriesBatch()","client.search()")),o.prototype.batch=function(t,r){var o=e(8),n="Usage: client.batch(operations[, callback])";if(!o(t))throw new Error(n);return this._jsonRequest({method:"POST",url:"/1/indexes/*/batch",body:{requests:t},hostType:"write",callback:r})},o.prototype.assignUserID=function(e,t){if(!e.userID||!e.cluster)throw new l.AlgoliaSearchError("You have to provide both a userID and cluster",e);return this._jsonRequest({method:"POST",url:"/1/clusters/mapping",hostType:"write",body:{cluster:e.cluster},callback:t,headers:{"x-algolia-user-id":e.userID}})},o.prototype.getTopUserID=function(e){return this._jsonRequest({method:"GET",url:"/1/clusters/mapping/top",hostType:"read",callback:e})},o.prototype.getUserID=function(e,t){if(!e.userID)throw new l.AlgoliaSearchError("You have to provide a userID",{debugData:e});return this._jsonRequest({method:"GET",url:"/1/clusters/mapping/"+e.userID,hostType:"read",callback:t})},o.prototype.listClusters=function(e){return this._jsonRequest({method:"GET",url:"/1/clusters",hostType:"read",callback:e})},o.prototype.listUserIDs=function(e,t){return this._jsonRequest({method:"GET",url:"/1/clusters/mapping",body:e,hostType:"read",callback:t})},o.prototype.removeUserID=function(e,t){if(!e.userID)throw new l.AlgoliaSearchError("You have to provide a userID",{debugData:e});return this._jsonRequest({method:"DELETE",url:"/1/clusters/mapping",hostType:"write",callback:t,headers:{"x-algolia-user-id":e.userID}})},o.prototype.searchUserIDs=function(e,t){return this._jsonRequest({method:"POST",url:"/1/clusters/mapping/search",body:e,hostType:"read",callback:t})},o.prototype.destroy=n,o.prototype.enableRateLimitForward=n,o.prototype.disableRateLimitForward=n,o.prototype.useSecuredAPIKey=n,o.prototype.disableSecuredAPIKey=n,o.prototype.generateSecuredApiKey=n},{15:15,16:16,25:25,26:26,27:27,28:28,29:29,7:7,8:8}],15:[function(e,t,r){(function(r){function o(t,r,o){var i=e(1)("algoliasearch"),s=e(25),a=e(8),u=e(31),l="Usage: algoliasearch(applicationID, apiKey, opts)";if(o._allowEmptyCredentials!==!0&&!t)throw new c.AlgoliaSearchError("Please provide an application ID. "+l);if(o._allowEmptyCredentials!==!0&&!r)throw new c.AlgoliaSearchError("Please provide an API key. "+l);this.applicationID=t,this.apiKey=r,this.hosts={read:[],write:[]},o=o||{},this._timeouts=o.timeouts||{connect:1e3,read:2e3,write:3e4},o.timeout&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=o.timeout);var p=o.protocol||"https:";if(/:$/.test(p)||(p+=":"),"http:"!==p&&"https:"!==p)throw new c.AlgoliaSearchError("protocol must be `http:` or `https:` (was `"+o.protocol+"`)");if(this._checkAppIdData(),o.hosts)a(o.hosts)?(this.hosts.read=s(o.hosts),this.hosts.write=s(o.hosts)):(this.hosts.read=s(o.hosts.read),this.hosts.write=s(o.hosts.write));else{var d=u(this._shuffleResult,function(e){return t+"-"+e+".algolianet.com"}),h=(o.dsn===!1?"":"-dsn")+".algolia.net";this.hosts.read=[this.applicationID+h].concat(d),this.hosts.write=[this.applicationID+".algolia.net"].concat(d)}this.hosts.read=u(this.hosts.read,n(p)),this.hosts.write=u(this.hosts.write,n(p)),this.extraHeaders={},this.cache=o._cache||{},this._ua=o._ua,this._useCache=!(void 0!==o._useCache&&!o._cache)||o._useCache,this._useRequestCache=this._useCache&&o._useRequestCache,this._useFallback=void 0===o.useFallback||o.useFallback,this._setTimeout=o._setTimeout,i("init done, %j",this)}function n(e){return function(t){return e+"//"+t.toLowerCase()}}function i(e){if(void 0===Array.prototype.toJSON)return JSON.stringify(e);var t=Array.prototype.toJSON;delete Array.prototype.toJSON;var r=JSON.stringify(e);return Array.prototype.toJSON=t,r}function s(e){for(var t,r,o=e.length;0!==o;)r=Math.floor(Math.random()*o),o-=1, +t=e[o],e[o]=e[r],e[r]=t;return e}function a(e){var t={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){var o;o="x-algolia-api-key"===r||"x-algolia-application-id"===r?"**hidden for security purposes**":e[r],t[r]=o}return t}t.exports=o;var c=e(29),u=e(30),l=e(18),p=e(35),d=500,h=r.env.RESET_APP_DATA_TIMER&&parseInt(r.env.RESET_APP_DATA_TIMER,10)||12e4;o.prototype.initIndex=function(e){return new l(this,e)},o.prototype.setExtraHeader=function(e,t){this.extraHeaders[e.toLowerCase()]=t},o.prototype.getExtraHeader=function(e){return this.extraHeaders[e.toLowerCase()]},o.prototype.unsetExtraHeader=function(e){delete this.extraHeaders[e.toLowerCase()]},o.prototype.addAlgoliaAgent=function(e){this._ua.indexOf(";"+e)===-1&&(this._ua+=";"+e)},o.prototype._jsonRequest=function(t){function r(e,n){function u(e){var t=e&&e.body&&e.body.message&&e.body.status||e.statusCode||e&&e.body&&200;h("received response: statusCode: %s, computed statusCode: %d, headers: %j",e.statusCode,t,e.headers);var r=2===Math.floor(t/100),o=new Date;if(w.push({currentHost:A,headers:a(p),content:s||null,contentLength:void 0!==s?s.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:x,endTime:o,duration:o-x,statusCode:t}),r)return m._useCache&&!m._useRequestCache&&y&&(y[l]=e.responseText),{responseText:e.responseText,body:e.body};var i=4!==Math.floor(t/100);if(i)return v+=1,_();h("unrecoverable error");var u=new c.AlgoliaSearchError(e.body&&e.body.message,{debugData:w,statusCode:t});return m._promise.reject(u)}function d(e){h("error: %s, stack: %s",e.message,e.stack);var r=new Date;return w.push({currentHost:A,headers:a(p),content:s||null,contentLength:void 0!==s?s.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:x,endTime:r,duration:r-x}),e instanceof c.AlgoliaSearchError||(e=new c.Unknown(e&&e.message,e)),v+=1,e instanceof c.Unknown||e instanceof c.UnparsableJSON||v>=m.hosts[t.hostType].length&&(g||!b)?(e.debugData=w,m._promise.reject(e)):e instanceof c.RequestTimeout?T():_()}function _(){return h("retrying request"),m._incrementHostIndex(t.hostType),r(e,n)}function T(){return h("retrying request with higher timeout"),m._incrementHostIndex(t.hostType),m._incrementTimeoutMultipler(),n.timeouts=m._getTimeoutsForRequest(t.hostType),r(e,n)}m._checkAppIdData();var x=new Date;if(m._useCache&&!m._useRequestCache&&(l=t.url),m._useCache&&!m._useRequestCache&&s&&(l+="_body_"+n.body),o(!m._useRequestCache,y,l)){h("serving response from cache");var R=y[l];return m._promise.resolve({body:JSON.parse(R),responseText:R})}if(v>=m.hosts[t.hostType].length)return!b||g?(h("could not get any response"),m._promise.reject(new c.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue. Application id was: "+m.applicationID,{debugData:w}))):(h("switching to fallback"),v=0,n.method=t.fallback.method,n.url=t.fallback.url,n.jsonBody=t.fallback.body,n.jsonBody&&(n.body=i(n.jsonBody)),p=m._computeRequestHeaders({additionalUA:f,headers:t.headers}),n.timeouts=m._getTimeoutsForRequest(t.hostType),m._setHostIndexByType(0,t.hostType),g=!0,r(m._request.fallback,n));var A=m._getHostByType(t.hostType),j=A+n.url,S={body:n.body,jsonBody:n.jsonBody,method:n.method,headers:p,timeouts:n.timeouts,debug:h,forceAuthHeaders:n.forceAuthHeaders};return h("method: %s, url: %s, headers: %j, timeouts: %d",S.method,j,S.headers,S.timeouts),e===m._request.fallback&&h("using fallback"),e.call(m,j,S).then(u,d)}function o(e,t,r){return m._useCache&&e&&t&&void 0!==t[r]}function n(e,r){return o(m._useRequestCache,y,l)&&e["catch"](function(){delete y[l]}),"function"!=typeof t.callback?e.then(r):void e.then(function(e){u(function(){t.callback(null,r(e))},m._setTimeout||setTimeout)},function(e){u(function(){t.callback(e)},m._setTimeout||setTimeout)})}this._checkAppIdData();var s,l,p,h=e(1)("algoliasearch:"+t.url),f=t.additionalUA||"",y=t.cache,m=this,v=0,g=!1,b=m._useFallback&&m._request.fallback&&t.fallback;this.apiKey.length>d&&void 0!==t.body&&(void 0!==t.body.params||void 0!==t.body.requests)?(t.body.apiKey=this.apiKey,p=this._computeRequestHeaders({additionalUA:f,withApiKey:!1,headers:t.headers})):p=this._computeRequestHeaders({additionalUA:f,headers:t.headers}),void 0!==t.body&&(s=i(t.body)),h("request start");var w=[];if(m._useCache&&m._useRequestCache&&(l=t.url),m._useCache&&m._useRequestCache&&s&&(l+="_body_"+s),o(m._useRequestCache,y,l)){h("serving request from cache");var _=y[l],T="function"!=typeof _.then?m._promise.resolve({responseText:_}):_;return n(T,function(e){return JSON.parse(e.responseText)})}var x=r(m._request,{url:t.url,method:t.method,body:s,jsonBody:t.body,timeouts:m._getTimeoutsForRequest(t.hostType),forceAuthHeaders:t.forceAuthHeaders});return m._useCache&&m._useRequestCache&&y&&(y[l]=x),n(x,function(e){return e.body})},o.prototype._getSearchParams=function(e,t){if(void 0===e||null===e)return t;for(var r in e)null!==r&&void 0!==e[r]&&e.hasOwnProperty(r)&&(t+=""===t?"":"&",t+=r+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(e[r])?i(e[r]):e[r]));return t},o.prototype._computeRequestHeaders=function(t){var r=e(5),o=t.additionalUA?this._ua+";"+t.additionalUA:this._ua,n={"x-algolia-agent":o,"x-algolia-application-id":this.applicationID};return t.withApiKey!==!1&&(n["x-algolia-api-key"]=this.apiKey),this.userToken&&(n["x-algolia-usertoken"]=this.userToken),this.securityTags&&(n["x-algolia-tagfilters"]=this.securityTags),r(this.extraHeaders,function(e,t){n[t]=e}),t.headers&&r(t.headers,function(e,t){n[t]=e}),n},o.prototype.search=function(t,r,o){var n=e(8),i=e(31),s="Usage: client.search(arrayOfQueries[, callback])";if(!n(t))throw new Error(s);"function"==typeof r?(o=r,r={}):void 0===r&&(r={});var a=this,c={requests:i(t,function(e){var t="";return void 0!==e.query&&(t+="query="+encodeURIComponent(e.query)),{indexName:e.indexName,params:a._getSearchParams(e.params,t)}})},u=i(c.requests,function(e,t){return t+"="+encodeURIComponent("/1/indexes/"+encodeURIComponent(e.indexName)+"?"+e.params)}).join("&"),l="/1/indexes/*/queries";return void 0!==r.strategy&&(c.strategy=r.strategy),this._jsonRequest({cache:this.cache,method:"POST",url:l,body:c,hostType:"read",fallback:{method:"GET",url:"/1/indexes/*",body:{params:u}},callback:o})},o.prototype.searchForFacetValues=function(t){var r=e(8),o=e(31),n="Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])";if(!r(t))throw new Error(n);var i=this;return i._promise.all(o(t,function(t){if(!t||void 0===t.indexName||void 0===t.params.facetName||void 0===t.params.facetQuery)throw new Error(n);var r=e(25),o=e(33),s=t.indexName,a=t.params,c=a.facetName,u=o(r(a),function(e){return"facetName"===e}),l=i._getSearchParams(u,"");return i._jsonRequest({cache:i.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(s)+"/facets/"+encodeURIComponent(c)+"/query",hostType:"read",body:{params:l}})}))},o.prototype.setSecurityTags=function(e){if("[object Array]"===Object.prototype.toString.call(e)){for(var t=[],r=0;r<e.length;++r)if("[object Array]"===Object.prototype.toString.call(e[r])){for(var o=[],n=0;n<e[r].length;++n)o.push(e[r][n]);t.push("("+o.join(",")+")")}else t.push(e[r]);e=t.join(",")}this.securityTags=e},o.prototype.setUserToken=function(e){this.userToken=e},o.prototype.clearCache=function(){this.cache={}},o.prototype.setRequestTimeout=function(e){e&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=e)},o.prototype.setTimeouts=function(e){this._timeouts=e},o.prototype.getTimeouts=function(){return this._timeouts},o.prototype._getAppIdData=function(){var e=p.get(this.applicationID);return null!==e&&this._cacheAppIdData(e),e},o.prototype._setAppIdData=function(e){return e.lastChange=(new Date).getTime(),this._cacheAppIdData(e),p.set(this.applicationID,e)},o.prototype._checkAppIdData=function(){var e=this._getAppIdData(),t=(new Date).getTime();return null===e||t-e.lastChange>h?this._resetInitialAppIdData(e):e},o.prototype._resetInitialAppIdData=function(e){var t=e||{};return t.hostIndexes={read:0,write:0},t.timeoutMultiplier=1,t.shuffleResult=t.shuffleResult||s([1,2,3]),this._setAppIdData(t)},o.prototype._cacheAppIdData=function(e){this._hostIndexes=e.hostIndexes,this._timeoutMultiplier=e.timeoutMultiplier,this._shuffleResult=e.shuffleResult},o.prototype._partialAppIdDataUpdate=function(t){var r=e(5),o=this._getAppIdData();return r(t,function(e,t){o[t]=e}),this._setAppIdData(o)},o.prototype._getHostByType=function(e){return this.hosts[e][this._getHostIndexByType(e)]},o.prototype._getTimeoutMultiplier=function(){return this._timeoutMultiplier},o.prototype._getHostIndexByType=function(e){return this._hostIndexes[e]},o.prototype._setHostIndexByType=function(t,r){var o=e(25),n=o(this._hostIndexes);return n[r]=t,this._partialAppIdDataUpdate({hostIndexes:n}),t},o.prototype._incrementHostIndex=function(e){return this._setHostIndexByType((this._getHostIndexByType(e)+1)%this.hosts[e].length,e)},o.prototype._incrementTimeoutMultipler=function(){var e=Math.max(this._timeoutMultiplier+1,4);return this._partialAppIdDataUpdate({timeoutMultiplier:e})},o.prototype._getTimeoutsForRequest=function(e){return{connect:this._timeouts.connect*this._timeoutMultiplier,complete:this._timeouts[e]*this._timeoutMultiplier}}}).call(this,e(12))},{1:1,12:12,18:18,25:25,29:29,30:30,31:31,33:33,35:35,5:5,8:8}],16:[function(e,t,r){function o(){s.apply(this,arguments)}function n(e,t,r){function o(r,n){var i={page:r||0,hitsPerPage:t||100},s=n||[];return e(i).then(function(e){var t=e.hits,r=e.nbHits,n=t.map(function(e){return delete e._highlightResult,e}),a=s.concat(n);return a.length<r?o(i.page+1,a):a})}return o().then(function(e){return"function"==typeof r?void r(e):e})}var i=e(7),s=e(18),a=e(27),c=e(28),u=e(30),l=e(29),p=a(function(){},c("forwardToSlaves","forwardToReplicas"));t.exports=o,i(o,s),o.prototype.addObject=function(e,t,r){var o=this;return 1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0),this.as._jsonRequest({method:void 0!==t?"PUT":"POST",url:"/1/indexes/"+encodeURIComponent(o.indexName)+(void 0!==t?"/"+encodeURIComponent(t):""),body:e,hostType:"write",callback:r})},o.prototype.addObjects=function(t,r){var o=e(8),n="Usage: index.addObjects(arrayOfObjects[, callback])";if(!o(t))throw new Error(n);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"addObject",body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},o.prototype.partialUpdateObject=function(e,t,r){1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var o=this,n="/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e.objectID)+"/partial";return t===!1&&(n+="?createIfNotExists=false"),this.as._jsonRequest({method:"POST",url:n,body:e,hostType:"write",callback:r})},o.prototype.partialUpdateObjects=function(t,r,o){1!==arguments.length&&"function"!=typeof r||(o=r,r=!0);var n=e(8),i="Usage: index.partialUpdateObjects(arrayOfObjects[, callback])";if(!n(t))throw new Error(i);for(var s=this,a={requests:[]},c=0;c<t.length;++c){var u={action:r===!0?"partialUpdateObject":"partialUpdateObjectNoCreate",objectID:t[c].objectID,body:t[c]};a.requests.push(u)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(s.indexName)+"/batch",body:a,hostType:"write",callback:o})},o.prototype.saveObject=function(e,t){var r=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/"+encodeURIComponent(e.objectID),body:e,hostType:"write",callback:t})},o.prototype.saveObjects=function(t,r){var o=e(8),n="Usage: index.saveObjects(arrayOfObjects[, callback])";if(!o(t))throw new Error(n);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"updateObject",objectID:t[a].objectID,body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},o.prototype.deleteObject=function(e,t){if("function"==typeof e||"string"!=typeof e&&"number"!=typeof e){var r=new l.AlgoliaSearchError(e&&"function"!=typeof e?"ObjectID must be a string":"Cannot delete an object without an objectID");return t=e,"function"==typeof t?t(r):this.as._promise.reject(r)}var o=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e),hostType:"write",callback:t})},o.prototype.deleteObjects=function(t,r){var o=e(8),n=e(31),i="Usage: index.deleteObjects(arrayOfObjectIDs[, callback])";if(!o(t))throw new Error(i);var s=this,a={requests:n(t,function(e){return{action:"deleteObject",objectID:e,body:{objectID:e}}})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(s.indexName)+"/batch",body:a,hostType:"write",callback:r})},o.prototype.deleteByQuery=a(function(t,r,o){function n(e){if(0===e.nbHits)return e;var t=p(e.hits,function(e){return e.objectID});return d.deleteObjects(t).then(i).then(s)}function i(e){return d.waitTask(e.taskID)}function s(){return d.deleteByQuery(t,r)}function a(){u(function(){o(null)},h._setTimeout||setTimeout)}function c(e){u(function(){o(e)},h._setTimeout||setTimeout)}var l=e(25),p=e(31),d=this,h=d.as;1===arguments.length||"function"==typeof r?(o=r,r={}):r=l(r),r.attributesToRetrieve="objectID",r.hitsPerPage=1e3,r.distinct=!1,this.clearCache();var f=this.search(t,r).then(n);return o?void f.then(a,c):f},c("index.deleteByQuery()","index.deleteBy()")),o.prototype.deleteBy=function(e,t){var r=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/deleteByQuery",body:{params:r.as._getSearchParams(e,"")},hostType:"write",callback:t})},o.prototype.browseAll=function(t,r){function o(e){if(!a._stopped){var t;t=void 0!==e?{cursor:e}:{params:l},c._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(u.indexName)+"/browse",hostType:"read",body:t,callback:n})}}function n(e,t){if(!a._stopped)return e?void a._error(e):(a._result(t),void 0===t.cursor?void a._end():void o(t.cursor))}"object"==typeof t&&(r=t,t=void 0);var i=e(32),s=e(17),a=new s,c=this.as,u=this,l=c._getSearchParams(i({},r||{},{query:t}),"");return o(),a},o.prototype.ttAdapter=a(function(e){var t=this;return function(r,o,n){var i;i="function"==typeof n?n:o,t.search(r,e,function(e,t){return e?void i(e):void i(t.hits)})}},"ttAdapter is not necessary anymore and will be removed in the next version,\nhave a look at autocomplete.js (https://github.com/algolia/autocomplete.js)"),o.prototype.waitTask=function(e,t){function r(){return l._jsonRequest({method:"GET",hostType:"read",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/task/"+e}).then(function(e){a++;var t=i*a*a;return t>s&&(t=s),"published"!==e.status?l._promise.delay(t).then(r):e})}function o(e){u(function(){t(null,e)},l._setTimeout||setTimeout)}function n(e){u(function(){t(e)},l._setTimeout||setTimeout)}var i=100,s=5e3,a=0,c=this,l=c.as,p=r();return t?void p.then(o,n):p},o.prototype.clearIndex=function(e){var t=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/clear",hostType:"write",callback:e})},o.prototype.getSettings=function(e,t){1===arguments.length&&"function"==typeof e&&(t=e,e={}),e=e||{};var r=encodeURIComponent(this.indexName);return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+r+"/settings?getVersion=2"+(e.advanced?"&advanced="+e.advanced:""),hostType:"read",callback:t})},o.prototype.searchSynonyms=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/search",body:e,hostType:"read",callback:t})},o.prototype.exportSynonyms=function(e,t){return n(this.searchSynonyms.bind(this),e,t)},o.prototype.saveSynonym=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e.objectID)+"?forwardToReplicas="+o,body:e,hostType:"write",callback:r})},o.prototype.getSynonym=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e),hostType:"read",callback:t})},o.prototype.deleteSynonym=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e)+"?forwardToReplicas="+o,hostType:"write",callback:r})},o.prototype.clearSynonyms=function(e,t){"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),void 0!==e.forwardToSlaves&&p();var r=e.forwardToSlaves||e.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/clear?forwardToReplicas="+r,hostType:"write",callback:t})},o.prototype.batchSynonyms=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/batch?forwardToReplicas="+o+"&replaceExistingSynonyms="+(t.replaceExistingSynonyms?"true":"false"),hostType:"write",body:e,callback:r})},o.prototype.searchRules=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/search",body:e,hostType:"read",callback:t})},o.prototype.exportRules=function(e,t){return n(this.searchRules.bind(this),e,t)},o.prototype.saveRule=function(e,t,r){if("function"==typeof t?(r=t,t={}):void 0===t&&(t={}),!e.objectID)throw new l.AlgoliaSearchError("Missing or empty objectID field for rule");var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e.objectID)+"?forwardToReplicas="+o,body:e,hostType:"write",callback:r})},o.prototype.getRule=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e),hostType:"read",callback:t})},o.prototype.deleteRule=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={});var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e)+"?forwardToReplicas="+o,hostType:"write",callback:r})},o.prototype.clearRules=function(e,t){"function"==typeof e?(t=e,e={}):void 0===e&&(e={});var r=e.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/clear?forwardToReplicas="+r,hostType:"write",callback:t})},o.prototype.batchRules=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={});var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/batch?forwardToReplicas="+o+"&clearExistingRules="+(t.clearExistingRules===!0?"true":"false"),hostType:"write",body:e,callback:r})},o.prototype.setSettings=function(e,t,r){1!==arguments.length&&"function"!=typeof t||(r=t,t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false",n=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/settings?forwardToReplicas="+o,hostType:"write",body:e,callback:r})},o.prototype.listUserKeys=a(function(e){return this.listApiKeys(e)},c("index.listUserKeys()","client.listApiKeys()")),o.prototype.listApiKeys=a(function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/keys",hostType:"read",callback:e})},c("index.listApiKeys()","client.listApiKeys()")),o.prototype.getUserKeyACL=a(function(e,t){return this.getApiKey(e,t)},c("index.getUserKeyACL()","client.getApiKey()")),o.prototype.getApiKey=a(function(e,t){var r=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/keys/"+e,hostType:"read",callback:t})},c("index.getApiKey()","client.getApiKey()")),o.prototype.deleteUserKey=a(function(e,t){return this.deleteApiKey(e,t)},c("index.deleteUserKey()","client.deleteApiKey()")),o.prototype.deleteApiKey=a(function(e,t){var r=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/keys/"+e,hostType:"write",callback:t})},c("index.deleteApiKey()","client.deleteApiKey()")),o.prototype.addUserKey=a(function(e,t,r){return this.addApiKey(e,t,r)},c("index.addUserKey()","client.addApiKey()")),o.prototype.addApiKey=a(function(t,r,o){var n=e(8),i="Usage: index.addApiKey(arrayOfAcls[, params, callback])";if(!n(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.description=r.description,r.queryParameters&&(s.queryParameters=this.as._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",body:s,hostType:"write",callback:o})},c("index.addApiKey()","client.addApiKey()")),o.prototype.addUserKeyWithValidity=a(function(e,t,r){return this.addApiKey(e,t,r)},c("index.addUserKeyWithValidity()","client.addApiKey()")),o.prototype.updateUserKey=a(function(e,t,r,o){return this.updateApiKey(e,t,r,o)},c("index.updateUserKey()","client.updateApiKey()")),o.prototype.updateApiKey=a(function(t,r,o,n){var i=e(8),s="Usage: index.updateApiKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof o||(n=o,o=null);var a={acl:r};return o&&(a.validity=o.validity,a.maxQueriesPerIPPerHour=o.maxQueriesPerIPPerHour,a.maxHitsPerQuery=o.maxHitsPerQuery,a.description=o.description,o.queryParameters&&(a.queryParameters=this.as._getSearchParams(o.queryParameters,"")),a.referers=o.referers),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+t,body:a,hostType:"write",callback:n})},c("index.updateApiKey()","client.updateApiKey()"))},{17:17,18:18,25:25,27:27,28:28,29:29,30:30,31:31,32:32,7:7,8:8}],17:[function(e,t,r){"use strict";function o(){}t.exports=o;var n=e(7),i=e(4).EventEmitter;n(o,i),o.prototype.stop=function(){this._stopped=!0,this._clean()},o.prototype._end=function(){this.emit("end"),this._clean()},o.prototype._error=function(e){this.emit("error",e),this._clean()},o.prototype._result=function(e){this.emit("result",e)},o.prototype._clean=function(){this.removeAllListeners("stop"),this.removeAllListeners("end"),this.removeAllListeners("error"),this.removeAllListeners("result")}},{4:4,7:7}],18:[function(e,t,r){function o(e,t){this.indexName=t,this.as=e,this.typeAheadArgs=null,this.typeAheadValueOption=null,this.cache={}}var n=e(24),i=e(27),s=e(28);t.exports=o,o.prototype.clearCache=function(){this.cache={}},o.prototype.search=n("query"),o.prototype.similarSearch=n("similarQuery"),o.prototype.browse=function(t,r,o){var n,i,s=e(32),a=this;0===arguments.length||1===arguments.length&&"function"==typeof arguments[0]?(n=0,o=arguments[0],t=void 0):"number"==typeof arguments[0]?(n=arguments[0],"number"==typeof arguments[1]?i=arguments[1]:"function"==typeof arguments[1]&&(o=arguments[1],i=void 0),t=void 0,r=void 0):"object"==typeof arguments[0]?("function"==typeof arguments[1]&&(o=arguments[1]),r=arguments[0],t=void 0):"string"==typeof arguments[0]&&"function"==typeof arguments[1]&&(o=arguments[1],r=void 0),r=s({},r||{},{page:n,hitsPerPage:i,query:t});var c=this.as._getSearchParams(r,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a.indexName)+"/browse",body:{params:c},hostType:"read",callback:o})},o.prototype.browseFrom=function(e,t){return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/browse",body:{cursor:e},hostType:"read",callback:t})},o.prototype.searchForFacetValues=function(t,r){var o=e(25),n=e(33),i="Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])";if(void 0===t.facetName||void 0===t.facetQuery)throw new Error(i);var s=t.facetName,a=n(o(t),function(e){return"facetName"===e}),c=this.as._getSearchParams(a,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/facets/"+encodeURIComponent(s)+"/query",hostType:"read",body:{params:c},callback:r})},o.prototype.searchFacet=i(function(e,t){return this.searchForFacetValues(e,t)},s("index.searchFacet(params[, callback])","index.searchForFacetValues(params[, callback])")),o.prototype._search=function(e,t,r,o){return this.as._jsonRequest({cache:this.cache,method:"POST",url:t||"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:e},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:e}},callback:r,additionalUA:o})},o.prototype.getObject=function(e,t,r){var o=this;1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var n="";if(void 0!==t){n="?attributes=";for(var i=0;i<t.length;++i)0!==i&&(n+=","),n+=t[i]}return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e)+n,hostType:"read",callback:r})},o.prototype.getObjects=function(t,r,o){var n=e(8),i=e(31),s="Usage: index.getObjects(arrayOfObjectIDs[, callback])";if(!n(t))throw new Error(s);var a=this;1!==arguments.length&&"function"!=typeof r||(o=r,r=void 0);var c={requests:i(t,function(e){var t={indexName:a.indexName,objectID:e};return r&&(t.attributesToRetrieve=r.join(",")),t})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/*/objects",hostType:"read",body:c,callback:o})},o.prototype.as=null,o.prototype.indexName=null,o.prototype.typeAheadArgs=null,o.prototype.typeAheadValueOption=null},{24:24,25:25,27:27,28:28,31:31,32:32,33:33,8:8}],19:[function(e,t,r){(function(t){"use strict";var r=e(7),o=e(5),n=e(14),i=e(29),s=e(22),a=e(23),c=e(34);window.algoliasearch=e(20),"debug"===t.env.NODE_ENV&&e(1).enable("algoliasearch*"),window.angular.module("algoliasearch",[]).service("algolia",["$http","$q","$timeout",function(t,u,l){function p(t,r,o){var n=e(25);return o=n(o||{}),o._ua=o._ua||p.ua,new d(t,r,o)}function d(){n.apply(this,arguments)}return p.version=e(36),p.ua="Algolia for AngularJS "+p.version,p.initPlaces=c(p),window.__algolia={debug:e(1),algoliasearch:p},r(d,n),d.prototype._request=function(e,r){function n(e){h({statusCode:e.status,headers:e.headers,body:JSON.parse(e.data),responseText:e.data})}function a(e){return e}function c(e){if(!p)return 0===e.status?void f(new i.Network({more:e})):void h({body:JSON.parse(e.data),statusCode:e.status})}var p,d=u.defer(),h=d.resolve,f=d.reject,y=r.body;e=s(e,r.headers);var m=u.defer(),v=m.promise;l(function(){p=!0,m.resolve("test"),f(new i.RequestTimeout)},r.timeouts.complete);var g={};return o(t.defaults.headers.common,function(e,t){g[t]=void 0}),g.accept="application/json",y&&("POST"===r.method?g["content-type"]="application/x-www-form-urlencoded":g["content-type"]="application/json"),t({url:e,method:r.method,data:y,cache:!1,timeout:v,headers:g,transformResponse:a,withCredentials:!1}).then(n,c),d.promise},d.prototype._request.fallback=function(e,t){e=s(e,t.headers);var r=u.defer(),o=r.resolve,n=r.reject;return a(e,t,function(e,t){return e?void n(e):void o(t)}),r.promise},d.prototype._promise={reject:function(e){return u.reject(e)},resolve:function(e){return u.when(e)},delay:function(e){var t=u.defer(),r=t.resolve;return l(r,e),t.promise},all:function(e){return u.all(e)}},{Client:function(e,t,r){return p(e,t,r)},ua:p.ua,version:p.version}}])}).call(this,e(12))},{1:1,12:12,14:14,20:20,22:22,23:23,25:25,29:29,34:34,36:36,5:5,7:7}],20:[function(e,t,r){"use strict";var o=e(14),n=e(21);t.exports=n(o)},{14:14,21:21}],21:[function(e,t,r){(function(r){"use strict";var o=e(6),n=o.Promise||e(3).Promise;t.exports=function(t,i){function s(t,r,o){var n=e(25);return o=n(o||{}),o._ua=o._ua||s.ua,new a(t,r,o)}function a(){t.apply(this,arguments)}var c=e(7),u=e(29),l=e(22),p=e(23),d=e(34);i=i||"","debug"===r.env.NODE_ENV&&e(1).enable("algoliasearch*"),s.version=e(36),s.ua="Algolia for vanilla JavaScript "+i+s.version,s.initPlaces=d(s),o.__algolia={debug:e(1),algoliasearch:s};var h={hasXMLHttpRequest:"XMLHttpRequest"in o,hasXDomainRequest:"XDomainRequest"in o};return h.hasXMLHttpRequest&&(h.cors="withCredentials"in new XMLHttpRequest),c(a,t),a.prototype._request=function(e,t){return new n(function(r,o){function n(){if(!f){clearTimeout(d);var e;try{e={body:JSON.parse(m.responseText),responseText:m.responseText,statusCode:m.status,headers:m.getAllResponseHeaders&&m.getAllResponseHeaders()||{}}}catch(t){e=new u.UnparsableJSON({more:m.responseText})}e instanceof u.UnparsableJSON?o(e):r(e)}}function i(e){f||(clearTimeout(d),o(new u.Network({more:e})))}function s(){f=!0,m.abort(),o(new u.RequestTimeout)}function a(){v=!0,clearTimeout(d),d=setTimeout(s,t.timeouts.complete)}function c(){v||a()}function p(){!v&&m.readyState>1&&a()}if(!h.cors&&!h.hasXDomainRequest)return void o(new u.Network("CORS not supported"));e=l(e,t.headers);var d,f,y=t.body,m=h.cors?new XMLHttpRequest:new XDomainRequest,v=!1;d=setTimeout(s,t.timeouts.connect),m.onprogress=c,"onreadystatechange"in m&&(m.onreadystatechange=p),m.onload=n,m.onerror=i,m instanceof XMLHttpRequest?(m.open(t.method,e,!0),t.forceAuthHeaders&&(m.setRequestHeader("x-algolia-application-id",t.headers["x-algolia-application-id"]),m.setRequestHeader("x-algolia-api-key",t.headers["x-algolia-api-key"]))):m.open(t.method,e),h.cors&&(y&&("POST"===t.method?m.setRequestHeader("content-type","application/x-www-form-urlencoded"):m.setRequestHeader("content-type","application/json")),m.setRequestHeader("accept","application/json")),y?m.send(y):m.send()})},a.prototype._request.fallback=function(e,t){return e=l(e,t.headers),new n(function(r,o){p(e,t,function(e,t){return e?void o(e):void r(t)})})},a.prototype._promise={reject:function(e){return n.reject(e)},resolve:function(e){return n.resolve(e)},delay:function(e){return new n(function(t){setTimeout(t,e)})},all:function(e){return n.all(e)}},s}}).call(this,e(12))},{1:1,12:12,22:22,23:23,25:25,29:29,3:3,34:34,36:36,6:6,7:7}],22:[function(e,t,r){"use strict";function o(e,t){return e+=/\?/.test(e)?"&":"?",e+n(t)}t.exports=o;var n=e(13)},{13:13}],23:[function(e,t,r){"use strict";function o(e,t,r){function o(){t.debug("JSONP: success"),m||d||(m=!0,p||(t.debug("JSONP: Fail. Script loaded but did not call the callback"),a(),r(new n.JSONPScriptFail)))}function s(){"loaded"!==this.readyState&&"complete"!==this.readyState||o()}function a(){clearTimeout(v),f.onload=null,f.onreadystatechange=null,f.onerror=null,h.removeChild(f)}function c(){try{delete window[y],delete window[y+"_loaded"]}catch(e){window[y]=window[y+"_loaded"]=void 0}}function u(){t.debug("JSONP: Script timeout"),d=!0,a(),r(new n.RequestTimeout)}function l(){t.debug("JSONP: Script error"),m||d||(a(),r(new n.JSONPScriptError))}if("GET"!==t.method)return void r(new Error("Method "+t.method+" "+e+" is not supported by JSONP."));t.debug("JSONP: start");var p=!1,d=!1;i+=1;var h=document.getElementsByTagName("head")[0],f=document.createElement("script"),y="algoliaJSONP_"+i,m=!1;window[y]=function(e){return c(),d?void t.debug("JSONP: Late answer, ignoring"):(p=!0,a(),void r(null,{body:e,responseText:JSON.stringify(e)}))},e+="&callback="+y,t.jsonBody&&t.jsonBody.params&&(e+="&"+t.jsonBody.params); +var v=setTimeout(u,t.timeouts.complete);f.onreadystatechange=s,f.onload=o,f.onerror=l,f.async=!0,f.defer=!0,f.src=e,h.appendChild(f)}t.exports=o;var n=e(29),i=0},{29:29}],24:[function(e,t,r){function o(e,t){return function(r,o,i){if("function"==typeof r&&"object"==typeof o||"object"==typeof i)throw new n.AlgoliaSearchError("index.search usage is index.search(query, params, cb)");0===arguments.length||"function"==typeof r?(i=r,r=""):1!==arguments.length&&"function"!=typeof o||(i=o,o=void 0),"object"==typeof r&&null!==r?(o=r,r=void 0):void 0!==r&&null!==r||(r="");var s="";void 0!==r&&(s+=e+"="+encodeURIComponent(r));var a;return void 0!==o&&(o.additionalUA&&(a=o.additionalUA,delete o.additionalUA),s=this.as._getSearchParams(o,s)),this._search(s,t,i,a)}}t.exports=o;var n=e(29)},{29:29}],25:[function(e,t,r){t.exports=function(e){return JSON.parse(JSON.stringify(e))}},{}],26:[function(e,t,r){function o(e,t,r){var o={};return r=r||{},r.hosts=r.hosts||["analytics.algolia.com","analytics.algolia.com","analytics.algolia.com","analytics.algolia.com"],r.protocol=r.protocol||"https:",o.as=n(e,t,r),o.getABTests=function(e,t){var r=r||{},o=r.offset||0,n=r.limit||10;return this.as._jsonRequest({method:"GET",url:"/2/abtests?offset="+encodeURIComponent(o)+"&limit="+encodeURIComponent(n),hostType:"read",forceAuthHeaders:!0,callback:t})},o.getABTest=function(e,t){return this.as._jsonRequest({method:"GET",url:"/2/abtests/"+encodeURIComponent(e),hostType:"read",forceAuthHeaders:!0,callback:t})},o.addABTest=function(e,t){return this.as._jsonRequest({method:"POST",url:"/2/abtests",body:e,hostType:"read",forceAuthHeaders:!0,callback:t})},o.stopABTest=function(e,t){return this.as._jsonRequest({method:"POST",url:"/2/abtests/"+encodeURIComponent(e)+"/stop",hostType:"read",forceAuthHeaders:!0,callback:t})},o.deleteABTest=function(e,t){return this.as._jsonRequest({method:"DELETE",url:"/2/abtests/"+encodeURIComponent(e),hostType:"write",forceAuthHeaders:!0,callback:t})},o.waitTask=function(e,t,r){return this.as.initIndex(e).waitTask(t,r)},o}t.exports=o;var n=e(20)},{20:20}],27:[function(e,t,r){t.exports=function(e,t){function r(){return o||(console.warn(t),o=!0),e.apply(this,arguments)}var o=!1;return r}},{}],28:[function(e,t,r){t.exports=function(e,t){var r=e.toLowerCase().replace(/[\.\(\)]/g,"");return"algoliasearch: `"+e+"` was replaced by `"+t+"`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#"+r}},{}],29:[function(e,t,r){"use strict";function o(t,r){var o=e(5),n=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):n.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name="AlgoliaSearchError",this.message=t||"Unknown error",r&&o(r,function(e,t){n[t]=e})}function n(e,t){function r(){var r=Array.prototype.slice.call(arguments,0);"string"!=typeof r[0]&&r.unshift(t),o.apply(this,r),this.name="AlgoliaSearch"+e+"Error"}return i(r,o),r}var i=e(7);i(o,Error),t.exports={AlgoliaSearchError:o,UnparsableJSON:n("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:n("RequestTimeout","Request timedout before getting a response"),Network:n("Network","Network issue, see err.more for details"),JSONPScriptFail:n("JSONPScriptFail","<script> was loaded but did not call our provided callback"),JSONPScriptError:n("JSONPScriptError","<script> unable to load due to an `error` event on it"),Unknown:n("Unknown","Unknown error occured")}},{5:5,7:7}],30:[function(e,t,r){t.exports=function(e,t){t(e,0)}},{}],31:[function(e,t,r){var o=e(5);t.exports=function(e,t){var r=[];return o(e,function(o,n){r.push(t(o,n,e))}),r}},{5:5}],32:[function(e,t,r){var o=e(5);t.exports=function n(e){var t=Array.prototype.slice.call(arguments);return o(t,function(t){for(var r in t)t.hasOwnProperty(r)&&("object"==typeof e[r]&&"object"==typeof t[r]?e[r]=n({},e[r],t[r]):void 0!==t[r]&&(e[r]=t[r]))}),e}},{5:5}],33:[function(e,t,r){t.exports=function(t,r){var o=e(10),n=e(5),i={};return n(o(t),function(e){r(e)!==!0&&(i[e]=t[e])}),i}},{10:10,5:5}],34:[function(e,t,r){function o(t){return function(r,o,i){var s=e(25);i=i&&s(i)||{},i.hosts=i.hosts||["places-dsn.algolia.net","places-1.algolianet.com","places-2.algolianet.com","places-3.algolianet.com"],0!==arguments.length&&"object"!=typeof r&&void 0!==r||(r="",o="",i._allowEmptyCredentials=!0);var a=t(r,o,i),c=a.initIndex("places");return c.search=n("query","/1/places/query"),c.getObject=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/places/"+encodeURIComponent(e),hostType:"read",callback:t})},c}}t.exports=o;var n=e(24)},{24:24,25:25}],35:[function(e,t,r){(function(r){function o(e,t){return c("localStorage failed with",t),s(),a=l,a.get(e)}function n(e,t){return 1===arguments.length?a.get(e):a.set(e,t)}function i(){try{return"localStorage"in r&&null!==r.localStorage&&(r.localStorage[u]||r.localStorage.setItem(u,JSON.stringify({})),!0)}catch(e){return!1}}function s(){try{r.localStorage.removeItem(u)}catch(e){}}var a,c=e(1)("algoliasearch:src/hostIndexState.js"),u="algoliasearch-client-js",l={state:{},set:function(e,t){return this.state[e]=t,this.state[e]},get:function(e){return this.state[e]||null}},p={set:function(e,t){l.set(e,t);try{var n=JSON.parse(r.localStorage[u]);return n[e]=t,r.localStorage[u]=JSON.stringify(n),n[e]}catch(i){return o(e,i)}},get:function(e){try{return JSON.parse(r.localStorage[u])[e]||null}catch(t){return o(e,t)}}};a=i()?p:l,t.exports={get:n,set:n,supportsLocalStorage:i}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],36:[function(e,t,r){"use strict";t.exports="3.30.0"},{}]},{},[19]); diff --git a/node_modules/algoliasearch/dist/algoliasearch.jquery.js b/node_modules/algoliasearch/dist/algoliasearch.jquery.js new file mode 100644 index 00000000..421585b4 --- /dev/null +++ b/node_modules/algoliasearch/dist/algoliasearch.jquery.js @@ -0,0 +1,7034 @@ +/*! algoliasearch 3.30.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +(function(f){var g;if(typeof window!=='undefined'){g=window}else if(typeof self!=='undefined'){g=self}g.ALGOLIA_MIGRATION_LAYER=f()})(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){ + +module.exports = function load (src, opts, cb) { + var head = document.head || document.getElementsByTagName('head')[0] + var script = document.createElement('script') + + if (typeof opts === 'function') { + cb = opts + opts = {} + } + + opts = opts || {} + cb = cb || function() {} + + script.type = opts.type || 'text/javascript' + script.charset = opts.charset || 'utf8'; + script.async = 'async' in opts ? !!opts.async : true + script.src = src + + if (opts.attrs) { + setAttributes(script, opts.attrs) + } + + if (opts.text) { + script.text = '' + opts.text + } + + var onend = 'onload' in script ? stdOnEnd : ieOnEnd + onend(script, cb) + + // some good legacy browsers (firefox) fail the 'in' detection above + // so as a fallback we always set onload + // old IE will ignore this and new IE will set onload + if (!script.onload) { + stdOnEnd(script, cb); + } + + head.appendChild(script) +} + +function setAttributes(script, attrs) { + for (var attr in attrs) { + script.setAttribute(attr, attrs[attr]); + } +} + +function stdOnEnd (script, cb) { + script.onload = function () { + this.onerror = this.onload = null + cb(null, script) + } + script.onerror = function () { + // this.onload = null here is necessary + // because even IE9 works not like others + this.onerror = this.onload = null + cb(new Error('Failed to load ' + this.src), script) + } +} + +function ieOnEnd (script, cb) { + script.onreadystatechange = function () { + if (this.readyState != 'complete' && this.readyState != 'loaded') return + this.onreadystatechange = null + cb(null, script) // there is no way to catch loading errors in IE8 + } +} + +},{}],2:[function(require,module,exports){ +'use strict'; + +// this module helps finding if the current page is using +// the cdn.jsdelivr.net/algoliasearch/latest/$BUILDNAME.min.js version + +module.exports = isUsingLatest; + +function isUsingLatest(buildName) { + var toFind = new RegExp('cdn\\.jsdelivr\\.net/algoliasearch/latest/' + + buildName.replace('.', '\\.') + // algoliasearch, algoliasearch.angular + '(?:\\.min)?\\.js$'); // [.min].js + + var scripts = document.getElementsByTagName('script'); + var found = false; + for (var currentScript = 0, nbScripts = scripts.length; currentScript < nbScripts; currentScript++) { + if (scripts[currentScript].src && toFind.test(scripts[currentScript].src)) { + found = true; + break; + } + } + + return found; +} + +},{}],3:[function(require,module,exports){ +'use strict'; + +module.exports = loadV2; + +function loadV2(buildName) { + var loadScript = require(1); + var v2ScriptUrl = '//cdn.jsdelivr.net/algoliasearch/2/' + buildName + '.min.js'; + + var message = '-- AlgoliaSearch `latest` warning --\n' + + 'Warning, you are using the `latest` version string from jsDelivr to load the AlgoliaSearch library.\n' + + 'Using `latest` is no more recommended, you should load //cdn.jsdelivr.net/algoliasearch/2/algoliasearch.min.js\n\n' + + 'Also, we updated the AlgoliaSearch JavaScript client to V3. If you want to upgrade,\n' + + 'please read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n' + + '-- /AlgoliaSearch `latest` warning --'; + + if (window.console) { + if (window.console.warn) { + window.console.warn(message); + } else if (window.console.log) { + window.console.log(message); + } + } + + // If current script loaded asynchronously, + // it will load the script with DOMElement + // otherwise, it will load the script with document.write + try { + // why \x3c? http://stackoverflow.com/a/236106/147079 + document.write('\x3Cscript>window.ALGOLIA_SUPPORTS_DOCWRITE = true\x3C/script>'); + + if (window.ALGOLIA_SUPPORTS_DOCWRITE === true) { + document.write('\x3Cscript src="' + v2ScriptUrl + '">\x3C/script>'); + scriptLoaded('document.write')(); + } else { + loadScript(v2ScriptUrl, scriptLoaded('DOMElement')); + } + } catch (e) { + loadScript(v2ScriptUrl, scriptLoaded('DOMElement')); + } +} + +function scriptLoaded(method) { + return function log() { + var message = 'AlgoliaSearch: loaded V2 script using ' + method; + + if (window.console && window.console.log) { + window.console.log(message); + } + }; +} + +},{"1":1}],4:[function(require,module,exports){ +'use strict'; + +/* eslint no-unused-vars: [2, {"vars": "local"}] */ + +module.exports = oldGlobals; + +// put old window.AlgoliaSearch.. into window. again so that +// users upgrading to V3 without changing their code, will be warned +function oldGlobals() { + var message = '-- AlgoliaSearch V2 => V3 error --\n' + + 'You are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\n' + + 'Please read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n' + + '-- /AlgoliaSearch V2 => V3 error --'; + + window.AlgoliaSearch = function() { + throw new Error(message); + }; + + window.AlgoliaSearchHelper = function() { + throw new Error(message); + }; + + window.AlgoliaExplainResults = function() { + throw new Error(message); + }; +} + +},{}],5:[function(require,module,exports){ +'use strict'; + +// This script will be browserified and prepended to the normal build +// directly in window, not wrapped in any module definition +// To avoid cases where we are loaded with /latest/ along with +migrationLayer("algoliasearch.jquery"); + +// Now onto the V2 related code: +// If the client is using /latest/$BUILDNAME.min.js, load V2 of the library +// +// Otherwise, setup a migration layer that will throw on old constructors like +// new AlgoliaSearch(). +// So that users upgrading from v2 to v3 will have a clear information +// message on what to do if they did not read the migration guide +function migrationLayer(buildName) { + var isUsingLatest = require(2); + var loadV2 = require(3); + var oldGlobals = require(4); + + if (isUsingLatest(buildName)) { + loadV2(buildName); + } else { + oldGlobals(); + } +} + +},{"2":2,"3":3,"4":4}]},{},[5])(5) +});(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){ +(function (process){ +/** + * This is the web browser implementation of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = require(2); +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); + +/** + * Colors. + */ + +exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' +]; + +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ + +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; + } + + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} + +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; + } +}; + + +/** + * Colorize log arguments if enabled. + * + * @api public + */ + +function formatArgs(args) { + var useColors = this.useColors; + + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); + + if (!useColors) return; + + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit') + + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); + + args.splice(lastC, 0, c); +} + +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ + +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); +} + +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ + +function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + + return r; +} + +/** + * Enable namespaces listed in `localStorage.debug` initially. + */ + +exports.enable(load()); + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + return window.localStorage; + } catch (e) {} +} + +}).call(this,require(12)) +},{"12":12,"2":2}],2:[function(require,module,exports){ + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = require(9); + +/** + * The currently active debug mode names, and names to skip. + */ + +exports.names = []; +exports.skips = []; + +/** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + +exports.formatters = {}; + +/** + * Previous log timestamp. + */ + +var prevTime; + +/** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ + +function selectColor(namespace) { + var hash = 0, i; + + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return exports.colors[Math.abs(hash) % exports.colors.length]; +} + +/** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + +function createDebug(namespace) { + + function debug() { + // disabled? + if (!debug.enabled) return; + + var self = debug; + + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + + args[0] = exports.coerce(args[0]); + + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); + } + + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); + + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); + + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); + + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); + } + + return debug; +} + +/** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + +function enable(namespaces) { + exports.save(namespaces); + + exports.names = []; + exports.skips = []; + + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } + } +} + +/** + * Disable debug output. + * + * @api public + */ + +function disable() { + exports.enable(''); +} + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } + } + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } + } + return false; +} + +/** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + +},{"9":9}],3:[function(require,module,exports){ +(function (process,global){ +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE + * @version 4.1.1 + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.ES6Promise = factory()); +}(this, (function () { 'use strict'; + +function objectOrFunction(x) { + var type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} + +function isFunction(x) { + return typeof x === 'function'; +} + +var _isArray = undefined; +if (Array.isArray) { + _isArray = Array.isArray; +} else { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; +} + +var isArray = _isArray; + +var len = 0; +var vertxNext = undefined; +var customSchedulerFn = undefined; + +var asap = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (customSchedulerFn) { + customSchedulerFn(flush); + } else { + scheduleFlush(); + } + } +}; + +function setScheduler(scheduleFn) { + customSchedulerFn = scheduleFn; +} + +function setAsap(asapFn) { + asap = asapFn; +} + +var browserWindow = typeof window !== 'undefined' ? window : undefined; +var browserGlobal = browserWindow || {}; +var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; +var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]'; + +// test for web worker but not in IE10 +var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; + +// node +function useNextTick() { + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // see https://github.com/cujojs/when/issues/410 for details + return function () { + return process.nextTick(flush); + }; +} + +// vertx +function useVertxTimer() { + if (typeof vertxNext !== 'undefined') { + return function () { + vertxNext(flush); + }; + } + + return useSetTimeout(); +} + +function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function () { + node.data = iterations = ++iterations % 2; + }; +} + +// web worker +function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + return channel.port2.postMessage(0); + }; +} + +function useSetTimeout() { + // Store setTimeout reference so es6-promise will be unaffected by + // other code modifying setTimeout (like sinon.useFakeTimers()) + var globalSetTimeout = setTimeout; + return function () { + return globalSetTimeout(flush, 1); + }; +} + +var queue = new Array(1000); +function flush() { + for (var i = 0; i < len; i += 2) { + var callback = queue[i]; + var arg = queue[i + 1]; + + callback(arg); + + queue[i] = undefined; + queue[i + 1] = undefined; + } + + len = 0; +} + +function attemptVertx() { + try { + var r = require; + var vertx = r('vertx'); + vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch (e) { + return useSetTimeout(); + } +} + +var scheduleFlush = undefined; +// Decide what async method to use to triggering processing of queued callbacks: +if (isNode) { + scheduleFlush = useNextTick(); +} else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); +} else if (isWorker) { + scheduleFlush = useMessageChannel(); +} else if (browserWindow === undefined && typeof require === 'function') { + scheduleFlush = attemptVertx(); +} else { + scheduleFlush = useSetTimeout(); +} + +function then(onFulfillment, onRejection) { + var _arguments = arguments; + + var parent = this; + + var child = new this.constructor(noop); + + if (child[PROMISE_ID] === undefined) { + makePromise(child); + } + + var _state = parent._state; + + if (_state) { + (function () { + var callback = _arguments[_state - 1]; + asap(function () { + return invokeCallback(_state, child, callback, parent._result); + }); + })(); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; +} + +/** + `Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` +*/ +function resolve$1(object) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop); + resolve(promise, object); + return promise; +} + +var PROMISE_ID = Math.random().toString(36).substring(16); + +function noop() {} + +var PENDING = void 0; +var FULFILLED = 1; +var REJECTED = 2; + +var GET_THEN_ERROR = new ErrorObject(); + +function selfFulfillment() { + return new TypeError("You cannot resolve a promise with itself"); +} + +function cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); +} + +function getThen(promise) { + try { + return promise.then; + } catch (error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } +} + +function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) { + try { + then$$1.call(value, fulfillmentHandler, rejectionHandler); + } catch (e) { + return e; + } +} + +function handleForeignThenable(promise, thenable, then$$1) { + asap(function (promise) { + var sealed = false; + var error = tryThen(then$$1, thenable, function (value) { + if (sealed) { + return; + } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function (reason) { + if (sealed) { + return; + } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); +} + +function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (thenable._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function (value) { + return resolve(promise, value); + }, function (reason) { + return reject(promise, reason); + }); + } +} + +function handleMaybeThenable(promise, maybeThenable, then$$1) { + if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) { + handleOwnThenable(promise, maybeThenable); + } else { + if (then$$1 === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + GET_THEN_ERROR.error = null; + } else if (then$$1 === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then$$1)) { + handleForeignThenable(promise, maybeThenable, then$$1); + } else { + fulfill(promise, maybeThenable); + } + } +} + +function resolve(promise, value) { + if (promise === value) { + reject(promise, selfFulfillment()); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value, getThen(value)); + } else { + fulfill(promise, value); + } +} + +function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); +} + +function fulfill(promise, value) { + if (promise._state !== PENDING) { + return; + } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length !== 0) { + asap(publish, promise); + } +} + +function reject(promise, reason) { + if (promise._state !== PENDING) { + return; + } + promise._state = REJECTED; + promise._result = reason; + + asap(publishRejection, promise); +} + +function subscribe(parent, child, onFulfillment, onRejection) { + var _subscribers = parent._subscribers; + var length = _subscribers.length; + + parent._onerror = null; + + _subscribers[length] = child; + _subscribers[length + FULFILLED] = onFulfillment; + _subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + asap(publish, parent); + } +} + +function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (subscribers.length === 0) { + return; + } + + var child = undefined, + callback = undefined, + detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; +} + +function ErrorObject() { + this.error = null; +} + +var TRY_CATCH_ERROR = new ErrorObject(); + +function tryCatch(callback, detail) { + try { + return callback(detail); + } catch (e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } +} + +function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value = undefined, + error = undefined, + succeeded = undefined, + failed = undefined; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value.error = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, cannotReturnOwn()); + return; + } + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } +} + +function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value) { + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch (e) { + reject(promise, e); + } +} + +var id = 0; +function nextId() { + return id++; +} + +function makePromise(promise) { + promise[PROMISE_ID] = id++; + promise._state = undefined; + promise._result = undefined; + promise._subscribers = []; +} + +function Enumerator$1(Constructor, input) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop); + + if (!this.promise[PROMISE_ID]) { + makePromise(this.promise); + } + + if (isArray(input)) { + this.length = input.length; + this._remaining = input.length; + + this._result = new Array(this.length); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(input); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, validationError()); + } +} + +function validationError() { + return new Error('Array Methods must be provided an Array'); +} + +Enumerator$1.prototype._enumerate = function (input) { + for (var i = 0; this._state === PENDING && i < input.length; i++) { + this._eachEntry(input[i], i); + } +}; + +Enumerator$1.prototype._eachEntry = function (entry, i) { + var c = this._instanceConstructor; + var resolve$$1 = c.resolve; + + if (resolve$$1 === resolve$1) { + var _then = getThen(entry); + + if (_then === then && entry._state !== PENDING) { + this._settledAt(entry._state, i, entry._result); + } else if (typeof _then !== 'function') { + this._remaining--; + this._result[i] = entry; + } else if (c === Promise$2) { + var promise = new c(noop); + handleMaybeThenable(promise, entry, _then); + this._willSettleAt(promise, i); + } else { + this._willSettleAt(new c(function (resolve$$1) { + return resolve$$1(entry); + }), i); + } + } else { + this._willSettleAt(resolve$$1(entry), i); + } +}; + +Enumerator$1.prototype._settledAt = function (state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = value; + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } +}; + +Enumerator$1.prototype._willSettleAt = function (promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function (value) { + return enumerator._settledAt(FULFILLED, i, value); + }, function (reason) { + return enumerator._settledAt(REJECTED, i, reason); + }); +}; + +/** + `Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = resolve(2); + let promise3 = resolve(3); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = reject(new Error("2")); + let promise3 = reject(new Error("3")); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static +*/ +function all$1(entries) { + return new Enumerator$1(this, entries).promise; +} + +/** + `Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. +*/ +function race$1(entries) { + /*jshint validthis:true */ + var Constructor = this; + + if (!isArray(entries)) { + return new Constructor(function (_, reject) { + return reject(new TypeError('You must pass an array to race.')); + }); + } else { + return new Constructor(function (resolve, reject) { + var length = entries.length; + for (var i = 0; i < length; i++) { + Constructor.resolve(entries[i]).then(resolve, reject); + } + }); + } +} + +/** + `Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. +*/ +function reject$1(reason) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop); + reject(promise, reason); + return promise; +} + +function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); +} + +function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); +} + +/** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + let promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + let xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {function} resolver + Useful for tooling. + @constructor +*/ +function Promise$2(resolver) { + this[PROMISE_ID] = nextId(); + this._result = this._state = undefined; + this._subscribers = []; + + if (noop !== resolver) { + typeof resolver !== 'function' && needsResolver(); + this instanceof Promise$2 ? initializePromise(this, resolver) : needsNew(); + } +} + +Promise$2.all = all$1; +Promise$2.race = race$1; +Promise$2.resolve = resolve$1; +Promise$2.reject = reject$1; +Promise$2._setScheduler = setScheduler; +Promise$2._setAsap = setAsap; +Promise$2._asap = asap; + +Promise$2.prototype = { + constructor: Promise$2, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + let result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + let author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: then, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function _catch(onRejection) { + return this.then(null, onRejection); + } +}; + +/*global self*/ +function polyfill$1() { + var local = undefined; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } + + var P = local.Promise; + + if (P) { + var promiseToString = null; + try { + promiseToString = Object.prototype.toString.call(P.resolve()); + } catch (e) { + // silently ignored + } + + if (promiseToString === '[object Promise]' && !P.cast) { + return; + } + } + + local.Promise = Promise$2; +} + +// Strange compat.. +Promise$2.polyfill = polyfill$1; +Promise$2.Promise = Promise$2; + +return Promise$2; + +}))); + + + +}).call(this,require(12),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"12":12}],4:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); + err.context = er; + throw err; + } + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + args = Array.prototype.slice.call(arguments, 1); + handler.apply(this, args); + } + } else if (isObject(handler)) { + args = Array.prototype.slice.call(arguments, 1); + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.prototype.listenerCount = function(type) { + if (this._events) { + var evlistener = this._events[type]; + + if (isFunction(evlistener)) + return 1; + else if (evlistener) + return evlistener.length; + } + return 0; +}; + +EventEmitter.listenerCount = function(emitter, type) { + return emitter.listenerCount(type); +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],5:[function(require,module,exports){ + +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; + +module.exports = function forEach (obj, fn, ctx) { + if (toString.call(fn) !== '[object Function]') { + throw new TypeError('iterator must be a function'); + } + var l = obj.length; + if (l === +l) { + for (var i = 0; i < l; i++) { + fn.call(ctx, obj[i], i, obj); + } + } else { + for (var k in obj) { + if (hasOwn.call(obj, k)) { + fn.call(ctx, obj[k], k, obj); + } + } + } +}; + + +},{}],6:[function(require,module,exports){ +(function (global){ +var win; + +if (typeof window !== "undefined") { + win = window; +} else if (typeof global !== "undefined") { + win = global; +} else if (typeof self !== "undefined"){ + win = self; +} else { + win = {}; +} + +module.exports = win; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],7:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],8:[function(require,module,exports){ +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; + +},{}],9:[function(require,module,exports){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + if (ms >= d) { + return Math.round(ms / d) + 'd'; + } + if (ms >= h) { + return Math.round(ms / h) + 'h'; + } + if (ms >= m) { + return Math.round(ms / m) + 'm'; + } + if (ms >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + return plural(ms, d, 'day') || + plural(ms, h, 'hour') || + plural(ms, m, 'minute') || + plural(ms, s, 'second') || + ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) { + return; + } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; + } + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +},{}],10:[function(require,module,exports){ +'use strict'; + +// modified from https://github.com/es-shims/es5-shim +var has = Object.prototype.hasOwnProperty; +var toStr = Object.prototype.toString; +var slice = Array.prototype.slice; +var isArgs = require(11); +var isEnumerable = Object.prototype.propertyIsEnumerable; +var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); +var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); +var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' +]; +var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; +}; +var excludedKeys = { + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true +}; +var hasAutomationEqualityBug = (function () { + /* global window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; +}()); +var equalsConstructorPrototypeIfNotBuggy = function (o) { + /* global window */ + if (typeof window === 'undefined' || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } +}; + +var keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; + + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } + + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; +}; + +keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function () { + // Safari 5.0 bug + return (Object.keys(arguments) || '').length === 2; + }(1, 2)); + if (!keysWorksWithArguments) { + var originalKeys = Object.keys; + Object.keys = function keys(object) { + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } else { + return originalKeys(object); + } + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; +}; + +module.exports = keysShim; + +},{"11":11}],11:[function(require,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + toStr.call(value.callee) === '[object Function]'; + } + return isArgs; +}; + +},{}],12:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],13:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; + + case 'boolean': + return v ? 'true' : 'false'; + + case 'number': + return isFinite(v) ? v : ''; + + default: + return ''; + } +}; + +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; + } + + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); + } + }).join(sep); + + } + + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); + } + return res; +} + +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + return res; +}; + +},{}],14:[function(require,module,exports){ +module.exports = AlgoliaSearch; + +var Index = require(16); +var deprecate = require(27); +var deprecatedMessage = require(28); +var AlgoliaSearchCore = require(15); +var inherits = require(7); +var errors = require(29); + +function AlgoliaSearch() { + AlgoliaSearchCore.apply(this, arguments); +} + +inherits(AlgoliaSearch, AlgoliaSearchCore); + +/* + * Delete an index + * + * @param indexName the name of index to delete + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.deleteIndex = function(indexName, callback) { + return this._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexName), + hostType: 'write', + callback: callback + }); +}; + +/** + * Move an existing index. + * @param srcIndexName the name of index to copy. + * @param dstIndexName the new index name that will contains a copy of + * srcIndexName (destination will be overriten if it already exist). + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.moveIndex = function(srcIndexName, dstIndexName, callback) { + var postObj = { + operation: 'move', destination: dstIndexName + }; + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Copy an existing index. + * @param srcIndexName the name of index to copy. + * @param dstIndexName the new index name that will contains a copy + * of srcIndexName (destination will be overriten if it already exist). + * @param scope an array of scopes to copy: ['settings', 'synonyms', 'rules'] + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.copyIndex = function(srcIndexName, dstIndexName, scopeOrCallback, _callback) { + var postObj = { + operation: 'copy', + destination: dstIndexName + }; + var callback = _callback; + if (typeof scopeOrCallback === 'function') { + // oops, old behaviour of third argument being a function + callback = scopeOrCallback; + } else if (Array.isArray(scopeOrCallback) && scopeOrCallback.length > 0) { + postObj.scope = scopeOrCallback; + } else if (typeof scopeOrCallback !== 'undefined') { + throw new Error('the scope given to `copyIndex` was not an array with settings, synonyms or rules'); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Return last log entries. + * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry). + * @param length Specify the maximum number of entries to retrieve starting + * at offset. Maximum allowed value: 1000. + * @param type Specify the maximum number of entries to retrieve starting + * at offset. Maximum allowed value: 1000. + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.getLogs = function(offset, length, callback) { + var clone = require(25); + var params = {}; + if (typeof offset === 'object') { + // getLogs(params) + params = clone(offset); + callback = length; + } else if (arguments.length === 0 || typeof offset === 'function') { + // getLogs([cb]) + callback = offset; + } else if (arguments.length === 1 || typeof length === 'function') { + // getLogs(1, [cb)] + callback = length; + params.offset = offset; + } else { + // getLogs(1, 2, [cb]) + params.offset = offset; + params.length = length; + } + + if (params.offset === undefined) params.offset = 0; + if (params.length === undefined) params.length = 10; + + return this._jsonRequest({ + method: 'GET', + url: '/1/logs?' + this._getSearchParams(params, ''), + hostType: 'read', + callback: callback + }); +}; + +/* + * List all existing indexes (paginated) + * + * @param page The page to retrieve, starting at 0. + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with index list + */ +AlgoliaSearch.prototype.listIndexes = function(page, callback) { + var params = ''; + + if (page === undefined || typeof page === 'function') { + callback = page; + } else { + params = '?page=' + page; + } + + return this._jsonRequest({ + method: 'GET', + url: '/1/indexes' + params, + hostType: 'read', + callback: callback + }); +}; + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearch.prototype.initIndex = function(indexName) { + return new Index(this, indexName); +}; + +AlgoliaSearch.prototype.initAnalytics = function(opts) { + // the actual require must be inside the function, when put outside then you have a cyclic dependency + // not well resolved that ends up making the main "./index.js" (main module, the agloliasearch function) + // export an object instead of a function + // Other workarounds: + // - rewrite the lib in ES6, cyclic dependencies may be better supported + // - move initAnalytics to a property on the main module (algoliasearch.initAnalytics), + // same as places. + // The current API was made mostly to mimic the one made in PHP + var createAnalyticsClient = require(26); + return createAnalyticsClient(this.applicationID, this.apiKey, opts); +}; + +/* + * @deprecated use client.listApiKeys + */ +AlgoliaSearch.prototype.listUserKeys = deprecate(function(callback) { + return this.listApiKeys(callback); +}, deprecatedMessage('client.listUserKeys()', 'client.listApiKeys()')); + +/* + * List all existing api keys with their associated ACLs + * + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with api keys list + */ +AlgoliaSearch.prototype.listApiKeys = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/keys', + hostType: 'read', + callback: callback + }); +}; + +/* + * @deprecated see client.getApiKey + */ +AlgoliaSearch.prototype.getUserKeyACL = deprecate(function(key, callback) { + return this.getApiKey(key, callback); +}, deprecatedMessage('client.getUserKeyACL()', 'client.getApiKey()')); + +/* + * Get an API key + * + * @param key + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the right API key + */ +AlgoliaSearch.prototype.getApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/keys/' + key, + hostType: 'read', + callback: callback + }); +}; + +/* + * @deprecated see client.deleteApiKey + */ +AlgoliaSearch.prototype.deleteUserKey = deprecate(function(key, callback) { + return this.deleteApiKey(key, callback); +}, deprecatedMessage('client.deleteUserKey()', 'client.deleteApiKey()')); + +/* + * Delete an existing API key + * @param key + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the date of deletion + */ +AlgoliaSearch.prototype.deleteApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'DELETE', + url: '/1/keys/' + key, + hostType: 'write', + callback: callback + }); +}; + +/* + @deprecated see client.addApiKey + */ +AlgoliaSearch.prototype.addUserKey = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('client.addUserKey()', 'client.addApiKey()')); + +/* + * Add a new global API key + * + * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that + * can contains the following values: + * - search: allow to search (https and http) + * - addObject: allows to add/update an object in the index (https only) + * - deleteObject : allows to delete an existing object (https only) + * - deleteIndex : allows to delete index content (https only) + * - settings : allows to get index settings (https only) + * - editSettings : allows to change index settings (https only) + * @param {Object} [params] - Optionnal parameters to set for the key + * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key) + * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour + * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call + * @param {string[]} params.indexes - Allowed targeted indexes for this key + * @param {string} params.description - A description for your key + * @param {string[]} params.referers - A list of authorized referers + * @param {Object} params.queryParameters - Force the key to use specific query parameters + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the added API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.addApiKey(['search'], { + * validity: 300, + * maxQueriesPerIPPerHour: 2000, + * maxHitsPerQuery: 3, + * indexes: ['fruits'], + * description: 'Eat three fruits', + * referers: ['*.algolia.com'], + * queryParameters: { + * tagFilters: ['public'], + * } + * }) + * @see {@link https://www.algolia.com/doc/rest_api#AddKey|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.addApiKey = function(acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: client.addApiKey(arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = null; + } + + var postObj = { + acl: acls + }; + + if (params) { + postObj.validity = params.validity; + postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + postObj.maxHitsPerQuery = params.maxHitsPerQuery; + postObj.indexes = params.indexes; + postObj.description = params.description; + + if (params.queryParameters) { + postObj.queryParameters = this._getSearchParams(params.queryParameters, ''); + } + + postObj.referers = params.referers; + } + + return this._jsonRequest({ + method: 'POST', + url: '/1/keys', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * @deprecated Please use client.addApiKey() + */ +AlgoliaSearch.prototype.addUserKeyWithValidity = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('client.addUserKeyWithValidity()', 'client.addApiKey()')); + +/** + * @deprecated Please use client.updateApiKey() + */ +AlgoliaSearch.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { + return this.updateApiKey(key, acls, params, callback); +}, deprecatedMessage('client.updateUserKey()', 'client.updateApiKey()')); + +/** + * Update an existing API key + * @param {string} key - The key to update + * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that + * can contains the following values: + * - search: allow to search (https and http) + * - addObject: allows to add/update an object in the index (https only) + * - deleteObject : allows to delete an existing object (https only) + * - deleteIndex : allows to delete index content (https only) + * - settings : allows to get index settings (https only) + * - editSettings : allows to change index settings (https only) + * @param {Object} [params] - Optionnal parameters to set for the key + * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key) + * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour + * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call + * @param {string[]} params.indexes - Allowed targeted indexes for this key + * @param {string} params.description - A description for your key + * @param {string[]} params.referers - A list of authorized referers + * @param {Object} params.queryParameters - Force the key to use specific query parameters + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the modified API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.updateApiKey('APIKEY', ['search'], { + * validity: 300, + * maxQueriesPerIPPerHour: 2000, + * maxHitsPerQuery: 3, + * indexes: ['fruits'], + * description: 'Eat three fruits', + * referers: ['*.algolia.com'], + * queryParameters: { + * tagFilters: ['public'], + * } + * }) + * @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.updateApiKey = function(key, acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: client.updateApiKey(key, arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 2 || typeof params === 'function') { + callback = params; + params = null; + } + + var putObj = { + acl: acls + }; + + if (params) { + putObj.validity = params.validity; + putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + putObj.maxHitsPerQuery = params.maxHitsPerQuery; + putObj.indexes = params.indexes; + putObj.description = params.description; + + if (params.queryParameters) { + putObj.queryParameters = this._getSearchParams(params.queryParameters, ''); + } + + putObj.referers = params.referers; + } + + return this._jsonRequest({ + method: 'PUT', + url: '/1/keys/' + key, + body: putObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Initialize a new batch of search queries + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.startQueriesBatch = deprecate(function startQueriesBatchDeprecated() { + this._batch = []; +}, deprecatedMessage('client.startQueriesBatch()', 'client.search()')); + +/** + * Add a search query in the batch + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.addQueryInBatch = deprecate(function addQueryInBatchDeprecated(indexName, query, args) { + this._batch.push({ + indexName: indexName, + query: query, + params: args + }); +}, deprecatedMessage('client.addQueryInBatch()', 'client.search()')); + +/** + * Launch the batch of queries using XMLHttpRequest. + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.sendQueriesBatch = deprecate(function sendQueriesBatchDeprecated(callback) { + return this.search(this._batch, callback); +}, deprecatedMessage('client.sendQueriesBatch()', 'client.search()')); + +/** + * Perform write operations accross multiple indexes. + * + * To reduce the amount of time spent on network round trips, + * you can create, update, or delete several objects in one call, + * using the batch endpoint (all operations are done in the given order). + * + * Available actions: + * - addObject + * - updateObject + * - partialUpdateObject + * - partialUpdateObjectNoCreate + * - deleteObject + * + * https://www.algolia.com/doc/rest_api#Indexes + * @param {Object[]} operations An array of operations to perform + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.batch([{ + * action: 'addObject', + * indexName: 'clients', + * body: { + * name: 'Bill' + * } + * }, { + * action: 'udpateObject', + * indexName: 'fruits', + * body: { + * objectID: '29138', + * name: 'banana' + * } + * }], cb) + */ +AlgoliaSearch.prototype.batch = function(operations, callback) { + var isArray = require(8); + var usage = 'Usage: client.batch(operations[, callback])'; + + if (!isArray(operations)) { + throw new Error(usage); + } + + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/batch', + body: { + requests: operations + }, + hostType: 'write', + callback: callback + }); +}; + +/** + * Assign or Move a userID to a cluster + * + * @param {string} data.userID The userID to assign to a new cluster + * @param {string} data.cluster The cluster to assign the user to + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.assignUserID({ cluster: 'c1-test', userID: 'some-user' }); + */ +AlgoliaSearch.prototype.assignUserID = function(data, callback) { + if (!data.userID || !data.cluster) { + throw new errors.AlgoliaSearchError('You have to provide both a userID and cluster', data); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping', + hostType: 'write', + body: {cluster: data.cluster}, + callback: callback, + headers: { + 'x-algolia-user-id': data.userID + } + }); +}; + +/** + * Get the top userIDs + * + * (the callback is the second argument) + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getTopUserID(); + */ +AlgoliaSearch.prototype.getTopUserID = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping/top', + hostType: 'read', + callback: callback + }); +}; + +/** + * Get userID + * + * @param {string} data.userID The userID to get info about + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getUserID({ userID: 'some-user' }); + */ +AlgoliaSearch.prototype.getUserID = function(data, callback) { + if (!data.userID) { + throw new errors.AlgoliaSearchError('You have to provide a userID', {debugData: data}); + } + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping/' + data.userID, + hostType: 'read', + callback: callback + }); +}; + +/** + * List all the clusters + * + * (the callback is the second argument) + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.listClusters(); + */ +AlgoliaSearch.prototype.listClusters = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters', + hostType: 'read', + callback: callback + }); +}; + +/** + * List the userIDs + * + * (the callback is the second argument) + * + * @param {string} data.hitsPerPage How many hits on every page + * @param {string} data.page The page to retrieve + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.listClusters(); + * client.listClusters({ page: 3, hitsPerPage: 30}); + */ +AlgoliaSearch.prototype.listUserIDs = function(data, callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping', + body: data, + hostType: 'read', + callback: callback + }); +}; + +/** + * Remove an userID + * + * @param {string} data.userID The userID to assign to a new cluster + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.removeUserID({ userID: 'some-user' }); + */ +AlgoliaSearch.prototype.removeUserID = function(data, callback) { + if (!data.userID) { + throw new errors.AlgoliaSearchError('You have to provide a userID', {debugData: data}); + } + return this._jsonRequest({ + method: 'DELETE', + url: '/1/clusters/mapping', + hostType: 'write', + callback: callback, + headers: { + 'x-algolia-user-id': data.userID + } + }); +}; + +/** + * Search for userIDs + * + * @param {string} data.cluster The cluster to target + * @param {string} data.query The query to execute + * @param {string} data.hitsPerPage How many hits on every page + * @param {string} data.page The page to retrieve + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.searchUserIDs({ cluster: 'c1-test', query: 'some-user' }); + * client.searchUserIDs({ + * cluster: "c1-test", + * query: "some-user", + * page: 3, + * hitsPerPage: 2 + * }); + */ +AlgoliaSearch.prototype.searchUserIDs = function(data, callback) { + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping/search', + body: data, + hostType: 'read', + callback: callback + }); +}; + +// environment specific methods +AlgoliaSearch.prototype.destroy = notImplemented; +AlgoliaSearch.prototype.enableRateLimitForward = notImplemented; +AlgoliaSearch.prototype.disableRateLimitForward = notImplemented; +AlgoliaSearch.prototype.useSecuredAPIKey = notImplemented; +AlgoliaSearch.prototype.disableSecuredAPIKey = notImplemented; +AlgoliaSearch.prototype.generateSecuredApiKey = notImplemented; + +function notImplemented() { + var message = 'Not implemented in this environment.\n' + + 'If you feel this is a mistake, write to support@algolia.com'; + + throw new errors.AlgoliaSearchError(message); +} + +},{"15":15,"16":16,"25":25,"26":26,"27":27,"28":28,"29":29,"7":7,"8":8}],15:[function(require,module,exports){ +(function (process){ +module.exports = AlgoliaSearchCore; + +var errors = require(29); +var exitPromise = require(30); +var IndexCore = require(18); +var store = require(35); + +// We will always put the API KEY in the JSON body in case of too long API KEY, +// to avoid query string being too long and failing in various conditions (our server limit, browser limit, +// proxies limit) +var MAX_API_KEY_LENGTH = 500; +var RESET_APP_DATA_TIMER = + process.env.RESET_APP_DATA_TIMER && parseInt(process.env.RESET_APP_DATA_TIMER, 10) || + 60 * 2 * 1000; // after 2 minutes reset to first host + +/* + * Algolia Search library initialization + * https://www.algolia.com/ + * + * @param {string} applicationID - Your applicationID, found in your dashboard + * @param {string} apiKey - Your API key, found in your dashboard + * @param {Object} [opts] + * @param {number} [opts.timeout=2000] - The request timeout set in milliseconds, + * another request will be issued after this timeout + * @param {string} [opts.protocol='https:'] - The protocol used to query Algolia Search API. + * Set to 'http:' to force using http. + * @param {Object|Array} [opts.hosts={ + * read: [this.applicationID + '-dsn.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]), + * write: [this.applicationID + '.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]) - The hosts to use for Algolia Search API. + * If you provide them, you will less benefit from our HA implementation + */ +function AlgoliaSearchCore(applicationID, apiKey, opts) { + var debug = require(1)('algoliasearch'); + + var clone = require(25); + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: algoliasearch(applicationID, apiKey, opts)'; + + if (opts._allowEmptyCredentials !== true && !applicationID) { + throw new errors.AlgoliaSearchError('Please provide an application ID. ' + usage); + } + + if (opts._allowEmptyCredentials !== true && !apiKey) { + throw new errors.AlgoliaSearchError('Please provide an API key. ' + usage); + } + + this.applicationID = applicationID; + this.apiKey = apiKey; + + this.hosts = { + read: [], + write: [] + }; + + opts = opts || {}; + + this._timeouts = opts.timeouts || { + connect: 1 * 1000, // 500ms connect is GPRS latency + read: 2 * 1000, + write: 30 * 1000 + }; + + // backward compat, if opts.timeout is passed, we use it to configure all timeouts like before + if (opts.timeout) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = opts.timeout; + } + + var protocol = opts.protocol || 'https:'; + // while we advocate for colon-at-the-end values: 'http:' for `opts.protocol` + // we also accept `http` and `https`. It's a common error. + if (!/:$/.test(protocol)) { + protocol = protocol + ':'; + } + + if (protocol !== 'http:' && protocol !== 'https:') { + throw new errors.AlgoliaSearchError('protocol must be `http:` or `https:` (was `' + opts.protocol + '`)'); + } + + this._checkAppIdData(); + + if (!opts.hosts) { + var defaultHosts = map(this._shuffleResult, function(hostNumber) { + return applicationID + '-' + hostNumber + '.algolianet.com'; + }); + + // no hosts given, compute defaults + var mainSuffix = (opts.dsn === false ? '' : '-dsn') + '.algolia.net'; + this.hosts.read = [this.applicationID + mainSuffix].concat(defaultHosts); + this.hosts.write = [this.applicationID + '.algolia.net'].concat(defaultHosts); + } else if (isArray(opts.hosts)) { + // when passing custom hosts, we need to have a different host index if the number + // of write/read hosts are different. + this.hosts.read = clone(opts.hosts); + this.hosts.write = clone(opts.hosts); + } else { + this.hosts.read = clone(opts.hosts.read); + this.hosts.write = clone(opts.hosts.write); + } + + // add protocol and lowercase hosts + this.hosts.read = map(this.hosts.read, prepareHost(protocol)); + this.hosts.write = map(this.hosts.write, prepareHost(protocol)); + + this.extraHeaders = {}; + + // In some situations you might want to warm the cache + this.cache = opts._cache || {}; + + this._ua = opts._ua; + this._useCache = opts._useCache === undefined || opts._cache ? true : opts._useCache; + this._useRequestCache = this._useCache && opts._useRequestCache; + this._useFallback = opts.useFallback === undefined ? true : opts.useFallback; + + this._setTimeout = opts._setTimeout; + + debug('init done, %j', this); +} + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearchCore.prototype.initIndex = function(indexName) { + return new IndexCore(this, indexName); +}; + +/** +* Add an extra field to the HTTP request +* +* @param name the header field name +* @param value the header field value +*/ +AlgoliaSearchCore.prototype.setExtraHeader = function(name, value) { + this.extraHeaders[name.toLowerCase()] = value; +}; + +/** +* Get the value of an extra HTTP header +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.getExtraHeader = function(name) { + return this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Remove an extra field from the HTTP request +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.unsetExtraHeader = function(name) { + delete this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Augment sent x-algolia-agent with more data, each agent part +* is automatically separated from the others by a semicolon; +* +* @param algoliaAgent the agent to add +*/ +AlgoliaSearchCore.prototype.addAlgoliaAgent = function(algoliaAgent) { + if (this._ua.indexOf(';' + algoliaAgent) === -1) { + this._ua += ';' + algoliaAgent; + } +}; + +/* + * Wrapper that try all hosts to maximize the quality of service + */ +AlgoliaSearchCore.prototype._jsonRequest = function(initialOpts) { + this._checkAppIdData(); + + var requestDebug = require(1)('algoliasearch:' + initialOpts.url); + + + var body; + var cacheID; + var additionalUA = initialOpts.additionalUA || ''; + var cache = initialOpts.cache; + var client = this; + var tries = 0; + var usingFallback = false; + var hasFallback = client._useFallback && client._request.fallback && initialOpts.fallback; + var headers; + + if ( + this.apiKey.length > MAX_API_KEY_LENGTH && + initialOpts.body !== undefined && + (initialOpts.body.params !== undefined || // index.search() + initialOpts.body.requests !== undefined) // client.search() + ) { + initialOpts.body.apiKey = this.apiKey; + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + withApiKey: false, + headers: initialOpts.headers + }); + } else { + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + } + + if (initialOpts.body !== undefined) { + body = safeJSONStringify(initialOpts.body); + } + + requestDebug('request start'); + var debugData = []; + + + function doRequest(requester, reqOpts) { + client._checkAppIdData(); + + var startTime = new Date(); + + if (client._useCache && !client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && !client._useRequestCache && body) { + cacheID += '_body_' + reqOpts.body; + } + + // handle cache existence + if (isCacheValidWithCurrentID(!client._useRequestCache, cache, cacheID)) { + requestDebug('serving response from cache'); + + var responseText = cache[cacheID]; + + // Cache response must match the type of the original one + return client._promise.resolve({ + body: JSON.parse(responseText), + responseText: responseText + }); + } + + // if we reached max tries + if (tries >= client.hosts[initialOpts.hostType].length) { + if (!hasFallback || usingFallback) { + requestDebug('could not get any response'); + // then stop + return client._promise.reject(new errors.AlgoliaSearchError( + 'Cannot connect to the AlgoliaSearch API.' + + ' Send an email to support@algolia.com to report and resolve the issue.' + + ' Application id was: ' + client.applicationID, {debugData: debugData} + )); + } + + requestDebug('switching to fallback'); + + // let's try the fallback starting from here + tries = 0; + + // method, url and body are fallback dependent + reqOpts.method = initialOpts.fallback.method; + reqOpts.url = initialOpts.fallback.url; + reqOpts.jsonBody = initialOpts.fallback.body; + if (reqOpts.jsonBody) { + reqOpts.body = safeJSONStringify(reqOpts.jsonBody); + } + // re-compute headers, they could be omitting the API KEY + headers = client._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + client._setHostIndexByType(0, initialOpts.hostType); + usingFallback = true; // the current request is now using fallback + return doRequest(client._request.fallback, reqOpts); + } + + var currentHost = client._getHostByType(initialOpts.hostType); + + var url = currentHost + reqOpts.url; + var options = { + body: reqOpts.body, + jsonBody: reqOpts.jsonBody, + method: reqOpts.method, + headers: headers, + timeouts: reqOpts.timeouts, + debug: requestDebug, + forceAuthHeaders: reqOpts.forceAuthHeaders + }; + + requestDebug('method: %s, url: %s, headers: %j, timeouts: %d', + options.method, url, options.headers, options.timeouts); + + if (requester === client._request.fallback) { + requestDebug('using fallback'); + } + + // `requester` is any of this._request or this._request.fallback + // thus it needs to be called using the client as context + return requester.call(client, url, options).then(success, tryFallback); + + function success(httpResponse) { + // compute the status of the response, + // + // When in browser mode, using XDR or JSONP, we have no statusCode available + // So we rely on our API response `status` property. + // But `waitTask` can set a `status` property which is not the statusCode (it's the task status) + // So we check if there's a `message` along `status` and it means it's an error + // + // That's the only case where we have a response.status that's not the http statusCode + var status = httpResponse && httpResponse.body && httpResponse.body.message && httpResponse.body.status || + + // this is important to check the request statusCode AFTER the body eventual + // statusCode because some implementations (jQuery XDomainRequest transport) may + // send statusCode 200 while we had an error + httpResponse.statusCode || + + // When in browser mode, using XDR or JSONP + // we default to success when no error (no response.status && response.message) + // If there was a JSON.parse() error then body is null and it fails + httpResponse && httpResponse.body && 200; + + requestDebug('received response: statusCode: %s, computed statusCode: %d, headers: %j', + httpResponse.statusCode, status, httpResponse.headers); + + var httpResponseOk = Math.floor(status / 100) === 2; + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime, + statusCode: status + }); + + if (httpResponseOk) { + if (client._useCache && !client._useRequestCache && cache) { + cache[cacheID] = httpResponse.responseText; + } + + return { + responseText: httpResponse.responseText, + body: httpResponse.body + }; + } + + var shouldRetry = Math.floor(status / 100) !== 4; + + if (shouldRetry) { + tries += 1; + return retryRequest(); + } + + requestDebug('unrecoverable error'); + + // no success and no retry => fail + var unrecoverableError = new errors.AlgoliaSearchError( + httpResponse.body && httpResponse.body.message, {debugData: debugData, statusCode: status} + ); + + return client._promise.reject(unrecoverableError); + } + + function tryFallback(err) { + // error cases: + // While not in fallback mode: + // - CORS not supported + // - network error + // While in fallback mode: + // - timeout + // - network error + // - badly formatted JSONP (script loaded, did not call our callback) + // In both cases: + // - uncaught exception occurs (TypeError) + requestDebug('error: %s, stack: %s', err.message, err.stack); + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime + }); + + if (!(err instanceof errors.AlgoliaSearchError)) { + err = new errors.Unknown(err && err.message, err); + } + + tries += 1; + + // stop the request implementation when: + if ( + // we did not generate this error, + // it comes from a throw in some other piece of code + err instanceof errors.Unknown || + + // server sent unparsable JSON + err instanceof errors.UnparsableJSON || + + // max tries and already using fallback or no fallback + tries >= client.hosts[initialOpts.hostType].length && + (usingFallback || !hasFallback)) { + // stop request implementation for this command + err.debugData = debugData; + return client._promise.reject(err); + } + + // When a timeout occured, retry by raising timeout + if (err instanceof errors.RequestTimeout) { + return retryRequestWithHigherTimeout(); + } + + return retryRequest(); + } + + function retryRequest() { + requestDebug('retrying request'); + client._incrementHostIndex(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + + function retryRequestWithHigherTimeout() { + requestDebug('retrying request with higher timeout'); + client._incrementHostIndex(initialOpts.hostType); + client._incrementTimeoutMultipler(); + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + } + + function isCacheValidWithCurrentID( + useRequestCache, + currentCache, + currentCacheID + ) { + return ( + client._useCache && + useRequestCache && + currentCache && + currentCache[currentCacheID] !== undefined + ); + } + + + function interopCallbackReturn(request, callback) { + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + request.catch(function() { + // Release the cache on error + delete cache[cacheID]; + }); + } + + if (typeof initialOpts.callback === 'function') { + // either we have a callback + request.then(function okCb(content) { + exitPromise(function() { + initialOpts.callback(null, callback(content)); + }, client._setTimeout || setTimeout); + }, function nookCb(err) { + exitPromise(function() { + initialOpts.callback(err); + }, client._setTimeout || setTimeout); + }); + } else { + // either we are using promises + return request.then(callback); + } + } + + if (client._useCache && client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && client._useRequestCache && body) { + cacheID += '_body_' + body; + } + + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + requestDebug('serving request from cache'); + + var maybePromiseForCache = cache[cacheID]; + + // In case the cache is warmup with value that is not a promise + var promiseForCache = typeof maybePromiseForCache.then !== 'function' + ? client._promise.resolve({responseText: maybePromiseForCache}) + : maybePromiseForCache; + + return interopCallbackReturn(promiseForCache, function(content) { + // In case of the cache request, return the original value + return JSON.parse(content.responseText); + }); + } + + var request = doRequest( + client._request, { + url: initialOpts.url, + method: initialOpts.method, + body: body, + jsonBody: initialOpts.body, + timeouts: client._getTimeoutsForRequest(initialOpts.hostType), + forceAuthHeaders: initialOpts.forceAuthHeaders + } + ); + + if (client._useCache && client._useRequestCache && cache) { + cache[cacheID] = request; + } + + return interopCallbackReturn(request, function(content) { + // In case of the first request, return the JSON value + return content.body; + }); +}; + +/* +* Transform search param object in query string +* @param {object} args arguments to add to the current query string +* @param {string} params current query string +* @return {string} the final query string +*/ +AlgoliaSearchCore.prototype._getSearchParams = function(args, params) { + if (args === undefined || args === null) { + return params; + } + for (var key in args) { + if (key !== null && args[key] !== undefined && args.hasOwnProperty(key)) { + params += params === '' ? '' : '&'; + params += key + '=' + encodeURIComponent(Object.prototype.toString.call(args[key]) === '[object Array]' ? safeJSONStringify(args[key]) : args[key]); + } + } + return params; +}; + +/** + * Compute the headers for a request + * + * @param [string] options.additionalUA semi-colon separated string with other user agents to add + * @param [boolean=true] options.withApiKey Send the api key as a header + * @param [Object] options.headers Extra headers to send + */ +AlgoliaSearchCore.prototype._computeRequestHeaders = function(options) { + var forEach = require(5); + + var ua = options.additionalUA ? + this._ua + ';' + options.additionalUA : + this._ua; + + var requestHeaders = { + 'x-algolia-agent': ua, + 'x-algolia-application-id': this.applicationID + }; + + // browser will inline headers in the url, node.js will use http headers + // but in some situations, the API KEY will be too long (big secured API keys) + // so if the request is a POST and the KEY is very long, we will be asked to not put + // it into headers but in the JSON body + if (options.withApiKey !== false) { + requestHeaders['x-algolia-api-key'] = this.apiKey; + } + + if (this.userToken) { + requestHeaders['x-algolia-usertoken'] = this.userToken; + } + + if (this.securityTags) { + requestHeaders['x-algolia-tagfilters'] = this.securityTags; + } + + forEach(this.extraHeaders, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + + if (options.headers) { + forEach(options.headers, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + } + + return requestHeaders; +}; + +/** + * Search through multiple indices at the same time + * @param {Object[]} queries An array of queries you want to run. + * @param {string} queries[].indexName The index name you want to target + * @param {string} [queries[].query] The query to issue on this index. Can also be passed into `params` + * @param {Object} queries[].params Any search param like hitsPerPage, .. + * @param {Function} callback Callback to be called + * @return {Promise|undefined} Returns a promise if no callback given + */ +AlgoliaSearchCore.prototype.search = function(queries, opts, callback) { + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: client.search(arrayOfQueries[, callback])'; + + if (!isArray(queries)) { + throw new Error(usage); + } + + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var client = this; + + var postObj = { + requests: map(queries, function prepareRequest(query) { + var params = ''; + + // allow query.query + // so we are mimicing the index.search(query, params) method + // {indexName:, query:, params:} + if (query.query !== undefined) { + params += 'query=' + encodeURIComponent(query.query); + } + + return { + indexName: query.indexName, + params: client._getSearchParams(query.params, params) + }; + }) + }; + + var JSONPParams = map(postObj.requests, function prepareJSONPParams(request, requestId) { + return requestId + '=' + + encodeURIComponent( + '/1/indexes/' + encodeURIComponent(request.indexName) + '?' + + request.params + ); + }).join('&'); + + var url = '/1/indexes/*/queries'; + + if (opts.strategy !== undefined) { + postObj.strategy = opts.strategy; + } + + return this._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url, + body: postObj, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/*', + body: { + params: JSONPParams + } + }, + callback: callback + }); +}; + +/** +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* This is the top-level API for SFFV. +* +* @param {object[]} queries An array of queries to run. +* @param {string} queries[].indexName Index name, name of the index to search. +* @param {object} queries[].params Query parameters. +* @param {string} queries[].params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} queries[].params.facetQuery Query for the facet search +* @param {string} [queries[].params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +*/ +AlgoliaSearchCore.prototype.searchForFacetValues = function(queries) { + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])'; // eslint-disable-line max-len + + if (!isArray(queries)) { + throw new Error(usage); + } + + var client = this; + + return client._promise.all(map(queries, function performQuery(query) { + if ( + !query || + query.indexName === undefined || + query.params.facetName === undefined || + query.params.facetQuery === undefined + ) { + throw new Error(usage); + } + + var clone = require(25); + var omit = require(33); + + var indexName = query.indexName; + var params = query.params; + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = client._getSearchParams(filteredParams, ''); + + return client._jsonRequest({ + cache: client.cache, + method: 'POST', + url: + '/1/indexes/' + + encodeURIComponent(indexName) + + '/facets/' + + encodeURIComponent(facetName) + + '/query', + hostType: 'read', + body: {params: searchParameters} + }); + })); +}; + +/** + * Set the extra security tagFilters header + * @param {string|array} tags The list of tags defining the current security filters + */ +AlgoliaSearchCore.prototype.setSecurityTags = function(tags) { + if (Object.prototype.toString.call(tags) === '[object Array]') { + var strTags = []; + for (var i = 0; i < tags.length; ++i) { + if (Object.prototype.toString.call(tags[i]) === '[object Array]') { + var oredTags = []; + for (var j = 0; j < tags[i].length; ++j) { + oredTags.push(tags[i][j]); + } + strTags.push('(' + oredTags.join(',') + ')'); + } else { + strTags.push(tags[i]); + } + } + tags = strTags.join(','); + } + + this.securityTags = tags; +}; + +/** + * Set the extra user token header + * @param {string} userToken The token identifying a uniq user (used to apply rate limits) + */ +AlgoliaSearchCore.prototype.setUserToken = function(userToken) { + this.userToken = userToken; +}; + +/** + * Clear all queries in client's cache + * @return undefined + */ +AlgoliaSearchCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/** +* Set the number of milliseconds a request can take before automatically being terminated. +* @deprecated +* @param {Number} milliseconds +*/ +AlgoliaSearchCore.prototype.setRequestTimeout = function(milliseconds) { + if (milliseconds) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = milliseconds; + } +}; + +/** +* Set the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.setTimeouts = function(timeouts) { + this._timeouts = timeouts; +}; + +/** +* Get the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.getTimeouts = function() { + return this._timeouts; +}; + +AlgoliaSearchCore.prototype._getAppIdData = function() { + var data = store.get(this.applicationID); + if (data !== null) this._cacheAppIdData(data); + return data; +}; + +AlgoliaSearchCore.prototype._setAppIdData = function(data) { + data.lastChange = (new Date()).getTime(); + this._cacheAppIdData(data); + return store.set(this.applicationID, data); +}; + +AlgoliaSearchCore.prototype._checkAppIdData = function() { + var data = this._getAppIdData(); + var now = (new Date()).getTime(); + if (data === null || now - data.lastChange > RESET_APP_DATA_TIMER) { + return this._resetInitialAppIdData(data); + } + + return data; +}; + +AlgoliaSearchCore.prototype._resetInitialAppIdData = function(data) { + var newData = data || {}; + newData.hostIndexes = {read: 0, write: 0}; + newData.timeoutMultiplier = 1; + newData.shuffleResult = newData.shuffleResult || shuffle([1, 2, 3]); + return this._setAppIdData(newData); +}; + +AlgoliaSearchCore.prototype._cacheAppIdData = function(data) { + this._hostIndexes = data.hostIndexes; + this._timeoutMultiplier = data.timeoutMultiplier; + this._shuffleResult = data.shuffleResult; +}; + +AlgoliaSearchCore.prototype._partialAppIdDataUpdate = function(newData) { + var foreach = require(5); + var currentData = this._getAppIdData(); + foreach(newData, function(value, key) { + currentData[key] = value; + }); + + return this._setAppIdData(currentData); +}; + +AlgoliaSearchCore.prototype._getHostByType = function(hostType) { + return this.hosts[hostType][this._getHostIndexByType(hostType)]; +}; + +AlgoliaSearchCore.prototype._getTimeoutMultiplier = function() { + return this._timeoutMultiplier; +}; + +AlgoliaSearchCore.prototype._getHostIndexByType = function(hostType) { + return this._hostIndexes[hostType]; +}; + +AlgoliaSearchCore.prototype._setHostIndexByType = function(hostIndex, hostType) { + var clone = require(25); + var newHostIndexes = clone(this._hostIndexes); + newHostIndexes[hostType] = hostIndex; + this._partialAppIdDataUpdate({hostIndexes: newHostIndexes}); + return hostIndex; +}; + +AlgoliaSearchCore.prototype._incrementHostIndex = function(hostType) { + return this._setHostIndexByType( + (this._getHostIndexByType(hostType) + 1) % this.hosts[hostType].length, hostType + ); +}; + +AlgoliaSearchCore.prototype._incrementTimeoutMultipler = function() { + var timeoutMultiplier = Math.max(this._timeoutMultiplier + 1, 4); + return this._partialAppIdDataUpdate({timeoutMultiplier: timeoutMultiplier}); +}; + +AlgoliaSearchCore.prototype._getTimeoutsForRequest = function(hostType) { + return { + connect: this._timeouts.connect * this._timeoutMultiplier, + complete: this._timeouts[hostType] * this._timeoutMultiplier + }; +}; + +function prepareHost(protocol) { + return function prepare(host) { + return protocol + '//' + host.toLowerCase(); + }; +} + +// Prototype.js < 1.7, a widely used library, defines a weird +// Array.prototype.toJSON function that will fail to stringify our content +// appropriately +// refs: +// - https://groups.google.com/forum/#!topic/prototype-core/E-SAVvV_V9Q +// - https://github.com/sstephenson/prototype/commit/038a2985a70593c1a86c230fadbdfe2e4898a48c +// - http://stackoverflow.com/a/3148441/147079 +function safeJSONStringify(obj) { + /* eslint no-extend-native:0 */ + + if (Array.prototype.toJSON === undefined) { + return JSON.stringify(obj); + } + + var toJSON = Array.prototype.toJSON; + delete Array.prototype.toJSON; + var out = JSON.stringify(obj); + Array.prototype.toJSON = toJSON; + + return out; +} + +function shuffle(array) { + var currentIndex = array.length; + var temporaryValue; + var randomIndex; + + // While there remain elements to shuffle... + while (currentIndex !== 0) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + + return array; +} + +function removeCredentials(headers) { + var newHeaders = {}; + + for (var headerName in headers) { + if (Object.prototype.hasOwnProperty.call(headers, headerName)) { + var value; + + if (headerName === 'x-algolia-api-key' || headerName === 'x-algolia-application-id') { + value = '**hidden for security purposes**'; + } else { + value = headers[headerName]; + } + + newHeaders[headerName] = value; + } + } + + return newHeaders; +} + +}).call(this,require(12)) +},{"1":1,"12":12,"18":18,"25":25,"29":29,"30":30,"31":31,"33":33,"35":35,"5":5,"8":8}],16:[function(require,module,exports){ +var inherits = require(7); +var IndexCore = require(18); +var deprecate = require(27); +var deprecatedMessage = require(28); +var exitPromise = require(30); +var errors = require(29); + +var deprecateForwardToSlaves = deprecate( + function() {}, + deprecatedMessage('forwardToSlaves', 'forwardToReplicas') +); + +module.exports = Index; + +function Index() { + IndexCore.apply(this, arguments); +} + +inherits(Index, IndexCore); + +/* +* Add an object in this index +* +* @param content contains the javascript object to add inside the index +* @param objectID (optional) an objectID you want to attribute to this object +* (if the attribute already exist the old object will be overwrite) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.addObject = function(content, objectID, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof objectID === 'function') { + callback = objectID; + objectID = undefined; + } + + return this.as._jsonRequest({ + method: objectID !== undefined ? + 'PUT' : // update or create + 'POST', // create (API generates an objectID) + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + // create + (objectID !== undefined ? '/' + encodeURIComponent(objectID) : ''), // update or create + body: content, + hostType: 'write', + callback: callback + }); +}; + +/* +* Add several objects +* +* @param objects contains an array of objects to add +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.addObjects = function(objects, callback) { + var isArray = require(8); + var usage = 'Usage: index.addObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: 'addObject', + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Update partially an object (only update attributes passed in argument) +* +* @param partialObject contains the javascript attributes to override, the +* object must contains an objectID attribute +* @param createIfNotExists (optional) if false, avoid an automatic creation of the object +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.partialUpdateObject = function(partialObject, createIfNotExists, callback) { + if (arguments.length === 1 || typeof createIfNotExists === 'function') { + callback = createIfNotExists; + createIfNotExists = undefined; + } + + var indexObj = this; + var url = '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(partialObject.objectID) + '/partial'; + if (createIfNotExists === false) { + url += '?createIfNotExists=false'; + } + + return this.as._jsonRequest({ + method: 'POST', + url: url, + body: partialObject, + hostType: 'write', + callback: callback + }); +}; + +/* +* Partially Override the content of several objects +* +* @param objects contains an array of objects to update (each object must contains a objectID attribute) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.partialUpdateObjects = function(objects, createIfNotExists, callback) { + if (arguments.length === 1 || typeof createIfNotExists === 'function') { + callback = createIfNotExists; + createIfNotExists = true; + } + + var isArray = require(8); + var usage = 'Usage: index.partialUpdateObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: createIfNotExists === true ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate', + objectID: objects[i].objectID, + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Override the content of object +* +* @param object contains the javascript object to save, the object must contains an objectID attribute +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.saveObject = function(object, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(object.objectID), + body: object, + hostType: 'write', + callback: callback + }); +}; + +/* +* Override the content of several objects +* +* @param objects contains an array of objects to update (each object must contains a objectID attribute) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.saveObjects = function(objects, callback) { + var isArray = require(8); + var usage = 'Usage: index.saveObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: 'updateObject', + objectID: objects[i].objectID, + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete an object from the index +* +* @param objectID the unique identifier of object to delete +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.deleteObject = function(objectID, callback) { + if (typeof objectID === 'function' || typeof objectID !== 'string' && typeof objectID !== 'number') { + var err = new errors.AlgoliaSearchError( + objectID && typeof objectID !== 'function' + ? 'ObjectID must be a string' + : 'Cannot delete an object without an objectID' + ); + callback = objectID; + if (typeof callback === 'function') { + return callback(err); + } + + return this.as._promise.reject(err); + } + + var indexObj = this; + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID), + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete several objects from an index +* +* @param objectIDs contains an array of objectID to delete +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.deleteObjects = function(objectIDs, callback) { + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: index.deleteObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: map(objectIDs, function prepareRequest(objectID) { + return { + action: 'deleteObject', + objectID: objectID, + body: { + objectID: objectID + } + }; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete all objects matching a query +* +* @param query the query string +* @param params the optional query parameters +* @param callback (optional) the result callback called with one argument +* error: null or Error('message') +* @deprecated see index.deleteBy +*/ +Index.prototype.deleteByQuery = deprecate(function(query, params, callback) { + var clone = require(25); + var map = require(31); + + var indexObj = this; + var client = indexObj.as; + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = {}; + } else { + params = clone(params); + } + + params.attributesToRetrieve = 'objectID'; + params.hitsPerPage = 1000; + params.distinct = false; + + // when deleting, we should never use cache to get the + // search results + this.clearCache(); + + // there's a problem in how we use the promise chain, + // see how waitTask is done + var promise = this + .search(query, params) + .then(stopOrDelete); + + function stopOrDelete(searchContent) { + // stop here + if (searchContent.nbHits === 0) { + // return indexObj.as._request.resolve(); + return searchContent; + } + + // continue and do a recursive call + var objectIDs = map(searchContent.hits, function getObjectID(object) { + return object.objectID; + }); + + return indexObj + .deleteObjects(objectIDs) + .then(waitTask) + .then(doDeleteByQuery); + } + + function waitTask(deleteObjectsContent) { + return indexObj.waitTask(deleteObjectsContent.taskID); + } + + function doDeleteByQuery() { + return indexObj.deleteByQuery(query, params); + } + + if (!callback) { + return promise; + } + + promise.then(success, failure); + + function success() { + exitPromise(function exit() { + callback(null); + }, client._setTimeout || setTimeout); + } + + function failure(err) { + exitPromise(function exit() { + callback(err); + }, client._setTimeout || setTimeout); + } +}, deprecatedMessage('index.deleteByQuery()', 'index.deleteBy()')); + +/** +* Delete all objects matching a query +* +* the query parameters that can be used are: +* - filters (numeric, facet, tag) +* - geo +* +* you can not send an empty query or filters +* +* @param params the optional query parameters +* @param callback (optional) the result callback called with one argument +* error: null or Error('message') +*/ +Index.prototype.deleteBy = function(params, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/deleteByQuery', + body: {params: indexObj.as._getSearchParams(params, '')}, + hostType: 'write', + callback: callback + }); +}; + +/* +* Browse all content from an index using events. Basically this will do +* .browse() -> .browseFrom -> .browseFrom -> .. until all the results are returned +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @return {EventEmitter} +* @example +* var browser = index.browseAll('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }); +* +* browser.on('result', function resultCallback(content) { +* console.log(content.hits); +* }); +* +* // if any error occurs, you get it +* browser.on('error', function(err) { +* throw err; +* }); +* +* // when you have browsed the whole index, you get this event +* browser.on('end', function() { +* console.log('finished'); +* }); +* +* // at any point if you want to stop the browsing process, you can stop it manually +* // otherwise it will go on and on +* browser.stop(); +* +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +Index.prototype.browseAll = function(query, queryParameters) { + if (typeof query === 'object') { + queryParameters = query; + query = undefined; + } + + var merge = require(32); + + var IndexBrowser = require(17); + + var browser = new IndexBrowser(); + var client = this.as; + var index = this; + var params = client._getSearchParams( + merge({}, queryParameters || {}, { + query: query + }), '' + ); + + // start browsing + browseLoop(); + + function browseLoop(cursor) { + if (browser._stopped) { + return; + } + + var body; + + if (cursor !== undefined) { + body = { + cursor: cursor + }; + } else { + body = { + params: params + }; + } + + client._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(index.indexName) + '/browse', + hostType: 'read', + body: body, + callback: browseCallback + }); + } + + function browseCallback(err, content) { + if (browser._stopped) { + return; + } + + if (err) { + browser._error(err); + return; + } + + browser._result(content); + + // no cursor means we are finished browsing + if (content.cursor === undefined) { + browser._end(); + return; + } + + browseLoop(content.cursor); + } + + return browser; +}; + +/* +* Get a Typeahead.js adapter +* @param searchParams contains an object with query parameters (see search for details) +*/ +Index.prototype.ttAdapter = deprecate(function(params) { + var self = this; + return function ttAdapter(query, syncCb, asyncCb) { + var cb; + + if (typeof asyncCb === 'function') { + // typeahead 0.11 + cb = asyncCb; + } else { + // pre typeahead 0.11 + cb = syncCb; + } + + self.search(query, params, function searchDone(err, content) { + if (err) { + cb(err); + return; + } + + cb(content.hits); + }); + }; +}, +'ttAdapter is not necessary anymore and will be removed in the next version,\n' + +'have a look at autocomplete.js (https://github.com/algolia/autocomplete.js)'); + +/* +* Wait the publication of a task on the server. +* All server task are asynchronous and you can check with this method that the task is published. +* +* @param taskID the id of the task returned by server +* @param callback the result callback with with two arguments: +* error: null or Error('message') +* content: the server answer that contains the list of results +*/ +Index.prototype.waitTask = function(taskID, callback) { + // wait minimum 100ms before retrying + var baseDelay = 100; + // wait maximum 5s before retrying + var maxDelay = 5000; + var loop = 0; + + // waitTask() must be handled differently from other methods, + // it's a recursive method using a timeout + var indexObj = this; + var client = indexObj.as; + + var promise = retryLoop(); + + function retryLoop() { + return client._jsonRequest({ + method: 'GET', + hostType: 'read', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/task/' + taskID + }).then(function success(content) { + loop++; + var delay = baseDelay * loop * loop; + if (delay > maxDelay) { + delay = maxDelay; + } + + if (content.status !== 'published') { + return client._promise.delay(delay).then(retryLoop); + } + + return content; + }); + } + + if (!callback) { + return promise; + } + + promise.then(successCb, failureCb); + + function successCb(content) { + exitPromise(function exit() { + callback(null, content); + }, client._setTimeout || setTimeout); + } + + function failureCb(err) { + exitPromise(function exit() { + callback(err); + }, client._setTimeout || setTimeout); + } +}; + +/* +* This function deletes the index content. Settings and index specific API keys are kept untouched. +* +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the settings object or the error message if a failure occured +*/ +Index.prototype.clearIndex = function(callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/clear', + hostType: 'write', + callback: callback + }); +}; + +/* +* Get settings of this index +* +* @param opts an object of options to add +* @param opts.advanced get more settings like nbShards (useful for Enterprise) +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the settings object or the error message if a failure occurred +*/ +Index.prototype.getSettings = function(opts, callback) { + if (arguments.length === 1 && typeof opts === 'function') { + callback = opts; + opts = {}; + } + opts = opts || {}; + + var indexName = encodeURIComponent(this.indexName); + return this.as._jsonRequest({ + method: 'GET', + url: + '/1/indexes/' + + indexName + + '/settings?getVersion=2' + + (opts.advanced ? '&advanced=' + opts.advanced : ''), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.searchSynonyms = function(params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } else if (params === undefined) { + params = {}; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/search', + body: params, + hostType: 'read', + callback: callback + }); +}; + +function exportData(method, _hitsPerPage, callback) { + function search(page, _previous) { + var options = { + page: page || 0, + hitsPerPage: _hitsPerPage || 100 + }; + var previous = _previous || []; + + return method(options).then(function(result) { + var hits = result.hits; + var nbHits = result.nbHits; + var current = hits.map(function(s) { + delete s._highlightResult; + return s; + }); + var synonyms = previous.concat(current); + if (synonyms.length < nbHits) { + return search(options.page + 1, synonyms); + } + return synonyms; + }); + } + return search().then(function(data) { + if (typeof callback === 'function') { + callback(data); + return undefined; + } + return data; + }); +} + +/** + * Retrieve all the synonyms in an index + * @param [number=100] hitsPerPage The amount of synonyms to retrieve per batch + * @param [function] callback will be called after all synonyms are retrieved + */ +Index.prototype.exportSynonyms = function(hitsPerPage, callback) { + return exportData(this.searchSynonyms.bind(this), hitsPerPage, callback); +}; + +Index.prototype.saveSynonym = function(synonym, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(synonym.objectID) + + '?forwardToReplicas=' + forwardToReplicas, + body: synonym, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.getSynonym = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.deleteSynonym = function(objectID, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID) + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.clearSynonyms = function(opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/clear' + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.batchSynonyms = function(synonyms, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/batch' + + '?forwardToReplicas=' + forwardToReplicas + + '&replaceExistingSynonyms=' + (opts.replaceExistingSynonyms ? 'true' : 'false'), + hostType: 'write', + body: synonyms, + callback: callback + }); +}; + +Index.prototype.searchRules = function(params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } else if (params === undefined) { + params = {}; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/search', + body: params, + hostType: 'read', + callback: callback + }); +}; +/** + * Retrieve all the query rules in an index + * @param [number=100] hitsPerPage The amount of query rules to retrieve per batch + * @param [function] callback will be called after all query rules are retrieved + * error: null or Error('message') + */ +Index.prototype.exportRules = function(hitsPerPage, callback) { + return exportData(this.searchRules.bind(this), hitsPerPage, callback); +}; + +Index.prototype.saveRule = function(rule, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (!rule.objectID) { + throw new errors.AlgoliaSearchError('Missing or empty objectID field for rule'); + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(rule.objectID) + + '?forwardToReplicas=' + forwardToReplicas, + body: rule, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.getRule = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.deleteRule = function(objectID, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID) + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.clearRules = function(opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/clear' + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.batchRules = function(rules, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/batch' + + '?forwardToReplicas=' + forwardToReplicas + + '&clearExistingRules=' + (opts.clearExistingRules === true ? 'true' : 'false'), + hostType: 'write', + body: rules, + callback: callback + }); +}; + +/* +* Set settings for this index +* +* @param settigns the settings object that can contains : +* - minWordSizefor1Typo: (integer) the minimum number of characters to accept one typo (default = 3). +* - minWordSizefor2Typos: (integer) the minimum number of characters to accept two typos (default = 7). +* - hitsPerPage: (integer) the number of hits per page (default = 10). +* - attributesToRetrieve: (array of strings) default list of attributes to retrieve in objects. +* If set to null, all attributes are retrieved. +* - attributesToHighlight: (array of strings) default list of attributes to highlight. +* If set to null, all indexed attributes are highlighted. +* - attributesToSnippet**: (array of strings) default list of attributes to snippet alongside the number +* of words to return (syntax is attributeName:nbWords). +* By default no snippet is computed. If set to null, no snippet is computed. +* - attributesToIndex: (array of strings) the list of fields you want to index. +* If set to null, all textual and numerical attributes of your objects are indexed, +* but you should update it to get optimal results. +* This parameter has two important uses: +* - Limit the attributes to index: For example if you store a binary image in base64, +* you want to store it and be able to +* retrieve it but you don't want to search in the base64 string. +* - Control part of the ranking*: (see the ranking parameter for full explanation) +* Matches in attributes at the beginning of +* the list will be considered more important than matches in attributes further down the list. +* In one attribute, matching text at the beginning of the attribute will be +* considered more important than text after, you can disable +* this behavior if you add your attribute inside `unordered(AttributeName)`, +* for example attributesToIndex: ["title", "unordered(text)"]. +* - attributesForFaceting: (array of strings) The list of fields you want to use for faceting. +* All strings in the attribute selected for faceting are extracted and added as a facet. +* If set to null, no attribute is used for faceting. +* - attributeForDistinct: (string) The attribute name used for the Distinct feature. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in query with the distinct=1 parameter, all hits containing a duplicate +* value for this attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best one is kept and others are removed. +* - ranking: (array of strings) controls the way results are sorted. +* We have six available criteria: +* - typo: sort according to number of typos, +* - geo: sort according to decreassing distance when performing a geo-location based search, +* - proximity: sort according to the proximity of query words in hits, +* - attribute: sort according to the order of attributes defined by attributesToIndex, +* - exact: +* - if the user query contains one word: sort objects having an attribute +* that is exactly the query word before others. +* For example if you search for the "V" TV show, you want to find it +* with the "V" query and avoid to have all popular TV +* show starting by the v letter before it. +* - if the user query contains multiple words: sort according to the +* number of words that matched exactly (and not as a prefix). +* - custom: sort according to a user defined formula set in **customRanking** attribute. +* The standard order is ["typo", "geo", "proximity", "attribute", "exact", "custom"] +* - customRanking: (array of strings) lets you specify part of the ranking. +* The syntax of this condition is an array of strings containing attributes +* prefixed by asc (ascending order) or desc (descending order) operator. +* For example `"customRanking" => ["desc(population)", "asc(name)"]` +* - queryType: Select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - highlightPreTag: (string) Specify the string that is inserted before +* the highlighted parts in the query result (default to "<em>"). +* - highlightPostTag: (string) Specify the string that is inserted after +* the highlighted parts in the query result (default to "</em>"). +* - optionalWords: (array of strings) Specify a list of words that should +* be considered as optional when found in the query. +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the server answer or the error message if a failure occured +*/ +Index.prototype.setSettings = function(settings, opts, callback) { + if (arguments.length === 1 || typeof opts === 'function') { + callback = opts; + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + var indexObj = this; + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings?forwardToReplicas=' + + forwardToReplicas, + hostType: 'write', + body: settings, + callback: callback + }); +}; + +/* +* @deprecated see client.listApiKeys() +*/ +Index.prototype.listUserKeys = deprecate(function(callback) { + return this.listApiKeys(callback); +}, deprecatedMessage('index.listUserKeys()', 'client.listApiKeys()')); + +/* +* List all existing API keys to this index +* +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with API keys belonging to the index +* +* @deprecated see client.listApiKeys() +*/ +Index.prototype.listApiKeys = deprecate(function(callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys', + hostType: 'read', + callback: callback + }); +}, deprecatedMessage('index.listApiKeys()', 'client.listApiKeys()')); + +/* +* @deprecated see client.getApiKey() +*/ +Index.prototype.getUserKeyACL = deprecate(function(key, callback) { + return this.getApiKey(key, callback); +}, deprecatedMessage('index.getUserKeyACL()', 'client.getApiKey()')); + + +/* +* Get an API key from this index +* +* @param key +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the right API key +* +* @deprecated see client.getApiKey() +*/ +Index.prototype.getApiKey = deprecate(function(key, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, + hostType: 'read', + callback: callback + }); +}, deprecatedMessage('index.getApiKey()', 'client.getApiKey()')); + +/* +* @deprecated see client.deleteApiKey() +*/ +Index.prototype.deleteUserKey = deprecate(function(key, callback) { + return this.deleteApiKey(key, callback); +}, deprecatedMessage('index.deleteUserKey()', 'client.deleteApiKey()')); + +/* +* Delete an existing API key associated to this index +* +* @param key +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the deletion date +* +* @deprecated see client.deleteApiKey() +*/ +Index.prototype.deleteApiKey = deprecate(function(key, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.deleteApiKey()', 'client.deleteApiKey()')); + +/* +* @deprecated see client.addApiKey() +*/ +Index.prototype.addUserKey = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('index.addUserKey()', 'client.addApiKey()')); + +/* +* Add a new API key to this index +* +* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that +* can contains the following values: +* - search: allow to search (https and http) +* - addObject: allows to add/update an object in the index (https only) +* - deleteObject : allows to delete an existing object (https only) +* - deleteIndex : allows to delete index content (https only) +* - settings : allows to get index settings (https only) +* - editSettings : allows to change index settings (https only) +* @param {Object} [params] - Optionnal parameters to set for the key +* @param {number} params.validity - Number of seconds after which the key will +* be automatically removed (0 means no time limit for this key) +* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour +* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call +* @param {string} params.description - A description for your key +* @param {string[]} params.referers - A list of authorized referers +* @param {Object} params.queryParameters - Force the key to use specific query parameters +* @param {Function} callback - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the added API key +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.addUserKey(['search'], { +* validity: 300, +* maxQueriesPerIPPerHour: 2000, +* maxHitsPerQuery: 3, +* description: 'Eat three fruits', +* referers: ['*.algolia.com'], +* queryParameters: { +* tagFilters: ['public'], +* } +* }) +* @see {@link https://www.algolia.com/doc/rest_api#AddIndexKey|Algolia REST API Documentation} +* +* @deprecated see client.addApiKey() +*/ +Index.prototype.addApiKey = deprecate(function(acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: index.addApiKey(arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = null; + } + + var postObj = { + acl: acls + }; + + if (params) { + postObj.validity = params.validity; + postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + postObj.maxHitsPerQuery = params.maxHitsPerQuery; + postObj.description = params.description; + + if (params.queryParameters) { + postObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); + } + + postObj.referers = params.referers; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys', + body: postObj, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.addApiKey()', 'client.addApiKey()')); + +/** +* @deprecated use client.addApiKey() +*/ +Index.prototype.addUserKeyWithValidity = deprecate(function deprecatedAddUserKeyWithValidity(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('index.addUserKeyWithValidity()', 'client.addApiKey()')); + +/* +* @deprecated see client.updateApiKey() +*/ +Index.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { + return this.updateApiKey(key, acls, params, callback); +}, deprecatedMessage('index.updateUserKey()', 'client.updateApiKey()')); + +/** +* Update an existing API key of this index +* @param {string} key - The key to update +* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that +* can contains the following values: +* - search: allow to search (https and http) +* - addObject: allows to add/update an object in the index (https only) +* - deleteObject : allows to delete an existing object (https only) +* - deleteIndex : allows to delete index content (https only) +* - settings : allows to get index settings (https only) +* - editSettings : allows to change index settings (https only) +* @param {Object} [params] - Optionnal parameters to set for the key +* @param {number} params.validity - Number of seconds after which the key will +* be automatically removed (0 means no time limit for this key) +* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour +* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call +* @param {string} params.description - A description for your key +* @param {string[]} params.referers - A list of authorized referers +* @param {Object} params.queryParameters - Force the key to use specific query parameters +* @param {Function} callback - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with user keys list +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.updateApiKey('APIKEY', ['search'], { +* validity: 300, +* maxQueriesPerIPPerHour: 2000, +* maxHitsPerQuery: 3, +* description: 'Eat three fruits', +* referers: ['*.algolia.com'], +* queryParameters: { +* tagFilters: ['public'], +* } +* }) +* @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} +* +* @deprecated see client.updateApiKey() +*/ +Index.prototype.updateApiKey = deprecate(function(key, acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: index.updateApiKey(key, arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 2 || typeof params === 'function') { + callback = params; + params = null; + } + + var putObj = { + acl: acls + }; + + if (params) { + putObj.validity = params.validity; + putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + putObj.maxHitsPerQuery = params.maxHitsPerQuery; + putObj.description = params.description; + + if (params.queryParameters) { + putObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); + } + + putObj.referers = params.referers; + } + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys/' + key, + body: putObj, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.updateApiKey()', 'client.updateApiKey()')); + +},{"17":17,"18":18,"25":25,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"7":7,"8":8}],17:[function(require,module,exports){ +'use strict'; + +// This is the object returned by the `index.browseAll()` method + +module.exports = IndexBrowser; + +var inherits = require(7); +var EventEmitter = require(4).EventEmitter; + +function IndexBrowser() { +} + +inherits(IndexBrowser, EventEmitter); + +IndexBrowser.prototype.stop = function() { + this._stopped = true; + this._clean(); +}; + +IndexBrowser.prototype._end = function() { + this.emit('end'); + this._clean(); +}; + +IndexBrowser.prototype._error = function(err) { + this.emit('error', err); + this._clean(); +}; + +IndexBrowser.prototype._result = function(content) { + this.emit('result', content); +}; + +IndexBrowser.prototype._clean = function() { + this.removeAllListeners('stop'); + this.removeAllListeners('end'); + this.removeAllListeners('error'); + this.removeAllListeners('result'); +}; + +},{"4":4,"7":7}],18:[function(require,module,exports){ +var buildSearchMethod = require(24); +var deprecate = require(27); +var deprecatedMessage = require(28); + +module.exports = IndexCore; + +/* +* Index class constructor. +* You should not use this method directly but use initIndex() function +*/ +function IndexCore(algoliasearch, indexName) { + this.indexName = indexName; + this.as = algoliasearch; + this.typeAheadArgs = null; + this.typeAheadValueOption = null; + + // make sure every index instance has it's own cache + this.cache = {}; +} + +/* +* Clear all queries in cache +*/ +IndexCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/* +* Search inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the full text query +* @param {object} [args] (optional) if set, contains an object with query parameters: +* - page: (integer) Pagination parameter used to select the page to retrieve. +* Page is zero-based and defaults to 0. Thus, +* to retrieve the 10th page you need to set page=9 +* - hitsPerPage: (integer) Pagination parameter used to select the number of hits per page. Defaults to 20. +* - attributesToRetrieve: a string that contains the list of object attributes +* you want to retrieve (let you minimize the answer size). +* Attributes are separated with a comma (for example "name,address"). +* You can also use an array (for example ["name","address"]). +* By default, all attributes are retrieved. You can also use '*' to retrieve all +* values when an attributesToRetrieve setting is specified for your index. +* - attributesToHighlight: a string that contains the list of attributes you +* want to highlight according to the query. +* Attributes are separated by a comma. You can also use an array (for example ["name","address"]). +* If an attribute has no match for the query, the raw value is returned. +* By default all indexed text attributes are highlighted. +* You can use `*` if you want to highlight all textual attributes. +* Numerical attributes are not highlighted. +* A matchLevel is returned for each highlighted attribute and can contain: +* - full: if all the query terms were found in the attribute, +* - partial: if only some of the query terms were found, +* - none: if none of the query terms were found. +* - attributesToSnippet: a string that contains the list of attributes to snippet alongside +* the number of words to return (syntax is `attributeName:nbWords`). +* Attributes are separated by a comma (Example: attributesToSnippet=name:10,content:10). +* You can also use an array (Example: attributesToSnippet: ['name:10','content:10']). +* By default no snippet is computed. +* - minWordSizefor1Typo: the minimum number of characters in a query word to accept one typo in this word. +* Defaults to 3. +* - minWordSizefor2Typos: the minimum number of characters in a query word +* to accept two typos in this word. Defaults to 7. +* - getRankingInfo: if set to 1, the result hits will contain ranking +* information in _rankingInfo attribute. +* - aroundLatLng: search for entries around a given +* latitude/longitude (specified as two floats separated by a comma). +* For example aroundLatLng=47.316669,5.016670). +* You can specify the maximum distance in meters with the aroundRadius parameter (in meters) +* and the precision for ranking with aroundPrecision +* (for example if you set aroundPrecision=100, two objects that are distant of +* less than 100m will be considered as identical for "geo" ranking parameter). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - insideBoundingBox: search entries inside a given area defined by the two extreme points +* of a rectangle (defined by 4 floats: p1Lat,p1Lng,p2Lat,p2Lng). +* For example insideBoundingBox=47.3165,4.9665,47.3424,5.0201). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - numericFilters: a string that contains the list of numeric filters you want to +* apply separated by a comma. +* The syntax of one filter is `attributeName` followed by `operand` followed by `value`. +* Supported operands are `<`, `<=`, `=`, `>` and `>=`. +* You can have multiple conditions on one attribute like for example numericFilters=price>100,price<1000. +* You can also use an array (for example numericFilters: ["price>100","price<1000"]). +* - tagFilters: filter the query by a set of tags. You can AND tags by separating them by commas. +* To OR tags, you must add parentheses. For example, tags=tag1,(tag2,tag3) means tag1 AND (tag2 OR tag3). +* You can also use an array, for example tagFilters: ["tag1",["tag2","tag3"]] +* means tag1 AND (tag2 OR tag3). +* At indexing, tags should be added in the _tags** attribute +* of objects (for example {"_tags":["tag1","tag2"]}). +* - facetFilters: filter the query by a list of facets. +* Facets are separated by commas and each facet is encoded as `attributeName:value`. +* For example: `facetFilters=category:Book,author:John%20Doe`. +* You can also use an array (for example `["category:Book","author:John%20Doe"]`). +* - facets: List of object attributes that you want to use for faceting. +* Comma separated list: `"category,author"` or array `['category','author']` +* Only attributes that have been added in **attributesForFaceting** index setting +* can be used in this parameter. +* You can also use `*` to perform faceting on all attributes specified in **attributesForFaceting**. +* - queryType: select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - optionalWords: a string that contains the list of words that should +* be considered as optional when found in the query. +* Comma separated and array are accepted. +* - distinct: If set to 1, enable the distinct feature (disabled by default) +* if the attributeForDistinct index setting is set. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in a query with the distinct=1 parameter, +* all hits containing a duplicate value for the attributeForDistinct attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best +* one is kept and others are removed. +* - restrictSearchableAttributes: List of attributes you want to use for +* textual search (must be a subset of the attributesToIndex index setting) +* either comma separated or as an array +* @param {function} [callback] the result callback called with two arguments: +* error: null or Error('message'). If false, the content contains the error. +* content: the server answer that contains the list of results. +*/ +IndexCore.prototype.search = buildSearchMethod('query'); + +/* +* -- BETA -- +* Search a record similar to the query inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the similar query +* @param {object} [args] (optional) if set, contains an object with query parameters. +* All search parameters are supported (see search function), restrictSearchableAttributes and facetFilters +* are the two most useful to restrict the similar results and get more relevant content +*/ +IndexCore.prototype.similarSearch = buildSearchMethod('similarQuery'); + +/* +* Browse index content. The response content will have a `cursor` property that you can use +* to browse subsequent pages for this query. Use `index.browseFrom(cursor)` when you want. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browse('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }, callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browse = function(query, queryParameters, callback) { + var merge = require(32); + + var indexObj = this; + + var page; + var hitsPerPage; + + // we check variadic calls that are not the one defined + // .browse()/.browse(fn) + // => page = 0 + if (arguments.length === 0 || arguments.length === 1 && typeof arguments[0] === 'function') { + page = 0; + callback = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'number') { + // .browse(2)/.browse(2, 10)/.browse(2, fn)/.browse(2, 10, fn) + page = arguments[0]; + if (typeof arguments[1] === 'number') { + hitsPerPage = arguments[1]; + } else if (typeof arguments[1] === 'function') { + callback = arguments[1]; + hitsPerPage = undefined; + } + query = undefined; + queryParameters = undefined; + } else if (typeof arguments[0] === 'object') { + // .browse(queryParameters)/.browse(queryParameters, cb) + if (typeof arguments[1] === 'function') { + callback = arguments[1]; + } + queryParameters = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') { + // .browse(query, cb) + callback = arguments[1]; + queryParameters = undefined; + } + + // otherwise it's a .browse(query)/.browse(query, queryParameters)/.browse(query, queryParameters, cb) + + // get search query parameters combining various possible calls + // to .browse(); + queryParameters = merge({}, queryParameters || {}, { + page: page, + hitsPerPage: hitsPerPage, + query: query + }); + + var params = this.as._getSearchParams(queryParameters, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse', + body: {params: params}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Continue browsing from a previous position (cursor), obtained via a call to `.browse()`. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browseFrom('14lkfsakl32', callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browseFrom = function(cursor, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/browse', + body: {cursor: cursor}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* +* @param {string} params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} params.facetQuery Query for the facet search +* @param {string} [params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +* @param callback (optional) +*/ +IndexCore.prototype.searchForFacetValues = function(params, callback) { + var clone = require(25); + var omit = require(33); + var usage = 'Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])'; + + if (params.facetName === undefined || params.facetQuery === undefined) { + throw new Error(usage); + } + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = this.as._getSearchParams(filteredParams, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + + encodeURIComponent(this.indexName) + '/facets/' + encodeURIComponent(facetName) + '/query', + hostType: 'read', + body: {params: searchParameters}, + callback: callback + }); +}; + +IndexCore.prototype.searchFacet = deprecate(function(params, callback) { + return this.searchForFacetValues(params, callback); +}, deprecatedMessage( + 'index.searchFacet(params[, callback])', + 'index.searchForFacetValues(params[, callback])' +)); + +IndexCore.prototype._search = function(params, url, callback, additionalUA) { + return this.as._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url || '/1/indexes/' + encodeURIComponent(this.indexName) + '/query', + body: {params: params}, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName), + body: {params: params} + }, + callback: callback, + additionalUA: additionalUA + }); +}; + +/* +* Get an object from this index +* +* @param objectID the unique identifier of the object to retrieve +* @param attrs (optional) if set, contains the array of attribute names to retrieve +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the object to retrieve or the error message if a failure occured +*/ +IndexCore.prototype.getObject = function(objectID, attrs, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof attrs === 'function') { + callback = attrs; + attrs = undefined; + } + + var params = ''; + if (attrs !== undefined) { + params = '?attributes='; + for (var i = 0; i < attrs.length; ++i) { + if (i !== 0) { + params += ','; + } + params += attrs[i]; + } + } + + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID) + params, + hostType: 'read', + callback: callback + }); +}; + +/* +* Get several objects from this index +* +* @param objectIDs the array of unique identifier of objects to retrieve +*/ +IndexCore.prototype.getObjects = function(objectIDs, attributesToRetrieve, callback) { + var isArray = require(8); + var map = require(31); + + var usage = 'Usage: index.getObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + + if (arguments.length === 1 || typeof attributesToRetrieve === 'function') { + callback = attributesToRetrieve; + attributesToRetrieve = undefined; + } + + var body = { + requests: map(objectIDs, function prepareRequest(objectID) { + var request = { + indexName: indexObj.indexName, + objectID: objectID + }; + + if (attributesToRetrieve) { + request.attributesToRetrieve = attributesToRetrieve.join(','); + } + + return request; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/objects', + hostType: 'read', + body: body, + callback: callback + }); +}; + +IndexCore.prototype.as = null; +IndexCore.prototype.indexName = null; +IndexCore.prototype.typeAheadArgs = null; +IndexCore.prototype.typeAheadValueOption = null; + +},{"24":24,"25":25,"27":27,"28":28,"31":31,"32":32,"33":33,"8":8}],19:[function(require,module,exports){ +(function (process){ +'use strict'; + +// This is the jQuery Algolia Search module +// It's using $.ajax to do requests with a JSONP fallback +// jQuery promises are returned + +var inherits = require(7); + +var AlgoliaSearch = require(14); +var errors = require(29); +var inlineHeaders = require(22); +var jsonpRequest = require(23); +var places = require(34); + +// expose original algoliasearch fn in window +window.algoliasearch = require(20); + +if (process.env.NODE_ENV === 'debug') { + require(1).enable('algoliasearch*'); +} + +function algoliasearch(applicationID, apiKey, opts) { + var cloneDeep = require(25); + + opts = cloneDeep(opts || {}); + + opts._ua = opts._ua || algoliasearch.ua; + + return new AlgoliaSearchJQuery(applicationID, apiKey, opts); +} + +algoliasearch.version = require(36); +algoliasearch.ua = 'Algolia for jQuery ' + algoliasearch.version; +algoliasearch.initPlaces = places(algoliasearch); + +// we expose into window no matter how we are used, this will allow +// us to easily debug any website running algolia +window.__algolia = { + debug: require(1), + algoliasearch: algoliasearch +}; + +var $ = window.jQuery; + +$.algolia = { + Client: algoliasearch, + ua: algoliasearch.ua, + version: algoliasearch.version +}; + +function AlgoliaSearchJQuery() { + // call AlgoliaSearch constructor + AlgoliaSearch.apply(this, arguments); +} + +inherits(AlgoliaSearchJQuery, AlgoliaSearch); + +AlgoliaSearchJQuery.prototype._request = function request(url, opts) { + return new $.Deferred(function(deferred) { + var body = opts.body; + + url = inlineHeaders(url, opts.headers); + + var requestHeaders = { + accept: 'application/json' + }; + + if (body) { + if (opts.method === 'POST') { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests + requestHeaders['content-type'] = 'application/x-www-form-urlencoded'; + } else { + requestHeaders['content-type'] = 'application/json'; + } + } + + $.ajax(url, { + type: opts.method, + timeout: opts.timeouts.complete, + dataType: 'json', + data: body, + headers: requestHeaders, + complete: function onComplete(jqXHR, textStatus/* , error*/) { + if (textStatus === 'timeout') { + deferred.reject(new errors.RequestTimeout()); + return; + } + + if (jqXHR.status === 0) { + deferred.reject( + new errors.Network({ + more: jqXHR + }) + ); + return; + } + + deferred.resolve({ + statusCode: jqXHR.status, + body: jqXHR.responseJSON, + responseText: jqXHR.responseText, + headers: jqXHR.getAllResponseHeaders() + }); + } + }); + }).promise(); +}; + +// using IE8 or IE9 we will always end up here +// jQuery does not not fallback to XDomainRequest +AlgoliaSearchJQuery.prototype._request.fallback = function requestFallback(url, opts) { + url = inlineHeaders(url, opts.headers); + + return new $.Deferred(function wrapJsonpRequest(deferred) { + jsonpRequest(url, opts, function jsonpRequestDone(err, content) { + if (err) { + deferred.reject(err); + return; + } + + deferred.resolve(content); + }); + }).promise(); +}; + +AlgoliaSearchJQuery.prototype._promise = { + reject: function reject(val) { + return new $.Deferred(function rejectDeferred(deferred) { + deferred.reject(val); + }).promise(); + }, + resolve: function resolve(val) { + return new $.Deferred(function resolveDeferred(deferred) { + deferred.resolve(val); + }).promise(); + }, + delay: function delay(ms) { + return new $.Deferred(function delayResolve(deferred) { + setTimeout(function resolveDeferred() { + deferred.resolve(); + }, ms); + }).promise(); + }, + all: function all(promises) { + return $.when.apply(null, promises); + } +}; + +}).call(this,require(12)) +},{"1":1,"12":12,"14":14,"20":20,"22":22,"23":23,"25":25,"29":29,"34":34,"36":36,"7":7}],20:[function(require,module,exports){ +'use strict'; + +var AlgoliaSearch = require(14); +var createAlgoliasearch = require(21); + +module.exports = createAlgoliasearch(AlgoliaSearch); + +},{"14":14,"21":21}],21:[function(require,module,exports){ +(function (process){ +'use strict'; + +var global = require(6); +var Promise = global.Promise || require(3).Promise; + +// This is the standalone browser build entry point +// Browser implementation of the Algolia Search JavaScript client, +// using XMLHttpRequest, XDomainRequest and JSONP as fallback +module.exports = function createAlgoliasearch(AlgoliaSearch, uaSuffix) { + var inherits = require(7); + var errors = require(29); + var inlineHeaders = require(22); + var jsonpRequest = require(23); + var places = require(34); + uaSuffix = uaSuffix || ''; + + if (process.env.NODE_ENV === 'debug') { + require(1).enable('algoliasearch*'); + } + + function algoliasearch(applicationID, apiKey, opts) { + var cloneDeep = require(25); + + opts = cloneDeep(opts || {}); + + opts._ua = opts._ua || algoliasearch.ua; + + return new AlgoliaSearchBrowser(applicationID, apiKey, opts); + } + + algoliasearch.version = require(36); + algoliasearch.ua = 'Algolia for vanilla JavaScript ' + uaSuffix + algoliasearch.version; + algoliasearch.initPlaces = places(algoliasearch); + + // we expose into window no matter how we are used, this will allow + // us to easily debug any website running algolia + global.__algolia = { + debug: require(1), + algoliasearch: algoliasearch + }; + + var support = { + hasXMLHttpRequest: 'XMLHttpRequest' in global, + hasXDomainRequest: 'XDomainRequest' in global + }; + + if (support.hasXMLHttpRequest) { + support.cors = 'withCredentials' in new XMLHttpRequest(); + } + + function AlgoliaSearchBrowser() { + // call AlgoliaSearch constructor + AlgoliaSearch.apply(this, arguments); + } + + inherits(AlgoliaSearchBrowser, AlgoliaSearch); + + AlgoliaSearchBrowser.prototype._request = function request(url, opts) { + return new Promise(function wrapRequest(resolve, reject) { + // no cors or XDomainRequest, no request + if (!support.cors && !support.hasXDomainRequest) { + // very old browser, not supported + reject(new errors.Network('CORS not supported')); + return; + } + + url = inlineHeaders(url, opts.headers); + + var body = opts.body; + var req = support.cors ? new XMLHttpRequest() : new XDomainRequest(); + var reqTimeout; + var timedOut; + var connected = false; + + reqTimeout = setTimeout(onTimeout, opts.timeouts.connect); + // we set an empty onprogress listener + // so that XDomainRequest on IE9 is not aborted + // refs: + // - https://github.com/algolia/algoliasearch-client-js/issues/76 + // - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment + req.onprogress = onProgress; + if ('onreadystatechange' in req) req.onreadystatechange = onReadyStateChange; + req.onload = onLoad; + req.onerror = onError; + + // do not rely on default XHR async flag, as some analytics code like hotjar + // breaks it and set it to false by default + if (req instanceof XMLHttpRequest) { + req.open(opts.method, url, true); + + // The Analytics API never accepts Auth headers as query string + // this option exists specifically for them. + if (opts.forceAuthHeaders) { + req.setRequestHeader( + 'x-algolia-application-id', + opts.headers['x-algolia-application-id'] + ); + req.setRequestHeader( + 'x-algolia-api-key', + opts.headers['x-algolia-api-key'] + ); + } + } else { + req.open(opts.method, url); + } + + // headers are meant to be sent after open + if (support.cors) { + if (body) { + if (opts.method === 'POST') { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests + req.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); + } else { + req.setRequestHeader('content-type', 'application/json'); + } + } + req.setRequestHeader('accept', 'application/json'); + } + + if (body) { + req.send(body); + } else { + req.send(); + } + + // event object not received in IE8, at least + // but we do not use it, still important to note + function onLoad(/* event */) { + // When browser does not supports req.timeout, we can + // have both a load and timeout event, since handled by a dumb setTimeout + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + var out; + + try { + out = { + body: JSON.parse(req.responseText), + responseText: req.responseText, + statusCode: req.status, + // XDomainRequest does not have any response headers + headers: req.getAllResponseHeaders && req.getAllResponseHeaders() || {} + }; + } catch (e) { + out = new errors.UnparsableJSON({ + more: req.responseText + }); + } + + if (out instanceof errors.UnparsableJSON) { + reject(out); + } else { + resolve(out); + } + } + + function onError(event) { + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + // error event is trigerred both with XDR/XHR on: + // - DNS error + // - unallowed cross domain request + reject( + new errors.Network({ + more: event + }) + ); + } + + function onTimeout() { + timedOut = true; + req.abort(); + + reject(new errors.RequestTimeout()); + } + + function onConnect() { + connected = true; + clearTimeout(reqTimeout); + reqTimeout = setTimeout(onTimeout, opts.timeouts.complete); + } + + function onProgress() { + if (!connected) onConnect(); + } + + function onReadyStateChange() { + if (!connected && req.readyState > 1) onConnect(); + } + }); + }; + + AlgoliaSearchBrowser.prototype._request.fallback = function requestFallback(url, opts) { + url = inlineHeaders(url, opts.headers); + + return new Promise(function wrapJsonpRequest(resolve, reject) { + jsonpRequest(url, opts, function jsonpRequestDone(err, content) { + if (err) { + reject(err); + return; + } + + resolve(content); + }); + }); + }; + + AlgoliaSearchBrowser.prototype._promise = { + reject: function rejectPromise(val) { + return Promise.reject(val); + }, + resolve: function resolvePromise(val) { + return Promise.resolve(val); + }, + delay: function delayPromise(ms) { + return new Promise(function resolveOnTimeout(resolve/* , reject*/) { + setTimeout(resolve, ms); + }); + }, + all: function all(promises) { + return Promise.all(promises); + } + }; + + return algoliasearch; +}; + +}).call(this,require(12)) +},{"1":1,"12":12,"22":22,"23":23,"25":25,"29":29,"3":3,"34":34,"36":36,"6":6,"7":7}],22:[function(require,module,exports){ +'use strict'; + +module.exports = inlineHeaders; + +var encode = require(13); + +function inlineHeaders(url, headers) { + if (/\?/.test(url)) { + url += '&'; + } else { + url += '?'; + } + + return url + encode(headers); +} + +},{"13":13}],23:[function(require,module,exports){ +'use strict'; + +module.exports = jsonpRequest; + +var errors = require(29); + +var JSONPCounter = 0; + +function jsonpRequest(url, opts, cb) { + if (opts.method !== 'GET') { + cb(new Error('Method ' + opts.method + ' ' + url + ' is not supported by JSONP.')); + return; + } + + opts.debug('JSONP: start'); + + var cbCalled = false; + var timedOut = false; + + JSONPCounter += 1; + var head = document.getElementsByTagName('head')[0]; + var script = document.createElement('script'); + var cbName = 'algoliaJSONP_' + JSONPCounter; + var done = false; + + window[cbName] = function(data) { + removeGlobals(); + + if (timedOut) { + opts.debug('JSONP: Late answer, ignoring'); + return; + } + + cbCalled = true; + + clean(); + + cb(null, { + body: data, + responseText: JSON.stringify(data)/* , + // We do not send the statusCode, there's no statusCode in JSONP, it will be + // computed using data.status && data.message like with XDR + statusCode*/ + }); + }; + + // add callback by hand + url += '&callback=' + cbName; + + // add body params manually + if (opts.jsonBody && opts.jsonBody.params) { + url += '&' + opts.jsonBody.params; + } + + var ontimeout = setTimeout(timeout, opts.timeouts.complete); + + // script onreadystatechange needed only for + // <= IE8 + // https://github.com/angular/angular.js/issues/4523 + script.onreadystatechange = readystatechange; + script.onload = success; + script.onerror = error; + + script.async = true; + script.defer = true; + script.src = url; + head.appendChild(script); + + function success() { + opts.debug('JSONP: success'); + + if (done || timedOut) { + return; + } + + done = true; + + // script loaded but did not call the fn => script loading error + if (!cbCalled) { + opts.debug('JSONP: Fail. Script loaded but did not call the callback'); + clean(); + cb(new errors.JSONPScriptFail()); + } + } + + function readystatechange() { + if (this.readyState === 'loaded' || this.readyState === 'complete') { + success(); + } + } + + function clean() { + clearTimeout(ontimeout); + script.onload = null; + script.onreadystatechange = null; + script.onerror = null; + head.removeChild(script); + } + + function removeGlobals() { + try { + delete window[cbName]; + delete window[cbName + '_loaded']; + } catch (e) { + window[cbName] = window[cbName + '_loaded'] = undefined; + } + } + + function timeout() { + opts.debug('JSONP: Script timeout'); + timedOut = true; + clean(); + cb(new errors.RequestTimeout()); + } + + function error() { + opts.debug('JSONP: Script error'); + + if (done || timedOut) { + return; + } + + clean(); + cb(new errors.JSONPScriptError()); + } +} + +},{"29":29}],24:[function(require,module,exports){ +module.exports = buildSearchMethod; + +var errors = require(29); + +/** + * Creates a search method to be used in clients + * @param {string} queryParam the name of the attribute used for the query + * @param {string} url the url + * @return {function} the search method + */ +function buildSearchMethod(queryParam, url) { + /** + * The search method. Prepares the data and send the query to Algolia. + * @param {string} query the string used for query search + * @param {object} args additional parameters to send with the search + * @param {function} [callback] the callback to be called with the client gets the answer + * @return {undefined|Promise} If the callback is not provided then this methods returns a Promise + */ + return function search(query, args, callback) { + // warn V2 users on how to search + if (typeof query === 'function' && typeof args === 'object' || + typeof callback === 'object') { + // .search(query, params, cb) + // .search(cb, params) + throw new errors.AlgoliaSearchError('index.search usage is index.search(query, params, cb)'); + } + + // Normalizing the function signature + if (arguments.length === 0 || typeof query === 'function') { + // Usage : .search(), .search(cb) + callback = query; + query = ''; + } else if (arguments.length === 1 || typeof args === 'function') { + // Usage : .search(query/args), .search(query, cb) + callback = args; + args = undefined; + } + // At this point we have 3 arguments with values + + // Usage : .search(args) // careful: typeof null === 'object' + if (typeof query === 'object' && query !== null) { + args = query; + query = undefined; + } else if (query === undefined || query === null) { // .search(undefined/null) + query = ''; + } + + var params = ''; + + if (query !== undefined) { + params += queryParam + '=' + encodeURIComponent(query); + } + + var additionalUA; + if (args !== undefined) { + if (args.additionalUA) { + additionalUA = args.additionalUA; + delete args.additionalUA; + } + // `_getSearchParams` will augment params, do not be fooled by the = versus += from previous if + params = this.as._getSearchParams(args, params); + } + + + return this._search(params, url, callback, additionalUA); + }; +} + +},{"29":29}],25:[function(require,module,exports){ +module.exports = function clone(obj) { + return JSON.parse(JSON.stringify(obj)); +}; + +},{}],26:[function(require,module,exports){ +module.exports = createAnalyticsClient; + +var algoliasearch = require(20); + +function createAnalyticsClient(appId, apiKey, opts) { + var analytics = {}; + + opts = opts || {}; + // there need to be 4 hosts, like on the client, since if requests fail, + // the counter goes up by 1, so we need to have the same amount of hosts + // 4 because: -dsn, -1, -2, -3 + // This is done because the APPID used for search will be the same for the analytics client created, + // and since the state of available hosts is shared by APPID globally for the module, we had issues + // where the hostIndex would be 1 while the array was only one entry (you got an empty host) + opts.hosts = opts.hosts || [ + 'analytics.algolia.com', + 'analytics.algolia.com', + 'analytics.algolia.com', + 'analytics.algolia.com' + ]; + opts.protocol = opts.protocol || 'https:'; + + analytics.as = algoliasearch(appId, apiKey, opts); + + analytics.getABTests = function(_params, callback) { + var params = params || {}; + var offset = params.offset || 0; + var limit = params.limit || 10; + + return this.as._jsonRequest({ + method: 'GET', + url: '/2/abtests?offset=' + encodeURIComponent(offset) + '&limit=' + encodeURIComponent(limit), + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.getABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/2/abtests/' + encodeURIComponent(abTestID), + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.addABTest = function(abTest, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/2/abtests', + body: abTest, + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.stopABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/2/abtests/' + encodeURIComponent(abTestID) + '/stop', + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.deleteABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'DELETE', + url: '/2/abtests/' + encodeURIComponent(abTestID), + hostType: 'write', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.waitTask = function(indexName, taskID, callback) { + return this.as.initIndex(indexName).waitTask(taskID, callback); + }; + + return analytics; +} + +},{"20":20}],27:[function(require,module,exports){ +module.exports = function deprecate(fn, message) { + var warned = false; + + function deprecated() { + if (!warned) { + /* eslint no-console:0 */ + console.warn(message); + warned = true; + } + + return fn.apply(this, arguments); + } + + return deprecated; +}; + +},{}],28:[function(require,module,exports){ +module.exports = function deprecatedMessage(previousUsage, newUsage) { + var githubAnchorLink = previousUsage.toLowerCase() + .replace(/[\.\(\)]/g, ''); + + return 'algoliasearch: `' + previousUsage + '` was replaced by `' + newUsage + + '`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#' + githubAnchorLink; +}; + +},{}],29:[function(require,module,exports){ +'use strict'; + +// This file hosts our error definitions +// We use custom error "types" so that we can act on them when we need it +// e.g.: if error instanceof errors.UnparsableJSON then.. + +var inherits = require(7); + +function AlgoliaSearchError(message, extraProperties) { + var forEach = require(5); + + var error = this; + + // try to get a stacktrace + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, this.constructor); + } else { + error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old'; + } + + this.name = 'AlgoliaSearchError'; + this.message = message || 'Unknown error'; + + if (extraProperties) { + forEach(extraProperties, function addToErrorObject(value, key) { + error[key] = value; + }); + } +} + +inherits(AlgoliaSearchError, Error); + +function createCustomError(name, message) { + function AlgoliaSearchCustomError() { + var args = Array.prototype.slice.call(arguments, 0); + + // custom message not set, use default + if (typeof args[0] !== 'string') { + args.unshift(message); + } + + AlgoliaSearchError.apply(this, args); + this.name = 'AlgoliaSearch' + name + 'Error'; + } + + inherits(AlgoliaSearchCustomError, AlgoliaSearchError); + + return AlgoliaSearchCustomError; +} + +// late exports to let various fn defs and inherits take place +module.exports = { + AlgoliaSearchError: AlgoliaSearchError, + UnparsableJSON: createCustomError( + 'UnparsableJSON', + 'Could not parse the incoming response as JSON, see err.more for details' + ), + RequestTimeout: createCustomError( + 'RequestTimeout', + 'Request timedout before getting a response' + ), + Network: createCustomError( + 'Network', + 'Network issue, see err.more for details' + ), + JSONPScriptFail: createCustomError( + 'JSONPScriptFail', + '<script> was loaded but did not call our provided callback' + ), + JSONPScriptError: createCustomError( + 'JSONPScriptError', + '<script> unable to load due to an `error` event on it' + ), + Unknown: createCustomError( + 'Unknown', + 'Unknown error occured' + ) +}; + +},{"5":5,"7":7}],30:[function(require,module,exports){ +// Parse cloud does not supports setTimeout +// We do not store a setTimeout reference in the client everytime +// We only fallback to a fake setTimeout when not available +// setTimeout cannot be override globally sadly +module.exports = function exitPromise(fn, _setTimeout) { + _setTimeout(fn, 0); +}; + +},{}],31:[function(require,module,exports){ +var foreach = require(5); + +module.exports = function map(arr, fn) { + var newArr = []; + foreach(arr, function(item, itemIndex) { + newArr.push(fn(item, itemIndex, arr)); + }); + return newArr; +}; + +},{"5":5}],32:[function(require,module,exports){ +var foreach = require(5); + +module.exports = function merge(destination/* , sources */) { + var sources = Array.prototype.slice.call(arguments); + + foreach(sources, function(source) { + for (var keyName in source) { + if (source.hasOwnProperty(keyName)) { + if (typeof destination[keyName] === 'object' && typeof source[keyName] === 'object') { + destination[keyName] = merge({}, destination[keyName], source[keyName]); + } else if (source[keyName] !== undefined) { + destination[keyName] = source[keyName]; + } + } + } + }); + + return destination; +}; + +},{"5":5}],33:[function(require,module,exports){ +module.exports = function omit(obj, test) { + var keys = require(10); + var foreach = require(5); + + var filtered = {}; + + foreach(keys(obj), function doFilter(keyName) { + if (test(keyName) !== true) { + filtered[keyName] = obj[keyName]; + } + }); + + return filtered; +}; + +},{"10":10,"5":5}],34:[function(require,module,exports){ +module.exports = createPlacesClient; + +var buildSearchMethod = require(24); + +function createPlacesClient(algoliasearch) { + return function places(appID, apiKey, opts) { + var cloneDeep = require(25); + + opts = opts && cloneDeep(opts) || {}; + opts.hosts = opts.hosts || [ + 'places-dsn.algolia.net', + 'places-1.algolianet.com', + 'places-2.algolianet.com', + 'places-3.algolianet.com' + ]; + + // allow initPlaces() no arguments => community rate limited + if (arguments.length === 0 || typeof appID === 'object' || appID === undefined) { + appID = ''; + apiKey = ''; + opts._allowEmptyCredentials = true; + } + + var client = algoliasearch(appID, apiKey, opts); + var index = client.initIndex('places'); + index.search = buildSearchMethod('query', '/1/places/query'); + index.getObject = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/places/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); + }; + return index; + }; +} + +},{"24":24,"25":25}],35:[function(require,module,exports){ +(function (global){ +var debug = require(1)('algoliasearch:src/hostIndexState.js'); +var localStorageNamespace = 'algoliasearch-client-js'; + +var store; +var moduleStore = { + state: {}, + set: function(key, data) { + this.state[key] = data; + return this.state[key]; + }, + get: function(key) { + return this.state[key] || null; + } +}; + +var localStorageStore = { + set: function(key, data) { + moduleStore.set(key, data); // always replicate localStorageStore to moduleStore in case of failure + + try { + var namespace = JSON.parse(global.localStorage[localStorageNamespace]); + namespace[key] = data; + global.localStorage[localStorageNamespace] = JSON.stringify(namespace); + return namespace[key]; + } catch (e) { + return localStorageFailure(key, e); + } + }, + get: function(key) { + try { + return JSON.parse(global.localStorage[localStorageNamespace])[key] || null; + } catch (e) { + return localStorageFailure(key, e); + } + } +}; + +function localStorageFailure(key, e) { + debug('localStorage failed with', e); + cleanup(); + store = moduleStore; + return store.get(key); +} + +store = supportsLocalStorage() ? localStorageStore : moduleStore; + +module.exports = { + get: getOrSet, + set: getOrSet, + supportsLocalStorage: supportsLocalStorage +}; + +function getOrSet(key, data) { + if (arguments.length === 1) { + return store.get(key); + } + + return store.set(key, data); +} + +function supportsLocalStorage() { + try { + if ('localStorage' in global && + global.localStorage !== null) { + if (!global.localStorage[localStorageNamespace]) { + // actual creation of the namespace + global.localStorage.setItem(localStorageNamespace, JSON.stringify({})); + } + return true; + } + + return false; + } catch (_) { + return false; + } +} + +// In case of any error on localStorage, we clean our own namespace, this should handle +// quota errors when a lot of keys + data are used +function cleanup() { + try { + global.localStorage.removeItem(localStorageNamespace); + } catch (_) { + // nothing to do + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"1":1}],36:[function(require,module,exports){ +'use strict'; + +module.exports = '3.30.0'; + +},{}]},{},[19]); diff --git a/node_modules/algoliasearch/dist/algoliasearch.jquery.min.js b/node_modules/algoliasearch/dist/algoliasearch.jquery.min.js new file mode 100644 index 00000000..80b54a98 --- /dev/null +++ b/node_modules/algoliasearch/dist/algoliasearch.jquery.min.js @@ -0,0 +1,4 @@ +/*! algoliasearch 3.30.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +!function(e){var t;"undefined"!=typeof window?t=window:"undefined"!=typeof self&&(t=self),t.ALGOLIA_MIGRATION_LAYER=e()}(function(){return function e(t,r,o){function n(s,a){if(!r[s]){if(!t[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};t[s][0].call(l.exports,function(e){var r=t[s][1][e];return n(r?r:e)},l,l.exports,e,t,r,o)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s<o.length;s++)n(o[s]);return n}({1:[function(e,t,r){function o(e,t){for(var r in t)e.setAttribute(r,t[r])}function n(e,t){e.onload=function(){this.onerror=this.onload=null,t(null,e)},e.onerror=function(){this.onerror=this.onload=null,t(new Error("Failed to load "+this.src),e)}}function i(e,t){e.onreadystatechange=function(){"complete"!=this.readyState&&"loaded"!=this.readyState||(this.onreadystatechange=null,t(null,e))}}t.exports=function(e,t,r){var s=document.head||document.getElementsByTagName("head")[0],a=document.createElement("script");"function"==typeof t&&(r=t,t={}),t=t||{},r=r||function(){},a.type=t.type||"text/javascript",a.charset=t.charset||"utf8",a.async=!("async"in t)||!!t.async,a.src=e,t.attrs&&o(a,t.attrs),t.text&&(a.text=""+t.text);var c="onload"in a?n:i;c(a,r),a.onload||n(a,r),s.appendChild(a)}},{}],2:[function(e,t,r){"use strict";function o(e){for(var t=new RegExp("cdn\\.jsdelivr\\.net/algoliasearch/latest/"+e.replace(".","\\.")+"(?:\\.min)?\\.js$"),r=document.getElementsByTagName("script"),o=!1,n=0,i=r.length;n<i;n++)if(r[n].src&&t.test(r[n].src)){o=!0;break}return o}t.exports=o},{}],3:[function(e,t,r){"use strict";function o(t){var r=e(1),o="//cdn.jsdelivr.net/algoliasearch/2/"+t+".min.js",i="-- AlgoliaSearch `latest` warning --\nWarning, you are using the `latest` version string from jsDelivr to load the AlgoliaSearch library.\nUsing `latest` is no more recommended, you should load //cdn.jsdelivr.net/algoliasearch/2/algoliasearch.min.js\n\nAlso, we updated the AlgoliaSearch JavaScript client to V3. If you want to upgrade,\nplease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch `latest` warning --";window.console&&(window.console.warn?window.console.warn(i):window.console.log&&window.console.log(i));try{document.write("<script>window.ALGOLIA_SUPPORTS_DOCWRITE = true</script>"),window.ALGOLIA_SUPPORTS_DOCWRITE===!0?(document.write('<script src="'+o+'"></script>'),n("document.write")()):r(o,n("DOMElement"))}catch(s){r(o,n("DOMElement"))}}function n(e){return function(){var t="AlgoliaSearch: loaded V2 script using "+e;window.console&&window.console.log&&window.console.log(t)}}t.exports=o},{1:1}],4:[function(e,t,r){"use strict";function o(){var e="-- AlgoliaSearch V2 => V3 error --\nYou are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\nPlease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch V2 => V3 error --";window.AlgoliaSearch=function(){throw new Error(e)},window.AlgoliaSearchHelper=function(){throw new Error(e)},window.AlgoliaExplainResults=function(){throw new Error(e)}}t.exports=o},{}],5:[function(e,t,r){"use strict";function o(t){var r=e(2),o=e(3),n=e(4);r(t)?o(t):n()}o("algoliasearch.jquery")},{2:2,3:3,4:4}]},{},[5])(5)}),function e(t,r,o){function n(s,a){if(!r[s]){if(!t[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};t[s][0].call(l.exports,function(e){var r=t[s][1][e];return n(r?r:e)},l,l.exports,e,t,r,o)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s<o.length;s++)n(o[s]);return n}({1:[function(e,t,r){(function(o){function n(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function i(e){var t=this.useColors;if(e[0]=(t?"%c":"")+this.namespace+(t?" %c":" ")+e[0]+(t?"%c ":" ")+"+"+r.humanize(this.diff),t){var o="color: "+this.color;e.splice(1,0,o,"color: inherit");var n=0,i=0;e[0].replace(/%[a-zA-Z%]/g,function(e){"%%"!==e&&(n++,"%c"===e&&(i=n))}),e.splice(i,0,o)}}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?r.storage.removeItem("debug"):r.storage.debug=e}catch(t){}}function c(){var e;try{e=r.storage.debug}catch(t){}return!e&&"undefined"!=typeof o&&"env"in o&&(e=o.env.DEBUG),e}function u(){try{return window.localStorage}catch(e){}}r=t.exports=e(2),r.log=s,r.formatArgs=i,r.save=a,r.load=c,r.useColors=n,r.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:u(),r.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],r.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},r.enable(c())}).call(this,e(12))},{12:12,2:2}],2:[function(e,t,r){function o(e){var t,o=0;for(t in e)o=(o<<5)-o+e.charCodeAt(t),o|=0;return r.colors[Math.abs(o)%r.colors.length]}function n(e){function t(){if(t.enabled){var e=t,o=+new Date,n=o-(u||o);e.diff=n,e.prev=u,e.curr=o,u=o;for(var i=new Array(arguments.length),s=0;s<i.length;s++)i[s]=arguments[s];i[0]=r.coerce(i[0]),"string"!=typeof i[0]&&i.unshift("%O");var a=0;i[0]=i[0].replace(/%([a-zA-Z%])/g,function(t,o){if("%%"===t)return t;a++;var n=r.formatters[o];if("function"==typeof n){var s=i[a];t=n.call(e,s),i.splice(a,1),a--}return t}),r.formatArgs.call(e,i);var c=t.log||r.log||console.log.bind(console);c.apply(e,i)}}return t.namespace=e,t.enabled=r.enabled(e),t.useColors=r.useColors(),t.color=o(e),"function"==typeof r.init&&r.init(t),t}function i(e){r.save(e),r.names=[],r.skips=[];for(var t=("string"==typeof e?e:"").split(/[\s,]+/),o=t.length,n=0;n<o;n++)t[n]&&(e=t[n].replace(/\*/g,".*?"),"-"===e[0]?r.skips.push(new RegExp("^"+e.substr(1)+"$")):r.names.push(new RegExp("^"+e+"$")))}function s(){r.enable("")}function a(e){var t,o;for(t=0,o=r.skips.length;t<o;t++)if(r.skips[t].test(e))return!1;for(t=0,o=r.names.length;t<o;t++)if(r.names[t].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}r=t.exports=n.debug=n["default"]=n,r.coerce=c,r.disable=s,r.enable=i,r.enabled=a,r.humanize=e(9),r.names=[],r.skips=[],r.formatters={};var u},{9:9}],3:[function(e,t,r){(function(o,n){!function(e,o){"object"==typeof r&&"undefined"!=typeof t?t.exports=o():"function"==typeof define&&define.amd?define(o):e.ES6Promise=o()}(this,function(){"use strict";function t(e){var t=typeof e;return null!==e&&("object"===t||"function"===t)}function r(e){return"function"==typeof e}function i(e){X=e}function s(e){W=e}function a(){return function(){return o.nextTick(d)}}function c(){return"undefined"!=typeof V?function(){V(d)}:p()}function u(){var e=0,t=new Z(d),r=document.createTextNode("");return t.observe(r,{characterData:!0}),function(){r.data=e=++e%2}}function l(){var e=new MessageChannel;return e.port1.onmessage=d,function(){return e.port2.postMessage(0)}}function p(){var e=setTimeout;return function(){return e(d,1)}}function d(){for(var e=0;e<G;e+=2){var t=re[e],r=re[e+1];t(r),re[e]=void 0,re[e+1]=void 0}G=0}function h(){try{var t=e,r=t("vertx");return V=r.runOnLoop||r.runOnContext,c()}catch(o){return p()}}function f(e,t){var r=arguments,o=this,n=new this.constructor(m);void 0===n[ne]&&C(n);var i=o._state;return i?!function(){var e=r[i-1];W(function(){return E(i,n,e,o._result)})}():I(o,n,e,t),n}function y(e){var t=this;if(e&&"object"==typeof e&&e.constructor===t)return e;var r=new t(m);return R(r,e),r}function m(){}function v(){return new TypeError("You cannot resolve a promise with itself")}function g(){return new TypeError("A promises callback cannot return that same promise.")}function b(e){try{return e.then}catch(t){return ce.error=t,ce}}function w(e,t,r,o){try{e.call(t,r,o)}catch(n){return n}}function _(e,t,r){W(function(e){var o=!1,n=w(r,t,function(r){o||(o=!0,t!==r?R(e,r):j(e,r))},function(t){o||(o=!0,S(e,t))},"Settle: "+(e._label||" unknown promise"));!o&&n&&(o=!0,S(e,n))},e)}function T(e,t){t._state===se?j(e,t._result):t._state===ae?S(e,t._result):I(t,void 0,function(t){return R(e,t)},function(t){return S(e,t)})}function x(e,t,o){t.constructor===e.constructor&&o===f&&t.constructor.resolve===y?T(e,t):o===ce?(S(e,ce.error),ce.error=null):void 0===o?j(e,t):r(o)?_(e,t,o):j(e,t)}function R(e,r){e===r?S(e,v()):t(r)?x(e,r,b(r)):j(e,r)}function A(e){e._onerror&&e._onerror(e._result),k(e)}function j(e,t){e._state===ie&&(e._result=t,e._state=se,0!==e._subscribers.length&&W(k,e))}function S(e,t){e._state===ie&&(e._state=ae,e._result=t,W(A,e))}function I(e,t,r,o){var n=e._subscribers,i=n.length;e._onerror=null,n[i]=t,n[i+se]=r,n[i+ae]=o,0===i&&e._state&&W(k,e)}function k(e){var t=e._subscribers,r=e._state;if(0!==t.length){for(var o=void 0,n=void 0,i=e._result,s=0;s<t.length;s+=3)o=t[s],n=t[s+r],o?E(r,o,n,i):n(i);e._subscribers.length=0}}function O(){this.error=null}function q(e,t){try{return e(t)}catch(r){return ue.error=r,ue}}function E(e,t,o,n){var i=r(o),s=void 0,a=void 0,c=void 0,u=void 0;if(i){if(s=q(o,n),s===ue?(u=!0,a=s.error,s.error=null):c=!0,t===s)return void S(t,g())}else s=n,c=!0;t._state!==ie||(i&&c?R(t,s):u?S(t,a):e===se?j(t,s):e===ae&&S(t,s))}function U(e,t){try{t(function(t){R(e,t)},function(t){S(e,t)})}catch(r){S(e,r)}}function P(){return le++}function C(e){e[ne]=le++,e._state=void 0,e._result=void 0,e._subscribers=[]}function N(e,t){this._instanceConstructor=e,this.promise=new e(m),this.promise[ne]||C(this.promise),$(t)?(this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0===this.length?j(this.promise,this._result):(this.length=this.length||0,this._enumerate(t),0===this._remaining&&j(this.promise,this._result))):S(this.promise,D())}function D(){return new Error("Array Methods must be provided an Array")}function K(e){return new N(this,e).promise}function L(e){var t=this;return new t($(e)?function(r,o){for(var n=e.length,i=0;i<n;i++)t.resolve(e[i]).then(r,o)}:function(e,t){return t(new TypeError("You must pass an array to race."))})}function H(e){var t=this,r=new t(m);return S(r,e),r}function M(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function J(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function F(e){this[ne]=P(),this._result=this._state=void 0,this._subscribers=[],m!==e&&("function"!=typeof e&&M(),this instanceof F?U(this,e):J())}function B(){var e=void 0;if("undefined"!=typeof n)e=n;else if("undefined"!=typeof self)e=self;else try{e=Function("return this")()}catch(t){throw new Error("polyfill failed because global object is unavailable in this environment")}var r=e.Promise;if(r){var o=null;try{o=Object.prototype.toString.call(r.resolve())}catch(t){}if("[object Promise]"===o&&!r.cast)return}e.Promise=F}var Q=void 0;Q=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var $=Q,G=0,V=void 0,X=void 0,W=function(e,t){re[G]=e,re[G+1]=t,G+=2,2===G&&(X?X(d):oe())},Y="undefined"!=typeof window?window:void 0,z=Y||{},Z=z.MutationObserver||z.WebKitMutationObserver,ee="undefined"==typeof self&&"undefined"!=typeof o&&"[object process]"==={}.toString.call(o),te="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,re=new Array(1e3),oe=void 0;oe=ee?a():Z?u():te?l():void 0===Y&&"function"==typeof e?h():p();var ne=Math.random().toString(36).substring(16),ie=void 0,se=1,ae=2,ce=new O,ue=new O,le=0;return N.prototype._enumerate=function(e){for(var t=0;this._state===ie&&t<e.length;t++)this._eachEntry(e[t],t)},N.prototype._eachEntry=function(e,t){var r=this._instanceConstructor,o=r.resolve;if(o===y){var n=b(e);if(n===f&&e._state!==ie)this._settledAt(e._state,t,e._result);else if("function"!=typeof n)this._remaining--,this._result[t]=e;else if(r===F){var i=new r(m);x(i,e,n),this._willSettleAt(i,t)}else this._willSettleAt(new r(function(t){return t(e)}),t)}else this._willSettleAt(o(e),t)},N.prototype._settledAt=function(e,t,r){var o=this.promise;o._state===ie&&(this._remaining--,e===ae?S(o,r):this._result[t]=r),0===this._remaining&&j(o,this._result)},N.prototype._willSettleAt=function(e,t){var r=this;I(e,void 0,function(e){return r._settledAt(se,t,e)},function(e){return r._settledAt(ae,t,e)})},F.all=K,F.race=L,F.resolve=y,F.reject=H,F._setScheduler=i,F._setAsap=s,F._asap=W,F.prototype={constructor:F,then:f,"catch":function(e){return this.then(null,e)}},F.polyfill=B,F.Promise=F,F})}).call(this,e(12),"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{12:12}],4:[function(e,t,r){function o(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function n(e){return"function"==typeof e}function i(e){return"number"==typeof e}function s(e){return"object"==typeof e&&null!==e}function a(e){return void 0===e}t.exports=o,o.EventEmitter=o,o.prototype._events=void 0,o.prototype._maxListeners=void 0,o.defaultMaxListeners=10,o.prototype.setMaxListeners=function(e){if(!i(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},o.prototype.emit=function(e){var t,r,o,i,c,u;if(this._events||(this._events={}),"error"===e&&(!this._events.error||s(this._events.error)&&!this._events.error.length)){if(t=arguments[1],t instanceof Error)throw t;var l=new Error('Uncaught, unspecified "error" event. ('+t+")");throw l.context=t,l}if(r=this._events[e],a(r))return!1;if(n(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:i=Array.prototype.slice.call(arguments,1),r.apply(this,i)}else if(s(r))for(i=Array.prototype.slice.call(arguments,1),u=r.slice(),o=u.length,c=0;c<o;c++)u[c].apply(this,i);return!0},o.prototype.addListener=function(e,t){var r;if(!n(t))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,n(t.listener)?t.listener:t),this._events[e]?s(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,s(this._events[e])&&!this._events[e].warned&&(r=a(this._maxListeners)?o.defaultMaxListeners:this._maxListeners,r&&r>0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())),this},o.prototype.on=o.prototype.addListener,o.prototype.once=function(e,t){function r(){this.removeListener(e,r),o||(o=!0,t.apply(this,arguments))}if(!n(t))throw TypeError("listener must be a function");var o=!1;return r.listener=t,this.on(e,r),this},o.prototype.removeListener=function(e,t){var r,o,i,a;if(!n(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(r=this._events[e],i=r.length,o=-1,r===t||n(r.listener)&&r.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(s(r)){for(a=i;a-- >0;)if(r[a]===t||r[a].listener&&r[a].listener===t){o=a;break}if(o<0)return this;1===r.length?(r.length=0,delete this._events[e]):r.splice(o,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},o.prototype.removeAllListeners=function(e){var t,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[e],n(r))this.removeListener(e,r);else if(r)for(;r.length;)this.removeListener(e,r[r.length-1]);return delete this._events[e],this},o.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?n(this._events[e])?[this._events[e]]:this._events[e].slice():[]},o.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(n(t))return 1;if(t)return t.length}return 0},o.listenerCount=function(e,t){return e.listenerCount(t)}},{}],5:[function(e,t,r){var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString;t.exports=function(e,t,r){if("[object Function]"!==n.call(t))throw new TypeError("iterator must be a function");var i=e.length;if(i===+i)for(var s=0;s<i;s++)t.call(r,e[s],s,e);else for(var a in e)o.call(e,a)&&t.call(r,e[a],a,e)}},{}],6:[function(e,t,r){(function(e){var r;r="undefined"!=typeof window?window:"undefined"!=typeof e?e:"undefined"!=typeof self?self:{},t.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(e,t,r){"function"==typeof Object.create?t.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}},{}],8:[function(e,t,r){var o={}.toString;t.exports=Array.isArray||function(e){return"[object Array]"==o.call(e)}},{}],9:[function(e,t,r){function o(e){if(e=String(e),!(e.length>100)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var r=parseFloat(t[1]),o=(t[2]||"ms").toLowerCase();switch(o){case"years":case"year":case"yrs":case"yr":case"y":return r*p;case"days":case"day":case"d":return r*l;case"hours":case"hour":case"hrs":case"hr":case"h":return r*u;case"minutes":case"minute":case"mins":case"min":case"m":return r*c;case"seconds":case"second":case"secs":case"sec":case"s":return r*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function n(e){return e>=l?Math.round(e/l)+"d":e>=u?Math.round(e/u)+"h":e>=c?Math.round(e/c)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function i(e){return s(e,l,"day")||s(e,u,"hour")||s(e,c,"minute")||s(e,a,"second")||e+" ms"}function s(e,t,r){if(!(e<t))return e<1.5*t?Math.floor(e/t)+" "+r:Math.ceil(e/t)+" "+r+"s"}var a=1e3,c=60*a,u=60*c,l=24*u,p=365.25*l;t.exports=function(e,t){t=t||{};var r=typeof e;if("string"===r&&e.length>0)return o(e);if("number"===r&&isNaN(e)===!1)return t["long"]?i(e):n(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],10:[function(e,t,r){"use strict";var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString,i=Array.prototype.slice,s=e(11),a=Object.prototype.propertyIsEnumerable,c=!a.call({toString:null},"toString"),u=a.call(function(){},"prototype"),l=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],p=function(e){var t=e.constructor;return t&&t.prototype===e},d={$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},h=function(){if("undefined"==typeof window)return!1;for(var e in window)try{if(!d["$"+e]&&o.call(window,e)&&null!==window[e]&&"object"==typeof window[e])try{p(window[e])}catch(t){return!0}}catch(t){return!0}return!1}(),f=function(e){if("undefined"==typeof window||!h)return p(e);try{return p(e)}catch(t){return!1}},y=function(e){var t=null!==e&&"object"==typeof e,r="[object Function]"===n.call(e),i=s(e),a=t&&"[object String]"===n.call(e),p=[];if(!t&&!r&&!i)throw new TypeError("Object.keys called on a non-object");var d=u&&r;if(a&&e.length>0&&!o.call(e,0))for(var h=0;h<e.length;++h)p.push(String(h));if(i&&e.length>0)for(var y=0;y<e.length;++y)p.push(String(y));else for(var m in e)d&&"prototype"===m||!o.call(e,m)||p.push(String(m));if(c)for(var v=f(e),g=0;g<l.length;++g)v&&"constructor"===l[g]||!o.call(e,l[g])||p.push(l[g]);return p};y.shim=function(){if(Object.keys){var e=function(){return 2===(Object.keys(arguments)||"").length}(1,2);if(!e){var t=Object.keys;Object.keys=function(e){return t(s(e)?i.call(e):e)}}}else Object.keys=y;return Object.keys||y},t.exports=y},{11:11}],11:[function(e,t,r){"use strict";var o=Object.prototype.toString;t.exports=function(e){var t=o.call(e),r="[object Arguments]"===t;return r||(r="[object Array]"!==t&&null!==e&&"object"==typeof e&&"number"==typeof e.length&&e.length>=0&&"[object Function]"===o.call(e.callee)),r}},{}],12:[function(e,t,r){function o(){throw new Error("setTimeout has not been defined")}function n(){throw new Error("clearTimeout has not been defined")}function i(e){if(p===setTimeout)return setTimeout(e,0);if((p===o||!p)&&setTimeout)return p=setTimeout,setTimeout(e,0);try{return p(e,0)}catch(t){try{return p.call(null,e,0)}catch(t){return p.call(this,e,0)}}}function s(e){if(d===clearTimeout)return clearTimeout(e);if((d===n||!d)&&clearTimeout)return d=clearTimeout,clearTimeout(e);try{return d(e)}catch(t){try{return d.call(null,e)}catch(t){return d.call(this,e)}}}function a(){m&&f&&(m=!1,f.length?y=f.concat(y):v=-1,y.length&&c())}function c(){if(!m){var e=i(a);m=!0;for(var t=y.length;t;){for(f=y,y=[];++v<t;)f&&f[v].run();v=-1,t=y.length}f=null,m=!1,s(e)}}function u(e,t){this.fun=e,this.array=t}function l(){}var p,d,h=t.exports={};!function(){try{p="function"==typeof setTimeout?setTimeout:o}catch(e){p=o}try{d="function"==typeof clearTimeout?clearTimeout:n}catch(e){d=n}}();var f,y=[],m=!1,v=-1;h.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var r=1;r<arguments.length;r++)t[r-1]=arguments[r];y.push(new u(e,t)),1!==y.length||m||i(c)},u.prototype.run=function(){this.fun.apply(null,this.array)},h.title="browser",h.browser=!0,h.env={},h.argv=[],h.version="",h.versions={},h.on=l,h.addListener=l,h.once=l,h.off=l,h.removeListener=l,h.removeAllListeners=l,h.emit=l,h.binding=function(e){throw new Error("process.binding is not supported")},h.cwd=function(){return"/"},h.chdir=function(e){throw new Error("process.chdir is not supported")},h.umask=function(){return 0}},{}],13:[function(e,t,r){"use strict";function o(e,t){if(e.map)return e.map(t);for(var r=[],o=0;o<e.length;o++)r.push(t(e[o],o));return r}var n=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};t.exports=function(e,t,r,a){return t=t||"&",r=r||"=",null===e&&(e=void 0),"object"==typeof e?o(s(e),function(s){var a=encodeURIComponent(n(s))+r;return i(e[s])?o(e[s],function(e){return a+encodeURIComponent(n(e))}).join(t):a+encodeURIComponent(n(e[s]))}).join(t):a?encodeURIComponent(n(a))+r+encodeURIComponent(n(e)):""};var i=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},s=Object.keys||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.push(r);return t}},{}],14:[function(e,t,r){function o(){c.apply(this,arguments)}function n(){var e="Not implemented in this environment.\nIf you feel this is a mistake, write to support@algolia.com";throw new l.AlgoliaSearchError(e)}t.exports=o;var i=e(16),s=e(27),a=e(28),c=e(15),u=e(7),l=e(29);u(o,c),o.prototype.deleteIndex=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(e),hostType:"write",callback:t})},o.prototype.moveIndex=function(e,t,r){var o={operation:"move",destination:t};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:o,hostType:"write",callback:r})},o.prototype.copyIndex=function(e,t,r,o){var n={operation:"copy",destination:t},i=o;if("function"==typeof r)i=r;else if(Array.isArray(r)&&r.length>0)n.scope=r;else if("undefined"!=typeof r)throw new Error("the scope given to `copyIndex` was not an array with settings, synonyms or rules");return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:n,hostType:"write",callback:i})},o.prototype.getLogs=function(t,r,o){var n=e(25),i={};return"object"==typeof t?(i=n(t),o=r):0===arguments.length||"function"==typeof t?o=t:1===arguments.length||"function"==typeof r?(o=r,i.offset=t):(i.offset=t,i.length=r),void 0===i.offset&&(i.offset=0),void 0===i.length&&(i.length=10),this._jsonRequest({method:"GET",url:"/1/logs?"+this._getSearchParams(i,""),hostType:"read",callback:o})},o.prototype.listIndexes=function(e,t){var r="";return void 0===e||"function"==typeof e?t=e:r="?page="+e,this._jsonRequest({method:"GET",url:"/1/indexes"+r,hostType:"read",callback:t})},o.prototype.initIndex=function(e){return new i(this,e)},o.prototype.initAnalytics=function(t){var r=e(26);return r(this.applicationID,this.apiKey,t)},o.prototype.listUserKeys=s(function(e){return this.listApiKeys(e)},a("client.listUserKeys()","client.listApiKeys()")),o.prototype.listApiKeys=function(e){return this._jsonRequest({method:"GET",url:"/1/keys",hostType:"read",callback:e})},o.prototype.getUserKeyACL=s(function(e,t){return this.getApiKey(e,t)},a("client.getUserKeyACL()","client.getApiKey()")),o.prototype.getApiKey=function(e,t){return this._jsonRequest({method:"GET",url:"/1/keys/"+e,hostType:"read",callback:t})},o.prototype.deleteUserKey=s(function(e,t){return this.deleteApiKey(e,t)},a("client.deleteUserKey()","client.deleteApiKey()")),o.prototype.deleteApiKey=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/keys/"+e,hostType:"write",callback:t})},o.prototype.addUserKey=s(function(e,t,r){return this.addApiKey(e,t,r)},a("client.addUserKey()","client.addApiKey()")),o.prototype.addApiKey=function(t,r,o){var n=e(8),i="Usage: client.addApiKey(arrayOfAcls[, params, callback])";if(!n(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.indexes=r.indexes,s.description=r.description,r.queryParameters&&(s.queryParameters=this._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this._jsonRequest({method:"POST",url:"/1/keys",body:s,hostType:"write",callback:o})},o.prototype.addUserKeyWithValidity=s(function(e,t,r){return this.addApiKey(e,t,r)},a("client.addUserKeyWithValidity()","client.addApiKey()")),o.prototype.updateUserKey=s(function(e,t,r,o){return this.updateApiKey(e,t,r,o)},a("client.updateUserKey()","client.updateApiKey()")),o.prototype.updateApiKey=function(t,r,o,n){var i=e(8),s="Usage: client.updateApiKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof o||(n=o,o=null);var a={acl:r};return o&&(a.validity=o.validity,a.maxQueriesPerIPPerHour=o.maxQueriesPerIPPerHour,a.maxHitsPerQuery=o.maxHitsPerQuery,a.indexes=o.indexes,a.description=o.description,o.queryParameters&&(a.queryParameters=this._getSearchParams(o.queryParameters,"")),a.referers=o.referers),this._jsonRequest({method:"PUT",url:"/1/keys/"+t,body:a,hostType:"write",callback:n})},o.prototype.startQueriesBatch=s(function(){this._batch=[]},a("client.startQueriesBatch()","client.search()")),o.prototype.addQueryInBatch=s(function(e,t,r){this._batch.push({indexName:e,query:t,params:r})},a("client.addQueryInBatch()","client.search()")),o.prototype.sendQueriesBatch=s(function(e){return this.search(this._batch,e)},a("client.sendQueriesBatch()","client.search()")),o.prototype.batch=function(t,r){var o=e(8),n="Usage: client.batch(operations[, callback])";if(!o(t))throw new Error(n);return this._jsonRequest({method:"POST",url:"/1/indexes/*/batch",body:{requests:t},hostType:"write",callback:r})},o.prototype.assignUserID=function(e,t){if(!e.userID||!e.cluster)throw new l.AlgoliaSearchError("You have to provide both a userID and cluster",e);return this._jsonRequest({method:"POST",url:"/1/clusters/mapping",hostType:"write",body:{cluster:e.cluster},callback:t,headers:{"x-algolia-user-id":e.userID}})},o.prototype.getTopUserID=function(e){return this._jsonRequest({method:"GET",url:"/1/clusters/mapping/top",hostType:"read",callback:e})},o.prototype.getUserID=function(e,t){if(!e.userID)throw new l.AlgoliaSearchError("You have to provide a userID",{debugData:e});return this._jsonRequest({method:"GET",url:"/1/clusters/mapping/"+e.userID,hostType:"read",callback:t})},o.prototype.listClusters=function(e){return this._jsonRequest({method:"GET",url:"/1/clusters",hostType:"read",callback:e})},o.prototype.listUserIDs=function(e,t){return this._jsonRequest({method:"GET",url:"/1/clusters/mapping",body:e,hostType:"read",callback:t})},o.prototype.removeUserID=function(e,t){if(!e.userID)throw new l.AlgoliaSearchError("You have to provide a userID",{debugData:e});return this._jsonRequest({method:"DELETE",url:"/1/clusters/mapping",hostType:"write",callback:t,headers:{"x-algolia-user-id":e.userID}})},o.prototype.searchUserIDs=function(e,t){return this._jsonRequest({method:"POST",url:"/1/clusters/mapping/search",body:e,hostType:"read",callback:t})},o.prototype.destroy=n,o.prototype.enableRateLimitForward=n,o.prototype.disableRateLimitForward=n,o.prototype.useSecuredAPIKey=n,o.prototype.disableSecuredAPIKey=n,o.prototype.generateSecuredApiKey=n},{15:15,16:16,25:25,26:26,27:27,28:28,29:29,7:7,8:8}],15:[function(e,t,r){(function(r){function o(t,r,o){var i=e(1)("algoliasearch"),s=e(25),a=e(8),u=e(31),l="Usage: algoliasearch(applicationID, apiKey, opts)";if(o._allowEmptyCredentials!==!0&&!t)throw new c.AlgoliaSearchError("Please provide an application ID. "+l);if(o._allowEmptyCredentials!==!0&&!r)throw new c.AlgoliaSearchError("Please provide an API key. "+l);this.applicationID=t,this.apiKey=r,this.hosts={read:[],write:[]},o=o||{},this._timeouts=o.timeouts||{connect:1e3,read:2e3,write:3e4},o.timeout&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=o.timeout);var p=o.protocol||"https:";if(/:$/.test(p)||(p+=":"),"http:"!==p&&"https:"!==p)throw new c.AlgoliaSearchError("protocol must be `http:` or `https:` (was `"+o.protocol+"`)");if(this._checkAppIdData(),o.hosts)a(o.hosts)?(this.hosts.read=s(o.hosts),this.hosts.write=s(o.hosts)):(this.hosts.read=s(o.hosts.read),this.hosts.write=s(o.hosts.write));else{var d=u(this._shuffleResult,function(e){return t+"-"+e+".algolianet.com"}),h=(o.dsn===!1?"":"-dsn")+".algolia.net";this.hosts.read=[this.applicationID+h].concat(d),this.hosts.write=[this.applicationID+".algolia.net"].concat(d)}this.hosts.read=u(this.hosts.read,n(p)),this.hosts.write=u(this.hosts.write,n(p)),this.extraHeaders={},this.cache=o._cache||{},this._ua=o._ua,this._useCache=!(void 0!==o._useCache&&!o._cache)||o._useCache,this._useRequestCache=this._useCache&&o._useRequestCache,this._useFallback=void 0===o.useFallback||o.useFallback,this._setTimeout=o._setTimeout,i("init done, %j",this)}function n(e){return function(t){return e+"//"+t.toLowerCase()}}function i(e){if(void 0===Array.prototype.toJSON)return JSON.stringify(e);var t=Array.prototype.toJSON;delete Array.prototype.toJSON;var r=JSON.stringify(e);return Array.prototype.toJSON=t,r}function s(e){for(var t,r,o=e.length;0!==o;)r=Math.floor(Math.random()*o),o-=1, +t=e[o],e[o]=e[r],e[r]=t;return e}function a(e){var t={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){var o;o="x-algolia-api-key"===r||"x-algolia-application-id"===r?"**hidden for security purposes**":e[r],t[r]=o}return t}t.exports=o;var c=e(29),u=e(30),l=e(18),p=e(35),d=500,h=r.env.RESET_APP_DATA_TIMER&&parseInt(r.env.RESET_APP_DATA_TIMER,10)||12e4;o.prototype.initIndex=function(e){return new l(this,e)},o.prototype.setExtraHeader=function(e,t){this.extraHeaders[e.toLowerCase()]=t},o.prototype.getExtraHeader=function(e){return this.extraHeaders[e.toLowerCase()]},o.prototype.unsetExtraHeader=function(e){delete this.extraHeaders[e.toLowerCase()]},o.prototype.addAlgoliaAgent=function(e){this._ua.indexOf(";"+e)===-1&&(this._ua+=";"+e)},o.prototype._jsonRequest=function(t){function r(e,n){function u(e){var t=e&&e.body&&e.body.message&&e.body.status||e.statusCode||e&&e.body&&200;h("received response: statusCode: %s, computed statusCode: %d, headers: %j",e.statusCode,t,e.headers);var r=2===Math.floor(t/100),o=new Date;if(w.push({currentHost:A,headers:a(p),content:s||null,contentLength:void 0!==s?s.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:x,endTime:o,duration:o-x,statusCode:t}),r)return m._useCache&&!m._useRequestCache&&y&&(y[l]=e.responseText),{responseText:e.responseText,body:e.body};var i=4!==Math.floor(t/100);if(i)return v+=1,_();h("unrecoverable error");var u=new c.AlgoliaSearchError(e.body&&e.body.message,{debugData:w,statusCode:t});return m._promise.reject(u)}function d(e){h("error: %s, stack: %s",e.message,e.stack);var r=new Date;return w.push({currentHost:A,headers:a(p),content:s||null,contentLength:void 0!==s?s.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:x,endTime:r,duration:r-x}),e instanceof c.AlgoliaSearchError||(e=new c.Unknown(e&&e.message,e)),v+=1,e instanceof c.Unknown||e instanceof c.UnparsableJSON||v>=m.hosts[t.hostType].length&&(g||!b)?(e.debugData=w,m._promise.reject(e)):e instanceof c.RequestTimeout?T():_()}function _(){return h("retrying request"),m._incrementHostIndex(t.hostType),r(e,n)}function T(){return h("retrying request with higher timeout"),m._incrementHostIndex(t.hostType),m._incrementTimeoutMultipler(),n.timeouts=m._getTimeoutsForRequest(t.hostType),r(e,n)}m._checkAppIdData();var x=new Date;if(m._useCache&&!m._useRequestCache&&(l=t.url),m._useCache&&!m._useRequestCache&&s&&(l+="_body_"+n.body),o(!m._useRequestCache,y,l)){h("serving response from cache");var R=y[l];return m._promise.resolve({body:JSON.parse(R),responseText:R})}if(v>=m.hosts[t.hostType].length)return!b||g?(h("could not get any response"),m._promise.reject(new c.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue. Application id was: "+m.applicationID,{debugData:w}))):(h("switching to fallback"),v=0,n.method=t.fallback.method,n.url=t.fallback.url,n.jsonBody=t.fallback.body,n.jsonBody&&(n.body=i(n.jsonBody)),p=m._computeRequestHeaders({additionalUA:f,headers:t.headers}),n.timeouts=m._getTimeoutsForRequest(t.hostType),m._setHostIndexByType(0,t.hostType),g=!0,r(m._request.fallback,n));var A=m._getHostByType(t.hostType),j=A+n.url,S={body:n.body,jsonBody:n.jsonBody,method:n.method,headers:p,timeouts:n.timeouts,debug:h,forceAuthHeaders:n.forceAuthHeaders};return h("method: %s, url: %s, headers: %j, timeouts: %d",S.method,j,S.headers,S.timeouts),e===m._request.fallback&&h("using fallback"),e.call(m,j,S).then(u,d)}function o(e,t,r){return m._useCache&&e&&t&&void 0!==t[r]}function n(e,r){return o(m._useRequestCache,y,l)&&e["catch"](function(){delete y[l]}),"function"!=typeof t.callback?e.then(r):void e.then(function(e){u(function(){t.callback(null,r(e))},m._setTimeout||setTimeout)},function(e){u(function(){t.callback(e)},m._setTimeout||setTimeout)})}this._checkAppIdData();var s,l,p,h=e(1)("algoliasearch:"+t.url),f=t.additionalUA||"",y=t.cache,m=this,v=0,g=!1,b=m._useFallback&&m._request.fallback&&t.fallback;this.apiKey.length>d&&void 0!==t.body&&(void 0!==t.body.params||void 0!==t.body.requests)?(t.body.apiKey=this.apiKey,p=this._computeRequestHeaders({additionalUA:f,withApiKey:!1,headers:t.headers})):p=this._computeRequestHeaders({additionalUA:f,headers:t.headers}),void 0!==t.body&&(s=i(t.body)),h("request start");var w=[];if(m._useCache&&m._useRequestCache&&(l=t.url),m._useCache&&m._useRequestCache&&s&&(l+="_body_"+s),o(m._useRequestCache,y,l)){h("serving request from cache");var _=y[l],T="function"!=typeof _.then?m._promise.resolve({responseText:_}):_;return n(T,function(e){return JSON.parse(e.responseText)})}var x=r(m._request,{url:t.url,method:t.method,body:s,jsonBody:t.body,timeouts:m._getTimeoutsForRequest(t.hostType),forceAuthHeaders:t.forceAuthHeaders});return m._useCache&&m._useRequestCache&&y&&(y[l]=x),n(x,function(e){return e.body})},o.prototype._getSearchParams=function(e,t){if(void 0===e||null===e)return t;for(var r in e)null!==r&&void 0!==e[r]&&e.hasOwnProperty(r)&&(t+=""===t?"":"&",t+=r+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(e[r])?i(e[r]):e[r]));return t},o.prototype._computeRequestHeaders=function(t){var r=e(5),o=t.additionalUA?this._ua+";"+t.additionalUA:this._ua,n={"x-algolia-agent":o,"x-algolia-application-id":this.applicationID};return t.withApiKey!==!1&&(n["x-algolia-api-key"]=this.apiKey),this.userToken&&(n["x-algolia-usertoken"]=this.userToken),this.securityTags&&(n["x-algolia-tagfilters"]=this.securityTags),r(this.extraHeaders,function(e,t){n[t]=e}),t.headers&&r(t.headers,function(e,t){n[t]=e}),n},o.prototype.search=function(t,r,o){var n=e(8),i=e(31),s="Usage: client.search(arrayOfQueries[, callback])";if(!n(t))throw new Error(s);"function"==typeof r?(o=r,r={}):void 0===r&&(r={});var a=this,c={requests:i(t,function(e){var t="";return void 0!==e.query&&(t+="query="+encodeURIComponent(e.query)),{indexName:e.indexName,params:a._getSearchParams(e.params,t)}})},u=i(c.requests,function(e,t){return t+"="+encodeURIComponent("/1/indexes/"+encodeURIComponent(e.indexName)+"?"+e.params)}).join("&"),l="/1/indexes/*/queries";return void 0!==r.strategy&&(c.strategy=r.strategy),this._jsonRequest({cache:this.cache,method:"POST",url:l,body:c,hostType:"read",fallback:{method:"GET",url:"/1/indexes/*",body:{params:u}},callback:o})},o.prototype.searchForFacetValues=function(t){var r=e(8),o=e(31),n="Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])";if(!r(t))throw new Error(n);var i=this;return i._promise.all(o(t,function(t){if(!t||void 0===t.indexName||void 0===t.params.facetName||void 0===t.params.facetQuery)throw new Error(n);var r=e(25),o=e(33),s=t.indexName,a=t.params,c=a.facetName,u=o(r(a),function(e){return"facetName"===e}),l=i._getSearchParams(u,"");return i._jsonRequest({cache:i.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(s)+"/facets/"+encodeURIComponent(c)+"/query",hostType:"read",body:{params:l}})}))},o.prototype.setSecurityTags=function(e){if("[object Array]"===Object.prototype.toString.call(e)){for(var t=[],r=0;r<e.length;++r)if("[object Array]"===Object.prototype.toString.call(e[r])){for(var o=[],n=0;n<e[r].length;++n)o.push(e[r][n]);t.push("("+o.join(",")+")")}else t.push(e[r]);e=t.join(",")}this.securityTags=e},o.prototype.setUserToken=function(e){this.userToken=e},o.prototype.clearCache=function(){this.cache={}},o.prototype.setRequestTimeout=function(e){e&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=e)},o.prototype.setTimeouts=function(e){this._timeouts=e},o.prototype.getTimeouts=function(){return this._timeouts},o.prototype._getAppIdData=function(){var e=p.get(this.applicationID);return null!==e&&this._cacheAppIdData(e),e},o.prototype._setAppIdData=function(e){return e.lastChange=(new Date).getTime(),this._cacheAppIdData(e),p.set(this.applicationID,e)},o.prototype._checkAppIdData=function(){var e=this._getAppIdData(),t=(new Date).getTime();return null===e||t-e.lastChange>h?this._resetInitialAppIdData(e):e},o.prototype._resetInitialAppIdData=function(e){var t=e||{};return t.hostIndexes={read:0,write:0},t.timeoutMultiplier=1,t.shuffleResult=t.shuffleResult||s([1,2,3]),this._setAppIdData(t)},o.prototype._cacheAppIdData=function(e){this._hostIndexes=e.hostIndexes,this._timeoutMultiplier=e.timeoutMultiplier,this._shuffleResult=e.shuffleResult},o.prototype._partialAppIdDataUpdate=function(t){var r=e(5),o=this._getAppIdData();return r(t,function(e,t){o[t]=e}),this._setAppIdData(o)},o.prototype._getHostByType=function(e){return this.hosts[e][this._getHostIndexByType(e)]},o.prototype._getTimeoutMultiplier=function(){return this._timeoutMultiplier},o.prototype._getHostIndexByType=function(e){return this._hostIndexes[e]},o.prototype._setHostIndexByType=function(t,r){var o=e(25),n=o(this._hostIndexes);return n[r]=t,this._partialAppIdDataUpdate({hostIndexes:n}),t},o.prototype._incrementHostIndex=function(e){return this._setHostIndexByType((this._getHostIndexByType(e)+1)%this.hosts[e].length,e)},o.prototype._incrementTimeoutMultipler=function(){var e=Math.max(this._timeoutMultiplier+1,4);return this._partialAppIdDataUpdate({timeoutMultiplier:e})},o.prototype._getTimeoutsForRequest=function(e){return{connect:this._timeouts.connect*this._timeoutMultiplier,complete:this._timeouts[e]*this._timeoutMultiplier}}}).call(this,e(12))},{1:1,12:12,18:18,25:25,29:29,30:30,31:31,33:33,35:35,5:5,8:8}],16:[function(e,t,r){function o(){s.apply(this,arguments)}function n(e,t,r){function o(r,n){var i={page:r||0,hitsPerPage:t||100},s=n||[];return e(i).then(function(e){var t=e.hits,r=e.nbHits,n=t.map(function(e){return delete e._highlightResult,e}),a=s.concat(n);return a.length<r?o(i.page+1,a):a})}return o().then(function(e){return"function"==typeof r?void r(e):e})}var i=e(7),s=e(18),a=e(27),c=e(28),u=e(30),l=e(29),p=a(function(){},c("forwardToSlaves","forwardToReplicas"));t.exports=o,i(o,s),o.prototype.addObject=function(e,t,r){var o=this;return 1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0),this.as._jsonRequest({method:void 0!==t?"PUT":"POST",url:"/1/indexes/"+encodeURIComponent(o.indexName)+(void 0!==t?"/"+encodeURIComponent(t):""),body:e,hostType:"write",callback:r})},o.prototype.addObjects=function(t,r){var o=e(8),n="Usage: index.addObjects(arrayOfObjects[, callback])";if(!o(t))throw new Error(n);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"addObject",body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},o.prototype.partialUpdateObject=function(e,t,r){1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var o=this,n="/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e.objectID)+"/partial";return t===!1&&(n+="?createIfNotExists=false"),this.as._jsonRequest({method:"POST",url:n,body:e,hostType:"write",callback:r})},o.prototype.partialUpdateObjects=function(t,r,o){1!==arguments.length&&"function"!=typeof r||(o=r,r=!0);var n=e(8),i="Usage: index.partialUpdateObjects(arrayOfObjects[, callback])";if(!n(t))throw new Error(i);for(var s=this,a={requests:[]},c=0;c<t.length;++c){var u={action:r===!0?"partialUpdateObject":"partialUpdateObjectNoCreate",objectID:t[c].objectID,body:t[c]};a.requests.push(u)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(s.indexName)+"/batch",body:a,hostType:"write",callback:o})},o.prototype.saveObject=function(e,t){var r=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/"+encodeURIComponent(e.objectID),body:e,hostType:"write",callback:t})},o.prototype.saveObjects=function(t,r){var o=e(8),n="Usage: index.saveObjects(arrayOfObjects[, callback])";if(!o(t))throw new Error(n);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"updateObject",objectID:t[a].objectID,body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},o.prototype.deleteObject=function(e,t){if("function"==typeof e||"string"!=typeof e&&"number"!=typeof e){var r=new l.AlgoliaSearchError(e&&"function"!=typeof e?"ObjectID must be a string":"Cannot delete an object without an objectID");return t=e,"function"==typeof t?t(r):this.as._promise.reject(r)}var o=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e),hostType:"write",callback:t})},o.prototype.deleteObjects=function(t,r){var o=e(8),n=e(31),i="Usage: index.deleteObjects(arrayOfObjectIDs[, callback])";if(!o(t))throw new Error(i);var s=this,a={requests:n(t,function(e){return{action:"deleteObject",objectID:e,body:{objectID:e}}})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(s.indexName)+"/batch",body:a,hostType:"write",callback:r})},o.prototype.deleteByQuery=a(function(t,r,o){function n(e){if(0===e.nbHits)return e;var t=p(e.hits,function(e){return e.objectID});return d.deleteObjects(t).then(i).then(s)}function i(e){return d.waitTask(e.taskID)}function s(){return d.deleteByQuery(t,r)}function a(){u(function(){o(null)},h._setTimeout||setTimeout)}function c(e){u(function(){o(e)},h._setTimeout||setTimeout)}var l=e(25),p=e(31),d=this,h=d.as;1===arguments.length||"function"==typeof r?(o=r,r={}):r=l(r),r.attributesToRetrieve="objectID",r.hitsPerPage=1e3,r.distinct=!1,this.clearCache();var f=this.search(t,r).then(n);return o?void f.then(a,c):f},c("index.deleteByQuery()","index.deleteBy()")),o.prototype.deleteBy=function(e,t){var r=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/deleteByQuery",body:{params:r.as._getSearchParams(e,"")},hostType:"write",callback:t})},o.prototype.browseAll=function(t,r){function o(e){if(!a._stopped){var t;t=void 0!==e?{cursor:e}:{params:l},c._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(u.indexName)+"/browse",hostType:"read",body:t,callback:n})}}function n(e,t){if(!a._stopped)return e?void a._error(e):(a._result(t),void 0===t.cursor?void a._end():void o(t.cursor))}"object"==typeof t&&(r=t,t=void 0);var i=e(32),s=e(17),a=new s,c=this.as,u=this,l=c._getSearchParams(i({},r||{},{query:t}),"");return o(),a},o.prototype.ttAdapter=a(function(e){var t=this;return function(r,o,n){var i;i="function"==typeof n?n:o,t.search(r,e,function(e,t){return e?void i(e):void i(t.hits)})}},"ttAdapter is not necessary anymore and will be removed in the next version,\nhave a look at autocomplete.js (https://github.com/algolia/autocomplete.js)"),o.prototype.waitTask=function(e,t){function r(){return l._jsonRequest({method:"GET",hostType:"read",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/task/"+e}).then(function(e){a++;var t=i*a*a;return t>s&&(t=s),"published"!==e.status?l._promise.delay(t).then(r):e})}function o(e){u(function(){t(null,e)},l._setTimeout||setTimeout)}function n(e){u(function(){t(e)},l._setTimeout||setTimeout)}var i=100,s=5e3,a=0,c=this,l=c.as,p=r();return t?void p.then(o,n):p},o.prototype.clearIndex=function(e){var t=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/clear",hostType:"write",callback:e})},o.prototype.getSettings=function(e,t){1===arguments.length&&"function"==typeof e&&(t=e,e={}),e=e||{};var r=encodeURIComponent(this.indexName);return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+r+"/settings?getVersion=2"+(e.advanced?"&advanced="+e.advanced:""),hostType:"read",callback:t})},o.prototype.searchSynonyms=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/search",body:e,hostType:"read",callback:t})},o.prototype.exportSynonyms=function(e,t){return n(this.searchSynonyms.bind(this),e,t)},o.prototype.saveSynonym=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e.objectID)+"?forwardToReplicas="+o,body:e,hostType:"write",callback:r})},o.prototype.getSynonym=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e),hostType:"read",callback:t})},o.prototype.deleteSynonym=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e)+"?forwardToReplicas="+o,hostType:"write",callback:r})},o.prototype.clearSynonyms=function(e,t){"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),void 0!==e.forwardToSlaves&&p();var r=e.forwardToSlaves||e.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/clear?forwardToReplicas="+r,hostType:"write",callback:t})},o.prototype.batchSynonyms=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/batch?forwardToReplicas="+o+"&replaceExistingSynonyms="+(t.replaceExistingSynonyms?"true":"false"),hostType:"write",body:e,callback:r})},o.prototype.searchRules=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/search",body:e,hostType:"read",callback:t})},o.prototype.exportRules=function(e,t){return n(this.searchRules.bind(this),e,t)},o.prototype.saveRule=function(e,t,r){if("function"==typeof t?(r=t,t={}):void 0===t&&(t={}),!e.objectID)throw new l.AlgoliaSearchError("Missing or empty objectID field for rule");var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e.objectID)+"?forwardToReplicas="+o,body:e,hostType:"write",callback:r})},o.prototype.getRule=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e),hostType:"read",callback:t})},o.prototype.deleteRule=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={});var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e)+"?forwardToReplicas="+o,hostType:"write",callback:r})},o.prototype.clearRules=function(e,t){"function"==typeof e?(t=e,e={}):void 0===e&&(e={});var r=e.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/clear?forwardToReplicas="+r,hostType:"write",callback:t})},o.prototype.batchRules=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={});var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/batch?forwardToReplicas="+o+"&clearExistingRules="+(t.clearExistingRules===!0?"true":"false"),hostType:"write",body:e,callback:r})},o.prototype.setSettings=function(e,t,r){1!==arguments.length&&"function"!=typeof t||(r=t,t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false",n=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/settings?forwardToReplicas="+o,hostType:"write",body:e,callback:r})},o.prototype.listUserKeys=a(function(e){return this.listApiKeys(e)},c("index.listUserKeys()","client.listApiKeys()")),o.prototype.listApiKeys=a(function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/keys",hostType:"read",callback:e})},c("index.listApiKeys()","client.listApiKeys()")),o.prototype.getUserKeyACL=a(function(e,t){return this.getApiKey(e,t)},c("index.getUserKeyACL()","client.getApiKey()")),o.prototype.getApiKey=a(function(e,t){var r=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/keys/"+e,hostType:"read",callback:t})},c("index.getApiKey()","client.getApiKey()")),o.prototype.deleteUserKey=a(function(e,t){return this.deleteApiKey(e,t)},c("index.deleteUserKey()","client.deleteApiKey()")),o.prototype.deleteApiKey=a(function(e,t){var r=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/keys/"+e,hostType:"write",callback:t})},c("index.deleteApiKey()","client.deleteApiKey()")),o.prototype.addUserKey=a(function(e,t,r){return this.addApiKey(e,t,r)},c("index.addUserKey()","client.addApiKey()")),o.prototype.addApiKey=a(function(t,r,o){var n=e(8),i="Usage: index.addApiKey(arrayOfAcls[, params, callback])";if(!n(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.description=r.description,r.queryParameters&&(s.queryParameters=this.as._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",body:s,hostType:"write",callback:o})},c("index.addApiKey()","client.addApiKey()")),o.prototype.addUserKeyWithValidity=a(function(e,t,r){return this.addApiKey(e,t,r)},c("index.addUserKeyWithValidity()","client.addApiKey()")),o.prototype.updateUserKey=a(function(e,t,r,o){return this.updateApiKey(e,t,r,o)},c("index.updateUserKey()","client.updateApiKey()")),o.prototype.updateApiKey=a(function(t,r,o,n){var i=e(8),s="Usage: index.updateApiKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof o||(n=o,o=null);var a={acl:r};return o&&(a.validity=o.validity,a.maxQueriesPerIPPerHour=o.maxQueriesPerIPPerHour,a.maxHitsPerQuery=o.maxHitsPerQuery,a.description=o.description,o.queryParameters&&(a.queryParameters=this.as._getSearchParams(o.queryParameters,"")),a.referers=o.referers),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+t,body:a,hostType:"write",callback:n})},c("index.updateApiKey()","client.updateApiKey()"))},{17:17,18:18,25:25,27:27,28:28,29:29,30:30,31:31,32:32,7:7,8:8}],17:[function(e,t,r){"use strict";function o(){}t.exports=o;var n=e(7),i=e(4).EventEmitter;n(o,i),o.prototype.stop=function(){this._stopped=!0,this._clean()},o.prototype._end=function(){this.emit("end"),this._clean()},o.prototype._error=function(e){this.emit("error",e),this._clean()},o.prototype._result=function(e){this.emit("result",e)},o.prototype._clean=function(){this.removeAllListeners("stop"),this.removeAllListeners("end"),this.removeAllListeners("error"),this.removeAllListeners("result")}},{4:4,7:7}],18:[function(e,t,r){function o(e,t){this.indexName=t,this.as=e,this.typeAheadArgs=null,this.typeAheadValueOption=null,this.cache={}}var n=e(24),i=e(27),s=e(28);t.exports=o,o.prototype.clearCache=function(){this.cache={}},o.prototype.search=n("query"),o.prototype.similarSearch=n("similarQuery"),o.prototype.browse=function(t,r,o){var n,i,s=e(32),a=this;0===arguments.length||1===arguments.length&&"function"==typeof arguments[0]?(n=0,o=arguments[0],t=void 0):"number"==typeof arguments[0]?(n=arguments[0],"number"==typeof arguments[1]?i=arguments[1]:"function"==typeof arguments[1]&&(o=arguments[1],i=void 0),t=void 0,r=void 0):"object"==typeof arguments[0]?("function"==typeof arguments[1]&&(o=arguments[1]),r=arguments[0],t=void 0):"string"==typeof arguments[0]&&"function"==typeof arguments[1]&&(o=arguments[1],r=void 0),r=s({},r||{},{page:n,hitsPerPage:i,query:t});var c=this.as._getSearchParams(r,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a.indexName)+"/browse",body:{params:c},hostType:"read",callback:o})},o.prototype.browseFrom=function(e,t){return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/browse",body:{cursor:e},hostType:"read",callback:t})},o.prototype.searchForFacetValues=function(t,r){var o=e(25),n=e(33),i="Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])";if(void 0===t.facetName||void 0===t.facetQuery)throw new Error(i);var s=t.facetName,a=n(o(t),function(e){return"facetName"===e}),c=this.as._getSearchParams(a,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/facets/"+encodeURIComponent(s)+"/query",hostType:"read",body:{params:c},callback:r})},o.prototype.searchFacet=i(function(e,t){return this.searchForFacetValues(e,t)},s("index.searchFacet(params[, callback])","index.searchForFacetValues(params[, callback])")),o.prototype._search=function(e,t,r,o){return this.as._jsonRequest({cache:this.cache,method:"POST",url:t||"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:e},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:e}},callback:r,additionalUA:o})},o.prototype.getObject=function(e,t,r){var o=this;1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var n="";if(void 0!==t){n="?attributes=";for(var i=0;i<t.length;++i)0!==i&&(n+=","),n+=t[i]}return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e)+n,hostType:"read",callback:r})},o.prototype.getObjects=function(t,r,o){var n=e(8),i=e(31),s="Usage: index.getObjects(arrayOfObjectIDs[, callback])";if(!n(t))throw new Error(s);var a=this;1!==arguments.length&&"function"!=typeof r||(o=r,r=void 0);var c={requests:i(t,function(e){var t={indexName:a.indexName,objectID:e};return r&&(t.attributesToRetrieve=r.join(",")),t})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/*/objects",hostType:"read",body:c,callback:o})},o.prototype.as=null,o.prototype.indexName=null,o.prototype.typeAheadArgs=null,o.prototype.typeAheadValueOption=null},{24:24,25:25,27:27,28:28,31:31,32:32,33:33,8:8}],19:[function(e,t,r){(function(t){"use strict";function r(t,n,i){var s=e(25);return i=s(i||{}),i._ua=i._ua||r.ua,new o(t,n,i)}function o(){i.apply(this,arguments)}var n=e(7),i=e(14),s=e(29),a=e(22),c=e(23),u=e(34);window.algoliasearch=e(20),"debug"===t.env.NODE_ENV&&e(1).enable("algoliasearch*"),r.version=e(36),r.ua="Algolia for jQuery "+r.version,r.initPlaces=u(r),window.__algolia={debug:e(1),algoliasearch:r};var l=window.jQuery;l.algolia={Client:r,ua:r.ua,version:r.version},n(o,i),o.prototype._request=function(e,t){return new l.Deferred(function(r){var o=t.body;e=a(e,t.headers);var n={accept:"application/json"};o&&("POST"===t.method?n["content-type"]="application/x-www-form-urlencoded":n["content-type"]="application/json"),l.ajax(e,{type:t.method,timeout:t.timeouts.complete,dataType:"json",data:o,headers:n,complete:function(e,t){return"timeout"===t?void r.reject(new s.RequestTimeout):0===e.status?void r.reject(new s.Network({more:e})):void r.resolve({statusCode:e.status,body:e.responseJSON,responseText:e.responseText,headers:e.getAllResponseHeaders()})}})}).promise()},o.prototype._request.fallback=function(e,t){return e=a(e,t.headers),new l.Deferred(function(r){c(e,t,function(e,t){return e?void r.reject(e):void r.resolve(t)})}).promise()},o.prototype._promise={reject:function(e){return new l.Deferred(function(t){t.reject(e)}).promise()},resolve:function(e){return new l.Deferred(function(t){t.resolve(e)}).promise()},delay:function(e){return new l.Deferred(function(t){setTimeout(function(){t.resolve()},e)}).promise()},all:function(e){return l.when.apply(null,e)}}}).call(this,e(12))},{1:1,12:12,14:14,20:20,22:22,23:23,25:25,29:29,34:34,36:36,7:7}],20:[function(e,t,r){"use strict";var o=e(14),n=e(21);t.exports=n(o)},{14:14,21:21}],21:[function(e,t,r){(function(r){"use strict";var o=e(6),n=o.Promise||e(3).Promise;t.exports=function(t,i){function s(t,r,o){var n=e(25);return o=n(o||{}),o._ua=o._ua||s.ua,new a(t,r,o)}function a(){t.apply(this,arguments)}var c=e(7),u=e(29),l=e(22),p=e(23),d=e(34);i=i||"","debug"===r.env.NODE_ENV&&e(1).enable("algoliasearch*"),s.version=e(36),s.ua="Algolia for vanilla JavaScript "+i+s.version,s.initPlaces=d(s),o.__algolia={debug:e(1),algoliasearch:s};var h={hasXMLHttpRequest:"XMLHttpRequest"in o,hasXDomainRequest:"XDomainRequest"in o};return h.hasXMLHttpRequest&&(h.cors="withCredentials"in new XMLHttpRequest),c(a,t),a.prototype._request=function(e,t){return new n(function(r,o){function n(){if(!f){clearTimeout(d);var e;try{e={body:JSON.parse(m.responseText),responseText:m.responseText,statusCode:m.status,headers:m.getAllResponseHeaders&&m.getAllResponseHeaders()||{}}}catch(t){e=new u.UnparsableJSON({more:m.responseText})}e instanceof u.UnparsableJSON?o(e):r(e)}}function i(e){f||(clearTimeout(d),o(new u.Network({more:e})))}function s(){f=!0,m.abort(),o(new u.RequestTimeout)}function a(){v=!0,clearTimeout(d),d=setTimeout(s,t.timeouts.complete)}function c(){v||a()}function p(){!v&&m.readyState>1&&a()}if(!h.cors&&!h.hasXDomainRequest)return void o(new u.Network("CORS not supported"));e=l(e,t.headers);var d,f,y=t.body,m=h.cors?new XMLHttpRequest:new XDomainRequest,v=!1;d=setTimeout(s,t.timeouts.connect),m.onprogress=c,"onreadystatechange"in m&&(m.onreadystatechange=p),m.onload=n,m.onerror=i,m instanceof XMLHttpRequest?(m.open(t.method,e,!0),t.forceAuthHeaders&&(m.setRequestHeader("x-algolia-application-id",t.headers["x-algolia-application-id"]),m.setRequestHeader("x-algolia-api-key",t.headers["x-algolia-api-key"]))):m.open(t.method,e),h.cors&&(y&&("POST"===t.method?m.setRequestHeader("content-type","application/x-www-form-urlencoded"):m.setRequestHeader("content-type","application/json")),m.setRequestHeader("accept","application/json")),y?m.send(y):m.send()})},a.prototype._request.fallback=function(e,t){return e=l(e,t.headers),new n(function(r,o){p(e,t,function(e,t){return e?void o(e):void r(t)})})},a.prototype._promise={reject:function(e){return n.reject(e)},resolve:function(e){return n.resolve(e)},delay:function(e){return new n(function(t){setTimeout(t,e)})},all:function(e){return n.all(e)}},s}}).call(this,e(12))},{1:1,12:12,22:22,23:23,25:25,29:29,3:3,34:34,36:36,6:6,7:7}],22:[function(e,t,r){"use strict";function o(e,t){return e+=/\?/.test(e)?"&":"?",e+n(t)}t.exports=o;var n=e(13)},{13:13}],23:[function(e,t,r){"use strict";function o(e,t,r){function o(){t.debug("JSONP: success"),m||d||(m=!0,p||(t.debug("JSONP: Fail. Script loaded but did not call the callback"),a(),r(new n.JSONPScriptFail)))}function s(){"loaded"!==this.readyState&&"complete"!==this.readyState||o()}function a(){clearTimeout(v),f.onload=null,f.onreadystatechange=null,f.onerror=null,h.removeChild(f)}function c(){try{delete window[y],delete window[y+"_loaded"]}catch(e){window[y]=window[y+"_loaded"]=void 0}}function u(){t.debug("JSONP: Script timeout"),d=!0,a(),r(new n.RequestTimeout)}function l(){t.debug("JSONP: Script error"),m||d||(a(),r(new n.JSONPScriptError))}if("GET"!==t.method)return void r(new Error("Method "+t.method+" "+e+" is not supported by JSONP."));t.debug("JSONP: start");var p=!1,d=!1;i+=1;var h=document.getElementsByTagName("head")[0],f=document.createElement("script"),y="algoliaJSONP_"+i,m=!1;window[y]=function(e){return c(),d?void t.debug("JSONP: Late answer, ignoring"):(p=!0,a(),void r(null,{body:e,responseText:JSON.stringify(e)}))},e+="&callback="+y,t.jsonBody&&t.jsonBody.params&&(e+="&"+t.jsonBody.params);var v=setTimeout(u,t.timeouts.complete);f.onreadystatechange=s,f.onload=o,f.onerror=l,f.async=!0,f.defer=!0,f.src=e,h.appendChild(f)}t.exports=o; +var n=e(29),i=0},{29:29}],24:[function(e,t,r){function o(e,t){return function(r,o,i){if("function"==typeof r&&"object"==typeof o||"object"==typeof i)throw new n.AlgoliaSearchError("index.search usage is index.search(query, params, cb)");0===arguments.length||"function"==typeof r?(i=r,r=""):1!==arguments.length&&"function"!=typeof o||(i=o,o=void 0),"object"==typeof r&&null!==r?(o=r,r=void 0):void 0!==r&&null!==r||(r="");var s="";void 0!==r&&(s+=e+"="+encodeURIComponent(r));var a;return void 0!==o&&(o.additionalUA&&(a=o.additionalUA,delete o.additionalUA),s=this.as._getSearchParams(o,s)),this._search(s,t,i,a)}}t.exports=o;var n=e(29)},{29:29}],25:[function(e,t,r){t.exports=function(e){return JSON.parse(JSON.stringify(e))}},{}],26:[function(e,t,r){function o(e,t,r){var o={};return r=r||{},r.hosts=r.hosts||["analytics.algolia.com","analytics.algolia.com","analytics.algolia.com","analytics.algolia.com"],r.protocol=r.protocol||"https:",o.as=n(e,t,r),o.getABTests=function(e,t){var r=r||{},o=r.offset||0,n=r.limit||10;return this.as._jsonRequest({method:"GET",url:"/2/abtests?offset="+encodeURIComponent(o)+"&limit="+encodeURIComponent(n),hostType:"read",forceAuthHeaders:!0,callback:t})},o.getABTest=function(e,t){return this.as._jsonRequest({method:"GET",url:"/2/abtests/"+encodeURIComponent(e),hostType:"read",forceAuthHeaders:!0,callback:t})},o.addABTest=function(e,t){return this.as._jsonRequest({method:"POST",url:"/2/abtests",body:e,hostType:"read",forceAuthHeaders:!0,callback:t})},o.stopABTest=function(e,t){return this.as._jsonRequest({method:"POST",url:"/2/abtests/"+encodeURIComponent(e)+"/stop",hostType:"read",forceAuthHeaders:!0,callback:t})},o.deleteABTest=function(e,t){return this.as._jsonRequest({method:"DELETE",url:"/2/abtests/"+encodeURIComponent(e),hostType:"write",forceAuthHeaders:!0,callback:t})},o.waitTask=function(e,t,r){return this.as.initIndex(e).waitTask(t,r)},o}t.exports=o;var n=e(20)},{20:20}],27:[function(e,t,r){t.exports=function(e,t){function r(){return o||(console.warn(t),o=!0),e.apply(this,arguments)}var o=!1;return r}},{}],28:[function(e,t,r){t.exports=function(e,t){var r=e.toLowerCase().replace(/[\.\(\)]/g,"");return"algoliasearch: `"+e+"` was replaced by `"+t+"`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#"+r}},{}],29:[function(e,t,r){"use strict";function o(t,r){var o=e(5),n=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):n.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name="AlgoliaSearchError",this.message=t||"Unknown error",r&&o(r,function(e,t){n[t]=e})}function n(e,t){function r(){var r=Array.prototype.slice.call(arguments,0);"string"!=typeof r[0]&&r.unshift(t),o.apply(this,r),this.name="AlgoliaSearch"+e+"Error"}return i(r,o),r}var i=e(7);i(o,Error),t.exports={AlgoliaSearchError:o,UnparsableJSON:n("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:n("RequestTimeout","Request timedout before getting a response"),Network:n("Network","Network issue, see err.more for details"),JSONPScriptFail:n("JSONPScriptFail","<script> was loaded but did not call our provided callback"),JSONPScriptError:n("JSONPScriptError","<script> unable to load due to an `error` event on it"),Unknown:n("Unknown","Unknown error occured")}},{5:5,7:7}],30:[function(e,t,r){t.exports=function(e,t){t(e,0)}},{}],31:[function(e,t,r){var o=e(5);t.exports=function(e,t){var r=[];return o(e,function(o,n){r.push(t(o,n,e))}),r}},{5:5}],32:[function(e,t,r){var o=e(5);t.exports=function n(e){var t=Array.prototype.slice.call(arguments);return o(t,function(t){for(var r in t)t.hasOwnProperty(r)&&("object"==typeof e[r]&&"object"==typeof t[r]?e[r]=n({},e[r],t[r]):void 0!==t[r]&&(e[r]=t[r]))}),e}},{5:5}],33:[function(e,t,r){t.exports=function(t,r){var o=e(10),n=e(5),i={};return n(o(t),function(e){r(e)!==!0&&(i[e]=t[e])}),i}},{10:10,5:5}],34:[function(e,t,r){function o(t){return function(r,o,i){var s=e(25);i=i&&s(i)||{},i.hosts=i.hosts||["places-dsn.algolia.net","places-1.algolianet.com","places-2.algolianet.com","places-3.algolianet.com"],0!==arguments.length&&"object"!=typeof r&&void 0!==r||(r="",o="",i._allowEmptyCredentials=!0);var a=t(r,o,i),c=a.initIndex("places");return c.search=n("query","/1/places/query"),c.getObject=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/places/"+encodeURIComponent(e),hostType:"read",callback:t})},c}}t.exports=o;var n=e(24)},{24:24,25:25}],35:[function(e,t,r){(function(r){function o(e,t){return c("localStorage failed with",t),s(),a=l,a.get(e)}function n(e,t){return 1===arguments.length?a.get(e):a.set(e,t)}function i(){try{return"localStorage"in r&&null!==r.localStorage&&(r.localStorage[u]||r.localStorage.setItem(u,JSON.stringify({})),!0)}catch(e){return!1}}function s(){try{r.localStorage.removeItem(u)}catch(e){}}var a,c=e(1)("algoliasearch:src/hostIndexState.js"),u="algoliasearch-client-js",l={state:{},set:function(e,t){return this.state[e]=t,this.state[e]},get:function(e){return this.state[e]||null}},p={set:function(e,t){l.set(e,t);try{var n=JSON.parse(r.localStorage[u]);return n[e]=t,r.localStorage[u]=JSON.stringify(n),n[e]}catch(i){return o(e,i)}},get:function(e){try{return JSON.parse(r.localStorage[u])[e]||null}catch(t){return o(e,t)}}};a=i()?p:l,t.exports={get:n,set:n,supportsLocalStorage:i}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],36:[function(e,t,r){"use strict";t.exports="3.30.0"},{}]},{},[19]); diff --git a/node_modules/algoliasearch/dist/algoliasearch.js b/node_modules/algoliasearch/dist/algoliasearch.js new file mode 100644 index 00000000..e2720c41 --- /dev/null +++ b/node_modules/algoliasearch/dist/algoliasearch.js @@ -0,0 +1,6884 @@ +/*! algoliasearch 3.30.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +(function(f){var g;if(typeof window!=='undefined'){g=window}else if(typeof self!=='undefined'){g=self}g.ALGOLIA_MIGRATION_LAYER=f()})(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){ + +module.exports = function load (src, opts, cb) { + var head = document.head || document.getElementsByTagName('head')[0] + var script = document.createElement('script') + + if (typeof opts === 'function') { + cb = opts + opts = {} + } + + opts = opts || {} + cb = cb || function() {} + + script.type = opts.type || 'text/javascript' + script.charset = opts.charset || 'utf8'; + script.async = 'async' in opts ? !!opts.async : true + script.src = src + + if (opts.attrs) { + setAttributes(script, opts.attrs) + } + + if (opts.text) { + script.text = '' + opts.text + } + + var onend = 'onload' in script ? stdOnEnd : ieOnEnd + onend(script, cb) + + // some good legacy browsers (firefox) fail the 'in' detection above + // so as a fallback we always set onload + // old IE will ignore this and new IE will set onload + if (!script.onload) { + stdOnEnd(script, cb); + } + + head.appendChild(script) +} + +function setAttributes(script, attrs) { + for (var attr in attrs) { + script.setAttribute(attr, attrs[attr]); + } +} + +function stdOnEnd (script, cb) { + script.onload = function () { + this.onerror = this.onload = null + cb(null, script) + } + script.onerror = function () { + // this.onload = null here is necessary + // because even IE9 works not like others + this.onerror = this.onload = null + cb(new Error('Failed to load ' + this.src), script) + } +} + +function ieOnEnd (script, cb) { + script.onreadystatechange = function () { + if (this.readyState != 'complete' && this.readyState != 'loaded') return + this.onreadystatechange = null + cb(null, script) // there is no way to catch loading errors in IE8 + } +} + +},{}],2:[function(require,module,exports){ +'use strict'; + +// this module helps finding if the current page is using +// the cdn.jsdelivr.net/algoliasearch/latest/$BUILDNAME.min.js version + +module.exports = isUsingLatest; + +function isUsingLatest(buildName) { + var toFind = new RegExp('cdn\\.jsdelivr\\.net/algoliasearch/latest/' + + buildName.replace('.', '\\.') + // algoliasearch, algoliasearch.angular + '(?:\\.min)?\\.js$'); // [.min].js + + var scripts = document.getElementsByTagName('script'); + var found = false; + for (var currentScript = 0, nbScripts = scripts.length; currentScript < nbScripts; currentScript++) { + if (scripts[currentScript].src && toFind.test(scripts[currentScript].src)) { + found = true; + break; + } + } + + return found; +} + +},{}],3:[function(require,module,exports){ +'use strict'; + +module.exports = loadV2; + +function loadV2(buildName) { + var loadScript = require(1); + var v2ScriptUrl = '//cdn.jsdelivr.net/algoliasearch/2/' + buildName + '.min.js'; + + var message = '-- AlgoliaSearch `latest` warning --\n' + + 'Warning, you are using the `latest` version string from jsDelivr to load the AlgoliaSearch library.\n' + + 'Using `latest` is no more recommended, you should load //cdn.jsdelivr.net/algoliasearch/2/algoliasearch.min.js\n\n' + + 'Also, we updated the AlgoliaSearch JavaScript client to V3. If you want to upgrade,\n' + + 'please read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n' + + '-- /AlgoliaSearch `latest` warning --'; + + if (window.console) { + if (window.console.warn) { + window.console.warn(message); + } else if (window.console.log) { + window.console.log(message); + } + } + + // If current script loaded asynchronously, + // it will load the script with DOMElement + // otherwise, it will load the script with document.write + try { + // why \x3c? http://stackoverflow.com/a/236106/147079 + document.write('\x3Cscript>window.ALGOLIA_SUPPORTS_DOCWRITE = true\x3C/script>'); + + if (window.ALGOLIA_SUPPORTS_DOCWRITE === true) { + document.write('\x3Cscript src="' + v2ScriptUrl + '">\x3C/script>'); + scriptLoaded('document.write')(); + } else { + loadScript(v2ScriptUrl, scriptLoaded('DOMElement')); + } + } catch (e) { + loadScript(v2ScriptUrl, scriptLoaded('DOMElement')); + } +} + +function scriptLoaded(method) { + return function log() { + var message = 'AlgoliaSearch: loaded V2 script using ' + method; + + if (window.console && window.console.log) { + window.console.log(message); + } + }; +} + +},{"1":1}],4:[function(require,module,exports){ +'use strict'; + +/* eslint no-unused-vars: [2, {"vars": "local"}] */ + +module.exports = oldGlobals; + +// put old window.AlgoliaSearch.. into window. again so that +// users upgrading to V3 without changing their code, will be warned +function oldGlobals() { + var message = '-- AlgoliaSearch V2 => V3 error --\n' + + 'You are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\n' + + 'Please read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n' + + '-- /AlgoliaSearch V2 => V3 error --'; + + window.AlgoliaSearch = function() { + throw new Error(message); + }; + + window.AlgoliaSearchHelper = function() { + throw new Error(message); + }; + + window.AlgoliaExplainResults = function() { + throw new Error(message); + }; +} + +},{}],5:[function(require,module,exports){ +'use strict'; + +// This script will be browserified and prepended to the normal build +// directly in window, not wrapped in any module definition +// To avoid cases where we are loaded with /latest/ along with +migrationLayer("algoliasearch"); + +// Now onto the V2 related code: +// If the client is using /latest/$BUILDNAME.min.js, load V2 of the library +// +// Otherwise, setup a migration layer that will throw on old constructors like +// new AlgoliaSearch(). +// So that users upgrading from v2 to v3 will have a clear information +// message on what to do if they did not read the migration guide +function migrationLayer(buildName) { + var isUsingLatest = require(2); + var loadV2 = require(3); + var oldGlobals = require(4); + + if (isUsingLatest(buildName)) { + loadV2(buildName); + } else { + oldGlobals(); + } +} + +},{"2":2,"3":3,"4":4}]},{},[5])(5) +});(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.algoliasearch = f()}})(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){ +(function (process){ +/** + * This is the web browser implementation of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = require(2); +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); + +/** + * Colors. + */ + +exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' +]; + +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ + +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; + } + + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} + +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; + } +}; + + +/** + * Colorize log arguments if enabled. + * + * @api public + */ + +function formatArgs(args) { + var useColors = this.useColors; + + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); + + if (!useColors) return; + + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit') + + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); + + args.splice(lastC, 0, c); +} + +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ + +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); +} + +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ + +function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + + return r; +} + +/** + * Enable namespaces listed in `localStorage.debug` initially. + */ + +exports.enable(load()); + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + return window.localStorage; + } catch (e) {} +} + +}).call(this,require(12)) +},{"12":12,"2":2}],2:[function(require,module,exports){ + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = require(9); + +/** + * The currently active debug mode names, and names to skip. + */ + +exports.names = []; +exports.skips = []; + +/** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + +exports.formatters = {}; + +/** + * Previous log timestamp. + */ + +var prevTime; + +/** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ + +function selectColor(namespace) { + var hash = 0, i; + + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return exports.colors[Math.abs(hash) % exports.colors.length]; +} + +/** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + +function createDebug(namespace) { + + function debug() { + // disabled? + if (!debug.enabled) return; + + var self = debug; + + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + + args[0] = exports.coerce(args[0]); + + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); + } + + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); + + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); + + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); + + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); + } + + return debug; +} + +/** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + +function enable(namespaces) { + exports.save(namespaces); + + exports.names = []; + exports.skips = []; + + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } + } +} + +/** + * Disable debug output. + * + * @api public + */ + +function disable() { + exports.enable(''); +} + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } + } + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } + } + return false; +} + +/** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + +},{"9":9}],3:[function(require,module,exports){ +(function (process,global){ +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE + * @version 4.1.1 + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.ES6Promise = factory()); +}(this, (function () { 'use strict'; + +function objectOrFunction(x) { + var type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} + +function isFunction(x) { + return typeof x === 'function'; +} + +var _isArray = undefined; +if (Array.isArray) { + _isArray = Array.isArray; +} else { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; +} + +var isArray = _isArray; + +var len = 0; +var vertxNext = undefined; +var customSchedulerFn = undefined; + +var asap = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (customSchedulerFn) { + customSchedulerFn(flush); + } else { + scheduleFlush(); + } + } +}; + +function setScheduler(scheduleFn) { + customSchedulerFn = scheduleFn; +} + +function setAsap(asapFn) { + asap = asapFn; +} + +var browserWindow = typeof window !== 'undefined' ? window : undefined; +var browserGlobal = browserWindow || {}; +var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; +var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]'; + +// test for web worker but not in IE10 +var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; + +// node +function useNextTick() { + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // see https://github.com/cujojs/when/issues/410 for details + return function () { + return process.nextTick(flush); + }; +} + +// vertx +function useVertxTimer() { + if (typeof vertxNext !== 'undefined') { + return function () { + vertxNext(flush); + }; + } + + return useSetTimeout(); +} + +function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function () { + node.data = iterations = ++iterations % 2; + }; +} + +// web worker +function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + return channel.port2.postMessage(0); + }; +} + +function useSetTimeout() { + // Store setTimeout reference so es6-promise will be unaffected by + // other code modifying setTimeout (like sinon.useFakeTimers()) + var globalSetTimeout = setTimeout; + return function () { + return globalSetTimeout(flush, 1); + }; +} + +var queue = new Array(1000); +function flush() { + for (var i = 0; i < len; i += 2) { + var callback = queue[i]; + var arg = queue[i + 1]; + + callback(arg); + + queue[i] = undefined; + queue[i + 1] = undefined; + } + + len = 0; +} + +function attemptVertx() { + try { + var r = require; + var vertx = r('vertx'); + vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch (e) { + return useSetTimeout(); + } +} + +var scheduleFlush = undefined; +// Decide what async method to use to triggering processing of queued callbacks: +if (isNode) { + scheduleFlush = useNextTick(); +} else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); +} else if (isWorker) { + scheduleFlush = useMessageChannel(); +} else if (browserWindow === undefined && typeof require === 'function') { + scheduleFlush = attemptVertx(); +} else { + scheduleFlush = useSetTimeout(); +} + +function then(onFulfillment, onRejection) { + var _arguments = arguments; + + var parent = this; + + var child = new this.constructor(noop); + + if (child[PROMISE_ID] === undefined) { + makePromise(child); + } + + var _state = parent._state; + + if (_state) { + (function () { + var callback = _arguments[_state - 1]; + asap(function () { + return invokeCallback(_state, child, callback, parent._result); + }); + })(); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; +} + +/** + `Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` +*/ +function resolve$1(object) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop); + resolve(promise, object); + return promise; +} + +var PROMISE_ID = Math.random().toString(36).substring(16); + +function noop() {} + +var PENDING = void 0; +var FULFILLED = 1; +var REJECTED = 2; + +var GET_THEN_ERROR = new ErrorObject(); + +function selfFulfillment() { + return new TypeError("You cannot resolve a promise with itself"); +} + +function cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); +} + +function getThen(promise) { + try { + return promise.then; + } catch (error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } +} + +function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) { + try { + then$$1.call(value, fulfillmentHandler, rejectionHandler); + } catch (e) { + return e; + } +} + +function handleForeignThenable(promise, thenable, then$$1) { + asap(function (promise) { + var sealed = false; + var error = tryThen(then$$1, thenable, function (value) { + if (sealed) { + return; + } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function (reason) { + if (sealed) { + return; + } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); +} + +function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (thenable._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function (value) { + return resolve(promise, value); + }, function (reason) { + return reject(promise, reason); + }); + } +} + +function handleMaybeThenable(promise, maybeThenable, then$$1) { + if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) { + handleOwnThenable(promise, maybeThenable); + } else { + if (then$$1 === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + GET_THEN_ERROR.error = null; + } else if (then$$1 === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then$$1)) { + handleForeignThenable(promise, maybeThenable, then$$1); + } else { + fulfill(promise, maybeThenable); + } + } +} + +function resolve(promise, value) { + if (promise === value) { + reject(promise, selfFulfillment()); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value, getThen(value)); + } else { + fulfill(promise, value); + } +} + +function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); +} + +function fulfill(promise, value) { + if (promise._state !== PENDING) { + return; + } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length !== 0) { + asap(publish, promise); + } +} + +function reject(promise, reason) { + if (promise._state !== PENDING) { + return; + } + promise._state = REJECTED; + promise._result = reason; + + asap(publishRejection, promise); +} + +function subscribe(parent, child, onFulfillment, onRejection) { + var _subscribers = parent._subscribers; + var length = _subscribers.length; + + parent._onerror = null; + + _subscribers[length] = child; + _subscribers[length + FULFILLED] = onFulfillment; + _subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + asap(publish, parent); + } +} + +function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (subscribers.length === 0) { + return; + } + + var child = undefined, + callback = undefined, + detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; +} + +function ErrorObject() { + this.error = null; +} + +var TRY_CATCH_ERROR = new ErrorObject(); + +function tryCatch(callback, detail) { + try { + return callback(detail); + } catch (e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } +} + +function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value = undefined, + error = undefined, + succeeded = undefined, + failed = undefined; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value.error = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, cannotReturnOwn()); + return; + } + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } +} + +function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value) { + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch (e) { + reject(promise, e); + } +} + +var id = 0; +function nextId() { + return id++; +} + +function makePromise(promise) { + promise[PROMISE_ID] = id++; + promise._state = undefined; + promise._result = undefined; + promise._subscribers = []; +} + +function Enumerator$1(Constructor, input) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop); + + if (!this.promise[PROMISE_ID]) { + makePromise(this.promise); + } + + if (isArray(input)) { + this.length = input.length; + this._remaining = input.length; + + this._result = new Array(this.length); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(input); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, validationError()); + } +} + +function validationError() { + return new Error('Array Methods must be provided an Array'); +} + +Enumerator$1.prototype._enumerate = function (input) { + for (var i = 0; this._state === PENDING && i < input.length; i++) { + this._eachEntry(input[i], i); + } +}; + +Enumerator$1.prototype._eachEntry = function (entry, i) { + var c = this._instanceConstructor; + var resolve$$1 = c.resolve; + + if (resolve$$1 === resolve$1) { + var _then = getThen(entry); + + if (_then === then && entry._state !== PENDING) { + this._settledAt(entry._state, i, entry._result); + } else if (typeof _then !== 'function') { + this._remaining--; + this._result[i] = entry; + } else if (c === Promise$2) { + var promise = new c(noop); + handleMaybeThenable(promise, entry, _then); + this._willSettleAt(promise, i); + } else { + this._willSettleAt(new c(function (resolve$$1) { + return resolve$$1(entry); + }), i); + } + } else { + this._willSettleAt(resolve$$1(entry), i); + } +}; + +Enumerator$1.prototype._settledAt = function (state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = value; + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } +}; + +Enumerator$1.prototype._willSettleAt = function (promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function (value) { + return enumerator._settledAt(FULFILLED, i, value); + }, function (reason) { + return enumerator._settledAt(REJECTED, i, reason); + }); +}; + +/** + `Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = resolve(2); + let promise3 = resolve(3); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = reject(new Error("2")); + let promise3 = reject(new Error("3")); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static +*/ +function all$1(entries) { + return new Enumerator$1(this, entries).promise; +} + +/** + `Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. +*/ +function race$1(entries) { + /*jshint validthis:true */ + var Constructor = this; + + if (!isArray(entries)) { + return new Constructor(function (_, reject) { + return reject(new TypeError('You must pass an array to race.')); + }); + } else { + return new Constructor(function (resolve, reject) { + var length = entries.length; + for (var i = 0; i < length; i++) { + Constructor.resolve(entries[i]).then(resolve, reject); + } + }); + } +} + +/** + `Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. +*/ +function reject$1(reason) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop); + reject(promise, reason); + return promise; +} + +function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); +} + +function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); +} + +/** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + let promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + let xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {function} resolver + Useful for tooling. + @constructor +*/ +function Promise$2(resolver) { + this[PROMISE_ID] = nextId(); + this._result = this._state = undefined; + this._subscribers = []; + + if (noop !== resolver) { + typeof resolver !== 'function' && needsResolver(); + this instanceof Promise$2 ? initializePromise(this, resolver) : needsNew(); + } +} + +Promise$2.all = all$1; +Promise$2.race = race$1; +Promise$2.resolve = resolve$1; +Promise$2.reject = reject$1; +Promise$2._setScheduler = setScheduler; +Promise$2._setAsap = setAsap; +Promise$2._asap = asap; + +Promise$2.prototype = { + constructor: Promise$2, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + let result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + let author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: then, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function _catch(onRejection) { + return this.then(null, onRejection); + } +}; + +/*global self*/ +function polyfill$1() { + var local = undefined; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } + + var P = local.Promise; + + if (P) { + var promiseToString = null; + try { + promiseToString = Object.prototype.toString.call(P.resolve()); + } catch (e) { + // silently ignored + } + + if (promiseToString === '[object Promise]' && !P.cast) { + return; + } + } + + local.Promise = Promise$2; +} + +// Strange compat.. +Promise$2.polyfill = polyfill$1; +Promise$2.Promise = Promise$2; + +return Promise$2; + +}))); + + + +}).call(this,require(12),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"12":12}],4:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); + err.context = er; + throw err; + } + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + args = Array.prototype.slice.call(arguments, 1); + handler.apply(this, args); + } + } else if (isObject(handler)) { + args = Array.prototype.slice.call(arguments, 1); + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.prototype.listenerCount = function(type) { + if (this._events) { + var evlistener = this._events[type]; + + if (isFunction(evlistener)) + return 1; + else if (evlistener) + return evlistener.length; + } + return 0; +}; + +EventEmitter.listenerCount = function(emitter, type) { + return emitter.listenerCount(type); +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],5:[function(require,module,exports){ + +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; + +module.exports = function forEach (obj, fn, ctx) { + if (toString.call(fn) !== '[object Function]') { + throw new TypeError('iterator must be a function'); + } + var l = obj.length; + if (l === +l) { + for (var i = 0; i < l; i++) { + fn.call(ctx, obj[i], i, obj); + } + } else { + for (var k in obj) { + if (hasOwn.call(obj, k)) { + fn.call(ctx, obj[k], k, obj); + } + } + } +}; + + +},{}],6:[function(require,module,exports){ +(function (global){ +var win; + +if (typeof window !== "undefined") { + win = window; +} else if (typeof global !== "undefined") { + win = global; +} else if (typeof self !== "undefined"){ + win = self; +} else { + win = {}; +} + +module.exports = win; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],7:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],8:[function(require,module,exports){ +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; + +},{}],9:[function(require,module,exports){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + if (ms >= d) { + return Math.round(ms / d) + 'd'; + } + if (ms >= h) { + return Math.round(ms / h) + 'h'; + } + if (ms >= m) { + return Math.round(ms / m) + 'm'; + } + if (ms >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + return plural(ms, d, 'day') || + plural(ms, h, 'hour') || + plural(ms, m, 'minute') || + plural(ms, s, 'second') || + ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) { + return; + } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; + } + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +},{}],10:[function(require,module,exports){ +'use strict'; + +// modified from https://github.com/es-shims/es5-shim +var has = Object.prototype.hasOwnProperty; +var toStr = Object.prototype.toString; +var slice = Array.prototype.slice; +var isArgs = require(11); +var isEnumerable = Object.prototype.propertyIsEnumerable; +var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); +var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); +var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' +]; +var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; +}; +var excludedKeys = { + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true +}; +var hasAutomationEqualityBug = (function () { + /* global window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; +}()); +var equalsConstructorPrototypeIfNotBuggy = function (o) { + /* global window */ + if (typeof window === 'undefined' || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } +}; + +var keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; + + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } + + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; +}; + +keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function () { + // Safari 5.0 bug + return (Object.keys(arguments) || '').length === 2; + }(1, 2)); + if (!keysWorksWithArguments) { + var originalKeys = Object.keys; + Object.keys = function keys(object) { + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } else { + return originalKeys(object); + } + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; +}; + +module.exports = keysShim; + +},{"11":11}],11:[function(require,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + toStr.call(value.callee) === '[object Function]'; + } + return isArgs; +}; + +},{}],12:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],13:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; + + case 'boolean': + return v ? 'true' : 'false'; + + case 'number': + return isFinite(v) ? v : ''; + + default: + return ''; + } +}; + +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; + } + + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); + } + }).join(sep); + + } + + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); + } + return res; +} + +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + return res; +}; + +},{}],14:[function(require,module,exports){ +module.exports = AlgoliaSearch; + +var Index = require(16); +var deprecate = require(26); +var deprecatedMessage = require(27); +var AlgoliaSearchCore = require(15); +var inherits = require(7); +var errors = require(28); + +function AlgoliaSearch() { + AlgoliaSearchCore.apply(this, arguments); +} + +inherits(AlgoliaSearch, AlgoliaSearchCore); + +/* + * Delete an index + * + * @param indexName the name of index to delete + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.deleteIndex = function(indexName, callback) { + return this._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexName), + hostType: 'write', + callback: callback + }); +}; + +/** + * Move an existing index. + * @param srcIndexName the name of index to copy. + * @param dstIndexName the new index name that will contains a copy of + * srcIndexName (destination will be overriten if it already exist). + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.moveIndex = function(srcIndexName, dstIndexName, callback) { + var postObj = { + operation: 'move', destination: dstIndexName + }; + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Copy an existing index. + * @param srcIndexName the name of index to copy. + * @param dstIndexName the new index name that will contains a copy + * of srcIndexName (destination will be overriten if it already exist). + * @param scope an array of scopes to copy: ['settings', 'synonyms', 'rules'] + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.copyIndex = function(srcIndexName, dstIndexName, scopeOrCallback, _callback) { + var postObj = { + operation: 'copy', + destination: dstIndexName + }; + var callback = _callback; + if (typeof scopeOrCallback === 'function') { + // oops, old behaviour of third argument being a function + callback = scopeOrCallback; + } else if (Array.isArray(scopeOrCallback) && scopeOrCallback.length > 0) { + postObj.scope = scopeOrCallback; + } else if (typeof scopeOrCallback !== 'undefined') { + throw new Error('the scope given to `copyIndex` was not an array with settings, synonyms or rules'); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Return last log entries. + * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry). + * @param length Specify the maximum number of entries to retrieve starting + * at offset. Maximum allowed value: 1000. + * @param type Specify the maximum number of entries to retrieve starting + * at offset. Maximum allowed value: 1000. + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer that contains the task ID + */ +AlgoliaSearch.prototype.getLogs = function(offset, length, callback) { + var clone = require(24); + var params = {}; + if (typeof offset === 'object') { + // getLogs(params) + params = clone(offset); + callback = length; + } else if (arguments.length === 0 || typeof offset === 'function') { + // getLogs([cb]) + callback = offset; + } else if (arguments.length === 1 || typeof length === 'function') { + // getLogs(1, [cb)] + callback = length; + params.offset = offset; + } else { + // getLogs(1, 2, [cb]) + params.offset = offset; + params.length = length; + } + + if (params.offset === undefined) params.offset = 0; + if (params.length === undefined) params.length = 10; + + return this._jsonRequest({ + method: 'GET', + url: '/1/logs?' + this._getSearchParams(params, ''), + hostType: 'read', + callback: callback + }); +}; + +/* + * List all existing indexes (paginated) + * + * @param page The page to retrieve, starting at 0. + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with index list + */ +AlgoliaSearch.prototype.listIndexes = function(page, callback) { + var params = ''; + + if (page === undefined || typeof page === 'function') { + callback = page; + } else { + params = '?page=' + page; + } + + return this._jsonRequest({ + method: 'GET', + url: '/1/indexes' + params, + hostType: 'read', + callback: callback + }); +}; + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearch.prototype.initIndex = function(indexName) { + return new Index(this, indexName); +}; + +AlgoliaSearch.prototype.initAnalytics = function(opts) { + // the actual require must be inside the function, when put outside then you have a cyclic dependency + // not well resolved that ends up making the main "./index.js" (main module, the agloliasearch function) + // export an object instead of a function + // Other workarounds: + // - rewrite the lib in ES6, cyclic dependencies may be better supported + // - move initAnalytics to a property on the main module (algoliasearch.initAnalytics), + // same as places. + // The current API was made mostly to mimic the one made in PHP + var createAnalyticsClient = require(25); + return createAnalyticsClient(this.applicationID, this.apiKey, opts); +}; + +/* + * @deprecated use client.listApiKeys + */ +AlgoliaSearch.prototype.listUserKeys = deprecate(function(callback) { + return this.listApiKeys(callback); +}, deprecatedMessage('client.listUserKeys()', 'client.listApiKeys()')); + +/* + * List all existing api keys with their associated ACLs + * + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with api keys list + */ +AlgoliaSearch.prototype.listApiKeys = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/keys', + hostType: 'read', + callback: callback + }); +}; + +/* + * @deprecated see client.getApiKey + */ +AlgoliaSearch.prototype.getUserKeyACL = deprecate(function(key, callback) { + return this.getApiKey(key, callback); +}, deprecatedMessage('client.getUserKeyACL()', 'client.getApiKey()')); + +/* + * Get an API key + * + * @param key + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the right API key + */ +AlgoliaSearch.prototype.getApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/keys/' + key, + hostType: 'read', + callback: callback + }); +}; + +/* + * @deprecated see client.deleteApiKey + */ +AlgoliaSearch.prototype.deleteUserKey = deprecate(function(key, callback) { + return this.deleteApiKey(key, callback); +}, deprecatedMessage('client.deleteUserKey()', 'client.deleteApiKey()')); + +/* + * Delete an existing API key + * @param key + * @param callback the result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the date of deletion + */ +AlgoliaSearch.prototype.deleteApiKey = function(key, callback) { + return this._jsonRequest({ + method: 'DELETE', + url: '/1/keys/' + key, + hostType: 'write', + callback: callback + }); +}; + +/* + @deprecated see client.addApiKey + */ +AlgoliaSearch.prototype.addUserKey = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('client.addUserKey()', 'client.addApiKey()')); + +/* + * Add a new global API key + * + * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that + * can contains the following values: + * - search: allow to search (https and http) + * - addObject: allows to add/update an object in the index (https only) + * - deleteObject : allows to delete an existing object (https only) + * - deleteIndex : allows to delete index content (https only) + * - settings : allows to get index settings (https only) + * - editSettings : allows to change index settings (https only) + * @param {Object} [params] - Optionnal parameters to set for the key + * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key) + * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour + * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call + * @param {string[]} params.indexes - Allowed targeted indexes for this key + * @param {string} params.description - A description for your key + * @param {string[]} params.referers - A list of authorized referers + * @param {Object} params.queryParameters - Force the key to use specific query parameters + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the added API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.addApiKey(['search'], { + * validity: 300, + * maxQueriesPerIPPerHour: 2000, + * maxHitsPerQuery: 3, + * indexes: ['fruits'], + * description: 'Eat three fruits', + * referers: ['*.algolia.com'], + * queryParameters: { + * tagFilters: ['public'], + * } + * }) + * @see {@link https://www.algolia.com/doc/rest_api#AddKey|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.addApiKey = function(acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: client.addApiKey(arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = null; + } + + var postObj = { + acl: acls + }; + + if (params) { + postObj.validity = params.validity; + postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + postObj.maxHitsPerQuery = params.maxHitsPerQuery; + postObj.indexes = params.indexes; + postObj.description = params.description; + + if (params.queryParameters) { + postObj.queryParameters = this._getSearchParams(params.queryParameters, ''); + } + + postObj.referers = params.referers; + } + + return this._jsonRequest({ + method: 'POST', + url: '/1/keys', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * @deprecated Please use client.addApiKey() + */ +AlgoliaSearch.prototype.addUserKeyWithValidity = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('client.addUserKeyWithValidity()', 'client.addApiKey()')); + +/** + * @deprecated Please use client.updateApiKey() + */ +AlgoliaSearch.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { + return this.updateApiKey(key, acls, params, callback); +}, deprecatedMessage('client.updateUserKey()', 'client.updateApiKey()')); + +/** + * Update an existing API key + * @param {string} key - The key to update + * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that + * can contains the following values: + * - search: allow to search (https and http) + * - addObject: allows to add/update an object in the index (https only) + * - deleteObject : allows to delete an existing object (https only) + * - deleteIndex : allows to delete index content (https only) + * - settings : allows to get index settings (https only) + * - editSettings : allows to change index settings (https only) + * @param {Object} [params] - Optionnal parameters to set for the key + * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key) + * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour + * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call + * @param {string[]} params.indexes - Allowed targeted indexes for this key + * @param {string} params.description - A description for your key + * @param {string[]} params.referers - A list of authorized referers + * @param {Object} params.queryParameters - Force the key to use specific query parameters + * @param {Function} callback - The result callback called with two arguments + * error: null or Error('message') + * content: the server answer with the modified API key + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.updateApiKey('APIKEY', ['search'], { + * validity: 300, + * maxQueriesPerIPPerHour: 2000, + * maxHitsPerQuery: 3, + * indexes: ['fruits'], + * description: 'Eat three fruits', + * referers: ['*.algolia.com'], + * queryParameters: { + * tagFilters: ['public'], + * } + * }) + * @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} + */ +AlgoliaSearch.prototype.updateApiKey = function(key, acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: client.updateApiKey(key, arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 2 || typeof params === 'function') { + callback = params; + params = null; + } + + var putObj = { + acl: acls + }; + + if (params) { + putObj.validity = params.validity; + putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + putObj.maxHitsPerQuery = params.maxHitsPerQuery; + putObj.indexes = params.indexes; + putObj.description = params.description; + + if (params.queryParameters) { + putObj.queryParameters = this._getSearchParams(params.queryParameters, ''); + } + + putObj.referers = params.referers; + } + + return this._jsonRequest({ + method: 'PUT', + url: '/1/keys/' + key, + body: putObj, + hostType: 'write', + callback: callback + }); +}; + +/** + * Initialize a new batch of search queries + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.startQueriesBatch = deprecate(function startQueriesBatchDeprecated() { + this._batch = []; +}, deprecatedMessage('client.startQueriesBatch()', 'client.search()')); + +/** + * Add a search query in the batch + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.addQueryInBatch = deprecate(function addQueryInBatchDeprecated(indexName, query, args) { + this._batch.push({ + indexName: indexName, + query: query, + params: args + }); +}, deprecatedMessage('client.addQueryInBatch()', 'client.search()')); + +/** + * Launch the batch of queries using XMLHttpRequest. + * @deprecated use client.search() + */ +AlgoliaSearch.prototype.sendQueriesBatch = deprecate(function sendQueriesBatchDeprecated(callback) { + return this.search(this._batch, callback); +}, deprecatedMessage('client.sendQueriesBatch()', 'client.search()')); + +/** + * Perform write operations accross multiple indexes. + * + * To reduce the amount of time spent on network round trips, + * you can create, update, or delete several objects in one call, + * using the batch endpoint (all operations are done in the given order). + * + * Available actions: + * - addObject + * - updateObject + * - partialUpdateObject + * - partialUpdateObjectNoCreate + * - deleteObject + * + * https://www.algolia.com/doc/rest_api#Indexes + * @param {Object[]} operations An array of operations to perform + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.batch([{ + * action: 'addObject', + * indexName: 'clients', + * body: { + * name: 'Bill' + * } + * }, { + * action: 'udpateObject', + * indexName: 'fruits', + * body: { + * objectID: '29138', + * name: 'banana' + * } + * }], cb) + */ +AlgoliaSearch.prototype.batch = function(operations, callback) { + var isArray = require(8); + var usage = 'Usage: client.batch(operations[, callback])'; + + if (!isArray(operations)) { + throw new Error(usage); + } + + return this._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/batch', + body: { + requests: operations + }, + hostType: 'write', + callback: callback + }); +}; + +/** + * Assign or Move a userID to a cluster + * + * @param {string} data.userID The userID to assign to a new cluster + * @param {string} data.cluster The cluster to assign the user to + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.assignUserID({ cluster: 'c1-test', userID: 'some-user' }); + */ +AlgoliaSearch.prototype.assignUserID = function(data, callback) { + if (!data.userID || !data.cluster) { + throw new errors.AlgoliaSearchError('You have to provide both a userID and cluster', data); + } + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping', + hostType: 'write', + body: {cluster: data.cluster}, + callback: callback, + headers: { + 'x-algolia-user-id': data.userID + } + }); +}; + +/** + * Get the top userIDs + * + * (the callback is the second argument) + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getTopUserID(); + */ +AlgoliaSearch.prototype.getTopUserID = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping/top', + hostType: 'read', + callback: callback + }); +}; + +/** + * Get userID + * + * @param {string} data.userID The userID to get info about + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.getUserID({ userID: 'some-user' }); + */ +AlgoliaSearch.prototype.getUserID = function(data, callback) { + if (!data.userID) { + throw new errors.AlgoliaSearchError('You have to provide a userID', {debugData: data}); + } + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping/' + data.userID, + hostType: 'read', + callback: callback + }); +}; + +/** + * List all the clusters + * + * (the callback is the second argument) + * + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.listClusters(); + */ +AlgoliaSearch.prototype.listClusters = function(callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters', + hostType: 'read', + callback: callback + }); +}; + +/** + * List the userIDs + * + * (the callback is the second argument) + * + * @param {string} data.hitsPerPage How many hits on every page + * @param {string} data.page The page to retrieve + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.listClusters(); + * client.listClusters({ page: 3, hitsPerPage: 30}); + */ +AlgoliaSearch.prototype.listUserIDs = function(data, callback) { + return this._jsonRequest({ + method: 'GET', + url: '/1/clusters/mapping', + body: data, + hostType: 'read', + callback: callback + }); +}; + +/** + * Remove an userID + * + * @param {string} data.userID The userID to assign to a new cluster + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.removeUserID({ userID: 'some-user' }); + */ +AlgoliaSearch.prototype.removeUserID = function(data, callback) { + if (!data.userID) { + throw new errors.AlgoliaSearchError('You have to provide a userID', {debugData: data}); + } + return this._jsonRequest({ + method: 'DELETE', + url: '/1/clusters/mapping', + hostType: 'write', + callback: callback, + headers: { + 'x-algolia-user-id': data.userID + } + }); +}; + +/** + * Search for userIDs + * + * @param {string} data.cluster The cluster to target + * @param {string} data.query The query to execute + * @param {string} data.hitsPerPage How many hits on every page + * @param {string} data.page The page to retrieve + * @return {Promise|undefined} Returns a promise if no callback given + * @example + * client.searchUserIDs({ cluster: 'c1-test', query: 'some-user' }); + * client.searchUserIDs({ + * cluster: "c1-test", + * query: "some-user", + * page: 3, + * hitsPerPage: 2 + * }); + */ +AlgoliaSearch.prototype.searchUserIDs = function(data, callback) { + return this._jsonRequest({ + method: 'POST', + url: '/1/clusters/mapping/search', + body: data, + hostType: 'read', + callback: callback + }); +}; + +// environment specific methods +AlgoliaSearch.prototype.destroy = notImplemented; +AlgoliaSearch.prototype.enableRateLimitForward = notImplemented; +AlgoliaSearch.prototype.disableRateLimitForward = notImplemented; +AlgoliaSearch.prototype.useSecuredAPIKey = notImplemented; +AlgoliaSearch.prototype.disableSecuredAPIKey = notImplemented; +AlgoliaSearch.prototype.generateSecuredApiKey = notImplemented; + +function notImplemented() { + var message = 'Not implemented in this environment.\n' + + 'If you feel this is a mistake, write to support@algolia.com'; + + throw new errors.AlgoliaSearchError(message); +} + +},{"15":15,"16":16,"24":24,"25":25,"26":26,"27":27,"28":28,"7":7,"8":8}],15:[function(require,module,exports){ +(function (process){ +module.exports = AlgoliaSearchCore; + +var errors = require(28); +var exitPromise = require(29); +var IndexCore = require(18); +var store = require(34); + +// We will always put the API KEY in the JSON body in case of too long API KEY, +// to avoid query string being too long and failing in various conditions (our server limit, browser limit, +// proxies limit) +var MAX_API_KEY_LENGTH = 500; +var RESET_APP_DATA_TIMER = + process.env.RESET_APP_DATA_TIMER && parseInt(process.env.RESET_APP_DATA_TIMER, 10) || + 60 * 2 * 1000; // after 2 minutes reset to first host + +/* + * Algolia Search library initialization + * https://www.algolia.com/ + * + * @param {string} applicationID - Your applicationID, found in your dashboard + * @param {string} apiKey - Your API key, found in your dashboard + * @param {Object} [opts] + * @param {number} [opts.timeout=2000] - The request timeout set in milliseconds, + * another request will be issued after this timeout + * @param {string} [opts.protocol='https:'] - The protocol used to query Algolia Search API. + * Set to 'http:' to force using http. + * @param {Object|Array} [opts.hosts={ + * read: [this.applicationID + '-dsn.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]), + * write: [this.applicationID + '.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]) - The hosts to use for Algolia Search API. + * If you provide them, you will less benefit from our HA implementation + */ +function AlgoliaSearchCore(applicationID, apiKey, opts) { + var debug = require(1)('algoliasearch'); + + var clone = require(24); + var isArray = require(8); + var map = require(30); + + var usage = 'Usage: algoliasearch(applicationID, apiKey, opts)'; + + if (opts._allowEmptyCredentials !== true && !applicationID) { + throw new errors.AlgoliaSearchError('Please provide an application ID. ' + usage); + } + + if (opts._allowEmptyCredentials !== true && !apiKey) { + throw new errors.AlgoliaSearchError('Please provide an API key. ' + usage); + } + + this.applicationID = applicationID; + this.apiKey = apiKey; + + this.hosts = { + read: [], + write: [] + }; + + opts = opts || {}; + + this._timeouts = opts.timeouts || { + connect: 1 * 1000, // 500ms connect is GPRS latency + read: 2 * 1000, + write: 30 * 1000 + }; + + // backward compat, if opts.timeout is passed, we use it to configure all timeouts like before + if (opts.timeout) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = opts.timeout; + } + + var protocol = opts.protocol || 'https:'; + // while we advocate for colon-at-the-end values: 'http:' for `opts.protocol` + // we also accept `http` and `https`. It's a common error. + if (!/:$/.test(protocol)) { + protocol = protocol + ':'; + } + + if (protocol !== 'http:' && protocol !== 'https:') { + throw new errors.AlgoliaSearchError('protocol must be `http:` or `https:` (was `' + opts.protocol + '`)'); + } + + this._checkAppIdData(); + + if (!opts.hosts) { + var defaultHosts = map(this._shuffleResult, function(hostNumber) { + return applicationID + '-' + hostNumber + '.algolianet.com'; + }); + + // no hosts given, compute defaults + var mainSuffix = (opts.dsn === false ? '' : '-dsn') + '.algolia.net'; + this.hosts.read = [this.applicationID + mainSuffix].concat(defaultHosts); + this.hosts.write = [this.applicationID + '.algolia.net'].concat(defaultHosts); + } else if (isArray(opts.hosts)) { + // when passing custom hosts, we need to have a different host index if the number + // of write/read hosts are different. + this.hosts.read = clone(opts.hosts); + this.hosts.write = clone(opts.hosts); + } else { + this.hosts.read = clone(opts.hosts.read); + this.hosts.write = clone(opts.hosts.write); + } + + // add protocol and lowercase hosts + this.hosts.read = map(this.hosts.read, prepareHost(protocol)); + this.hosts.write = map(this.hosts.write, prepareHost(protocol)); + + this.extraHeaders = {}; + + // In some situations you might want to warm the cache + this.cache = opts._cache || {}; + + this._ua = opts._ua; + this._useCache = opts._useCache === undefined || opts._cache ? true : opts._useCache; + this._useRequestCache = this._useCache && opts._useRequestCache; + this._useFallback = opts.useFallback === undefined ? true : opts.useFallback; + + this._setTimeout = opts._setTimeout; + + debug('init done, %j', this); +} + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearchCore.prototype.initIndex = function(indexName) { + return new IndexCore(this, indexName); +}; + +/** +* Add an extra field to the HTTP request +* +* @param name the header field name +* @param value the header field value +*/ +AlgoliaSearchCore.prototype.setExtraHeader = function(name, value) { + this.extraHeaders[name.toLowerCase()] = value; +}; + +/** +* Get the value of an extra HTTP header +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.getExtraHeader = function(name) { + return this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Remove an extra field from the HTTP request +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.unsetExtraHeader = function(name) { + delete this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Augment sent x-algolia-agent with more data, each agent part +* is automatically separated from the others by a semicolon; +* +* @param algoliaAgent the agent to add +*/ +AlgoliaSearchCore.prototype.addAlgoliaAgent = function(algoliaAgent) { + if (this._ua.indexOf(';' + algoliaAgent) === -1) { + this._ua += ';' + algoliaAgent; + } +}; + +/* + * Wrapper that try all hosts to maximize the quality of service + */ +AlgoliaSearchCore.prototype._jsonRequest = function(initialOpts) { + this._checkAppIdData(); + + var requestDebug = require(1)('algoliasearch:' + initialOpts.url); + + + var body; + var cacheID; + var additionalUA = initialOpts.additionalUA || ''; + var cache = initialOpts.cache; + var client = this; + var tries = 0; + var usingFallback = false; + var hasFallback = client._useFallback && client._request.fallback && initialOpts.fallback; + var headers; + + if ( + this.apiKey.length > MAX_API_KEY_LENGTH && + initialOpts.body !== undefined && + (initialOpts.body.params !== undefined || // index.search() + initialOpts.body.requests !== undefined) // client.search() + ) { + initialOpts.body.apiKey = this.apiKey; + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + withApiKey: false, + headers: initialOpts.headers + }); + } else { + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + } + + if (initialOpts.body !== undefined) { + body = safeJSONStringify(initialOpts.body); + } + + requestDebug('request start'); + var debugData = []; + + + function doRequest(requester, reqOpts) { + client._checkAppIdData(); + + var startTime = new Date(); + + if (client._useCache && !client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && !client._useRequestCache && body) { + cacheID += '_body_' + reqOpts.body; + } + + // handle cache existence + if (isCacheValidWithCurrentID(!client._useRequestCache, cache, cacheID)) { + requestDebug('serving response from cache'); + + var responseText = cache[cacheID]; + + // Cache response must match the type of the original one + return client._promise.resolve({ + body: JSON.parse(responseText), + responseText: responseText + }); + } + + // if we reached max tries + if (tries >= client.hosts[initialOpts.hostType].length) { + if (!hasFallback || usingFallback) { + requestDebug('could not get any response'); + // then stop + return client._promise.reject(new errors.AlgoliaSearchError( + 'Cannot connect to the AlgoliaSearch API.' + + ' Send an email to support@algolia.com to report and resolve the issue.' + + ' Application id was: ' + client.applicationID, {debugData: debugData} + )); + } + + requestDebug('switching to fallback'); + + // let's try the fallback starting from here + tries = 0; + + // method, url and body are fallback dependent + reqOpts.method = initialOpts.fallback.method; + reqOpts.url = initialOpts.fallback.url; + reqOpts.jsonBody = initialOpts.fallback.body; + if (reqOpts.jsonBody) { + reqOpts.body = safeJSONStringify(reqOpts.jsonBody); + } + // re-compute headers, they could be omitting the API KEY + headers = client._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + client._setHostIndexByType(0, initialOpts.hostType); + usingFallback = true; // the current request is now using fallback + return doRequest(client._request.fallback, reqOpts); + } + + var currentHost = client._getHostByType(initialOpts.hostType); + + var url = currentHost + reqOpts.url; + var options = { + body: reqOpts.body, + jsonBody: reqOpts.jsonBody, + method: reqOpts.method, + headers: headers, + timeouts: reqOpts.timeouts, + debug: requestDebug, + forceAuthHeaders: reqOpts.forceAuthHeaders + }; + + requestDebug('method: %s, url: %s, headers: %j, timeouts: %d', + options.method, url, options.headers, options.timeouts); + + if (requester === client._request.fallback) { + requestDebug('using fallback'); + } + + // `requester` is any of this._request or this._request.fallback + // thus it needs to be called using the client as context + return requester.call(client, url, options).then(success, tryFallback); + + function success(httpResponse) { + // compute the status of the response, + // + // When in browser mode, using XDR or JSONP, we have no statusCode available + // So we rely on our API response `status` property. + // But `waitTask` can set a `status` property which is not the statusCode (it's the task status) + // So we check if there's a `message` along `status` and it means it's an error + // + // That's the only case where we have a response.status that's not the http statusCode + var status = httpResponse && httpResponse.body && httpResponse.body.message && httpResponse.body.status || + + // this is important to check the request statusCode AFTER the body eventual + // statusCode because some implementations (jQuery XDomainRequest transport) may + // send statusCode 200 while we had an error + httpResponse.statusCode || + + // When in browser mode, using XDR or JSONP + // we default to success when no error (no response.status && response.message) + // If there was a JSON.parse() error then body is null and it fails + httpResponse && httpResponse.body && 200; + + requestDebug('received response: statusCode: %s, computed statusCode: %d, headers: %j', + httpResponse.statusCode, status, httpResponse.headers); + + var httpResponseOk = Math.floor(status / 100) === 2; + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime, + statusCode: status + }); + + if (httpResponseOk) { + if (client._useCache && !client._useRequestCache && cache) { + cache[cacheID] = httpResponse.responseText; + } + + return { + responseText: httpResponse.responseText, + body: httpResponse.body + }; + } + + var shouldRetry = Math.floor(status / 100) !== 4; + + if (shouldRetry) { + tries += 1; + return retryRequest(); + } + + requestDebug('unrecoverable error'); + + // no success and no retry => fail + var unrecoverableError = new errors.AlgoliaSearchError( + httpResponse.body && httpResponse.body.message, {debugData: debugData, statusCode: status} + ); + + return client._promise.reject(unrecoverableError); + } + + function tryFallback(err) { + // error cases: + // While not in fallback mode: + // - CORS not supported + // - network error + // While in fallback mode: + // - timeout + // - network error + // - badly formatted JSONP (script loaded, did not call our callback) + // In both cases: + // - uncaught exception occurs (TypeError) + requestDebug('error: %s, stack: %s', err.message, err.stack); + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime + }); + + if (!(err instanceof errors.AlgoliaSearchError)) { + err = new errors.Unknown(err && err.message, err); + } + + tries += 1; + + // stop the request implementation when: + if ( + // we did not generate this error, + // it comes from a throw in some other piece of code + err instanceof errors.Unknown || + + // server sent unparsable JSON + err instanceof errors.UnparsableJSON || + + // max tries and already using fallback or no fallback + tries >= client.hosts[initialOpts.hostType].length && + (usingFallback || !hasFallback)) { + // stop request implementation for this command + err.debugData = debugData; + return client._promise.reject(err); + } + + // When a timeout occured, retry by raising timeout + if (err instanceof errors.RequestTimeout) { + return retryRequestWithHigherTimeout(); + } + + return retryRequest(); + } + + function retryRequest() { + requestDebug('retrying request'); + client._incrementHostIndex(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + + function retryRequestWithHigherTimeout() { + requestDebug('retrying request with higher timeout'); + client._incrementHostIndex(initialOpts.hostType); + client._incrementTimeoutMultipler(); + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + } + + function isCacheValidWithCurrentID( + useRequestCache, + currentCache, + currentCacheID + ) { + return ( + client._useCache && + useRequestCache && + currentCache && + currentCache[currentCacheID] !== undefined + ); + } + + + function interopCallbackReturn(request, callback) { + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + request.catch(function() { + // Release the cache on error + delete cache[cacheID]; + }); + } + + if (typeof initialOpts.callback === 'function') { + // either we have a callback + request.then(function okCb(content) { + exitPromise(function() { + initialOpts.callback(null, callback(content)); + }, client._setTimeout || setTimeout); + }, function nookCb(err) { + exitPromise(function() { + initialOpts.callback(err); + }, client._setTimeout || setTimeout); + }); + } else { + // either we are using promises + return request.then(callback); + } + } + + if (client._useCache && client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && client._useRequestCache && body) { + cacheID += '_body_' + body; + } + + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + requestDebug('serving request from cache'); + + var maybePromiseForCache = cache[cacheID]; + + // In case the cache is warmup with value that is not a promise + var promiseForCache = typeof maybePromiseForCache.then !== 'function' + ? client._promise.resolve({responseText: maybePromiseForCache}) + : maybePromiseForCache; + + return interopCallbackReturn(promiseForCache, function(content) { + // In case of the cache request, return the original value + return JSON.parse(content.responseText); + }); + } + + var request = doRequest( + client._request, { + url: initialOpts.url, + method: initialOpts.method, + body: body, + jsonBody: initialOpts.body, + timeouts: client._getTimeoutsForRequest(initialOpts.hostType), + forceAuthHeaders: initialOpts.forceAuthHeaders + } + ); + + if (client._useCache && client._useRequestCache && cache) { + cache[cacheID] = request; + } + + return interopCallbackReturn(request, function(content) { + // In case of the first request, return the JSON value + return content.body; + }); +}; + +/* +* Transform search param object in query string +* @param {object} args arguments to add to the current query string +* @param {string} params current query string +* @return {string} the final query string +*/ +AlgoliaSearchCore.prototype._getSearchParams = function(args, params) { + if (args === undefined || args === null) { + return params; + } + for (var key in args) { + if (key !== null && args[key] !== undefined && args.hasOwnProperty(key)) { + params += params === '' ? '' : '&'; + params += key + '=' + encodeURIComponent(Object.prototype.toString.call(args[key]) === '[object Array]' ? safeJSONStringify(args[key]) : args[key]); + } + } + return params; +}; + +/** + * Compute the headers for a request + * + * @param [string] options.additionalUA semi-colon separated string with other user agents to add + * @param [boolean=true] options.withApiKey Send the api key as a header + * @param [Object] options.headers Extra headers to send + */ +AlgoliaSearchCore.prototype._computeRequestHeaders = function(options) { + var forEach = require(5); + + var ua = options.additionalUA ? + this._ua + ';' + options.additionalUA : + this._ua; + + var requestHeaders = { + 'x-algolia-agent': ua, + 'x-algolia-application-id': this.applicationID + }; + + // browser will inline headers in the url, node.js will use http headers + // but in some situations, the API KEY will be too long (big secured API keys) + // so if the request is a POST and the KEY is very long, we will be asked to not put + // it into headers but in the JSON body + if (options.withApiKey !== false) { + requestHeaders['x-algolia-api-key'] = this.apiKey; + } + + if (this.userToken) { + requestHeaders['x-algolia-usertoken'] = this.userToken; + } + + if (this.securityTags) { + requestHeaders['x-algolia-tagfilters'] = this.securityTags; + } + + forEach(this.extraHeaders, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + + if (options.headers) { + forEach(options.headers, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + } + + return requestHeaders; +}; + +/** + * Search through multiple indices at the same time + * @param {Object[]} queries An array of queries you want to run. + * @param {string} queries[].indexName The index name you want to target + * @param {string} [queries[].query] The query to issue on this index. Can also be passed into `params` + * @param {Object} queries[].params Any search param like hitsPerPage, .. + * @param {Function} callback Callback to be called + * @return {Promise|undefined} Returns a promise if no callback given + */ +AlgoliaSearchCore.prototype.search = function(queries, opts, callback) { + var isArray = require(8); + var map = require(30); + + var usage = 'Usage: client.search(arrayOfQueries[, callback])'; + + if (!isArray(queries)) { + throw new Error(usage); + } + + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var client = this; + + var postObj = { + requests: map(queries, function prepareRequest(query) { + var params = ''; + + // allow query.query + // so we are mimicing the index.search(query, params) method + // {indexName:, query:, params:} + if (query.query !== undefined) { + params += 'query=' + encodeURIComponent(query.query); + } + + return { + indexName: query.indexName, + params: client._getSearchParams(query.params, params) + }; + }) + }; + + var JSONPParams = map(postObj.requests, function prepareJSONPParams(request, requestId) { + return requestId + '=' + + encodeURIComponent( + '/1/indexes/' + encodeURIComponent(request.indexName) + '?' + + request.params + ); + }).join('&'); + + var url = '/1/indexes/*/queries'; + + if (opts.strategy !== undefined) { + postObj.strategy = opts.strategy; + } + + return this._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url, + body: postObj, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/*', + body: { + params: JSONPParams + } + }, + callback: callback + }); +}; + +/** +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* This is the top-level API for SFFV. +* +* @param {object[]} queries An array of queries to run. +* @param {string} queries[].indexName Index name, name of the index to search. +* @param {object} queries[].params Query parameters. +* @param {string} queries[].params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} queries[].params.facetQuery Query for the facet search +* @param {string} [queries[].params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +*/ +AlgoliaSearchCore.prototype.searchForFacetValues = function(queries) { + var isArray = require(8); + var map = require(30); + + var usage = 'Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])'; // eslint-disable-line max-len + + if (!isArray(queries)) { + throw new Error(usage); + } + + var client = this; + + return client._promise.all(map(queries, function performQuery(query) { + if ( + !query || + query.indexName === undefined || + query.params.facetName === undefined || + query.params.facetQuery === undefined + ) { + throw new Error(usage); + } + + var clone = require(24); + var omit = require(32); + + var indexName = query.indexName; + var params = query.params; + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = client._getSearchParams(filteredParams, ''); + + return client._jsonRequest({ + cache: client.cache, + method: 'POST', + url: + '/1/indexes/' + + encodeURIComponent(indexName) + + '/facets/' + + encodeURIComponent(facetName) + + '/query', + hostType: 'read', + body: {params: searchParameters} + }); + })); +}; + +/** + * Set the extra security tagFilters header + * @param {string|array} tags The list of tags defining the current security filters + */ +AlgoliaSearchCore.prototype.setSecurityTags = function(tags) { + if (Object.prototype.toString.call(tags) === '[object Array]') { + var strTags = []; + for (var i = 0; i < tags.length; ++i) { + if (Object.prototype.toString.call(tags[i]) === '[object Array]') { + var oredTags = []; + for (var j = 0; j < tags[i].length; ++j) { + oredTags.push(tags[i][j]); + } + strTags.push('(' + oredTags.join(',') + ')'); + } else { + strTags.push(tags[i]); + } + } + tags = strTags.join(','); + } + + this.securityTags = tags; +}; + +/** + * Set the extra user token header + * @param {string} userToken The token identifying a uniq user (used to apply rate limits) + */ +AlgoliaSearchCore.prototype.setUserToken = function(userToken) { + this.userToken = userToken; +}; + +/** + * Clear all queries in client's cache + * @return undefined + */ +AlgoliaSearchCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/** +* Set the number of milliseconds a request can take before automatically being terminated. +* @deprecated +* @param {Number} milliseconds +*/ +AlgoliaSearchCore.prototype.setRequestTimeout = function(milliseconds) { + if (milliseconds) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = milliseconds; + } +}; + +/** +* Set the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.setTimeouts = function(timeouts) { + this._timeouts = timeouts; +}; + +/** +* Get the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.getTimeouts = function() { + return this._timeouts; +}; + +AlgoliaSearchCore.prototype._getAppIdData = function() { + var data = store.get(this.applicationID); + if (data !== null) this._cacheAppIdData(data); + return data; +}; + +AlgoliaSearchCore.prototype._setAppIdData = function(data) { + data.lastChange = (new Date()).getTime(); + this._cacheAppIdData(data); + return store.set(this.applicationID, data); +}; + +AlgoliaSearchCore.prototype._checkAppIdData = function() { + var data = this._getAppIdData(); + var now = (new Date()).getTime(); + if (data === null || now - data.lastChange > RESET_APP_DATA_TIMER) { + return this._resetInitialAppIdData(data); + } + + return data; +}; + +AlgoliaSearchCore.prototype._resetInitialAppIdData = function(data) { + var newData = data || {}; + newData.hostIndexes = {read: 0, write: 0}; + newData.timeoutMultiplier = 1; + newData.shuffleResult = newData.shuffleResult || shuffle([1, 2, 3]); + return this._setAppIdData(newData); +}; + +AlgoliaSearchCore.prototype._cacheAppIdData = function(data) { + this._hostIndexes = data.hostIndexes; + this._timeoutMultiplier = data.timeoutMultiplier; + this._shuffleResult = data.shuffleResult; +}; + +AlgoliaSearchCore.prototype._partialAppIdDataUpdate = function(newData) { + var foreach = require(5); + var currentData = this._getAppIdData(); + foreach(newData, function(value, key) { + currentData[key] = value; + }); + + return this._setAppIdData(currentData); +}; + +AlgoliaSearchCore.prototype._getHostByType = function(hostType) { + return this.hosts[hostType][this._getHostIndexByType(hostType)]; +}; + +AlgoliaSearchCore.prototype._getTimeoutMultiplier = function() { + return this._timeoutMultiplier; +}; + +AlgoliaSearchCore.prototype._getHostIndexByType = function(hostType) { + return this._hostIndexes[hostType]; +}; + +AlgoliaSearchCore.prototype._setHostIndexByType = function(hostIndex, hostType) { + var clone = require(24); + var newHostIndexes = clone(this._hostIndexes); + newHostIndexes[hostType] = hostIndex; + this._partialAppIdDataUpdate({hostIndexes: newHostIndexes}); + return hostIndex; +}; + +AlgoliaSearchCore.prototype._incrementHostIndex = function(hostType) { + return this._setHostIndexByType( + (this._getHostIndexByType(hostType) + 1) % this.hosts[hostType].length, hostType + ); +}; + +AlgoliaSearchCore.prototype._incrementTimeoutMultipler = function() { + var timeoutMultiplier = Math.max(this._timeoutMultiplier + 1, 4); + return this._partialAppIdDataUpdate({timeoutMultiplier: timeoutMultiplier}); +}; + +AlgoliaSearchCore.prototype._getTimeoutsForRequest = function(hostType) { + return { + connect: this._timeouts.connect * this._timeoutMultiplier, + complete: this._timeouts[hostType] * this._timeoutMultiplier + }; +}; + +function prepareHost(protocol) { + return function prepare(host) { + return protocol + '//' + host.toLowerCase(); + }; +} + +// Prototype.js < 1.7, a widely used library, defines a weird +// Array.prototype.toJSON function that will fail to stringify our content +// appropriately +// refs: +// - https://groups.google.com/forum/#!topic/prototype-core/E-SAVvV_V9Q +// - https://github.com/sstephenson/prototype/commit/038a2985a70593c1a86c230fadbdfe2e4898a48c +// - http://stackoverflow.com/a/3148441/147079 +function safeJSONStringify(obj) { + /* eslint no-extend-native:0 */ + + if (Array.prototype.toJSON === undefined) { + return JSON.stringify(obj); + } + + var toJSON = Array.prototype.toJSON; + delete Array.prototype.toJSON; + var out = JSON.stringify(obj); + Array.prototype.toJSON = toJSON; + + return out; +} + +function shuffle(array) { + var currentIndex = array.length; + var temporaryValue; + var randomIndex; + + // While there remain elements to shuffle... + while (currentIndex !== 0) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + + return array; +} + +function removeCredentials(headers) { + var newHeaders = {}; + + for (var headerName in headers) { + if (Object.prototype.hasOwnProperty.call(headers, headerName)) { + var value; + + if (headerName === 'x-algolia-api-key' || headerName === 'x-algolia-application-id') { + value = '**hidden for security purposes**'; + } else { + value = headers[headerName]; + } + + newHeaders[headerName] = value; + } + } + + return newHeaders; +} + +}).call(this,require(12)) +},{"1":1,"12":12,"18":18,"24":24,"28":28,"29":29,"30":30,"32":32,"34":34,"5":5,"8":8}],16:[function(require,module,exports){ +var inherits = require(7); +var IndexCore = require(18); +var deprecate = require(26); +var deprecatedMessage = require(27); +var exitPromise = require(29); +var errors = require(28); + +var deprecateForwardToSlaves = deprecate( + function() {}, + deprecatedMessage('forwardToSlaves', 'forwardToReplicas') +); + +module.exports = Index; + +function Index() { + IndexCore.apply(this, arguments); +} + +inherits(Index, IndexCore); + +/* +* Add an object in this index +* +* @param content contains the javascript object to add inside the index +* @param objectID (optional) an objectID you want to attribute to this object +* (if the attribute already exist the old object will be overwrite) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.addObject = function(content, objectID, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof objectID === 'function') { + callback = objectID; + objectID = undefined; + } + + return this.as._jsonRequest({ + method: objectID !== undefined ? + 'PUT' : // update or create + 'POST', // create (API generates an objectID) + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + // create + (objectID !== undefined ? '/' + encodeURIComponent(objectID) : ''), // update or create + body: content, + hostType: 'write', + callback: callback + }); +}; + +/* +* Add several objects +* +* @param objects contains an array of objects to add +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.addObjects = function(objects, callback) { + var isArray = require(8); + var usage = 'Usage: index.addObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: 'addObject', + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Update partially an object (only update attributes passed in argument) +* +* @param partialObject contains the javascript attributes to override, the +* object must contains an objectID attribute +* @param createIfNotExists (optional) if false, avoid an automatic creation of the object +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.partialUpdateObject = function(partialObject, createIfNotExists, callback) { + if (arguments.length === 1 || typeof createIfNotExists === 'function') { + callback = createIfNotExists; + createIfNotExists = undefined; + } + + var indexObj = this; + var url = '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(partialObject.objectID) + '/partial'; + if (createIfNotExists === false) { + url += '?createIfNotExists=false'; + } + + return this.as._jsonRequest({ + method: 'POST', + url: url, + body: partialObject, + hostType: 'write', + callback: callback + }); +}; + +/* +* Partially Override the content of several objects +* +* @param objects contains an array of objects to update (each object must contains a objectID attribute) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.partialUpdateObjects = function(objects, createIfNotExists, callback) { + if (arguments.length === 1 || typeof createIfNotExists === 'function') { + callback = createIfNotExists; + createIfNotExists = true; + } + + var isArray = require(8); + var usage = 'Usage: index.partialUpdateObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: createIfNotExists === true ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate', + objectID: objects[i].objectID, + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Override the content of object +* +* @param object contains the javascript object to save, the object must contains an objectID attribute +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.saveObject = function(object, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(object.objectID), + body: object, + hostType: 'write', + callback: callback + }); +}; + +/* +* Override the content of several objects +* +* @param objects contains an array of objects to update (each object must contains a objectID attribute) +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that updateAt and taskID +*/ +Index.prototype.saveObjects = function(objects, callback) { + var isArray = require(8); + var usage = 'Usage: index.saveObjects(arrayOfObjects[, callback])'; + + if (!isArray(objects)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: [] + }; + for (var i = 0; i < objects.length; ++i) { + var request = { + action: 'updateObject', + objectID: objects[i].objectID, + body: objects[i] + }; + postObj.requests.push(request); + } + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete an object from the index +* +* @param objectID the unique identifier of object to delete +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.deleteObject = function(objectID, callback) { + if (typeof objectID === 'function' || typeof objectID !== 'string' && typeof objectID !== 'number') { + var err = new errors.AlgoliaSearchError( + objectID && typeof objectID !== 'function' + ? 'ObjectID must be a string' + : 'Cannot delete an object without an objectID' + ); + callback = objectID; + if (typeof callback === 'function') { + return callback(err); + } + + return this.as._promise.reject(err); + } + + var indexObj = this; + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID), + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete several objects from an index +* +* @param objectIDs contains an array of objectID to delete +* @param callback (optional) the result callback called with two arguments: +* error: null or Error('message') +* content: the server answer that contains 3 elements: createAt, taskId and objectID +*/ +Index.prototype.deleteObjects = function(objectIDs, callback) { + var isArray = require(8); + var map = require(30); + + var usage = 'Usage: index.deleteObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + var postObj = { + requests: map(objectIDs, function prepareRequest(objectID) { + return { + action: 'deleteObject', + objectID: objectID, + body: { + objectID: objectID + } + }; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', + body: postObj, + hostType: 'write', + callback: callback + }); +}; + +/* +* Delete all objects matching a query +* +* @param query the query string +* @param params the optional query parameters +* @param callback (optional) the result callback called with one argument +* error: null or Error('message') +* @deprecated see index.deleteBy +*/ +Index.prototype.deleteByQuery = deprecate(function(query, params, callback) { + var clone = require(24); + var map = require(30); + + var indexObj = this; + var client = indexObj.as; + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = {}; + } else { + params = clone(params); + } + + params.attributesToRetrieve = 'objectID'; + params.hitsPerPage = 1000; + params.distinct = false; + + // when deleting, we should never use cache to get the + // search results + this.clearCache(); + + // there's a problem in how we use the promise chain, + // see how waitTask is done + var promise = this + .search(query, params) + .then(stopOrDelete); + + function stopOrDelete(searchContent) { + // stop here + if (searchContent.nbHits === 0) { + // return indexObj.as._request.resolve(); + return searchContent; + } + + // continue and do a recursive call + var objectIDs = map(searchContent.hits, function getObjectID(object) { + return object.objectID; + }); + + return indexObj + .deleteObjects(objectIDs) + .then(waitTask) + .then(doDeleteByQuery); + } + + function waitTask(deleteObjectsContent) { + return indexObj.waitTask(deleteObjectsContent.taskID); + } + + function doDeleteByQuery() { + return indexObj.deleteByQuery(query, params); + } + + if (!callback) { + return promise; + } + + promise.then(success, failure); + + function success() { + exitPromise(function exit() { + callback(null); + }, client._setTimeout || setTimeout); + } + + function failure(err) { + exitPromise(function exit() { + callback(err); + }, client._setTimeout || setTimeout); + } +}, deprecatedMessage('index.deleteByQuery()', 'index.deleteBy()')); + +/** +* Delete all objects matching a query +* +* the query parameters that can be used are: +* - filters (numeric, facet, tag) +* - geo +* +* you can not send an empty query or filters +* +* @param params the optional query parameters +* @param callback (optional) the result callback called with one argument +* error: null or Error('message') +*/ +Index.prototype.deleteBy = function(params, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/deleteByQuery', + body: {params: indexObj.as._getSearchParams(params, '')}, + hostType: 'write', + callback: callback + }); +}; + +/* +* Browse all content from an index using events. Basically this will do +* .browse() -> .browseFrom -> .browseFrom -> .. until all the results are returned +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @return {EventEmitter} +* @example +* var browser = index.browseAll('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }); +* +* browser.on('result', function resultCallback(content) { +* console.log(content.hits); +* }); +* +* // if any error occurs, you get it +* browser.on('error', function(err) { +* throw err; +* }); +* +* // when you have browsed the whole index, you get this event +* browser.on('end', function() { +* console.log('finished'); +* }); +* +* // at any point if you want to stop the browsing process, you can stop it manually +* // otherwise it will go on and on +* browser.stop(); +* +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +Index.prototype.browseAll = function(query, queryParameters) { + if (typeof query === 'object') { + queryParameters = query; + query = undefined; + } + + var merge = require(31); + + var IndexBrowser = require(17); + + var browser = new IndexBrowser(); + var client = this.as; + var index = this; + var params = client._getSearchParams( + merge({}, queryParameters || {}, { + query: query + }), '' + ); + + // start browsing + browseLoop(); + + function browseLoop(cursor) { + if (browser._stopped) { + return; + } + + var body; + + if (cursor !== undefined) { + body = { + cursor: cursor + }; + } else { + body = { + params: params + }; + } + + client._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(index.indexName) + '/browse', + hostType: 'read', + body: body, + callback: browseCallback + }); + } + + function browseCallback(err, content) { + if (browser._stopped) { + return; + } + + if (err) { + browser._error(err); + return; + } + + browser._result(content); + + // no cursor means we are finished browsing + if (content.cursor === undefined) { + browser._end(); + return; + } + + browseLoop(content.cursor); + } + + return browser; +}; + +/* +* Get a Typeahead.js adapter +* @param searchParams contains an object with query parameters (see search for details) +*/ +Index.prototype.ttAdapter = deprecate(function(params) { + var self = this; + return function ttAdapter(query, syncCb, asyncCb) { + var cb; + + if (typeof asyncCb === 'function') { + // typeahead 0.11 + cb = asyncCb; + } else { + // pre typeahead 0.11 + cb = syncCb; + } + + self.search(query, params, function searchDone(err, content) { + if (err) { + cb(err); + return; + } + + cb(content.hits); + }); + }; +}, +'ttAdapter is not necessary anymore and will be removed in the next version,\n' + +'have a look at autocomplete.js (https://github.com/algolia/autocomplete.js)'); + +/* +* Wait the publication of a task on the server. +* All server task are asynchronous and you can check with this method that the task is published. +* +* @param taskID the id of the task returned by server +* @param callback the result callback with with two arguments: +* error: null or Error('message') +* content: the server answer that contains the list of results +*/ +Index.prototype.waitTask = function(taskID, callback) { + // wait minimum 100ms before retrying + var baseDelay = 100; + // wait maximum 5s before retrying + var maxDelay = 5000; + var loop = 0; + + // waitTask() must be handled differently from other methods, + // it's a recursive method using a timeout + var indexObj = this; + var client = indexObj.as; + + var promise = retryLoop(); + + function retryLoop() { + return client._jsonRequest({ + method: 'GET', + hostType: 'read', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/task/' + taskID + }).then(function success(content) { + loop++; + var delay = baseDelay * loop * loop; + if (delay > maxDelay) { + delay = maxDelay; + } + + if (content.status !== 'published') { + return client._promise.delay(delay).then(retryLoop); + } + + return content; + }); + } + + if (!callback) { + return promise; + } + + promise.then(successCb, failureCb); + + function successCb(content) { + exitPromise(function exit() { + callback(null, content); + }, client._setTimeout || setTimeout); + } + + function failureCb(err) { + exitPromise(function exit() { + callback(err); + }, client._setTimeout || setTimeout); + } +}; + +/* +* This function deletes the index content. Settings and index specific API keys are kept untouched. +* +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the settings object or the error message if a failure occured +*/ +Index.prototype.clearIndex = function(callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/clear', + hostType: 'write', + callback: callback + }); +}; + +/* +* Get settings of this index +* +* @param opts an object of options to add +* @param opts.advanced get more settings like nbShards (useful for Enterprise) +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the settings object or the error message if a failure occurred +*/ +Index.prototype.getSettings = function(opts, callback) { + if (arguments.length === 1 && typeof opts === 'function') { + callback = opts; + opts = {}; + } + opts = opts || {}; + + var indexName = encodeURIComponent(this.indexName); + return this.as._jsonRequest({ + method: 'GET', + url: + '/1/indexes/' + + indexName + + '/settings?getVersion=2' + + (opts.advanced ? '&advanced=' + opts.advanced : ''), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.searchSynonyms = function(params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } else if (params === undefined) { + params = {}; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/search', + body: params, + hostType: 'read', + callback: callback + }); +}; + +function exportData(method, _hitsPerPage, callback) { + function search(page, _previous) { + var options = { + page: page || 0, + hitsPerPage: _hitsPerPage || 100 + }; + var previous = _previous || []; + + return method(options).then(function(result) { + var hits = result.hits; + var nbHits = result.nbHits; + var current = hits.map(function(s) { + delete s._highlightResult; + return s; + }); + var synonyms = previous.concat(current); + if (synonyms.length < nbHits) { + return search(options.page + 1, synonyms); + } + return synonyms; + }); + } + return search().then(function(data) { + if (typeof callback === 'function') { + callback(data); + return undefined; + } + return data; + }); +} + +/** + * Retrieve all the synonyms in an index + * @param [number=100] hitsPerPage The amount of synonyms to retrieve per batch + * @param [function] callback will be called after all synonyms are retrieved + */ +Index.prototype.exportSynonyms = function(hitsPerPage, callback) { + return exportData(this.searchSynonyms.bind(this), hitsPerPage, callback); +}; + +Index.prototype.saveSynonym = function(synonym, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(synonym.objectID) + + '?forwardToReplicas=' + forwardToReplicas, + body: synonym, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.getSynonym = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.deleteSynonym = function(objectID, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID) + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.clearSynonyms = function(opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/clear' + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.batchSynonyms = function(synonyms, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/batch' + + '?forwardToReplicas=' + forwardToReplicas + + '&replaceExistingSynonyms=' + (opts.replaceExistingSynonyms ? 'true' : 'false'), + hostType: 'write', + body: synonyms, + callback: callback + }); +}; + +Index.prototype.searchRules = function(params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } else if (params === undefined) { + params = {}; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/search', + body: params, + hostType: 'read', + callback: callback + }); +}; +/** + * Retrieve all the query rules in an index + * @param [number=100] hitsPerPage The amount of query rules to retrieve per batch + * @param [function] callback will be called after all query rules are retrieved + * error: null or Error('message') + */ +Index.prototype.exportRules = function(hitsPerPage, callback) { + return exportData(this.searchRules.bind(this), hitsPerPage, callback); +}; + +Index.prototype.saveRule = function(rule, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + if (!rule.objectID) { + throw new errors.AlgoliaSearchError('Missing or empty objectID field for rule'); + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(rule.objectID) + + '?forwardToReplicas=' + forwardToReplicas, + body: rule, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.getRule = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); +}; + +Index.prototype.deleteRule = function(objectID, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID) + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.clearRules = function(opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/clear' + + '?forwardToReplicas=' + forwardToReplicas, + hostType: 'write', + callback: callback + }); +}; + +Index.prototype.batchRules = function(rules, opts, callback) { + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/batch' + + '?forwardToReplicas=' + forwardToReplicas + + '&clearExistingRules=' + (opts.clearExistingRules === true ? 'true' : 'false'), + hostType: 'write', + body: rules, + callback: callback + }); +}; + +/* +* Set settings for this index +* +* @param settigns the settings object that can contains : +* - minWordSizefor1Typo: (integer) the minimum number of characters to accept one typo (default = 3). +* - minWordSizefor2Typos: (integer) the minimum number of characters to accept two typos (default = 7). +* - hitsPerPage: (integer) the number of hits per page (default = 10). +* - attributesToRetrieve: (array of strings) default list of attributes to retrieve in objects. +* If set to null, all attributes are retrieved. +* - attributesToHighlight: (array of strings) default list of attributes to highlight. +* If set to null, all indexed attributes are highlighted. +* - attributesToSnippet**: (array of strings) default list of attributes to snippet alongside the number +* of words to return (syntax is attributeName:nbWords). +* By default no snippet is computed. If set to null, no snippet is computed. +* - attributesToIndex: (array of strings) the list of fields you want to index. +* If set to null, all textual and numerical attributes of your objects are indexed, +* but you should update it to get optimal results. +* This parameter has two important uses: +* - Limit the attributes to index: For example if you store a binary image in base64, +* you want to store it and be able to +* retrieve it but you don't want to search in the base64 string. +* - Control part of the ranking*: (see the ranking parameter for full explanation) +* Matches in attributes at the beginning of +* the list will be considered more important than matches in attributes further down the list. +* In one attribute, matching text at the beginning of the attribute will be +* considered more important than text after, you can disable +* this behavior if you add your attribute inside `unordered(AttributeName)`, +* for example attributesToIndex: ["title", "unordered(text)"]. +* - attributesForFaceting: (array of strings) The list of fields you want to use for faceting. +* All strings in the attribute selected for faceting are extracted and added as a facet. +* If set to null, no attribute is used for faceting. +* - attributeForDistinct: (string) The attribute name used for the Distinct feature. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in query with the distinct=1 parameter, all hits containing a duplicate +* value for this attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best one is kept and others are removed. +* - ranking: (array of strings) controls the way results are sorted. +* We have six available criteria: +* - typo: sort according to number of typos, +* - geo: sort according to decreassing distance when performing a geo-location based search, +* - proximity: sort according to the proximity of query words in hits, +* - attribute: sort according to the order of attributes defined by attributesToIndex, +* - exact: +* - if the user query contains one word: sort objects having an attribute +* that is exactly the query word before others. +* For example if you search for the "V" TV show, you want to find it +* with the "V" query and avoid to have all popular TV +* show starting by the v letter before it. +* - if the user query contains multiple words: sort according to the +* number of words that matched exactly (and not as a prefix). +* - custom: sort according to a user defined formula set in **customRanking** attribute. +* The standard order is ["typo", "geo", "proximity", "attribute", "exact", "custom"] +* - customRanking: (array of strings) lets you specify part of the ranking. +* The syntax of this condition is an array of strings containing attributes +* prefixed by asc (ascending order) or desc (descending order) operator. +* For example `"customRanking" => ["desc(population)", "asc(name)"]` +* - queryType: Select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - highlightPreTag: (string) Specify the string that is inserted before +* the highlighted parts in the query result (default to "<em>"). +* - highlightPostTag: (string) Specify the string that is inserted after +* the highlighted parts in the query result (default to "</em>"). +* - optionalWords: (array of strings) Specify a list of words that should +* be considered as optional when found in the query. +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the server answer or the error message if a failure occured +*/ +Index.prototype.setSettings = function(settings, opts, callback) { + if (arguments.length === 1 || typeof opts === 'function') { + callback = opts; + opts = {}; + } + + if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); + var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; + + var indexObj = this; + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings?forwardToReplicas=' + + forwardToReplicas, + hostType: 'write', + body: settings, + callback: callback + }); +}; + +/* +* @deprecated see client.listApiKeys() +*/ +Index.prototype.listUserKeys = deprecate(function(callback) { + return this.listApiKeys(callback); +}, deprecatedMessage('index.listUserKeys()', 'client.listApiKeys()')); + +/* +* List all existing API keys to this index +* +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with API keys belonging to the index +* +* @deprecated see client.listApiKeys() +*/ +Index.prototype.listApiKeys = deprecate(function(callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys', + hostType: 'read', + callback: callback + }); +}, deprecatedMessage('index.listApiKeys()', 'client.listApiKeys()')); + +/* +* @deprecated see client.getApiKey() +*/ +Index.prototype.getUserKeyACL = deprecate(function(key, callback) { + return this.getApiKey(key, callback); +}, deprecatedMessage('index.getUserKeyACL()', 'client.getApiKey()')); + + +/* +* Get an API key from this index +* +* @param key +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the right API key +* +* @deprecated see client.getApiKey() +*/ +Index.prototype.getApiKey = deprecate(function(key, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, + hostType: 'read', + callback: callback + }); +}, deprecatedMessage('index.getApiKey()', 'client.getApiKey()')); + +/* +* @deprecated see client.deleteApiKey() +*/ +Index.prototype.deleteUserKey = deprecate(function(key, callback) { + return this.deleteApiKey(key, callback); +}, deprecatedMessage('index.deleteUserKey()', 'client.deleteApiKey()')); + +/* +* Delete an existing API key associated to this index +* +* @param key +* @param callback the result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the deletion date +* +* @deprecated see client.deleteApiKey() +*/ +Index.prototype.deleteApiKey = deprecate(function(key, callback) { + var indexObj = this; + return this.as._jsonRequest({ + method: 'DELETE', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.deleteApiKey()', 'client.deleteApiKey()')); + +/* +* @deprecated see client.addApiKey() +*/ +Index.prototype.addUserKey = deprecate(function(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('index.addUserKey()', 'client.addApiKey()')); + +/* +* Add a new API key to this index +* +* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that +* can contains the following values: +* - search: allow to search (https and http) +* - addObject: allows to add/update an object in the index (https only) +* - deleteObject : allows to delete an existing object (https only) +* - deleteIndex : allows to delete index content (https only) +* - settings : allows to get index settings (https only) +* - editSettings : allows to change index settings (https only) +* @param {Object} [params] - Optionnal parameters to set for the key +* @param {number} params.validity - Number of seconds after which the key will +* be automatically removed (0 means no time limit for this key) +* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour +* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call +* @param {string} params.description - A description for your key +* @param {string[]} params.referers - A list of authorized referers +* @param {Object} params.queryParameters - Force the key to use specific query parameters +* @param {Function} callback - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the added API key +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.addUserKey(['search'], { +* validity: 300, +* maxQueriesPerIPPerHour: 2000, +* maxHitsPerQuery: 3, +* description: 'Eat three fruits', +* referers: ['*.algolia.com'], +* queryParameters: { +* tagFilters: ['public'], +* } +* }) +* @see {@link https://www.algolia.com/doc/rest_api#AddIndexKey|Algolia REST API Documentation} +* +* @deprecated see client.addApiKey() +*/ +Index.prototype.addApiKey = deprecate(function(acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: index.addApiKey(arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 1 || typeof params === 'function') { + callback = params; + params = null; + } + + var postObj = { + acl: acls + }; + + if (params) { + postObj.validity = params.validity; + postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + postObj.maxHitsPerQuery = params.maxHitsPerQuery; + postObj.description = params.description; + + if (params.queryParameters) { + postObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); + } + + postObj.referers = params.referers; + } + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys', + body: postObj, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.addApiKey()', 'client.addApiKey()')); + +/** +* @deprecated use client.addApiKey() +*/ +Index.prototype.addUserKeyWithValidity = deprecate(function deprecatedAddUserKeyWithValidity(acls, params, callback) { + return this.addApiKey(acls, params, callback); +}, deprecatedMessage('index.addUserKeyWithValidity()', 'client.addApiKey()')); + +/* +* @deprecated see client.updateApiKey() +*/ +Index.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { + return this.updateApiKey(key, acls, params, callback); +}, deprecatedMessage('index.updateUserKey()', 'client.updateApiKey()')); + +/** +* Update an existing API key of this index +* @param {string} key - The key to update +* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that +* can contains the following values: +* - search: allow to search (https and http) +* - addObject: allows to add/update an object in the index (https only) +* - deleteObject : allows to delete an existing object (https only) +* - deleteIndex : allows to delete index content (https only) +* - settings : allows to get index settings (https only) +* - editSettings : allows to change index settings (https only) +* @param {Object} [params] - Optionnal parameters to set for the key +* @param {number} params.validity - Number of seconds after which the key will +* be automatically removed (0 means no time limit for this key) +* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour +* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call +* @param {string} params.description - A description for your key +* @param {string[]} params.referers - A list of authorized referers +* @param {Object} params.queryParameters - Force the key to use specific query parameters +* @param {Function} callback - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with user keys list +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.updateApiKey('APIKEY', ['search'], { +* validity: 300, +* maxQueriesPerIPPerHour: 2000, +* maxHitsPerQuery: 3, +* description: 'Eat three fruits', +* referers: ['*.algolia.com'], +* queryParameters: { +* tagFilters: ['public'], +* } +* }) +* @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} +* +* @deprecated see client.updateApiKey() +*/ +Index.prototype.updateApiKey = deprecate(function(key, acls, params, callback) { + var isArray = require(8); + var usage = 'Usage: index.updateApiKey(key, arrayOfAcls[, params, callback])'; + + if (!isArray(acls)) { + throw new Error(usage); + } + + if (arguments.length === 2 || typeof params === 'function') { + callback = params; + params = null; + } + + var putObj = { + acl: acls + }; + + if (params) { + putObj.validity = params.validity; + putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; + putObj.maxHitsPerQuery = params.maxHitsPerQuery; + putObj.description = params.description; + + if (params.queryParameters) { + putObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); + } + + putObj.referers = params.referers; + } + + return this.as._jsonRequest({ + method: 'PUT', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys/' + key, + body: putObj, + hostType: 'write', + callback: callback + }); +}, deprecatedMessage('index.updateApiKey()', 'client.updateApiKey()')); + +},{"17":17,"18":18,"24":24,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"7":7,"8":8}],17:[function(require,module,exports){ +'use strict'; + +// This is the object returned by the `index.browseAll()` method + +module.exports = IndexBrowser; + +var inherits = require(7); +var EventEmitter = require(4).EventEmitter; + +function IndexBrowser() { +} + +inherits(IndexBrowser, EventEmitter); + +IndexBrowser.prototype.stop = function() { + this._stopped = true; + this._clean(); +}; + +IndexBrowser.prototype._end = function() { + this.emit('end'); + this._clean(); +}; + +IndexBrowser.prototype._error = function(err) { + this.emit('error', err); + this._clean(); +}; + +IndexBrowser.prototype._result = function(content) { + this.emit('result', content); +}; + +IndexBrowser.prototype._clean = function() { + this.removeAllListeners('stop'); + this.removeAllListeners('end'); + this.removeAllListeners('error'); + this.removeAllListeners('result'); +}; + +},{"4":4,"7":7}],18:[function(require,module,exports){ +var buildSearchMethod = require(23); +var deprecate = require(26); +var deprecatedMessage = require(27); + +module.exports = IndexCore; + +/* +* Index class constructor. +* You should not use this method directly but use initIndex() function +*/ +function IndexCore(algoliasearch, indexName) { + this.indexName = indexName; + this.as = algoliasearch; + this.typeAheadArgs = null; + this.typeAheadValueOption = null; + + // make sure every index instance has it's own cache + this.cache = {}; +} + +/* +* Clear all queries in cache +*/ +IndexCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/* +* Search inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the full text query +* @param {object} [args] (optional) if set, contains an object with query parameters: +* - page: (integer) Pagination parameter used to select the page to retrieve. +* Page is zero-based and defaults to 0. Thus, +* to retrieve the 10th page you need to set page=9 +* - hitsPerPage: (integer) Pagination parameter used to select the number of hits per page. Defaults to 20. +* - attributesToRetrieve: a string that contains the list of object attributes +* you want to retrieve (let you minimize the answer size). +* Attributes are separated with a comma (for example "name,address"). +* You can also use an array (for example ["name","address"]). +* By default, all attributes are retrieved. You can also use '*' to retrieve all +* values when an attributesToRetrieve setting is specified for your index. +* - attributesToHighlight: a string that contains the list of attributes you +* want to highlight according to the query. +* Attributes are separated by a comma. You can also use an array (for example ["name","address"]). +* If an attribute has no match for the query, the raw value is returned. +* By default all indexed text attributes are highlighted. +* You can use `*` if you want to highlight all textual attributes. +* Numerical attributes are not highlighted. +* A matchLevel is returned for each highlighted attribute and can contain: +* - full: if all the query terms were found in the attribute, +* - partial: if only some of the query terms were found, +* - none: if none of the query terms were found. +* - attributesToSnippet: a string that contains the list of attributes to snippet alongside +* the number of words to return (syntax is `attributeName:nbWords`). +* Attributes are separated by a comma (Example: attributesToSnippet=name:10,content:10). +* You can also use an array (Example: attributesToSnippet: ['name:10','content:10']). +* By default no snippet is computed. +* - minWordSizefor1Typo: the minimum number of characters in a query word to accept one typo in this word. +* Defaults to 3. +* - minWordSizefor2Typos: the minimum number of characters in a query word +* to accept two typos in this word. Defaults to 7. +* - getRankingInfo: if set to 1, the result hits will contain ranking +* information in _rankingInfo attribute. +* - aroundLatLng: search for entries around a given +* latitude/longitude (specified as two floats separated by a comma). +* For example aroundLatLng=47.316669,5.016670). +* You can specify the maximum distance in meters with the aroundRadius parameter (in meters) +* and the precision for ranking with aroundPrecision +* (for example if you set aroundPrecision=100, two objects that are distant of +* less than 100m will be considered as identical for "geo" ranking parameter). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - insideBoundingBox: search entries inside a given area defined by the two extreme points +* of a rectangle (defined by 4 floats: p1Lat,p1Lng,p2Lat,p2Lng). +* For example insideBoundingBox=47.3165,4.9665,47.3424,5.0201). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - numericFilters: a string that contains the list of numeric filters you want to +* apply separated by a comma. +* The syntax of one filter is `attributeName` followed by `operand` followed by `value`. +* Supported operands are `<`, `<=`, `=`, `>` and `>=`. +* You can have multiple conditions on one attribute like for example numericFilters=price>100,price<1000. +* You can also use an array (for example numericFilters: ["price>100","price<1000"]). +* - tagFilters: filter the query by a set of tags. You can AND tags by separating them by commas. +* To OR tags, you must add parentheses. For example, tags=tag1,(tag2,tag3) means tag1 AND (tag2 OR tag3). +* You can also use an array, for example tagFilters: ["tag1",["tag2","tag3"]] +* means tag1 AND (tag2 OR tag3). +* At indexing, tags should be added in the _tags** attribute +* of objects (for example {"_tags":["tag1","tag2"]}). +* - facetFilters: filter the query by a list of facets. +* Facets are separated by commas and each facet is encoded as `attributeName:value`. +* For example: `facetFilters=category:Book,author:John%20Doe`. +* You can also use an array (for example `["category:Book","author:John%20Doe"]`). +* - facets: List of object attributes that you want to use for faceting. +* Comma separated list: `"category,author"` or array `['category','author']` +* Only attributes that have been added in **attributesForFaceting** index setting +* can be used in this parameter. +* You can also use `*` to perform faceting on all attributes specified in **attributesForFaceting**. +* - queryType: select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - optionalWords: a string that contains the list of words that should +* be considered as optional when found in the query. +* Comma separated and array are accepted. +* - distinct: If set to 1, enable the distinct feature (disabled by default) +* if the attributeForDistinct index setting is set. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in a query with the distinct=1 parameter, +* all hits containing a duplicate value for the attributeForDistinct attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best +* one is kept and others are removed. +* - restrictSearchableAttributes: List of attributes you want to use for +* textual search (must be a subset of the attributesToIndex index setting) +* either comma separated or as an array +* @param {function} [callback] the result callback called with two arguments: +* error: null or Error('message'). If false, the content contains the error. +* content: the server answer that contains the list of results. +*/ +IndexCore.prototype.search = buildSearchMethod('query'); + +/* +* -- BETA -- +* Search a record similar to the query inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the similar query +* @param {object} [args] (optional) if set, contains an object with query parameters. +* All search parameters are supported (see search function), restrictSearchableAttributes and facetFilters +* are the two most useful to restrict the similar results and get more relevant content +*/ +IndexCore.prototype.similarSearch = buildSearchMethod('similarQuery'); + +/* +* Browse index content. The response content will have a `cursor` property that you can use +* to browse subsequent pages for this query. Use `index.browseFrom(cursor)` when you want. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browse('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }, callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browse = function(query, queryParameters, callback) { + var merge = require(31); + + var indexObj = this; + + var page; + var hitsPerPage; + + // we check variadic calls that are not the one defined + // .browse()/.browse(fn) + // => page = 0 + if (arguments.length === 0 || arguments.length === 1 && typeof arguments[0] === 'function') { + page = 0; + callback = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'number') { + // .browse(2)/.browse(2, 10)/.browse(2, fn)/.browse(2, 10, fn) + page = arguments[0]; + if (typeof arguments[1] === 'number') { + hitsPerPage = arguments[1]; + } else if (typeof arguments[1] === 'function') { + callback = arguments[1]; + hitsPerPage = undefined; + } + query = undefined; + queryParameters = undefined; + } else if (typeof arguments[0] === 'object') { + // .browse(queryParameters)/.browse(queryParameters, cb) + if (typeof arguments[1] === 'function') { + callback = arguments[1]; + } + queryParameters = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') { + // .browse(query, cb) + callback = arguments[1]; + queryParameters = undefined; + } + + // otherwise it's a .browse(query)/.browse(query, queryParameters)/.browse(query, queryParameters, cb) + + // get search query parameters combining various possible calls + // to .browse(); + queryParameters = merge({}, queryParameters || {}, { + page: page, + hitsPerPage: hitsPerPage, + query: query + }); + + var params = this.as._getSearchParams(queryParameters, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse', + body: {params: params}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Continue browsing from a previous position (cursor), obtained via a call to `.browse()`. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browseFrom('14lkfsakl32', callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browseFrom = function(cursor, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/browse', + body: {cursor: cursor}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* +* @param {string} params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} params.facetQuery Query for the facet search +* @param {string} [params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +* @param callback (optional) +*/ +IndexCore.prototype.searchForFacetValues = function(params, callback) { + var clone = require(24); + var omit = require(32); + var usage = 'Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])'; + + if (params.facetName === undefined || params.facetQuery === undefined) { + throw new Error(usage); + } + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = this.as._getSearchParams(filteredParams, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + + encodeURIComponent(this.indexName) + '/facets/' + encodeURIComponent(facetName) + '/query', + hostType: 'read', + body: {params: searchParameters}, + callback: callback + }); +}; + +IndexCore.prototype.searchFacet = deprecate(function(params, callback) { + return this.searchForFacetValues(params, callback); +}, deprecatedMessage( + 'index.searchFacet(params[, callback])', + 'index.searchForFacetValues(params[, callback])' +)); + +IndexCore.prototype._search = function(params, url, callback, additionalUA) { + return this.as._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url || '/1/indexes/' + encodeURIComponent(this.indexName) + '/query', + body: {params: params}, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName), + body: {params: params} + }, + callback: callback, + additionalUA: additionalUA + }); +}; + +/* +* Get an object from this index +* +* @param objectID the unique identifier of the object to retrieve +* @param attrs (optional) if set, contains the array of attribute names to retrieve +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the object to retrieve or the error message if a failure occured +*/ +IndexCore.prototype.getObject = function(objectID, attrs, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof attrs === 'function') { + callback = attrs; + attrs = undefined; + } + + var params = ''; + if (attrs !== undefined) { + params = '?attributes='; + for (var i = 0; i < attrs.length; ++i) { + if (i !== 0) { + params += ','; + } + params += attrs[i]; + } + } + + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID) + params, + hostType: 'read', + callback: callback + }); +}; + +/* +* Get several objects from this index +* +* @param objectIDs the array of unique identifier of objects to retrieve +*/ +IndexCore.prototype.getObjects = function(objectIDs, attributesToRetrieve, callback) { + var isArray = require(8); + var map = require(30); + + var usage = 'Usage: index.getObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + + if (arguments.length === 1 || typeof attributesToRetrieve === 'function') { + callback = attributesToRetrieve; + attributesToRetrieve = undefined; + } + + var body = { + requests: map(objectIDs, function prepareRequest(objectID) { + var request = { + indexName: indexObj.indexName, + objectID: objectID + }; + + if (attributesToRetrieve) { + request.attributesToRetrieve = attributesToRetrieve.join(','); + } + + return request; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/objects', + hostType: 'read', + body: body, + callback: callback + }); +}; + +IndexCore.prototype.as = null; +IndexCore.prototype.indexName = null; +IndexCore.prototype.typeAheadArgs = null; +IndexCore.prototype.typeAheadValueOption = null; + +},{"23":23,"24":24,"26":26,"27":27,"30":30,"31":31,"32":32,"8":8}],19:[function(require,module,exports){ +'use strict'; + +var AlgoliaSearch = require(14); +var createAlgoliasearch = require(20); + +module.exports = createAlgoliasearch(AlgoliaSearch); + +},{"14":14,"20":20}],20:[function(require,module,exports){ +(function (process){ +'use strict'; + +var global = require(6); +var Promise = global.Promise || require(3).Promise; + +// This is the standalone browser build entry point +// Browser implementation of the Algolia Search JavaScript client, +// using XMLHttpRequest, XDomainRequest and JSONP as fallback +module.exports = function createAlgoliasearch(AlgoliaSearch, uaSuffix) { + var inherits = require(7); + var errors = require(28); + var inlineHeaders = require(21); + var jsonpRequest = require(22); + var places = require(33); + uaSuffix = uaSuffix || ''; + + if (process.env.NODE_ENV === 'debug') { + require(1).enable('algoliasearch*'); + } + + function algoliasearch(applicationID, apiKey, opts) { + var cloneDeep = require(24); + + opts = cloneDeep(opts || {}); + + opts._ua = opts._ua || algoliasearch.ua; + + return new AlgoliaSearchBrowser(applicationID, apiKey, opts); + } + + algoliasearch.version = require(35); + algoliasearch.ua = 'Algolia for vanilla JavaScript ' + uaSuffix + algoliasearch.version; + algoliasearch.initPlaces = places(algoliasearch); + + // we expose into window no matter how we are used, this will allow + // us to easily debug any website running algolia + global.__algolia = { + debug: require(1), + algoliasearch: algoliasearch + }; + + var support = { + hasXMLHttpRequest: 'XMLHttpRequest' in global, + hasXDomainRequest: 'XDomainRequest' in global + }; + + if (support.hasXMLHttpRequest) { + support.cors = 'withCredentials' in new XMLHttpRequest(); + } + + function AlgoliaSearchBrowser() { + // call AlgoliaSearch constructor + AlgoliaSearch.apply(this, arguments); + } + + inherits(AlgoliaSearchBrowser, AlgoliaSearch); + + AlgoliaSearchBrowser.prototype._request = function request(url, opts) { + return new Promise(function wrapRequest(resolve, reject) { + // no cors or XDomainRequest, no request + if (!support.cors && !support.hasXDomainRequest) { + // very old browser, not supported + reject(new errors.Network('CORS not supported')); + return; + } + + url = inlineHeaders(url, opts.headers); + + var body = opts.body; + var req = support.cors ? new XMLHttpRequest() : new XDomainRequest(); + var reqTimeout; + var timedOut; + var connected = false; + + reqTimeout = setTimeout(onTimeout, opts.timeouts.connect); + // we set an empty onprogress listener + // so that XDomainRequest on IE9 is not aborted + // refs: + // - https://github.com/algolia/algoliasearch-client-js/issues/76 + // - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment + req.onprogress = onProgress; + if ('onreadystatechange' in req) req.onreadystatechange = onReadyStateChange; + req.onload = onLoad; + req.onerror = onError; + + // do not rely on default XHR async flag, as some analytics code like hotjar + // breaks it and set it to false by default + if (req instanceof XMLHttpRequest) { + req.open(opts.method, url, true); + + // The Analytics API never accepts Auth headers as query string + // this option exists specifically for them. + if (opts.forceAuthHeaders) { + req.setRequestHeader( + 'x-algolia-application-id', + opts.headers['x-algolia-application-id'] + ); + req.setRequestHeader( + 'x-algolia-api-key', + opts.headers['x-algolia-api-key'] + ); + } + } else { + req.open(opts.method, url); + } + + // headers are meant to be sent after open + if (support.cors) { + if (body) { + if (opts.method === 'POST') { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests + req.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); + } else { + req.setRequestHeader('content-type', 'application/json'); + } + } + req.setRequestHeader('accept', 'application/json'); + } + + if (body) { + req.send(body); + } else { + req.send(); + } + + // event object not received in IE8, at least + // but we do not use it, still important to note + function onLoad(/* event */) { + // When browser does not supports req.timeout, we can + // have both a load and timeout event, since handled by a dumb setTimeout + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + var out; + + try { + out = { + body: JSON.parse(req.responseText), + responseText: req.responseText, + statusCode: req.status, + // XDomainRequest does not have any response headers + headers: req.getAllResponseHeaders && req.getAllResponseHeaders() || {} + }; + } catch (e) { + out = new errors.UnparsableJSON({ + more: req.responseText + }); + } + + if (out instanceof errors.UnparsableJSON) { + reject(out); + } else { + resolve(out); + } + } + + function onError(event) { + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + // error event is trigerred both with XDR/XHR on: + // - DNS error + // - unallowed cross domain request + reject( + new errors.Network({ + more: event + }) + ); + } + + function onTimeout() { + timedOut = true; + req.abort(); + + reject(new errors.RequestTimeout()); + } + + function onConnect() { + connected = true; + clearTimeout(reqTimeout); + reqTimeout = setTimeout(onTimeout, opts.timeouts.complete); + } + + function onProgress() { + if (!connected) onConnect(); + } + + function onReadyStateChange() { + if (!connected && req.readyState > 1) onConnect(); + } + }); + }; + + AlgoliaSearchBrowser.prototype._request.fallback = function requestFallback(url, opts) { + url = inlineHeaders(url, opts.headers); + + return new Promise(function wrapJsonpRequest(resolve, reject) { + jsonpRequest(url, opts, function jsonpRequestDone(err, content) { + if (err) { + reject(err); + return; + } + + resolve(content); + }); + }); + }; + + AlgoliaSearchBrowser.prototype._promise = { + reject: function rejectPromise(val) { + return Promise.reject(val); + }, + resolve: function resolvePromise(val) { + return Promise.resolve(val); + }, + delay: function delayPromise(ms) { + return new Promise(function resolveOnTimeout(resolve/* , reject*/) { + setTimeout(resolve, ms); + }); + }, + all: function all(promises) { + return Promise.all(promises); + } + }; + + return algoliasearch; +}; + +}).call(this,require(12)) +},{"1":1,"12":12,"21":21,"22":22,"24":24,"28":28,"3":3,"33":33,"35":35,"6":6,"7":7}],21:[function(require,module,exports){ +'use strict'; + +module.exports = inlineHeaders; + +var encode = require(13); + +function inlineHeaders(url, headers) { + if (/\?/.test(url)) { + url += '&'; + } else { + url += '?'; + } + + return url + encode(headers); +} + +},{"13":13}],22:[function(require,module,exports){ +'use strict'; + +module.exports = jsonpRequest; + +var errors = require(28); + +var JSONPCounter = 0; + +function jsonpRequest(url, opts, cb) { + if (opts.method !== 'GET') { + cb(new Error('Method ' + opts.method + ' ' + url + ' is not supported by JSONP.')); + return; + } + + opts.debug('JSONP: start'); + + var cbCalled = false; + var timedOut = false; + + JSONPCounter += 1; + var head = document.getElementsByTagName('head')[0]; + var script = document.createElement('script'); + var cbName = 'algoliaJSONP_' + JSONPCounter; + var done = false; + + window[cbName] = function(data) { + removeGlobals(); + + if (timedOut) { + opts.debug('JSONP: Late answer, ignoring'); + return; + } + + cbCalled = true; + + clean(); + + cb(null, { + body: data, + responseText: JSON.stringify(data)/* , + // We do not send the statusCode, there's no statusCode in JSONP, it will be + // computed using data.status && data.message like with XDR + statusCode*/ + }); + }; + + // add callback by hand + url += '&callback=' + cbName; + + // add body params manually + if (opts.jsonBody && opts.jsonBody.params) { + url += '&' + opts.jsonBody.params; + } + + var ontimeout = setTimeout(timeout, opts.timeouts.complete); + + // script onreadystatechange needed only for + // <= IE8 + // https://github.com/angular/angular.js/issues/4523 + script.onreadystatechange = readystatechange; + script.onload = success; + script.onerror = error; + + script.async = true; + script.defer = true; + script.src = url; + head.appendChild(script); + + function success() { + opts.debug('JSONP: success'); + + if (done || timedOut) { + return; + } + + done = true; + + // script loaded but did not call the fn => script loading error + if (!cbCalled) { + opts.debug('JSONP: Fail. Script loaded but did not call the callback'); + clean(); + cb(new errors.JSONPScriptFail()); + } + } + + function readystatechange() { + if (this.readyState === 'loaded' || this.readyState === 'complete') { + success(); + } + } + + function clean() { + clearTimeout(ontimeout); + script.onload = null; + script.onreadystatechange = null; + script.onerror = null; + head.removeChild(script); + } + + function removeGlobals() { + try { + delete window[cbName]; + delete window[cbName + '_loaded']; + } catch (e) { + window[cbName] = window[cbName + '_loaded'] = undefined; + } + } + + function timeout() { + opts.debug('JSONP: Script timeout'); + timedOut = true; + clean(); + cb(new errors.RequestTimeout()); + } + + function error() { + opts.debug('JSONP: Script error'); + + if (done || timedOut) { + return; + } + + clean(); + cb(new errors.JSONPScriptError()); + } +} + +},{"28":28}],23:[function(require,module,exports){ +module.exports = buildSearchMethod; + +var errors = require(28); + +/** + * Creates a search method to be used in clients + * @param {string} queryParam the name of the attribute used for the query + * @param {string} url the url + * @return {function} the search method + */ +function buildSearchMethod(queryParam, url) { + /** + * The search method. Prepares the data and send the query to Algolia. + * @param {string} query the string used for query search + * @param {object} args additional parameters to send with the search + * @param {function} [callback] the callback to be called with the client gets the answer + * @return {undefined|Promise} If the callback is not provided then this methods returns a Promise + */ + return function search(query, args, callback) { + // warn V2 users on how to search + if (typeof query === 'function' && typeof args === 'object' || + typeof callback === 'object') { + // .search(query, params, cb) + // .search(cb, params) + throw new errors.AlgoliaSearchError('index.search usage is index.search(query, params, cb)'); + } + + // Normalizing the function signature + if (arguments.length === 0 || typeof query === 'function') { + // Usage : .search(), .search(cb) + callback = query; + query = ''; + } else if (arguments.length === 1 || typeof args === 'function') { + // Usage : .search(query/args), .search(query, cb) + callback = args; + args = undefined; + } + // At this point we have 3 arguments with values + + // Usage : .search(args) // careful: typeof null === 'object' + if (typeof query === 'object' && query !== null) { + args = query; + query = undefined; + } else if (query === undefined || query === null) { // .search(undefined/null) + query = ''; + } + + var params = ''; + + if (query !== undefined) { + params += queryParam + '=' + encodeURIComponent(query); + } + + var additionalUA; + if (args !== undefined) { + if (args.additionalUA) { + additionalUA = args.additionalUA; + delete args.additionalUA; + } + // `_getSearchParams` will augment params, do not be fooled by the = versus += from previous if + params = this.as._getSearchParams(args, params); + } + + + return this._search(params, url, callback, additionalUA); + }; +} + +},{"28":28}],24:[function(require,module,exports){ +module.exports = function clone(obj) { + return JSON.parse(JSON.stringify(obj)); +}; + +},{}],25:[function(require,module,exports){ +module.exports = createAnalyticsClient; + +var algoliasearch = require(19); + +function createAnalyticsClient(appId, apiKey, opts) { + var analytics = {}; + + opts = opts || {}; + // there need to be 4 hosts, like on the client, since if requests fail, + // the counter goes up by 1, so we need to have the same amount of hosts + // 4 because: -dsn, -1, -2, -3 + // This is done because the APPID used for search will be the same for the analytics client created, + // and since the state of available hosts is shared by APPID globally for the module, we had issues + // where the hostIndex would be 1 while the array was only one entry (you got an empty host) + opts.hosts = opts.hosts || [ + 'analytics.algolia.com', + 'analytics.algolia.com', + 'analytics.algolia.com', + 'analytics.algolia.com' + ]; + opts.protocol = opts.protocol || 'https:'; + + analytics.as = algoliasearch(appId, apiKey, opts); + + analytics.getABTests = function(_params, callback) { + var params = params || {}; + var offset = params.offset || 0; + var limit = params.limit || 10; + + return this.as._jsonRequest({ + method: 'GET', + url: '/2/abtests?offset=' + encodeURIComponent(offset) + '&limit=' + encodeURIComponent(limit), + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.getABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/2/abtests/' + encodeURIComponent(abTestID), + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.addABTest = function(abTest, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/2/abtests', + body: abTest, + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.stopABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/2/abtests/' + encodeURIComponent(abTestID) + '/stop', + hostType: 'read', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.deleteABTest = function(abTestID, callback) { + return this.as._jsonRequest({ + method: 'DELETE', + url: '/2/abtests/' + encodeURIComponent(abTestID), + hostType: 'write', + forceAuthHeaders: true, + callback: callback + }); + }; + + analytics.waitTask = function(indexName, taskID, callback) { + return this.as.initIndex(indexName).waitTask(taskID, callback); + }; + + return analytics; +} + +},{"19":19}],26:[function(require,module,exports){ +module.exports = function deprecate(fn, message) { + var warned = false; + + function deprecated() { + if (!warned) { + /* eslint no-console:0 */ + console.warn(message); + warned = true; + } + + return fn.apply(this, arguments); + } + + return deprecated; +}; + +},{}],27:[function(require,module,exports){ +module.exports = function deprecatedMessage(previousUsage, newUsage) { + var githubAnchorLink = previousUsage.toLowerCase() + .replace(/[\.\(\)]/g, ''); + + return 'algoliasearch: `' + previousUsage + '` was replaced by `' + newUsage + + '`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#' + githubAnchorLink; +}; + +},{}],28:[function(require,module,exports){ +'use strict'; + +// This file hosts our error definitions +// We use custom error "types" so that we can act on them when we need it +// e.g.: if error instanceof errors.UnparsableJSON then.. + +var inherits = require(7); + +function AlgoliaSearchError(message, extraProperties) { + var forEach = require(5); + + var error = this; + + // try to get a stacktrace + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, this.constructor); + } else { + error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old'; + } + + this.name = 'AlgoliaSearchError'; + this.message = message || 'Unknown error'; + + if (extraProperties) { + forEach(extraProperties, function addToErrorObject(value, key) { + error[key] = value; + }); + } +} + +inherits(AlgoliaSearchError, Error); + +function createCustomError(name, message) { + function AlgoliaSearchCustomError() { + var args = Array.prototype.slice.call(arguments, 0); + + // custom message not set, use default + if (typeof args[0] !== 'string') { + args.unshift(message); + } + + AlgoliaSearchError.apply(this, args); + this.name = 'AlgoliaSearch' + name + 'Error'; + } + + inherits(AlgoliaSearchCustomError, AlgoliaSearchError); + + return AlgoliaSearchCustomError; +} + +// late exports to let various fn defs and inherits take place +module.exports = { + AlgoliaSearchError: AlgoliaSearchError, + UnparsableJSON: createCustomError( + 'UnparsableJSON', + 'Could not parse the incoming response as JSON, see err.more for details' + ), + RequestTimeout: createCustomError( + 'RequestTimeout', + 'Request timedout before getting a response' + ), + Network: createCustomError( + 'Network', + 'Network issue, see err.more for details' + ), + JSONPScriptFail: createCustomError( + 'JSONPScriptFail', + '<script> was loaded but did not call our provided callback' + ), + JSONPScriptError: createCustomError( + 'JSONPScriptError', + '<script> unable to load due to an `error` event on it' + ), + Unknown: createCustomError( + 'Unknown', + 'Unknown error occured' + ) +}; + +},{"5":5,"7":7}],29:[function(require,module,exports){ +// Parse cloud does not supports setTimeout +// We do not store a setTimeout reference in the client everytime +// We only fallback to a fake setTimeout when not available +// setTimeout cannot be override globally sadly +module.exports = function exitPromise(fn, _setTimeout) { + _setTimeout(fn, 0); +}; + +},{}],30:[function(require,module,exports){ +var foreach = require(5); + +module.exports = function map(arr, fn) { + var newArr = []; + foreach(arr, function(item, itemIndex) { + newArr.push(fn(item, itemIndex, arr)); + }); + return newArr; +}; + +},{"5":5}],31:[function(require,module,exports){ +var foreach = require(5); + +module.exports = function merge(destination/* , sources */) { + var sources = Array.prototype.slice.call(arguments); + + foreach(sources, function(source) { + for (var keyName in source) { + if (source.hasOwnProperty(keyName)) { + if (typeof destination[keyName] === 'object' && typeof source[keyName] === 'object') { + destination[keyName] = merge({}, destination[keyName], source[keyName]); + } else if (source[keyName] !== undefined) { + destination[keyName] = source[keyName]; + } + } + } + }); + + return destination; +}; + +},{"5":5}],32:[function(require,module,exports){ +module.exports = function omit(obj, test) { + var keys = require(10); + var foreach = require(5); + + var filtered = {}; + + foreach(keys(obj), function doFilter(keyName) { + if (test(keyName) !== true) { + filtered[keyName] = obj[keyName]; + } + }); + + return filtered; +}; + +},{"10":10,"5":5}],33:[function(require,module,exports){ +module.exports = createPlacesClient; + +var buildSearchMethod = require(23); + +function createPlacesClient(algoliasearch) { + return function places(appID, apiKey, opts) { + var cloneDeep = require(24); + + opts = opts && cloneDeep(opts) || {}; + opts.hosts = opts.hosts || [ + 'places-dsn.algolia.net', + 'places-1.algolianet.com', + 'places-2.algolianet.com', + 'places-3.algolianet.com' + ]; + + // allow initPlaces() no arguments => community rate limited + if (arguments.length === 0 || typeof appID === 'object' || appID === undefined) { + appID = ''; + apiKey = ''; + opts._allowEmptyCredentials = true; + } + + var client = algoliasearch(appID, apiKey, opts); + var index = client.initIndex('places'); + index.search = buildSearchMethod('query', '/1/places/query'); + index.getObject = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/places/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); + }; + return index; + }; +} + +},{"23":23,"24":24}],34:[function(require,module,exports){ +(function (global){ +var debug = require(1)('algoliasearch:src/hostIndexState.js'); +var localStorageNamespace = 'algoliasearch-client-js'; + +var store; +var moduleStore = { + state: {}, + set: function(key, data) { + this.state[key] = data; + return this.state[key]; + }, + get: function(key) { + return this.state[key] || null; + } +}; + +var localStorageStore = { + set: function(key, data) { + moduleStore.set(key, data); // always replicate localStorageStore to moduleStore in case of failure + + try { + var namespace = JSON.parse(global.localStorage[localStorageNamespace]); + namespace[key] = data; + global.localStorage[localStorageNamespace] = JSON.stringify(namespace); + return namespace[key]; + } catch (e) { + return localStorageFailure(key, e); + } + }, + get: function(key) { + try { + return JSON.parse(global.localStorage[localStorageNamespace])[key] || null; + } catch (e) { + return localStorageFailure(key, e); + } + } +}; + +function localStorageFailure(key, e) { + debug('localStorage failed with', e); + cleanup(); + store = moduleStore; + return store.get(key); +} + +store = supportsLocalStorage() ? localStorageStore : moduleStore; + +module.exports = { + get: getOrSet, + set: getOrSet, + supportsLocalStorage: supportsLocalStorage +}; + +function getOrSet(key, data) { + if (arguments.length === 1) { + return store.get(key); + } + + return store.set(key, data); +} + +function supportsLocalStorage() { + try { + if ('localStorage' in global && + global.localStorage !== null) { + if (!global.localStorage[localStorageNamespace]) { + // actual creation of the namespace + global.localStorage.setItem(localStorageNamespace, JSON.stringify({})); + } + return true; + } + + return false; + } catch (_) { + return false; + } +} + +// In case of any error on localStorage, we clean our own namespace, this should handle +// quota errors when a lot of keys + data are used +function cleanup() { + try { + global.localStorage.removeItem(localStorageNamespace); + } catch (_) { + // nothing to do + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"1":1}],35:[function(require,module,exports){ +'use strict'; + +module.exports = '3.30.0'; + +},{}]},{},[19])(19) +});
\ No newline at end of file diff --git a/node_modules/algoliasearch/dist/algoliasearch.min.js b/node_modules/algoliasearch/dist/algoliasearch.min.js new file mode 100644 index 00000000..8e6945bd --- /dev/null +++ b/node_modules/algoliasearch/dist/algoliasearch.min.js @@ -0,0 +1,4 @@ +/*! algoliasearch 3.30.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +!function(e){var t;"undefined"!=typeof window?t=window:"undefined"!=typeof self&&(t=self),t.ALGOLIA_MIGRATION_LAYER=e()}(function(){return function e(t,r,o){function n(s,a){if(!r[s]){if(!t[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};t[s][0].call(l.exports,function(e){var r=t[s][1][e];return n(r?r:e)},l,l.exports,e,t,r,o)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s<o.length;s++)n(o[s]);return n}({1:[function(e,t,r){function o(e,t){for(var r in t)e.setAttribute(r,t[r])}function n(e,t){e.onload=function(){this.onerror=this.onload=null,t(null,e)},e.onerror=function(){this.onerror=this.onload=null,t(new Error("Failed to load "+this.src),e)}}function i(e,t){e.onreadystatechange=function(){"complete"!=this.readyState&&"loaded"!=this.readyState||(this.onreadystatechange=null,t(null,e))}}t.exports=function(e,t,r){var s=document.head||document.getElementsByTagName("head")[0],a=document.createElement("script");"function"==typeof t&&(r=t,t={}),t=t||{},r=r||function(){},a.type=t.type||"text/javascript",a.charset=t.charset||"utf8",a.async=!("async"in t)||!!t.async,a.src=e,t.attrs&&o(a,t.attrs),t.text&&(a.text=""+t.text);var c="onload"in a?n:i;c(a,r),a.onload||n(a,r),s.appendChild(a)}},{}],2:[function(e,t,r){"use strict";function o(e){for(var t=new RegExp("cdn\\.jsdelivr\\.net/algoliasearch/latest/"+e.replace(".","\\.")+"(?:\\.min)?\\.js$"),r=document.getElementsByTagName("script"),o=!1,n=0,i=r.length;n<i;n++)if(r[n].src&&t.test(r[n].src)){o=!0;break}return o}t.exports=o},{}],3:[function(e,t,r){"use strict";function o(t){var r=e(1),o="//cdn.jsdelivr.net/algoliasearch/2/"+t+".min.js",i="-- AlgoliaSearch `latest` warning --\nWarning, you are using the `latest` version string from jsDelivr to load the AlgoliaSearch library.\nUsing `latest` is no more recommended, you should load //cdn.jsdelivr.net/algoliasearch/2/algoliasearch.min.js\n\nAlso, we updated the AlgoliaSearch JavaScript client to V3. If you want to upgrade,\nplease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch `latest` warning --";window.console&&(window.console.warn?window.console.warn(i):window.console.log&&window.console.log(i));try{document.write("<script>window.ALGOLIA_SUPPORTS_DOCWRITE = true</script>"),window.ALGOLIA_SUPPORTS_DOCWRITE===!0?(document.write('<script src="'+o+'"></script>'),n("document.write")()):r(o,n("DOMElement"))}catch(s){r(o,n("DOMElement"))}}function n(e){return function(){var t="AlgoliaSearch: loaded V2 script using "+e;window.console&&window.console.log&&window.console.log(t)}}t.exports=o},{1:1}],4:[function(e,t,r){"use strict";function o(){var e="-- AlgoliaSearch V2 => V3 error --\nYou are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\nPlease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch V2 => V3 error --";window.AlgoliaSearch=function(){throw new Error(e)},window.AlgoliaSearchHelper=function(){throw new Error(e)},window.AlgoliaExplainResults=function(){throw new Error(e)}}t.exports=o},{}],5:[function(e,t,r){"use strict";function o(t){var r=e(2),o=e(3),n=e(4);r(t)?o(t):n()}o("algoliasearch")},{2:2,3:3,4:4}]},{},[5])(5)}),function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.algoliasearch=e()}}(function(){var e;return function t(e,r,o){function n(s,a){if(!r[s]){if(!e[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};e[s][0].call(l.exports,function(t){var r=e[s][1][t];return n(r?r:t)},l,l.exports,t,e,r,o)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s<o.length;s++)n(o[s]);return n}({1:[function(e,t,r){(function(o){function n(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function i(e){var t=this.useColors;if(e[0]=(t?"%c":"")+this.namespace+(t?" %c":" ")+e[0]+(t?"%c ":" ")+"+"+r.humanize(this.diff),t){var o="color: "+this.color;e.splice(1,0,o,"color: inherit");var n=0,i=0;e[0].replace(/%[a-zA-Z%]/g,function(e){"%%"!==e&&(n++,"%c"===e&&(i=n))}),e.splice(i,0,o)}}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?r.storage.removeItem("debug"):r.storage.debug=e}catch(t){}}function c(){var e;try{e=r.storage.debug}catch(t){}return!e&&"undefined"!=typeof o&&"env"in o&&(e=o.env.DEBUG),e}function u(){try{return window.localStorage}catch(e){}}r=t.exports=e(2),r.log=s,r.formatArgs=i,r.save=a,r.load=c,r.useColors=n,r.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:u(),r.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],r.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},r.enable(c())}).call(this,e(12))},{12:12,2:2}],2:[function(e,t,r){function o(e){var t,o=0;for(t in e)o=(o<<5)-o+e.charCodeAt(t),o|=0;return r.colors[Math.abs(o)%r.colors.length]}function n(e){function t(){if(t.enabled){var e=t,o=+new Date,n=o-(u||o);e.diff=n,e.prev=u,e.curr=o,u=o;for(var i=new Array(arguments.length),s=0;s<i.length;s++)i[s]=arguments[s];i[0]=r.coerce(i[0]),"string"!=typeof i[0]&&i.unshift("%O");var a=0;i[0]=i[0].replace(/%([a-zA-Z%])/g,function(t,o){if("%%"===t)return t;a++;var n=r.formatters[o];if("function"==typeof n){var s=i[a];t=n.call(e,s),i.splice(a,1),a--}return t}),r.formatArgs.call(e,i);var c=t.log||r.log||console.log.bind(console);c.apply(e,i)}}return t.namespace=e,t.enabled=r.enabled(e),t.useColors=r.useColors(),t.color=o(e),"function"==typeof r.init&&r.init(t),t}function i(e){r.save(e),r.names=[],r.skips=[];for(var t=("string"==typeof e?e:"").split(/[\s,]+/),o=t.length,n=0;n<o;n++)t[n]&&(e=t[n].replace(/\*/g,".*?"),"-"===e[0]?r.skips.push(new RegExp("^"+e.substr(1)+"$")):r.names.push(new RegExp("^"+e+"$")))}function s(){r.enable("")}function a(e){var t,o;for(t=0,o=r.skips.length;t<o;t++)if(r.skips[t].test(e))return!1;for(t=0,o=r.names.length;t<o;t++)if(r.names[t].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}r=t.exports=n.debug=n["default"]=n,r.coerce=c,r.disable=s,r.enable=i,r.enabled=a,r.humanize=e(9),r.names=[],r.skips=[],r.formatters={};var u},{9:9}],3:[function(t,r,o){(function(n,i){!function(t,n){"object"==typeof o&&"undefined"!=typeof r?r.exports=n():"function"==typeof e&&e.amd?e(n):t.ES6Promise=n()}(this,function(){"use strict";function e(e){var t=typeof e;return null!==e&&("object"===t||"function"===t)}function r(e){return"function"==typeof e}function o(e){X=e}function s(e){W=e}function a(){return function(){return n.nextTick(d)}}function c(){return"undefined"!=typeof V?function(){V(d)}:p()}function u(){var e=0,t=new Z(d),r=document.createTextNode("");return t.observe(r,{characterData:!0}),function(){r.data=e=++e%2}}function l(){var e=new MessageChannel;return e.port1.onmessage=d,function(){return e.port2.postMessage(0)}}function p(){var e=setTimeout;return function(){return e(d,1)}}function d(){for(var e=0;e<G;e+=2){var t=re[e],r=re[e+1];t(r),re[e]=void 0,re[e+1]=void 0}G=0}function h(){try{var e=t,r=e("vertx");return V=r.runOnLoop||r.runOnContext,c()}catch(o){return p()}}function f(e,t){var r=arguments,o=this,n=new this.constructor(m);void 0===n[ne]&&C(n);var i=o._state;return i?!function(){var e=r[i-1];W(function(){return U(i,n,e,o._result)})}():I(o,n,e,t),n}function y(e){var t=this;if(e&&"object"==typeof e&&e.constructor===t)return e;var r=new t(m);return R(r,e),r}function m(){}function v(){return new TypeError("You cannot resolve a promise with itself")}function g(){return new TypeError("A promises callback cannot return that same promise.")}function b(e){try{return e.then}catch(t){return ce.error=t,ce}}function w(e,t,r,o){try{e.call(t,r,o)}catch(n){return n}}function _(e,t,r){W(function(e){var o=!1,n=w(r,t,function(r){o||(o=!0,t!==r?R(e,r):j(e,r))},function(t){o||(o=!0,S(e,t))},"Settle: "+(e._label||" unknown promise"));!o&&n&&(o=!0,S(e,n))},e)}function T(e,t){t._state===se?j(e,t._result):t._state===ae?S(e,t._result):I(t,void 0,function(t){return R(e,t)},function(t){return S(e,t)})}function x(e,t,o){t.constructor===e.constructor&&o===f&&t.constructor.resolve===y?T(e,t):o===ce?(S(e,ce.error),ce.error=null):void 0===o?j(e,t):r(o)?_(e,t,o):j(e,t)}function R(t,r){t===r?S(t,v()):e(r)?x(t,r,b(r)):j(t,r)}function A(e){e._onerror&&e._onerror(e._result),k(e)}function j(e,t){e._state===ie&&(e._result=t,e._state=se,0!==e._subscribers.length&&W(k,e))}function S(e,t){e._state===ie&&(e._state=ae,e._result=t,W(A,e))}function I(e,t,r,o){var n=e._subscribers,i=n.length;e._onerror=null,n[i]=t,n[i+se]=r,n[i+ae]=o,0===i&&e._state&&W(k,e)}function k(e){var t=e._subscribers,r=e._state;if(0!==t.length){for(var o=void 0,n=void 0,i=e._result,s=0;s<t.length;s+=3)o=t[s],n=t[s+r],o?U(r,o,n,i):n(i);e._subscribers.length=0}}function O(){this.error=null}function E(e,t){try{return e(t)}catch(r){return ue.error=r,ue}}function U(e,t,o,n){var i=r(o),s=void 0,a=void 0,c=void 0,u=void 0;if(i){if(s=E(o,n),s===ue?(u=!0,a=s.error,s.error=null):c=!0,t===s)return void S(t,g())}else s=n,c=!0;t._state!==ie||(i&&c?R(t,s):u?S(t,a):e===se?j(t,s):e===ae&&S(t,s))}function q(e,t){try{t(function(t){R(e,t)},function(t){S(e,t)})}catch(r){S(e,r)}}function P(){return le++}function C(e){e[ne]=le++,e._state=void 0,e._result=void 0,e._subscribers=[]}function N(e,t){this._instanceConstructor=e,this.promise=new e(m),this.promise[ne]||C(this.promise),$(t)?(this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0===this.length?j(this.promise,this._result):(this.length=this.length||0,this._enumerate(t),0===this._remaining&&j(this.promise,this._result))):S(this.promise,D())}function D(){return new Error("Array Methods must be provided an Array")}function K(e){return new N(this,e).promise}function L(e){var t=this;return new t($(e)?function(r,o){for(var n=e.length,i=0;i<n;i++)t.resolve(e[i]).then(r,o)}:function(e,t){return t(new TypeError("You must pass an array to race."))})}function H(e){var t=this,r=new t(m);return S(r,e),r}function M(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function J(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function F(e){this[ne]=P(),this._result=this._state=void 0,this._subscribers=[],m!==e&&("function"!=typeof e&&M(),this instanceof F?q(this,e):J())}function B(){var e=void 0;if("undefined"!=typeof i)e=i;else if("undefined"!=typeof self)e=self;else try{e=Function("return this")()}catch(t){throw new Error("polyfill failed because global object is unavailable in this environment")}var r=e.Promise;if(r){var o=null;try{o=Object.prototype.toString.call(r.resolve())}catch(t){}if("[object Promise]"===o&&!r.cast)return}e.Promise=F}var Q=void 0;Q=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var $=Q,G=0,V=void 0,X=void 0,W=function(e,t){re[G]=e,re[G+1]=t,G+=2,2===G&&(X?X(d):oe())},Y="undefined"!=typeof window?window:void 0,z=Y||{},Z=z.MutationObserver||z.WebKitMutationObserver,ee="undefined"==typeof self&&"undefined"!=typeof n&&"[object process]"==={}.toString.call(n),te="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,re=new Array(1e3),oe=void 0;oe=ee?a():Z?u():te?l():void 0===Y&&"function"==typeof t?h():p();var ne=Math.random().toString(36).substring(16),ie=void 0,se=1,ae=2,ce=new O,ue=new O,le=0;return N.prototype._enumerate=function(e){for(var t=0;this._state===ie&&t<e.length;t++)this._eachEntry(e[t],t)},N.prototype._eachEntry=function(e,t){var r=this._instanceConstructor,o=r.resolve;if(o===y){var n=b(e);if(n===f&&e._state!==ie)this._settledAt(e._state,t,e._result);else if("function"!=typeof n)this._remaining--,this._result[t]=e;else if(r===F){var i=new r(m);x(i,e,n),this._willSettleAt(i,t)}else this._willSettleAt(new r(function(t){return t(e)}),t)}else this._willSettleAt(o(e),t)},N.prototype._settledAt=function(e,t,r){var o=this.promise;o._state===ie&&(this._remaining--,e===ae?S(o,r):this._result[t]=r),0===this._remaining&&j(o,this._result)},N.prototype._willSettleAt=function(e,t){var r=this;I(e,void 0,function(e){return r._settledAt(se,t,e)},function(e){return r._settledAt(ae,t,e)})},F.all=K,F.race=L,F.resolve=y,F.reject=H,F._setScheduler=o,F._setAsap=s,F._asap=W,F.prototype={constructor:F,then:f,"catch":function(e){return this.then(null,e)}},F.polyfill=B,F.Promise=F,F})}).call(this,t(12),"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{12:12}],4:[function(e,t,r){function o(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function n(e){return"function"==typeof e}function i(e){return"number"==typeof e}function s(e){return"object"==typeof e&&null!==e}function a(e){return void 0===e}t.exports=o,o.EventEmitter=o,o.prototype._events=void 0,o.prototype._maxListeners=void 0,o.defaultMaxListeners=10,o.prototype.setMaxListeners=function(e){if(!i(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},o.prototype.emit=function(e){var t,r,o,i,c,u;if(this._events||(this._events={}),"error"===e&&(!this._events.error||s(this._events.error)&&!this._events.error.length)){if(t=arguments[1],t instanceof Error)throw t;var l=new Error('Uncaught, unspecified "error" event. ('+t+")");throw l.context=t,l}if(r=this._events[e],a(r))return!1;if(n(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:i=Array.prototype.slice.call(arguments,1),r.apply(this,i)}else if(s(r))for(i=Array.prototype.slice.call(arguments,1),u=r.slice(),o=u.length,c=0;c<o;c++)u[c].apply(this,i);return!0},o.prototype.addListener=function(e,t){var r;if(!n(t))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,n(t.listener)?t.listener:t),this._events[e]?s(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,s(this._events[e])&&!this._events[e].warned&&(r=a(this._maxListeners)?o.defaultMaxListeners:this._maxListeners,r&&r>0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())),this},o.prototype.on=o.prototype.addListener,o.prototype.once=function(e,t){function r(){this.removeListener(e,r),o||(o=!0,t.apply(this,arguments))}if(!n(t))throw TypeError("listener must be a function");var o=!1;return r.listener=t,this.on(e,r),this},o.prototype.removeListener=function(e,t){var r,o,i,a;if(!n(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(r=this._events[e],i=r.length,o=-1,r===t||n(r.listener)&&r.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(s(r)){for(a=i;a-- >0;)if(r[a]===t||r[a].listener&&r[a].listener===t){o=a;break}if(o<0)return this;1===r.length?(r.length=0,delete this._events[e]):r.splice(o,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},o.prototype.removeAllListeners=function(e){var t,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[e],n(r))this.removeListener(e,r);else if(r)for(;r.length;)this.removeListener(e,r[r.length-1]);return delete this._events[e],this},o.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?n(this._events[e])?[this._events[e]]:this._events[e].slice():[]},o.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(n(t))return 1;if(t)return t.length}return 0},o.listenerCount=function(e,t){return e.listenerCount(t)}},{}],5:[function(e,t,r){var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString;t.exports=function(e,t,r){if("[object Function]"!==n.call(t))throw new TypeError("iterator must be a function");var i=e.length;if(i===+i)for(var s=0;s<i;s++)t.call(r,e[s],s,e);else for(var a in e)o.call(e,a)&&t.call(r,e[a],a,e)}},{}],6:[function(e,t,r){(function(e){var r;r="undefined"!=typeof window?window:"undefined"!=typeof e?e:"undefined"!=typeof self?self:{},t.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(e,t,r){"function"==typeof Object.create?t.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}},{}],8:[function(e,t,r){var o={}.toString;t.exports=Array.isArray||function(e){return"[object Array]"==o.call(e)}},{}],9:[function(e,t,r){function o(e){if(e=String(e),!(e.length>100)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var r=parseFloat(t[1]),o=(t[2]||"ms").toLowerCase();switch(o){case"years":case"year":case"yrs":case"yr":case"y":return r*p;case"days":case"day":case"d":return r*l;case"hours":case"hour":case"hrs":case"hr":case"h":return r*u;case"minutes":case"minute":case"mins":case"min":case"m":return r*c;case"seconds":case"second":case"secs":case"sec":case"s":return r*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function n(e){return e>=l?Math.round(e/l)+"d":e>=u?Math.round(e/u)+"h":e>=c?Math.round(e/c)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function i(e){return s(e,l,"day")||s(e,u,"hour")||s(e,c,"minute")||s(e,a,"second")||e+" ms"}function s(e,t,r){if(!(e<t))return e<1.5*t?Math.floor(e/t)+" "+r:Math.ceil(e/t)+" "+r+"s"}var a=1e3,c=60*a,u=60*c,l=24*u,p=365.25*l;t.exports=function(e,t){t=t||{};var r=typeof e;if("string"===r&&e.length>0)return o(e);if("number"===r&&isNaN(e)===!1)return t["long"]?i(e):n(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],10:[function(e,t,r){"use strict";var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString,i=Array.prototype.slice,s=e(11),a=Object.prototype.propertyIsEnumerable,c=!a.call({toString:null},"toString"),u=a.call(function(){},"prototype"),l=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],p=function(e){var t=e.constructor;return t&&t.prototype===e},d={$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},h=function(){if("undefined"==typeof window)return!1;for(var e in window)try{if(!d["$"+e]&&o.call(window,e)&&null!==window[e]&&"object"==typeof window[e])try{p(window[e])}catch(t){return!0}}catch(t){return!0}return!1}(),f=function(e){if("undefined"==typeof window||!h)return p(e);try{return p(e)}catch(t){return!1}},y=function(e){var t=null!==e&&"object"==typeof e,r="[object Function]"===n.call(e),i=s(e),a=t&&"[object String]"===n.call(e),p=[];if(!t&&!r&&!i)throw new TypeError("Object.keys called on a non-object");var d=u&&r;if(a&&e.length>0&&!o.call(e,0))for(var h=0;h<e.length;++h)p.push(String(h));if(i&&e.length>0)for(var y=0;y<e.length;++y)p.push(String(y));else for(var m in e)d&&"prototype"===m||!o.call(e,m)||p.push(String(m));if(c)for(var v=f(e),g=0;g<l.length;++g)v&&"constructor"===l[g]||!o.call(e,l[g])||p.push(l[g]);return p};y.shim=function(){if(Object.keys){var e=function(){return 2===(Object.keys(arguments)||"").length}(1,2);if(!e){var t=Object.keys;Object.keys=function(e){return t(s(e)?i.call(e):e)}}}else Object.keys=y;return Object.keys||y},t.exports=y},{11:11}],11:[function(e,t,r){"use strict";var o=Object.prototype.toString;t.exports=function(e){var t=o.call(e),r="[object Arguments]"===t;return r||(r="[object Array]"!==t&&null!==e&&"object"==typeof e&&"number"==typeof e.length&&e.length>=0&&"[object Function]"===o.call(e.callee)),r}},{}],12:[function(e,t,r){function o(){throw new Error("setTimeout has not been defined")}function n(){throw new Error("clearTimeout has not been defined")}function i(e){if(p===setTimeout)return setTimeout(e,0);if((p===o||!p)&&setTimeout)return p=setTimeout,setTimeout(e,0);try{return p(e,0)}catch(t){try{return p.call(null,e,0)}catch(t){return p.call(this,e,0)}}}function s(e){if(d===clearTimeout)return clearTimeout(e);if((d===n||!d)&&clearTimeout)return d=clearTimeout,clearTimeout(e);try{return d(e)}catch(t){try{return d.call(null,e)}catch(t){return d.call(this,e)}}}function a(){m&&f&&(m=!1,f.length?y=f.concat(y):v=-1,y.length&&c())}function c(){if(!m){var e=i(a);m=!0;for(var t=y.length;t;){for(f=y,y=[];++v<t;)f&&f[v].run();v=-1,t=y.length}f=null,m=!1,s(e)}}function u(e,t){this.fun=e,this.array=t}function l(){}var p,d,h=t.exports={};!function(){try{p="function"==typeof setTimeout?setTimeout:o}catch(e){p=o}try{d="function"==typeof clearTimeout?clearTimeout:n}catch(e){d=n}}();var f,y=[],m=!1,v=-1;h.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var r=1;r<arguments.length;r++)t[r-1]=arguments[r];y.push(new u(e,t)),1!==y.length||m||i(c)},u.prototype.run=function(){this.fun.apply(null,this.array)},h.title="browser",h.browser=!0,h.env={},h.argv=[],h.version="",h.versions={},h.on=l,h.addListener=l,h.once=l,h.off=l,h.removeListener=l,h.removeAllListeners=l,h.emit=l,h.binding=function(e){throw new Error("process.binding is not supported")},h.cwd=function(){return"/"},h.chdir=function(e){throw new Error("process.chdir is not supported")},h.umask=function(){return 0}},{}],13:[function(e,t,r){"use strict";function o(e,t){if(e.map)return e.map(t);for(var r=[],o=0;o<e.length;o++)r.push(t(e[o],o));return r}var n=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};t.exports=function(e,t,r,a){return t=t||"&",r=r||"=",null===e&&(e=void 0),"object"==typeof e?o(s(e),function(s){var a=encodeURIComponent(n(s))+r;return i(e[s])?o(e[s],function(e){return a+encodeURIComponent(n(e))}).join(t):a+encodeURIComponent(n(e[s]))}).join(t):a?encodeURIComponent(n(a))+r+encodeURIComponent(n(e)):""};var i=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},s=Object.keys||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.push(r);return t}},{}],14:[function(e,t,r){function o(){c.apply(this,arguments)}function n(){var e="Not implemented in this environment.\nIf you feel this is a mistake, write to support@algolia.com";throw new l.AlgoliaSearchError(e)}t.exports=o;var i=e(16),s=e(26),a=e(27),c=e(15),u=e(7),l=e(28);u(o,c),o.prototype.deleteIndex=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(e),hostType:"write",callback:t})},o.prototype.moveIndex=function(e,t,r){var o={operation:"move",destination:t};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:o,hostType:"write",callback:r})},o.prototype.copyIndex=function(e,t,r,o){var n={operation:"copy",destination:t},i=o;if("function"==typeof r)i=r;else if(Array.isArray(r)&&r.length>0)n.scope=r;else if("undefined"!=typeof r)throw new Error("the scope given to `copyIndex` was not an array with settings, synonyms or rules");return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:n,hostType:"write",callback:i})},o.prototype.getLogs=function(t,r,o){var n=e(24),i={};return"object"==typeof t?(i=n(t),o=r):0===arguments.length||"function"==typeof t?o=t:1===arguments.length||"function"==typeof r?(o=r,i.offset=t):(i.offset=t,i.length=r),void 0===i.offset&&(i.offset=0),void 0===i.length&&(i.length=10),this._jsonRequest({method:"GET",url:"/1/logs?"+this._getSearchParams(i,""),hostType:"read",callback:o})},o.prototype.listIndexes=function(e,t){var r="";return void 0===e||"function"==typeof e?t=e:r="?page="+e,this._jsonRequest({method:"GET",url:"/1/indexes"+r,hostType:"read",callback:t})},o.prototype.initIndex=function(e){return new i(this,e)},o.prototype.initAnalytics=function(t){var r=e(25);return r(this.applicationID,this.apiKey,t)},o.prototype.listUserKeys=s(function(e){return this.listApiKeys(e)},a("client.listUserKeys()","client.listApiKeys()")),o.prototype.listApiKeys=function(e){return this._jsonRequest({method:"GET",url:"/1/keys",hostType:"read",callback:e})},o.prototype.getUserKeyACL=s(function(e,t){return this.getApiKey(e,t)},a("client.getUserKeyACL()","client.getApiKey()")),o.prototype.getApiKey=function(e,t){return this._jsonRequest({method:"GET",url:"/1/keys/"+e,hostType:"read",callback:t})},o.prototype.deleteUserKey=s(function(e,t){return this.deleteApiKey(e,t)},a("client.deleteUserKey()","client.deleteApiKey()")),o.prototype.deleteApiKey=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/keys/"+e,hostType:"write",callback:t})},o.prototype.addUserKey=s(function(e,t,r){return this.addApiKey(e,t,r)},a("client.addUserKey()","client.addApiKey()")),o.prototype.addApiKey=function(t,r,o){var n=e(8),i="Usage: client.addApiKey(arrayOfAcls[, params, callback])";if(!n(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.indexes=r.indexes,s.description=r.description,r.queryParameters&&(s.queryParameters=this._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this._jsonRequest({method:"POST",url:"/1/keys",body:s,hostType:"write",callback:o})},o.prototype.addUserKeyWithValidity=s(function(e,t,r){return this.addApiKey(e,t,r)},a("client.addUserKeyWithValidity()","client.addApiKey()")),o.prototype.updateUserKey=s(function(e,t,r,o){return this.updateApiKey(e,t,r,o)},a("client.updateUserKey()","client.updateApiKey()")),o.prototype.updateApiKey=function(t,r,o,n){var i=e(8),s="Usage: client.updateApiKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof o||(n=o,o=null);var a={acl:r};return o&&(a.validity=o.validity,a.maxQueriesPerIPPerHour=o.maxQueriesPerIPPerHour,a.maxHitsPerQuery=o.maxHitsPerQuery,a.indexes=o.indexes,a.description=o.description,o.queryParameters&&(a.queryParameters=this._getSearchParams(o.queryParameters,"")),a.referers=o.referers),this._jsonRequest({method:"PUT",url:"/1/keys/"+t,body:a,hostType:"write",callback:n})},o.prototype.startQueriesBatch=s(function(){this._batch=[]},a("client.startQueriesBatch()","client.search()")),o.prototype.addQueryInBatch=s(function(e,t,r){this._batch.push({indexName:e,query:t,params:r})},a("client.addQueryInBatch()","client.search()")),o.prototype.sendQueriesBatch=s(function(e){return this.search(this._batch,e)},a("client.sendQueriesBatch()","client.search()")),o.prototype.batch=function(t,r){var o=e(8),n="Usage: client.batch(operations[, callback])";if(!o(t))throw new Error(n);return this._jsonRequest({method:"POST",url:"/1/indexes/*/batch",body:{requests:t},hostType:"write",callback:r})},o.prototype.assignUserID=function(e,t){if(!e.userID||!e.cluster)throw new l.AlgoliaSearchError("You have to provide both a userID and cluster",e);return this._jsonRequest({method:"POST",url:"/1/clusters/mapping",hostType:"write",body:{cluster:e.cluster},callback:t,headers:{"x-algolia-user-id":e.userID}})},o.prototype.getTopUserID=function(e){return this._jsonRequest({method:"GET",url:"/1/clusters/mapping/top",hostType:"read",callback:e})},o.prototype.getUserID=function(e,t){if(!e.userID)throw new l.AlgoliaSearchError("You have to provide a userID",{debugData:e});return this._jsonRequest({method:"GET",url:"/1/clusters/mapping/"+e.userID,hostType:"read",callback:t})},o.prototype.listClusters=function(e){return this._jsonRequest({method:"GET",url:"/1/clusters",hostType:"read",callback:e})},o.prototype.listUserIDs=function(e,t){return this._jsonRequest({method:"GET",url:"/1/clusters/mapping",body:e,hostType:"read",callback:t})},o.prototype.removeUserID=function(e,t){if(!e.userID)throw new l.AlgoliaSearchError("You have to provide a userID",{debugData:e});return this._jsonRequest({method:"DELETE",url:"/1/clusters/mapping",hostType:"write",callback:t,headers:{"x-algolia-user-id":e.userID}})},o.prototype.searchUserIDs=function(e,t){return this._jsonRequest({method:"POST",url:"/1/clusters/mapping/search",body:e,hostType:"read",callback:t})},o.prototype.destroy=n,o.prototype.enableRateLimitForward=n,o.prototype.disableRateLimitForward=n,o.prototype.useSecuredAPIKey=n,o.prototype.disableSecuredAPIKey=n,o.prototype.generateSecuredApiKey=n},{15:15,16:16,24:24,25:25,26:26,27:27,28:28,7:7,8:8}],15:[function(e,t,r){(function(r){function o(t,r,o){var i=e(1)("algoliasearch"),s=e(24),a=e(8),u=e(30),l="Usage: algoliasearch(applicationID, apiKey, opts)";if(o._allowEmptyCredentials!==!0&&!t)throw new c.AlgoliaSearchError("Please provide an application ID. "+l);if(o._allowEmptyCredentials!==!0&&!r)throw new c.AlgoliaSearchError("Please provide an API key. "+l);this.applicationID=t,this.apiKey=r,this.hosts={read:[],write:[]},o=o||{},this._timeouts=o.timeouts||{connect:1e3,read:2e3,write:3e4},o.timeout&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=o.timeout);var p=o.protocol||"https:";if(/:$/.test(p)||(p+=":"),"http:"!==p&&"https:"!==p)throw new c.AlgoliaSearchError("protocol must be `http:` or `https:` (was `"+o.protocol+"`)");if(this._checkAppIdData(),o.hosts)a(o.hosts)?(this.hosts.read=s(o.hosts),this.hosts.write=s(o.hosts)):(this.hosts.read=s(o.hosts.read),this.hosts.write=s(o.hosts.write));else{var d=u(this._shuffleResult,function(e){return t+"-"+e+".algolianet.com"}),h=(o.dsn===!1?"":"-dsn")+".algolia.net";this.hosts.read=[this.applicationID+h].concat(d),this.hosts.write=[this.applicationID+".algolia.net"].concat(d)}this.hosts.read=u(this.hosts.read,n(p)),this.hosts.write=u(this.hosts.write,n(p)),this.extraHeaders={},this.cache=o._cache||{},this._ua=o._ua,this._useCache=!(void 0!==o._useCache&&!o._cache)||o._useCache,this._useRequestCache=this._useCache&&o._useRequestCache,this._useFallback=void 0===o.useFallback||o.useFallback,this._setTimeout=o._setTimeout,i("init done, %j",this)}function n(e){return function(t){return e+"//"+t.toLowerCase(); +}}function i(e){if(void 0===Array.prototype.toJSON)return JSON.stringify(e);var t=Array.prototype.toJSON;delete Array.prototype.toJSON;var r=JSON.stringify(e);return Array.prototype.toJSON=t,r}function s(e){for(var t,r,o=e.length;0!==o;)r=Math.floor(Math.random()*o),o-=1,t=e[o],e[o]=e[r],e[r]=t;return e}function a(e){var t={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){var o;o="x-algolia-api-key"===r||"x-algolia-application-id"===r?"**hidden for security purposes**":e[r],t[r]=o}return t}t.exports=o;var c=e(28),u=e(29),l=e(18),p=e(34),d=500,h=r.env.RESET_APP_DATA_TIMER&&parseInt(r.env.RESET_APP_DATA_TIMER,10)||12e4;o.prototype.initIndex=function(e){return new l(this,e)},o.prototype.setExtraHeader=function(e,t){this.extraHeaders[e.toLowerCase()]=t},o.prototype.getExtraHeader=function(e){return this.extraHeaders[e.toLowerCase()]},o.prototype.unsetExtraHeader=function(e){delete this.extraHeaders[e.toLowerCase()]},o.prototype.addAlgoliaAgent=function(e){this._ua.indexOf(";"+e)===-1&&(this._ua+=";"+e)},o.prototype._jsonRequest=function(t){function r(e,n){function u(e){var t=e&&e.body&&e.body.message&&e.body.status||e.statusCode||e&&e.body&&200;h("received response: statusCode: %s, computed statusCode: %d, headers: %j",e.statusCode,t,e.headers);var r=2===Math.floor(t/100),o=new Date;if(w.push({currentHost:A,headers:a(p),content:s||null,contentLength:void 0!==s?s.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:x,endTime:o,duration:o-x,statusCode:t}),r)return m._useCache&&!m._useRequestCache&&y&&(y[l]=e.responseText),{responseText:e.responseText,body:e.body};var i=4!==Math.floor(t/100);if(i)return v+=1,_();h("unrecoverable error");var u=new c.AlgoliaSearchError(e.body&&e.body.message,{debugData:w,statusCode:t});return m._promise.reject(u)}function d(e){h("error: %s, stack: %s",e.message,e.stack);var r=new Date;return w.push({currentHost:A,headers:a(p),content:s||null,contentLength:void 0!==s?s.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:x,endTime:r,duration:r-x}),e instanceof c.AlgoliaSearchError||(e=new c.Unknown(e&&e.message,e)),v+=1,e instanceof c.Unknown||e instanceof c.UnparsableJSON||v>=m.hosts[t.hostType].length&&(g||!b)?(e.debugData=w,m._promise.reject(e)):e instanceof c.RequestTimeout?T():_()}function _(){return h("retrying request"),m._incrementHostIndex(t.hostType),r(e,n)}function T(){return h("retrying request with higher timeout"),m._incrementHostIndex(t.hostType),m._incrementTimeoutMultipler(),n.timeouts=m._getTimeoutsForRequest(t.hostType),r(e,n)}m._checkAppIdData();var x=new Date;if(m._useCache&&!m._useRequestCache&&(l=t.url),m._useCache&&!m._useRequestCache&&s&&(l+="_body_"+n.body),o(!m._useRequestCache,y,l)){h("serving response from cache");var R=y[l];return m._promise.resolve({body:JSON.parse(R),responseText:R})}if(v>=m.hosts[t.hostType].length)return!b||g?(h("could not get any response"),m._promise.reject(new c.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue. Application id was: "+m.applicationID,{debugData:w}))):(h("switching to fallback"),v=0,n.method=t.fallback.method,n.url=t.fallback.url,n.jsonBody=t.fallback.body,n.jsonBody&&(n.body=i(n.jsonBody)),p=m._computeRequestHeaders({additionalUA:f,headers:t.headers}),n.timeouts=m._getTimeoutsForRequest(t.hostType),m._setHostIndexByType(0,t.hostType),g=!0,r(m._request.fallback,n));var A=m._getHostByType(t.hostType),j=A+n.url,S={body:n.body,jsonBody:n.jsonBody,method:n.method,headers:p,timeouts:n.timeouts,debug:h,forceAuthHeaders:n.forceAuthHeaders};return h("method: %s, url: %s, headers: %j, timeouts: %d",S.method,j,S.headers,S.timeouts),e===m._request.fallback&&h("using fallback"),e.call(m,j,S).then(u,d)}function o(e,t,r){return m._useCache&&e&&t&&void 0!==t[r]}function n(e,r){return o(m._useRequestCache,y,l)&&e["catch"](function(){delete y[l]}),"function"!=typeof t.callback?e.then(r):void e.then(function(e){u(function(){t.callback(null,r(e))},m._setTimeout||setTimeout)},function(e){u(function(){t.callback(e)},m._setTimeout||setTimeout)})}this._checkAppIdData();var s,l,p,h=e(1)("algoliasearch:"+t.url),f=t.additionalUA||"",y=t.cache,m=this,v=0,g=!1,b=m._useFallback&&m._request.fallback&&t.fallback;this.apiKey.length>d&&void 0!==t.body&&(void 0!==t.body.params||void 0!==t.body.requests)?(t.body.apiKey=this.apiKey,p=this._computeRequestHeaders({additionalUA:f,withApiKey:!1,headers:t.headers})):p=this._computeRequestHeaders({additionalUA:f,headers:t.headers}),void 0!==t.body&&(s=i(t.body)),h("request start");var w=[];if(m._useCache&&m._useRequestCache&&(l=t.url),m._useCache&&m._useRequestCache&&s&&(l+="_body_"+s),o(m._useRequestCache,y,l)){h("serving request from cache");var _=y[l],T="function"!=typeof _.then?m._promise.resolve({responseText:_}):_;return n(T,function(e){return JSON.parse(e.responseText)})}var x=r(m._request,{url:t.url,method:t.method,body:s,jsonBody:t.body,timeouts:m._getTimeoutsForRequest(t.hostType),forceAuthHeaders:t.forceAuthHeaders});return m._useCache&&m._useRequestCache&&y&&(y[l]=x),n(x,function(e){return e.body})},o.prototype._getSearchParams=function(e,t){if(void 0===e||null===e)return t;for(var r in e)null!==r&&void 0!==e[r]&&e.hasOwnProperty(r)&&(t+=""===t?"":"&",t+=r+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(e[r])?i(e[r]):e[r]));return t},o.prototype._computeRequestHeaders=function(t){var r=e(5),o=t.additionalUA?this._ua+";"+t.additionalUA:this._ua,n={"x-algolia-agent":o,"x-algolia-application-id":this.applicationID};return t.withApiKey!==!1&&(n["x-algolia-api-key"]=this.apiKey),this.userToken&&(n["x-algolia-usertoken"]=this.userToken),this.securityTags&&(n["x-algolia-tagfilters"]=this.securityTags),r(this.extraHeaders,function(e,t){n[t]=e}),t.headers&&r(t.headers,function(e,t){n[t]=e}),n},o.prototype.search=function(t,r,o){var n=e(8),i=e(30),s="Usage: client.search(arrayOfQueries[, callback])";if(!n(t))throw new Error(s);"function"==typeof r?(o=r,r={}):void 0===r&&(r={});var a=this,c={requests:i(t,function(e){var t="";return void 0!==e.query&&(t+="query="+encodeURIComponent(e.query)),{indexName:e.indexName,params:a._getSearchParams(e.params,t)}})},u=i(c.requests,function(e,t){return t+"="+encodeURIComponent("/1/indexes/"+encodeURIComponent(e.indexName)+"?"+e.params)}).join("&"),l="/1/indexes/*/queries";return void 0!==r.strategy&&(c.strategy=r.strategy),this._jsonRequest({cache:this.cache,method:"POST",url:l,body:c,hostType:"read",fallback:{method:"GET",url:"/1/indexes/*",body:{params:u}},callback:o})},o.prototype.searchForFacetValues=function(t){var r=e(8),o=e(30),n="Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])";if(!r(t))throw new Error(n);var i=this;return i._promise.all(o(t,function(t){if(!t||void 0===t.indexName||void 0===t.params.facetName||void 0===t.params.facetQuery)throw new Error(n);var r=e(24),o=e(32),s=t.indexName,a=t.params,c=a.facetName,u=o(r(a),function(e){return"facetName"===e}),l=i._getSearchParams(u,"");return i._jsonRequest({cache:i.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(s)+"/facets/"+encodeURIComponent(c)+"/query",hostType:"read",body:{params:l}})}))},o.prototype.setSecurityTags=function(e){if("[object Array]"===Object.prototype.toString.call(e)){for(var t=[],r=0;r<e.length;++r)if("[object Array]"===Object.prototype.toString.call(e[r])){for(var o=[],n=0;n<e[r].length;++n)o.push(e[r][n]);t.push("("+o.join(",")+")")}else t.push(e[r]);e=t.join(",")}this.securityTags=e},o.prototype.setUserToken=function(e){this.userToken=e},o.prototype.clearCache=function(){this.cache={}},o.prototype.setRequestTimeout=function(e){e&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=e)},o.prototype.setTimeouts=function(e){this._timeouts=e},o.prototype.getTimeouts=function(){return this._timeouts},o.prototype._getAppIdData=function(){var e=p.get(this.applicationID);return null!==e&&this._cacheAppIdData(e),e},o.prototype._setAppIdData=function(e){return e.lastChange=(new Date).getTime(),this._cacheAppIdData(e),p.set(this.applicationID,e)},o.prototype._checkAppIdData=function(){var e=this._getAppIdData(),t=(new Date).getTime();return null===e||t-e.lastChange>h?this._resetInitialAppIdData(e):e},o.prototype._resetInitialAppIdData=function(e){var t=e||{};return t.hostIndexes={read:0,write:0},t.timeoutMultiplier=1,t.shuffleResult=t.shuffleResult||s([1,2,3]),this._setAppIdData(t)},o.prototype._cacheAppIdData=function(e){this._hostIndexes=e.hostIndexes,this._timeoutMultiplier=e.timeoutMultiplier,this._shuffleResult=e.shuffleResult},o.prototype._partialAppIdDataUpdate=function(t){var r=e(5),o=this._getAppIdData();return r(t,function(e,t){o[t]=e}),this._setAppIdData(o)},o.prototype._getHostByType=function(e){return this.hosts[e][this._getHostIndexByType(e)]},o.prototype._getTimeoutMultiplier=function(){return this._timeoutMultiplier},o.prototype._getHostIndexByType=function(e){return this._hostIndexes[e]},o.prototype._setHostIndexByType=function(t,r){var o=e(24),n=o(this._hostIndexes);return n[r]=t,this._partialAppIdDataUpdate({hostIndexes:n}),t},o.prototype._incrementHostIndex=function(e){return this._setHostIndexByType((this._getHostIndexByType(e)+1)%this.hosts[e].length,e)},o.prototype._incrementTimeoutMultipler=function(){var e=Math.max(this._timeoutMultiplier+1,4);return this._partialAppIdDataUpdate({timeoutMultiplier:e})},o.prototype._getTimeoutsForRequest=function(e){return{connect:this._timeouts.connect*this._timeoutMultiplier,complete:this._timeouts[e]*this._timeoutMultiplier}}}).call(this,e(12))},{1:1,12:12,18:18,24:24,28:28,29:29,30:30,32:32,34:34,5:5,8:8}],16:[function(e,t,r){function o(){s.apply(this,arguments)}function n(e,t,r){function o(r,n){var i={page:r||0,hitsPerPage:t||100},s=n||[];return e(i).then(function(e){var t=e.hits,r=e.nbHits,n=t.map(function(e){return delete e._highlightResult,e}),a=s.concat(n);return a.length<r?o(i.page+1,a):a})}return o().then(function(e){return"function"==typeof r?void r(e):e})}var i=e(7),s=e(18),a=e(26),c=e(27),u=e(29),l=e(28),p=a(function(){},c("forwardToSlaves","forwardToReplicas"));t.exports=o,i(o,s),o.prototype.addObject=function(e,t,r){var o=this;return 1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0),this.as._jsonRequest({method:void 0!==t?"PUT":"POST",url:"/1/indexes/"+encodeURIComponent(o.indexName)+(void 0!==t?"/"+encodeURIComponent(t):""),body:e,hostType:"write",callback:r})},o.prototype.addObjects=function(t,r){var o=e(8),n="Usage: index.addObjects(arrayOfObjects[, callback])";if(!o(t))throw new Error(n);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"addObject",body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},o.prototype.partialUpdateObject=function(e,t,r){1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var o=this,n="/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e.objectID)+"/partial";return t===!1&&(n+="?createIfNotExists=false"),this.as._jsonRequest({method:"POST",url:n,body:e,hostType:"write",callback:r})},o.prototype.partialUpdateObjects=function(t,r,o){1!==arguments.length&&"function"!=typeof r||(o=r,r=!0);var n=e(8),i="Usage: index.partialUpdateObjects(arrayOfObjects[, callback])";if(!n(t))throw new Error(i);for(var s=this,a={requests:[]},c=0;c<t.length;++c){var u={action:r===!0?"partialUpdateObject":"partialUpdateObjectNoCreate",objectID:t[c].objectID,body:t[c]};a.requests.push(u)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(s.indexName)+"/batch",body:a,hostType:"write",callback:o})},o.prototype.saveObject=function(e,t){var r=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/"+encodeURIComponent(e.objectID),body:e,hostType:"write",callback:t})},o.prototype.saveObjects=function(t,r){var o=e(8),n="Usage: index.saveObjects(arrayOfObjects[, callback])";if(!o(t))throw new Error(n);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"updateObject",objectID:t[a].objectID,body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},o.prototype.deleteObject=function(e,t){if("function"==typeof e||"string"!=typeof e&&"number"!=typeof e){var r=new l.AlgoliaSearchError(e&&"function"!=typeof e?"ObjectID must be a string":"Cannot delete an object without an objectID");return t=e,"function"==typeof t?t(r):this.as._promise.reject(r)}var o=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e),hostType:"write",callback:t})},o.prototype.deleteObjects=function(t,r){var o=e(8),n=e(30),i="Usage: index.deleteObjects(arrayOfObjectIDs[, callback])";if(!o(t))throw new Error(i);var s=this,a={requests:n(t,function(e){return{action:"deleteObject",objectID:e,body:{objectID:e}}})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(s.indexName)+"/batch",body:a,hostType:"write",callback:r})},o.prototype.deleteByQuery=a(function(t,r,o){function n(e){if(0===e.nbHits)return e;var t=p(e.hits,function(e){return e.objectID});return d.deleteObjects(t).then(i).then(s)}function i(e){return d.waitTask(e.taskID)}function s(){return d.deleteByQuery(t,r)}function a(){u(function(){o(null)},h._setTimeout||setTimeout)}function c(e){u(function(){o(e)},h._setTimeout||setTimeout)}var l=e(24),p=e(30),d=this,h=d.as;1===arguments.length||"function"==typeof r?(o=r,r={}):r=l(r),r.attributesToRetrieve="objectID",r.hitsPerPage=1e3,r.distinct=!1,this.clearCache();var f=this.search(t,r).then(n);return o?void f.then(a,c):f},c("index.deleteByQuery()","index.deleteBy()")),o.prototype.deleteBy=function(e,t){var r=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/deleteByQuery",body:{params:r.as._getSearchParams(e,"")},hostType:"write",callback:t})},o.prototype.browseAll=function(t,r){function o(e){if(!a._stopped){var t;t=void 0!==e?{cursor:e}:{params:l},c._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(u.indexName)+"/browse",hostType:"read",body:t,callback:n})}}function n(e,t){if(!a._stopped)return e?void a._error(e):(a._result(t),void 0===t.cursor?void a._end():void o(t.cursor))}"object"==typeof t&&(r=t,t=void 0);var i=e(31),s=e(17),a=new s,c=this.as,u=this,l=c._getSearchParams(i({},r||{},{query:t}),"");return o(),a},o.prototype.ttAdapter=a(function(e){var t=this;return function(r,o,n){var i;i="function"==typeof n?n:o,t.search(r,e,function(e,t){return e?void i(e):void i(t.hits)})}},"ttAdapter is not necessary anymore and will be removed in the next version,\nhave a look at autocomplete.js (https://github.com/algolia/autocomplete.js)"),o.prototype.waitTask=function(e,t){function r(){return l._jsonRequest({method:"GET",hostType:"read",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/task/"+e}).then(function(e){a++;var t=i*a*a;return t>s&&(t=s),"published"!==e.status?l._promise.delay(t).then(r):e})}function o(e){u(function(){t(null,e)},l._setTimeout||setTimeout)}function n(e){u(function(){t(e)},l._setTimeout||setTimeout)}var i=100,s=5e3,a=0,c=this,l=c.as,p=r();return t?void p.then(o,n):p},o.prototype.clearIndex=function(e){var t=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/clear",hostType:"write",callback:e})},o.prototype.getSettings=function(e,t){1===arguments.length&&"function"==typeof e&&(t=e,e={}),e=e||{};var r=encodeURIComponent(this.indexName);return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+r+"/settings?getVersion=2"+(e.advanced?"&advanced="+e.advanced:""),hostType:"read",callback:t})},o.prototype.searchSynonyms=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/search",body:e,hostType:"read",callback:t})},o.prototype.exportSynonyms=function(e,t){return n(this.searchSynonyms.bind(this),e,t)},o.prototype.saveSynonym=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e.objectID)+"?forwardToReplicas="+o,body:e,hostType:"write",callback:r})},o.prototype.getSynonym=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e),hostType:"read",callback:t})},o.prototype.deleteSynonym=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e)+"?forwardToReplicas="+o,hostType:"write",callback:r})},o.prototype.clearSynonyms=function(e,t){"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),void 0!==e.forwardToSlaves&&p();var r=e.forwardToSlaves||e.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/clear?forwardToReplicas="+r,hostType:"write",callback:t})},o.prototype.batchSynonyms=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/batch?forwardToReplicas="+o+"&replaceExistingSynonyms="+(t.replaceExistingSynonyms?"true":"false"),hostType:"write",body:e,callback:r})},o.prototype.searchRules=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/search",body:e,hostType:"read",callback:t})},o.prototype.exportRules=function(e,t){return n(this.searchRules.bind(this),e,t)},o.prototype.saveRule=function(e,t,r){if("function"==typeof t?(r=t,t={}):void 0===t&&(t={}),!e.objectID)throw new l.AlgoliaSearchError("Missing or empty objectID field for rule");var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e.objectID)+"?forwardToReplicas="+o,body:e,hostType:"write",callback:r})},o.prototype.getRule=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e),hostType:"read",callback:t})},o.prototype.deleteRule=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={});var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/"+encodeURIComponent(e)+"?forwardToReplicas="+o,hostType:"write",callback:r})},o.prototype.clearRules=function(e,t){"function"==typeof e?(t=e,e={}):void 0===e&&(e={});var r=e.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/clear?forwardToReplicas="+r,hostType:"write",callback:t})},o.prototype.batchRules=function(e,t,r){"function"==typeof t?(r=t,t={}):void 0===t&&(t={});var o=t.forwardToReplicas===!0?"true":"false";return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/rules/batch?forwardToReplicas="+o+"&clearExistingRules="+(t.clearExistingRules===!0?"true":"false"),hostType:"write",body:e,callback:r})},o.prototype.setSettings=function(e,t,r){1!==arguments.length&&"function"!=typeof t||(r=t,t={}),void 0!==t.forwardToSlaves&&p();var o=t.forwardToSlaves||t.forwardToReplicas?"true":"false",n=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/settings?forwardToReplicas="+o,hostType:"write",body:e,callback:r})},o.prototype.listUserKeys=a(function(e){return this.listApiKeys(e)},c("index.listUserKeys()","client.listApiKeys()")),o.prototype.listApiKeys=a(function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/keys",hostType:"read",callback:e})},c("index.listApiKeys()","client.listApiKeys()")),o.prototype.getUserKeyACL=a(function(e,t){return this.getApiKey(e,t)},c("index.getUserKeyACL()","client.getApiKey()")),o.prototype.getApiKey=a(function(e,t){var r=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/keys/"+e,hostType:"read",callback:t})},c("index.getApiKey()","client.getApiKey()")),o.prototype.deleteUserKey=a(function(e,t){return this.deleteApiKey(e,t)},c("index.deleteUserKey()","client.deleteApiKey()")),o.prototype.deleteApiKey=a(function(e,t){var r=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/keys/"+e,hostType:"write",callback:t})},c("index.deleteApiKey()","client.deleteApiKey()")),o.prototype.addUserKey=a(function(e,t,r){return this.addApiKey(e,t,r)},c("index.addUserKey()","client.addApiKey()")),o.prototype.addApiKey=a(function(t,r,o){var n=e(8),i="Usage: index.addApiKey(arrayOfAcls[, params, callback])";if(!n(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.description=r.description,r.queryParameters&&(s.queryParameters=this.as._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",body:s,hostType:"write",callback:o})},c("index.addApiKey()","client.addApiKey()")),o.prototype.addUserKeyWithValidity=a(function(e,t,r){return this.addApiKey(e,t,r)},c("index.addUserKeyWithValidity()","client.addApiKey()")),o.prototype.updateUserKey=a(function(e,t,r,o){return this.updateApiKey(e,t,r,o)},c("index.updateUserKey()","client.updateApiKey()")),o.prototype.updateApiKey=a(function(t,r,o,n){var i=e(8),s="Usage: index.updateApiKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof o||(n=o,o=null);var a={acl:r};return o&&(a.validity=o.validity,a.maxQueriesPerIPPerHour=o.maxQueriesPerIPPerHour,a.maxHitsPerQuery=o.maxHitsPerQuery,a.description=o.description,o.queryParameters&&(a.queryParameters=this.as._getSearchParams(o.queryParameters,"")),a.referers=o.referers),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+t,body:a,hostType:"write",callback:n})},c("index.updateApiKey()","client.updateApiKey()"))},{17:17,18:18,24:24,26:26,27:27,28:28,29:29,30:30,31:31,7:7,8:8}],17:[function(e,t,r){"use strict";function o(){}t.exports=o;var n=e(7),i=e(4).EventEmitter;n(o,i),o.prototype.stop=function(){this._stopped=!0,this._clean()},o.prototype._end=function(){this.emit("end"),this._clean()},o.prototype._error=function(e){this.emit("error",e),this._clean()},o.prototype._result=function(e){this.emit("result",e)},o.prototype._clean=function(){this.removeAllListeners("stop"),this.removeAllListeners("end"),this.removeAllListeners("error"),this.removeAllListeners("result")}},{4:4,7:7}],18:[function(e,t,r){function o(e,t){this.indexName=t,this.as=e,this.typeAheadArgs=null,this.typeAheadValueOption=null,this.cache={}}var n=e(23),i=e(26),s=e(27);t.exports=o,o.prototype.clearCache=function(){this.cache={}},o.prototype.search=n("query"),o.prototype.similarSearch=n("similarQuery"),o.prototype.browse=function(t,r,o){var n,i,s=e(31),a=this;0===arguments.length||1===arguments.length&&"function"==typeof arguments[0]?(n=0,o=arguments[0],t=void 0):"number"==typeof arguments[0]?(n=arguments[0],"number"==typeof arguments[1]?i=arguments[1]:"function"==typeof arguments[1]&&(o=arguments[1],i=void 0),t=void 0,r=void 0):"object"==typeof arguments[0]?("function"==typeof arguments[1]&&(o=arguments[1]),r=arguments[0],t=void 0):"string"==typeof arguments[0]&&"function"==typeof arguments[1]&&(o=arguments[1],r=void 0),r=s({},r||{},{page:n,hitsPerPage:i,query:t});var c=this.as._getSearchParams(r,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a.indexName)+"/browse",body:{params:c},hostType:"read",callback:o})},o.prototype.browseFrom=function(e,t){return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/browse",body:{cursor:e},hostType:"read",callback:t})},o.prototype.searchForFacetValues=function(t,r){var o=e(24),n=e(32),i="Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])";if(void 0===t.facetName||void 0===t.facetQuery)throw new Error(i);var s=t.facetName,a=n(o(t),function(e){return"facetName"===e}),c=this.as._getSearchParams(a,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/facets/"+encodeURIComponent(s)+"/query",hostType:"read",body:{params:c},callback:r})},o.prototype.searchFacet=i(function(e,t){return this.searchForFacetValues(e,t)},s("index.searchFacet(params[, callback])","index.searchForFacetValues(params[, callback])")),o.prototype._search=function(e,t,r,o){return this.as._jsonRequest({cache:this.cache,method:"POST",url:t||"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:e},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:e}},callback:r,additionalUA:o})},o.prototype.getObject=function(e,t,r){var o=this;1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var n="";if(void 0!==t){n="?attributes=";for(var i=0;i<t.length;++i)0!==i&&(n+=","),n+=t[i]}return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e)+n,hostType:"read",callback:r})},o.prototype.getObjects=function(t,r,o){var n=e(8),i=e(30),s="Usage: index.getObjects(arrayOfObjectIDs[, callback])";if(!n(t))throw new Error(s);var a=this;1!==arguments.length&&"function"!=typeof r||(o=r,r=void 0);var c={requests:i(t,function(e){var t={indexName:a.indexName,objectID:e};return r&&(t.attributesToRetrieve=r.join(",")),t})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/*/objects",hostType:"read",body:c,callback:o})},o.prototype.as=null,o.prototype.indexName=null,o.prototype.typeAheadArgs=null,o.prototype.typeAheadValueOption=null},{23:23,24:24,26:26,27:27,30:30,31:31,32:32,8:8}],19:[function(e,t,r){"use strict";var o=e(14),n=e(20);t.exports=n(o)},{14:14,20:20}],20:[function(e,t,r){(function(r){"use strict";var o=e(6),n=o.Promise||e(3).Promise;t.exports=function(t,i){function s(t,r,o){var n=e(24);return o=n(o||{}),o._ua=o._ua||s.ua,new a(t,r,o)}function a(){t.apply(this,arguments)}var c=e(7),u=e(28),l=e(21),p=e(22),d=e(33);i=i||"","debug"===r.env.NODE_ENV&&e(1).enable("algoliasearch*"),s.version=e(35),s.ua="Algolia for vanilla JavaScript "+i+s.version,s.initPlaces=d(s),o.__algolia={debug:e(1),algoliasearch:s};var h={hasXMLHttpRequest:"XMLHttpRequest"in o,hasXDomainRequest:"XDomainRequest"in o};return h.hasXMLHttpRequest&&(h.cors="withCredentials"in new XMLHttpRequest),c(a,t),a.prototype._request=function(e,t){return new n(function(r,o){function n(){if(!f){clearTimeout(d);var e;try{e={body:JSON.parse(m.responseText),responseText:m.responseText,statusCode:m.status,headers:m.getAllResponseHeaders&&m.getAllResponseHeaders()||{}}}catch(t){e=new u.UnparsableJSON({more:m.responseText})}e instanceof u.UnparsableJSON?o(e):r(e)}}function i(e){f||(clearTimeout(d),o(new u.Network({more:e})))}function s(){f=!0,m.abort(),o(new u.RequestTimeout)}function a(){v=!0,clearTimeout(d),d=setTimeout(s,t.timeouts.complete)}function c(){v||a()}function p(){!v&&m.readyState>1&&a()}if(!h.cors&&!h.hasXDomainRequest)return void o(new u.Network("CORS not supported"));e=l(e,t.headers);var d,f,y=t.body,m=h.cors?new XMLHttpRequest:new XDomainRequest,v=!1;d=setTimeout(s,t.timeouts.connect),m.onprogress=c,"onreadystatechange"in m&&(m.onreadystatechange=p),m.onload=n,m.onerror=i,m instanceof XMLHttpRequest?(m.open(t.method,e,!0),t.forceAuthHeaders&&(m.setRequestHeader("x-algolia-application-id",t.headers["x-algolia-application-id"]),m.setRequestHeader("x-algolia-api-key",t.headers["x-algolia-api-key"]))):m.open(t.method,e),h.cors&&(y&&("POST"===t.method?m.setRequestHeader("content-type","application/x-www-form-urlencoded"):m.setRequestHeader("content-type","application/json")),m.setRequestHeader("accept","application/json")),y?m.send(y):m.send()})},a.prototype._request.fallback=function(e,t){return e=l(e,t.headers),new n(function(r,o){p(e,t,function(e,t){return e?void o(e):void r(t)})})},a.prototype._promise={reject:function(e){return n.reject(e)},resolve:function(e){return n.resolve(e)},delay:function(e){return new n(function(t){setTimeout(t,e)})},all:function(e){return n.all(e)}},s}}).call(this,e(12))},{1:1,12:12,21:21,22:22,24:24,28:28,3:3,33:33,35:35,6:6,7:7}],21:[function(e,t,r){"use strict";function o(e,t){return e+=/\?/.test(e)?"&":"?",e+n(t)}t.exports=o;var n=e(13)},{13:13}],22:[function(e,t,r){"use strict";function o(e,t,r){function o(){t.debug("JSONP: success"),m||d||(m=!0,p||(t.debug("JSONP: Fail. Script loaded but did not call the callback"),a(),r(new n.JSONPScriptFail)))}function s(){"loaded"!==this.readyState&&"complete"!==this.readyState||o()}function a(){clearTimeout(v),f.onload=null,f.onreadystatechange=null,f.onerror=null,h.removeChild(f)}function c(){try{delete window[y],delete window[y+"_loaded"]}catch(e){window[y]=window[y+"_loaded"]=void 0}}function u(){t.debug("JSONP: Script timeout"),d=!0,a(),r(new n.RequestTimeout)}function l(){t.debug("JSONP: Script error"),m||d||(a(),r(new n.JSONPScriptError))}if("GET"!==t.method)return void r(new Error("Method "+t.method+" "+e+" is not supported by JSONP."));t.debug("JSONP: start");var p=!1,d=!1;i+=1;var h=document.getElementsByTagName("head")[0],f=document.createElement("script"),y="algoliaJSONP_"+i,m=!1;window[y]=function(e){return c(),d?void t.debug("JSONP: Late answer, ignoring"):(p=!0,a(),void r(null,{body:e,responseText:JSON.stringify(e)}))},e+="&callback="+y,t.jsonBody&&t.jsonBody.params&&(e+="&"+t.jsonBody.params);var v=setTimeout(u,t.timeouts.complete);f.onreadystatechange=s,f.onload=o,f.onerror=l,f.async=!0,f.defer=!0,f.src=e,h.appendChild(f)}t.exports=o;var n=e(28),i=0},{28:28}],23:[function(e,t,r){function o(e,t){return function(r,o,i){if("function"==typeof r&&"object"==typeof o||"object"==typeof i)throw new n.AlgoliaSearchError("index.search usage is index.search(query, params, cb)");0===arguments.length||"function"==typeof r?(i=r,r=""):1!==arguments.length&&"function"!=typeof o||(i=o,o=void 0),"object"==typeof r&&null!==r?(o=r,r=void 0):void 0!==r&&null!==r||(r="");var s="";void 0!==r&&(s+=e+"="+encodeURIComponent(r));var a;return void 0!==o&&(o.additionalUA&&(a=o.additionalUA,delete o.additionalUA),s=this.as._getSearchParams(o,s)),this._search(s,t,i,a)}}t.exports=o;var n=e(28)},{28:28}],24:[function(e,t,r){t.exports=function(e){return JSON.parse(JSON.stringify(e))}},{}],25:[function(e,t,r){function o(e,t,r){var o={};return r=r||{},r.hosts=r.hosts||["analytics.algolia.com","analytics.algolia.com","analytics.algolia.com","analytics.algolia.com"],r.protocol=r.protocol||"https:",o.as=n(e,t,r),o.getABTests=function(e,t){var r=r||{},o=r.offset||0,n=r.limit||10;return this.as._jsonRequest({method:"GET",url:"/2/abtests?offset="+encodeURIComponent(o)+"&limit="+encodeURIComponent(n),hostType:"read",forceAuthHeaders:!0,callback:t})},o.getABTest=function(e,t){return this.as._jsonRequest({method:"GET",url:"/2/abtests/"+encodeURIComponent(e),hostType:"read",forceAuthHeaders:!0,callback:t})},o.addABTest=function(e,t){return this.as._jsonRequest({ +method:"POST",url:"/2/abtests",body:e,hostType:"read",forceAuthHeaders:!0,callback:t})},o.stopABTest=function(e,t){return this.as._jsonRequest({method:"POST",url:"/2/abtests/"+encodeURIComponent(e)+"/stop",hostType:"read",forceAuthHeaders:!0,callback:t})},o.deleteABTest=function(e,t){return this.as._jsonRequest({method:"DELETE",url:"/2/abtests/"+encodeURIComponent(e),hostType:"write",forceAuthHeaders:!0,callback:t})},o.waitTask=function(e,t,r){return this.as.initIndex(e).waitTask(t,r)},o}t.exports=o;var n=e(19)},{19:19}],26:[function(e,t,r){t.exports=function(e,t){function r(){return o||(console.warn(t),o=!0),e.apply(this,arguments)}var o=!1;return r}},{}],27:[function(e,t,r){t.exports=function(e,t){var r=e.toLowerCase().replace(/[\.\(\)]/g,"");return"algoliasearch: `"+e+"` was replaced by `"+t+"`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#"+r}},{}],28:[function(e,t,r){"use strict";function o(t,r){var o=e(5),n=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):n.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name="AlgoliaSearchError",this.message=t||"Unknown error",r&&o(r,function(e,t){n[t]=e})}function n(e,t){function r(){var r=Array.prototype.slice.call(arguments,0);"string"!=typeof r[0]&&r.unshift(t),o.apply(this,r),this.name="AlgoliaSearch"+e+"Error"}return i(r,o),r}var i=e(7);i(o,Error),t.exports={AlgoliaSearchError:o,UnparsableJSON:n("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:n("RequestTimeout","Request timedout before getting a response"),Network:n("Network","Network issue, see err.more for details"),JSONPScriptFail:n("JSONPScriptFail","<script> was loaded but did not call our provided callback"),JSONPScriptError:n("JSONPScriptError","<script> unable to load due to an `error` event on it"),Unknown:n("Unknown","Unknown error occured")}},{5:5,7:7}],29:[function(e,t,r){t.exports=function(e,t){t(e,0)}},{}],30:[function(e,t,r){var o=e(5);t.exports=function(e,t){var r=[];return o(e,function(o,n){r.push(t(o,n,e))}),r}},{5:5}],31:[function(e,t,r){var o=e(5);t.exports=function n(e){var t=Array.prototype.slice.call(arguments);return o(t,function(t){for(var r in t)t.hasOwnProperty(r)&&("object"==typeof e[r]&&"object"==typeof t[r]?e[r]=n({},e[r],t[r]):void 0!==t[r]&&(e[r]=t[r]))}),e}},{5:5}],32:[function(e,t,r){t.exports=function(t,r){var o=e(10),n=e(5),i={};return n(o(t),function(e){r(e)!==!0&&(i[e]=t[e])}),i}},{10:10,5:5}],33:[function(e,t,r){function o(t){return function(r,o,i){var s=e(24);i=i&&s(i)||{},i.hosts=i.hosts||["places-dsn.algolia.net","places-1.algolianet.com","places-2.algolianet.com","places-3.algolianet.com"],0!==arguments.length&&"object"!=typeof r&&void 0!==r||(r="",o="",i._allowEmptyCredentials=!0);var a=t(r,o,i),c=a.initIndex("places");return c.search=n("query","/1/places/query"),c.getObject=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/places/"+encodeURIComponent(e),hostType:"read",callback:t})},c}}t.exports=o;var n=e(23)},{23:23,24:24}],34:[function(e,t,r){(function(r){function o(e,t){return c("localStorage failed with",t),s(),a=l,a.get(e)}function n(e,t){return 1===arguments.length?a.get(e):a.set(e,t)}function i(){try{return"localStorage"in r&&null!==r.localStorage&&(r.localStorage[u]||r.localStorage.setItem(u,JSON.stringify({})),!0)}catch(e){return!1}}function s(){try{r.localStorage.removeItem(u)}catch(e){}}var a,c=e(1)("algoliasearch:src/hostIndexState.js"),u="algoliasearch-client-js",l={state:{},set:function(e,t){return this.state[e]=t,this.state[e]},get:function(e){return this.state[e]||null}},p={set:function(e,t){l.set(e,t);try{var n=JSON.parse(r.localStorage[u]);return n[e]=t,r.localStorage[u]=JSON.stringify(n),n[e]}catch(i){return o(e,i)}},get:function(e){try{return JSON.parse(r.localStorage[u])[e]||null}catch(t){return o(e,t)}}};a=i()?p:l,t.exports={get:n,set:n,supportsLocalStorage:i}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],35:[function(e,t,r){"use strict";t.exports="3.30.0"},{}]},{},[19])(19)}); diff --git a/node_modules/algoliasearch/dist/algoliasearchLite.js b/node_modules/algoliasearch/dist/algoliasearchLite.js new file mode 100644 index 00000000..c61e568e --- /dev/null +++ b/node_modules/algoliasearch/dist/algoliasearchLite.js @@ -0,0 +1,4330 @@ +/*! algoliasearch 3.30.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.algoliasearch = f()}})(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){ +(function (process){ +/** + * This is the web browser implementation of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = require(2); +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); + +/** + * Colors. + */ + +exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' +]; + +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ + +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; + } + + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} + +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; + } +}; + + +/** + * Colorize log arguments if enabled. + * + * @api public + */ + +function formatArgs(args) { + var useColors = this.useColors; + + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); + + if (!useColors) return; + + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit') + + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); + + args.splice(lastC, 0, c); +} + +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ + +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); +} + +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ + +function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + + return r; +} + +/** + * Enable namespaces listed in `localStorage.debug` initially. + */ + +exports.enable(load()); + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + return window.localStorage; + } catch (e) {} +} + +}).call(this,require(11)) +},{"11":11,"2":2}],2:[function(require,module,exports){ + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ + +exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = require(8); + +/** + * The currently active debug mode names, and names to skip. + */ + +exports.names = []; +exports.skips = []; + +/** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + +exports.formatters = {}; + +/** + * Previous log timestamp. + */ + +var prevTime; + +/** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ + +function selectColor(namespace) { + var hash = 0, i; + + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return exports.colors[Math.abs(hash) % exports.colors.length]; +} + +/** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + +function createDebug(namespace) { + + function debug() { + // disabled? + if (!debug.enabled) return; + + var self = debug; + + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + + args[0] = exports.coerce(args[0]); + + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); + } + + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); + + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); + + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); + + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); + } + + return debug; +} + +/** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + +function enable(namespaces) { + exports.save(namespaces); + + exports.names = []; + exports.skips = []; + + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } + } +} + +/** + * Disable debug output. + * + * @api public + */ + +function disable() { + exports.enable(''); +} + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } + } + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } + } + return false; +} + +/** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + +},{"8":8}],3:[function(require,module,exports){ +(function (process,global){ +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE + * @version 4.1.1 + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.ES6Promise = factory()); +}(this, (function () { 'use strict'; + +function objectOrFunction(x) { + var type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} + +function isFunction(x) { + return typeof x === 'function'; +} + +var _isArray = undefined; +if (Array.isArray) { + _isArray = Array.isArray; +} else { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; +} + +var isArray = _isArray; + +var len = 0; +var vertxNext = undefined; +var customSchedulerFn = undefined; + +var asap = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (customSchedulerFn) { + customSchedulerFn(flush); + } else { + scheduleFlush(); + } + } +}; + +function setScheduler(scheduleFn) { + customSchedulerFn = scheduleFn; +} + +function setAsap(asapFn) { + asap = asapFn; +} + +var browserWindow = typeof window !== 'undefined' ? window : undefined; +var browserGlobal = browserWindow || {}; +var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; +var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]'; + +// test for web worker but not in IE10 +var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; + +// node +function useNextTick() { + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // see https://github.com/cujojs/when/issues/410 for details + return function () { + return process.nextTick(flush); + }; +} + +// vertx +function useVertxTimer() { + if (typeof vertxNext !== 'undefined') { + return function () { + vertxNext(flush); + }; + } + + return useSetTimeout(); +} + +function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function () { + node.data = iterations = ++iterations % 2; + }; +} + +// web worker +function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + return channel.port2.postMessage(0); + }; +} + +function useSetTimeout() { + // Store setTimeout reference so es6-promise will be unaffected by + // other code modifying setTimeout (like sinon.useFakeTimers()) + var globalSetTimeout = setTimeout; + return function () { + return globalSetTimeout(flush, 1); + }; +} + +var queue = new Array(1000); +function flush() { + for (var i = 0; i < len; i += 2) { + var callback = queue[i]; + var arg = queue[i + 1]; + + callback(arg); + + queue[i] = undefined; + queue[i + 1] = undefined; + } + + len = 0; +} + +function attemptVertx() { + try { + var r = require; + var vertx = r('vertx'); + vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch (e) { + return useSetTimeout(); + } +} + +var scheduleFlush = undefined; +// Decide what async method to use to triggering processing of queued callbacks: +if (isNode) { + scheduleFlush = useNextTick(); +} else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); +} else if (isWorker) { + scheduleFlush = useMessageChannel(); +} else if (browserWindow === undefined && typeof require === 'function') { + scheduleFlush = attemptVertx(); +} else { + scheduleFlush = useSetTimeout(); +} + +function then(onFulfillment, onRejection) { + var _arguments = arguments; + + var parent = this; + + var child = new this.constructor(noop); + + if (child[PROMISE_ID] === undefined) { + makePromise(child); + } + + var _state = parent._state; + + if (_state) { + (function () { + var callback = _arguments[_state - 1]; + asap(function () { + return invokeCallback(_state, child, callback, parent._result); + }); + })(); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; +} + +/** + `Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` +*/ +function resolve$1(object) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop); + resolve(promise, object); + return promise; +} + +var PROMISE_ID = Math.random().toString(36).substring(16); + +function noop() {} + +var PENDING = void 0; +var FULFILLED = 1; +var REJECTED = 2; + +var GET_THEN_ERROR = new ErrorObject(); + +function selfFulfillment() { + return new TypeError("You cannot resolve a promise with itself"); +} + +function cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); +} + +function getThen(promise) { + try { + return promise.then; + } catch (error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } +} + +function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) { + try { + then$$1.call(value, fulfillmentHandler, rejectionHandler); + } catch (e) { + return e; + } +} + +function handleForeignThenable(promise, thenable, then$$1) { + asap(function (promise) { + var sealed = false; + var error = tryThen(then$$1, thenable, function (value) { + if (sealed) { + return; + } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function (reason) { + if (sealed) { + return; + } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); +} + +function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (thenable._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function (value) { + return resolve(promise, value); + }, function (reason) { + return reject(promise, reason); + }); + } +} + +function handleMaybeThenable(promise, maybeThenable, then$$1) { + if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) { + handleOwnThenable(promise, maybeThenable); + } else { + if (then$$1 === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + GET_THEN_ERROR.error = null; + } else if (then$$1 === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then$$1)) { + handleForeignThenable(promise, maybeThenable, then$$1); + } else { + fulfill(promise, maybeThenable); + } + } +} + +function resolve(promise, value) { + if (promise === value) { + reject(promise, selfFulfillment()); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value, getThen(value)); + } else { + fulfill(promise, value); + } +} + +function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); +} + +function fulfill(promise, value) { + if (promise._state !== PENDING) { + return; + } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length !== 0) { + asap(publish, promise); + } +} + +function reject(promise, reason) { + if (promise._state !== PENDING) { + return; + } + promise._state = REJECTED; + promise._result = reason; + + asap(publishRejection, promise); +} + +function subscribe(parent, child, onFulfillment, onRejection) { + var _subscribers = parent._subscribers; + var length = _subscribers.length; + + parent._onerror = null; + + _subscribers[length] = child; + _subscribers[length + FULFILLED] = onFulfillment; + _subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + asap(publish, parent); + } +} + +function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (subscribers.length === 0) { + return; + } + + var child = undefined, + callback = undefined, + detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; +} + +function ErrorObject() { + this.error = null; +} + +var TRY_CATCH_ERROR = new ErrorObject(); + +function tryCatch(callback, detail) { + try { + return callback(detail); + } catch (e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } +} + +function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value = undefined, + error = undefined, + succeeded = undefined, + failed = undefined; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value.error = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, cannotReturnOwn()); + return; + } + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } +} + +function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value) { + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch (e) { + reject(promise, e); + } +} + +var id = 0; +function nextId() { + return id++; +} + +function makePromise(promise) { + promise[PROMISE_ID] = id++; + promise._state = undefined; + promise._result = undefined; + promise._subscribers = []; +} + +function Enumerator$1(Constructor, input) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop); + + if (!this.promise[PROMISE_ID]) { + makePromise(this.promise); + } + + if (isArray(input)) { + this.length = input.length; + this._remaining = input.length; + + this._result = new Array(this.length); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(input); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, validationError()); + } +} + +function validationError() { + return new Error('Array Methods must be provided an Array'); +} + +Enumerator$1.prototype._enumerate = function (input) { + for (var i = 0; this._state === PENDING && i < input.length; i++) { + this._eachEntry(input[i], i); + } +}; + +Enumerator$1.prototype._eachEntry = function (entry, i) { + var c = this._instanceConstructor; + var resolve$$1 = c.resolve; + + if (resolve$$1 === resolve$1) { + var _then = getThen(entry); + + if (_then === then && entry._state !== PENDING) { + this._settledAt(entry._state, i, entry._result); + } else if (typeof _then !== 'function') { + this._remaining--; + this._result[i] = entry; + } else if (c === Promise$2) { + var promise = new c(noop); + handleMaybeThenable(promise, entry, _then); + this._willSettleAt(promise, i); + } else { + this._willSettleAt(new c(function (resolve$$1) { + return resolve$$1(entry); + }), i); + } + } else { + this._willSettleAt(resolve$$1(entry), i); + } +}; + +Enumerator$1.prototype._settledAt = function (state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = value; + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } +}; + +Enumerator$1.prototype._willSettleAt = function (promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function (value) { + return enumerator._settledAt(FULFILLED, i, value); + }, function (reason) { + return enumerator._settledAt(REJECTED, i, reason); + }); +}; + +/** + `Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = resolve(2); + let promise3 = resolve(3); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = reject(new Error("2")); + let promise3 = reject(new Error("3")); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static +*/ +function all$1(entries) { + return new Enumerator$1(this, entries).promise; +} + +/** + `Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. +*/ +function race$1(entries) { + /*jshint validthis:true */ + var Constructor = this; + + if (!isArray(entries)) { + return new Constructor(function (_, reject) { + return reject(new TypeError('You must pass an array to race.')); + }); + } else { + return new Constructor(function (resolve, reject) { + var length = entries.length; + for (var i = 0; i < length; i++) { + Constructor.resolve(entries[i]).then(resolve, reject); + } + }); + } +} + +/** + `Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. +*/ +function reject$1(reason) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop); + reject(promise, reason); + return promise; +} + +function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); +} + +function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); +} + +/** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + let promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + let xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {function} resolver + Useful for tooling. + @constructor +*/ +function Promise$2(resolver) { + this[PROMISE_ID] = nextId(); + this._result = this._state = undefined; + this._subscribers = []; + + if (noop !== resolver) { + typeof resolver !== 'function' && needsResolver(); + this instanceof Promise$2 ? initializePromise(this, resolver) : needsNew(); + } +} + +Promise$2.all = all$1; +Promise$2.race = race$1; +Promise$2.resolve = resolve$1; +Promise$2.reject = reject$1; +Promise$2._setScheduler = setScheduler; +Promise$2._setAsap = setAsap; +Promise$2._asap = asap; + +Promise$2.prototype = { + constructor: Promise$2, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + let result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + let author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: then, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function _catch(onRejection) { + return this.then(null, onRejection); + } +}; + +/*global self*/ +function polyfill$1() { + var local = undefined; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } + + var P = local.Promise; + + if (P) { + var promiseToString = null; + try { + promiseToString = Object.prototype.toString.call(P.resolve()); + } catch (e) { + // silently ignored + } + + if (promiseToString === '[object Promise]' && !P.cast) { + return; + } + } + + local.Promise = Promise$2; +} + +// Strange compat.. +Promise$2.polyfill = polyfill$1; +Promise$2.Promise = Promise$2; + +return Promise$2; + +}))); + + + +}).call(this,require(11),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"11":11}],4:[function(require,module,exports){ + +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; + +module.exports = function forEach (obj, fn, ctx) { + if (toString.call(fn) !== '[object Function]') { + throw new TypeError('iterator must be a function'); + } + var l = obj.length; + if (l === +l) { + for (var i = 0; i < l; i++) { + fn.call(ctx, obj[i], i, obj); + } + } else { + for (var k in obj) { + if (hasOwn.call(obj, k)) { + fn.call(ctx, obj[k], k, obj); + } + } + } +}; + + +},{}],5:[function(require,module,exports){ +(function (global){ +var win; + +if (typeof window !== "undefined") { + win = window; +} else if (typeof global !== "undefined") { + win = global; +} else if (typeof self !== "undefined"){ + win = self; +} else { + win = {}; +} + +module.exports = win; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],6:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],7:[function(require,module,exports){ +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; + +},{}],8:[function(require,module,exports){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + if (ms >= d) { + return Math.round(ms / d) + 'd'; + } + if (ms >= h) { + return Math.round(ms / h) + 'h'; + } + if (ms >= m) { + return Math.round(ms / m) + 'm'; + } + if (ms >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + return plural(ms, d, 'day') || + plural(ms, h, 'hour') || + plural(ms, m, 'minute') || + plural(ms, s, 'second') || + ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) { + return; + } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; + } + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +},{}],9:[function(require,module,exports){ +'use strict'; + +// modified from https://github.com/es-shims/es5-shim +var has = Object.prototype.hasOwnProperty; +var toStr = Object.prototype.toString; +var slice = Array.prototype.slice; +var isArgs = require(10); +var isEnumerable = Object.prototype.propertyIsEnumerable; +var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); +var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); +var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' +]; +var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; +}; +var excludedKeys = { + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true +}; +var hasAutomationEqualityBug = (function () { + /* global window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; +}()); +var equalsConstructorPrototypeIfNotBuggy = function (o) { + /* global window */ + if (typeof window === 'undefined' || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } +}; + +var keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; + + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } + + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; +}; + +keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function () { + // Safari 5.0 bug + return (Object.keys(arguments) || '').length === 2; + }(1, 2)); + if (!keysWorksWithArguments) { + var originalKeys = Object.keys; + Object.keys = function keys(object) { + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } else { + return originalKeys(object); + } + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; +}; + +module.exports = keysShim; + +},{"10":10}],10:[function(require,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + toStr.call(value.callee) === '[object Function]'; + } + return isArgs; +}; + +},{}],11:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],12:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; + + case 'boolean': + return v ? 'true' : 'false'; + + case 'number': + return isFinite(v) ? v : ''; + + default: + return ''; + } +}; + +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; + } + + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); + } + }).join(sep); + + } + + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); + } + return res; +} + +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + return res; +}; + +},{}],13:[function(require,module,exports){ +(function (process){ +module.exports = AlgoliaSearchCore; + +var errors = require(23); +var exitPromise = require(24); +var IndexCore = require(14); +var store = require(29); + +// We will always put the API KEY in the JSON body in case of too long API KEY, +// to avoid query string being too long and failing in various conditions (our server limit, browser limit, +// proxies limit) +var MAX_API_KEY_LENGTH = 500; +var RESET_APP_DATA_TIMER = + process.env.RESET_APP_DATA_TIMER && parseInt(process.env.RESET_APP_DATA_TIMER, 10) || + 60 * 2 * 1000; // after 2 minutes reset to first host + +/* + * Algolia Search library initialization + * https://www.algolia.com/ + * + * @param {string} applicationID - Your applicationID, found in your dashboard + * @param {string} apiKey - Your API key, found in your dashboard + * @param {Object} [opts] + * @param {number} [opts.timeout=2000] - The request timeout set in milliseconds, + * another request will be issued after this timeout + * @param {string} [opts.protocol='https:'] - The protocol used to query Algolia Search API. + * Set to 'http:' to force using http. + * @param {Object|Array} [opts.hosts={ + * read: [this.applicationID + '-dsn.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]), + * write: [this.applicationID + '.algolia.net'].concat([ + * this.applicationID + '-1.algolianet.com', + * this.applicationID + '-2.algolianet.com', + * this.applicationID + '-3.algolianet.com'] + * ]) - The hosts to use for Algolia Search API. + * If you provide them, you will less benefit from our HA implementation + */ +function AlgoliaSearchCore(applicationID, apiKey, opts) { + var debug = require(1)('algoliasearch'); + + var clone = require(20); + var isArray = require(7); + var map = require(25); + + var usage = 'Usage: algoliasearch(applicationID, apiKey, opts)'; + + if (opts._allowEmptyCredentials !== true && !applicationID) { + throw new errors.AlgoliaSearchError('Please provide an application ID. ' + usage); + } + + if (opts._allowEmptyCredentials !== true && !apiKey) { + throw new errors.AlgoliaSearchError('Please provide an API key. ' + usage); + } + + this.applicationID = applicationID; + this.apiKey = apiKey; + + this.hosts = { + read: [], + write: [] + }; + + opts = opts || {}; + + this._timeouts = opts.timeouts || { + connect: 1 * 1000, // 500ms connect is GPRS latency + read: 2 * 1000, + write: 30 * 1000 + }; + + // backward compat, if opts.timeout is passed, we use it to configure all timeouts like before + if (opts.timeout) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = opts.timeout; + } + + var protocol = opts.protocol || 'https:'; + // while we advocate for colon-at-the-end values: 'http:' for `opts.protocol` + // we also accept `http` and `https`. It's a common error. + if (!/:$/.test(protocol)) { + protocol = protocol + ':'; + } + + if (protocol !== 'http:' && protocol !== 'https:') { + throw new errors.AlgoliaSearchError('protocol must be `http:` or `https:` (was `' + opts.protocol + '`)'); + } + + this._checkAppIdData(); + + if (!opts.hosts) { + var defaultHosts = map(this._shuffleResult, function(hostNumber) { + return applicationID + '-' + hostNumber + '.algolianet.com'; + }); + + // no hosts given, compute defaults + var mainSuffix = (opts.dsn === false ? '' : '-dsn') + '.algolia.net'; + this.hosts.read = [this.applicationID + mainSuffix].concat(defaultHosts); + this.hosts.write = [this.applicationID + '.algolia.net'].concat(defaultHosts); + } else if (isArray(opts.hosts)) { + // when passing custom hosts, we need to have a different host index if the number + // of write/read hosts are different. + this.hosts.read = clone(opts.hosts); + this.hosts.write = clone(opts.hosts); + } else { + this.hosts.read = clone(opts.hosts.read); + this.hosts.write = clone(opts.hosts.write); + } + + // add protocol and lowercase hosts + this.hosts.read = map(this.hosts.read, prepareHost(protocol)); + this.hosts.write = map(this.hosts.write, prepareHost(protocol)); + + this.extraHeaders = {}; + + // In some situations you might want to warm the cache + this.cache = opts._cache || {}; + + this._ua = opts._ua; + this._useCache = opts._useCache === undefined || opts._cache ? true : opts._useCache; + this._useRequestCache = this._useCache && opts._useRequestCache; + this._useFallback = opts.useFallback === undefined ? true : opts.useFallback; + + this._setTimeout = opts._setTimeout; + + debug('init done, %j', this); +} + +/* + * Get the index object initialized + * + * @param indexName the name of index + * @param callback the result callback with one argument (the Index instance) + */ +AlgoliaSearchCore.prototype.initIndex = function(indexName) { + return new IndexCore(this, indexName); +}; + +/** +* Add an extra field to the HTTP request +* +* @param name the header field name +* @param value the header field value +*/ +AlgoliaSearchCore.prototype.setExtraHeader = function(name, value) { + this.extraHeaders[name.toLowerCase()] = value; +}; + +/** +* Get the value of an extra HTTP header +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.getExtraHeader = function(name) { + return this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Remove an extra field from the HTTP request +* +* @param name the header field name +*/ +AlgoliaSearchCore.prototype.unsetExtraHeader = function(name) { + delete this.extraHeaders[name.toLowerCase()]; +}; + +/** +* Augment sent x-algolia-agent with more data, each agent part +* is automatically separated from the others by a semicolon; +* +* @param algoliaAgent the agent to add +*/ +AlgoliaSearchCore.prototype.addAlgoliaAgent = function(algoliaAgent) { + if (this._ua.indexOf(';' + algoliaAgent) === -1) { + this._ua += ';' + algoliaAgent; + } +}; + +/* + * Wrapper that try all hosts to maximize the quality of service + */ +AlgoliaSearchCore.prototype._jsonRequest = function(initialOpts) { + this._checkAppIdData(); + + var requestDebug = require(1)('algoliasearch:' + initialOpts.url); + + + var body; + var cacheID; + var additionalUA = initialOpts.additionalUA || ''; + var cache = initialOpts.cache; + var client = this; + var tries = 0; + var usingFallback = false; + var hasFallback = client._useFallback && client._request.fallback && initialOpts.fallback; + var headers; + + if ( + this.apiKey.length > MAX_API_KEY_LENGTH && + initialOpts.body !== undefined && + (initialOpts.body.params !== undefined || // index.search() + initialOpts.body.requests !== undefined) // client.search() + ) { + initialOpts.body.apiKey = this.apiKey; + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + withApiKey: false, + headers: initialOpts.headers + }); + } else { + headers = this._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + } + + if (initialOpts.body !== undefined) { + body = safeJSONStringify(initialOpts.body); + } + + requestDebug('request start'); + var debugData = []; + + + function doRequest(requester, reqOpts) { + client._checkAppIdData(); + + var startTime = new Date(); + + if (client._useCache && !client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && !client._useRequestCache && body) { + cacheID += '_body_' + reqOpts.body; + } + + // handle cache existence + if (isCacheValidWithCurrentID(!client._useRequestCache, cache, cacheID)) { + requestDebug('serving response from cache'); + + var responseText = cache[cacheID]; + + // Cache response must match the type of the original one + return client._promise.resolve({ + body: JSON.parse(responseText), + responseText: responseText + }); + } + + // if we reached max tries + if (tries >= client.hosts[initialOpts.hostType].length) { + if (!hasFallback || usingFallback) { + requestDebug('could not get any response'); + // then stop + return client._promise.reject(new errors.AlgoliaSearchError( + 'Cannot connect to the AlgoliaSearch API.' + + ' Send an email to support@algolia.com to report and resolve the issue.' + + ' Application id was: ' + client.applicationID, {debugData: debugData} + )); + } + + requestDebug('switching to fallback'); + + // let's try the fallback starting from here + tries = 0; + + // method, url and body are fallback dependent + reqOpts.method = initialOpts.fallback.method; + reqOpts.url = initialOpts.fallback.url; + reqOpts.jsonBody = initialOpts.fallback.body; + if (reqOpts.jsonBody) { + reqOpts.body = safeJSONStringify(reqOpts.jsonBody); + } + // re-compute headers, they could be omitting the API KEY + headers = client._computeRequestHeaders({ + additionalUA: additionalUA, + headers: initialOpts.headers + }); + + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + client._setHostIndexByType(0, initialOpts.hostType); + usingFallback = true; // the current request is now using fallback + return doRequest(client._request.fallback, reqOpts); + } + + var currentHost = client._getHostByType(initialOpts.hostType); + + var url = currentHost + reqOpts.url; + var options = { + body: reqOpts.body, + jsonBody: reqOpts.jsonBody, + method: reqOpts.method, + headers: headers, + timeouts: reqOpts.timeouts, + debug: requestDebug, + forceAuthHeaders: reqOpts.forceAuthHeaders + }; + + requestDebug('method: %s, url: %s, headers: %j, timeouts: %d', + options.method, url, options.headers, options.timeouts); + + if (requester === client._request.fallback) { + requestDebug('using fallback'); + } + + // `requester` is any of this._request or this._request.fallback + // thus it needs to be called using the client as context + return requester.call(client, url, options).then(success, tryFallback); + + function success(httpResponse) { + // compute the status of the response, + // + // When in browser mode, using XDR or JSONP, we have no statusCode available + // So we rely on our API response `status` property. + // But `waitTask` can set a `status` property which is not the statusCode (it's the task status) + // So we check if there's a `message` along `status` and it means it's an error + // + // That's the only case where we have a response.status that's not the http statusCode + var status = httpResponse && httpResponse.body && httpResponse.body.message && httpResponse.body.status || + + // this is important to check the request statusCode AFTER the body eventual + // statusCode because some implementations (jQuery XDomainRequest transport) may + // send statusCode 200 while we had an error + httpResponse.statusCode || + + // When in browser mode, using XDR or JSONP + // we default to success when no error (no response.status && response.message) + // If there was a JSON.parse() error then body is null and it fails + httpResponse && httpResponse.body && 200; + + requestDebug('received response: statusCode: %s, computed statusCode: %d, headers: %j', + httpResponse.statusCode, status, httpResponse.headers); + + var httpResponseOk = Math.floor(status / 100) === 2; + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime, + statusCode: status + }); + + if (httpResponseOk) { + if (client._useCache && !client._useRequestCache && cache) { + cache[cacheID] = httpResponse.responseText; + } + + return { + responseText: httpResponse.responseText, + body: httpResponse.body + }; + } + + var shouldRetry = Math.floor(status / 100) !== 4; + + if (shouldRetry) { + tries += 1; + return retryRequest(); + } + + requestDebug('unrecoverable error'); + + // no success and no retry => fail + var unrecoverableError = new errors.AlgoliaSearchError( + httpResponse.body && httpResponse.body.message, {debugData: debugData, statusCode: status} + ); + + return client._promise.reject(unrecoverableError); + } + + function tryFallback(err) { + // error cases: + // While not in fallback mode: + // - CORS not supported + // - network error + // While in fallback mode: + // - timeout + // - network error + // - badly formatted JSONP (script loaded, did not call our callback) + // In both cases: + // - uncaught exception occurs (TypeError) + requestDebug('error: %s, stack: %s', err.message, err.stack); + + var endTime = new Date(); + debugData.push({ + currentHost: currentHost, + headers: removeCredentials(headers), + content: body || null, + contentLength: body !== undefined ? body.length : null, + method: reqOpts.method, + timeouts: reqOpts.timeouts, + url: reqOpts.url, + startTime: startTime, + endTime: endTime, + duration: endTime - startTime + }); + + if (!(err instanceof errors.AlgoliaSearchError)) { + err = new errors.Unknown(err && err.message, err); + } + + tries += 1; + + // stop the request implementation when: + if ( + // we did not generate this error, + // it comes from a throw in some other piece of code + err instanceof errors.Unknown || + + // server sent unparsable JSON + err instanceof errors.UnparsableJSON || + + // max tries and already using fallback or no fallback + tries >= client.hosts[initialOpts.hostType].length && + (usingFallback || !hasFallback)) { + // stop request implementation for this command + err.debugData = debugData; + return client._promise.reject(err); + } + + // When a timeout occured, retry by raising timeout + if (err instanceof errors.RequestTimeout) { + return retryRequestWithHigherTimeout(); + } + + return retryRequest(); + } + + function retryRequest() { + requestDebug('retrying request'); + client._incrementHostIndex(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + + function retryRequestWithHigherTimeout() { + requestDebug('retrying request with higher timeout'); + client._incrementHostIndex(initialOpts.hostType); + client._incrementTimeoutMultipler(); + reqOpts.timeouts = client._getTimeoutsForRequest(initialOpts.hostType); + return doRequest(requester, reqOpts); + } + } + + function isCacheValidWithCurrentID( + useRequestCache, + currentCache, + currentCacheID + ) { + return ( + client._useCache && + useRequestCache && + currentCache && + currentCache[currentCacheID] !== undefined + ); + } + + + function interopCallbackReturn(request, callback) { + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + request.catch(function() { + // Release the cache on error + delete cache[cacheID]; + }); + } + + if (typeof initialOpts.callback === 'function') { + // either we have a callback + request.then(function okCb(content) { + exitPromise(function() { + initialOpts.callback(null, callback(content)); + }, client._setTimeout || setTimeout); + }, function nookCb(err) { + exitPromise(function() { + initialOpts.callback(err); + }, client._setTimeout || setTimeout); + }); + } else { + // either we are using promises + return request.then(callback); + } + } + + if (client._useCache && client._useRequestCache) { + cacheID = initialOpts.url; + } + + // as we sometime use POST requests to pass parameters (like query='aa'), + // the cacheID must also include the body to be different between calls + if (client._useCache && client._useRequestCache && body) { + cacheID += '_body_' + body; + } + + if (isCacheValidWithCurrentID(client._useRequestCache, cache, cacheID)) { + requestDebug('serving request from cache'); + + var maybePromiseForCache = cache[cacheID]; + + // In case the cache is warmup with value that is not a promise + var promiseForCache = typeof maybePromiseForCache.then !== 'function' + ? client._promise.resolve({responseText: maybePromiseForCache}) + : maybePromiseForCache; + + return interopCallbackReturn(promiseForCache, function(content) { + // In case of the cache request, return the original value + return JSON.parse(content.responseText); + }); + } + + var request = doRequest( + client._request, { + url: initialOpts.url, + method: initialOpts.method, + body: body, + jsonBody: initialOpts.body, + timeouts: client._getTimeoutsForRequest(initialOpts.hostType), + forceAuthHeaders: initialOpts.forceAuthHeaders + } + ); + + if (client._useCache && client._useRequestCache && cache) { + cache[cacheID] = request; + } + + return interopCallbackReturn(request, function(content) { + // In case of the first request, return the JSON value + return content.body; + }); +}; + +/* +* Transform search param object in query string +* @param {object} args arguments to add to the current query string +* @param {string} params current query string +* @return {string} the final query string +*/ +AlgoliaSearchCore.prototype._getSearchParams = function(args, params) { + if (args === undefined || args === null) { + return params; + } + for (var key in args) { + if (key !== null && args[key] !== undefined && args.hasOwnProperty(key)) { + params += params === '' ? '' : '&'; + params += key + '=' + encodeURIComponent(Object.prototype.toString.call(args[key]) === '[object Array]' ? safeJSONStringify(args[key]) : args[key]); + } + } + return params; +}; + +/** + * Compute the headers for a request + * + * @param [string] options.additionalUA semi-colon separated string with other user agents to add + * @param [boolean=true] options.withApiKey Send the api key as a header + * @param [Object] options.headers Extra headers to send + */ +AlgoliaSearchCore.prototype._computeRequestHeaders = function(options) { + var forEach = require(4); + + var ua = options.additionalUA ? + this._ua + ';' + options.additionalUA : + this._ua; + + var requestHeaders = { + 'x-algolia-agent': ua, + 'x-algolia-application-id': this.applicationID + }; + + // browser will inline headers in the url, node.js will use http headers + // but in some situations, the API KEY will be too long (big secured API keys) + // so if the request is a POST and the KEY is very long, we will be asked to not put + // it into headers but in the JSON body + if (options.withApiKey !== false) { + requestHeaders['x-algolia-api-key'] = this.apiKey; + } + + if (this.userToken) { + requestHeaders['x-algolia-usertoken'] = this.userToken; + } + + if (this.securityTags) { + requestHeaders['x-algolia-tagfilters'] = this.securityTags; + } + + forEach(this.extraHeaders, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + + if (options.headers) { + forEach(options.headers, function addToRequestHeaders(value, key) { + requestHeaders[key] = value; + }); + } + + return requestHeaders; +}; + +/** + * Search through multiple indices at the same time + * @param {Object[]} queries An array of queries you want to run. + * @param {string} queries[].indexName The index name you want to target + * @param {string} [queries[].query] The query to issue on this index. Can also be passed into `params` + * @param {Object} queries[].params Any search param like hitsPerPage, .. + * @param {Function} callback Callback to be called + * @return {Promise|undefined} Returns a promise if no callback given + */ +AlgoliaSearchCore.prototype.search = function(queries, opts, callback) { + var isArray = require(7); + var map = require(25); + + var usage = 'Usage: client.search(arrayOfQueries[, callback])'; + + if (!isArray(queries)) { + throw new Error(usage); + } + + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } else if (opts === undefined) { + opts = {}; + } + + var client = this; + + var postObj = { + requests: map(queries, function prepareRequest(query) { + var params = ''; + + // allow query.query + // so we are mimicing the index.search(query, params) method + // {indexName:, query:, params:} + if (query.query !== undefined) { + params += 'query=' + encodeURIComponent(query.query); + } + + return { + indexName: query.indexName, + params: client._getSearchParams(query.params, params) + }; + }) + }; + + var JSONPParams = map(postObj.requests, function prepareJSONPParams(request, requestId) { + return requestId + '=' + + encodeURIComponent( + '/1/indexes/' + encodeURIComponent(request.indexName) + '?' + + request.params + ); + }).join('&'); + + var url = '/1/indexes/*/queries'; + + if (opts.strategy !== undefined) { + postObj.strategy = opts.strategy; + } + + return this._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url, + body: postObj, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/*', + body: { + params: JSONPParams + } + }, + callback: callback + }); +}; + +/** +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* This is the top-level API for SFFV. +* +* @param {object[]} queries An array of queries to run. +* @param {string} queries[].indexName Index name, name of the index to search. +* @param {object} queries[].params Query parameters. +* @param {string} queries[].params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} queries[].params.facetQuery Query for the facet search +* @param {string} [queries[].params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +*/ +AlgoliaSearchCore.prototype.searchForFacetValues = function(queries) { + var isArray = require(7); + var map = require(25); + + var usage = 'Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])'; // eslint-disable-line max-len + + if (!isArray(queries)) { + throw new Error(usage); + } + + var client = this; + + return client._promise.all(map(queries, function performQuery(query) { + if ( + !query || + query.indexName === undefined || + query.params.facetName === undefined || + query.params.facetQuery === undefined + ) { + throw new Error(usage); + } + + var clone = require(20); + var omit = require(27); + + var indexName = query.indexName; + var params = query.params; + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = client._getSearchParams(filteredParams, ''); + + return client._jsonRequest({ + cache: client.cache, + method: 'POST', + url: + '/1/indexes/' + + encodeURIComponent(indexName) + + '/facets/' + + encodeURIComponent(facetName) + + '/query', + hostType: 'read', + body: {params: searchParameters} + }); + })); +}; + +/** + * Set the extra security tagFilters header + * @param {string|array} tags The list of tags defining the current security filters + */ +AlgoliaSearchCore.prototype.setSecurityTags = function(tags) { + if (Object.prototype.toString.call(tags) === '[object Array]') { + var strTags = []; + for (var i = 0; i < tags.length; ++i) { + if (Object.prototype.toString.call(tags[i]) === '[object Array]') { + var oredTags = []; + for (var j = 0; j < tags[i].length; ++j) { + oredTags.push(tags[i][j]); + } + strTags.push('(' + oredTags.join(',') + ')'); + } else { + strTags.push(tags[i]); + } + } + tags = strTags.join(','); + } + + this.securityTags = tags; +}; + +/** + * Set the extra user token header + * @param {string} userToken The token identifying a uniq user (used to apply rate limits) + */ +AlgoliaSearchCore.prototype.setUserToken = function(userToken) { + this.userToken = userToken; +}; + +/** + * Clear all queries in client's cache + * @return undefined + */ +AlgoliaSearchCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/** +* Set the number of milliseconds a request can take before automatically being terminated. +* @deprecated +* @param {Number} milliseconds +*/ +AlgoliaSearchCore.prototype.setRequestTimeout = function(milliseconds) { + if (milliseconds) { + this._timeouts.connect = this._timeouts.read = this._timeouts.write = milliseconds; + } +}; + +/** +* Set the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.setTimeouts = function(timeouts) { + this._timeouts = timeouts; +}; + +/** +* Get the three different (connect, read, write) timeouts to be used when requesting +* @param {Object} timeouts +*/ +AlgoliaSearchCore.prototype.getTimeouts = function() { + return this._timeouts; +}; + +AlgoliaSearchCore.prototype._getAppIdData = function() { + var data = store.get(this.applicationID); + if (data !== null) this._cacheAppIdData(data); + return data; +}; + +AlgoliaSearchCore.prototype._setAppIdData = function(data) { + data.lastChange = (new Date()).getTime(); + this._cacheAppIdData(data); + return store.set(this.applicationID, data); +}; + +AlgoliaSearchCore.prototype._checkAppIdData = function() { + var data = this._getAppIdData(); + var now = (new Date()).getTime(); + if (data === null || now - data.lastChange > RESET_APP_DATA_TIMER) { + return this._resetInitialAppIdData(data); + } + + return data; +}; + +AlgoliaSearchCore.prototype._resetInitialAppIdData = function(data) { + var newData = data || {}; + newData.hostIndexes = {read: 0, write: 0}; + newData.timeoutMultiplier = 1; + newData.shuffleResult = newData.shuffleResult || shuffle([1, 2, 3]); + return this._setAppIdData(newData); +}; + +AlgoliaSearchCore.prototype._cacheAppIdData = function(data) { + this._hostIndexes = data.hostIndexes; + this._timeoutMultiplier = data.timeoutMultiplier; + this._shuffleResult = data.shuffleResult; +}; + +AlgoliaSearchCore.prototype._partialAppIdDataUpdate = function(newData) { + var foreach = require(4); + var currentData = this._getAppIdData(); + foreach(newData, function(value, key) { + currentData[key] = value; + }); + + return this._setAppIdData(currentData); +}; + +AlgoliaSearchCore.prototype._getHostByType = function(hostType) { + return this.hosts[hostType][this._getHostIndexByType(hostType)]; +}; + +AlgoliaSearchCore.prototype._getTimeoutMultiplier = function() { + return this._timeoutMultiplier; +}; + +AlgoliaSearchCore.prototype._getHostIndexByType = function(hostType) { + return this._hostIndexes[hostType]; +}; + +AlgoliaSearchCore.prototype._setHostIndexByType = function(hostIndex, hostType) { + var clone = require(20); + var newHostIndexes = clone(this._hostIndexes); + newHostIndexes[hostType] = hostIndex; + this._partialAppIdDataUpdate({hostIndexes: newHostIndexes}); + return hostIndex; +}; + +AlgoliaSearchCore.prototype._incrementHostIndex = function(hostType) { + return this._setHostIndexByType( + (this._getHostIndexByType(hostType) + 1) % this.hosts[hostType].length, hostType + ); +}; + +AlgoliaSearchCore.prototype._incrementTimeoutMultipler = function() { + var timeoutMultiplier = Math.max(this._timeoutMultiplier + 1, 4); + return this._partialAppIdDataUpdate({timeoutMultiplier: timeoutMultiplier}); +}; + +AlgoliaSearchCore.prototype._getTimeoutsForRequest = function(hostType) { + return { + connect: this._timeouts.connect * this._timeoutMultiplier, + complete: this._timeouts[hostType] * this._timeoutMultiplier + }; +}; + +function prepareHost(protocol) { + return function prepare(host) { + return protocol + '//' + host.toLowerCase(); + }; +} + +// Prototype.js < 1.7, a widely used library, defines a weird +// Array.prototype.toJSON function that will fail to stringify our content +// appropriately +// refs: +// - https://groups.google.com/forum/#!topic/prototype-core/E-SAVvV_V9Q +// - https://github.com/sstephenson/prototype/commit/038a2985a70593c1a86c230fadbdfe2e4898a48c +// - http://stackoverflow.com/a/3148441/147079 +function safeJSONStringify(obj) { + /* eslint no-extend-native:0 */ + + if (Array.prototype.toJSON === undefined) { + return JSON.stringify(obj); + } + + var toJSON = Array.prototype.toJSON; + delete Array.prototype.toJSON; + var out = JSON.stringify(obj); + Array.prototype.toJSON = toJSON; + + return out; +} + +function shuffle(array) { + var currentIndex = array.length; + var temporaryValue; + var randomIndex; + + // While there remain elements to shuffle... + while (currentIndex !== 0) { + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + + return array; +} + +function removeCredentials(headers) { + var newHeaders = {}; + + for (var headerName in headers) { + if (Object.prototype.hasOwnProperty.call(headers, headerName)) { + var value; + + if (headerName === 'x-algolia-api-key' || headerName === 'x-algolia-application-id') { + value = '**hidden for security purposes**'; + } else { + value = headers[headerName]; + } + + newHeaders[headerName] = value; + } + } + + return newHeaders; +} + +}).call(this,require(11)) +},{"1":1,"11":11,"14":14,"20":20,"23":23,"24":24,"25":25,"27":27,"29":29,"4":4,"7":7}],14:[function(require,module,exports){ +var buildSearchMethod = require(19); +var deprecate = require(21); +var deprecatedMessage = require(22); + +module.exports = IndexCore; + +/* +* Index class constructor. +* You should not use this method directly but use initIndex() function +*/ +function IndexCore(algoliasearch, indexName) { + this.indexName = indexName; + this.as = algoliasearch; + this.typeAheadArgs = null; + this.typeAheadValueOption = null; + + // make sure every index instance has it's own cache + this.cache = {}; +} + +/* +* Clear all queries in cache +*/ +IndexCore.prototype.clearCache = function() { + this.cache = {}; +}; + +/* +* Search inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the full text query +* @param {object} [args] (optional) if set, contains an object with query parameters: +* - page: (integer) Pagination parameter used to select the page to retrieve. +* Page is zero-based and defaults to 0. Thus, +* to retrieve the 10th page you need to set page=9 +* - hitsPerPage: (integer) Pagination parameter used to select the number of hits per page. Defaults to 20. +* - attributesToRetrieve: a string that contains the list of object attributes +* you want to retrieve (let you minimize the answer size). +* Attributes are separated with a comma (for example "name,address"). +* You can also use an array (for example ["name","address"]). +* By default, all attributes are retrieved. You can also use '*' to retrieve all +* values when an attributesToRetrieve setting is specified for your index. +* - attributesToHighlight: a string that contains the list of attributes you +* want to highlight according to the query. +* Attributes are separated by a comma. You can also use an array (for example ["name","address"]). +* If an attribute has no match for the query, the raw value is returned. +* By default all indexed text attributes are highlighted. +* You can use `*` if you want to highlight all textual attributes. +* Numerical attributes are not highlighted. +* A matchLevel is returned for each highlighted attribute and can contain: +* - full: if all the query terms were found in the attribute, +* - partial: if only some of the query terms were found, +* - none: if none of the query terms were found. +* - attributesToSnippet: a string that contains the list of attributes to snippet alongside +* the number of words to return (syntax is `attributeName:nbWords`). +* Attributes are separated by a comma (Example: attributesToSnippet=name:10,content:10). +* You can also use an array (Example: attributesToSnippet: ['name:10','content:10']). +* By default no snippet is computed. +* - minWordSizefor1Typo: the minimum number of characters in a query word to accept one typo in this word. +* Defaults to 3. +* - minWordSizefor2Typos: the minimum number of characters in a query word +* to accept two typos in this word. Defaults to 7. +* - getRankingInfo: if set to 1, the result hits will contain ranking +* information in _rankingInfo attribute. +* - aroundLatLng: search for entries around a given +* latitude/longitude (specified as two floats separated by a comma). +* For example aroundLatLng=47.316669,5.016670). +* You can specify the maximum distance in meters with the aroundRadius parameter (in meters) +* and the precision for ranking with aroundPrecision +* (for example if you set aroundPrecision=100, two objects that are distant of +* less than 100m will be considered as identical for "geo" ranking parameter). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - insideBoundingBox: search entries inside a given area defined by the two extreme points +* of a rectangle (defined by 4 floats: p1Lat,p1Lng,p2Lat,p2Lng). +* For example insideBoundingBox=47.3165,4.9665,47.3424,5.0201). +* At indexing, you should specify geoloc of an object with the _geoloc attribute +* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}}) +* - numericFilters: a string that contains the list of numeric filters you want to +* apply separated by a comma. +* The syntax of one filter is `attributeName` followed by `operand` followed by `value`. +* Supported operands are `<`, `<=`, `=`, `>` and `>=`. +* You can have multiple conditions on one attribute like for example numericFilters=price>100,price<1000. +* You can also use an array (for example numericFilters: ["price>100","price<1000"]). +* - tagFilters: filter the query by a set of tags. You can AND tags by separating them by commas. +* To OR tags, you must add parentheses. For example, tags=tag1,(tag2,tag3) means tag1 AND (tag2 OR tag3). +* You can also use an array, for example tagFilters: ["tag1",["tag2","tag3"]] +* means tag1 AND (tag2 OR tag3). +* At indexing, tags should be added in the _tags** attribute +* of objects (for example {"_tags":["tag1","tag2"]}). +* - facetFilters: filter the query by a list of facets. +* Facets are separated by commas and each facet is encoded as `attributeName:value`. +* For example: `facetFilters=category:Book,author:John%20Doe`. +* You can also use an array (for example `["category:Book","author:John%20Doe"]`). +* - facets: List of object attributes that you want to use for faceting. +* Comma separated list: `"category,author"` or array `['category','author']` +* Only attributes that have been added in **attributesForFaceting** index setting +* can be used in this parameter. +* You can also use `*` to perform faceting on all attributes specified in **attributesForFaceting**. +* - queryType: select how the query words are interpreted, it can be one of the following value: +* - prefixAll: all query words are interpreted as prefixes, +* - prefixLast: only the last word is interpreted as a prefix (default behavior), +* - prefixNone: no query word is interpreted as a prefix. This option is not recommended. +* - optionalWords: a string that contains the list of words that should +* be considered as optional when found in the query. +* Comma separated and array are accepted. +* - distinct: If set to 1, enable the distinct feature (disabled by default) +* if the attributeForDistinct index setting is set. +* This feature is similar to the SQL "distinct" keyword: when enabled +* in a query with the distinct=1 parameter, +* all hits containing a duplicate value for the attributeForDistinct attribute are removed from results. +* For example, if the chosen attribute is show_name and several hits have +* the same value for show_name, then only the best +* one is kept and others are removed. +* - restrictSearchableAttributes: List of attributes you want to use for +* textual search (must be a subset of the attributesToIndex index setting) +* either comma separated or as an array +* @param {function} [callback] the result callback called with two arguments: +* error: null or Error('message'). If false, the content contains the error. +* content: the server answer that contains the list of results. +*/ +IndexCore.prototype.search = buildSearchMethod('query'); + +/* +* -- BETA -- +* Search a record similar to the query inside the index using XMLHttpRequest request (Using a POST query to +* minimize number of OPTIONS queries: Cross-Origin Resource Sharing). +* +* @param {string} [query] the similar query +* @param {object} [args] (optional) if set, contains an object with query parameters. +* All search parameters are supported (see search function), restrictSearchableAttributes and facetFilters +* are the two most useful to restrict the similar results and get more relevant content +*/ +IndexCore.prototype.similarSearch = buildSearchMethod('similarQuery'); + +/* +* Browse index content. The response content will have a `cursor` property that you can use +* to browse subsequent pages for this query. Use `index.browseFrom(cursor)` when you want. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browse('cool songs', { +* tagFilters: 'public,comments', +* hitsPerPage: 500 +* }, callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browse = function(query, queryParameters, callback) { + var merge = require(26); + + var indexObj = this; + + var page; + var hitsPerPage; + + // we check variadic calls that are not the one defined + // .browse()/.browse(fn) + // => page = 0 + if (arguments.length === 0 || arguments.length === 1 && typeof arguments[0] === 'function') { + page = 0; + callback = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'number') { + // .browse(2)/.browse(2, 10)/.browse(2, fn)/.browse(2, 10, fn) + page = arguments[0]; + if (typeof arguments[1] === 'number') { + hitsPerPage = arguments[1]; + } else if (typeof arguments[1] === 'function') { + callback = arguments[1]; + hitsPerPage = undefined; + } + query = undefined; + queryParameters = undefined; + } else if (typeof arguments[0] === 'object') { + // .browse(queryParameters)/.browse(queryParameters, cb) + if (typeof arguments[1] === 'function') { + callback = arguments[1]; + } + queryParameters = arguments[0]; + query = undefined; + } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') { + // .browse(query, cb) + callback = arguments[1]; + queryParameters = undefined; + } + + // otherwise it's a .browse(query)/.browse(query, queryParameters)/.browse(query, queryParameters, cb) + + // get search query parameters combining various possible calls + // to .browse(); + queryParameters = merge({}, queryParameters || {}, { + page: page, + hitsPerPage: hitsPerPage, + query: query + }); + + var params = this.as._getSearchParams(queryParameters, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse', + body: {params: params}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Continue browsing from a previous position (cursor), obtained via a call to `.browse()`. +* +* @param {string} query - The full text query +* @param {Object} [queryParameters] - Any search query parameter +* @param {Function} [callback] - The result callback called with two arguments +* error: null or Error('message') +* content: the server answer with the browse result +* @return {Promise|undefined} Returns a promise if no callback given +* @example +* index.browseFrom('14lkfsakl32', callback); +* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} +*/ +IndexCore.prototype.browseFrom = function(cursor, callback) { + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/browse', + body: {cursor: cursor}, + hostType: 'read', + callback: callback + }); +}; + +/* +* Search for facet values +* https://www.algolia.com/doc/rest-api/search#search-for-facet-values +* +* @param {string} params.facetName Facet name, name of the attribute to search for values in. +* Must be declared as a facet +* @param {string} params.facetQuery Query for the facet search +* @param {string} [params.*] Any search parameter of Algolia, +* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters +* Pagination is not supported. The page and hitsPerPage parameters will be ignored. +* @param callback (optional) +*/ +IndexCore.prototype.searchForFacetValues = function(params, callback) { + var clone = require(20); + var omit = require(27); + var usage = 'Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])'; + + if (params.facetName === undefined || params.facetQuery === undefined) { + throw new Error(usage); + } + + var facetName = params.facetName; + var filteredParams = omit(clone(params), function(keyName) { + return keyName === 'facetName'; + }); + var searchParameters = this.as._getSearchParams(filteredParams, ''); + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/' + + encodeURIComponent(this.indexName) + '/facets/' + encodeURIComponent(facetName) + '/query', + hostType: 'read', + body: {params: searchParameters}, + callback: callback + }); +}; + +IndexCore.prototype.searchFacet = deprecate(function(params, callback) { + return this.searchForFacetValues(params, callback); +}, deprecatedMessage( + 'index.searchFacet(params[, callback])', + 'index.searchForFacetValues(params[, callback])' +)); + +IndexCore.prototype._search = function(params, url, callback, additionalUA) { + return this.as._jsonRequest({ + cache: this.cache, + method: 'POST', + url: url || '/1/indexes/' + encodeURIComponent(this.indexName) + '/query', + body: {params: params}, + hostType: 'read', + fallback: { + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(this.indexName), + body: {params: params} + }, + callback: callback, + additionalUA: additionalUA + }); +}; + +/* +* Get an object from this index +* +* @param objectID the unique identifier of the object to retrieve +* @param attrs (optional) if set, contains the array of attribute names to retrieve +* @param callback (optional) the result callback called with two arguments +* error: null or Error('message') +* content: the object to retrieve or the error message if a failure occured +*/ +IndexCore.prototype.getObject = function(objectID, attrs, callback) { + var indexObj = this; + + if (arguments.length === 1 || typeof attrs === 'function') { + callback = attrs; + attrs = undefined; + } + + var params = ''; + if (attrs !== undefined) { + params = '?attributes='; + for (var i = 0; i < attrs.length; ++i) { + if (i !== 0) { + params += ','; + } + params += attrs[i]; + } + } + + return this.as._jsonRequest({ + method: 'GET', + url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID) + params, + hostType: 'read', + callback: callback + }); +}; + +/* +* Get several objects from this index +* +* @param objectIDs the array of unique identifier of objects to retrieve +*/ +IndexCore.prototype.getObjects = function(objectIDs, attributesToRetrieve, callback) { + var isArray = require(7); + var map = require(25); + + var usage = 'Usage: index.getObjects(arrayOfObjectIDs[, callback])'; + + if (!isArray(objectIDs)) { + throw new Error(usage); + } + + var indexObj = this; + + if (arguments.length === 1 || typeof attributesToRetrieve === 'function') { + callback = attributesToRetrieve; + attributesToRetrieve = undefined; + } + + var body = { + requests: map(objectIDs, function prepareRequest(objectID) { + var request = { + indexName: indexObj.indexName, + objectID: objectID + }; + + if (attributesToRetrieve) { + request.attributesToRetrieve = attributesToRetrieve.join(','); + } + + return request; + }) + }; + + return this.as._jsonRequest({ + method: 'POST', + url: '/1/indexes/*/objects', + hostType: 'read', + body: body, + callback: callback + }); +}; + +IndexCore.prototype.as = null; +IndexCore.prototype.indexName = null; +IndexCore.prototype.typeAheadArgs = null; +IndexCore.prototype.typeAheadValueOption = null; + +},{"19":19,"20":20,"21":21,"22":22,"25":25,"26":26,"27":27,"7":7}],15:[function(require,module,exports){ +'use strict'; + +var AlgoliaSearchCore = require(13); +var createAlgoliasearch = require(16); + +module.exports = createAlgoliasearch(AlgoliaSearchCore, '(lite) '); + +},{"13":13,"16":16}],16:[function(require,module,exports){ +(function (process){ +'use strict'; + +var global = require(5); +var Promise = global.Promise || require(3).Promise; + +// This is the standalone browser build entry point +// Browser implementation of the Algolia Search JavaScript client, +// using XMLHttpRequest, XDomainRequest and JSONP as fallback +module.exports = function createAlgoliasearch(AlgoliaSearch, uaSuffix) { + var inherits = require(6); + var errors = require(23); + var inlineHeaders = require(17); + var jsonpRequest = require(18); + var places = require(28); + uaSuffix = uaSuffix || ''; + + if (process.env.NODE_ENV === 'debug') { + require(1).enable('algoliasearch*'); + } + + function algoliasearch(applicationID, apiKey, opts) { + var cloneDeep = require(20); + + opts = cloneDeep(opts || {}); + + opts._ua = opts._ua || algoliasearch.ua; + + return new AlgoliaSearchBrowser(applicationID, apiKey, opts); + } + + algoliasearch.version = require(30); + algoliasearch.ua = 'Algolia for vanilla JavaScript ' + uaSuffix + algoliasearch.version; + algoliasearch.initPlaces = places(algoliasearch); + + // we expose into window no matter how we are used, this will allow + // us to easily debug any website running algolia + global.__algolia = { + debug: require(1), + algoliasearch: algoliasearch + }; + + var support = { + hasXMLHttpRequest: 'XMLHttpRequest' in global, + hasXDomainRequest: 'XDomainRequest' in global + }; + + if (support.hasXMLHttpRequest) { + support.cors = 'withCredentials' in new XMLHttpRequest(); + } + + function AlgoliaSearchBrowser() { + // call AlgoliaSearch constructor + AlgoliaSearch.apply(this, arguments); + } + + inherits(AlgoliaSearchBrowser, AlgoliaSearch); + + AlgoliaSearchBrowser.prototype._request = function request(url, opts) { + return new Promise(function wrapRequest(resolve, reject) { + // no cors or XDomainRequest, no request + if (!support.cors && !support.hasXDomainRequest) { + // very old browser, not supported + reject(new errors.Network('CORS not supported')); + return; + } + + url = inlineHeaders(url, opts.headers); + + var body = opts.body; + var req = support.cors ? new XMLHttpRequest() : new XDomainRequest(); + var reqTimeout; + var timedOut; + var connected = false; + + reqTimeout = setTimeout(onTimeout, opts.timeouts.connect); + // we set an empty onprogress listener + // so that XDomainRequest on IE9 is not aborted + // refs: + // - https://github.com/algolia/algoliasearch-client-js/issues/76 + // - https://social.msdn.microsoft.com/Forums/ie/en-US/30ef3add-767c-4436-b8a9-f1ca19b4812e/ie9-rtm-xdomainrequest-issued-requests-may-abort-if-all-event-handlers-not-specified?forum=iewebdevelopment + req.onprogress = onProgress; + if ('onreadystatechange' in req) req.onreadystatechange = onReadyStateChange; + req.onload = onLoad; + req.onerror = onError; + + // do not rely on default XHR async flag, as some analytics code like hotjar + // breaks it and set it to false by default + if (req instanceof XMLHttpRequest) { + req.open(opts.method, url, true); + + // The Analytics API never accepts Auth headers as query string + // this option exists specifically for them. + if (opts.forceAuthHeaders) { + req.setRequestHeader( + 'x-algolia-application-id', + opts.headers['x-algolia-application-id'] + ); + req.setRequestHeader( + 'x-algolia-api-key', + opts.headers['x-algolia-api-key'] + ); + } + } else { + req.open(opts.method, url); + } + + // headers are meant to be sent after open + if (support.cors) { + if (body) { + if (opts.method === 'POST') { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests + req.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); + } else { + req.setRequestHeader('content-type', 'application/json'); + } + } + req.setRequestHeader('accept', 'application/json'); + } + + if (body) { + req.send(body); + } else { + req.send(); + } + + // event object not received in IE8, at least + // but we do not use it, still important to note + function onLoad(/* event */) { + // When browser does not supports req.timeout, we can + // have both a load and timeout event, since handled by a dumb setTimeout + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + var out; + + try { + out = { + body: JSON.parse(req.responseText), + responseText: req.responseText, + statusCode: req.status, + // XDomainRequest does not have any response headers + headers: req.getAllResponseHeaders && req.getAllResponseHeaders() || {} + }; + } catch (e) { + out = new errors.UnparsableJSON({ + more: req.responseText + }); + } + + if (out instanceof errors.UnparsableJSON) { + reject(out); + } else { + resolve(out); + } + } + + function onError(event) { + if (timedOut) { + return; + } + + clearTimeout(reqTimeout); + + // error event is trigerred both with XDR/XHR on: + // - DNS error + // - unallowed cross domain request + reject( + new errors.Network({ + more: event + }) + ); + } + + function onTimeout() { + timedOut = true; + req.abort(); + + reject(new errors.RequestTimeout()); + } + + function onConnect() { + connected = true; + clearTimeout(reqTimeout); + reqTimeout = setTimeout(onTimeout, opts.timeouts.complete); + } + + function onProgress() { + if (!connected) onConnect(); + } + + function onReadyStateChange() { + if (!connected && req.readyState > 1) onConnect(); + } + }); + }; + + AlgoliaSearchBrowser.prototype._request.fallback = function requestFallback(url, opts) { + url = inlineHeaders(url, opts.headers); + + return new Promise(function wrapJsonpRequest(resolve, reject) { + jsonpRequest(url, opts, function jsonpRequestDone(err, content) { + if (err) { + reject(err); + return; + } + + resolve(content); + }); + }); + }; + + AlgoliaSearchBrowser.prototype._promise = { + reject: function rejectPromise(val) { + return Promise.reject(val); + }, + resolve: function resolvePromise(val) { + return Promise.resolve(val); + }, + delay: function delayPromise(ms) { + return new Promise(function resolveOnTimeout(resolve/* , reject*/) { + setTimeout(resolve, ms); + }); + }, + all: function all(promises) { + return Promise.all(promises); + } + }; + + return algoliasearch; +}; + +}).call(this,require(11)) +},{"1":1,"11":11,"17":17,"18":18,"20":20,"23":23,"28":28,"3":3,"30":30,"5":5,"6":6}],17:[function(require,module,exports){ +'use strict'; + +module.exports = inlineHeaders; + +var encode = require(12); + +function inlineHeaders(url, headers) { + if (/\?/.test(url)) { + url += '&'; + } else { + url += '?'; + } + + return url + encode(headers); +} + +},{"12":12}],18:[function(require,module,exports){ +'use strict'; + +module.exports = jsonpRequest; + +var errors = require(23); + +var JSONPCounter = 0; + +function jsonpRequest(url, opts, cb) { + if (opts.method !== 'GET') { + cb(new Error('Method ' + opts.method + ' ' + url + ' is not supported by JSONP.')); + return; + } + + opts.debug('JSONP: start'); + + var cbCalled = false; + var timedOut = false; + + JSONPCounter += 1; + var head = document.getElementsByTagName('head')[0]; + var script = document.createElement('script'); + var cbName = 'algoliaJSONP_' + JSONPCounter; + var done = false; + + window[cbName] = function(data) { + removeGlobals(); + + if (timedOut) { + opts.debug('JSONP: Late answer, ignoring'); + return; + } + + cbCalled = true; + + clean(); + + cb(null, { + body: data, + responseText: JSON.stringify(data)/* , + // We do not send the statusCode, there's no statusCode in JSONP, it will be + // computed using data.status && data.message like with XDR + statusCode*/ + }); + }; + + // add callback by hand + url += '&callback=' + cbName; + + // add body params manually + if (opts.jsonBody && opts.jsonBody.params) { + url += '&' + opts.jsonBody.params; + } + + var ontimeout = setTimeout(timeout, opts.timeouts.complete); + + // script onreadystatechange needed only for + // <= IE8 + // https://github.com/angular/angular.js/issues/4523 + script.onreadystatechange = readystatechange; + script.onload = success; + script.onerror = error; + + script.async = true; + script.defer = true; + script.src = url; + head.appendChild(script); + + function success() { + opts.debug('JSONP: success'); + + if (done || timedOut) { + return; + } + + done = true; + + // script loaded but did not call the fn => script loading error + if (!cbCalled) { + opts.debug('JSONP: Fail. Script loaded but did not call the callback'); + clean(); + cb(new errors.JSONPScriptFail()); + } + } + + function readystatechange() { + if (this.readyState === 'loaded' || this.readyState === 'complete') { + success(); + } + } + + function clean() { + clearTimeout(ontimeout); + script.onload = null; + script.onreadystatechange = null; + script.onerror = null; + head.removeChild(script); + } + + function removeGlobals() { + try { + delete window[cbName]; + delete window[cbName + '_loaded']; + } catch (e) { + window[cbName] = window[cbName + '_loaded'] = undefined; + } + } + + function timeout() { + opts.debug('JSONP: Script timeout'); + timedOut = true; + clean(); + cb(new errors.RequestTimeout()); + } + + function error() { + opts.debug('JSONP: Script error'); + + if (done || timedOut) { + return; + } + + clean(); + cb(new errors.JSONPScriptError()); + } +} + +},{"23":23}],19:[function(require,module,exports){ +module.exports = buildSearchMethod; + +var errors = require(23); + +/** + * Creates a search method to be used in clients + * @param {string} queryParam the name of the attribute used for the query + * @param {string} url the url + * @return {function} the search method + */ +function buildSearchMethod(queryParam, url) { + /** + * The search method. Prepares the data and send the query to Algolia. + * @param {string} query the string used for query search + * @param {object} args additional parameters to send with the search + * @param {function} [callback] the callback to be called with the client gets the answer + * @return {undefined|Promise} If the callback is not provided then this methods returns a Promise + */ + return function search(query, args, callback) { + // warn V2 users on how to search + if (typeof query === 'function' && typeof args === 'object' || + typeof callback === 'object') { + // .search(query, params, cb) + // .search(cb, params) + throw new errors.AlgoliaSearchError('index.search usage is index.search(query, params, cb)'); + } + + // Normalizing the function signature + if (arguments.length === 0 || typeof query === 'function') { + // Usage : .search(), .search(cb) + callback = query; + query = ''; + } else if (arguments.length === 1 || typeof args === 'function') { + // Usage : .search(query/args), .search(query, cb) + callback = args; + args = undefined; + } + // At this point we have 3 arguments with values + + // Usage : .search(args) // careful: typeof null === 'object' + if (typeof query === 'object' && query !== null) { + args = query; + query = undefined; + } else if (query === undefined || query === null) { // .search(undefined/null) + query = ''; + } + + var params = ''; + + if (query !== undefined) { + params += queryParam + '=' + encodeURIComponent(query); + } + + var additionalUA; + if (args !== undefined) { + if (args.additionalUA) { + additionalUA = args.additionalUA; + delete args.additionalUA; + } + // `_getSearchParams` will augment params, do not be fooled by the = versus += from previous if + params = this.as._getSearchParams(args, params); + } + + + return this._search(params, url, callback, additionalUA); + }; +} + +},{"23":23}],20:[function(require,module,exports){ +module.exports = function clone(obj) { + return JSON.parse(JSON.stringify(obj)); +}; + +},{}],21:[function(require,module,exports){ +module.exports = function deprecate(fn, message) { + var warned = false; + + function deprecated() { + if (!warned) { + /* eslint no-console:0 */ + console.warn(message); + warned = true; + } + + return fn.apply(this, arguments); + } + + return deprecated; +}; + +},{}],22:[function(require,module,exports){ +module.exports = function deprecatedMessage(previousUsage, newUsage) { + var githubAnchorLink = previousUsage.toLowerCase() + .replace(/[\.\(\)]/g, ''); + + return 'algoliasearch: `' + previousUsage + '` was replaced by `' + newUsage + + '`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#' + githubAnchorLink; +}; + +},{}],23:[function(require,module,exports){ +'use strict'; + +// This file hosts our error definitions +// We use custom error "types" so that we can act on them when we need it +// e.g.: if error instanceof errors.UnparsableJSON then.. + +var inherits = require(6); + +function AlgoliaSearchError(message, extraProperties) { + var forEach = require(4); + + var error = this; + + // try to get a stacktrace + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, this.constructor); + } else { + error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old'; + } + + this.name = 'AlgoliaSearchError'; + this.message = message || 'Unknown error'; + + if (extraProperties) { + forEach(extraProperties, function addToErrorObject(value, key) { + error[key] = value; + }); + } +} + +inherits(AlgoliaSearchError, Error); + +function createCustomError(name, message) { + function AlgoliaSearchCustomError() { + var args = Array.prototype.slice.call(arguments, 0); + + // custom message not set, use default + if (typeof args[0] !== 'string') { + args.unshift(message); + } + + AlgoliaSearchError.apply(this, args); + this.name = 'AlgoliaSearch' + name + 'Error'; + } + + inherits(AlgoliaSearchCustomError, AlgoliaSearchError); + + return AlgoliaSearchCustomError; +} + +// late exports to let various fn defs and inherits take place +module.exports = { + AlgoliaSearchError: AlgoliaSearchError, + UnparsableJSON: createCustomError( + 'UnparsableJSON', + 'Could not parse the incoming response as JSON, see err.more for details' + ), + RequestTimeout: createCustomError( + 'RequestTimeout', + 'Request timedout before getting a response' + ), + Network: createCustomError( + 'Network', + 'Network issue, see err.more for details' + ), + JSONPScriptFail: createCustomError( + 'JSONPScriptFail', + '<script> was loaded but did not call our provided callback' + ), + JSONPScriptError: createCustomError( + 'JSONPScriptError', + '<script> unable to load due to an `error` event on it' + ), + Unknown: createCustomError( + 'Unknown', + 'Unknown error occured' + ) +}; + +},{"4":4,"6":6}],24:[function(require,module,exports){ +// Parse cloud does not supports setTimeout +// We do not store a setTimeout reference in the client everytime +// We only fallback to a fake setTimeout when not available +// setTimeout cannot be override globally sadly +module.exports = function exitPromise(fn, _setTimeout) { + _setTimeout(fn, 0); +}; + +},{}],25:[function(require,module,exports){ +var foreach = require(4); + +module.exports = function map(arr, fn) { + var newArr = []; + foreach(arr, function(item, itemIndex) { + newArr.push(fn(item, itemIndex, arr)); + }); + return newArr; +}; + +},{"4":4}],26:[function(require,module,exports){ +var foreach = require(4); + +module.exports = function merge(destination/* , sources */) { + var sources = Array.prototype.slice.call(arguments); + + foreach(sources, function(source) { + for (var keyName in source) { + if (source.hasOwnProperty(keyName)) { + if (typeof destination[keyName] === 'object' && typeof source[keyName] === 'object') { + destination[keyName] = merge({}, destination[keyName], source[keyName]); + } else if (source[keyName] !== undefined) { + destination[keyName] = source[keyName]; + } + } + } + }); + + return destination; +}; + +},{"4":4}],27:[function(require,module,exports){ +module.exports = function omit(obj, test) { + var keys = require(9); + var foreach = require(4); + + var filtered = {}; + + foreach(keys(obj), function doFilter(keyName) { + if (test(keyName) !== true) { + filtered[keyName] = obj[keyName]; + } + }); + + return filtered; +}; + +},{"4":4,"9":9}],28:[function(require,module,exports){ +module.exports = createPlacesClient; + +var buildSearchMethod = require(19); + +function createPlacesClient(algoliasearch) { + return function places(appID, apiKey, opts) { + var cloneDeep = require(20); + + opts = opts && cloneDeep(opts) || {}; + opts.hosts = opts.hosts || [ + 'places-dsn.algolia.net', + 'places-1.algolianet.com', + 'places-2.algolianet.com', + 'places-3.algolianet.com' + ]; + + // allow initPlaces() no arguments => community rate limited + if (arguments.length === 0 || typeof appID === 'object' || appID === undefined) { + appID = ''; + apiKey = ''; + opts._allowEmptyCredentials = true; + } + + var client = algoliasearch(appID, apiKey, opts); + var index = client.initIndex('places'); + index.search = buildSearchMethod('query', '/1/places/query'); + index.getObject = function(objectID, callback) { + return this.as._jsonRequest({ + method: 'GET', + url: '/1/places/' + encodeURIComponent(objectID), + hostType: 'read', + callback: callback + }); + }; + return index; + }; +} + +},{"19":19,"20":20}],29:[function(require,module,exports){ +(function (global){ +var debug = require(1)('algoliasearch:src/hostIndexState.js'); +var localStorageNamespace = 'algoliasearch-client-js'; + +var store; +var moduleStore = { + state: {}, + set: function(key, data) { + this.state[key] = data; + return this.state[key]; + }, + get: function(key) { + return this.state[key] || null; + } +}; + +var localStorageStore = { + set: function(key, data) { + moduleStore.set(key, data); // always replicate localStorageStore to moduleStore in case of failure + + try { + var namespace = JSON.parse(global.localStorage[localStorageNamespace]); + namespace[key] = data; + global.localStorage[localStorageNamespace] = JSON.stringify(namespace); + return namespace[key]; + } catch (e) { + return localStorageFailure(key, e); + } + }, + get: function(key) { + try { + return JSON.parse(global.localStorage[localStorageNamespace])[key] || null; + } catch (e) { + return localStorageFailure(key, e); + } + } +}; + +function localStorageFailure(key, e) { + debug('localStorage failed with', e); + cleanup(); + store = moduleStore; + return store.get(key); +} + +store = supportsLocalStorage() ? localStorageStore : moduleStore; + +module.exports = { + get: getOrSet, + set: getOrSet, + supportsLocalStorage: supportsLocalStorage +}; + +function getOrSet(key, data) { + if (arguments.length === 1) { + return store.get(key); + } + + return store.set(key, data); +} + +function supportsLocalStorage() { + try { + if ('localStorage' in global && + global.localStorage !== null) { + if (!global.localStorage[localStorageNamespace]) { + // actual creation of the namespace + global.localStorage.setItem(localStorageNamespace, JSON.stringify({})); + } + return true; + } + + return false; + } catch (_) { + return false; + } +} + +// In case of any error on localStorage, we clean our own namespace, this should handle +// quota errors when a lot of keys + data are used +function cleanup() { + try { + global.localStorage.removeItem(localStorageNamespace); + } catch (_) { + // nothing to do + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"1":1}],30:[function(require,module,exports){ +'use strict'; + +module.exports = '3.30.0'; + +},{}]},{},[15])(15) +});
\ No newline at end of file diff --git a/node_modules/algoliasearch/dist/algoliasearchLite.min.js b/node_modules/algoliasearch/dist/algoliasearchLite.min.js new file mode 100644 index 00000000..d87f4fd4 --- /dev/null +++ b/node_modules/algoliasearch/dist/algoliasearchLite.min.js @@ -0,0 +1,3 @@ +/*! algoliasearch 3.30.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.algoliasearch=e()}}(function(){var e;return function t(e,r,o){function n(a,s){if(!r[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=r[a]={exports:{}};e[a][0].call(l.exports,function(t){var r=e[a][1][t];return n(r?r:t)},l,l.exports,t,e,r,o)}return r[a].exports}for(var i="function"==typeof require&&require,a=0;a<o.length;a++)n(o[a]);return n}({1:[function(e,t,r){(function(o){function n(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function i(e){var t=this.useColors;if(e[0]=(t?"%c":"")+this.namespace+(t?" %c":" ")+e[0]+(t?"%c ":" ")+"+"+r.humanize(this.diff),t){var o="color: "+this.color;e.splice(1,0,o,"color: inherit");var n=0,i=0;e[0].replace(/%[a-zA-Z%]/g,function(e){"%%"!==e&&(n++,"%c"===e&&(i=n))}),e.splice(i,0,o)}}function a(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function s(e){try{null==e?r.storage.removeItem("debug"):r.storage.debug=e}catch(t){}}function u(){var e;try{e=r.storage.debug}catch(t){}return!e&&"undefined"!=typeof o&&"env"in o&&(e=o.env.DEBUG),e}function c(){try{return window.localStorage}catch(e){}}r=t.exports=e(2),r.log=a,r.formatArgs=i,r.save=s,r.load=u,r.useColors=n,r.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:c(),r.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],r.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},r.enable(u())}).call(this,e(11))},{11:11,2:2}],2:[function(e,t,r){function o(e){var t,o=0;for(t in e)o=(o<<5)-o+e.charCodeAt(t),o|=0;return r.colors[Math.abs(o)%r.colors.length]}function n(e){function t(){if(t.enabled){var e=t,o=+new Date,n=o-(c||o);e.diff=n,e.prev=c,e.curr=o,c=o;for(var i=new Array(arguments.length),a=0;a<i.length;a++)i[a]=arguments[a];i[0]=r.coerce(i[0]),"string"!=typeof i[0]&&i.unshift("%O");var s=0;i[0]=i[0].replace(/%([a-zA-Z%])/g,function(t,o){if("%%"===t)return t;s++;var n=r.formatters[o];if("function"==typeof n){var a=i[s];t=n.call(e,a),i.splice(s,1),s--}return t}),r.formatArgs.call(e,i);var u=t.log||r.log||console.log.bind(console);u.apply(e,i)}}return t.namespace=e,t.enabled=r.enabled(e),t.useColors=r.useColors(),t.color=o(e),"function"==typeof r.init&&r.init(t),t}function i(e){r.save(e),r.names=[],r.skips=[];for(var t=("string"==typeof e?e:"").split(/[\s,]+/),o=t.length,n=0;n<o;n++)t[n]&&(e=t[n].replace(/\*/g,".*?"),"-"===e[0]?r.skips.push(new RegExp("^"+e.substr(1)+"$")):r.names.push(new RegExp("^"+e+"$")))}function a(){r.enable("")}function s(e){var t,o;for(t=0,o=r.skips.length;t<o;t++)if(r.skips[t].test(e))return!1;for(t=0,o=r.names.length;t<o;t++)if(r.names[t].test(e))return!0;return!1}function u(e){return e instanceof Error?e.stack||e.message:e}r=t.exports=n.debug=n["default"]=n,r.coerce=u,r.disable=a,r.enable=i,r.enabled=s,r.humanize=e(8),r.names=[],r.skips=[],r.formatters={};var c},{8:8}],3:[function(t,r,o){(function(n,i){!function(t,n){"object"==typeof o&&"undefined"!=typeof r?r.exports=n():"function"==typeof e&&e.amd?e(n):t.ES6Promise=n()}(this,function(){"use strict";function e(e){var t=typeof e;return null!==e&&("object"===t||"function"===t)}function r(e){return"function"==typeof e}function o(e){Q=e}function a(e){Y=e}function s(){return function(){return n.nextTick(f)}}function u(){return"undefined"!=typeof G?function(){G(f)}:p()}function c(){var e=0,t=new Z(f),r=document.createTextNode("");return t.observe(r,{characterData:!0}),function(){r.data=e=++e%2}}function l(){var e=new MessageChannel;return e.port1.onmessage=f,function(){return e.port2.postMessage(0)}}function p(){var e=setTimeout;return function(){return e(f,1)}}function f(){for(var e=0;e<V;e+=2){var t=re[e],r=re[e+1];t(r),re[e]=void 0,re[e+1]=void 0}V=0}function d(){try{var e=t,r=e("vertx");return G=r.runOnLoop||r.runOnContext,u()}catch(o){return p()}}function h(e,t){var r=arguments,o=this,n=new this.constructor(m);void 0===n[ne]&&P(n);var i=o._state;return i?!function(){var e=r[i-1];Y(function(){return q(i,n,e,o._result)})}():k(o,n,e,t),n}function y(e){var t=this;if(e&&"object"==typeof e&&e.constructor===t)return e;var r=new t(m);return S(r,e),r}function m(){}function g(){return new TypeError("You cannot resolve a promise with itself")}function v(){return new TypeError("A promises callback cannot return that same promise.")}function b(e){try{return e.then}catch(t){return ue.error=t,ue}}function w(e,t,r,o){try{e.call(t,r,o)}catch(n){return n}}function _(e,t,r){Y(function(e){var o=!1,n=w(r,t,function(r){o||(o=!0,t!==r?S(e,r):j(e,r))},function(t){o||(o=!0,O(e,t))},"Settle: "+(e._label||" unknown promise"));!o&&n&&(o=!0,O(e,n))},e)}function x(e,t){t._state===ae?j(e,t._result):t._state===se?O(e,t._result):k(t,void 0,function(t){return S(e,t)},function(t){return O(e,t)})}function T(e,t,o){t.constructor===e.constructor&&o===h&&t.constructor.resolve===y?x(e,t):o===ue?(O(e,ue.error),ue.error=null):void 0===o?j(e,t):r(o)?_(e,t,o):j(e,t)}function S(t,r){t===r?O(t,g()):e(r)?T(t,r,b(r)):j(t,r)}function A(e){e._onerror&&e._onerror(e._result),R(e)}function j(e,t){e._state===ie&&(e._result=t,e._state=ae,0!==e._subscribers.length&&Y(R,e))}function O(e,t){e._state===ie&&(e._state=se,e._result=t,Y(A,e))}function k(e,t,r,o){var n=e._subscribers,i=n.length;e._onerror=null,n[i]=t,n[i+ae]=r,n[i+se]=o,0===i&&e._state&&Y(R,e)}function R(e){var t=e._subscribers,r=e._state;if(0!==t.length){for(var o=void 0,n=void 0,i=e._result,a=0;a<t.length;a+=3)o=t[a],n=t[a+r],o?q(r,o,n,i):n(i);e._subscribers.length=0}}function C(){this.error=null}function I(e,t){try{return e(t)}catch(r){return ce.error=r,ce}}function q(e,t,o,n){var i=r(o),a=void 0,s=void 0,u=void 0,c=void 0;if(i){if(a=I(o,n),a===ce?(c=!0,s=a.error,a.error=null):u=!0,t===a)return void O(t,v())}else a=n,u=!0;t._state!==ie||(i&&u?S(t,a):c?O(t,s):e===ae?j(t,a):e===se&&O(t,a))}function N(e,t){try{t(function(t){S(e,t)},function(t){O(e,t)})}catch(r){O(e,r)}}function E(){return le++}function P(e){e[ne]=le++,e._state=void 0,e._result=void 0,e._subscribers=[]}function U(e,t){this._instanceConstructor=e,this.promise=new e(m),this.promise[ne]||P(this.promise),K(t)?(this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0===this.length?j(this.promise,this._result):(this.length=this.length||0,this._enumerate(t),0===this._remaining&&j(this.promise,this._result))):O(this.promise,D())}function D(){return new Error("Array Methods must be provided an Array")}function H(e){return new U(this,e).promise}function J(e){var t=this;return new t(K(e)?function(r,o){for(var n=e.length,i=0;i<n;i++)t.resolve(e[i]).then(r,o)}:function(e,t){return t(new TypeError("You must pass an array to race."))})}function M(e){var t=this,r=new t(m);return O(r,e),r}function F(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function $(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function L(e){this[ne]=E(),this._result=this._state=void 0,this._subscribers=[],m!==e&&("function"!=typeof e&&F(),this instanceof L?N(this,e):$())}function B(){var e=void 0;if("undefined"!=typeof i)e=i;else if("undefined"!=typeof self)e=self;else try{e=Function("return this")()}catch(t){throw new Error("polyfill failed because global object is unavailable in this environment")}var r=e.Promise;if(r){var o=null;try{o=Object.prototype.toString.call(r.resolve())}catch(t){}if("[object Promise]"===o&&!r.cast)return}e.Promise=L}var X=void 0;X=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var K=X,V=0,G=void 0,Q=void 0,Y=function(e,t){re[V]=e,re[V+1]=t,V+=2,2===V&&(Q?Q(f):oe())},z="undefined"!=typeof window?window:void 0,W=z||{},Z=W.MutationObserver||W.WebKitMutationObserver,ee="undefined"==typeof self&&"undefined"!=typeof n&&"[object process]"==={}.toString.call(n),te="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,re=new Array(1e3),oe=void 0;oe=ee?s():Z?c():te?l():void 0===z&&"function"==typeof t?d():p();var ne=Math.random().toString(36).substring(16),ie=void 0,ae=1,se=2,ue=new C,ce=new C,le=0;return U.prototype._enumerate=function(e){for(var t=0;this._state===ie&&t<e.length;t++)this._eachEntry(e[t],t)},U.prototype._eachEntry=function(e,t){var r=this._instanceConstructor,o=r.resolve;if(o===y){var n=b(e);if(n===h&&e._state!==ie)this._settledAt(e._state,t,e._result);else if("function"!=typeof n)this._remaining--,this._result[t]=e;else if(r===L){var i=new r(m);T(i,e,n),this._willSettleAt(i,t)}else this._willSettleAt(new r(function(t){return t(e)}),t)}else this._willSettleAt(o(e),t)},U.prototype._settledAt=function(e,t,r){var o=this.promise;o._state===ie&&(this._remaining--,e===se?O(o,r):this._result[t]=r),0===this._remaining&&j(o,this._result)},U.prototype._willSettleAt=function(e,t){var r=this;k(e,void 0,function(e){return r._settledAt(ae,t,e)},function(e){return r._settledAt(se,t,e)})},L.all=H,L.race=J,L.resolve=y,L.reject=M,L._setScheduler=o,L._setAsap=a,L._asap=Y,L.prototype={constructor:L,then:h,"catch":function(e){return this.then(null,e)}},L.polyfill=B,L.Promise=L,L})}).call(this,t(11),"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{11:11}],4:[function(e,t,r){var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString;t.exports=function(e,t,r){if("[object Function]"!==n.call(t))throw new TypeError("iterator must be a function");var i=e.length;if(i===+i)for(var a=0;a<i;a++)t.call(r,e[a],a,e);else for(var s in e)o.call(e,s)&&t.call(r,e[s],s,e)}},{}],5:[function(e,t,r){(function(e){var r;r="undefined"!=typeof window?window:"undefined"!=typeof e?e:"undefined"!=typeof self?self:{},t.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],6:[function(e,t,r){"function"==typeof Object.create?t.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}},{}],7:[function(e,t,r){var o={}.toString;t.exports=Array.isArray||function(e){return"[object Array]"==o.call(e)}},{}],8:[function(e,t,r){function o(e){if(e=String(e),!(e.length>100)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var r=parseFloat(t[1]),o=(t[2]||"ms").toLowerCase();switch(o){case"years":case"year":case"yrs":case"yr":case"y":return r*p;case"days":case"day":case"d":return r*l;case"hours":case"hour":case"hrs":case"hr":case"h":return r*c;case"minutes":case"minute":case"mins":case"min":case"m":return r*u;case"seconds":case"second":case"secs":case"sec":case"s":return r*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function n(e){return e>=l?Math.round(e/l)+"d":e>=c?Math.round(e/c)+"h":e>=u?Math.round(e/u)+"m":e>=s?Math.round(e/s)+"s":e+"ms"}function i(e){return a(e,l,"day")||a(e,c,"hour")||a(e,u,"minute")||a(e,s,"second")||e+" ms"}function a(e,t,r){if(!(e<t))return e<1.5*t?Math.floor(e/t)+" "+r:Math.ceil(e/t)+" "+r+"s"}var s=1e3,u=60*s,c=60*u,l=24*c,p=365.25*l;t.exports=function(e,t){t=t||{};var r=typeof e;if("string"===r&&e.length>0)return o(e);if("number"===r&&isNaN(e)===!1)return t["long"]?i(e):n(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],9:[function(e,t,r){"use strict";var o=Object.prototype.hasOwnProperty,n=Object.prototype.toString,i=Array.prototype.slice,a=e(10),s=Object.prototype.propertyIsEnumerable,u=!s.call({toString:null},"toString"),c=s.call(function(){},"prototype"),l=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],p=function(e){var t=e.constructor;return t&&t.prototype===e},f={$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},d=function(){if("undefined"==typeof window)return!1;for(var e in window)try{if(!f["$"+e]&&o.call(window,e)&&null!==window[e]&&"object"==typeof window[e])try{p(window[e])}catch(t){return!0}}catch(t){return!0}return!1}(),h=function(e){if("undefined"==typeof window||!d)return p(e);try{return p(e)}catch(t){return!1}},y=function(e){var t=null!==e&&"object"==typeof e,r="[object Function]"===n.call(e),i=a(e),s=t&&"[object String]"===n.call(e),p=[];if(!t&&!r&&!i)throw new TypeError("Object.keys called on a non-object");var f=c&&r;if(s&&e.length>0&&!o.call(e,0))for(var d=0;d<e.length;++d)p.push(String(d));if(i&&e.length>0)for(var y=0;y<e.length;++y)p.push(String(y));else for(var m in e)f&&"prototype"===m||!o.call(e,m)||p.push(String(m));if(u)for(var g=h(e),v=0;v<l.length;++v)g&&"constructor"===l[v]||!o.call(e,l[v])||p.push(l[v]);return p};y.shim=function(){if(Object.keys){var e=function(){return 2===(Object.keys(arguments)||"").length}(1,2);if(!e){var t=Object.keys;Object.keys=function(e){return t(a(e)?i.call(e):e)}}}else Object.keys=y;return Object.keys||y},t.exports=y},{10:10}],10:[function(e,t,r){"use strict";var o=Object.prototype.toString;t.exports=function(e){var t=o.call(e),r="[object Arguments]"===t;return r||(r="[object Array]"!==t&&null!==e&&"object"==typeof e&&"number"==typeof e.length&&e.length>=0&&"[object Function]"===o.call(e.callee)),r}},{}],11:[function(e,t,r){function o(){throw new Error("setTimeout has not been defined")}function n(){throw new Error("clearTimeout has not been defined")}function i(e){if(p===setTimeout)return setTimeout(e,0);if((p===o||!p)&&setTimeout)return p=setTimeout,setTimeout(e,0);try{return p(e,0)}catch(t){try{return p.call(null,e,0)}catch(t){return p.call(this,e,0)}}}function a(e){if(f===clearTimeout)return clearTimeout(e);if((f===n||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(e);try{return f(e)}catch(t){try{return f.call(null,e)}catch(t){return f.call(this,e)}}}function s(){m&&h&&(m=!1,h.length?y=h.concat(y):g=-1,y.length&&u())}function u(){if(!m){var e=i(s);m=!0;for(var t=y.length;t;){for(h=y,y=[];++g<t;)h&&h[g].run();g=-1,t=y.length}h=null,m=!1,a(e)}}function c(e,t){this.fun=e,this.array=t}function l(){}var p,f,d=t.exports={};!function(){try{p="function"==typeof setTimeout?setTimeout:o}catch(e){p=o}try{f="function"==typeof clearTimeout?clearTimeout:n}catch(e){f=n}}();var h,y=[],m=!1,g=-1;d.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var r=1;r<arguments.length;r++)t[r-1]=arguments[r];y.push(new c(e,t)),1!==y.length||m||i(u)},c.prototype.run=function(){this.fun.apply(null,this.array)},d.title="browser",d.browser=!0,d.env={},d.argv=[],d.version="",d.versions={},d.on=l,d.addListener=l,d.once=l,d.off=l,d.removeListener=l,d.removeAllListeners=l,d.emit=l,d.binding=function(e){throw new Error("process.binding is not supported")},d.cwd=function(){return"/"},d.chdir=function(e){throw new Error("process.chdir is not supported")},d.umask=function(){return 0}},{}],12:[function(e,t,r){"use strict";function o(e,t){if(e.map)return e.map(t);for(var r=[],o=0;o<e.length;o++)r.push(t(e[o],o));return r}var n=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};t.exports=function(e,t,r,s){return t=t||"&",r=r||"=",null===e&&(e=void 0),"object"==typeof e?o(a(e),function(a){var s=encodeURIComponent(n(a))+r;return i(e[a])?o(e[a],function(e){return s+encodeURIComponent(n(e))}).join(t):s+encodeURIComponent(n(e[a]))}).join(t):s?encodeURIComponent(n(s))+r+encodeURIComponent(n(e)):""};var i=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},a=Object.keys||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.push(r);return t}},{}],13:[function(e,t,r){(function(r){function o(t,r,o){var i=e(1)("algoliasearch"),a=e(20),s=e(7),c=e(25),l="Usage: algoliasearch(applicationID, apiKey, opts)";if(o._allowEmptyCredentials!==!0&&!t)throw new u.AlgoliaSearchError("Please provide an application ID. "+l);if(o._allowEmptyCredentials!==!0&&!r)throw new u.AlgoliaSearchError("Please provide an API key. "+l);this.applicationID=t,this.apiKey=r,this.hosts={read:[],write:[]},o=o||{},this._timeouts=o.timeouts||{connect:1e3,read:2e3,write:3e4},o.timeout&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=o.timeout);var p=o.protocol||"https:";if(/:$/.test(p)||(p+=":"),"http:"!==p&&"https:"!==p)throw new u.AlgoliaSearchError("protocol must be `http:` or `https:` (was `"+o.protocol+"`)");if(this._checkAppIdData(),o.hosts)s(o.hosts)?(this.hosts.read=a(o.hosts),this.hosts.write=a(o.hosts)):(this.hosts.read=a(o.hosts.read),this.hosts.write=a(o.hosts.write));else{var f=c(this._shuffleResult,function(e){return t+"-"+e+".algolianet.com"}),d=(o.dsn===!1?"":"-dsn")+".algolia.net";this.hosts.read=[this.applicationID+d].concat(f),this.hosts.write=[this.applicationID+".algolia.net"].concat(f)}this.hosts.read=c(this.hosts.read,n(p)),this.hosts.write=c(this.hosts.write,n(p)),this.extraHeaders={},this.cache=o._cache||{},this._ua=o._ua,this._useCache=!(void 0!==o._useCache&&!o._cache)||o._useCache,this._useRequestCache=this._useCache&&o._useRequestCache,this._useFallback=void 0===o.useFallback||o.useFallback,this._setTimeout=o._setTimeout,i("init done, %j",this)}function n(e){return function(t){return e+"//"+t.toLowerCase()}}function i(e){if(void 0===Array.prototype.toJSON)return JSON.stringify(e);var t=Array.prototype.toJSON;delete Array.prototype.toJSON;var r=JSON.stringify(e);return Array.prototype.toJSON=t,r}function a(e){for(var t,r,o=e.length;0!==o;)r=Math.floor(Math.random()*o),o-=1,t=e[o],e[o]=e[r],e[r]=t;return e}function s(e){var t={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){var o;o="x-algolia-api-key"===r||"x-algolia-application-id"===r?"**hidden for security purposes**":e[r],t[r]=o}return t}t.exports=o;var u=e(23),c=e(24),l=e(14),p=e(29),f=500,d=r.env.RESET_APP_DATA_TIMER&&parseInt(r.env.RESET_APP_DATA_TIMER,10)||12e4;o.prototype.initIndex=function(e){return new l(this,e)},o.prototype.setExtraHeader=function(e,t){this.extraHeaders[e.toLowerCase()]=t},o.prototype.getExtraHeader=function(e){return this.extraHeaders[e.toLowerCase()]},o.prototype.unsetExtraHeader=function(e){delete this.extraHeaders[e.toLowerCase()]},o.prototype.addAlgoliaAgent=function(e){this._ua.indexOf(";"+e)===-1&&(this._ua+=";"+e)},o.prototype._jsonRequest=function(t){function r(e,n){function c(e){var t=e&&e.body&&e.body.message&&e.body.status||e.statusCode||e&&e.body&&200;d("received response: statusCode: %s, computed statusCode: %d, headers: %j",e.statusCode,t,e.headers);var r=2===Math.floor(t/100),o=new Date;if(w.push({currentHost:A,headers:s(p),content:a||null,contentLength:void 0!==a?a.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:T,endTime:o,duration:o-T,statusCode:t}),r)return m._useCache&&!m._useRequestCache&&y&&(y[l]=e.responseText),{responseText:e.responseText,body:e.body};var i=4!==Math.floor(t/100);if(i)return g+=1,_();d("unrecoverable error");var c=new u.AlgoliaSearchError(e.body&&e.body.message,{debugData:w,statusCode:t});return m._promise.reject(c)}function f(e){d("error: %s, stack: %s",e.message,e.stack);var r=new Date;return w.push({currentHost:A,headers:s(p),content:a||null,contentLength:void 0!==a?a.length:null,method:n.method,timeouts:n.timeouts,url:n.url,startTime:T,endTime:r,duration:r-T}),e instanceof u.AlgoliaSearchError||(e=new u.Unknown(e&&e.message,e)),g+=1,e instanceof u.Unknown||e instanceof u.UnparsableJSON||g>=m.hosts[t.hostType].length&&(v||!b)?(e.debugData=w,m._promise.reject(e)):e instanceof u.RequestTimeout?x():_()}function _(){return d("retrying request"),m._incrementHostIndex(t.hostType),r(e,n)}function x(){return d("retrying request with higher timeout"),m._incrementHostIndex(t.hostType),m._incrementTimeoutMultipler(),n.timeouts=m._getTimeoutsForRequest(t.hostType),r(e,n)}m._checkAppIdData();var T=new Date;if(m._useCache&&!m._useRequestCache&&(l=t.url),m._useCache&&!m._useRequestCache&&a&&(l+="_body_"+n.body),o(!m._useRequestCache,y,l)){d("serving response from cache");var S=y[l];return m._promise.resolve({body:JSON.parse(S),responseText:S})}if(g>=m.hosts[t.hostType].length)return!b||v?(d("could not get any response"),m._promise.reject(new u.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue. Application id was: "+m.applicationID,{debugData:w}))):(d("switching to fallback"),g=0,n.method=t.fallback.method,n.url=t.fallback.url,n.jsonBody=t.fallback.body,n.jsonBody&&(n.body=i(n.jsonBody)),p=m._computeRequestHeaders({additionalUA:h,headers:t.headers}),n.timeouts=m._getTimeoutsForRequest(t.hostType),m._setHostIndexByType(0,t.hostType),v=!0,r(m._request.fallback,n));var A=m._getHostByType(t.hostType),j=A+n.url,O={body:n.body,jsonBody:n.jsonBody,method:n.method,headers:p,timeouts:n.timeouts,debug:d,forceAuthHeaders:n.forceAuthHeaders};return d("method: %s, url: %s, headers: %j, timeouts: %d",O.method,j,O.headers,O.timeouts),e===m._request.fallback&&d("using fallback"),e.call(m,j,O).then(c,f)}function o(e,t,r){return m._useCache&&e&&t&&void 0!==t[r]}function n(e,r){return o(m._useRequestCache,y,l)&&e["catch"](function(){delete y[l]}),"function"!=typeof t.callback?e.then(r):void e.then(function(e){c(function(){t.callback(null,r(e))},m._setTimeout||setTimeout)},function(e){c(function(){t.callback(e)},m._setTimeout||setTimeout)})}this._checkAppIdData();var a,l,p,d=e(1)("algoliasearch:"+t.url),h=t.additionalUA||"",y=t.cache,m=this,g=0,v=!1,b=m._useFallback&&m._request.fallback&&t.fallback;this.apiKey.length>f&&void 0!==t.body&&(void 0!==t.body.params||void 0!==t.body.requests)?(t.body.apiKey=this.apiKey,p=this._computeRequestHeaders({additionalUA:h,withApiKey:!1,headers:t.headers})):p=this._computeRequestHeaders({additionalUA:h,headers:t.headers}),void 0!==t.body&&(a=i(t.body)),d("request start");var w=[];if(m._useCache&&m._useRequestCache&&(l=t.url),m._useCache&&m._useRequestCache&&a&&(l+="_body_"+a),o(m._useRequestCache,y,l)){d("serving request from cache");var _=y[l],x="function"!=typeof _.then?m._promise.resolve({responseText:_}):_;return n(x,function(e){return JSON.parse(e.responseText)})}var T=r(m._request,{url:t.url,method:t.method,body:a,jsonBody:t.body,timeouts:m._getTimeoutsForRequest(t.hostType),forceAuthHeaders:t.forceAuthHeaders});return m._useCache&&m._useRequestCache&&y&&(y[l]=T),n(T,function(e){return e.body})},o.prototype._getSearchParams=function(e,t){if(void 0===e||null===e)return t;for(var r in e)null!==r&&void 0!==e[r]&&e.hasOwnProperty(r)&&(t+=""===t?"":"&",t+=r+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(e[r])?i(e[r]):e[r]));return t},o.prototype._computeRequestHeaders=function(t){var r=e(4),o=t.additionalUA?this._ua+";"+t.additionalUA:this._ua,n={"x-algolia-agent":o,"x-algolia-application-id":this.applicationID};return t.withApiKey!==!1&&(n["x-algolia-api-key"]=this.apiKey),this.userToken&&(n["x-algolia-usertoken"]=this.userToken),this.securityTags&&(n["x-algolia-tagfilters"]=this.securityTags),r(this.extraHeaders,function(e,t){n[t]=e}),t.headers&&r(t.headers,function(e,t){n[t]=e}),n},o.prototype.search=function(t,r,o){var n=e(7),i=e(25),a="Usage: client.search(arrayOfQueries[, callback])";if(!n(t))throw new Error(a);"function"==typeof r?(o=r,r={}):void 0===r&&(r={});var s=this,u={requests:i(t,function(e){var t="";return void 0!==e.query&&(t+="query="+encodeURIComponent(e.query)),{indexName:e.indexName,params:s._getSearchParams(e.params,t)}})},c=i(u.requests,function(e,t){return t+"="+encodeURIComponent("/1/indexes/"+encodeURIComponent(e.indexName)+"?"+e.params)}).join("&"),l="/1/indexes/*/queries";return void 0!==r.strategy&&(u.strategy=r.strategy),this._jsonRequest({cache:this.cache,method:"POST",url:l,body:u,hostType:"read",fallback:{method:"GET",url:"/1/indexes/*",body:{params:c}},callback:o})},o.prototype.searchForFacetValues=function(t){var r=e(7),o=e(25),n="Usage: client.searchForFacetValues([{indexName, params: {facetName, facetQuery, ...params}}, ...queries])";if(!r(t))throw new Error(n);var i=this;return i._promise.all(o(t,function(t){if(!t||void 0===t.indexName||void 0===t.params.facetName||void 0===t.params.facetQuery)throw new Error(n);var r=e(20),o=e(27),a=t.indexName,s=t.params,u=s.facetName,c=o(r(s),function(e){return"facetName"===e}),l=i._getSearchParams(c,"");return i._jsonRequest({cache:i.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/facets/"+encodeURIComponent(u)+"/query",hostType:"read",body:{params:l}})}))},o.prototype.setSecurityTags=function(e){if("[object Array]"===Object.prototype.toString.call(e)){for(var t=[],r=0;r<e.length;++r)if("[object Array]"===Object.prototype.toString.call(e[r])){for(var o=[],n=0;n<e[r].length;++n)o.push(e[r][n]);t.push("("+o.join(",")+")")}else t.push(e[r]);e=t.join(",")}this.securityTags=e},o.prototype.setUserToken=function(e){this.userToken=e},o.prototype.clearCache=function(){this.cache={}},o.prototype.setRequestTimeout=function(e){e&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=e)},o.prototype.setTimeouts=function(e){this._timeouts=e},o.prototype.getTimeouts=function(){return this._timeouts},o.prototype._getAppIdData=function(){var e=p.get(this.applicationID);return null!==e&&this._cacheAppIdData(e),e},o.prototype._setAppIdData=function(e){return e.lastChange=(new Date).getTime(),this._cacheAppIdData(e),p.set(this.applicationID,e)},o.prototype._checkAppIdData=function(){var e=this._getAppIdData(),t=(new Date).getTime();return null===e||t-e.lastChange>d?this._resetInitialAppIdData(e):e},o.prototype._resetInitialAppIdData=function(e){var t=e||{};return t.hostIndexes={read:0,write:0},t.timeoutMultiplier=1,t.shuffleResult=t.shuffleResult||a([1,2,3]),this._setAppIdData(t)},o.prototype._cacheAppIdData=function(e){this._hostIndexes=e.hostIndexes,this._timeoutMultiplier=e.timeoutMultiplier,this._shuffleResult=e.shuffleResult},o.prototype._partialAppIdDataUpdate=function(t){var r=e(4),o=this._getAppIdData();return r(t,function(e,t){o[t]=e}),this._setAppIdData(o)},o.prototype._getHostByType=function(e){return this.hosts[e][this._getHostIndexByType(e)]},o.prototype._getTimeoutMultiplier=function(){return this._timeoutMultiplier},o.prototype._getHostIndexByType=function(e){return this._hostIndexes[e]},o.prototype._setHostIndexByType=function(t,r){var o=e(20),n=o(this._hostIndexes);return n[r]=t,this._partialAppIdDataUpdate({hostIndexes:n}),t},o.prototype._incrementHostIndex=function(e){return this._setHostIndexByType((this._getHostIndexByType(e)+1)%this.hosts[e].length,e)},o.prototype._incrementTimeoutMultipler=function(){var e=Math.max(this._timeoutMultiplier+1,4);return this._partialAppIdDataUpdate({timeoutMultiplier:e})},o.prototype._getTimeoutsForRequest=function(e){return{connect:this._timeouts.connect*this._timeoutMultiplier,complete:this._timeouts[e]*this._timeoutMultiplier}}}).call(this,e(11))},{1:1,11:11,14:14,20:20,23:23,24:24,25:25,27:27,29:29,4:4,7:7}],14:[function(e,t,r){function o(e,t){this.indexName=t,this.as=e,this.typeAheadArgs=null,this.typeAheadValueOption=null,this.cache={}}var n=e(19),i=e(21),a=e(22);t.exports=o,o.prototype.clearCache=function(){this.cache={}},o.prototype.search=n("query"),o.prototype.similarSearch=n("similarQuery"),o.prototype.browse=function(t,r,o){var n,i,a=e(26),s=this;0===arguments.length||1===arguments.length&&"function"==typeof arguments[0]?(n=0,o=arguments[0],t=void 0):"number"==typeof arguments[0]?(n=arguments[0],"number"==typeof arguments[1]?i=arguments[1]:"function"==typeof arguments[1]&&(o=arguments[1],i=void 0),t=void 0,r=void 0):"object"==typeof arguments[0]?("function"==typeof arguments[1]&&(o=arguments[1]),r=arguments[0],t=void 0):"string"==typeof arguments[0]&&"function"==typeof arguments[1]&&(o=arguments[1],r=void 0),r=a({},r||{},{page:n,hitsPerPage:i,query:t});var u=this.as._getSearchParams(r,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(s.indexName)+"/browse",body:{params:u},hostType:"read",callback:o})},o.prototype.browseFrom=function(e,t){return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/browse",body:{cursor:e},hostType:"read",callback:t})},o.prototype.searchForFacetValues=function(t,r){var o=e(20),n=e(27),i="Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])";if(void 0===t.facetName||void 0===t.facetQuery)throw new Error(i);var a=t.facetName,s=n(o(t),function(e){return"facetName"===e}),u=this.as._getSearchParams(s,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/facets/"+encodeURIComponent(a)+"/query",hostType:"read",body:{params:u},callback:r})},o.prototype.searchFacet=i(function(e,t){return this.searchForFacetValues(e,t)},a("index.searchFacet(params[, callback])","index.searchForFacetValues(params[, callback])")),o.prototype._search=function(e,t,r,o){return this.as._jsonRequest({cache:this.cache,method:"POST",url:t||"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:e},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:e}},callback:r,additionalUA:o})},o.prototype.getObject=function(e,t,r){var o=this;1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var n="";if(void 0!==t){n="?attributes=";for(var i=0;i<t.length;++i)0!==i&&(n+=","),n+=t[i]}return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(o.indexName)+"/"+encodeURIComponent(e)+n,hostType:"read",callback:r})},o.prototype.getObjects=function(t,r,o){var n=e(7),i=e(25),a="Usage: index.getObjects(arrayOfObjectIDs[, callback])";if(!n(t))throw new Error(a);var s=this;1!==arguments.length&&"function"!=typeof r||(o=r,r=void 0);var u={requests:i(t,function(e){var t={indexName:s.indexName,objectID:e};return r&&(t.attributesToRetrieve=r.join(",")),t})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/*/objects",hostType:"read",body:u,callback:o})},o.prototype.as=null,o.prototype.indexName=null,o.prototype.typeAheadArgs=null,o.prototype.typeAheadValueOption=null},{19:19,20:20,21:21,22:22,25:25,26:26,27:27,7:7}],15:[function(e,t,r){"use strict";var o=e(13),n=e(16);t.exports=n(o,"(lite) ")},{13:13,16:16}],16:[function(e,t,r){(function(r){"use strict";var o=e(5),n=o.Promise||e(3).Promise;t.exports=function(t,i){function a(t,r,o){var n=e(20);return o=n(o||{}),o._ua=o._ua||a.ua,new s(t,r,o)}function s(){t.apply(this,arguments)}var u=e(6),c=e(23),l=e(17),p=e(18),f=e(28);i=i||"","debug"===r.env.NODE_ENV&&e(1).enable("algoliasearch*"),a.version=e(30), +a.ua="Algolia for vanilla JavaScript "+i+a.version,a.initPlaces=f(a),o.__algolia={debug:e(1),algoliasearch:a};var d={hasXMLHttpRequest:"XMLHttpRequest"in o,hasXDomainRequest:"XDomainRequest"in o};return d.hasXMLHttpRequest&&(d.cors="withCredentials"in new XMLHttpRequest),u(s,t),s.prototype._request=function(e,t){return new n(function(r,o){function n(){if(!h){clearTimeout(f);var e;try{e={body:JSON.parse(m.responseText),responseText:m.responseText,statusCode:m.status,headers:m.getAllResponseHeaders&&m.getAllResponseHeaders()||{}}}catch(t){e=new c.UnparsableJSON({more:m.responseText})}e instanceof c.UnparsableJSON?o(e):r(e)}}function i(e){h||(clearTimeout(f),o(new c.Network({more:e})))}function a(){h=!0,m.abort(),o(new c.RequestTimeout)}function s(){g=!0,clearTimeout(f),f=setTimeout(a,t.timeouts.complete)}function u(){g||s()}function p(){!g&&m.readyState>1&&s()}if(!d.cors&&!d.hasXDomainRequest)return void o(new c.Network("CORS not supported"));e=l(e,t.headers);var f,h,y=t.body,m=d.cors?new XMLHttpRequest:new XDomainRequest,g=!1;f=setTimeout(a,t.timeouts.connect),m.onprogress=u,"onreadystatechange"in m&&(m.onreadystatechange=p),m.onload=n,m.onerror=i,m instanceof XMLHttpRequest?(m.open(t.method,e,!0),t.forceAuthHeaders&&(m.setRequestHeader("x-algolia-application-id",t.headers["x-algolia-application-id"]),m.setRequestHeader("x-algolia-api-key",t.headers["x-algolia-api-key"]))):m.open(t.method,e),d.cors&&(y&&("POST"===t.method?m.setRequestHeader("content-type","application/x-www-form-urlencoded"):m.setRequestHeader("content-type","application/json")),m.setRequestHeader("accept","application/json")),y?m.send(y):m.send()})},s.prototype._request.fallback=function(e,t){return e=l(e,t.headers),new n(function(r,o){p(e,t,function(e,t){return e?void o(e):void r(t)})})},s.prototype._promise={reject:function(e){return n.reject(e)},resolve:function(e){return n.resolve(e)},delay:function(e){return new n(function(t){setTimeout(t,e)})},all:function(e){return n.all(e)}},a}}).call(this,e(11))},{1:1,11:11,17:17,18:18,20:20,23:23,28:28,3:3,30:30,5:5,6:6}],17:[function(e,t,r){"use strict";function o(e,t){return e+=/\?/.test(e)?"&":"?",e+n(t)}t.exports=o;var n=e(12)},{12:12}],18:[function(e,t,r){"use strict";function o(e,t,r){function o(){t.debug("JSONP: success"),m||f||(m=!0,p||(t.debug("JSONP: Fail. Script loaded but did not call the callback"),s(),r(new n.JSONPScriptFail)))}function a(){"loaded"!==this.readyState&&"complete"!==this.readyState||o()}function s(){clearTimeout(g),h.onload=null,h.onreadystatechange=null,h.onerror=null,d.removeChild(h)}function u(){try{delete window[y],delete window[y+"_loaded"]}catch(e){window[y]=window[y+"_loaded"]=void 0}}function c(){t.debug("JSONP: Script timeout"),f=!0,s(),r(new n.RequestTimeout)}function l(){t.debug("JSONP: Script error"),m||f||(s(),r(new n.JSONPScriptError))}if("GET"!==t.method)return void r(new Error("Method "+t.method+" "+e+" is not supported by JSONP."));t.debug("JSONP: start");var p=!1,f=!1;i+=1;var d=document.getElementsByTagName("head")[0],h=document.createElement("script"),y="algoliaJSONP_"+i,m=!1;window[y]=function(e){return u(),f?void t.debug("JSONP: Late answer, ignoring"):(p=!0,s(),void r(null,{body:e,responseText:JSON.stringify(e)}))},e+="&callback="+y,t.jsonBody&&t.jsonBody.params&&(e+="&"+t.jsonBody.params);var g=setTimeout(c,t.timeouts.complete);h.onreadystatechange=a,h.onload=o,h.onerror=l,h.async=!0,h.defer=!0,h.src=e,d.appendChild(h)}t.exports=o;var n=e(23),i=0},{23:23}],19:[function(e,t,r){function o(e,t){return function(r,o,i){if("function"==typeof r&&"object"==typeof o||"object"==typeof i)throw new n.AlgoliaSearchError("index.search usage is index.search(query, params, cb)");0===arguments.length||"function"==typeof r?(i=r,r=""):1!==arguments.length&&"function"!=typeof o||(i=o,o=void 0),"object"==typeof r&&null!==r?(o=r,r=void 0):void 0!==r&&null!==r||(r="");var a="";void 0!==r&&(a+=e+"="+encodeURIComponent(r));var s;return void 0!==o&&(o.additionalUA&&(s=o.additionalUA,delete o.additionalUA),a=this.as._getSearchParams(o,a)),this._search(a,t,i,s)}}t.exports=o;var n=e(23)},{23:23}],20:[function(e,t,r){t.exports=function(e){return JSON.parse(JSON.stringify(e))}},{}],21:[function(e,t,r){t.exports=function(e,t){function r(){return o||(console.warn(t),o=!0),e.apply(this,arguments)}var o=!1;return r}},{}],22:[function(e,t,r){t.exports=function(e,t){var r=e.toLowerCase().replace(/[\.\(\)]/g,"");return"algoliasearch: `"+e+"` was replaced by `"+t+"`. Please see https://github.com/algolia/algoliasearch-client-javascript/wiki/Deprecated#"+r}},{}],23:[function(e,t,r){"use strict";function o(t,r){var o=e(4),n=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):n.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name="AlgoliaSearchError",this.message=t||"Unknown error",r&&o(r,function(e,t){n[t]=e})}function n(e,t){function r(){var r=Array.prototype.slice.call(arguments,0);"string"!=typeof r[0]&&r.unshift(t),o.apply(this,r),this.name="AlgoliaSearch"+e+"Error"}return i(r,o),r}var i=e(6);i(o,Error),t.exports={AlgoliaSearchError:o,UnparsableJSON:n("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:n("RequestTimeout","Request timedout before getting a response"),Network:n("Network","Network issue, see err.more for details"),JSONPScriptFail:n("JSONPScriptFail","<script> was loaded but did not call our provided callback"),JSONPScriptError:n("JSONPScriptError","<script> unable to load due to an `error` event on it"),Unknown:n("Unknown","Unknown error occured")}},{4:4,6:6}],24:[function(e,t,r){t.exports=function(e,t){t(e,0)}},{}],25:[function(e,t,r){var o=e(4);t.exports=function(e,t){var r=[];return o(e,function(o,n){r.push(t(o,n,e))}),r}},{4:4}],26:[function(e,t,r){var o=e(4);t.exports=function n(e){var t=Array.prototype.slice.call(arguments);return o(t,function(t){for(var r in t)t.hasOwnProperty(r)&&("object"==typeof e[r]&&"object"==typeof t[r]?e[r]=n({},e[r],t[r]):void 0!==t[r]&&(e[r]=t[r]))}),e}},{4:4}],27:[function(e,t,r){t.exports=function(t,r){var o=e(9),n=e(4),i={};return n(o(t),function(e){r(e)!==!0&&(i[e]=t[e])}),i}},{4:4,9:9}],28:[function(e,t,r){function o(t){return function(r,o,i){var a=e(20);i=i&&a(i)||{},i.hosts=i.hosts||["places-dsn.algolia.net","places-1.algolianet.com","places-2.algolianet.com","places-3.algolianet.com"],0!==arguments.length&&"object"!=typeof r&&void 0!==r||(r="",o="",i._allowEmptyCredentials=!0);var s=t(r,o,i),u=s.initIndex("places");return u.search=n("query","/1/places/query"),u.getObject=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/places/"+encodeURIComponent(e),hostType:"read",callback:t})},u}}t.exports=o;var n=e(19)},{19:19,20:20}],29:[function(e,t,r){(function(r){function o(e,t){return u("localStorage failed with",t),a(),s=l,s.get(e)}function n(e,t){return 1===arguments.length?s.get(e):s.set(e,t)}function i(){try{return"localStorage"in r&&null!==r.localStorage&&(r.localStorage[c]||r.localStorage.setItem(c,JSON.stringify({})),!0)}catch(e){return!1}}function a(){try{r.localStorage.removeItem(c)}catch(e){}}var s,u=e(1)("algoliasearch:src/hostIndexState.js"),c="algoliasearch-client-js",l={state:{},set:function(e,t){return this.state[e]=t,this.state[e]},get:function(e){return this.state[e]||null}},p={set:function(e,t){l.set(e,t);try{var n=JSON.parse(r.localStorage[c]);return n[e]=t,r.localStorage[c]=JSON.stringify(n),n[e]}catch(i){return o(e,i)}},get:function(e){try{return JSON.parse(r.localStorage[c])[e]||null}catch(t){return o(e,t)}}};s=i()?p:l,t.exports={get:n,set:n,supportsLocalStorage:i}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],30:[function(e,t,r){"use strict";t.exports="3.30.0"},{}]},{},[15])(15)}); |
