algoliasearch-rails 1.12.0 → 1.12.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,37 +1,75 @@
1
- /*! algoliasearch 3.0.3 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */
2
- (function(m){var l;"undefined"!==typeof window?l=window:"undefined"!==typeof self&&(l=self);l.ALGOLIA_MIGRATION_LAYER=m()})(function(){return function l(n,k,e){function h(a,c){if(!k[a]){if(!n[a]){var d="function"==typeof require&&require;if(!c&&d)return d(a,!0);if(g)return g(a,!0);d=Error("Cannot find module '"+a+"'");throw d.code="MODULE_NOT_FOUND",d;}d=k[a]={exports:{}};n[a][0].call(d.exports,function(c){var d=n[a][1][c];return h(d?d:c)},d,d.exports,l,n,k,e)}return k[a].exports}for(var g="function"==
3
- typeof require&&require,a=0;a<e.length;a++)h(e[a]);return h}({1:[function(l,n,k){function e(a,b){for(var c in b)a.setAttribute(c,b[c])}function h(a,b){a.onload=function(){this.onerror=this.onload=null;b(null,a)};a.onerror=function(){this.onerror=this.onload=null;b(Error("Failed to load "+this.src),a)}}function g(a,b){a.onreadystatechange=function(){if("complete"==this.readyState||"loaded"==this.readyState)this.onreadystatechange=null,b(null,a)}}n.exports=function(a,b,c){var d=document.head||document.getElementsByTagName("head")[0],
4
- f=document.createElement("script");"function"===typeof b&&(c=b,b={});b=b||{};c=c||function(){};f.type=b.type||"text/javascript";f.charset=b.charset||"utf8";f.async="async"in b?!!b.async:!0;f.src=a;b.attrs&&e(f,b.attrs);b.text&&(f.text=""+b.text);("onload"in f?h:g)(f,c);f.onload||h(f,c);d.appendChild(f)}},{}],2:[function(l,n,k){n.exports=function(e){e=new RegExp("cdn\\.jsdelivr\\.net/algoliasearch/latest/"+e.replace(".","\\.")+"(?:\\.min)?\\.js$");for(var h=document.getElementsByTagName("script"),
5
- g=!1,a=0,b=h.length;a<b;a++)if(h[a].src&&e.test(h[a].src)){g=!0;break}return g}},{}],3:[function(l,n,k){(function(e){function h(h){return function(){var a="AlgoliaSearch: loaded V2 script using "+h;e.console&&e.console.log&&e.console.log(a)}}n.exports=function(g){var a=l(1);g="//cdn.jsdelivr.net/algoliasearch/2/"+g+".min.js";e.console&&(e.console.warn?e.console.warn("-- 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 --"):
6
- e.console.log&&e.console.log("-- 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 --"));
7
- try{document.write("<script>window.ALGOLIA_SUPPORTS_DOCWRITE = true\x3c/script>"),!0===e.ALGOLIA_SUPPORTS_DOCWRITE?(document.write('<script src="'+g+'">\x3c/script>'),h("document.write")()):a(g,h("DOMElement"))}catch(b){a(g,h("DOMElement"))}}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{1:1}],4:[function(l,n,k){(function(e){n.exports=function(){e.AlgoliaSearch=function(){throw Error("-- 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 --");
8
- };e.AlgoliaSearchHelper=function(){throw Error("-- 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 --");};AlgoliaExplainResults=function(){throw Error("-- 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 --");
9
- }}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{}],5:[function(l,n,k){n=l(2);k=l(3);l=l(4);n("algoliasearch.jquery")?k("algoliasearch.jquery"):l()},{2:2,3:3,4:4}]},{},[5])(5)});
10
- (function e$$0(l,n,k){function e(a,b){if(!n[a]){if(!l[a]){var c="function"==typeof require&&require;if(!b&&c)return c(a,!0);if(h)return h(a,!0);c=Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c;}c=n[a]={exports:{}};l[a][0].call(c.exports,function(b){var c=l[a][1][b];return e(c?c:b)},c,c.exports,e$$0,l,n,k)}return n[a].exports}for(var h="function"==typeof require&&require,g=0;g<k.length;g++)e(k[g]);return e})({1:[function(m,l,n){function k(){if(!g){g=!0;for(var a,b=h.length;b;){a=
11
- h;h=[];for(var c=-1;++c<b;)a[c]();b=h.length}g=!1}}function e(){}m=l.exports={};var h=[],g=!1;m.nextTick=function(a){h.push(a);g||setTimeout(k,0)};m.title="browser";m.browser=!0;m.env={};m.argv=[];m.version="";m.versions={};m.on=e;m.addListener=e;m.once=e;m.off=e;m.removeListener=e;m.removeAllListeners=e;m.emit=e;m.binding=function(a){throw Error("process.binding is not supported");};m.cwd=function(){return"/"};m.chdir=function(a){throw Error("process.chdir is not supported");};m.umask=function(){return 0}},
12
- {}],2:[function(m,l,n){(function(k){function e(a,b,c,d){if(!a)throw Error("Please provide an application ID. Usage: algoliasearch(applicationID, apiKey, opts)");if(!b)throw Error("Please provide an API key. Usage: algoliasearch(applicationID, apiKey, opts)");c=c||{};void 0===c.timeout&&(c.timeout=2E3);void 0===c.protocol&&(c.protocol=document&&document.location.protocol||"http:");void 0===c.hosts&&(c.hosts=[]);void 0===c.tld&&(c.tld="net");/:$/.test(c.protocol)||(c.protocol+=":");0===c.hosts.length&&
13
- (c.hosts=g([a+"-1.algolia."+c.tld,a+"-2.algolia."+c.tld,a+"-3.algolia."+c.tld]),c.hosts.unshift(a+"-dsn.algolia."+c.tld));c.hosts=h(c.hosts,function(a){return c.protocol+"//"+a});this.applicationID=a;this.apiKey=b;this.hosts=c.hosts;this.currentHostIndex=0;this.requestTimeout=c.timeout;this.extraHeaders=[];this.cache={};this._request=d}function h(a,b){for(var c=[],d=0;d<a.length;++d)c.push(b(a[d],d));return c}function g(a){for(var b=a.length,c,d;0!==b;)d=Math.floor(Math.random()*b),--b,c=a[b],a[b]=
14
- a[d],a[d]=c;return a}l.exports=e;e.prototype={deleteIndex:function(a,b){return this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(a),callback:b})},moveIndex:function(a,b,c){b={operation:"move",destination:b};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:b,callback:c})},copyIndex:function(a,b,c){b={operation:"copy",destination:b};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:b,
15
- callback:c})},getLogs:function(a,b,c){if(0===arguments.length||"function"===typeof a)c=a,a=0,b=10;else if(1===arguments.length||"function"===typeof b)c=b,b=10;return this._jsonRequest({method:"GET",url:"/1/logs?offset="+a+"&length="+b,callback:c})},listIndexes:function(a,b){var c="";void 0===a||"function"===typeof a?b=a:c="?page="+a;return this._jsonRequest({method:"GET",url:"/1/indexes"+c,callback:b})},initIndex:function(a){return new this.Index(this,a)},listUserKeys:function(a){return this._jsonRequest({method:"GET",
16
- url:"/1/keys",callback:a})},getUserKeyACL:function(a,b){return this._jsonRequest({method:"GET",url:"/1/keys/"+a,callback:b})},deleteUserKey:function(a,b){return this._jsonRequest({method:"DELETE",url:"/1/keys/"+a,callback:b})},addUserKey:function(a,b){return this.addUserKeyWithValidity(a,{validity:0,maxQueriesPerIPPerHour:0,maxHitsPerQuery:0},b)},addUserKeyWithValidity:function(a,b,c){var d={};d.acl=a;d.validity=b.validity;d.maxQueriesPerIPPerHour=b.maxQueriesPerIPPerHour;d.maxHitsPerQuery=b.maxHitsPerQuery;
17
- return this._jsonRequest({method:"POST",url:"/1/keys",body:d,callback:c})},setSecurityTags:function(a){if("[object Array]"===Object.prototype.toString.call(a)){for(var b=[],c=0;c<a.length;++c)if("[object Array]"===Object.prototype.toString.call(a[c])){for(var d=[],f=0;f<a[c].length;++f)d.push(a[c][f]);b.push("("+d.join(",")+")")}else b.push(a[c]);a=b.join(",")}this.tagFilters=a},setUserToken:function(a){this.userToken=a},startQueriesBatch:function(){this.batch=[]},addQueryInBatch:function(a,b,c){b=
18
- "query="+encodeURIComponent(b);this._isUndefined(c)||null===c||(b=this._getSearchParams(c,b));this.batch.push({indexName:a,params:b})},clearCache:function(){this.cache={}},sendQueriesBatch:function(a){for(var b={requests:[]},c=0;c<this.batch.length;++c)b.requests.push(this.batch[c]);return this._sendQueriesBatch(b,a)},setRequestTimeout:function(a){a&&(this.requestTimeout=parseInt(a,10))},Index:function(a,b){this.indexName=b;this.as=a;this.typeAheadValueOption=this.typeAheadArgs=null;this.cache={}},
19
- setExtraHeader:function(a,b){this.extraHeaders.push({key:a,value:b})},_sendQueriesBatch:function(a,b){return this._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/*/queries",body:a,fallback:{method:"GET",url:"/1/indexes/*",body:{params:function(){for(var b="",d=0;d<a.requests.length;++d)var f="/1/indexes/"+encodeURIComponent(a.requests[d].indexName)+"?"+a.requests[d].params,b=b+(d+"="+encodeURIComponent(f)+"&");return b}()}},callback:b})},_jsonRequest:function(a){function b(h,g){function l(){f.currentHostIndex=
20
- ++f.currentHostIndex%f.hosts.length;e+=1;g.timeout=f.requestTimeout*(e+1);return b(h,g)}if(c&&void 0!==c[d])return f._request.resolve(c[d]);if(e>=f.hosts.length){if(!a.fallback||h===f._request.fallback)return f._request.reject(Error("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue."));e=0;g.method=a.fallback.method;g.url=a.fallback.url;g.body=a.fallback.body;g.timeout=f.requestTimeout*(e+1);f.currentHostIndex=0;f.forceFallback=!0;return b(f._request.fallback,
21
- g)}var k=g.url,k=k+((-1===k.indexOf("?")?"?":"&")+"X-Algolia-API-Key="+f.apiKey),k=k+("&X-Algolia-Application-Id="+f.applicationID);f.userToken&&(k+="&X-Algolia-UserToken="+encodeURIComponent(f.userToken));f.tagFilters&&(k+="&X-Algolia-TagFilters="+encodeURIComponent(f.tagFilters));for(var m=0;m<f.extraHeaders.length;++m)k+="&"+f.extraHeaders[m].key+"="+f.extraHeaders[m].value;return h(f.hosts[f.currentHostIndex]+k,{body:g.body,method:g.method,timeout:g.timeout}).then(function(a){if(a instanceof Error)return l();
22
- var b=a&&a.body&&a.body.message&&a.body.status||a.statusCode||a&&a.body&&200,e=200===b||201===b,b=!e&&4!==Math.floor(b/100)&&1!==Math.floor(b/100);e&&c&&(c[d]=a.body);return e?a.body:b?l():f._request.reject(Error(a.body&&a.body.message||"Unknown error"))},function(){f.forceFallback?(f.currentHostIndex=++f.currentHostIndex%f.hosts.length,e+=1):e=f.hosts.length;return b(h,g)})}var c=a.cache,d=a.url,f=this,e=0;void 0!==a.body&&(d+="_body_"+JSON.stringify(a.body));var h=f.forceFallback&&a.fallback,g=
23
- h?a.fallback:a,h=b(h?f._request.fallback:f._request,{url:g.url,method:g.method,body:g.body,timeout:f.requestTimeout*(e+1)});if(a.callback)h.then(function(b){k.nextTick(function(){a.callback(null,b)})},function(b){k.nextTick(function(){a.callback(b)})});else return h},_getSearchParams:function(a,b){if(this._isUndefined(a)||null===a)return b;for(var c in a)null!==c&&a.hasOwnProperty(c)&&(b+=""===b?"":"&",b+=c+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(a[c])?JSON.stringify(a[c]):
24
- a[c]));return b},_isUndefined:function(a){return void 0===a}};e.prototype.Index.prototype={clearCache:function(){this.cache={}},addObject:function(a,b,c){if(1===arguments.length||"function"===typeof b)c=b,b=void 0;return this.as._jsonRequest({method:void 0!==b?"PUT":"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+(void 0!==b?"/"+encodeURIComponent(b):""),body:a,callback:c})},addObjects:function(a,b){for(var c={requests:[]},d=0;d<a.length;++d)c.requests.push({action:"addObject",body:a[d]});
25
- return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/batch",body:c,callback:b})},getObject:function(a,b,c){if(1===arguments.length||"function"===typeof b)c=b,b=void 0;var d="";if(void 0!==b)for(var d="?attributes=",f=0;f<b.length;++f)0!==f&&(d+=","),d+=b[f];return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/"+encodeURIComponent(a)+d,callback:c})},partialUpdateObject:function(a,b){return this.as._jsonRequest({method:"POST",
26
- url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/"+encodeURIComponent(a.objectID)+"/partial",body:a,callback:b})},partialUpdateObjects:function(a,b){for(var c={requests:[]},d=0;d<a.length;++d)c.requests.push({action:"partialUpdateObject",objectID:a[d].objectID,body:a[d]});return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/batch",body:c,callback:b})},saveObject:function(a,b){return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+
27
- "/"+encodeURIComponent(a.objectID),body:a,callback:b})},saveObjects:function(a,b){for(var c={requests:[]},d=0;d<a.length;++d)c.requests.push({action:"updateObject",objectID:a[d].objectID,body:a[d]});return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/batch",body:c,callback:b})},deleteObject:function(a,b){if("function"===typeof a||"string"!==typeof a&&"number"!==typeof a){var c=Error("Cannot delete an object without an objectID");b=a;return"function"===
28
- typeof b?b(c):this.as._request.reject(c)}return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/"+encodeURIComponent(a),callback:b})},search:function(a,b,c){if(0===arguments.length||"function"===typeof a)c=a,a="";else if(1===arguments.length||"function"===typeof b)c=b,b=void 0;if("object"===typeof a&&null!==a)b=a,a=void 0;else if(void 0===a||null===a)a="";var d="";void 0!==a&&(d+="query="+encodeURIComponent(a));void 0!==b&&(d=this.as._getSearchParams(b,
29
- d));return this._search(d,c)},browse:function(a,b,c){if(1===arguments.length||"function"===typeof b)c=b,b=void 0;var d="?page="+a;this.as._isUndefined(b)||(d+="&hitsPerPage="+b);return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/browse"+d,callback:c})},ttAdapter:function(a){var b=this;return function(c,d){b.search(c,a,function(a,b){a?d(a):d(b.hits)})}},waitTask:function(a,b){var c=this,d=this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+
30
- "/task/"+a}).then(function(d){if("published"!==d.status)return(new c.as._request.delay(100)).then(function(){return c.waitTask(a,b)});if(b)k.nextTick(function(){b(null,d)});else return d},function(a){if(b)k.nextTick(function(){b(a)});else return a});if(!b)return d},clearIndex:function(a){return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/clear",callback:a})},getSettings:function(a){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+
31
- "/settings",callback:a})},setSettings:function(a,b){return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/settings",body:a,callback:b})},listUserKeys:function(a){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",callback:a})},getUserKeyACL:function(a,b){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+a,callback:b})},deleteUserKey:function(a,b){return this.as._jsonRequest({method:"DELETE",
32
- url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+a,callback:b})},addUserKey:function(a,b){var c={};c.acl=a;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",body:c,callback:b})},addUserKeyWithValidity:function(a,b,c){var d={};d.acl=a;d.validity=b.validity;d.maxQueriesPerIPPerHour=b.maxQueriesPerIPPerHour;d.maxHitsPerQuery=b.maxHitsPerQuery;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+
33
- "/keys",body:d,callback:c})},_search:function(a,b){return this.as._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:a},fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:a}},callback:b})},as:null,indexName:null,typeAheadArgs:null,typeAheadValueOption:null}}).call(this,m(1))},{1:1}],3:[function(m,l,n){(function(k){function e(b,c){return a.Deferred(function(d){var e=null;void 0!==c.body&&(e=JSON.stringify(c.body));
34
- a.ajax(b,{type:c.method,timeout:c.timeout,dataType:"json",data:e,complete:function(a,c){"timeout"===c?d.resolve(Error("Timeout - Could not connect to endpoint "+b)):0===a.status?d.reject(Error("Network error")):d.resolve({statusCode:a.status,body:a.responseJSON})}})}).promise()}var h=m(5),g=m(4),h=h(e),a=k.jQuery;a.algolia={Client:h};e.fallback=function(b,c){return a.Deferred(function(a){g(b,c,function(b,c){b?a.reject(b):a.resolve(c)})}).promise()};e.reject=function(b){return a.Deferred(function(a){a.reject(b)}).promise()};
35
- e.resolve=function(b){return a.Deferred(function(a){a.resolve(b)}).promise()};e.delay=function(b){return a.Deferred(function(a){setTimeout(function(){a.resolve()},b)}).promise()}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{4:4,5:5}],4:[function(m,l,n){l.exports=function(e,h,g){function a(){r||l||(r=!0,m||(c(),g(Error("Failed to load JSONP script"))))}function b(){"loaded"!==this.readyState&&"complete"!==this.readyState||a()}
36
- function c(){clearTimeout(t);p.onload=null;p.onreadystatechange=null;p.onerror=null;n.removeChild(p);try{delete window[q],delete window[q+"_loaded"]}catch(a){window[q]=null,window[q+"_loaded"]=null}}function d(){l=!0;c();g(Error("Timeout - Could not connect to endpoint "+e))}function f(){r||l||(c(),g(Error("Failed to load JSONP script")))}if("GET"!==h.method)g(Error("Method "+h.method+" "+e+" is not supported by JSONP."));else{var m=!1,l=!1;k+=1;var n=document.getElementsByTagName("head")[0],p=document.createElement("script"),
37
- q="algoliaJSONP_"+k,r=!1;window[q]=function(a){try{delete window[q]}catch(b){window[q]=void 0}l||(m=!0,c(),g(null,{body:a}))};e+="&callback="+q;h.body&&h.body.params&&(e+="&"+h.body.params);var t=setTimeout(d,h.timeout);p.onreadystatechange=b;p.onload=a;p.onerror=f;p.async=!0;p.defer=!0;p.src=e;n.appendChild(p)}};var k=0},{}],5:[function(m,l,n){l.exports=function(k){function e(e,g,a){return new (m(2))(e,g,a,k)}e.version="3.0.3";return e}},{2:2}]},{},[3]);
1
+ /*! algoliasearch 3.3.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */
2
+ (function(g){var h;"undefined"!==typeof window?h=window:"undefined"!==typeof self&&(h=self);h.ALGOLIA_MIGRATION_LAYER=g()})(function(){return function h(d,n,c){function b(f,p){if(!n[f]){if(!d[f]){var l="function"==typeof require&&require;if(!p&&l)return l(f,!0);if(k)return k(f,!0);l=Error("Cannot find module '"+f+"'");throw l.code="MODULE_NOT_FOUND",l;}l=n[f]={exports:{}};d[f][0].call(l.exports,function(c){var k=d[f][1][c];return b(k?k:c)},l,l.exports,h,d,n,c)}return n[f].exports}for(var k="function"==
3
+ typeof require&&require,f=0;f<c.length;f++)b(c[f]);return b}({1:[function(h,d,n){function c(f,b){for(var c in b)f.setAttribute(c,b[c])}function b(f,b){f.onload=function(){this.onerror=this.onload=null;b(null,f)};f.onerror=function(){this.onerror=this.onload=null;b(Error("Failed to load "+this.src),f)}}function k(f,b){f.onreadystatechange=function(){if("complete"==this.readyState||"loaded"==this.readyState)this.onreadystatechange=null,b(null,f)}}d.exports=function(f,d,p){var l=document.head||document.getElementsByTagName("head")[0],
4
+ q=document.createElement("script");"function"===typeof d&&(p=d,d={});d=d||{};p=p||function(){};q.type=d.type||"text/javascript";q.charset=d.charset||"utf8";q.async="async"in d?!!d.async:!0;q.src=f;d.attrs&&c(q,d.attrs);d.text&&(q.text=""+d.text);("onload"in q?b:k)(q,p);q.onload||b(q,p);l.appendChild(q)}},{}],2:[function(h,d,n){d.exports=function(c){c=new RegExp("cdn\\.jsdelivr\\.net/algoliasearch/latest/"+c.replace(".","\\.")+"(?:\\.min)?\\.js$");for(var b=document.getElementsByTagName("script"),
5
+ k=!1,f=0,d=b.length;f<d;f++)if(b[f].src&&c.test(b[f].src)){k=!0;break}return k}},{}],3:[function(h,d,n){(function(c){function b(b){return function(){var f="AlgoliaSearch: loaded V2 script using "+b;c.console&&c.console.log&&c.console.log(f)}}d.exports=function(k){var f=h(1);k="//cdn.jsdelivr.net/algoliasearch/2/"+k+".min.js";c.console&&(c.console.warn?c.console.warn("-- 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 --"):
6
+ c.console.log&&c.console.log("-- 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 --"));
7
+ try{document.write("<script>window.ALGOLIA_SUPPORTS_DOCWRITE = true\x3c/script>"),!0===c.ALGOLIA_SUPPORTS_DOCWRITE?(document.write('<script src="'+k+'">\x3c/script>'),b("document.write")()):f(k,b("DOMElement"))}catch(d){f(k,b("DOMElement"))}}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{1:1}],4:[function(h,d,n){(function(c){d.exports=function(){c.AlgoliaSearch=function(){throw Error("-- 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 --");
8
+ };c.AlgoliaSearchHelper=function(){throw Error("-- 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 --");};AlgoliaExplainResults=function(){throw Error("-- 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 --");
9
+ }}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{}],5:[function(h,d,n){d=h(2);n=h(3);h=h(4);d("algoliasearch.jquery")?n("algoliasearch.jquery"):h()},{2:2,3:3,4:4}]},{},[5])(5)});
10
+ (function e$$0(h,d,n){function c(f,k){if(!d[f]){if(!h[f]){var p="function"==typeof require&&require;if(!k&&p)return p(f,!0);if(b)return b(f,!0);p=Error("Cannot find module '"+f+"'");throw p.code="MODULE_NOT_FOUND",p;}p=d[f]={exports:{}};h[f][0].call(p.exports,function(b){var k=h[f][1][b];return c(k?k:b)},p,p.exports,e$$0,h,d,n)}return d[f].exports}for(var b="function"==typeof require&&require,k=0;k<n.length;k++)c(n[k]);return c})({1:[function(g,h,d){function n(){if(!k){k=!0;for(var f,c=b.length;c;){f=
11
+ b;b=[];for(var d=-1;++d<c;)f[d]();c=b.length}k=!1}}function c(){}g=h.exports={};var b=[],k=!1;g.nextTick=function(f){b.push(f);k||setTimeout(n,0)};g.title="browser";g.browser=!0;g.env={};g.argv=[];g.version="";g.versions={};g.on=c;g.addListener=c;g.once=c;g.off=c;g.removeListener=c;g.removeAllListeners=c;g.emit=c;g.binding=function(f){throw Error("process.binding is not supported");};g.cwd=function(){return"/"};g.chdir=function(f){throw Error("process.chdir is not supported");};g.umask=function(){return 0}},
12
+ {}],2:[function(g,h,d){h.exports=function(c,b,k,f){k=k||"=";var d={};if("string"!==typeof c||0===c.length)return d;var p=/\+/g;c=c.split(b||"&");b=1E3;f&&"number"===typeof f.maxKeys&&(b=f.maxKeys);f=c.length;0<b&&f>b&&(f=b);for(b=0;b<f;++b){var l=c[b].replace(p,"%20"),g=l.indexOf(k),h;0<=g?(h=l.substr(0,g),l=l.substr(g+1)):(h=l,l="");h=decodeURIComponent(h);l=decodeURIComponent(l);Object.prototype.hasOwnProperty.call(d,h)?n(d[h])?d[h].push(l):d[h]=[d[h],l]:d[h]=l}return d};var n=Array.isArray||function(c){return"[object Array]"===
13
+ Object.prototype.toString.call(c)}},{}],3:[function(g,h,d){function n(f,b){if(f.map)return f.map(b);for(var c=[],d=0;d<f.length;d++)c.push(b(f[d],d));return c}var c=function(f){switch(typeof f){case "string":return f;case "boolean":return f?"true":"false";case "number":return isFinite(f)?f:"";default:return""}};h.exports=function(f,d,g,l){d=d||"&";g=g||"=";null===f&&(f=void 0);return"object"===typeof f?n(k(f),function(k){var l=encodeURIComponent(c(k))+g;return b(f[k])?n(f[k],function(a){return l+
14
+ encodeURIComponent(c(a))}).join(d):l+encodeURIComponent(c(f[k]))}).join(d):l?encodeURIComponent(c(l))+g+encodeURIComponent(c(f)):""};var b=Array.isArray||function(f){return"[object Array]"===Object.prototype.toString.call(f)},k=Object.keys||function(f){var b=[],c;for(c in f)Object.prototype.hasOwnProperty.call(f,c)&&b.push(c);return b}},{}],4:[function(g,h,d){d.decode=d.parse=g(2);d.encode=d.stringify=g(3)},{2:2,3:3}],5:[function(g,h,d){function n(){var b;try{b=c.debug}catch(f){}return b}d=h.exports=
15
+ g(6);d.log=function(){return"object"===typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)};d.formatArgs=function(){var b=arguments,f=this.useColors;b[0]=(f?"%c":"")+this.namespace+(f?" %c":" ")+b[0]+(f?"%c ":" ")+"+"+d.humanize(this.diff);if(!f)return b;var f="color: "+this.color,b=[b[0],f,"color: inherit"].concat(Array.prototype.slice.call(b,1)),c=0,g=0;b[0].replace(/%[a-z%]/g,function(b){"%%"!==b&&(c++,"%c"===b&&(g=c))});b.splice(g,0,f);return b};d.save=function(b){try{null==
16
+ b?c.removeItem("debug"):c.debug=b}catch(f){}};d.load=n;d.useColors=function(){return"WebkitAppearance"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&31<=parseInt(RegExp.$1,10)};var c;if("undefined"!==typeof chrome&&"undefined"!==typeof chrome.storage)c=chrome.storage.local;else a:{try{c=window.localStorage;break a}catch(b){}c=void 0}d.colors="lightseagreen forestgreen goldenrod dodgerblue darkorchid crimson".split(" ");
17
+ d.formatters.j=function(b){return JSON.stringify(b)};d.enable(n())},{6:6}],6:[function(g,h,d){d=h.exports=function(b){function k(){}function f(){var b=+new Date;f.diff=b-(c||b);f.prev=c;c=f.curr=b;null==f.useColors&&(f.useColors=d.useColors());null==f.color&&f.useColors&&(f.color=d.colors[n++%d.colors.length]);var k=Array.prototype.slice.call(arguments);k[0]=d.coerce(k[0]);"string"!==typeof k[0]&&(k=["%o"].concat(k));var g=0;k[0]=k[0].replace(/%([a-z%])/g,function(b,a){if("%%"===b)return b;g++;var e=
18
+ d.formatters[a];"function"===typeof e&&(b=e.call(f,k[g]),k.splice(g,1),g--);return b});"function"===typeof d.formatArgs&&(k=d.formatArgs.apply(f,k));(f.log||d.log||console.log.bind(console)).apply(f,k)}k.enabled=!1;f.enabled=!0;var g=d.enabled(b)?f:k;g.namespace=b;return g};d.coerce=function(b){return b instanceof Error?b.stack||b.message:b};d.disable=function(){d.enable("")};d.enable=function(b){d.save(b);for(var c=(b||"").split(/[\s,]+/),f=c.length,g=0;g<f;g++)c[g]&&(b=c[g].replace(/\*/g,".*?"),
19
+ "-"===b[0]?d.skips.push(new RegExp("^"+b.substr(1)+"$")):d.names.push(new RegExp("^"+b+"$")))};d.enabled=function(b){var c,f;c=0;for(f=d.skips.length;c<f;c++)if(d.skips[c].test(b))return!1;c=0;for(f=d.names.length;c<f;c++)if(d.names[c].test(b))return!0;return!1};d.humanize=g(7);d.names=[];d.skips=[];d.formatters={};var n=0,c},{7:7}],7:[function(g,h,d){function n(b){if(b=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(b)){var c=
20
+ parseFloat(b[1]);switch((b[2]||"ms").toLowerCase()){case "years":case "year":case "yrs":case "yr":case "y":return 315576E5*c;case "days":case "day":case "d":return 864E5*c;case "hours":case "hour":case "hrs":case "hr":case "h":return 36E5*c;case "minutes":case "minute":case "mins":case "min":case "m":return 6E4*c;case "seconds":case "second":case "secs":case "sec":case "s":return 1E3*c;case "milliseconds":case "millisecond":case "msecs":case "msec":case "ms":return c}}}function c(b,c,f){if(!(b<c))return b<
21
+ 1.5*c?Math.floor(b/c)+" "+f:Math.ceil(b/c)+" "+f+"s"}h.exports=function(b,d){d=d||{};return"string"==typeof b?n(b):d.long?c(b,864E5,"day")||c(b,36E5,"hour")||c(b,6E4,"minute")||c(b,1E3,"second")||b+" ms":864E5<=b?Math.round(b/864E5)+"d":36E5<=b?Math.round(b/36E5)+"h":6E4<=b?Math.round(b/6E4)+"m":1E3<=b?Math.round(b/1E3)+"s":b+"ms"}},{}],8:[function(g,h,d){(function(d,c){(function(){function b(a){return"function"===typeof a}function g(){return function(){d.nextTick(l)}}function f(){var a=0,e=new I(l),
22
+ b=document.createTextNode("");e.observe(b,{characterData:!0});return function(){b.data=a=++a%2}}function t(){var a=new MessageChannel;a.port1.onmessage=l;return function(){a.port2.postMessage(0)}}function p(){return function(){setTimeout(l,1)}}function l(){for(var a=0;a<z;a+=2)(0,A[a])(A[a+1]),A[a]=void 0,A[a+1]=void 0;z=0}function q(){}function x(a,e,b,m){try{a.call(e,b,m)}catch(c){return c}}function a(a,e,b){B(function(a){var c=!1,f=x(b,e,function(b){c||(c=!0,e!==b?m(a,b):v(a,b))},function(e){c||
23
+ (c=!0,u(a,e))},"Settle: "+(a._label||" unknown promise"));!c&&f&&(c=!0,u(a,f))},a)}function e(a,e){1===e._state?v(a,e._result):2===a._state?u(a,e._result):C(e,void 0,function(e){m(a,e)},function(e){u(a,e)})}function m(m,c){if(m===c)u(m,new TypeError("You cannot resolve a promise with itself"));else if("function"===typeof c||"object"===typeof c&&null!==c)if(c.constructor===m.constructor)e(m,c);else{var f;try{f=c.then}catch(d){D.error=d,f=D}f===D?u(m,D.error):void 0===f?v(m,c):b(f)?a(m,c,f):v(m,c)}else v(m,
24
+ c)}function r(a){a._onerror&&a._onerror(a._result);F(a)}function v(a,e){void 0===a._state&&(a._result=e,a._state=1,0!==a._subscribers.length&&B(F,a))}function u(a,e){void 0===a._state&&(a._state=2,a._result=e,B(r,a))}function C(a,e,b,m){var c=a._subscribers,f=c.length;a._onerror=null;c[f]=e;c[f+1]=b;c[f+2]=m;0===f&&a._state&&B(F,a)}function F(a){var e=a._subscribers,b=a._state;if(0!==e.length){for(var m,c,f=a._result,d=0;d<e.length;d+=3)m=e[d],c=e[d+b],m?J(b,m,c,f):c(f);a._subscribers.length=0}}function K(){this.error=
25
+ null}function J(a,e,c,f){var d=b(c),r,g,k,h;if(d){try{r=c(f)}catch(l){G.error=l,r=G}r===G?(h=!0,g=r.error,r=null):k=!0;if(e===r){u(e,new TypeError("A promises callback cannot return that same promise."));return}}else r=f,k=!0;void 0===e._state&&(d&&k?m(e,r):h?u(e,g):1===a?v(e,r):2===a&&u(e,r))}function N(a,e){try{e(function(e){m(a,e)},function(e){u(a,e)})}catch(b){u(a,b)}}function w(a,e,b,m){this._instanceConstructor=a;this.promise=new a(q,m);this._abortOnReject=b;this._validateInput(e)?(this._input=
26
+ e,this._remaining=this.length=e.length,this._init(),0===this.length?v(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&v(this.promise,this._result))):u(this.promise,this._validationError())}function y(a){this._id=O++;this._result=this._state=void 0;this._subscribers=[];if(q!==a){if(!b(a))throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(!(this instanceof y))throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
27
+ N(this,a)}}var L=Array.isArray?Array.isArray:function(a){return"[object Array]"===Object.prototype.toString.call(a)},z=0,B=function(a,e){A[z]=a;A[z+1]=e;z+=2;2===z&&M()},E="undefined"!==typeof window?window:{},I=E.MutationObserver||E.WebKitMutationObserver,E="undefined"!==typeof Uint8ClampedArray&&"undefined"!==typeof importScripts&&"undefined"!==typeof MessageChannel,A=Array(1E3),M;M="undefined"!==typeof d&&"[object process]"==={}.toString.call(d)?g():I?f():E?t():p();var D=new K,G=new K;w.prototype._validateInput=
28
+ function(a){return L(a)};w.prototype._validationError=function(){return Error("Array Methods must be provided an Array")};w.prototype._init=function(){this._result=Array(this.length)};w.prototype._enumerate=function(){for(var a=this.length,e=this.promise,b=this._input,m=0;void 0===e._state&&m<a;m++)this._eachEntry(b[m],m)};w.prototype._eachEntry=function(a,e){var b=this._instanceConstructor;"object"===typeof a&&null!==a?a.constructor===b&&void 0!==a._state?(a._onerror=null,this._settledAt(a._state,
29
+ e,a._result)):this._willSettleAt(b.resolve(a),e):(this._remaining--,this._result[e]=this._makeResult(1,e,a))};w.prototype._settledAt=function(a,e,b){var m=this.promise;void 0===m._state&&(this._remaining--,this._abortOnReject&&2===a?u(m,b):this._result[e]=this._makeResult(a,e,b));0===this._remaining&&v(m,this._result)};w.prototype._makeResult=function(a,e,b){return b};w.prototype._willSettleAt=function(a,e){var b=this;C(a,void 0,function(a){b._settledAt(1,e,a)},function(a){b._settledAt(2,e,a)})};
30
+ var O=0;y.all=function(a,e){return(new w(this,a,!0,e)).promise};y.race=function(a,e){function b(a){m(f,a)}function c(a){u(f,a)}var f=new this(q,e);if(!L(a))return u(f,new TypeError("You must pass an array to race.")),f;for(var d=a.length,r=0;void 0===f._state&&r<d;r++)C(this.resolve(a[r]),void 0,b,c);return f};y.resolve=function(a,e){if(a&&"object"===typeof a&&a.constructor===this)return a;var b=new this(q,e);m(b,a);return b};y.reject=function(a,e){var b=new this(q,e);u(b,a);return b};y.prototype=
31
+ {constructor:y,then:function(a,e){var b=this._state;if(1===b&&!a||2===b&&!e)return this;var m=new this.constructor(q),c=this._result;if(b){var f=arguments[b-1];B(function(){J(b,m,f,c)})}else C(this,m,a,e);return m},"catch":function(a){return this.then(null,a)}};var H={Promise:y,polyfill:function(){var a;a="undefined"!==typeof c?c:"undefined"!==typeof window&&window.document?window:self;"Promise"in a&&"resolve"in a.Promise&&"reject"in a.Promise&&"all"in a.Promise&&"race"in a.Promise&&function(){var e;
32
+ new a.Promise(function(a){e=a});return b(e)}()||(a.Promise=y)}};"function"===typeof define&&define.amd?define(function(){return H}):"undefined"!==typeof h&&h.exports?h.exports=H:"undefined"!==typeof this&&(this.ES6Promise=H)}).call(this)}).call(this,g(1),"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{1:1}],9:[function(g,h,d){var n=Object.prototype.hasOwnProperty,c=Object.prototype.toString,b=g(10),k=function(b){if(!b||"[object Object]"!==
33
+ c.call(b))return!1;var d=n.call(b,"constructor"),g=b.constructor&&b.constructor.prototype&&n.call(b.constructor.prototype,"isPrototypeOf");if(b.constructor&&!d&&!g)return!1;for(var k in b);return void 0===k||n.call(b,k)};h.exports=function t(){var c,d,g,h,a,e=arguments[0],m=1,r=arguments.length,v=!1;if("boolean"===typeof e)v=e,e=arguments[1]||{},m=2;else if("object"!==typeof e&&"function"!==typeof e||null==e)e={};for(;m<r;++m)if(c=arguments[m],null!=c)for(d in c)g=e[d],h=c[d],e!==h&&(v&&h&&(k(h)||
34
+ (a=b(h)))?(a?(a=!1,g=g&&b(g)?g:[]):g=g&&k(g)?g:{},e[d]=t(v,g,h)):void 0!==h&&(e[d]=h));return e}},{10:10}],10:[function(g,h,d){h.exports=Array.isArray||function(d){return"[object Array]"==Object.prototype.toString.call(d)}},{}],11:[function(g,h,d){var n=Object.prototype.hasOwnProperty,c=Object.prototype.toString;h.exports=function(b,d,f){if("[object Function]"!==c.call(d))throw new TypeError("iterator must be a function");var g=b.length;if(g===+g)for(var h=0;h<g;h++)d.call(f,b[h],h,b);else for(h in b)n.call(b,
35
+ h)&&d.call(f,b[h],h,b)}},{}],12:[function(g,h,d){h.exports="function"===typeof Object.create?function(d,c){d.super_=c;d.prototype=Object.create(c.prototype,{constructor:{value:d,enumerable:!1,writable:!0,configurable:!0}})}:function(d,c){d.super_=c;var b=function(){};b.prototype=c.prototype;d.prototype=new b;d.prototype.constructor=d}},{}],13:[function(g,h,d){(function(d){function c(a,e,m){var c=g(9);if(!a)throw Error("algoliasearch: Please provide an application ID. Usage: algoliasearch(applicationID, apiKey, opts)");
36
+ if(!e)throw Error("algoliasearch: Please provide an API key. Usage: algoliasearch(applicationID, apiKey, opts)");this.applicationID=a;this.apiKey=e;a=[this.applicationID+"-1.algolianet.com",this.applicationID+"-2.algolianet.com",this.applicationID+"-3.algolianet.com"];this.hosts={read:[],write:[]};this.hostIndex={read:0,write:0};m=m||{};e=m.protocol||"https:";var f=void 0===m.timeout?2E3:m.timeout;/:$/.test(e)||(e+=":");if("http:"!==m.protocol&&"https:"!==m.protocol)throw Error("algoliasearch: protocol must be `http:` or `https:` (was `"+
37
+ m.protocol+"`)");m.hosts?(this.hosts.read=c([],m.hosts),this.hosts.write=c([],m.hosts)):(this.hosts.read=[this.applicationID+"-dsn.algolia.net"].concat(a),this.hosts.write=[this.applicationID+".algolia.net"].concat(a));this.hosts.read=b(this.hosts.read,k(e));this.hosts.write=b(this.hosts.write,k(e));this.requestTimeout=f;this.extraHeaders=[];this.cache={};this._ua=m._ua;this._useCache=void 0===m._useCache?!0:m._useCache;this._setTimeout=m._setTimeout;q("init done, %j",this)}function b(a,e){for(var b=
38
+ [],c=0;c<a.length;++c)b.push(e(a[c],c));return b}function k(a){return function(e){return a+"//"+e.toLowerCase()}}function f(){throw Error("algoliasearch: Not implemented in this environment.\nIf you feel this is a mistake, write to support@algolia.com");}function t(a,e){var b=a.toLowerCase().replace(".","").replace("()","");return"algoliasearch: `"+a+"` was replaced by `"+e+"`. Please see https://github.com/algolia/algoliasearch-client-js/wiki/Deprecated#"+b}function p(a,e){e(a,0)}function l(a,e){var b=
39
+ !1;return function(){b||(console.log(e),b=!0);return a.apply(this,arguments)}}h.exports=c;"development"===d.env.NODE_ENV&&g(5).enable("algoliasearch*");var q=g(5)("algoliasearch"),x=g(11);c.prototype={deleteIndex:function(a,e){return this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(a),hostType:"write",callback:e})},moveIndex:function(a,e,b){e={operation:"move",destination:e};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:e,
40
+ hostType:"write",callback:b})},copyIndex:function(a,e,b){e={operation:"copy",destination:e};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:e,hostType:"write",callback:b})},getLogs:function(a,e,b){if(0===arguments.length||"function"===typeof a)b=a,a=0,e=10;else if(1===arguments.length||"function"===typeof e)b=e,e=10;return this._jsonRequest({method:"GET",url:"/1/logs?offset="+a+"&length="+e,hostType:"read",callback:b})},listIndexes:function(a,e){var b=
41
+ "";void 0===a||"function"===typeof a?e=a:b="?page="+a;return this._jsonRequest({method:"GET",url:"/1/indexes"+b,hostType:"read",callback:e})},initIndex:function(a){return new this.Index(this,a)},listUserKeys:function(a){return this._jsonRequest({method:"GET",url:"/1/keys",hostType:"read",callback:a})},getUserKeyACL:function(a,e){return this._jsonRequest({method:"GET",url:"/1/keys/"+a,hostType:"read",callback:e})},deleteUserKey:function(a,e){return this._jsonRequest({method:"DELETE",url:"/1/keys/"+
42
+ a,hostType:"write",callback:e})},addUserKey:function(a,e,b){if(1===arguments.length||"function"===typeof e)b=e,e=null;var c={acl:a};e&&(c.validity=e.validity,c.maxQueriesPerIPPerHour=e.maxQueriesPerIPPerHour,c.maxHitsPerQuery=e.maxHitsPerQuery,c.indexes=e.indexes);return this._jsonRequest({method:"POST",url:"/1/keys",body:c,hostType:"write",callback:b})},addUserKeyWithValidity:l(function(a,e,b){return this.addUserKey(a,e,b)},t("client.addUserKeyWithValidity()","client.addUserKey()")),updateUserKey:function(a,
43
+ e,b,c){if(2===arguments.length||"function"===typeof b)c=b,b=null;var f={acl:e};b&&(f.validity=b.validity,f.maxQueriesPerIPPerHour=b.maxQueriesPerIPPerHour,f.maxHitsPerQuery=b.maxHitsPerQuery,f.indexes=b.indexes);return this._jsonRequest({method:"PUT",url:"/1/keys/"+a,body:f,hostType:"write",callback:c})},setSecurityTags:function(a){if("[object Array]"===Object.prototype.toString.call(a)){for(var e=[],b=0;b<a.length;++b)if("[object Array]"===Object.prototype.toString.call(a[b])){for(var c=[],f=0;f<
44
+ a[b].length;++f)c.push(a[b][f]);e.push("("+c.join(",")+")")}else e.push(a[b]);a=e.join(",")}this.securityTags=a},setUserToken:function(a){this.userToken=a},startQueriesBatch:l(function(){this._batch=[]},t("client.startQueriesBatch()","client.search()")),addQueryInBatch:l(function(a,e,b){this._batch.push({indexName:a,query:e,params:b})},t("client.addQueryInBatch()","client.search()")),clearCache:function(){this.cache={}},sendQueriesBatch:l(function(a){return this.search(this._batch,a)},t("client.sendQueriesBatch()",
45
+ "client.search()")),setRequestTimeout:function(a){a&&(this.requestTimeout=parseInt(a,10))},search:function(a,e){var c=this,f={requests:b(a,function(a){var e="";void 0!==a.query&&(e+="query="+encodeURIComponent(a.query));return{indexName:a.indexName,params:c._getSearchParams(a.params,e)}})};return this._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/*/queries",body:f,hostType:"read",callback:e})},destroy:f,enableRateLimitForward:f,disableRateLimitForward:f,useSecuredAPIKey:f,disableSecuredAPIKey:f,
46
+ generateSecuredApiKey:f,Index:function(a,e){this.indexName=e;this.as=a;this.typeAheadValueOption=this.typeAheadArgs=null;this.cache={}},setExtraHeader:function(a,e){this.extraHeaders.push({name:a.toLowerCase(),value:e})},_sendQueriesBatch:function(a,e){return this._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/*/queries",body:a,hostType:"read",fallback:{method:"GET",url:"/1/indexes/*",body:{params:function(){for(var e="",b=0;b<a.requests.length;++b)var c="/1/indexes/"+encodeURIComponent(a.requests[b].indexName)+
47
+ "?"+a.requests[b].params,e=e+(b+"="+encodeURIComponent(c)+"&");return e}()}},callback:e})},_jsonRequest:function(a){function e(g,l){function n(){d.hostIndex[a.hostType]=++d.hostIndex[a.hostType]%d.hosts[a.hostType].length;h+=1;l.timeout=d.requestTimeout*(h+1);return e(g,l)}var q;d._useCache&&(q=a.url);d._useCache&&c&&(q+="_body_"+l.body);if(d._useCache&&f&&void 0!==f[q])return b("serving response from cache"),d._promise.resolve(f[q]);if(h>=d.hosts[a.hostType].length){if(!a.fallback||!d._request.fallback||
48
+ k)return d._promise.reject(Error("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue."));h=0;l.method=a.fallback.method;l.url=a.fallback.url;l.jsonBody=a.fallback.body;l.jsonBody&&(l.body=JSON.stringify(a.fallback.body));l.timeout=d.requestTimeout*(h+1);d.hostIndex[a.hostType]=0;k=d.useFallback=!0;return e(d._request.fallback,l)}return g.call(d,d.hosts[a.hostType][d.hostIndex[a.hostType]]+l.url,{body:c,jsonBody:a.body,method:l.method,headers:d._computeRequestHeaders(),
49
+ timeout:l.timeout,debug:b}).then(function(a){if(a instanceof Error)return b("error: %s",a.message),n();b("received response: %j",a);var e=a&&a.body&&a.body.message&&a.body.status||a.statusCode||a&&a.body&&200,c=200===e||201===e,e=!c&&4!==Math.floor(e/100)&&1!==Math.floor(e/100);d._useCache&&c&&f&&(f[q]=a.body);return c?a.body:e?n():d._promise.reject(Error(a.body&&a.body.message||"Unknown error"))},function(c){b("error: %s, stack: %s",c.message,c.stack);d.useFallback?(d.hostIndex[a.hostType]=++d.hostIndex[a.hostType]%
50
+ d.hosts[a.hostType].length,h+=1):h=d.hosts[a.hostType].length;return e(g,l)})}var b=g(5)("algoliasearch:"+a.url),c,f=a.cache,d=this,h=0,k=!1;void 0!==a.body&&(c=JSON.stringify(a.body));b("request start");var l=d.useFallback&&a.fallback,n=l?a.fallback:a,l=e(l?d._request.fallback:d._request,{url:n.url,method:n.method,body:c,jsonBody:a.body,timeout:d.requestTimeout*(h+1)});if(a.callback)l.then(function(e){p(function(){a.callback(null,e)},d._setTimeout||setTimeout)},function(e){p(function(){a.callback(e)},
51
+ d._setTimeout||setTimeout)});else return l},_getSearchParams:function(a,e){if(this._isUndefined(a)||null===a)return e;for(var b in a)null!==b&&a.hasOwnProperty(b)&&(e+=""===e?"":"&",e+=b+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(a[b])?JSON.stringify(a[b]):a[b]));return e},_isUndefined:function(a){return void 0===a},_computeRequestHeaders:function(){var a={"x-algolia-api-key":this.apiKey,"x-algolia-application-id":this.applicationID,"x-user-agent":this._ua};this.userToken&&
52
+ (a["x-algolia-usertoken"]=this.userToken);this.securityTags&&(a["x-algolia-tagfilters"]=this.securityTags);this.extraHeaders&&x(this.extraHeaders,function(e){a[e.name]=e.value});return a}};c.prototype.Index.prototype={clearCache:function(){this.cache={}},addObject:function(a,e,b){if(1===arguments.length||"function"===typeof e)b=e,e=void 0;return this.as._jsonRequest({method:void 0!==e?"PUT":"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+(void 0!==e?"/"+encodeURIComponent(e):""),body:a,
53
+ hostType:"write",callback:b})},addObjects:function(a,e){for(var b={requests:[]},c=0;c<a.length;++c)b.requests.push({action:"addObject",body:a[c]});return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/batch",body:b,hostType:"write",callback:e})},getObject:function(a,b,c){if(1===arguments.length||"function"===typeof b)c=b,b=void 0;var d="";if(void 0!==b)for(var d="?attributes=",f=0;f<b.length;++f)0!==f&&(d+=","),d+=b[f];return this.as._jsonRequest({method:"GET",
54
+ url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/"+encodeURIComponent(a)+d,hostType:"read",callback:c})},getObjects:function(a,e){var c=this,d={requests:b(a,function(a){return{indexName:c.indexName,objectID:a}})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/*/objects",hostType:"read",body:d,callback:e})},partialUpdateObject:function(a,b){return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/"+encodeURIComponent(a.objectID)+"/partial",
55
+ body:a,hostType:"write",callback:b})},partialUpdateObjects:function(a,b){for(var c={requests:[]},d=0;d<a.length;++d)c.requests.push({action:"partialUpdateObject",objectID:a[d].objectID,body:a[d]});return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/batch",body:c,hostType:"write",callback:b})},saveObject:function(a,b){return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/"+encodeURIComponent(a.objectID),body:a,
56
+ hostType:"write",callback:b})},saveObjects:function(a,b){for(var c={requests:[]},d=0;d<a.length;++d)c.requests.push({action:"updateObject",objectID:a[d].objectID,body:a[d]});return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/batch",body:c,hostType:"write",callback:b})},deleteObject:function(a,b){if("function"===typeof a||"string"!==typeof a&&"number"!==typeof a){var c=Error("Cannot delete an object without an objectID");b=a;return"function"===typeof b?
57
+ b(c):this.as._promise.reject(c)}return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/"+encodeURIComponent(a),hostType:"write",callback:b})},deleteObjects:function(a,e){var c={requests:b(a,function(a){return{action:"deleteObject",objectID:a,body:{objectID:a}}})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/batch",body:c,hostType:"write",callback:e})},deleteByQuery:function(a,e,c){function d(a){return g.waitTask(a.taskID)}
58
+ function f(){return g.deleteByQuery(a,e)}var g=this,h=g.as;if(1===arguments.length||"function"===typeof e)c=e,e={};e.attributesToRetrieve="objectID";e.hitsPerPage=1E3;this.clearCache();var k=this.search(a,e).then(function(a){if(0===a.nbHits)return a;a=b(a.hits,function(a){return a.objectID});return g.deleteObjects(a).then(d).then(f)});if(!c)return k;k.then(function(){p(function(){c(null)},h._setTimeout||setTimeout)},function(a){p(function(){c(a)},h._setTimeout||setTimeout)})},search:function(a,b,
59
+ c){if("function"===typeof a&&"object"===typeof b||"object"===typeof c)throw Error("algoliasearch: index.search usage is index.search(query, params, cb)");if(0===arguments.length||"function"===typeof a)c=a,a="";else if(1===arguments.length||"function"===typeof b)c=b,b=void 0;if("object"===typeof a&&null!==a)b=a,a=void 0;else if(void 0===a||null===a)a="";var d="";void 0!==a&&(d+="query="+encodeURIComponent(a));void 0!==b&&(d=this.as._getSearchParams(b,d));return this._search(d,c)},browse:function(a,
60
+ b,c){if(1===arguments.length||"function"===typeof b)c=b,b=void 0;var d="?page="+a;this.as._isUndefined(b)||(d+="&hitsPerPage="+b);return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/browse"+d,hostType:"read",callback:c})},ttAdapter:function(a){var b=this;return function(c,d){b.search(c,a,function(a,b){a?d(a):d(b.hits)})}},waitTask:function(a,b){var c=this,d=c.as,f=this.as._jsonRequest({method:"GET",hostType:"read",url:"/1/indexes/"+encodeURIComponent(c.indexName)+
61
+ "/task/"+a}).then(function(b){return"published"!==b.status?c.as._promise.delay(100).then(function(){return c.waitTask(a)}):b});if(!b)return f;f.then(function(a){p(function(){b(null,a)},d._setTimeout||setTimeout)},function(a){p(function(){b(a)},d._setTimeout||setTimeout)})},clearIndex:function(a){return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/clear",hostType:"write",callback:a})},getSettings:function(a){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+
62
+ encodeURIComponent(this.indexName)+"/settings",hostType:"read",callback:a})},setSettings:function(a,b){return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/settings",hostType:"write",body:a,callback:b})},listUserKeys:function(a){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",hostType:"read",callback:a})},getUserKeyACL:function(a,b){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+
63
+ "/keys/"+a,hostType:"read",callback:b})},deleteUserKey:function(a,b){return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+a,hostType:"write",callback:b})},addUserKey:function(a,b,c){if(1===arguments.length||"function"===typeof b)c=b,b=null;var d={acl:a};b&&(d.validity=b.validity,d.maxQueriesPerIPPerHour=b.maxQueriesPerIPPerHour,d.maxHitsPerQuery=b.maxHitsPerQuery);return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+
64
+ "/keys",body:d,hostType:"write",callback:c})},addUserKeyWithValidity:l(function(a,b,c){return this.addUserKey(a,b,c)},t("index.addUserKeyWithValidity()","index.addUserKey()")),updateUserKey:function(a,b,c,d){if(2===arguments.length||"function"===typeof c)d=c,c=null;var f={acl:b};c&&(f.validity=c.validity,f.maxQueriesPerIPPerHour=c.maxQueriesPerIPPerHour,f.maxHitsPerQuery=c.maxHitsPerQuery);return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+a,body:f,
65
+ hostType:"write",callback:d})},_search:function(a,b){return this.as._jsonRequest({cache:this.cache,method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:a},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:a}},callback:b})},as:null,indexName:null,typeAheadArgs:null,typeAheadValueOption:null}}).call(this,g(1))},{1:1,11:11,5:5,9:9}],14:[function(g,h,d){h.exports=function(c,b,d){function f(){b.debug("JSONP: success");
66
+ v||a||(v=!0,x||(b.debug("JSONP: Fail. Script loaded but did not call the callback"),h(),d(Error("Failed to load JSONP script"))))}function g(){"loaded"!==this.readyState&&"complete"!==this.readyState||f()}function h(){clearTimeout(u);m.onload=null;m.onreadystatechange=null;m.onerror=null;e.removeChild(m);try{delete window[r],delete window[r+"_loaded"]}catch(a){window[r]=null,window[r+"_loaded"]=null}}function l(){b.debug("JSONP: Script timeout");a=!0;h();d(Error("Timeout - Could not connect to endpoint "+
67
+ c))}function q(){b.debug("JSONP: Script error");v||a||(h(),d(Error("Failed to load JSONP script")))}if("GET"!==b.method)d(Error("Method "+b.method+" "+c+" is not supported by JSONP."));else{b.debug("JSONP: start");var x=!1,a=!1;n+=1;var e=document.getElementsByTagName("head")[0],m=document.createElement("script"),r="algoliaJSONP_"+n,v=!1;window[r]=function(b){try{delete window[r]}catch(c){window[r]=void 0}a||(x=!0,h(),d(null,{body:b}))};c+="&callback="+r;b.jsonBody&&b.jsonBody.params&&(c+="&"+b.jsonBody.params);
68
+ var u=setTimeout(l,b.timeout);m.onreadystatechange=g;m.onload=f;m.onerror=q;m.async=!0;m.defer=!0;m.src=c;e.appendChild(m)}};var n=0},{}],15:[function(g,h,d){(function(d){function c(d,f,a){var e=g(9),h=g(17);a=e(!0,{},a)||{};void 0===a.protocol&&(a.protocol=h());a._ua=c.ua;return new b(d,f,a)}function b(){f.apply(this,arguments)}var h=g(12),f=g(13),t=g(18),p=g(14);window.algoliasearch=g(16);c.version=g(19);c.ua="Algolia for jQuery "+c.version;var l=d.jQuery;l.algolia={Client:c,ua:c.ua,version:c.version};
69
+ h(b,f);b.prototype._request=function(b,c){return l.Deferred(function(a){var d=c.body;b=t(b,c.headers);l.ajax(b,{type:c.method,timeout:c.timeout,dataType:"json",data:d,complete:function(c,d){"timeout"===d?a.resolve(Error("Timeout - Could not connect to endpoint "+b)):0===c.status?a.reject(Error("Network error")):a.resolve({statusCode:c.status,body:c.responseJSON})}})}).promise()};b.prototype._request.fallback=function(b,c){b=t(b,c.headers);return l.Deferred(function(a){p(b,c,function(b,c){b?a.reject(b):
70
+ a.resolve(c)})}).promise()};b.prototype._promise={reject:function(b){return l.Deferred(function(c){c.reject(b)}).promise()},resolve:function(b){return l.Deferred(function(c){c.resolve(b)}).promise()},delay:function(b){return l.Deferred(function(c){setTimeout(function(){c.resolve()},b)}).promise()}}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{12:12,13:13,14:14,16:16,17:17,18:18,19:19,9:9}],16:[function(g,h,d){(function(d){function c(a,
71
+ d,f){var h=g(9),k=g(17);f=h(!0,{},f)||{};void 0===f.protocol&&(f.protocol=k());f._ua=c.ua;return new b(a,d,f)}function b(){t.apply(this,arguments)}h.exports=c;var k=g(12),f=d.Promise||g(8).Promise,t=g(13),p=g(18),l=g(14);c.version=g(19);c.ua="Algolia for vanilla JavaScript "+c.version;var q="XDomainRequest"in window,x="withCredentials"in new XMLHttpRequest,a="timeout"in new XMLHttpRequest;k(b,t);b.prototype._request=function(b,c){return new f(function(d,f){function g(){if(!w){a||clearTimeout(t);var b=
72
+ null;try{b=JSON.parse(n.responseText)}catch(c){}d({body:b,statusCode:n.status})}}function h(b){w||(a||clearTimeout(t),f(Error("Could not connect to host, error was:"+b)))}function k(){a||(w=!0,n.abort());d(Error("Timeout - Could not connect to endpoint "+b))}if(x||q){b=p(b,c.headers);var l=c.body,n=x?new XMLHttpRequest:new XDomainRequest,t,w;n instanceof XMLHttpRequest?n.open(c.method,b,!0):n.open(c.method,b);x&&l&&"GET"!==c.method&&n.setRequestHeader("content-type","application/x-www-form-urlencoded");
73
+ n.onprogress=function(){};n.onload=g;n.onerror=h;a?(n.timeout=c.timeout,n.ontimeout=k):t=setTimeout(k,c.timeout);n.send(l)}else f(Error("CORS not supported"))})};b.prototype._request.fallback=function(a,b){a=p(a,b.headers);return new f(function(c,d){l(a,b,function(a,b){a?d(a):c(b)})})};b.prototype._promise={reject:function(a){return f.reject(a)},resolve:function(a){return f.resolve(a)},delay:function(a){return new f(function(b){setTimeout(b,a)})}}}).call(this,"undefined"!==typeof global?global:"undefined"!==
74
+ typeof self?self:"undefined"!==typeof window?window:{})},{12:12,13:13,14:14,17:17,18:18,19:19,8:8,9:9}],17:[function(g,h,d){(function(d){h.exports=function(){var c=d.document.location.protocol;"http:"!==c&&"https:"!==c&&(c="http:");return c}}).call(this,"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{}],18:[function(g,h,d){h.exports=function(c,b){c=/\?/.test(c)?c+"&":c+"?";return c+n.encode(b)};var n=g(4)},{4:4}],19:[function(g,h,d){h.exports=
75
+ "3.3.0"},{}]},{},[15]);
@@ -1,4 +1,4 @@
1
- /*! algoliasearch 3.0.3 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */
1
+ /*! algoliasearch 3.3.0 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */
2
2
  (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){
3
3
 
4
4
  module.exports = function load (src, opts, cb) {
@@ -200,209 +200,746 @@ function migrationLayer(buildName) {
200
200
 
201
201
  },{"2":2,"3":3,"4":4}]},{},[5])(5)
202
202
  });(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){
203
- (function (global){
204
- // this is the standalone build entry of AlgoliaSearch
205
- var createAlgoliasearch = require(6);
203
+ // shim for using process in browser
206
204
 
207
- module.exports = createAlgoliasearch(request);
205
+ var process = module.exports = {};
206
+ var queue = [];
207
+ var draining = false;
208
208
 
209
- var Promise = global.Promise || require(3).Promise;
209
+ function drainQueue() {
210
+ if (draining) {
211
+ return;
212
+ }
213
+ draining = true;
214
+ var currentQueue;
215
+ var len = queue.length;
216
+ while(len) {
217
+ currentQueue = queue;
218
+ queue = [];
219
+ var i = -1;
220
+ while (++i < len) {
221
+ currentQueue[i]();
222
+ }
223
+ len = queue.length;
224
+ }
225
+ draining = false;
226
+ }
227
+ process.nextTick = function (fun) {
228
+ queue.push(fun);
229
+ if (!draining) {
230
+ setTimeout(drainQueue, 0);
231
+ }
232
+ };
210
233
 
211
- var JSONPRequest = require(5);
234
+ process.title = 'browser';
235
+ process.browser = true;
236
+ process.env = {};
237
+ process.argv = [];
238
+ process.version = ''; // empty string to avoid regexp issues
239
+ process.versions = {};
212
240
 
213
- var support = {
214
- hasXMLHttpRequest: 'XMLHttpRequest' in window,
215
- hasXDomainRequest: 'XDomainRequest' in window,
216
- cors: 'withCredentials' in new XMLHttpRequest(),
217
- timeout: 'timeout' in new XMLHttpRequest()
241
+ function noop() {}
242
+
243
+ process.on = noop;
244
+ process.addListener = noop;
245
+ process.once = noop;
246
+ process.off = noop;
247
+ process.removeListener = noop;
248
+ process.removeAllListeners = noop;
249
+ process.emit = noop;
250
+
251
+ process.binding = function (name) {
252
+ throw new Error('process.binding is not supported');
218
253
  };
219
254
 
220
- function request(url, opts) {
221
- return new Promise(function(resolve, reject) {
222
- // no cors or XDomainRequest, no request
223
- if (!support.cors && !support.hasXDomainRequest) {
224
- // very old browser, not supported
225
- reject(new Error('CORS not supported'));
226
- return;
227
- }
255
+ // TODO(shtylman)
256
+ process.cwd = function () { return '/' };
257
+ process.chdir = function (dir) {
258
+ throw new Error('process.chdir is not supported');
259
+ };
260
+ process.umask = function() { return 0; };
228
261
 
229
- var body = null;
230
- var req = support.cors ? new XMLHttpRequest() : new XDomainRequest();
231
- var ontimeout;
232
- var timedOut;
262
+ },{}],2:[function(require,module,exports){
263
+ // Copyright Joyent, Inc. and other Node contributors.
264
+ //
265
+ // Permission is hereby granted, free of charge, to any person obtaining a
266
+ // copy of this software and associated documentation files (the
267
+ // "Software"), to deal in the Software without restriction, including
268
+ // without limitation the rights to use, copy, modify, merge, publish,
269
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
270
+ // persons to whom the Software is furnished to do so, subject to the
271
+ // following conditions:
272
+ //
273
+ // The above copyright notice and this permission notice shall be included
274
+ // in all copies or substantial portions of the Software.
275
+ //
276
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
277
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
278
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
279
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
280
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
281
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
282
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
283
+
284
+ 'use strict';
285
+
286
+ // If obj.hasOwnProperty has been overridden, then calling
287
+ // obj.hasOwnProperty(prop) will break.
288
+ // See: https://github.com/joyent/node/issues/1707
289
+ function hasOwnProperty(obj, prop) {
290
+ return Object.prototype.hasOwnProperty.call(obj, prop);
291
+ }
233
292
 
234
- if (opts.body !== undefined) {
235
- body = JSON.stringify(opts.body);
293
+ module.exports = function(qs, sep, eq, options) {
294
+ sep = sep || '&';
295
+ eq = eq || '=';
296
+ var obj = {};
297
+
298
+ if (typeof qs !== 'string' || qs.length === 0) {
299
+ return obj;
300
+ }
301
+
302
+ var regexp = /\+/g;
303
+ qs = qs.split(sep);
304
+
305
+ var maxKeys = 1000;
306
+ if (options && typeof options.maxKeys === 'number') {
307
+ maxKeys = options.maxKeys;
308
+ }
309
+
310
+ var len = qs.length;
311
+ // maxKeys <= 0 means that we should not limit keys count
312
+ if (maxKeys > 0 && len > maxKeys) {
313
+ len = maxKeys;
314
+ }
315
+
316
+ for (var i = 0; i < len; ++i) {
317
+ var x = qs[i].replace(regexp, '%20'),
318
+ idx = x.indexOf(eq),
319
+ kstr, vstr, k, v;
320
+
321
+ if (idx >= 0) {
322
+ kstr = x.substr(0, idx);
323
+ vstr = x.substr(idx + 1);
324
+ } else {
325
+ kstr = x;
326
+ vstr = '';
236
327
  }
237
328
 
238
- // do not rely on default XHR async flag, as some analytics code like hotjar
239
- // breaks it and set it to false by default
240
- if (req instanceof XMLHttpRequest) {
241
- req.open(opts.method, url, true);
329
+ k = decodeURIComponent(kstr);
330
+ v = decodeURIComponent(vstr);
331
+
332
+ if (!hasOwnProperty(obj, k)) {
333
+ obj[k] = v;
334
+ } else if (isArray(obj[k])) {
335
+ obj[k].push(v);
242
336
  } else {
243
- req.open(opts.method, url);
337
+ obj[k] = [obj[k], v];
244
338
  }
339
+ }
245
340
 
246
- if (support.cors && body && opts.method !== 'GET') {
247
- req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
341
+ return obj;
342
+ };
343
+
344
+ var isArray = Array.isArray || function (xs) {
345
+ return Object.prototype.toString.call(xs) === '[object Array]';
346
+ };
347
+
348
+ },{}],3:[function(require,module,exports){
349
+ // Copyright Joyent, Inc. and other Node contributors.
350
+ //
351
+ // Permission is hereby granted, free of charge, to any person obtaining a
352
+ // copy of this software and associated documentation files (the
353
+ // "Software"), to deal in the Software without restriction, including
354
+ // without limitation the rights to use, copy, modify, merge, publish,
355
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
356
+ // persons to whom the Software is furnished to do so, subject to the
357
+ // following conditions:
358
+ //
359
+ // The above copyright notice and this permission notice shall be included
360
+ // in all copies or substantial portions of the Software.
361
+ //
362
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
363
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
364
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
365
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
366
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
367
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
368
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
369
+
370
+ 'use strict';
371
+
372
+ var stringifyPrimitive = function(v) {
373
+ switch (typeof v) {
374
+ case 'string':
375
+ return v;
376
+
377
+ case 'boolean':
378
+ return v ? 'true' : 'false';
379
+
380
+ case 'number':
381
+ return isFinite(v) ? v : '';
382
+
383
+ default:
384
+ return '';
385
+ }
386
+ };
387
+
388
+ module.exports = function(obj, sep, eq, name) {
389
+ sep = sep || '&';
390
+ eq = eq || '=';
391
+ if (obj === null) {
392
+ obj = undefined;
393
+ }
394
+
395
+ if (typeof obj === 'object') {
396
+ return map(objectKeys(obj), function(k) {
397
+ var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
398
+ if (isArray(obj[k])) {
399
+ return map(obj[k], function(v) {
400
+ return ks + encodeURIComponent(stringifyPrimitive(v));
401
+ }).join(sep);
402
+ } else {
403
+ return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
404
+ }
405
+ }).join(sep);
406
+
407
+ }
408
+
409
+ if (!name) return '';
410
+ return encodeURIComponent(stringifyPrimitive(name)) + eq +
411
+ encodeURIComponent(stringifyPrimitive(obj));
412
+ };
413
+
414
+ var isArray = Array.isArray || function (xs) {
415
+ return Object.prototype.toString.call(xs) === '[object Array]';
416
+ };
417
+
418
+ function map (xs, f) {
419
+ if (xs.map) return xs.map(f);
420
+ var res = [];
421
+ for (var i = 0; i < xs.length; i++) {
422
+ res.push(f(xs[i], i));
423
+ }
424
+ return res;
425
+ }
426
+
427
+ var objectKeys = Object.keys || function (obj) {
428
+ var res = [];
429
+ for (var key in obj) {
430
+ if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key);
431
+ }
432
+ return res;
433
+ };
434
+
435
+ },{}],4:[function(require,module,exports){
436
+ 'use strict';
437
+
438
+ exports.decode = exports.parse = require(2);
439
+ exports.encode = exports.stringify = require(3);
440
+
441
+ },{"2":2,"3":3}],5:[function(require,module,exports){
442
+
443
+ /**
444
+ * This is the web browser implementation of `debug()`.
445
+ *
446
+ * Expose `debug()` as the module.
447
+ */
448
+
449
+ exports = module.exports = require(6);
450
+ exports.log = log;
451
+ exports.formatArgs = formatArgs;
452
+ exports.save = save;
453
+ exports.load = load;
454
+ exports.useColors = useColors;
455
+
456
+ /**
457
+ * Use chrome.storage.local if we are in an app
458
+ */
459
+
460
+ var storage;
461
+
462
+ if (typeof chrome !== 'undefined' && typeof chrome.storage !== 'undefined')
463
+ storage = chrome.storage.local;
464
+ else
465
+ storage = localstorage();
466
+
467
+ /**
468
+ * Colors.
469
+ */
470
+
471
+ exports.colors = [
472
+ 'lightseagreen',
473
+ 'forestgreen',
474
+ 'goldenrod',
475
+ 'dodgerblue',
476
+ 'darkorchid',
477
+ 'crimson'
478
+ ];
479
+
480
+ /**
481
+ * Currently only WebKit-based Web Inspectors, Firefox >= v31,
482
+ * and the Firebug extension (any Firefox version) are known
483
+ * to support "%c" CSS customizations.
484
+ *
485
+ * TODO: add a `localStorage` variable to explicitly enable/disable colors
486
+ */
487
+
488
+ function useColors() {
489
+ // is webkit? http://stackoverflow.com/a/16459606/376773
490
+ return ('WebkitAppearance' in document.documentElement.style) ||
491
+ // is firebug? http://stackoverflow.com/a/398120/376773
492
+ (window.console && (console.firebug || (console.exception && console.table))) ||
493
+ // is firefox >= v31?
494
+ // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
495
+ (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
496
+ }
497
+
498
+ /**
499
+ * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
500
+ */
501
+
502
+ exports.formatters.j = function(v) {
503
+ return JSON.stringify(v);
504
+ };
505
+
506
+
507
+ /**
508
+ * Colorize log arguments if enabled.
509
+ *
510
+ * @api public
511
+ */
512
+
513
+ function formatArgs() {
514
+ var args = arguments;
515
+ var useColors = this.useColors;
516
+
517
+ args[0] = (useColors ? '%c' : '')
518
+ + this.namespace
519
+ + (useColors ? ' %c' : ' ')
520
+ + args[0]
521
+ + (useColors ? '%c ' : ' ')
522
+ + '+' + exports.humanize(this.diff);
523
+
524
+ if (!useColors) return args;
525
+
526
+ var c = 'color: ' + this.color;
527
+ args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
528
+
529
+ // the final "%c" is somewhat tricky, because there could be other
530
+ // arguments passed either before or after the %c, so we need to
531
+ // figure out the correct index to insert the CSS into
532
+ var index = 0;
533
+ var lastC = 0;
534
+ args[0].replace(/%[a-z%]/g, function(match) {
535
+ if ('%%' === match) return;
536
+ index++;
537
+ if ('%c' === match) {
538
+ // we only are interested in the *last* %c
539
+ // (the user may have provided their own)
540
+ lastC = index;
248
541
  }
542
+ });
249
543
 
250
- req.onload = load;
251
- req.onerror = error;
544
+ args.splice(lastC, 0, c);
545
+ return args;
546
+ }
252
547
 
253
- if (support.timeout) {
254
- // .timeout supported by both XHR and XDR,
255
- // we do receive timeout event, tested
256
- req.timeout = opts.timeout;
548
+ /**
549
+ * Invokes `console.log()` when available.
550
+ * No-op when `console.log` is not a "function".
551
+ *
552
+ * @api public
553
+ */
257
554
 
258
- req.ontimeout = timeout;
555
+ function log() {
556
+ // this hackery is required for IE8/9, where
557
+ // the `console.log` function doesn't have 'apply'
558
+ return 'object' === typeof console
559
+ && console.log
560
+ && Function.prototype.apply.call(console.log, console, arguments);
561
+ }
562
+
563
+ /**
564
+ * Save `namespaces`.
565
+ *
566
+ * @param {String} namespaces
567
+ * @api private
568
+ */
569
+
570
+ function save(namespaces) {
571
+ try {
572
+ if (null == namespaces) {
573
+ storage.removeItem('debug');
259
574
  } else {
260
- ontimeout = setTimeout(timeout, opts.timeout);
575
+ storage.debug = namespaces;
261
576
  }
577
+ } catch(e) {}
578
+ }
262
579
 
263
- req.send(body);
580
+ /**
581
+ * Load `namespaces`.
582
+ *
583
+ * @return {String} returns the previously persisted debug modes
584
+ * @api private
585
+ */
264
586
 
265
- // event object not received in IE8, at least
266
- // but we do not use it, still important to note
267
- function load(/*event*/) {
268
- // When browser does not supports req.timeout, we can
269
- // have both a load and timeout event, since handled by a dumb setTimeout
270
- if (timedOut) {
271
- return;
272
- }
587
+ function load() {
588
+ var r;
589
+ try {
590
+ r = storage.debug;
591
+ } catch(e) {}
592
+ return r;
593
+ }
273
594
 
274
- if (!support.timeout) {
275
- clearTimeout(ontimeout);
276
- }
595
+ /**
596
+ * Enable namespaces listed in `localStorage.debug` initially.
597
+ */
277
598
 
278
- var response = null;
599
+ exports.enable(load());
279
600
 
280
- try {
281
- response = JSON.parse(req.responseText);
282
- } catch(e) {}
601
+ /**
602
+ * Localstorage attempts to return the localstorage.
603
+ *
604
+ * This is necessary because safari throws
605
+ * when a user disables cookies/localstorage
606
+ * and you attempt to access it.
607
+ *
608
+ * @return {LocalStorage}
609
+ * @api private
610
+ */
283
611
 
284
- resolve({
285
- body: response,
286
- statusCode: req.status
287
- });
612
+ function localstorage(){
613
+ try {
614
+ return window.localStorage;
615
+ } catch (e) {}
616
+ }
617
+
618
+ },{"6":6}],6:[function(require,module,exports){
619
+
620
+ /**
621
+ * This is the common logic for both the Node.js and web browser
622
+ * implementations of `debug()`.
623
+ *
624
+ * Expose `debug()` as the module.
625
+ */
626
+
627
+ exports = module.exports = debug;
628
+ exports.coerce = coerce;
629
+ exports.disable = disable;
630
+ exports.enable = enable;
631
+ exports.enabled = enabled;
632
+ exports.humanize = require(7);
633
+
634
+ /**
635
+ * The currently active debug mode names, and names to skip.
636
+ */
637
+
638
+ exports.names = [];
639
+ exports.skips = [];
640
+
641
+ /**
642
+ * Map of special "%n" handling functions, for the debug "format" argument.
643
+ *
644
+ * Valid key names are a single, lowercased letter, i.e. "n".
645
+ */
646
+
647
+ exports.formatters = {};
648
+
649
+ /**
650
+ * Previously assigned color.
651
+ */
652
+
653
+ var prevColor = 0;
654
+
655
+ /**
656
+ * Previous log timestamp.
657
+ */
658
+
659
+ var prevTime;
660
+
661
+ /**
662
+ * Select a color.
663
+ *
664
+ * @return {Number}
665
+ * @api private
666
+ */
667
+
668
+ function selectColor() {
669
+ return exports.colors[prevColor++ % exports.colors.length];
670
+ }
671
+
672
+ /**
673
+ * Create a debugger with the given `namespace`.
674
+ *
675
+ * @param {String} namespace
676
+ * @return {Function}
677
+ * @api public
678
+ */
679
+
680
+ function debug(namespace) {
681
+
682
+ // define the `disabled` version
683
+ function disabled() {
684
+ }
685
+ disabled.enabled = false;
686
+
687
+ // define the `enabled` version
688
+ function enabled() {
689
+
690
+ var self = enabled;
691
+
692
+ // set `diff` timestamp
693
+ var curr = +new Date();
694
+ var ms = curr - (prevTime || curr);
695
+ self.diff = ms;
696
+ self.prev = prevTime;
697
+ self.curr = curr;
698
+ prevTime = curr;
699
+
700
+ // add the `color` if not set
701
+ if (null == self.useColors) self.useColors = exports.useColors();
702
+ if (null == self.color && self.useColors) self.color = selectColor();
703
+
704
+ var args = Array.prototype.slice.call(arguments);
705
+
706
+ args[0] = exports.coerce(args[0]);
707
+
708
+ if ('string' !== typeof args[0]) {
709
+ // anything else let's inspect with %o
710
+ args = ['%o'].concat(args);
288
711
  }
289
712
 
290
- function error(event) {
291
- if (timedOut) {
292
- return;
293
- }
713
+ // apply any `formatters` transformations
714
+ var index = 0;
715
+ args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
716
+ // if we encounter an escaped % then don't increase the array index
717
+ if (match === '%%') return match;
718
+ index++;
719
+ var formatter = exports.formatters[format];
720
+ if ('function' === typeof formatter) {
721
+ var val = args[index];
722
+ match = formatter.call(self, val);
294
723
 
295
- if (!support.timeout) {
296
- clearTimeout(ontimeout);
724
+ // now we need to remove `args[index]` since it's inlined in the `format`
725
+ args.splice(index, 1);
726
+ index--;
297
727
  }
728
+ return match;
729
+ });
298
730
 
299
- // error event is trigerred both with XDR/XHR on:
300
- // - DNS error
301
- // - unallowed cross domain request
302
- reject(new Error('Could not connect to host, error was:' + event));
731
+ if ('function' === typeof exports.formatArgs) {
732
+ args = exports.formatArgs.apply(self, args);
303
733
  }
734
+ var logFn = enabled.log || exports.log || console.log.bind(console);
735
+ logFn.apply(self, args);
736
+ }
737
+ enabled.enabled = true;
304
738
 
305
- function timeout() {
306
- if (!support.timeout) {
307
- timedOut = true;
308
- req.abort();
309
- }
739
+ var fn = exports.enabled(namespace) ? enabled : disabled;
310
740
 
311
- resolve(new Error('Timeout - Could not connect to endpoint ' + url));
741
+ fn.namespace = namespace;
742
+
743
+ return fn;
744
+ }
745
+
746
+ /**
747
+ * Enables a debug mode by namespaces. This can include modes
748
+ * separated by a colon and wildcards.
749
+ *
750
+ * @param {String} namespaces
751
+ * @api public
752
+ */
753
+
754
+ function enable(namespaces) {
755
+ exports.save(namespaces);
756
+
757
+ var split = (namespaces || '').split(/[\s,]+/);
758
+ var len = split.length;
759
+
760
+ for (var i = 0; i < len; i++) {
761
+ if (!split[i]) continue; // ignore empty strings
762
+ namespaces = split[i].replace(/\*/g, '.*?');
763
+ if (namespaces[0] === '-') {
764
+ exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
765
+ } else {
766
+ exports.names.push(new RegExp('^' + namespaces + '$'));
312
767
  }
768
+ }
769
+ }
313
770
 
314
- });
771
+ /**
772
+ * Disable debug output.
773
+ *
774
+ * @api public
775
+ */
776
+
777
+ function disable() {
778
+ exports.enable('');
315
779
  }
316
780
 
317
- request.fallback = function(url, opts) {
318
- return new Promise(function(resolve, reject) {
319
- JSONPRequest(url, opts, function JSONPRequestDone(err, content) {
320
- if (err) {
321
- reject(err);
322
- return;
323
- }
781
+ /**
782
+ * Returns true if the given mode name is enabled, false otherwise.
783
+ *
784
+ * @param {String} name
785
+ * @return {Boolean}
786
+ * @api public
787
+ */
324
788
 
325
- resolve(content);
326
- });
327
- });
328
- };
789
+ function enabled(name) {
790
+ var i, len;
791
+ for (i = 0, len = exports.skips.length; i < len; i++) {
792
+ if (exports.skips[i].test(name)) {
793
+ return false;
794
+ }
795
+ }
796
+ for (i = 0, len = exports.names.length; i < len; i++) {
797
+ if (exports.names[i].test(name)) {
798
+ return true;
799
+ }
800
+ }
801
+ return false;
802
+ }
329
803
 
330
- request.reject = function(val) {
331
- return Promise.reject(val);
332
- };
804
+ /**
805
+ * Coerce `val`.
806
+ *
807
+ * @param {Mixed} val
808
+ * @return {Mixed}
809
+ * @api private
810
+ */
811
+
812
+ function coerce(val) {
813
+ if (val instanceof Error) return val.stack || val.message;
814
+ return val;
815
+ }
816
+
817
+ },{"7":7}],7:[function(require,module,exports){
818
+ /**
819
+ * Helpers.
820
+ */
821
+
822
+ var s = 1000;
823
+ var m = s * 60;
824
+ var h = m * 60;
825
+ var d = h * 24;
826
+ var y = d * 365.25;
827
+
828
+ /**
829
+ * Parse or format the given `val`.
830
+ *
831
+ * Options:
832
+ *
833
+ * - `long` verbose formatting [false]
834
+ *
835
+ * @param {String|Number} val
836
+ * @param {Object} options
837
+ * @return {String|Number}
838
+ * @api public
839
+ */
333
840
 
334
- request.resolve = function(val) {
335
- return Promise.resolve(val);
841
+ module.exports = function(val, options){
842
+ options = options || {};
843
+ if ('string' == typeof val) return parse(val);
844
+ return options.long
845
+ ? long(val)
846
+ : short(val);
336
847
  };
337
848
 
338
- request.delay = function(ms) {
339
- return new Promise(function(resolve/*, reject*/) {
340
- setTimeout(resolve, ms);
341
- });
342
- };
849
+ /**
850
+ * Parse the given `str` and return milliseconds.
851
+ *
852
+ * @param {String} str
853
+ * @return {Number}
854
+ * @api private
855
+ */
343
856
 
344
- }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
345
- },{"3":3,"5":5,"6":6}],2:[function(require,module,exports){
346
- // shim for using process in browser
857
+ function parse(str) {
858
+ var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
859
+ if (!match) return;
860
+ var n = parseFloat(match[1]);
861
+ var type = (match[2] || 'ms').toLowerCase();
862
+ switch (type) {
863
+ case 'years':
864
+ case 'year':
865
+ case 'yrs':
866
+ case 'yr':
867
+ case 'y':
868
+ return n * y;
869
+ case 'days':
870
+ case 'day':
871
+ case 'd':
872
+ return n * d;
873
+ case 'hours':
874
+ case 'hour':
875
+ case 'hrs':
876
+ case 'hr':
877
+ case 'h':
878
+ return n * h;
879
+ case 'minutes':
880
+ case 'minute':
881
+ case 'mins':
882
+ case 'min':
883
+ case 'm':
884
+ return n * m;
885
+ case 'seconds':
886
+ case 'second':
887
+ case 'secs':
888
+ case 'sec':
889
+ case 's':
890
+ return n * s;
891
+ case 'milliseconds':
892
+ case 'millisecond':
893
+ case 'msecs':
894
+ case 'msec':
895
+ case 'ms':
896
+ return n;
897
+ }
898
+ }
347
899
 
348
- var process = module.exports = {};
349
- var queue = [];
350
- var draining = false;
900
+ /**
901
+ * Short format for `ms`.
902
+ *
903
+ * @param {Number} ms
904
+ * @return {String}
905
+ * @api private
906
+ */
351
907
 
352
- function drainQueue() {
353
- if (draining) {
354
- return;
355
- }
356
- draining = true;
357
- var currentQueue;
358
- var len = queue.length;
359
- while(len) {
360
- currentQueue = queue;
361
- queue = [];
362
- var i = -1;
363
- while (++i < len) {
364
- currentQueue[i]();
365
- }
366
- len = queue.length;
367
- }
368
- draining = false;
908
+ function short(ms) {
909
+ if (ms >= d) return Math.round(ms / d) + 'd';
910
+ if (ms >= h) return Math.round(ms / h) + 'h';
911
+ if (ms >= m) return Math.round(ms / m) + 'm';
912
+ if (ms >= s) return Math.round(ms / s) + 's';
913
+ return ms + 'ms';
369
914
  }
370
- process.nextTick = function (fun) {
371
- queue.push(fun);
372
- if (!draining) {
373
- setTimeout(drainQueue, 0);
374
- }
375
- };
376
-
377
- process.title = 'browser';
378
- process.browser = true;
379
- process.env = {};
380
- process.argv = [];
381
- process.version = ''; // empty string to avoid regexp issues
382
- process.versions = {};
383
915
 
384
- function noop() {}
916
+ /**
917
+ * Long format for `ms`.
918
+ *
919
+ * @param {Number} ms
920
+ * @return {String}
921
+ * @api private
922
+ */
385
923
 
386
- process.on = noop;
387
- process.addListener = noop;
388
- process.once = noop;
389
- process.off = noop;
390
- process.removeListener = noop;
391
- process.removeAllListeners = noop;
392
- process.emit = noop;
924
+ function long(ms) {
925
+ return plural(ms, d, 'day')
926
+ || plural(ms, h, 'hour')
927
+ || plural(ms, m, 'minute')
928
+ || plural(ms, s, 'second')
929
+ || ms + ' ms';
930
+ }
393
931
 
394
- process.binding = function (name) {
395
- throw new Error('process.binding is not supported');
396
- };
932
+ /**
933
+ * Pluralization helper.
934
+ */
397
935
 
398
- // TODO(shtylman)
399
- process.cwd = function () { return '/' };
400
- process.chdir = function (dir) {
401
- throw new Error('process.chdir is not supported');
402
- };
403
- process.umask = function() { return 0; };
936
+ function plural(ms, n, name) {
937
+ if (ms < n) return;
938
+ if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
939
+ return Math.ceil(ms / n) + ' ' + name + 's';
940
+ }
404
941
 
405
- },{}],3:[function(require,module,exports){
942
+ },{}],8:[function(require,module,exports){
406
943
  (function (process,global){
407
944
  /*!
408
945
  * @overview es6-promise - a tiny implementation of Promises/A+.
@@ -1364,11 +1901,159 @@ process.umask = function() { return 0; };
1364
1901
  this['ES6Promise'] = es6$promise$umd$$ES6Promise;
1365
1902
  }
1366
1903
  }).call(this);
1367
- }).call(this,require(2),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1368
- },{"2":2}],4:[function(require,module,exports){
1904
+ }).call(this,require(1),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1905
+ },{"1":1}],9:[function(require,module,exports){
1906
+ var hasOwn = Object.prototype.hasOwnProperty;
1907
+ var toString = Object.prototype.toString;
1908
+ var undefined;
1909
+
1910
+ var isArray = require(10);
1911
+
1912
+ var isPlainObject = function isPlainObject(obj) {
1913
+ 'use strict';
1914
+ if (!obj || toString.call(obj) !== '[object Object]') {
1915
+ return false;
1916
+ }
1917
+
1918
+ var has_own_constructor = hasOwn.call(obj, 'constructor');
1919
+ var has_is_property_of_method = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
1920
+ // Not own constructor property must be Object
1921
+ if (obj.constructor && !has_own_constructor && !has_is_property_of_method) {
1922
+ return false;
1923
+ }
1924
+
1925
+ // Own properties are enumerated firstly, so to speed up,
1926
+ // if last one is own, then all properties are own.
1927
+ var key;
1928
+ for (key in obj) {}
1929
+
1930
+ return key === undefined || hasOwn.call(obj, key);
1931
+ };
1932
+
1933
+ module.exports = function extend() {
1934
+ 'use strict';
1935
+ var options, name, src, copy, copyIsArray, clone,
1936
+ target = arguments[0],
1937
+ i = 1,
1938
+ length = arguments.length,
1939
+ deep = false;
1940
+
1941
+ // Handle a deep copy situation
1942
+ if (typeof target === 'boolean') {
1943
+ deep = target;
1944
+ target = arguments[1] || {};
1945
+ // skip the boolean and the target
1946
+ i = 2;
1947
+ } else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) {
1948
+ target = {};
1949
+ }
1950
+
1951
+ for (; i < length; ++i) {
1952
+ options = arguments[i];
1953
+ // Only deal with non-null/undefined values
1954
+ if (options != null) {
1955
+ // Extend the base object
1956
+ for (name in options) {
1957
+ src = target[name];
1958
+ copy = options[name];
1959
+
1960
+ // Prevent never-ending loop
1961
+ if (target === copy) {
1962
+ continue;
1963
+ }
1964
+
1965
+ // Recurse if we're merging plain objects or arrays
1966
+ if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
1967
+ if (copyIsArray) {
1968
+ copyIsArray = false;
1969
+ clone = src && isArray(src) ? src : [];
1970
+ } else {
1971
+ clone = src && isPlainObject(src) ? src : {};
1972
+ }
1973
+
1974
+ // Never move original objects, clone them
1975
+ target[name] = extend(deep, clone, copy);
1976
+
1977
+ // Don't bring in undefined values
1978
+ } else if (copy !== undefined) {
1979
+ target[name] = copy;
1980
+ }
1981
+ }
1982
+ }
1983
+ }
1984
+
1985
+ // Return the modified object
1986
+ return target;
1987
+ };
1988
+
1989
+
1990
+ },{"10":10}],10:[function(require,module,exports){
1991
+ module.exports = Array.isArray || function (arr) {
1992
+ return Object.prototype.toString.call(arr) == '[object Array]';
1993
+ };
1994
+
1995
+ },{}],11:[function(require,module,exports){
1996
+
1997
+ var hasOwn = Object.prototype.hasOwnProperty;
1998
+ var toString = Object.prototype.toString;
1999
+
2000
+ module.exports = function forEach (obj, fn, ctx) {
2001
+ if (toString.call(fn) !== '[object Function]') {
2002
+ throw new TypeError('iterator must be a function');
2003
+ }
2004
+ var l = obj.length;
2005
+ if (l === +l) {
2006
+ for (var i = 0; i < l; i++) {
2007
+ fn.call(ctx, obj[i], i, obj);
2008
+ }
2009
+ } else {
2010
+ for (var k in obj) {
2011
+ if (hasOwn.call(obj, k)) {
2012
+ fn.call(ctx, obj[k], k, obj);
2013
+ }
2014
+ }
2015
+ }
2016
+ };
2017
+
2018
+
2019
+ },{}],12:[function(require,module,exports){
2020
+ if (typeof Object.create === 'function') {
2021
+ // implementation from standard node.js 'util' module
2022
+ module.exports = function inherits(ctor, superCtor) {
2023
+ ctor.super_ = superCtor
2024
+ ctor.prototype = Object.create(superCtor.prototype, {
2025
+ constructor: {
2026
+ value: ctor,
2027
+ enumerable: false,
2028
+ writable: true,
2029
+ configurable: true
2030
+ }
2031
+ });
2032
+ };
2033
+ } else {
2034
+ // old school shim for old browsers
2035
+ module.exports = function inherits(ctor, superCtor) {
2036
+ ctor.super_ = superCtor
2037
+ var TempCtor = function () {}
2038
+ TempCtor.prototype = superCtor.prototype
2039
+ ctor.prototype = new TempCtor()
2040
+ ctor.prototype.constructor = ctor
2041
+ }
2042
+ }
2043
+
2044
+ },{}],13:[function(require,module,exports){
1369
2045
  (function (process){
1370
2046
  module.exports = AlgoliaSearch;
1371
2047
 
2048
+ // default debug activated in dev environments
2049
+ // this is triggered in package.json, using the envify transform
2050
+ if (process.env.NODE_ENV === 'development') {
2051
+ require(5).enable('algoliasearch*');
2052
+ }
2053
+
2054
+ var debug = require(5)('algoliasearch');
2055
+ var foreach = require(11);
2056
+
1372
2057
  /*
1373
2058
  * Algolia Search library initialization
1374
2059
  * https://www.algolia.com/
@@ -1380,74 +2065,80 @@ module.exports = AlgoliaSearch;
1380
2065
  * @param {string} [opts.protocol='http:'] - The protocol used to query Algolia Search API.
1381
2066
  * Set to 'https:' to force using https. Default to document.location.protocol in browsers
1382
2067
  * @param {string[]} [opts.hosts=[
1383
- * this.applicationID + '-1.algolia.' + opts.tld,
1384
- * this.applicationID + '-2.algolia.' + opts.tld,
1385
- * this.applicationID + '-3.algolia.' + opts.tld]
1386
- * ] - The hosts to use for Algolia Search API. It this your responsibility to shuffle the hosts and add a DSN host in it
1387
- * @param {string} [opts.tld='net'] - The tld to use when computing hosts default list
2068
+ * this.applicationID + '-1.algolianet.com',
2069
+ * this.applicationID + '-2.algolianet.com',
2070
+ * this.applicationID + '-3.algolianet.com']
2071
+ * ] - The hosts to use for Algolia Search API. If you provide them, you will no more benefit from our HA implementation
1388
2072
  */
1389
- function AlgoliaSearch(applicationID, apiKey, opts, _request) {
2073
+ function AlgoliaSearch(applicationID, apiKey, opts) {
2074
+ var extend = require(9);
2075
+
1390
2076
  var usage = 'Usage: algoliasearch(applicationID, apiKey, opts)';
1391
2077
 
1392
2078
  if (!applicationID) {
1393
- throw new Error('Please provide an application ID. ' + usage);
2079
+ throw new Error('algoliasearch: Please provide an application ID. ' + usage);
1394
2080
  }
1395
2081
 
1396
2082
  if (!apiKey) {
1397
- throw new Error('Please provide an API key. ' + usage);
2083
+ throw new Error('algoliasearch: Please provide an API key. ' + usage);
1398
2084
  }
1399
2085
 
1400
- opts = opts || {};
2086
+ this.applicationID = applicationID;
2087
+ this.apiKey = apiKey;
1401
2088
 
1402
- // now setting default options
1403
- // could not find a tiny module to do that, let's go manual
1404
- if (opts.timeout === undefined) {
1405
- opts.timeout = 2000;
1406
- }
2089
+ var defaultHosts = [
2090
+ this.applicationID + '-1.algolianet.com',
2091
+ this.applicationID + '-2.algolianet.com',
2092
+ this.applicationID + '-3.algolianet.com'
2093
+ ];
2094
+ this.hosts = {
2095
+ read: [],
2096
+ write: []
2097
+ };
1407
2098
 
1408
- if (opts.protocol === undefined) {
1409
- opts.protocol = document && document.location.protocol || 'http:';
1410
- }
2099
+ this.hostIndex = {
2100
+ read: 0,
2101
+ write: 0
2102
+ };
1411
2103
 
1412
- if (opts.hosts === undefined) {
1413
- opts.hosts = []; // filled later on, has dependencies
1414
- }
2104
+ opts = opts || {};
1415
2105
 
1416
- if (opts.tld === undefined) {
1417
- opts.tld = 'net';
1418
- }
2106
+ var protocol = opts.protocol || 'https:';
2107
+ var timeout = opts.timeout === undefined ? 2000 : opts.timeout;
1419
2108
 
1420
2109
  // while we advocate for colon-at-the-end values: 'http:' for `opts.protocol`
1421
2110
  // we also accept `http` and `https`. It's a common error.
1422
- if (!/:$/.test(opts.protocol)) {
1423
- opts.protocol = opts.protocol + ':';
2111
+ if (!/:$/.test(protocol)) {
2112
+ protocol = protocol + ':';
1424
2113
  }
1425
2114
 
1426
- // no hosts given, add defaults
1427
- if (opts.hosts.length === 0) {
1428
- opts.hosts = shuffle([
1429
- applicationID + '-1.algolia.' + opts.tld,
1430
- applicationID + '-2.algolia.' + opts.tld,
1431
- applicationID + '-3.algolia.' + opts.tld
1432
- ]);
1433
-
1434
- // add default dsn host
1435
- opts.hosts.unshift(applicationID + '-dsn.algolia.' + opts.tld);
2115
+ if (opts.protocol !== 'http:' && opts.protocol !== 'https:') {
2116
+ throw new Error('algoliasearch: protocol must be `http:` or `https:` (was `' + opts.protocol + '`)');
1436
2117
  }
1437
2118
 
1438
- opts.hosts = map(opts.hosts, function prependProtocol(host) {
1439
- return opts.protocol + '//' + host;
1440
- });
2119
+ // no hosts given, add defaults
2120
+ if (!opts.hosts) {
2121
+ this.hosts.read = [this.applicationID + '-dsn.algolia.net'].concat(defaultHosts);
2122
+ this.hosts.write = [this.applicationID + '.algolia.net'].concat(defaultHosts);
2123
+ } else {
2124
+ this.hosts.read = extend([], opts.hosts);
2125
+ this.hosts.write = extend([], opts.hosts);
2126
+ }
1441
2127
 
1442
- this.applicationID = applicationID;
1443
- this.apiKey = apiKey;
1444
- this.hosts = opts.hosts;
2128
+ // add protocol and lowercase hosts
2129
+ this.hosts.read = map(this.hosts.read, prepareHost(protocol));
2130
+ this.hosts.write = map(this.hosts.write, prepareHost(protocol));
2131
+ this.requestTimeout = timeout;
1445
2132
 
1446
- this.currentHostIndex = 0;
1447
- this.requestTimeout = opts.timeout;
1448
2133
  this.extraHeaders = [];
1449
2134
  this.cache = {};
1450
- this._request = _request;
2135
+
2136
+ this._ua = opts._ua;
2137
+ this._useCache = opts._useCache === undefined ? true : opts._useCache;
2138
+
2139
+ this._setTimeout = opts._setTimeout;
2140
+
2141
+ debug('init done, %j', this);
1451
2142
  }
1452
2143
 
1453
2144
  AlgoliaSearch.prototype = {
@@ -1455,20 +2146,21 @@ AlgoliaSearch.prototype = {
1455
2146
  * Delete an index
1456
2147
  *
1457
2148
  * @param indexName the name of index to delete
1458
- * @param callback the result callback with two arguments
2149
+ * @param callback the result callback called with two arguments
1459
2150
  * error: null or Error('message')
1460
2151
  * content: the server answer that contains the task ID
1461
2152
  */
1462
2153
  deleteIndex: function(indexName, callback) {
1463
2154
  return this._jsonRequest({ method: 'DELETE',
1464
2155
  url: '/1/indexes/' + encodeURIComponent(indexName),
2156
+ hostType: 'write',
1465
2157
  callback: callback });
1466
2158
  },
1467
2159
  /**
1468
2160
  * Move an existing index.
1469
2161
  * @param srcIndexName the name of index to copy.
1470
2162
  * @param dstIndexName the new index name that will contains a copy of srcIndexName (destination will be overriten if it already exist).
1471
- * @param callback the result callback with two arguments
2163
+ * @param callback the result callback called with two arguments
1472
2164
  * error: null or Error('message')
1473
2165
  * content: the server answer that contains the task ID
1474
2166
  */
@@ -1477,6 +2169,7 @@ AlgoliaSearch.prototype = {
1477
2169
  return this._jsonRequest({ method: 'POST',
1478
2170
  url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation',
1479
2171
  body: postObj,
2172
+ hostType: 'write',
1480
2173
  callback: callback });
1481
2174
 
1482
2175
  },
@@ -1484,7 +2177,7 @@ AlgoliaSearch.prototype = {
1484
2177
  * Copy an existing index.
1485
2178
  * @param srcIndexName the name of index to copy.
1486
2179
  * @param dstIndexName the new index name that will contains a copy of srcIndexName (destination will be overriten if it already exist).
1487
- * @param callback the result callback with two arguments
2180
+ * @param callback the result callback called with two arguments
1488
2181
  * error: null or Error('message')
1489
2182
  * content: the server answer that contains the task ID
1490
2183
  */
@@ -1493,13 +2186,14 @@ AlgoliaSearch.prototype = {
1493
2186
  return this._jsonRequest({ method: 'POST',
1494
2187
  url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation',
1495
2188
  body: postObj,
2189
+ hostType: 'write',
1496
2190
  callback: callback });
1497
2191
  },
1498
2192
  /**
1499
2193
  * Return last log entries.
1500
2194
  * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry).
1501
2195
  * @param length Specify the maximum number of entries to retrieve starting at offset. Maximum allowed value: 1000.
1502
- * @param callback the result callback with two arguments
2196
+ * @param callback the result callback called with two arguments
1503
2197
  * error: null or Error('message')
1504
2198
  * content: the server answer that contains the task ID
1505
2199
  */
@@ -1517,13 +2211,14 @@ AlgoliaSearch.prototype = {
1517
2211
 
1518
2212
  return this._jsonRequest({ method: 'GET',
1519
2213
  url: '/1/logs?offset=' + offset + '&length=' + length,
2214
+ hostType: 'read',
1520
2215
  callback: callback });
1521
2216
  },
1522
2217
  /*
1523
2218
  * List all existing indexes (paginated)
1524
2219
  *
1525
2220
  * @param page The page to retrieve, starting at 0.
1526
- * @param callback the result callback with two arguments
2221
+ * @param callback the result callback called with two arguments
1527
2222
  * error: null or Error('message')
1528
2223
  * content: the server answer with index list
1529
2224
  */
@@ -1538,6 +2233,7 @@ AlgoliaSearch.prototype = {
1538
2233
 
1539
2234
  return this._jsonRequest({ method: 'GET',
1540
2235
  url: '/1/indexes' + params,
2236
+ hostType: 'read',
1541
2237
  callback: callback });
1542
2238
  },
1543
2239
 
@@ -1553,90 +2249,142 @@ AlgoliaSearch.prototype = {
1553
2249
  /*
1554
2250
  * List all existing user keys with their associated ACLs
1555
2251
  *
1556
- * @param callback the result callback with two arguments
2252
+ * @param callback the result callback called with two arguments
1557
2253
  * error: null or Error('message')
1558
2254
  * content: the server answer with user keys list
1559
2255
  */
1560
2256
  listUserKeys: function(callback) {
1561
2257
  return this._jsonRequest({ method: 'GET',
1562
2258
  url: '/1/keys',
2259
+ hostType: 'read',
1563
2260
  callback: callback });
1564
2261
  },
1565
2262
  /*
1566
2263
  * Get ACL of a user key
1567
2264
  *
1568
2265
  * @param key
1569
- * @param callback the result callback with two arguments
2266
+ * @param callback the result callback called with two arguments
1570
2267
  * error: null or Error('message')
1571
2268
  * content: the server answer with user keys list
1572
2269
  */
1573
2270
  getUserKeyACL: function(key, callback) {
1574
2271
  return this._jsonRequest({ method: 'GET',
1575
2272
  url: '/1/keys/' + key,
2273
+ hostType: 'read',
1576
2274
  callback: callback });
1577
2275
  },
1578
2276
  /*
1579
2277
  * Delete an existing user key
1580
2278
  * @param key
1581
- * @param callback the result callback with two arguments
2279
+ * @param callback the result callback called with two arguments
1582
2280
  * error: null or Error('message')
1583
2281
  * content: the server answer with user keys list
1584
2282
  */
1585
2283
  deleteUserKey: function(key, callback) {
1586
2284
  return this._jsonRequest({ method: 'DELETE',
1587
2285
  url: '/1/keys/' + key,
2286
+ hostType: 'write',
1588
2287
  callback: callback });
1589
2288
  },
1590
2289
  /*
1591
2290
  * Add an existing user key
1592
2291
  *
1593
- * @param acls the list of ACL for this key. Defined by an array of strings that
1594
- * can contains the following values:
1595
- * - search: allow to search (https and http)
1596
- * - addObject: allows to add/update an object in the index (https only)
1597
- * - deleteObject : allows to delete an existing object (https only)
1598
- * - deleteIndex : allows to delete index content (https only)
1599
- * - settings : allows to get index settings (https only)
1600
- * - editSettings : allows to change index settings (https only)
1601
- * @param callback the result callback with two arguments
1602
- * error: null or Error('message')
1603
- * content: the server answer with user keys list
2292
+ * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that
2293
+ * can contains the following values:
2294
+ * - search: allow to search (https and http)
2295
+ * - addObject: allows to add/update an object in the index (https only)
2296
+ * - deleteObject : allows to delete an existing object (https only)
2297
+ * - deleteIndex : allows to delete index content (https only)
2298
+ * - settings : allows to get index settings (https only)
2299
+ * - editSettings : allows to change index settings (https only)
2300
+ * @param {Object} [params] - Optionnal parameters to set for the key
2301
+ * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key)
2302
+ * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour
2303
+ * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call
2304
+ * @param {string[]} params.indexes - Allowed targeted indexes for this key
2305
+ * @param {Function} callback - The result callback called with two arguments
2306
+ * error: null or Error('message')
2307
+ * content: the server answer with user keys list
2308
+ * @return {Promise|undefined} Returns a promise if no callback given
1604
2309
  */
1605
- addUserKey: function(acls, callback) {
1606
- return this.addUserKeyWithValidity(acls, {
1607
- validity: 0,
1608
- maxQueriesPerIPPerHour: 0,
1609
- maxHitsPerQuery: 0
1610
- }, callback);
2310
+ addUserKey: function(acls, params, callback) {
2311
+ if (arguments.length === 1 || typeof params === 'function') {
2312
+ callback = params;
2313
+ params = null;
2314
+ }
2315
+
2316
+ var postObj = {
2317
+ acl: acls
2318
+ };
2319
+
2320
+ if (params) {
2321
+ postObj.validity = params.validity;
2322
+ postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
2323
+ postObj.maxHitsPerQuery = params.maxHitsPerQuery;
2324
+ postObj.indexes = params.indexes;
2325
+ }
2326
+
2327
+ return this._jsonRequest({
2328
+ method: 'POST',
2329
+ url: '/1/keys',
2330
+ body: postObj,
2331
+ hostType: 'write',
2332
+ callback: callback
2333
+ });
1611
2334
  },
1612
- /*
2335
+ /**
1613
2336
  * Add an existing user key
1614
- *
1615
- * @param acls the list of ACL for this key. Defined by an array of strings that
1616
- * can contains the following values:
1617
- * - search: allow to search (https and http)
1618
- * - addObject: allows to add/update an object in the index (https only)
1619
- * - deleteObject : allows to delete an existing object (https only)
1620
- * - deleteIndex : allows to delete index content (https only)
1621
- * - settings : allows to get index settings (https only)
1622
- * - editSettings : allows to change index settings (https only)
1623
- * @param params.validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key)
1624
- * @param params.maxQueriesPerIPPerHour Specify the maximum number of API calls allowed from an IP address per hour.
1625
- * @param params.maxHitsPerQuery Specify the maximum number of hits this API key can retrieve in one call.
1626
- * @param callback the result callback with two arguments
1627
- * error: null or Error('message')
1628
- * content: the server answer with user keys list
2337
+ * @deprecated Please use client.addUserKey()
1629
2338
  */
1630
- addUserKeyWithValidity: function(acls, params, callback) {
1631
- var aclsObject = {};
1632
- aclsObject.acl = acls;
1633
- aclsObject.validity = params.validity;
1634
- aclsObject.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
1635
- aclsObject.maxHitsPerQuery = params.maxHitsPerQuery;
1636
- return this._jsonRequest({ method: 'POST',
1637
- url: '/1/keys',
1638
- body: aclsObject,
1639
- callback: callback });
2339
+ addUserKeyWithValidity: deprecate(function(acls, params, callback) {
2340
+ return this.addUserKey(acls, params, callback);
2341
+ }, deprecatedMessage('client.addUserKeyWithValidity()', 'client.addUserKey()')),
2342
+
2343
+ /**
2344
+ * Update an existing user key
2345
+ * @param {string} key - The key to update
2346
+ * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that
2347
+ * can contains the following values:
2348
+ * - search: allow to search (https and http)
2349
+ * - addObject: allows to add/update an object in the index (https only)
2350
+ * - deleteObject : allows to delete an existing object (https only)
2351
+ * - deleteIndex : allows to delete index content (https only)
2352
+ * - settings : allows to get index settings (https only)
2353
+ * - editSettings : allows to change index settings (https only)
2354
+ * @param {Object} [params] - Optionnal parameters to set for the key
2355
+ * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key)
2356
+ * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour
2357
+ * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call
2358
+ * @param {string[]} params.indexes - Allowed targeted indexes for this key
2359
+ * @param {Function} callback - The result callback called with two arguments
2360
+ * error: null or Error('message')
2361
+ * content: the server answer with user keys list
2362
+ * @return {Promise|undefined} Returns a promise if no callback given
2363
+ */
2364
+ updateUserKey: function(key, acls, params, callback) {
2365
+ if (arguments.length === 2 || typeof params === 'function') {
2366
+ callback = params;
2367
+ params = null;
2368
+ }
2369
+
2370
+ var putObj = {
2371
+ acl: acls
2372
+ };
2373
+
2374
+ if (params) {
2375
+ putObj.validity = params.validity;
2376
+ putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
2377
+ putObj.maxHitsPerQuery = params.maxHitsPerQuery;
2378
+ putObj.indexes = params.indexes;
2379
+ }
2380
+
2381
+ return this._jsonRequest({
2382
+ method: 'PUT',
2383
+ url: '/1/keys/' + key,
2384
+ body: putObj,
2385
+ hostType: 'write',
2386
+ callback: callback
2387
+ });
1640
2388
  },
1641
2389
 
1642
2390
  /**
@@ -1659,7 +2407,8 @@ AlgoliaSearch.prototype = {
1659
2407
  }
1660
2408
  tags = strTags.join(',');
1661
2409
  }
1662
- this.tagFilters = tags;
2410
+
2411
+ this.securityTags = tags;
1663
2412
  },
1664
2413
 
1665
2414
  /**
@@ -1670,59 +2419,41 @@ AlgoliaSearch.prototype = {
1670
2419
  this.userToken = userToken;
1671
2420
  },
1672
2421
 
1673
- /*
2422
+ /**
1674
2423
  * Initialize a new batch of search queries
2424
+ * @deprecated use client.search()
1675
2425
  */
1676
- startQueriesBatch: function() {
1677
- this.batch = [];
1678
- },
1679
- /*
2426
+ startQueriesBatch: deprecate(function() {
2427
+ this._batch = [];
2428
+ }, deprecatedMessage('client.startQueriesBatch()', 'client.search()')),
2429
+
2430
+ /**
1680
2431
  * Add a search query in the batch
1681
- *
1682
- * @param query the full text query
1683
- * @param args (optional) if set, contains an object with query parameters:
1684
- * - attributes: an array of object attribute names to retrieve
1685
- * (if not set all attributes are retrieve)
1686
- * - attributesToHighlight: an array of object attribute names to highlight
1687
- * (if not set indexed attributes are highlighted)
1688
- * - minWordSizefor1Typo: the minimum number of characters to accept one typo.
1689
- * Defaults to 3.
1690
- * - minWordSizefor2Typos: the minimum number of characters to accept two typos.
1691
- * Defaults to 7.
1692
- * - getRankingInfo: if set, the result hits will contain ranking information in
1693
- * _rankingInfo attribute
1694
- * - page: (pagination parameter) page to retrieve (zero base). Defaults to 0.
1695
- * - hitsPerPage: (pagination parameter) number of hits per page. Defaults to 10.
2432
+ * @deprecated use client.search()
1696
2433
  */
1697
- addQueryInBatch: function(indexName, query, args) {
1698
- var params = 'query=' + encodeURIComponent(query);
1699
- if (!this._isUndefined(args) && args !== null) {
1700
- params = this._getSearchParams(args, params);
1701
- }
1702
- this.batch.push({ indexName: indexName, params: params });
1703
- },
1704
- /*
1705
- * Clear all queries in cache
2434
+ addQueryInBatch: deprecate(function(indexName, query, args) {
2435
+ this._batch.push({
2436
+ indexName: indexName,
2437
+ query: query,
2438
+ params: args
2439
+ });
2440
+ }, deprecatedMessage('client.addQueryInBatch()', 'client.search()')),
2441
+
2442
+ /**
2443
+ * Clear all queries in client's cache
2444
+ * @return undefined
1706
2445
  */
1707
2446
  clearCache: function() {
1708
2447
  this.cache = {};
1709
2448
  },
1710
- /*
2449
+
2450
+ /**
1711
2451
  * Launch the batch of queries using XMLHttpRequest.
1712
- * (Optimized for browser using a POST query to minimize number of OPTIONS queries)
1713
- *
1714
- * @param callback the function that will receive results
2452
+ * @deprecated use client.search()
1715
2453
  */
1716
- sendQueriesBatch: function(callback) {
1717
- var as = this;
1718
- var params = {requests: []};
1719
-
1720
- for (var i = 0; i < as.batch.length; ++i) {
1721
- params.requests.push(as.batch[i]);
1722
- }
1723
-
1724
- return this._sendQueriesBatch(params, callback);
1725
- },
2454
+ sendQueriesBatch: deprecate(function(callback) {
2455
+ return this.search(this._batch, callback);
2456
+ }, deprecatedMessage('client.sendQueriesBatch()', 'client.search()')),
1726
2457
 
1727
2458
  /**
1728
2459
  * Set the number of milliseconds a request can take before automatically being terminated.
@@ -1735,6 +2466,53 @@ AlgoliaSearch.prototype = {
1735
2466
  }
1736
2467
  },
1737
2468
 
2469
+ /**
2470
+ * Search through multiple indices at the same time
2471
+ * @param {Object[]} queries An array of queries you want to run.
2472
+ * @param {string} queries[].indexName The index name you want to target
2473
+ * @param {string} [queries[].query] The query to issue on this index. Can also be passed into `params`
2474
+ * @param {Object} queries[].params Any search param like hitsPerPage, ..
2475
+ * @param {Function} callback Callback to be called
2476
+ * @return {Promise|undefined} Returns a promise if no callback given
2477
+ */
2478
+ search: function(queries, callback) {
2479
+ var client = this;
2480
+
2481
+ var postObj = {
2482
+ requests: map(queries, function prepareRequest(query) {
2483
+ var params = '';
2484
+
2485
+ // allow query.query
2486
+ // so we are mimicing the index.search(query, params) method
2487
+ // {indexName:, query:, params:}
2488
+ if (query.query !== undefined) {
2489
+ params += 'query=' + encodeURIComponent(query.query)
2490
+ }
2491
+
2492
+ return {
2493
+ indexName: query.indexName,
2494
+ params: client._getSearchParams(query.params, params)
2495
+ };
2496
+ })
2497
+ };
2498
+
2499
+ return this._jsonRequest({
2500
+ cache: this.cache,
2501
+ method: 'POST',
2502
+ url: '/1/indexes/*/queries',
2503
+ body: postObj,
2504
+ hostType: 'read',
2505
+ callback: callback
2506
+ });
2507
+ },
2508
+
2509
+ // environment specific methods
2510
+ destroy: notImplemented,
2511
+ enableRateLimitForward: notImplemented,
2512
+ disableRateLimitForward: notImplemented,
2513
+ useSecuredAPIKey: notImplemented,
2514
+ disableSecuredAPIKey: notImplemented,
2515
+ generateSecuredApiKey: notImplemented,
1738
2516
  /*
1739
2517
  * Index class constructor.
1740
2518
  * You should not use this method directly but use initIndex() function
@@ -1751,11 +2529,11 @@ AlgoliaSearch.prototype = {
1751
2529
  /**
1752
2530
  * Add an extra field to the HTTP request
1753
2531
  *
1754
- * @param key the header field name
2532
+ * @param name the header field name
1755
2533
  * @param value the header field value
1756
2534
  */
1757
- setExtraHeader: function(key, value) {
1758
- this.extraHeaders.push({ key: key, value: value});
2535
+ setExtraHeader: function(name, value) {
2536
+ this.extraHeaders.push({ name: name.toLowerCase(), value: value});
1759
2537
  },
1760
2538
 
1761
2539
  _sendQueriesBatch: function(params, callback) {
@@ -1763,6 +2541,7 @@ AlgoliaSearch.prototype = {
1763
2541
  method: 'POST',
1764
2542
  url: '/1/indexes/*/queries',
1765
2543
  body: params,
2544
+ hostType: 'read',
1766
2545
  fallback: {
1767
2546
  method: 'GET',
1768
2547
  url: '/1/indexes/*',
@@ -1782,77 +2561,88 @@ AlgoliaSearch.prototype = {
1782
2561
  * Wrapper that try all hosts to maximize the quality of service
1783
2562
  */
1784
2563
  _jsonRequest: function(opts) {
1785
- // handle opts.fallback, automatically use fallback (JSONP in browser plugins, wrapped with $plugin-promises)
1786
- // so if an error occurs and max tries => use fallback
1787
- // set tries to 0 again
1788
- // if fallback used and no more tries, return error
1789
- // fallback parameters are in opts.fallback
1790
- // call request.fallback or request accordingly, same promise chain otherwise
1791
- // put callback& params in front if problem
2564
+ var requestDebug = require(5)('algoliasearch:' + opts.url);
2565
+
2566
+ var body;
1792
2567
  var cache = opts.cache;
1793
- var cacheID = opts.url;
1794
2568
  var client = this;
1795
2569
  var tries = 0;
2570
+ var usingFallback = false;
1796
2571
 
1797
- // as we use POST requests to pass parameters (like query='aa'),
1798
- // the cacheID must be different between calls
1799
2572
  if (opts.body !== undefined) {
1800
- cacheID += '_body_' + JSON.stringify(opts.body);
2573
+ body = JSON.stringify(opts.body);
1801
2574
  }
1802
2575
 
2576
+ requestDebug('request start');
2577
+
1803
2578
  function doRequest(requester, reqOpts) {
2579
+ var cacheID;
2580
+
2581
+ if (client._useCache) {
2582
+ cacheID = opts.url;
2583
+ }
2584
+
2585
+ // as we sometime use POST requests to pass parameters (like query='aa'),
2586
+ // the cacheID must also include the body to be different between calls
2587
+ if (client._useCache && body) {
2588
+ cacheID += '_body_' + reqOpts.body;
2589
+ }
2590
+
1804
2591
  // handle cache existence
1805
- if (cache && cache[cacheID] !== undefined) {
1806
- return client._request.resolve(cache[cacheID]);
2592
+ if (client._useCache && cache && cache[cacheID] !== undefined) {
2593
+ requestDebug('serving response from cache');
2594
+ return client._promise.resolve(cache[cacheID]);
1807
2595
  }
1808
2596
 
1809
- if (tries >= client.hosts.length) {
1810
- if (!opts.fallback || requester === client._request.fallback) {
2597
+ if (tries >= client.hosts[opts.hostType].length) {
2598
+ if (!opts.fallback || !client._request.fallback || usingFallback) {
1811
2599
  // could not get a response even using the fallback if one was available
1812
- return client._request.reject(new Error(
2600
+ return client._promise.reject(new Error(
1813
2601
  'Cannot connect to the AlgoliaSearch API.' +
1814
2602
  ' Send an email to support@algolia.com to report and resolve the issue.'
1815
2603
  ));
1816
2604
  }
1817
2605
 
2606
+ // let's try the fallback starting from here
1818
2607
  tries = 0;
2608
+
2609
+ // method, url and body are fallback dependent
1819
2610
  reqOpts.method = opts.fallback.method;
1820
2611
  reqOpts.url = opts.fallback.url;
1821
- reqOpts.body = opts.fallback.body;
2612
+ reqOpts.jsonBody = opts.fallback.body;
2613
+ if (reqOpts.jsonBody) {
2614
+ reqOpts.body = JSON.stringify(opts.fallback.body);
2615
+ }
2616
+
1822
2617
  reqOpts.timeout = client.requestTimeout * (tries + 1);
1823
- client.currentHostIndex = 0;
1824
- client.forceFallback = true;
2618
+ client.hostIndex[opts.hostType] = 0;
2619
+ client.useFallback = true; // now we will only use JSONP, even on future requests
2620
+ usingFallback = true; // the current request is now using fallback
1825
2621
  return doRequest(client._request.fallback, reqOpts);
1826
2622
  }
1827
2623
 
1828
- var url = reqOpts.url;
1829
-
1830
- url += (url.indexOf('?') === -1 ? '?' : '&') + 'X-Algolia-API-Key=' + client.apiKey;
1831
- url += '&X-Algolia-Application-Id=' + client.applicationID;
1832
-
1833
- if (client.userToken) {
1834
- url += '&X-Algolia-UserToken=' + encodeURIComponent(client.userToken);
1835
- }
1836
-
1837
- if (client.tagFilters) {
1838
- url += '&X-Algolia-TagFilters=' + encodeURIComponent(client.tagFilters);
1839
- }
1840
-
1841
- for (var i = 0; i < client.extraHeaders.length; ++i) {
1842
- url += '&' + client.extraHeaders[i].key + '=' + client.extraHeaders[i].value;
1843
- }
1844
-
1845
- return requester(client.hosts[client.currentHostIndex] + url, {
1846
- body: reqOpts.body,
1847
- method: reqOpts.method,
1848
- timeout: reqOpts.timeout
1849
- })
2624
+ // `requester` is any of this._request or this._request.fallback
2625
+ // thus it needs to be called using the client as context
2626
+ return requester.call(client,
2627
+ // http(s)://currenthost/url(?qs)
2628
+ client.hosts[opts.hostType][client.hostIndex[opts.hostType]] + reqOpts.url, {
2629
+ body: body,
2630
+ jsonBody: opts.body,
2631
+ method: reqOpts.method,
2632
+ headers: client._computeRequestHeaders(),
2633
+ timeout: reqOpts.timeout,
2634
+ debug: requestDebug
2635
+ }
2636
+ )
1850
2637
  .then(function success(httpResponse) {
1851
2638
  // timeout case, retry immediately
1852
2639
  if (httpResponse instanceof Error) {
2640
+ requestDebug('error: %s', httpResponse.message);
1853
2641
  return retryRequest();
1854
2642
  }
1855
2643
 
2644
+ requestDebug('received response: %j', httpResponse);
2645
+
1856
2646
  var status =
1857
2647
  // When in browser mode, using XDR or JSONP
1858
2648
  // We rely on our own API response `status`, only
@@ -1874,7 +2664,7 @@ AlgoliaSearch.prototype = {
1874
2664
  var ok = status === 200 || status === 201;
1875
2665
  var retry = !ok && Math.floor(status / 100) !== 4 && Math.floor(status / 100) !== 1;
1876
2666
 
1877
- if (ok && cache) {
2667
+ if (client._useCache && ok && cache) {
1878
2668
  cache[cacheID] = httpResponse.body;
1879
2669
  }
1880
2670
 
@@ -1890,24 +2680,38 @@ AlgoliaSearch.prototype = {
1890
2680
  httpResponse.body && httpResponse.body.message || 'Unknown error'
1891
2681
  );
1892
2682
 
1893
- return client._request.reject(unrecoverableError);
2683
+ return client._promise.reject(unrecoverableError);
1894
2684
  }, tryFallback);
1895
2685
 
1896
2686
  function retryRequest() {
1897
- client.currentHostIndex = ++client.currentHostIndex % client.hosts.length;
2687
+ client.hostIndex[opts.hostType] = ++client.hostIndex[opts.hostType] % client.hosts[opts.hostType].length;
1898
2688
  tries += 1;
1899
2689
  reqOpts.timeout = client.requestTimeout * (tries + 1);
1900
2690
  return doRequest(requester, reqOpts);
1901
2691
  }
1902
2692
 
1903
- function tryFallback() {
2693
+ function tryFallback(err) {
2694
+ // error cases:
2695
+ // While not in fallback mode:
2696
+ // - CORS not supported
2697
+ // - network error
2698
+ // While in fallback mode:
2699
+ // - timeout
2700
+ // - network error
2701
+ // - badly formatted JSONP (script loaded, did not call our callback)
2702
+ // In both cases:
2703
+ // - uncaught exception occurs (TypeError)
2704
+ requestDebug('error: %s, stack: %s', err.message, err.stack);
2705
+
2706
+ // we were not using the fallback, try now
1904
2707
  // if we are switching to fallback right now, set tries to maximum
1905
- if (!client.forceFallback) {
1906
- // next time doRequest is called, simulate we tried all hosts
1907
- tries = client.hosts.length;
2708
+ if (!client.useFallback) {
2709
+ // next time doRequest is called, simulate we tried all hosts,
2710
+ // this will force to use the fallback
2711
+ tries = client.hosts[opts.hostType].length;
1908
2712
  } else {
1909
2713
  // we were already using the fallback, but something went wrong (script error)
1910
- client.currentHostIndex = ++client.currentHostIndex % client.hosts.length;
2714
+ client.hostIndex[opts.hostType] = ++client.hostIndex[opts.hostType] % client.hosts[opts.hostType].length;
1911
2715
  tries += 1;
1912
2716
  }
1913
2717
 
@@ -1916,14 +2720,16 @@ AlgoliaSearch.prototype = {
1916
2720
  }
1917
2721
 
1918
2722
  // we can use a fallback if forced AND fallback parameters are available
1919
- var useFallback = client.forceFallback && opts.fallback;
2723
+ var useFallback = client.useFallback && opts.fallback;
1920
2724
  var requestOptions = useFallback ? opts.fallback : opts;
1921
2725
 
1922
2726
  var promise = doRequest(
2727
+ // set the requester
1923
2728
  useFallback ? client._request.fallback : client._request, {
1924
2729
  url: requestOptions.url,
1925
2730
  method: requestOptions.method,
1926
- body: requestOptions.body,
2731
+ body: body,
2732
+ jsonBody: opts.body,
1927
2733
  timeout: client.requestTimeout * (tries + 1)
1928
2734
  }
1929
2735
  );
@@ -1932,13 +2738,13 @@ AlgoliaSearch.prototype = {
1932
2738
  // either we are using promises
1933
2739
  if (opts.callback) {
1934
2740
  promise.then(function okCb(content) {
1935
- process.nextTick(function() {
2741
+ exitPromise(function() {
1936
2742
  opts.callback(null, content);
1937
- });
2743
+ }, client._setTimeout || setTimeout);
1938
2744
  }, function nookCb(err) {
1939
- process.nextTick(function() {
2745
+ exitPromise(function() {
1940
2746
  opts.callback(err);
1941
- });
2747
+ }, client._setTimeout || setTimeout);
1942
2748
  });
1943
2749
  } else {
1944
2750
  return promise;
@@ -1960,8 +2766,33 @@ AlgoliaSearch.prototype = {
1960
2766
  }
1961
2767
  return params;
1962
2768
  },
2769
+
1963
2770
  _isUndefined: function(obj) {
1964
2771
  return obj === void 0;
2772
+ },
2773
+
2774
+ _computeRequestHeaders: function() {
2775
+ var requestHeaders = {
2776
+ 'x-algolia-api-key': this.apiKey,
2777
+ 'x-algolia-application-id': this.applicationID,
2778
+ 'x-user-agent': this._ua
2779
+ };
2780
+
2781
+ if (this.userToken) {
2782
+ requestHeaders['x-algolia-usertoken'] = this.userToken;
2783
+ }
2784
+
2785
+ if (this.securityTags) {
2786
+ requestHeaders['x-algolia-tagfilters'] = this.securityTags;
2787
+ }
2788
+
2789
+ if (this.extraHeaders) {
2790
+ foreach(this.extraHeaders, function addToRequestHeaders(header) {
2791
+ requestHeaders[header.name] = header.value;
2792
+ });
2793
+ }
2794
+
2795
+ return requestHeaders;
1965
2796
  }
1966
2797
  };
1967
2798
 
@@ -1982,7 +2813,7 @@ AlgoliaSearch.prototype.Index.prototype = {
1982
2813
  * @param content contains the javascript object to add inside the index
1983
2814
  * @param objectID (optional) an objectID you want to attribute to this object
1984
2815
  * (if the attribute already exist the old object will be overwrite)
1985
- * @param callback (optional) the result callback with two arguments:
2816
+ * @param callback (optional) the result callback called with two arguments:
1986
2817
  * error: null or Error('message')
1987
2818
  * content: the server answer that contains 3 elements: createAt, taskId and objectID
1988
2819
  */
@@ -2001,6 +2832,7 @@ AlgoliaSearch.prototype.Index.prototype = {
2001
2832
  url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + // create
2002
2833
  (objectID !== undefined ? '/' + encodeURIComponent(objectID) : ''), // update or create
2003
2834
  body: content,
2835
+ hostType: 'write',
2004
2836
  callback: callback
2005
2837
  });
2006
2838
  },
@@ -2008,7 +2840,7 @@ AlgoliaSearch.prototype.Index.prototype = {
2008
2840
  * Add several objects
2009
2841
  *
2010
2842
  * @param objects contains an array of objects to add
2011
- * @param callback (optional) the result callback with two arguments:
2843
+ * @param callback (optional) the result callback called with two arguments:
2012
2844
  * error: null or Error('message')
2013
2845
  * content: the server answer that updateAt and taskID
2014
2846
  */
@@ -2021,16 +2853,17 @@ AlgoliaSearch.prototype.Index.prototype = {
2021
2853
  postObj.requests.push(request);
2022
2854
  }
2023
2855
  return this.as._jsonRequest({ method: 'POST',
2024
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
2025
- body: postObj,
2026
- callback: callback });
2856
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
2857
+ body: postObj,
2858
+ hostType: 'write',
2859
+ callback: callback });
2027
2860
  },
2028
2861
  /*
2029
2862
  * Get an object from this index
2030
2863
  *
2031
2864
  * @param objectID the unique identifier of the object to retrieve
2032
2865
  * @param attrs (optional) if set, contains the array of attribute names to retrieve
2033
- * @param callback (optional) the result callback with two arguments
2866
+ * @param callback (optional) the result callback called with two arguments
2034
2867
  * error: null or Error('message')
2035
2868
  * content: the object to retrieve or the error message if a failure occured
2036
2869
  */
@@ -2056,6 +2889,33 @@ AlgoliaSearch.prototype.Index.prototype = {
2056
2889
  return this.as._jsonRequest({
2057
2890
  method: 'GET',
2058
2891
  url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID) + params,
2892
+ hostType: 'read',
2893
+ callback: callback
2894
+ });
2895
+ },
2896
+
2897
+ /*
2898
+ * Get several objects from this index
2899
+ *
2900
+ * @param objectIDs the array of unique identifier of objects to retrieve
2901
+ */
2902
+ getObjects: function(objectIDs, callback) {
2903
+ var indexObj = this;
2904
+
2905
+ var body = {
2906
+ requests: map(objectIDs, function prepareRequest(objectID) {
2907
+ return {
2908
+ 'indexName': indexObj.indexName,
2909
+ 'objectID': objectID
2910
+ };
2911
+ })
2912
+ };
2913
+
2914
+ return this.as._jsonRequest({
2915
+ method: 'POST',
2916
+ url: '/1/indexes/*/objects',
2917
+ hostType: 'read',
2918
+ body: body,
2059
2919
  callback: callback
2060
2920
  });
2061
2921
  },
@@ -2065,22 +2925,23 @@ AlgoliaSearch.prototype.Index.prototype = {
2065
2925
  *
2066
2926
  * @param partialObject contains the javascript attributes to override, the
2067
2927
  * object must contains an objectID attribute
2068
- * @param callback (optional) the result callback with two arguments:
2928
+ * @param callback (optional) the result callback called with two arguments:
2069
2929
  * error: null or Error('message')
2070
2930
  * content: the server answer that contains 3 elements: createAt, taskId and objectID
2071
2931
  */
2072
2932
  partialUpdateObject: function(partialObject, callback) {
2073
2933
  var indexObj = this;
2074
2934
  return this.as._jsonRequest({ method: 'POST',
2075
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(partialObject.objectID) + '/partial',
2076
- body: partialObject,
2077
- callback: callback });
2935
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(partialObject.objectID) + '/partial',
2936
+ body: partialObject,
2937
+ hostType: 'write',
2938
+ callback: callback });
2078
2939
  },
2079
2940
  /*
2080
2941
  * Partially Override the content of several objects
2081
2942
  *
2082
2943
  * @param objects contains an array of objects to update (each object must contains a objectID attribute)
2083
- * @param callback (optional) the result callback with two arguments:
2944
+ * @param callback (optional) the result callback called with two arguments:
2084
2945
  * error: null or Error('message')
2085
2946
  * content: the server answer that updateAt and taskID
2086
2947
  */
@@ -2094,30 +2955,32 @@ AlgoliaSearch.prototype.Index.prototype = {
2094
2955
  postObj.requests.push(request);
2095
2956
  }
2096
2957
  return this.as._jsonRequest({ method: 'POST',
2097
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
2098
- body: postObj,
2099
- callback: callback });
2958
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
2959
+ body: postObj,
2960
+ hostType: 'write',
2961
+ callback: callback });
2100
2962
  },
2101
2963
  /*
2102
2964
  * Override the content of object
2103
2965
  *
2104
2966
  * @param object contains the javascript object to save, the object must contains an objectID attribute
2105
- * @param callback (optional) the result callback with two arguments:
2967
+ * @param callback (optional) the result callback called with two arguments:
2106
2968
  * error: null or Error('message')
2107
2969
  * content: the server answer that updateAt and taskID
2108
2970
  */
2109
2971
  saveObject: function(object, callback) {
2110
2972
  var indexObj = this;
2111
2973
  return this.as._jsonRequest({ method: 'PUT',
2112
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(object.objectID),
2113
- body: object,
2114
- callback: callback });
2974
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(object.objectID),
2975
+ body: object,
2976
+ hostType: 'write',
2977
+ callback: callback });
2115
2978
  },
2116
2979
  /*
2117
2980
  * Override the content of several objects
2118
2981
  *
2119
2982
  * @param objects contains an array of objects to update (each object must contains a objectID attribute)
2120
- * @param callback (optional) the result callback with two arguments:
2983
+ * @param callback (optional) the result callback called with two arguments:
2121
2984
  * error: null or Error('message')
2122
2985
  * content: the server answer that updateAt and taskID
2123
2986
  */
@@ -2131,15 +2994,16 @@ AlgoliaSearch.prototype.Index.prototype = {
2131
2994
  postObj.requests.push(request);
2132
2995
  }
2133
2996
  return this.as._jsonRequest({ method: 'POST',
2134
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
2135
- body: postObj,
2136
- callback: callback });
2997
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
2998
+ body: postObj,
2999
+ hostType: 'write',
3000
+ callback: callback });
2137
3001
  },
2138
3002
  /*
2139
3003
  * Delete an object from the index
2140
3004
  *
2141
3005
  * @param objectID the unique identifier of object to delete
2142
- * @param callback (optional) the result callback with two arguments:
3006
+ * @param callback (optional) the result callback called with two arguments:
2143
3007
  * error: null or Error('message')
2144
3008
  * content: the server answer that contains 3 elements: createAt, taskId and objectID
2145
3009
  */
@@ -2151,13 +3015,118 @@ AlgoliaSearch.prototype.Index.prototype = {
2151
3015
  return callback(err);
2152
3016
  }
2153
3017
 
2154
- return this.as._request.reject(err);
3018
+ return this.as._promise.reject(err);
2155
3019
  }
2156
3020
 
2157
3021
  var indexObj = this;
2158
3022
  return this.as._jsonRequest({ method: 'DELETE',
2159
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID),
2160
- callback: callback });
3023
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID),
3024
+ hostType: 'write',
3025
+ callback: callback });
3026
+ },
3027
+ /*
3028
+ * Delete several objects from an index
3029
+ *
3030
+ * @param objectIDs contains an array of objectID to delete
3031
+ * @param callback (optional) the result callback called with two arguments:
3032
+ * error: null or Error('message')
3033
+ * content: the server answer that contains 3 elements: createAt, taskId and objectID
3034
+ */
3035
+ deleteObjects: function(objectIDs, callback) {
3036
+ var indexObj = this;
3037
+ var postObj = {
3038
+ requests: map(objectIDs, function prepareRequest(objectID) {
3039
+ return {
3040
+ action: 'deleteObject',
3041
+ objectID: objectID,
3042
+ body: {
3043
+ objectID: objectID
3044
+ }
3045
+ };
3046
+ })
3047
+ };
3048
+
3049
+ return this.as._jsonRequest({
3050
+ method: 'POST',
3051
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
3052
+ body: postObj,
3053
+ hostType: 'write',
3054
+ callback: callback
3055
+ });
3056
+ },
3057
+ /*
3058
+ * Delete all objects matching a query
3059
+ *
3060
+ * @param query the query string
3061
+ * @param params the optional query parameters
3062
+ * @param callback (optional) the result callback called with one argument
3063
+ * error: null or Error('message')
3064
+ */
3065
+ deleteByQuery: function(query, params, callback) {
3066
+ var indexObj = this;
3067
+ var client = indexObj.as;
3068
+
3069
+ if (arguments.length === 1 || typeof params === 'function') {
3070
+ callback = params;
3071
+ params = {};
3072
+ }
3073
+
3074
+ params.attributesToRetrieve = 'objectID';
3075
+ params.hitsPerPage = 1000;
3076
+
3077
+ // when deleting, we should never use cache to get the
3078
+ // search results
3079
+ this.clearCache();
3080
+
3081
+ // there's a problem in how we use the promise chain,
3082
+ // see how waitTask is done
3083
+ var promise = this
3084
+ .search(query, params)
3085
+ .then(stopOrDelete);
3086
+
3087
+ function stopOrDelete(searchContent) {
3088
+ // stop here
3089
+ if (searchContent.nbHits === 0) {
3090
+ // return indexObj.as._request.resolve();
3091
+ return searchContent;
3092
+ }
3093
+
3094
+ // continue and do a recursive call
3095
+ var objectIDs = map(searchContent.hits, function getObjectID(object) {
3096
+ return object.objectID;
3097
+ });
3098
+
3099
+ return indexObj
3100
+ .deleteObjects(objectIDs)
3101
+ .then(waitTask)
3102
+ .then(deleteByQuery);
3103
+ }
3104
+
3105
+ function waitTask(deleteObjectsContent) {
3106
+ return indexObj.waitTask(deleteObjectsContent.taskID);
3107
+ }
3108
+
3109
+ function deleteByQuery() {
3110
+ return indexObj.deleteByQuery(query, params);
3111
+ }
3112
+
3113
+ if (!callback) {
3114
+ return promise;
3115
+ }
3116
+
3117
+ promise.then(success, failure);
3118
+
3119
+ function success() {
3120
+ exitPromise(function() {
3121
+ callback(null);
3122
+ }, client._setTimeout || setTimeout);
3123
+ }
3124
+
3125
+ function failure(err) {
3126
+ exitPromise(function() {
3127
+ callback(err);
3128
+ }, client._setTimeout || setTimeout);
3129
+ }
2161
3130
  },
2162
3131
  /*
2163
3132
  * Search inside the index using XMLHttpRequest request (Using a POST query to
@@ -2223,11 +3192,19 @@ AlgoliaSearch.prototype.Index.prototype = {
2223
3192
  * one is kept and others are removed.
2224
3193
  * - restrictSearchableAttributes: List of attributes you want to use for textual search (must be a subset of the attributesToIndex index setting)
2225
3194
  * either comma separated or as an array
2226
- * @param callback the result callback with two arguments:
3195
+ * @param callback the result callback called with two arguments:
2227
3196
  * error: null or Error('message'). If false, the content contains the error.
2228
3197
  * content: the server answer that contains the list of results.
2229
3198
  */
2230
3199
  search: function(query, args, callback) {
3200
+ // warn V2 users on how to search
3201
+ if (typeof query === 'function' && typeof args === 'object' ||
3202
+ typeof callback === 'object') {
3203
+ // .search(query, params, cb)
3204
+ // .search(cb, params)
3205
+ throw new Error('algoliasearch: index.search usage is index.search(query, params, cb)');
3206
+ }
3207
+
2231
3208
  if (arguments.length === 0 || typeof query === 'function') {
2232
3209
  // .search(), .search(cb)
2233
3210
  callback = query;
@@ -2253,6 +3230,7 @@ AlgoliaSearch.prototype.Index.prototype = {
2253
3230
  }
2254
3231
 
2255
3232
  if (args !== undefined) {
3233
+ // `_getSearchParams` will augment params, do not be fooled by the = versus += from previous if
2256
3234
  params = this.as._getSearchParams(args, params);
2257
3235
  }
2258
3236
 
@@ -2265,7 +3243,7 @@ AlgoliaSearch.prototype.Index.prototype = {
2265
3243
  * @param page Pagination parameter used to select the page to retrieve.
2266
3244
  * Page is zero-based and defaults to 0. Thus, to retrieve the 10th page you need to set page=9
2267
3245
  * @param hitsPerPage: Pagination parameter used to select the number of hits per page. Defaults to 1000.
2268
- * @param callback the result callback with two arguments:
3246
+ * @param callback the result callback called with two arguments:
2269
3247
  * error: null or Error('message'). If false, the content contains the error.
2270
3248
  * content: the server answer that contains the list of results.
2271
3249
  */
@@ -2282,8 +3260,9 @@ AlgoliaSearch.prototype.Index.prototype = {
2282
3260
  params += '&hitsPerPage=' + hitsPerPage;
2283
3261
  }
2284
3262
  return this.as._jsonRequest({ method: 'GET',
2285
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse' + params,
2286
- callback: callback });
3263
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse' + params,
3264
+ hostType: 'read',
3265
+ callback: callback });
2287
3266
  },
2288
3267
 
2289
3268
  /*
@@ -2317,64 +3296,70 @@ AlgoliaSearch.prototype.Index.prototype = {
2317
3296
  // waitTask() must be handled differently from other methods,
2318
3297
  // it's a recursive method using a timeout
2319
3298
  var indexObj = this;
3299
+ var client = indexObj.as;
2320
3300
 
2321
3301
  var promise = this.as._jsonRequest({
2322
3302
  method: 'GET',
3303
+ hostType: 'read',
2323
3304
  url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/task/' + taskID
2324
3305
  }).then(function success(content) {
2325
3306
  if (content.status !== 'published') {
2326
- return new indexObj.as._request.delay(100).then(function() {
2327
- return indexObj.waitTask(taskID, callback);
3307
+ return indexObj.as._promise.delay(100).then(function() {
3308
+ // do not forward the callback, we want the promise
3309
+ // on next iteration
3310
+ return indexObj.waitTask(taskID);
2328
3311
  });
2329
3312
  }
2330
3313
 
2331
- if (callback) {
2332
- process.nextTick(function() {
2333
- callback(null, content);
2334
- });
2335
- } else {
2336
- return content;
2337
- }
2338
- }, function failure(err) {
2339
- if (callback) {
2340
- process.nextTick(function() {
2341
- callback(err);
2342
- });
2343
- } else {
2344
- return err;
2345
- }
3314
+ return content;
2346
3315
  });
2347
3316
 
2348
3317
  if (!callback) {
2349
3318
  return promise;
2350
3319
  }
3320
+
3321
+ promise.then(successCb, failureCb);
3322
+
3323
+ function successCb(content) {
3324
+ exitPromise(function() {
3325
+ callback(null, content);
3326
+ }, client._setTimeout || setTimeout);
3327
+ }
3328
+
3329
+ function failureCb(err) {
3330
+ exitPromise(function() {
3331
+ callback(err);
3332
+ }, client._setTimeout || setTimeout);
3333
+ }
2351
3334
  },
2352
3335
 
2353
3336
  /*
2354
3337
  * This function deletes the index content. Settings and index specific API keys are kept untouched.
2355
3338
  *
2356
- * @param callback (optional) the result callback with two arguments
3339
+ * @param callback (optional) the result callback called with two arguments
2357
3340
  * error: null or Error('message')
2358
3341
  * content: the settings object or the error message if a failure occured
2359
3342
  */
2360
3343
  clearIndex: function(callback) {
2361
3344
  var indexObj = this;
2362
3345
  return this.as._jsonRequest({ method: 'POST',
2363
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/clear',
2364
- callback: callback });
3346
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/clear',
3347
+ hostType: 'write',
3348
+ callback: callback });
2365
3349
  },
2366
3350
  /*
2367
3351
  * Get settings of this index
2368
3352
  *
2369
- * @param callback (optional) the result callback with two arguments
3353
+ * @param callback (optional) the result callback called with two arguments
2370
3354
  * error: null or Error('message')
2371
3355
  * content: the settings object or the error message if a failure occured
2372
3356
  */
2373
3357
  getSettings: function(callback) {
2374
3358
  var indexObj = this;
2375
3359
  return this.as._jsonRequest({ method: 'GET',
2376
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings',
2377
- callback: callback });
3360
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings',
3361
+ hostType: 'read',
3362
+ callback: callback });
2378
3363
  },
2379
3364
 
2380
3365
  /*
@@ -2427,57 +3412,61 @@ AlgoliaSearch.prototype.Index.prototype = {
2427
3412
  * - highlightPreTag: (string) Specify the string that is inserted before the highlighted parts in the query result (default to "<em>").
2428
3413
  * - highlightPostTag: (string) Specify the string that is inserted after the highlighted parts in the query result (default to "</em>").
2429
3414
  * - optionalWords: (array of strings) Specify a list of words that should be considered as optional when found in the query.
2430
- * @param callback (optional) the result callback with two arguments
3415
+ * @param callback (optional) the result callback called with two arguments
2431
3416
  * error: null or Error('message')
2432
3417
  * content: the server answer or the error message if a failure occured
2433
3418
  */
2434
3419
  setSettings: function(settings, callback) {
2435
3420
  var indexObj = this;
2436
3421
  return this.as._jsonRequest({ method: 'PUT',
2437
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings',
2438
- body: settings,
2439
- callback: callback });
3422
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings',
3423
+ hostType: 'write',
3424
+ body: settings,
3425
+ callback: callback });
2440
3426
  },
2441
3427
  /*
2442
3428
  * List all existing user keys associated to this index
2443
3429
  *
2444
- * @param callback the result callback with two arguments
3430
+ * @param callback the result callback called with two arguments
2445
3431
  * error: null or Error('message')
2446
3432
  * content: the server answer with user keys list
2447
3433
  */
2448
3434
  listUserKeys: function(callback) {
2449
3435
  var indexObj = this;
2450
3436
  return this.as._jsonRequest({ method: 'GET',
2451
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys',
2452
- callback: callback });
3437
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys',
3438
+ hostType: 'read',
3439
+ callback: callback });
2453
3440
  },
2454
3441
  /*
2455
3442
  * Get ACL of a user key associated to this index
2456
3443
  *
2457
3444
  * @param key
2458
- * @param callback the result callback with two arguments
3445
+ * @param callback the result callback called with two arguments
2459
3446
  * error: null or Error('message')
2460
3447
  * content: the server answer with user keys list
2461
3448
  */
2462
3449
  getUserKeyACL: function(key, callback) {
2463
3450
  var indexObj = this;
2464
3451
  return this.as._jsonRequest({ method: 'GET',
2465
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key,
2466
- callback: callback });
3452
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key,
3453
+ hostType: 'read',
3454
+ callback: callback });
2467
3455
  },
2468
3456
  /*
2469
3457
  * Delete an existing user key associated to this index
2470
3458
  *
2471
3459
  * @param key
2472
- * @param callback the result callback with two arguments
3460
+ * @param callback the result callback called with two arguments
2473
3461
  * error: null or Error('message')
2474
3462
  * content: the server answer with user keys list
2475
3463
  */
2476
3464
  deleteUserKey: function(key, callback) {
2477
3465
  var indexObj = this;
2478
3466
  return this.as._jsonRequest({ method: 'DELETE',
2479
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key,
2480
- callback: callback });
3467
+ url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key,
3468
+ hostType: 'write',
3469
+ callback: callback });
2481
3470
  },
2482
3471
  /*
2483
3472
  * Add an existing user key associated to this index
@@ -2490,57 +3479,94 @@ AlgoliaSearch.prototype.Index.prototype = {
2490
3479
  * - deleteIndex : allows to delete index content (https only)
2491
3480
  * - settings : allows to get index settings (https only)
2492
3481
  * - editSettings : allows to change index settings (https only)
2493
- * @param callback the result callback with two arguments
3482
+ * @param callback the result callback called with two arguments
2494
3483
  * error: null or Error('message')
2495
3484
  * content: the server answer with user keys list
2496
3485
  */
2497
- addUserKey: function(acls, callback) {
2498
- var indexObj = this;
2499
- var aclsObject = {};
2500
- aclsObject.acl = acls;
2501
- return this.as._jsonRequest({ method: 'POST',
2502
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys',
2503
- body: aclsObject,
2504
- callback: callback });
3486
+ addUserKey: function(acls, params, callback) {
3487
+ if (arguments.length === 1 || typeof params === 'function') {
3488
+ callback = params;
3489
+ params = null;
3490
+ }
3491
+
3492
+ var postObj = {
3493
+ acl: acls
3494
+ };
3495
+
3496
+ if (params) {
3497
+ postObj.validity = params.validity;
3498
+ postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
3499
+ postObj.maxHitsPerQuery = params.maxHitsPerQuery;
3500
+ }
3501
+
3502
+ return this.as._jsonRequest({
3503
+ method: 'POST',
3504
+ url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys',
3505
+ body: postObj,
3506
+ hostType: 'write',
3507
+ callback: callback
3508
+ });
2505
3509
  },
2506
- /*
3510
+
3511
+ /**
2507
3512
  * Add an existing user key associated to this index
2508
- *
2509
- * @param acls the list of ACL for this key. Defined by an array of strings that
2510
- * can contains the following values:
2511
- * - search: allow to search (https and http)
2512
- * - addObject: allows to add/update an object in the index (https only)
2513
- * - deleteObject : allows to delete an existing object (https only)
2514
- * - deleteIndex : allows to delete index content (https only)
2515
- * - settings : allows to get index settings (https only)
2516
- * - editSettings : allows to change index settings (https only)
2517
- * @param params.validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key)
2518
- * @param params.maxQueriesPerIPPerHour Specify the maximum number of API calls allowed from an IP address per hour.
2519
- * @param params.maxHitsPerQuery Specify the maximum number of hits this API key can retrieve in one call.
2520
- * @param callback the result callback with two arguments
2521
- * error: null or Error('message')
2522
- * content: the server answer with user keys list
3513
+ * @deprecated use index.addUserKey()
2523
3514
  */
2524
- addUserKeyWithValidity: function(acls, params, callback) {
2525
- var indexObj = this;
2526
- var aclsObject = {};
2527
- aclsObject.acl = acls;
2528
- aclsObject.validity = params.validity;
2529
- aclsObject.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
2530
- aclsObject.maxHitsPerQuery = params.maxHitsPerQuery;
2531
- return this.as._jsonRequest({ method: 'POST',
2532
- url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys',
2533
- body: aclsObject,
2534
- callback: callback });
2535
- },
2536
- ///
2537
- /// Internal methods only after this line
2538
- ///
3515
+ addUserKeyWithValidity: deprecate(function(acls, params, callback) {
3516
+ return this.addUserKey(acls, params, callback);
3517
+ }, deprecatedMessage('index.addUserKeyWithValidity()', 'index.addUserKey()')),
3518
+
3519
+ /**
3520
+ * Update an existing user key associated to this index
3521
+ * @param {string} key - The key to update
3522
+ * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that
3523
+ * can contains the following values:
3524
+ * - search: allow to search (https and http)
3525
+ * - addObject: allows to add/update an object in the index (https only)
3526
+ * - deleteObject : allows to delete an existing object (https only)
3527
+ * - deleteIndex : allows to delete index content (https only)
3528
+ * - settings : allows to get index settings (https only)
3529
+ * - editSettings : allows to change index settings (https only)
3530
+ * @param {Object} [params] - Optionnal parameters to set for the key
3531
+ * @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key)
3532
+ * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour
3533
+ * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call
3534
+ * @param {Function} callback - The result callback called with two arguments
3535
+ * error: null or Error('message')
3536
+ * content: the server answer with user keys list
3537
+ * @return {Promise|undefined} Returns a promise if no callback given
3538
+ */
3539
+ updateUserKey: function(key, acls, params, callback) {
3540
+ if (arguments.length === 2 || typeof params === 'function') {
3541
+ callback = params;
3542
+ params = null;
3543
+ }
3544
+
3545
+ var putObj = {
3546
+ acl: acls
3547
+ };
3548
+
3549
+ if (params) {
3550
+ putObj.validity = params.validity;
3551
+ putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
3552
+ putObj.maxHitsPerQuery = params.maxHitsPerQuery;
3553
+ }
3554
+
3555
+ return this.as._jsonRequest({
3556
+ method: 'PUT',
3557
+ url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys/' + key,
3558
+ body: putObj,
3559
+ hostType: 'write',
3560
+ callback: callback
3561
+ });
3562
+ },
3563
+
2539
3564
  _search: function(params, callback) {
2540
3565
  return this.as._jsonRequest({ cache: this.cache,
2541
3566
  method: 'POST',
2542
3567
  url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/query',
2543
3568
  body: {params: params},
3569
+ hostType: 'read',
2544
3570
  fallback: {
2545
3571
  method: 'GET',
2546
3572
  url: '/1/indexes/' + encodeURIComponent(this.indexName),
@@ -2550,7 +3576,6 @@ AlgoliaSearch.prototype.Index.prototype = {
2550
3576
  });
2551
3577
  },
2552
3578
 
2553
- // internal attributes
2554
3579
  as: null,
2555
3580
  indexName: null,
2556
3581
  typeAheadArgs: null,
@@ -2567,33 +3592,53 @@ function map(arr, fn){
2567
3592
  return ret;
2568
3593
  }
2569
3594
 
2570
- // extracted from https://github.com/coolaj86/knuth-shuffle
2571
- // not compatible with browserify
2572
- function shuffle(array) {
2573
- /*eslint-disable*/
2574
- var currentIndex = array.length
2575
- , temporaryValue
2576
- , randomIndex
2577
- ;
2578
-
2579
- // While there remain elements to shuffle...
2580
- while (0 !== currentIndex) {
2581
-
2582
- // Pick a remaining element...
2583
- randomIndex = Math.floor(Math.random() * currentIndex);
2584
- currentIndex -= 1;
2585
-
2586
- // And swap it with the current element.
2587
- temporaryValue = array[currentIndex];
2588
- array[currentIndex] = array[randomIndex];
2589
- array[randomIndex] = temporaryValue;
3595
+ function prepareHost(protocol) {
3596
+ return function prepare(host) {
3597
+ return protocol + '//' + host.toLowerCase();
3598
+ };
3599
+ }
3600
+
3601
+ function notImplemented() {
3602
+ var message = 'algoliasearch: Not implemented in this environment.\n' +
3603
+ 'If you feel this is a mistake, write to support@algolia.com';
3604
+
3605
+ throw new Error(message);
3606
+ }
3607
+
3608
+ function deprecatedMessage(previousUsage, newUsage) {
3609
+ var githubAnchorLink = previousUsage.toLowerCase()
3610
+ .replace('.', '')
3611
+ .replace('()', '');
3612
+
3613
+ return 'algoliasearch: `' + previousUsage + '` was replaced by `' +
3614
+ newUsage + '`. Please see https://github.com/algolia/algoliasearch-client-js/wiki/Deprecated#' + githubAnchorLink
3615
+ }
3616
+
3617
+ // Parse cloud does not supports setTimeout
3618
+ // We do not store a setTimeout reference in the client everytime
3619
+ // We only fallback to a fake setTimeout when not available
3620
+ // setTimeout cannot be override globally sadly
3621
+ function exitPromise(fn, _setTimeout) {
3622
+ _setTimeout(fn, 0);
3623
+ }
3624
+
3625
+ function deprecate(fn, message) {
3626
+ var warned = false;
3627
+
3628
+ function deprecated() {
3629
+ if (!warned) {
3630
+ console.log(message);
3631
+ warned = true;
3632
+ }
3633
+
3634
+ return fn.apply(this, arguments);
2590
3635
  }
2591
3636
 
2592
- return array;
3637
+ return deprecated;
2593
3638
  }
2594
3639
 
2595
- }).call(this,require(2))
2596
- },{"2":2}],5:[function(require,module,exports){
3640
+ }).call(this,require(1))
3641
+ },{"1":1,"11":11,"5":5,"9":9}],14:[function(require,module,exports){
2597
3642
  module.exports = JSONPRequest;
2598
3643
 
2599
3644
  var JSONPCounter = 0;
@@ -2604,6 +3649,8 @@ function JSONPRequest(url, opts, cb) {
2604
3649
  return;
2605
3650
  }
2606
3651
 
3652
+ opts.debug('JSONP: start');
3653
+
2607
3654
  var cbCalled = false;
2608
3655
  var timedOut = false;
2609
3656
 
@@ -2639,9 +3686,9 @@ function JSONPRequest(url, opts, cb) {
2639
3686
  // add callback by hand
2640
3687
  url += '&callback=' + cbName;
2641
3688
 
2642
- // add body params by hand
2643
- if (opts.body && opts.body.params) {
2644
- url += '&' + opts.body.params;
3689
+ // add body params manually
3690
+ if (opts.jsonBody && opts.jsonBody.params) {
3691
+ url += '&' + opts.jsonBody.params;
2645
3692
  }
2646
3693
 
2647
3694
  var ontimeout = setTimeout(timeout, opts.timeout);
@@ -2659,6 +3706,8 @@ function JSONPRequest(url, opts, cb) {
2659
3706
  head.appendChild(script);
2660
3707
 
2661
3708
  function success() {
3709
+ opts.debug('JSONP: success');
3710
+
2662
3711
  if (done || timedOut) {
2663
3712
  return;
2664
3713
  }
@@ -2667,6 +3716,7 @@ function JSONPRequest(url, opts, cb) {
2667
3716
 
2668
3717
  // script loaded but did not call the fn => script loading error
2669
3718
  if (!cbCalled) {
3719
+ opts.debug('JSONP: Fail. Script loaded but did not call the callback');
2670
3720
  clean();
2671
3721
  cb(new Error('Failed to load JSONP script'));
2672
3722
  }
@@ -2695,12 +3745,16 @@ function JSONPRequest(url, opts, cb) {
2695
3745
  }
2696
3746
 
2697
3747
  function timeout() {
3748
+ opts.debug('JSONP: Script timeout');
3749
+
2698
3750
  timedOut = true;
2699
3751
  clean();
2700
3752
  cb(new Error('Timeout - Could not connect to endpoint ' + url));
2701
3753
  }
2702
3754
 
2703
3755
  function error() {
3756
+ opts.debug('JSONP: Script error');
3757
+
2704
3758
  if (done || timedOut) {
2705
3759
  return;
2706
3760
  }
@@ -2710,23 +3764,217 @@ function JSONPRequest(url, opts, cb) {
2710
3764
  }
2711
3765
  }
2712
3766
 
2713
- },{}],6:[function(require,module,exports){
2714
- // this file is a `factory of algoliasearch()`
2715
- // Given a `request` param, it will provide you an AlgoliaSearch client
2716
- // using this particular request
2717
- module.exports = createAlgoliasearch;
3767
+ },{}],15:[function(require,module,exports){
3768
+ (function (global){
3769
+ // This is the standalone browser build entry point
3770
+ // Browser implementation of the Algolia Search JavaScript client,
3771
+ // using XMLHttpRequest, XDomainRequest and JSONP as fallback
3772
+ module.exports = algoliasearch;
3773
+
3774
+ var inherits = require(12);
3775
+ var Promise = global.Promise || require(8).Promise;
3776
+
3777
+ var AlgoliaSearch = require(13);
3778
+ var inlineHeaders = require(17);
3779
+ var JSONPRequest = require(14);
3780
+
3781
+ function algoliasearch(applicationID, apiKey, opts) {
3782
+ var extend = require(9);
3783
+
3784
+ var getDocumentProtocol = require(16);
3785
+
3786
+ opts = extend(true, {}, opts) || {};
3787
+
3788
+ if (opts.protocol === undefined) {
3789
+ opts.protocol = getDocumentProtocol();
3790
+ }
3791
+
3792
+ opts._ua = algoliasearch.ua;
3793
+
3794
+ return new AlgoliaSearchBrowser(applicationID, apiKey, opts);
3795
+ }
3796
+
3797
+ algoliasearch.version = require(18);
3798
+ algoliasearch.ua = 'Algolia for vanilla JavaScript ' + algoliasearch.version;
3799
+
3800
+ var support = {
3801
+ hasXMLHttpRequest: 'XMLHttpRequest' in window,
3802
+ hasXDomainRequest: 'XDomainRequest' in window,
3803
+ cors: 'withCredentials' in new XMLHttpRequest(),
3804
+ timeout: 'timeout' in new XMLHttpRequest()
3805
+ };
3806
+
3807
+ function AlgoliaSearchBrowser() {
3808
+ // call AlgoliaSearch constructor
3809
+ AlgoliaSearch.apply(this, arguments);
3810
+ }
3811
+
3812
+ inherits(AlgoliaSearchBrowser, AlgoliaSearch);
3813
+
3814
+ AlgoliaSearchBrowser.prototype._request = function(url, opts) {
3815
+ return new Promise(function(resolve, reject) {
3816
+ // no cors or XDomainRequest, no request
3817
+ if (!support.cors && !support.hasXDomainRequest) {
3818
+ // very old browser, not supported
3819
+ reject(new Error('CORS not supported'));
3820
+ return;
3821
+ }
3822
+
3823
+ url = inlineHeaders(url, opts.headers);
3824
+
3825
+ var body = opts.body;
3826
+ var req = support.cors ? new XMLHttpRequest() : new XDomainRequest();
3827
+ var ontimeout;
3828
+ var timedOut;
3829
+
3830
+ // do not rely on default XHR async flag, as some analytics code like hotjar
3831
+ // breaks it and set it to false by default
3832
+ if (req instanceof XMLHttpRequest) {
3833
+ req.open(opts.method, url, true);
3834
+ } else {
3835
+ req.open(opts.method, url);
3836
+ }
3837
+
3838
+ if (support.cors && body && opts.method !== 'GET') {
3839
+ req.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
3840
+ }
3841
+
3842
+ // we set an empty onprogress listener
3843
+ // so that XDomainRequest on IE9 is not aborted
3844
+ // refs:
3845
+ // - https://github.com/algolia/algoliasearch-client-js/issues/76
3846
+ // - 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
3847
+ req.onprogress = function noop() {};
3848
+
3849
+ req.onload = load;
3850
+ req.onerror = error;
3851
+
3852
+ if (support.timeout) {
3853
+ // .timeout supported by both XHR and XDR,
3854
+ // we do receive timeout event, tested
3855
+ req.timeout = opts.timeout;
3856
+
3857
+ req.ontimeout = timeout;
3858
+ } else {
3859
+ ontimeout = setTimeout(timeout, opts.timeout);
3860
+ }
3861
+
3862
+ req.send(body);
3863
+
3864
+ // event object not received in IE8, at least
3865
+ // but we do not use it, still important to note
3866
+ function load(/*event*/) {
3867
+ // When browser does not supports req.timeout, we can
3868
+ // have both a load and timeout event, since handled by a dumb setTimeout
3869
+ if (timedOut) {
3870
+ return;
3871
+ }
3872
+
3873
+ if (!support.timeout) {
3874
+ clearTimeout(ontimeout);
3875
+ }
3876
+
3877
+ var response = null;
3878
+
3879
+ try {
3880
+ response = JSON.parse(req.responseText);
3881
+ } catch(e) {}
3882
+
3883
+ resolve({
3884
+ body: response,
3885
+ statusCode: req.status
3886
+ });
3887
+ }
3888
+
3889
+ function error(event) {
3890
+ if (timedOut) {
3891
+ return;
3892
+ }
3893
+
3894
+ if (!support.timeout) {
3895
+ clearTimeout(ontimeout);
3896
+ }
3897
+
3898
+ // error event is trigerred both with XDR/XHR on:
3899
+ // - DNS error
3900
+ // - unallowed cross domain request
3901
+ reject(new Error('Could not connect to host, error was:' + event));
3902
+ }
3903
+
3904
+ function timeout() {
3905
+ if (!support.timeout) {
3906
+ timedOut = true;
3907
+ req.abort();
3908
+ }
3909
+
3910
+ resolve(new Error('Timeout - Could not connect to endpoint ' + url));
3911
+ }
3912
+
3913
+ });
3914
+ };
3915
+
3916
+ AlgoliaSearchBrowser.prototype._request.fallback = function(url, opts) {
3917
+ url = inlineHeaders(url, opts.headers);
3918
+
3919
+ return new Promise(function(resolve, reject) {
3920
+ JSONPRequest(url, opts, function JSONPRequestDone(err, content) {
3921
+ if (err) {
3922
+ reject(err);
3923
+ return;
3924
+ }
3925
+
3926
+ resolve(content);
3927
+ });
3928
+ });
3929
+ };
3930
+
3931
+ AlgoliaSearchBrowser.prototype._promise = {
3932
+ reject: function(val) {
3933
+ return Promise.reject(val);
3934
+ },
3935
+ resolve: function(val) {
3936
+ return Promise.resolve(val);
3937
+ },
3938
+ delay: function(ms) {
3939
+ return new Promise(function(resolve/*, reject*/) {
3940
+ setTimeout(resolve, ms);
3941
+ });
3942
+ }
3943
+ };
3944
+
3945
+ }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
3946
+ },{"12":12,"13":13,"14":14,"16":16,"17":17,"18":18,"8":8,"9":9}],16:[function(require,module,exports){
3947
+ (function (global){
3948
+ module.exports = getDocumentProtocol;
2718
3949
 
2719
- function createAlgoliasearch(request) {
2720
- function algoliasearch(applicationID, apiKey, opts) {
2721
- var AlgoliaSearch = require(4);
3950
+ function getDocumentProtocol() {
3951
+ var protocol = global.document.location.protocol;
2722
3952
 
2723
- return new AlgoliaSearch(applicationID, apiKey, opts, request);
3953
+ // when in `file:` mode (local html file), default to `http:`
3954
+ if (protocol !== 'http:' && protocol !== 'https:') {
3955
+ protocol = 'http:';
2724
3956
  }
2725
3957
 
2726
- algoliasearch.version = "3.0.3";
3958
+ return protocol;
3959
+ }
3960
+
3961
+ }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
3962
+ },{}],17:[function(require,module,exports){
3963
+ module.exports = inlineHeaders;
3964
+
3965
+ var querystring = require(4);
3966
+
3967
+ function inlineHeaders(url, headers) {
3968
+ if (/\?/.test(url)) {
3969
+ url += '&';
3970
+ } else {
3971
+ url += '?';
3972
+ }
2727
3973
 
2728
- return algoliasearch;
3974
+ return url + querystring.encode(headers);
2729
3975
  }
2730
3976
 
2731
- },{"4":4}]},{},[1])(1)
3977
+ },{"4":4}],18:[function(require,module,exports){
3978
+ module.exports="3.3.0"
3979
+ },{}]},{},[15])(15)
2732
3980
  });