diff --git a/404.html b/404.html index 1612da3..1d4ec4c 100644 --- a/404.html +++ b/404.html @@ -7,13 +7,13 @@ Page Not Found | foomo project docs - - + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - + + \ No newline at end of file diff --git a/assets/images/bundle_everywhere-12122e37ab5ca6bcdd61061c4dc32fd4.webp b/assets/images/bundle_everywhere-12122e37ab5ca6bcdd61061c4dc32fd4.webp new file mode 100644 index 0000000..47d7f9b Binary files /dev/null and b/assets/images/bundle_everywhere-12122e37ab5ca6bcdd61061c4dc32fd4.webp differ diff --git a/assets/images/meh-3b42aead7d2246467fd0101518403734.webp b/assets/images/meh-3b42aead7d2246467fd0101518403734.webp new file mode 100644 index 0000000..e475d4e Binary files /dev/null and b/assets/images/meh-3b42aead7d2246467fd0101518403734.webp differ diff --git a/assets/images/tools-91886b41cefeef7cc35b5cd21c43d2ba.webp b/assets/images/tools-91886b41cefeef7cc35b5cd21c43d2ba.webp new file mode 100644 index 0000000..fefd3d0 Binary files /dev/null and b/assets/images/tools-91886b41cefeef7cc35b5cd21c43d2ba.webp differ diff --git a/assets/js/9e4ef427.3bbe91d9.js b/assets/js/20efc167.a0a53068.js similarity index 99% rename from assets/js/9e4ef427.3bbe91d9.js rename to assets/js/20efc167.a0a53068.js index a9850ed..6da8ff7 100644 --- a/assets/js/9e4ef427.3bbe91d9.js +++ b/assets/js/20efc167.a0a53068.js @@ -1,2 +1,2 @@ -/*! For license information please see 9e4ef427.3bbe91d9.js.LICENSE.txt */ -(self.webpackChunkfoomo=self.webpackChunkfoomo||[]).push([[6081],{8131:function(e,t,r){"use strict";var n=r(9374),i=r(7775),a=r(3076);function s(e,t,r){return new n(e,t,r)}s.version=r(4336),s.AlgoliaSearchHelper=n,s.SearchParameters=i,s.SearchResults=a,e.exports=s},8078:function(e,t,r){"use strict";var n=r(7187);function i(e,t){this.main=e,this.fn=t,this.lastResults=null}r(4853)(i,n.EventEmitter),i.prototype.detach=function(){this.removeAllListeners(),this.main.detachDerivedHelper(this)},i.prototype.getModifiedState=function(e){return this.fn(e)},e.exports=i},2437:function(e,t,r){"use strict";var n=r(2344),i=r(9803),a=r(116),s={addRefinement:function(e,t,r){if(s.isRefined(e,t,r))return e;var i=""+r,a=e[t]?e[t].concat(i):[i],c={};return c[t]=a,n({},c,e)},removeRefinement:function(e,t,r){if(void 0===r)return s.clearRefinement(e,(function(e,r){return t===r}));var n=""+r;return s.clearRefinement(e,(function(e,r){return t===r&&n===e}))},toggleRefinement:function(e,t,r){if(void 0===r)throw new Error("toggleRefinement should be used with a value");return s.isRefined(e,t,r)?s.removeRefinement(e,t,r):s.addRefinement(e,t,r)},clearRefinement:function(e,t,r){if(void 0===t)return a(e)?{}:e;if("string"==typeof t)return i(e,[t]);if("function"==typeof t){var n=!1,s=Object.keys(e).reduce((function(i,a){var s=e[a]||[],c=s.filter((function(e){return!t(e,a,r)}));return c.length!==s.length&&(n=!0),i[a]=c,i}),{});return n?s:e}},isRefined:function(e,t,r){var n=!!e[t]&&e[t].length>0;if(void 0===r||!n)return n;var i=""+r;return-1!==e[t].indexOf(i)}};e.exports=s},7775:function(e,t,r){"use strict";var n=r(185),i=r(2344),a=r(2686),s=r(7888),c=r(8023),u=r(9803),o=r(116),h=r(6801),f=r(2437);function l(e,t){return Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((function(e,r){return l(t[r],e)})):e===t}function m(e){var t=e?m._parseNumbers(e):{};void 0===t.userToken||h(t.userToken)||console.warn("[algoliasearch-helper] The `userToken` parameter is invalid. This can lead to wrong analytics.\n - Format: [a-zA-Z0-9_-]{1,64}"),this.facets=t.facets||[],this.disjunctiveFacets=t.disjunctiveFacets||[],this.hierarchicalFacets=t.hierarchicalFacets||[],this.facetsRefinements=t.facetsRefinements||{},this.facetsExcludes=t.facetsExcludes||{},this.disjunctiveFacetsRefinements=t.disjunctiveFacetsRefinements||{},this.numericRefinements=t.numericRefinements||{},this.tagRefinements=t.tagRefinements||[],this.hierarchicalFacetsRefinements=t.hierarchicalFacetsRefinements||{};var r=this;Object.keys(t).forEach((function(e){var n=-1!==m.PARAMETERS.indexOf(e),i=void 0!==t[e];!n&&i&&(r[e]=t[e])}))}m.PARAMETERS=Object.keys(new m),m._parseNumbers=function(e){if(e instanceof m)return e;var t={};if(["aroundPrecision","aroundRadius","getRankingInfo","minWordSizefor2Typos","minWordSizefor1Typo","page","maxValuesPerFacet","distinct","minimumAroundRadius","hitsPerPage","minProximity"].forEach((function(r){var n=e[r];if("string"==typeof n){var i=parseFloat(n);t[r]=isNaN(i)?n:i}})),Array.isArray(e.insideBoundingBox)&&(t.insideBoundingBox=e.insideBoundingBox.map((function(e){return Array.isArray(e)?e.map((function(e){return parseFloat(e)})):e}))),e.numericRefinements){var r={};Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t]||{};r[t]={},Object.keys(n).forEach((function(e){var i=n[e].map((function(e){return Array.isArray(e)?e.map((function(e){return"string"==typeof e?parseFloat(e):e})):"string"==typeof e?parseFloat(e):e}));r[t][e]=i}))})),t.numericRefinements=r}return n({},e,t)},m.make=function(e){var t=new m(e);return(e.hierarchicalFacets||[]).forEach((function(e){if(e.rootPath){var r=t.getHierarchicalRefinement(e.name);r.length>0&&0!==r[0].indexOf(e.rootPath)&&(t=t.clearRefinements(e.name)),0===(r=t.getHierarchicalRefinement(e.name)).length&&(t=t.toggleHierarchicalFacetRefinement(e.name,e.rootPath))}})),t},m.validate=function(e,t){var r=t||{};return e.tagFilters&&r.tagRefinements&&r.tagRefinements.length>0?new Error("[Tags] Cannot switch from the managed tag API to the advanced API. It is probably an error, if it is really what you want, you should first clear the tags with clearTags method."):e.tagRefinements.length>0&&r.tagFilters?new Error("[Tags] Cannot switch from the advanced tag API to the managed API. It is probably an error, if it is not, you should first clear the tags with clearTags method."):e.numericFilters&&r.numericRefinements&&o(r.numericRefinements)?new Error("[Numeric filters] Can't switch from the advanced to the managed API. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):o(e.numericRefinements)&&r.numericFilters?new Error("[Numeric filters] Can't switch from the managed API to the advanced. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):null},m.prototype={constructor:m,clearRefinements:function(e){var t={numericRefinements:this._clearNumericRefinements(e),facetsRefinements:f.clearRefinement(this.facetsRefinements,e,"conjunctiveFacet"),facetsExcludes:f.clearRefinement(this.facetsExcludes,e,"exclude"),disjunctiveFacetsRefinements:f.clearRefinement(this.disjunctiveFacetsRefinements,e,"disjunctiveFacet"),hierarchicalFacetsRefinements:f.clearRefinement(this.hierarchicalFacetsRefinements,e,"hierarchicalFacet")};return t.numericRefinements===this.numericRefinements&&t.facetsRefinements===this.facetsRefinements&&t.facetsExcludes===this.facetsExcludes&&t.disjunctiveFacetsRefinements===this.disjunctiveFacetsRefinements&&t.hierarchicalFacetsRefinements===this.hierarchicalFacetsRefinements?this:this.setQueryParameters(t)},clearTags:function(){return void 0===this.tagFilters&&0===this.tagRefinements.length?this:this.setQueryParameters({tagFilters:void 0,tagRefinements:[]})},setIndex:function(e){return e===this.index?this:this.setQueryParameters({index:e})},setQuery:function(e){return e===this.query?this:this.setQueryParameters({query:e})},setPage:function(e){return e===this.page?this:this.setQueryParameters({page:e})},setFacets:function(e){return this.setQueryParameters({facets:e})},setDisjunctiveFacets:function(e){return this.setQueryParameters({disjunctiveFacets:e})},setHitsPerPage:function(e){return this.hitsPerPage===e?this:this.setQueryParameters({hitsPerPage:e})},setTypoTolerance:function(e){return this.typoTolerance===e?this:this.setQueryParameters({typoTolerance:e})},addNumericRefinement:function(e,t,r){var i=c(r);if(this.isNumericRefined(e,t,i))return this;var a=n({},this.numericRefinements);return a[e]=n({},a[e]),a[e][t]?(a[e][t]=a[e][t].slice(),a[e][t].push(i)):a[e][t]=[i],this.setQueryParameters({numericRefinements:a})},getConjunctiveRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsRefinements[e]||[]},getDisjunctiveRefinements:function(e){return this.isDisjunctiveFacet(e)&&this.disjunctiveFacetsRefinements[e]||[]},getHierarchicalRefinement:function(e){return this.hierarchicalFacetsRefinements[e]||[]},getExcludeRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsExcludes[e]||[]},removeNumericRefinement:function(e,t,r){return void 0!==r?this.isNumericRefined(e,t,r)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(n,i){return i===e&&n.op===t&&l(n.val,c(r))}))}):this:void 0!==t?this.isNumericRefined(e,t)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,n){return n===e&&r.op===t}))}):this:this.isNumericRefined(e)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(t,r){return r===e}))}):this},getNumericRefinements:function(e){return this.numericRefinements[e]||{}},getNumericRefinement:function(e,t){return this.numericRefinements[e]&&this.numericRefinements[e][t]},_clearNumericRefinements:function(e){if(void 0===e)return o(this.numericRefinements)?{}:this.numericRefinements;if("string"==typeof e)return u(this.numericRefinements,[e]);if("function"==typeof e){var t=!1,r=this.numericRefinements,n=Object.keys(r).reduce((function(n,i){var a=r[i],s={};return a=a||{},Object.keys(a).forEach((function(r){var n=a[r]||[],c=[];n.forEach((function(t){e({val:t,op:r},i,"numeric")||c.push(t)})),c.length!==n.length&&(t=!0),s[r]=c})),n[i]=s,n}),{});return t?n:this.numericRefinements}},addFacet:function(e){return this.isConjunctiveFacet(e)?this:this.setQueryParameters({facets:this.facets.concat([e])})},addDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this:this.setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.concat([e])})},addHierarchicalFacet:function(e){if(this.isHierarchicalFacet(e.name))throw new Error("Cannot declare two hierarchical facets with the same name: `"+e.name+"`");return this.setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.concat([e])})},addFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this:this.setQueryParameters({facetsRefinements:f.addRefinement(this.facetsRefinements,e,t)})},addExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this:this.setQueryParameters({facetsExcludes:f.addRefinement(this.facetsExcludes,e,t)})},addDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this:this.setQueryParameters({disjunctiveFacetsRefinements:f.addRefinement(this.disjunctiveFacetsRefinements,e,t)})},addTagRefinement:function(e){if(this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.concat(e)};return this.setQueryParameters(t)},removeFacet:function(e){return this.isConjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({facets:this.facets.filter((function(t){return t!==e}))}):this},removeDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.filter((function(t){return t!==e}))}):this},removeHierarchicalFacet:function(e){return this.isHierarchicalFacet(e)?this.clearRefinements(e).setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.filter((function(t){return t.name!==e}))}):this},removeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this.setQueryParameters({facetsRefinements:f.removeRefinement(this.facetsRefinements,e,t)}):this},removeExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this.setQueryParameters({facetsExcludes:f.removeRefinement(this.facetsExcludes,e,t)}):this},removeDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this.setQueryParameters({disjunctiveFacetsRefinements:f.removeRefinement(this.disjunctiveFacetsRefinements,e,t)}):this},removeTagRefinement:function(e){if(!this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.filter((function(t){return t!==e}))};return this.setQueryParameters(t)},toggleRefinement:function(e,t){return this.toggleFacetRefinement(e,t)},toggleFacetRefinement:function(e,t){if(this.isHierarchicalFacet(e))return this.toggleHierarchicalFacetRefinement(e,t);if(this.isConjunctiveFacet(e))return this.toggleConjunctiveFacetRefinement(e,t);if(this.isDisjunctiveFacet(e))return this.toggleDisjunctiveFacetRefinement(e,t);throw new Error("Cannot refine the undeclared facet "+e+"; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets")},toggleConjunctiveFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsRefinements:f.toggleRefinement(this.facetsRefinements,e,t)})},toggleExcludeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsExcludes:f.toggleRefinement(this.facetsExcludes,e,t)})},toggleDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return this.setQueryParameters({disjunctiveFacetsRefinements:f.toggleRefinement(this.disjunctiveFacetsRefinements,e,t)})},toggleHierarchicalFacetRefinement:function(e,t){if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration");var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e)),n={};return void 0!==this.hierarchicalFacetsRefinements[e]&&this.hierarchicalFacetsRefinements[e].length>0&&(this.hierarchicalFacetsRefinements[e][0]===t||0===this.hierarchicalFacetsRefinements[e][0].indexOf(t+r))?-1===t.indexOf(r)?n[e]=[]:n[e]=[t.slice(0,t.lastIndexOf(r))]:n[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:i({},n,this.hierarchicalFacetsRefinements)})},addHierarchicalFacetRefinement:function(e,t){if(this.isHierarchicalFacetRefined(e))throw new Error(e+" is already refined.");if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration.");var r={};return r[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:i({},r,this.hierarchicalFacetsRefinements)})},removeHierarchicalFacetRefinement:function(e){if(!this.isHierarchicalFacetRefined(e))return this;var t={};return t[e]=[],this.setQueryParameters({hierarchicalFacetsRefinements:i({},t,this.hierarchicalFacetsRefinements)})},toggleTagRefinement:function(e){return this.isTagRefined(e)?this.removeTagRefinement(e):this.addTagRefinement(e)},isDisjunctiveFacet:function(e){return this.disjunctiveFacets.indexOf(e)>-1},isHierarchicalFacet:function(e){return void 0!==this.getHierarchicalFacetByName(e)},isConjunctiveFacet:function(e){return this.facets.indexOf(e)>-1},isFacetRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsRefinements,e,t)},isExcludeRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsExcludes,e,t)},isDisjunctiveFacetRefined:function(e,t){return!!this.isDisjunctiveFacet(e)&&f.isRefined(this.disjunctiveFacetsRefinements,e,t)},isHierarchicalFacetRefined:function(e,t){if(!this.isHierarchicalFacet(e))return!1;var r=this.getHierarchicalRefinement(e);return t?-1!==r.indexOf(t):r.length>0},isNumericRefined:function(e,t,r){if(void 0===r&&void 0===t)return!!this.numericRefinements[e];var n=this.numericRefinements[e]&&void 0!==this.numericRefinements[e][t];if(void 0===r||!n)return n;var i,a,u=c(r),o=void 0!==(i=this.numericRefinements[e][t],a=u,s(i,(function(e){return l(e,a)})));return n&&o},isTagRefined:function(e){return-1!==this.tagRefinements.indexOf(e)},getRefinedDisjunctiveFacets:function(){var e=this,t=a(Object.keys(this.numericRefinements).filter((function(t){return Object.keys(e.numericRefinements[t]).length>0})),this.disjunctiveFacets);return Object.keys(this.disjunctiveFacetsRefinements).filter((function(t){return e.disjunctiveFacetsRefinements[t].length>0})).concat(t).concat(this.getRefinedHierarchicalFacets())},getRefinedHierarchicalFacets:function(){var e=this;return a(this.hierarchicalFacets.map((function(e){return e.name})),Object.keys(this.hierarchicalFacetsRefinements).filter((function(t){return e.hierarchicalFacetsRefinements[t].length>0})))},getUnrefinedDisjunctiveFacets:function(){var e=this.getRefinedDisjunctiveFacets();return this.disjunctiveFacets.filter((function(t){return-1===e.indexOf(t)}))},managedParameters:["index","facets","disjunctiveFacets","facetsRefinements","hierarchicalFacets","facetsExcludes","disjunctiveFacetsRefinements","numericRefinements","tagRefinements","hierarchicalFacetsRefinements"],getQueryParams:function(){var e=this.managedParameters,t={},r=this;return Object.keys(this).forEach((function(n){var i=r[n];-1===e.indexOf(n)&&void 0!==i&&(t[n]=i)})),t},setQueryParameter:function(e,t){if(this[e]===t)return this;var r={};return r[e]=t,this.setQueryParameters(r)},setQueryParameters:function(e){if(!e)return this;var t=m.validate(this,e);if(t)throw t;var r=this,n=m._parseNumbers(e),i=Object.keys(this).reduce((function(e,t){return e[t]=r[t],e}),{}),a=Object.keys(n).reduce((function(e,t){var r=void 0!==e[t],i=void 0!==n[t];return r&&!i?u(e,[t]):(i&&(e[t]=n[t]),e)}),i);return new this.constructor(a)},resetPage:function(){return void 0===this.page?this:this.setPage(0)},_getHierarchicalFacetSortBy:function(e){return e.sortBy||["isRefined:desc","name:asc"]},_getHierarchicalFacetSeparator:function(e){return e.separator||" > "},_getHierarchicalRootPath:function(e){return e.rootPath||null},_getHierarchicalShowParentLevel:function(e){return"boolean"!=typeof e.showParentLevel||e.showParentLevel},getHierarchicalFacetByName:function(e){return s(this.hierarchicalFacets,(function(t){return t.name===e}))},getHierarchicalFacetBreadcrumb:function(e){if(!this.isHierarchicalFacet(e))return[];var t=this.getHierarchicalRefinement(e)[0];if(!t)return[];var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e));return t.split(r).map((function(e){return e.trim()}))},toString:function(){return JSON.stringify(this,null,2)}},e.exports=m},210:function(e,t,r){"use strict";e.exports=function(e){return function(t,r){var s=e.hierarchicalFacets[r],c=e.hierarchicalFacetsRefinements[s.name]&&e.hierarchicalFacetsRefinements[s.name][0]||"",u=e._getHierarchicalFacetSeparator(s),o=e._getHierarchicalRootPath(s),h=e._getHierarchicalShowParentLevel(s),f=a(e._getHierarchicalFacetSortBy(s)),l=t.every((function(e){return e.exhaustive})),m=function(e,t,r,a,s){return function(c,u,o){var h=c;if(o>0){var f=0;for(h=c;f-1})));if(o){var h=o.attributes.indexOf(t),f=u(e.hierarchicalFacets,(function(e){return e.name===o.name}));a.hierarchicalFacets[f][h]={attribute:t,data:s,exhaustive:r.exhaustiveFacetsCount}}else{var v,g=-1!==e.disjunctiveFacets.indexOf(t),y=-1!==e.facets.indexOf(t);g&&(v=d[t],a.disjunctiveFacets[v]={name:t,data:s,exhaustive:r.exhaustiveFacetsCount},l(a.disjunctiveFacets[v],r.facets_stats,t)),y&&(v=m[t],a.facets[v]={name:t,data:s,exhaustive:r.exhaustiveFacetsCount},l(a.facets[v],r.facets_stats,t))}})),this.hierarchicalFacets=s(this.hierarchicalFacets),o.forEach((function(s){var c=t[v],o=c&&c.facets?c.facets:{},h=e.getHierarchicalFacetByName(s);Object.keys(o).forEach((function(t){var s,f=o[t];if(h){s=u(e.hierarchicalFacets,(function(e){return e.name===h.name}));var m=u(a.hierarchicalFacets[s],(function(e){return e.attribute===t}));if(-1===m)return;a.hierarchicalFacets[s][m].data=n({},a.hierarchicalFacets[s][m].data,f)}else{s=d[t];var v=r.facets&&r.facets[t]||{};a.disjunctiveFacets[s]={name:t,data:i({},f,v),exhaustive:c.exhaustiveFacetsCount},l(a.disjunctiveFacets[s],c.facets_stats,t),e.disjunctiveFacetsRefinements[t]&&e.disjunctiveFacetsRefinements[t].forEach((function(r){!a.disjunctiveFacets[s].data[r]&&e.disjunctiveFacetsRefinements[t].indexOf(r)>-1&&(a.disjunctiveFacets[s].data[r]=0)}))}})),v++})),e.getRefinedHierarchicalFacets().forEach((function(r){var n=e.getHierarchicalFacetByName(r),s=e._getHierarchicalFacetSeparator(n),c=e.getHierarchicalRefinement(r);if(!(0===c.length||c[0].split(s).length<2)){var o=t[v],h=o&&o.facets?o.facets:{};Object.keys(h).forEach((function(t){var r=h[t],o=u(e.hierarchicalFacets,(function(e){return e.name===n.name})),f=u(a.hierarchicalFacets[o],(function(e){return e.attribute===t}));if(-1!==f){var l={};if(c.length>0){var m=c[0].split(s)[0];l[m]=a.hierarchicalFacets[o][f].data[m]}a.hierarchicalFacets[o][f].data=i(l,r,a.hierarchicalFacets[o][f].data)}})),v++}})),Object.keys(e.facetsExcludes).forEach((function(t){var n=e.facetsExcludes[t],i=m[t];a.facets[i]={name:t,data:r.facets[t],exhaustive:r.exhaustiveFacetsCount},n.forEach((function(e){a.facets[i]=a.facets[i]||{name:t},a.facets[i].data=a.facets[i].data||{},a.facets[i].data[e]=0}))})),this.hierarchicalFacets=this.hierarchicalFacets.map(h(e)),this.facets=s(this.facets),this.disjunctiveFacets=s(this.disjunctiveFacets),this._state=e}function d(e,t,r,n){if(n=n||0,Array.isArray(t))return e(t,r[n]);if(!t.data||0===t.data.length)return t;var a=t.data.map((function(t){return d(e,t,r,n+1)})),s=e(a,r[n]);return i({data:s},t)}function v(e,t){var r=c(e,(function(e){return e.name===t}));return r&&r.stats}function p(e,t,r,n,i){var a=c(i,(function(e){return e.name===r})),s=a&&a.data&&a.data[n]?a.data[n]:0,u=a&&a.exhaustive||!1;return{type:t,attributeName:r,name:n,count:s,exhaustive:u}}m.prototype.getFacetByName=function(e){function t(t){return t.name===e}return c(this.facets,t)||c(this.disjunctiveFacets,t)||c(this.hierarchicalFacets,t)},m.DEFAULT_SORT=["isRefined:desc","count:desc","name:asc"],m.prototype.getFacetValues=function(e,t){var r=function(e,t){function r(e){return e.name===t}if(e._state.isConjunctiveFacet(t)){var n=c(e.facets,r);return n?Object.keys(n.data).map((function(r){return{name:r,count:n.data[r],isRefined:e._state.isFacetRefined(t,r),isExcluded:e._state.isExcludeRefined(t,r)}})):[]}if(e._state.isDisjunctiveFacet(t)){var i=c(e.disjunctiveFacets,r);return i?Object.keys(i.data).map((function(r){return{name:r,count:i.data[r],isRefined:e._state.isDisjunctiveFacetRefined(t,r)}})):[]}if(e._state.isHierarchicalFacet(t))return c(e.hierarchicalFacets,r)}(this,e);if(r){var n,s=i({},t,{sortBy:m.DEFAULT_SORT,facetOrdering:!(t&&t.sortBy)}),u=this;if(Array.isArray(r))n=[e];else n=u._state.getHierarchicalFacetByName(r.name).attributes;return d((function(e,t){if(s.facetOrdering){var r=function(e,t){return e.renderingContent&&e.renderingContent.facetOrdering&&e.renderingContent.facetOrdering.values&&e.renderingContent.facetOrdering.values[t]}(u,t);if(Boolean(r))return function(e,t){var r=[],n=[],i=(t.order||[]).reduce((function(e,t,r){return e[t]=r,e}),{});e.forEach((function(e){var t=e.path||e.name;void 0!==i[t]?r[i[t]]=e:n.push(e)})),r=r.filter((function(e){return e}));var s,c=t.sortRemainingBy;return"hidden"===c?r:(s="alpha"===c?[["path","name"],["asc","asc"]]:[["count"],["desc"]],r.concat(a(n,s[0],s[1])))}(e,r)}if(Array.isArray(s.sortBy)){var n=o(s.sortBy,m.DEFAULT_SORT);return a(e,n[0],n[1])}if("function"==typeof s.sortBy)return function(e,t){return t.sort(e)}(s.sortBy,e);throw new Error("options.sortBy is optional but if defined it must be either an array of string (predicates) or a sorting function")}),r,n)}},m.prototype.getFacetStats=function(e){return this._state.isConjunctiveFacet(e)?v(this.facets,e):this._state.isDisjunctiveFacet(e)?v(this.disjunctiveFacets,e):void 0},m.prototype.getRefinements=function(){var e=this._state,t=this,r=[];return Object.keys(e.facetsRefinements).forEach((function(n){e.facetsRefinements[n].forEach((function(i){r.push(p(e,"facet",n,i,t.facets))}))})),Object.keys(e.facetsExcludes).forEach((function(n){e.facetsExcludes[n].forEach((function(i){r.push(p(e,"exclude",n,i,t.facets))}))})),Object.keys(e.disjunctiveFacetsRefinements).forEach((function(n){e.disjunctiveFacetsRefinements[n].forEach((function(i){r.push(p(e,"disjunctive",n,i,t.disjunctiveFacets))}))})),Object.keys(e.hierarchicalFacetsRefinements).forEach((function(n){e.hierarchicalFacetsRefinements[n].forEach((function(i){r.push(function(e,t,r,n){var i=e.getHierarchicalFacetByName(t),a=e._getHierarchicalFacetSeparator(i),s=r.split(a),u=c(n,(function(e){return e.name===t})),o=s.reduce((function(e,t){var r=e&&c(e.data,(function(e){return e.name===t}));return void 0!==r?r:e}),u),h=o&&o.count||0,f=o&&o.exhaustive||!1,l=o&&o.path||"";return{type:"hierarchical",attributeName:t,name:l,count:h,exhaustive:f}}(e,n,i,t.hierarchicalFacets))}))})),Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t];Object.keys(n).forEach((function(e){n[e].forEach((function(n){r.push({type:"numeric",attributeName:t,name:n,numericValue:n,operator:e})}))}))})),e.tagRefinements.forEach((function(e){r.push({type:"tag",attributeName:"_tags",name:e})})),r},e.exports=m},9374:function(e,t,r){"use strict";var n=r(7775),i=r(3076),a=r(8078),s=r(6394),c=r(7187),u=r(4853),o=r(116),h=r(9803),f=r(185),l=r(4336);function m(e,t,r){"function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+l+")"),this.setClient(e);var i=r||{};i.index=t,this.state=n.make(i),this.lastResults=null,this._queryId=0,this._lastQueryIdReceived=-1,this.derivedHelpers=[],this._currentNbQueries=0}function d(e){if(e<0)throw new Error("Page requested below 0.");return this._change({state:this.state.setPage(e),isPageReset:!1}),this}function v(){return this.state.page}u(m,c.EventEmitter),m.prototype.search=function(){return this._search({onlyWithDerivedHelpers:!1}),this},m.prototype.searchOnlyWithDerivedHelpers=function(){return this._search({onlyWithDerivedHelpers:!0}),this},m.prototype.getQuery=function(){var e=this.state;return s._getHitsSearchParams(e)},m.prototype.searchOnce=function(e,t){var r=e?this.state.setQueryParameters(e):this.state,n=s._getQueries(r.index,r),a=this;if(this._currentNbQueries++,this.emit("searchOnce",{state:r}),!t)return this.client.search(n).then((function(e){return a._currentNbQueries--,0===a._currentNbQueries&&a.emit("searchQueueEmpty"),{content:new i(r,e.results),state:r,_originalResponse:e}}),(function(e){throw a._currentNbQueries--,0===a._currentNbQueries&&a.emit("searchQueueEmpty"),e}));this.client.search(n).then((function(e){a._currentNbQueries--,0===a._currentNbQueries&&a.emit("searchQueueEmpty"),t(null,new i(r,e.results),r)})).catch((function(e){a._currentNbQueries--,0===a._currentNbQueries&&a.emit("searchQueueEmpty"),t(e,null,r)}))},m.prototype.findAnswers=function(e){var t=this.state,r=this.derivedHelpers[0];if(!r)return Promise.resolve([]);var n=r.getModifiedState(t),i=f({attributesForPrediction:e.attributesForPrediction,nbHits:e.nbHits},{params:h(s._getHitsSearchParams(n),["attributesToSnippet","hitsPerPage","restrictSearchableAttributes","snippetEllipsisText"])}),a="search for answers was called, but this client does not have a function client.initIndex(index).findAnswers";if("function"!=typeof this.client.initIndex)throw new Error(a);var c=this.client.initIndex(n.index);if("function"!=typeof c.findAnswers)throw new Error(a);return c.findAnswers(n.query,e.queryLanguages,i)},m.prototype.searchForFacetValues=function(e,t,r,n){var i="function"==typeof this.client.searchForFacetValues;if(!i&&"function"!=typeof this.client.initIndex)throw new Error("search for facet values (searchable) was called, but this client does not have a function client.searchForFacetValues or client.initIndex(index).searchForFacetValues");var a=this.state.setQueryParameters(n||{}),c=a.isDisjunctiveFacet(e),u=s.getSearchForFacetQuery(e,t,r,a);this._currentNbQueries++;var o=this;return this.emit("searchForFacetValues",{state:a,facet:e,query:t}),(i?this.client.searchForFacetValues([{indexName:a.index,params:u}]):this.client.initIndex(a.index).searchForFacetValues(u)).then((function(t){return o._currentNbQueries--,0===o._currentNbQueries&&o.emit("searchQueueEmpty"),(t=Array.isArray(t)?t[0]:t).facetHits.forEach((function(t){t.isRefined=c?a.isDisjunctiveFacetRefined(e,t.value):a.isFacetRefined(e,t.value)})),t}),(function(e){throw o._currentNbQueries--,0===o._currentNbQueries&&o.emit("searchQueueEmpty"),e}))},m.prototype.setQuery=function(e){return this._change({state:this.state.resetPage().setQuery(e),isPageReset:!0}),this},m.prototype.clearRefinements=function(e){return this._change({state:this.state.resetPage().clearRefinements(e),isPageReset:!0}),this},m.prototype.clearTags=function(){return this._change({state:this.state.resetPage().clearTags(),isPageReset:!0}),this},m.prototype.addDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.addDisjunctiveRefine=function(){return this.addDisjunctiveFacetRefinement.apply(this,arguments)},m.prototype.addHierarchicalFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addHierarchicalFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.addNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().addNumericRefinement(e,t,r),isPageReset:!0}),this},m.prototype.addFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.addRefine=function(){return this.addFacetRefinement.apply(this,arguments)},m.prototype.addFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().addExcludeRefinement(e,t),isPageReset:!0}),this},m.prototype.addExclude=function(){return this.addFacetExclusion.apply(this,arguments)},m.prototype.addTag=function(e){return this._change({state:this.state.resetPage().addTagRefinement(e),isPageReset:!0}),this},m.prototype.removeNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().removeNumericRefinement(e,t,r),isPageReset:!0}),this},m.prototype.removeDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.removeDisjunctiveRefine=function(){return this.removeDisjunctiveFacetRefinement.apply(this,arguments)},m.prototype.removeHierarchicalFacetRefinement=function(e){return this._change({state:this.state.resetPage().removeHierarchicalFacetRefinement(e),isPageReset:!0}),this},m.prototype.removeFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.removeRefine=function(){return this.removeFacetRefinement.apply(this,arguments)},m.prototype.removeFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().removeExcludeRefinement(e,t),isPageReset:!0}),this},m.prototype.removeExclude=function(){return this.removeFacetExclusion.apply(this,arguments)},m.prototype.removeTag=function(e){return this._change({state:this.state.resetPage().removeTagRefinement(e),isPageReset:!0}),this},m.prototype.toggleFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().toggleExcludeFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.toggleExclude=function(){return this.toggleFacetExclusion.apply(this,arguments)},m.prototype.toggleRefinement=function(e,t){return this.toggleFacetRefinement(e,t)},m.prototype.toggleFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().toggleFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.toggleRefine=function(){return this.toggleFacetRefinement.apply(this,arguments)},m.prototype.toggleTag=function(e){return this._change({state:this.state.resetPage().toggleTagRefinement(e),isPageReset:!0}),this},m.prototype.nextPage=function(){var e=this.state.page||0;return this.setPage(e+1)},m.prototype.previousPage=function(){var e=this.state.page||0;return this.setPage(e-1)},m.prototype.setCurrentPage=d,m.prototype.setPage=d,m.prototype.setIndex=function(e){return this._change({state:this.state.resetPage().setIndex(e),isPageReset:!0}),this},m.prototype.setQueryParameter=function(e,t){return this._change({state:this.state.resetPage().setQueryParameter(e,t),isPageReset:!0}),this},m.prototype.setState=function(e){return this._change({state:n.make(e),isPageReset:!1}),this},m.prototype.overrideStateWithoutTriggeringChangeEvent=function(e){return this.state=new n(e),this},m.prototype.hasRefinements=function(e){return!!o(this.state.getNumericRefinements(e))||(this.state.isConjunctiveFacet(e)?this.state.isFacetRefined(e):this.state.isDisjunctiveFacet(e)?this.state.isDisjunctiveFacetRefined(e):!!this.state.isHierarchicalFacet(e)&&this.state.isHierarchicalFacetRefined(e))},m.prototype.isExcluded=function(e,t){return this.state.isExcludeRefined(e,t)},m.prototype.isDisjunctiveRefined=function(e,t){return this.state.isDisjunctiveFacetRefined(e,t)},m.prototype.hasTag=function(e){return this.state.isTagRefined(e)},m.prototype.isTagRefined=function(){return this.hasTagRefinements.apply(this,arguments)},m.prototype.getIndex=function(){return this.state.index},m.prototype.getCurrentPage=v,m.prototype.getPage=v,m.prototype.getTags=function(){return this.state.tagRefinements},m.prototype.getRefinements=function(e){var t=[];if(this.state.isConjunctiveFacet(e))this.state.getConjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"conjunctive"})})),this.state.getExcludeRefinements(e).forEach((function(e){t.push({value:e,type:"exclude"})}));else if(this.state.isDisjunctiveFacet(e)){this.state.getDisjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"disjunctive"})}))}var r=this.state.getNumericRefinements(e);return Object.keys(r).forEach((function(e){var n=r[e];t.push({value:n,operator:e,type:"numeric"})})),t},m.prototype.getNumericRefinement=function(e,t){return this.state.getNumericRefinement(e,t)},m.prototype.getHierarchicalFacetBreadcrumb=function(e){return this.state.getHierarchicalFacetBreadcrumb(e)},m.prototype._search=function(e){var t=this.state,r=[],n=[];e.onlyWithDerivedHelpers||(n=s._getQueries(t.index,t),r.push({state:t,queriesCount:n.length,helper:this}),this.emit("search",{state:t,results:this.lastResults}));var i=this.derivedHelpers.map((function(e){var n=e.getModifiedState(t),i=s._getQueries(n.index,n);return r.push({state:n,queriesCount:i.length,helper:e}),e.emit("search",{state:n,results:e.lastResults}),i})),a=Array.prototype.concat.apply(n,i),c=this._queryId++;this._currentNbQueries++;try{this.client.search(a).then(this._dispatchAlgoliaResponse.bind(this,r,c)).catch(this._dispatchAlgoliaError.bind(this,c))}catch(u){this.emit("error",{error:u})}},m.prototype._dispatchAlgoliaResponse=function(e,t,r){if(!(t0},m.prototype._change=function(e){var t=e.state,r=e.isPageReset;t!==this.state&&(this.state=t,this.emit("change",{state:this.state,results:this.lastResults,isPageReset:r}))},m.prototype.clearCache=function(){return this.client.clearCache&&this.client.clearCache(),this},m.prototype.setClient=function(e){return this.client===e||("function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+l+")"),this.client=e),this},m.prototype.getClient=function(){return this.client},m.prototype.derive=function(e){var t=new a(this,e);return this.derivedHelpers.push(t),t},m.prototype.detachDerivedHelper=function(e){var t=this.derivedHelpers.indexOf(e);if(-1===t)throw new Error("Derived helper already detached");this.derivedHelpers.splice(t,1)},m.prototype.hasPendingRequests=function(){return this._currentNbQueries>0},e.exports=m},4587:function(e){"use strict";e.exports=function(e){return Array.isArray(e)?e.filter(Boolean):[]}},2344:function(e){"use strict";e.exports=function(){var e=Array.prototype.slice.call(arguments);return e.reduceRight((function(e,t){return Object.keys(Object(t)).forEach((function(r){void 0!==t[r]&&(void 0!==e[r]&&delete e[r],e[r]=t[r])})),e}),{})}},7888:function(e){"use strict";e.exports=function(e,t){if(Array.isArray(e))for(var r=0;r1||!a?(e[0].push(i[0]),e[1].push(i[1]),e):(e[0].push(a[0]),e[1].push(a[1]),e)}),[[],[]])}},4853:function(e){"use strict";e.exports=function(e,t){e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}},2686:function(e){"use strict";e.exports=function(e,t){return e.filter((function(r,n){return t.indexOf(r)>-1&&e.indexOf(r)===n}))}},185:function(e){"use strict";function t(e){return"function"==typeof e||Array.isArray(e)||"[object Object]"===Object.prototype.toString.call(e)}function r(e,n){if(e===n)return e;for(var i in n)if(Object.prototype.hasOwnProperty.call(n,i)&&"__proto__"!==i){var a=n[i],s=e[i];void 0!==s&&void 0===a||(t(s)&&t(a)?e[i]=r(s,a):e[i]="object"==typeof(c=a)&&null!==c?r(Array.isArray(c)?[]:{},c):c)}var c;return e}e.exports=function(e){t(e)||(e={});for(var n=1,i=arguments.length;n0}},9803:function(e){"use strict";e.exports=function(e,t){if(null===e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n=0||(i[r]=e[r]);return i}},2148:function(e){"use strict";function t(e,t){if(e!==t){var r=void 0!==e,n=null===e,i=void 0!==t,a=null===t;if(!a&&e>t||n&&i||!r)return 1;if(!n&&e=n.length?a:"desc"===n[i]?-a:a}return e.index-r.index})),i.map((function(e){return e.value}))}},8023:function(e){"use strict";e.exports=function e(t){if("number"==typeof t)return t;if("string"==typeof t)return parseFloat(t);if(Array.isArray(t))return t.map(e);throw new Error("The value should be a number, a parsable string or an array of those.")}},6394:function(e,t,r){"use strict";var n=r(185),i={_getQueries:function(e,t){var r=[];return r.push({indexName:e,params:i._getHitsSearchParams(t)}),t.getRefinedDisjunctiveFacets().forEach((function(n){r.push({indexName:e,params:i._getDisjunctiveFacetSearchParams(t,n)})})),t.getRefinedHierarchicalFacets().forEach((function(n){var a=t.getHierarchicalFacetByName(n),s=t.getHierarchicalRefinement(n),c=t._getHierarchicalFacetSeparator(a);s.length>0&&s[0].split(c).length>1&&r.push({indexName:e,params:i._getDisjunctiveFacetSearchParams(t,n,!0)})})),r},_getHitsSearchParams:function(e){var t=e.facets.concat(e.disjunctiveFacets).concat(i._getHitsHierarchicalFacetsAttributes(e)),r=i._getFacetFilters(e),a=i._getNumericFilters(e),s=i._getTagFilters(e),c={facets:t.indexOf("*")>-1?["*"]:t,tagFilters:s};return r.length>0&&(c.facetFilters=r),a.length>0&&(c.numericFilters=a),n({},e.getQueryParams(),c)},_getDisjunctiveFacetSearchParams:function(e,t,r){var a=i._getFacetFilters(e,t,r),s=i._getNumericFilters(e,t),c={hitsPerPage:1,page:0,attributesToRetrieve:[],attributesToHighlight:[],attributesToSnippet:[],tagFilters:i._getTagFilters(e),analytics:!1,clickAnalytics:!1},u=e.getHierarchicalFacetByName(t);return c.facets=u?i._getDisjunctiveHierarchicalFacetAttribute(e,u,r):t,s.length>0&&(c.numericFilters=s),a.length>0&&(c.facetFilters=a),n({},e.getQueryParams(),c)},_getNumericFilters:function(e,t){if(e.numericFilters)return e.numericFilters;var r=[];return Object.keys(e.numericRefinements).forEach((function(n){var i=e.numericRefinements[n]||{};Object.keys(i).forEach((function(e){var a=i[e]||[];t!==n&&a.forEach((function(t){if(Array.isArray(t)){var i=t.map((function(t){return n+e+t}));r.push(i)}else r.push(n+e+t)}))}))})),r},_getTagFilters:function(e){return e.tagFilters?e.tagFilters:e.tagRefinements.join(",")},_getFacetFilters:function(e,t,r){var n=[],i=e.facetsRefinements||{};Object.keys(i).forEach((function(e){(i[e]||[]).forEach((function(t){n.push(e+":"+t)}))}));var a=e.facetsExcludes||{};Object.keys(a).forEach((function(e){(a[e]||[]).forEach((function(t){n.push(e+":-"+t)}))}));var s=e.disjunctiveFacetsRefinements||{};Object.keys(s).forEach((function(e){var r=s[e]||[];if(e!==t&&r&&0!==r.length){var i=[];r.forEach((function(t){i.push(e+":"+t)})),n.push(i)}}));var c=e.hierarchicalFacetsRefinements||{};return Object.keys(c).forEach((function(i){var a=(c[i]||[])[0];if(void 0!==a){var s,u,o=e.getHierarchicalFacetByName(i),h=e._getHierarchicalFacetSeparator(o),f=e._getHierarchicalRootPath(o);if(t===i){if(-1===a.indexOf(h)||!f&&!0===r||f&&f.split(h).length===a.split(h).length)return;f?(u=f.split(h).length-1,a=f):(u=a.split(h).length-2,a=a.slice(0,a.lastIndexOf(h))),s=o.attributes[u]}else u=a.split(h).length-1,s=o.attributes[u];s&&n.push([s+":"+a])}})),n},_getHitsHierarchicalFacetsAttributes:function(e){return e.hierarchicalFacets.reduce((function(t,r){var n=e.getHierarchicalRefinement(r.name)[0];if(!n)return t.push(r.attributes[0]),t;var i=e._getHierarchicalFacetSeparator(r),a=n.split(i).length,s=r.attributes.slice(0,a+1);return t.concat(s)}),[])},_getDisjunctiveHierarchicalFacetAttribute:function(e,t,r){var n=e._getHierarchicalFacetSeparator(t);if(!0===r){var i=e._getHierarchicalRootPath(t),a=0;return i&&(a=i.split(n).length),[t.attributes[a]]}var s=(e.getHierarchicalRefinement(t.name)[0]||"").split(n).length-1;return t.attributes.slice(0,s+1)},getSearchForFacetQuery:function(e,t,r,a){var s=a.isDisjunctiveFacet(e)?a.clearRefinements(e):a,c={facetQuery:t,facetName:e};return"number"==typeof r&&(c.maxFacetHits=r),n({},i._getHitsSearchParams(s),c)}};e.exports=i},6801:function(e){"use strict";e.exports=function(e){return null!==e&&/^[a-zA-Z0-9_-]{1,64}$/.test(e)}},4336:function(e){"use strict";e.exports="3.6.2"},290:function(e){e.exports=function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(r){for(var n=1;n=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}function i(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var r=[],n=!0,i=!1,a=void 0;try{for(var s,c=e[Symbol.iterator]();!(n=(s=c.next()).done)&&(r.push(s.value),!t||r.length!==t);n=!0);}catch(e){i=!0,a=e}finally{try{n||null==c.return||c.return()}finally{if(i)throw a}}return r}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){var r=JSON.stringify(e),n=a()[r];return Promise.all([n||t(),void 0!==n])})).then((function(e){var t=i(e,2),n=t[0],a=t[1];return Promise.all([n,a||r.miss(n)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var i=a();return i[JSON.stringify(e)]=t,n().setItem(r,JSON.stringify(i)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=a();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function c(e){var t=a(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return t().then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,i).catch((function(){return c({caches:t}).get(e,n,i)}))},set:function(e,n){return r.set(e,n).catch((function(){return c({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return c({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return c({caches:t}).clear()}))}}}function u(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);var s=n(),c=i&&i.miss||function(){return Promise.resolve()};return s.then((function(e){return c(e)})).then((function(){return s}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function o(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function h(e,t){return t?(Object.keys(t).forEach((function(r){e[r]=t[r](e)})),e):e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var d={Read:1,Write:2,Any:3},v=1,p=2,g=3;function y(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:v;return r(r({},e),{},{status:t,lastUpdate:Date.now()})}function R(e){return"string"==typeof e?{protocol:"https",url:e,accept:d.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||d.Any}}var F="GET",b="POST";function P(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(y(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===v||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===g&&Date.now()-e.lastUpdate<=12e4}(e)})),i=[].concat(a(r),a(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:i.length>0?i.map((function(e){return R(e)})):t}}))}function j(e,t,n,i){var s=[],c=function(e,t){if(e.method!==F&&(void 0!==e.data||void 0!==t.data)){var n=Array.isArray(e.data)?e.data:r(r({},e.data),t.data);return JSON.stringify(n)}}(n,i),u=function(e,t){var n=r(r({},e.headers),t.headers),i={};return Object.keys(n).forEach((function(e){var t=n[e];i[e.toLowerCase()]=t})),i}(e,i),o=n.method,h=n.method!==F?{}:r(r({},n.data),i.data),f=r(r(r({"x-algolia-agent":e.userAgent.value},e.queryParameters),h),i.queryParameters),l=0,m=function t(r,a){var h=r.pop();if(void 0===h)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:O(s)};var m={data:c,headers:u,method:o,url:E(h,n.path,f),connectTimeout:a(l,e.timeouts.connect),responseTimeout:a(l,i.timeout)},d=function(e){var t={request:m,response:e,host:h,triesLeft:r.length};return s.push(t),t},v={onSuccess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var i=d(n);return n.isTimedOut&&l++,Promise.all([e.logger.info("Retryable failure",w(i)),e.hostsCache.set(h,y(h,n.isTimedOut?g:p))]).then((function(){return t(r,a)}))},onFail:function(e){throw d(e),function(e,t){var r=e.content,n=e.status,i=r;try{i=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(i,n,t)}(e,O(s))}};return e.requester.send(m).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&0==~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSuccess(e):t.onFail(e)}(e,v)}))};return P(e.hostsCache,t).then((function(e){return m(a(e.statelessHosts).reverse(),e.getTimeout)}))}function _(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function E(e,t,r){var n=x(r),i="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(i+="?".concat(n)),i}function x(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function O(e){return e.map((function(e){return w(e)}))}function w(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},e),{},{request:r(r({},e.request),{},{headers:r(r({},e.request.headers),t)})})}var N=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===l.WithinHeaders?n:{}},queryParameters:function(){return e===l.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:l.WithinHeaders,t,e.apiKey),a=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,a=e.requestsCache,s=e.responsesCache,c=e.timeouts,u=e.userAgent,o=e.hosts,h=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:a,responsesCache:s,timeouts:c,userAgent:u,headers:e.headers,queryParameters:h,hosts:o.map((function(e){return R(e)})),read:function(e,t){var r=m(t,f.timeouts.read),n=function(){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var a={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(a,(function(){return f.requestsCache.get(a,(function(){return f.requestsCache.set(a,n()).then((function(e){return Promise.all([f.requestsCache.delete(a),e])}),(function(e){return Promise.all([f.requestsCache.delete(a),Promise.reject(e)])})).then((function(e){var t=i(e,2);return t[0],t[1]}))}))}),{miss:function(e){return f.responsesCache.set(a,e)}})},write:function(e,t){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Write)})),e,m(t,f.timeouts.write))}};return f}(r(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:d.Read},{url:"".concat(t,".algolia.net"),accept:d.Write}].concat(o([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:r(r({},n.queryParameters()),e.queryParameters)}));return h({transporter:a,appId:t,addAlgoliaAgent:function(e,t){a.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},e.methods)},A=function(e){return function(t,r){return t.method===F?e.transporter.read(t,r):e.transporter.write(t,r)}},H=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return h({transporter:e.transporter,appId:e.appId,indexName:t},r.methods)}},S=function(e){return function(t,n){var i=t.map((function(e){return r(r({},e),{},{params:x(e.params||{})})}));return e.transporter.read({method:b,path:"1/indexes/*/queries",data:{requests:i},cacheable:!0},n)}},T=function(e){return function(t,i){return Promise.all(t.map((function(t){var a=t.params,s=a.facetName,c=a.facetQuery,u=n(a,["facetName","facetQuery"]);return H(e)(t.indexName,{methods:{searchForFacetValues:k}}).searchForFacetValues(s,c,r(r({},i),u))})))}},Q=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n)}},C=function(e){return function(t,r){return e.transporter.read({method:b,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},k=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},D=1,I=2,q=3;function L(e,t,n){var i,a={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,i=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},a=i(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(a),n=i(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(a),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(a),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(i=q,{debug:function(e,t){return D>=i&&console.debug(e,t),Promise.resolve()},info:function(e,t){return I>=i&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:u(),requestsCache:u({serializable:!1}),hostsCache:c({caches:[s({key:"".concat("4.11.0","-").concat(e)}),u()]}),userAgent:_("4.11.0").add({segment:"Browser",version:"lite"}),authMode:l.WithinQueryParameters};return N(r(r(r({},a),n),{},{methods:{search:S,searchForFacetValues:T,multipleQueries:S,multipleSearchForFacetValues:T,customRequest:A,initIndex:function(e){return function(t){return H(e)(t,{methods:{search:C,searchForFacetValues:k,findAnswers:Q}})}}}}))}return L.version="4.11.0",L}()},9172:function(e,t,r){"use strict";r.r(t),r.d(t,{default:function(){return T}});var n=r(7294),i=r(290),a=r.n(i),s=r(8131),c=r.n(s),u=r(6010),o=r(2859),h=r(9960),f=r(412),l=r(6681),m=r(2263),d=r(907),v=r(9565),p=r(8882),g=r(5999),y="searchQueryInput_dLdO",R="searchVersionInput_oJeg",F="searchResultsColumn_V1kT",b="algoliaLogo_ieE9",P="algoliaLogoPathFill_NLBU",j="searchResultItem_f0c5",_="searchResultItemHeading_59Ih",E="searchResultItemPath_utd2",x="searchResultItemSummary_EzNh",O="searchQueryColumn_qeTZ",w="searchVersionColumn_2Kfj",N="searchLogoColumn_8GYL",A="loadingSpinner_CN74",H="loader_-Se+";function S(e){var t=e.docsSearchVersionsHelpers,r=Object.entries(t.allDocsData).filter((function(e){return e[1].versions.length>1}));return n.createElement("div",{className:(0,u.Z)("col","col--3","padding-left--none",w)},r.map((function(e){var i=e[0],a=e[1],s=r.length>1?i+": ":"";return n.createElement("select",{key:i,onChange:function(e){return t.setSearchVersion(i,e.target.value)},defaultValue:t.searchVersions[i],className:R},a.versions.map((function(e,t){return n.createElement("option",{key:t,label:""+s+e.label,value:e.name})})))})))}var T=function(){var e,t,r,i,s,R,w=(0,m.Z)(),T=w.siteConfig.themeConfig.algolia,Q=T.appId,C=T.apiKey,k=T.indexName,D=T.externalUrlRegex,I=w.i18n.currentLocale,q=(e=(0,l.c2)().selectMessage,function(t){return e(t,(0,g.I)({id:"theme.SearchPage.documentsFound.plurals",description:'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One document found|{count} documents found"},{count:t}))}),L=(t=(0,d._r)(),r=(0,n.useState)((function(){return Object.entries(t).reduce((function(e,t){var r,n=t[0],i=t[1];return Object.assign({},e,((r={})[n]=i.versions[0].name,r))}),{})})),i=r[0],s=r[1],R=Object.values(t).some((function(e){return e.versions.length>1})),{allDocsData:t,versioningEnabled:R,searchVersions:i,setSearchVersion:function(e,t){return s((function(r){var n;return Object.assign({},r,((n={})[e]=t,n))}))}}),V=(0,v.Z)(),B=V.searchQuery,z=V.setSearchQuery,M={items:[],query:null,totalResults:null,totalPages:null,lastPage:null,hasMore:null,loading:null},J=(0,n.useReducer)((function(e,t){switch(t.type){case"reset":return M;case"loading":return Object.assign({},e,{loading:!0});case"update":return B!==t.value.query?e:Object.assign({},t.value,{items:0===t.value.lastPage?t.value.items:e.items.concat(t.value.items)});case"advance":var r=e.totalPages>e.lastPage+1;return Object.assign({},e,{lastPage:r?e.lastPage+1:e.lastPage,hasMore:r});default:return e}}),M),U=J[0],W=J[1],Z=a()(Q,C),K=c()(Z,k,{hitsPerPage:15,advancedSyntax:!0,disjunctiveFacets:["language","docusaurus_tag"]});K.on("result",(function(e){var t=e.results,r=t.query,n=t.hits,i=t.page,a=t.nbHits,s=t.nbPages;if(""!==r&&n instanceof Array){var c=function(e){return e.replace(/algolia-docsearch-suggestion--highlight/g,"search-result-match")},u=n.map((function(e){var t=e.url,r=e._highlightResult.hierarchy,n=e._snippetResult,i=void 0===n?{}:n,a=new URL(t),s=Object.keys(r).map((function(e){return c(r[e].value)}));return{title:s.pop(),url:(0,l.Fx)(D,a.href)?a.href:a.pathname+a.hash,summary:i.content?c(i.content.value)+"...":"",breadcrumbs:s}}));W({type:"update",value:{items:u,query:r,totalResults:a,totalPages:s,lastPage:i,hasMore:s>i+1,loading:!1}})}else W({type:"reset"})}));var G=(0,n.useState)(null),X=G[0],Y=G[1],$=(0,n.useRef)(0),ee=(0,n.useRef)(f.Z.canUseDOM&&new IntersectionObserver((function(e){var t=e[0],r=t.isIntersecting,n=t.boundingClientRect.y;r&&$.current>n&&W({type:"advance"}),$.current=n}),{threshold:1})),te=function(){return B?(0,g.I)({id:"theme.SearchPage.existingResultsTitle",message:'Search results for "{query}"',description:"The search page title for non-empty query"},{query:B}):(0,g.I)({id:"theme.SearchPage.emptyResultsTitle",message:"Search the documentation",description:"The search page title for empty query"})},re=(0,l.ed)((function(e){void 0===e&&(e=0),K.addDisjunctiveFacetRefinement("docusaurus_tag","default"),K.addDisjunctiveFacetRefinement("language",I),Object.entries(L.searchVersions).forEach((function(e){var t=e[0],r=e[1];K.addDisjunctiveFacetRefinement("docusaurus_tag","docs-"+t+"-"+r)})),K.setQuery(B).setPage(e).search()}));return(0,n.useEffect)((function(){if(X){var e=ee.current;return e?(e.observe(X),function(){return e.unobserve(X)}):function(){return!0}}}),[X]),(0,n.useEffect)((function(){W({type:"reset"}),B&&(W({type:"loading"}),setTimeout((function(){re()}),300))}),[B,L.searchVersions,re]),(0,n.useEffect)((function(){U.lastPage&&0!==U.lastPage&&re(U.lastPage)}),[re,U.lastPage]),n.createElement(p.Z,{wrapperClassName:"search-page-wrapper"},n.createElement(o.Z,null,n.createElement("title",null,(0,l.pe)(te())),n.createElement("meta",{property:"robots",content:"noindex, follow"})),n.createElement("div",{className:"container margin-vert--lg"},n.createElement("h1",null,te()),n.createElement("form",{className:"row",onSubmit:function(e){return e.preventDefault()}},n.createElement("div",{className:(0,u.Z)("col",O,{"col--9":L.versioningEnabled,"col--12":!L.versioningEnabled})},n.createElement("input",{type:"search",name:"q",className:y,placeholder:(0,g.I)({id:"theme.SearchPage.inputPlaceholder",message:"Type your search here",description:"The placeholder for search page input"}),"aria-label":(0,g.I)({id:"theme.SearchPage.inputLabel",message:"Search",description:"The ARIA label for search page input"}),onChange:function(e){return z(e.target.value)},value:B,autoComplete:"off",autoFocus:!0})),L.versioningEnabled&&n.createElement(S,{docsSearchVersionsHelpers:L})),n.createElement("div",{className:"row"},n.createElement("div",{className:(0,u.Z)("col","col--8",F)},!!U.totalResults&&q(U.totalResults)),n.createElement("div",{className:(0,u.Z)("col","col--4","text--right",N)},n.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://www.algolia.com/","aria-label":(0,g.I)({id:"theme.SearchPage.algoliaLabel",message:"Search by Algolia",description:"The ARIA label for Algolia mention"})},n.createElement("svg",{viewBox:"0 0 168 24",className:b},n.createElement("g",{fill:"none"},n.createElement("path",{className:P,d:"M120.925 18.804c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 0 0-1.574-.199 5.7 5.7 0 0 0-.897.069 2.699 2.699 0 0 0-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 0 1-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 0 1-1.471-.636 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 0 1 1.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 0 1 1.82-.185 8.404 8.404 0 0 1 1.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 0 0-.384-.73 1.784 1.784 0 0 0-.724-.493 3.164 3.164 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 0 0-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 0 1 2.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 0 0-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 0 0-.814.24 1.46 1.46 0 0 0-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 0 1 .233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 0 1-1.471-.635 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 0 1 2.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 0 0-.109-.875 1.873 1.873 0 0 0-.384-.731 1.784 1.784 0 0 0-.724-.492 3.165 3.165 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 0 0-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 0 1 2.073-.177zm-8.034-1.271a1.626 1.626 0 0 1-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 0 1-1.128 1.906 4.986 4.986 0 0 1-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 0 1-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 0 1-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 0 1 1.15-1.892 5.133 5.133 0 0 1 1.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 0 1 1.753 1.216 5.644 5.644 0 0 1 1.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 0 0-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 0 1-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 0 1-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 0 1 2.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17zM6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 0 0-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 0 1-.582-.271 13.67 13.67 0 0 1-.55-.287 4.275 4.275 0 0 1-.567-.351 6.92 6.92 0 0 1-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 0 1-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 0 0-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 0 0-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 0 0-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 0 1-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z"}),n.createElement("path",{fill:"#5468FF",d:"M78.988.938h16.594a2.968 2.968 0 0 1 2.966 2.966V20.5a2.967 2.967 0 0 1-2.966 2.964H78.988a2.967 2.967 0 0 1-2.966-2.964V3.897A2.961 2.961 0 0 1 78.988.938z"}),n.createElement("path",{fill:"white",d:"M89.632 5.967v-.772a.978.978 0 0 0-.978-.977h-2.28a.978.978 0 0 0-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 0 1 1.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 0 0-1.382 0l-.465.465a.973.973 0 0 0 0 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 0 0-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 0 1-4.49-4.482 4.488 4.488 0 0 1 4.49-4.482 4.488 4.488 0 0 1 4.489 4.482 4.484 4.484 0 0 1-4.49 4.482m0-10.85a6.363 6.363 0 1 0 0 12.729 6.37 6.37 0 0 0 6.372-6.368 6.358 6.358 0 0 0-6.371-6.36"})))))),U.items.length>0?n.createElement("main",null,U.items.map((function(e,t){var r=e.title,i=e.url,a=e.summary,s=e.breadcrumbs;return n.createElement("article",{key:t,className:j},n.createElement("h2",{className:_},n.createElement(h.Z,{to:i,dangerouslySetInnerHTML:{__html:r}})),s.length>0&&n.createElement("nav",{"aria-label":"breadcrumbs"},n.createElement("ul",{className:(0,u.Z)("breadcrumbs",E)},s.map((function(e,t){return n.createElement("li",{key:t,className:"breadcrumbs__item",dangerouslySetInnerHTML:{__html:e}})})))),a&&n.createElement("p",{className:x,dangerouslySetInnerHTML:{__html:a}}))}))):[B&&!U.loading&&n.createElement("p",{key:"no-results"},n.createElement(g.Z,{id:"theme.SearchPage.noResultsText",description:"The paragraph for empty search result"},"No results were found")),!!U.loading&&n.createElement("div",{key:"spinner",className:A})],U.hasMore&&n.createElement("div",{className:H,ref:Y},n.createElement(g.Z,{id:"theme.SearchPage.fetchingNewResults",description:"The paragraph for fetching new search results"},"Fetching new results..."))))}},7187:function(e){function t(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function n(e){return"object"==typeof e&&null!==e}function i(e){return void 0===e}e.exports=t,t.EventEmitter=t,t.prototype._events=void 0,t.prototype._maxListeners=void 0,t.defaultMaxListeners=10,t.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},t.prototype.emit=function(e){var t,a,s,c,u,o;if(this._events||(this._events={}),"error"===e&&(!this._events.error||n(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var h=new Error('Uncaught, unspecified "error" event. ('+t+")");throw h.context=t,h}if(i(a=this._events[e]))return!1;if(r(a))switch(arguments.length){case 1:a.call(this);break;case 2:a.call(this,arguments[1]);break;case 3:a.call(this,arguments[1],arguments[2]);break;default:c=Array.prototype.slice.call(arguments,1),a.apply(this,c)}else if(n(a))for(c=Array.prototype.slice.call(arguments,1),s=(o=a.slice()).length,u=0;u0&&this._events[e].length>s&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},t.prototype.on=t.prototype.addListener,t.prototype.once=function(e,t){if(!r(t))throw TypeError("listener must be a function");var n=!1;function i(){this.removeListener(e,i),n||(n=!0,t.apply(this,arguments))}return i.listener=t,this.on(e,i),this},t.prototype.removeListener=function(e,t){var i,a,s,c;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(s=(i=this._events[e]).length,a=-1,i===t||r(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(n(i)){for(c=s;c-- >0;)if(i[c]===t||i[c].listener&&i[c].listener===t){a=c;break}if(a<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(a,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},t.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r(n=this._events[e]))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},t.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},t.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},t.listenerCount=function(e,t){return e.listenerCount(t)}}}]); \ No newline at end of file +/*! For license information please see 20efc167.a0a53068.js.LICENSE.txt */ +(self.webpackChunkfoomo=self.webpackChunkfoomo||[]).push([[4328],{8131:function(e,t,r){"use strict";var n=r(9374),i=r(7775),a=r(3076);function s(e,t,r){return new n(e,t,r)}s.version=r(4336),s.AlgoliaSearchHelper=n,s.SearchParameters=i,s.SearchResults=a,e.exports=s},8078:function(e,t,r){"use strict";var n=r(7187);function i(e,t){this.main=e,this.fn=t,this.lastResults=null}r(4853)(i,n.EventEmitter),i.prototype.detach=function(){this.removeAllListeners(),this.main.detachDerivedHelper(this)},i.prototype.getModifiedState=function(e){return this.fn(e)},e.exports=i},2437:function(e,t,r){"use strict";var n=r(2344),i=r(9803),a=r(116),s={addRefinement:function(e,t,r){if(s.isRefined(e,t,r))return e;var i=""+r,a=e[t]?e[t].concat(i):[i],c={};return c[t]=a,n({},c,e)},removeRefinement:function(e,t,r){if(void 0===r)return s.clearRefinement(e,(function(e,r){return t===r}));var n=""+r;return s.clearRefinement(e,(function(e,r){return t===r&&n===e}))},toggleRefinement:function(e,t,r){if(void 0===r)throw new Error("toggleRefinement should be used with a value");return s.isRefined(e,t,r)?s.removeRefinement(e,t,r):s.addRefinement(e,t,r)},clearRefinement:function(e,t,r){if(void 0===t)return a(e)?{}:e;if("string"==typeof t)return i(e,[t]);if("function"==typeof t){var n=!1,s=Object.keys(e).reduce((function(i,a){var s=e[a]||[],c=s.filter((function(e){return!t(e,a,r)}));return c.length!==s.length&&(n=!0),i[a]=c,i}),{});return n?s:e}},isRefined:function(e,t,r){var n=!!e[t]&&e[t].length>0;if(void 0===r||!n)return n;var i=""+r;return-1!==e[t].indexOf(i)}};e.exports=s},7775:function(e,t,r){"use strict";var n=r(185),i=r(2344),a=r(2686),s=r(7888),c=r(8023),u=r(9803),o=r(116),h=r(6801),f=r(2437);function l(e,t){return Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((function(e,r){return l(t[r],e)})):e===t}function m(e){var t=e?m._parseNumbers(e):{};void 0===t.userToken||h(t.userToken)||console.warn("[algoliasearch-helper] The `userToken` parameter is invalid. This can lead to wrong analytics.\n - Format: [a-zA-Z0-9_-]{1,64}"),this.facets=t.facets||[],this.disjunctiveFacets=t.disjunctiveFacets||[],this.hierarchicalFacets=t.hierarchicalFacets||[],this.facetsRefinements=t.facetsRefinements||{},this.facetsExcludes=t.facetsExcludes||{},this.disjunctiveFacetsRefinements=t.disjunctiveFacetsRefinements||{},this.numericRefinements=t.numericRefinements||{},this.tagRefinements=t.tagRefinements||[],this.hierarchicalFacetsRefinements=t.hierarchicalFacetsRefinements||{};var r=this;Object.keys(t).forEach((function(e){var n=-1!==m.PARAMETERS.indexOf(e),i=void 0!==t[e];!n&&i&&(r[e]=t[e])}))}m.PARAMETERS=Object.keys(new m),m._parseNumbers=function(e){if(e instanceof m)return e;var t={};if(["aroundPrecision","aroundRadius","getRankingInfo","minWordSizefor2Typos","minWordSizefor1Typo","page","maxValuesPerFacet","distinct","minimumAroundRadius","hitsPerPage","minProximity"].forEach((function(r){var n=e[r];if("string"==typeof n){var i=parseFloat(n);t[r]=isNaN(i)?n:i}})),Array.isArray(e.insideBoundingBox)&&(t.insideBoundingBox=e.insideBoundingBox.map((function(e){return Array.isArray(e)?e.map((function(e){return parseFloat(e)})):e}))),e.numericRefinements){var r={};Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t]||{};r[t]={},Object.keys(n).forEach((function(e){var i=n[e].map((function(e){return Array.isArray(e)?e.map((function(e){return"string"==typeof e?parseFloat(e):e})):"string"==typeof e?parseFloat(e):e}));r[t][e]=i}))})),t.numericRefinements=r}return n({},e,t)},m.make=function(e){var t=new m(e);return(e.hierarchicalFacets||[]).forEach((function(e){if(e.rootPath){var r=t.getHierarchicalRefinement(e.name);r.length>0&&0!==r[0].indexOf(e.rootPath)&&(t=t.clearRefinements(e.name)),0===(r=t.getHierarchicalRefinement(e.name)).length&&(t=t.toggleHierarchicalFacetRefinement(e.name,e.rootPath))}})),t},m.validate=function(e,t){var r=t||{};return e.tagFilters&&r.tagRefinements&&r.tagRefinements.length>0?new Error("[Tags] Cannot switch from the managed tag API to the advanced API. It is probably an error, if it is really what you want, you should first clear the tags with clearTags method."):e.tagRefinements.length>0&&r.tagFilters?new Error("[Tags] Cannot switch from the advanced tag API to the managed API. It is probably an error, if it is not, you should first clear the tags with clearTags method."):e.numericFilters&&r.numericRefinements&&o(r.numericRefinements)?new Error("[Numeric filters] Can't switch from the advanced to the managed API. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):o(e.numericRefinements)&&r.numericFilters?new Error("[Numeric filters] Can't switch from the managed API to the advanced. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):null},m.prototype={constructor:m,clearRefinements:function(e){var t={numericRefinements:this._clearNumericRefinements(e),facetsRefinements:f.clearRefinement(this.facetsRefinements,e,"conjunctiveFacet"),facetsExcludes:f.clearRefinement(this.facetsExcludes,e,"exclude"),disjunctiveFacetsRefinements:f.clearRefinement(this.disjunctiveFacetsRefinements,e,"disjunctiveFacet"),hierarchicalFacetsRefinements:f.clearRefinement(this.hierarchicalFacetsRefinements,e,"hierarchicalFacet")};return t.numericRefinements===this.numericRefinements&&t.facetsRefinements===this.facetsRefinements&&t.facetsExcludes===this.facetsExcludes&&t.disjunctiveFacetsRefinements===this.disjunctiveFacetsRefinements&&t.hierarchicalFacetsRefinements===this.hierarchicalFacetsRefinements?this:this.setQueryParameters(t)},clearTags:function(){return void 0===this.tagFilters&&0===this.tagRefinements.length?this:this.setQueryParameters({tagFilters:void 0,tagRefinements:[]})},setIndex:function(e){return e===this.index?this:this.setQueryParameters({index:e})},setQuery:function(e){return e===this.query?this:this.setQueryParameters({query:e})},setPage:function(e){return e===this.page?this:this.setQueryParameters({page:e})},setFacets:function(e){return this.setQueryParameters({facets:e})},setDisjunctiveFacets:function(e){return this.setQueryParameters({disjunctiveFacets:e})},setHitsPerPage:function(e){return this.hitsPerPage===e?this:this.setQueryParameters({hitsPerPage:e})},setTypoTolerance:function(e){return this.typoTolerance===e?this:this.setQueryParameters({typoTolerance:e})},addNumericRefinement:function(e,t,r){var i=c(r);if(this.isNumericRefined(e,t,i))return this;var a=n({},this.numericRefinements);return a[e]=n({},a[e]),a[e][t]?(a[e][t]=a[e][t].slice(),a[e][t].push(i)):a[e][t]=[i],this.setQueryParameters({numericRefinements:a})},getConjunctiveRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsRefinements[e]||[]},getDisjunctiveRefinements:function(e){return this.isDisjunctiveFacet(e)&&this.disjunctiveFacetsRefinements[e]||[]},getHierarchicalRefinement:function(e){return this.hierarchicalFacetsRefinements[e]||[]},getExcludeRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsExcludes[e]||[]},removeNumericRefinement:function(e,t,r){return void 0!==r?this.isNumericRefined(e,t,r)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(n,i){return i===e&&n.op===t&&l(n.val,c(r))}))}):this:void 0!==t?this.isNumericRefined(e,t)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,n){return n===e&&r.op===t}))}):this:this.isNumericRefined(e)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(t,r){return r===e}))}):this},getNumericRefinements:function(e){return this.numericRefinements[e]||{}},getNumericRefinement:function(e,t){return this.numericRefinements[e]&&this.numericRefinements[e][t]},_clearNumericRefinements:function(e){if(void 0===e)return o(this.numericRefinements)?{}:this.numericRefinements;if("string"==typeof e)return u(this.numericRefinements,[e]);if("function"==typeof e){var t=!1,r=this.numericRefinements,n=Object.keys(r).reduce((function(n,i){var a=r[i],s={};return a=a||{},Object.keys(a).forEach((function(r){var n=a[r]||[],c=[];n.forEach((function(t){e({val:t,op:r},i,"numeric")||c.push(t)})),c.length!==n.length&&(t=!0),s[r]=c})),n[i]=s,n}),{});return t?n:this.numericRefinements}},addFacet:function(e){return this.isConjunctiveFacet(e)?this:this.setQueryParameters({facets:this.facets.concat([e])})},addDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this:this.setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.concat([e])})},addHierarchicalFacet:function(e){if(this.isHierarchicalFacet(e.name))throw new Error("Cannot declare two hierarchical facets with the same name: `"+e.name+"`");return this.setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.concat([e])})},addFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this:this.setQueryParameters({facetsRefinements:f.addRefinement(this.facetsRefinements,e,t)})},addExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this:this.setQueryParameters({facetsExcludes:f.addRefinement(this.facetsExcludes,e,t)})},addDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this:this.setQueryParameters({disjunctiveFacetsRefinements:f.addRefinement(this.disjunctiveFacetsRefinements,e,t)})},addTagRefinement:function(e){if(this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.concat(e)};return this.setQueryParameters(t)},removeFacet:function(e){return this.isConjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({facets:this.facets.filter((function(t){return t!==e}))}):this},removeDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.filter((function(t){return t!==e}))}):this},removeHierarchicalFacet:function(e){return this.isHierarchicalFacet(e)?this.clearRefinements(e).setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.filter((function(t){return t.name!==e}))}):this},removeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this.setQueryParameters({facetsRefinements:f.removeRefinement(this.facetsRefinements,e,t)}):this},removeExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this.setQueryParameters({facetsExcludes:f.removeRefinement(this.facetsExcludes,e,t)}):this},removeDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this.setQueryParameters({disjunctiveFacetsRefinements:f.removeRefinement(this.disjunctiveFacetsRefinements,e,t)}):this},removeTagRefinement:function(e){if(!this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.filter((function(t){return t!==e}))};return this.setQueryParameters(t)},toggleRefinement:function(e,t){return this.toggleFacetRefinement(e,t)},toggleFacetRefinement:function(e,t){if(this.isHierarchicalFacet(e))return this.toggleHierarchicalFacetRefinement(e,t);if(this.isConjunctiveFacet(e))return this.toggleConjunctiveFacetRefinement(e,t);if(this.isDisjunctiveFacet(e))return this.toggleDisjunctiveFacetRefinement(e,t);throw new Error("Cannot refine the undeclared facet "+e+"; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets")},toggleConjunctiveFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsRefinements:f.toggleRefinement(this.facetsRefinements,e,t)})},toggleExcludeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsExcludes:f.toggleRefinement(this.facetsExcludes,e,t)})},toggleDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return this.setQueryParameters({disjunctiveFacetsRefinements:f.toggleRefinement(this.disjunctiveFacetsRefinements,e,t)})},toggleHierarchicalFacetRefinement:function(e,t){if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration");var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e)),n={};return void 0!==this.hierarchicalFacetsRefinements[e]&&this.hierarchicalFacetsRefinements[e].length>0&&(this.hierarchicalFacetsRefinements[e][0]===t||0===this.hierarchicalFacetsRefinements[e][0].indexOf(t+r))?-1===t.indexOf(r)?n[e]=[]:n[e]=[t.slice(0,t.lastIndexOf(r))]:n[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:i({},n,this.hierarchicalFacetsRefinements)})},addHierarchicalFacetRefinement:function(e,t){if(this.isHierarchicalFacetRefined(e))throw new Error(e+" is already refined.");if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration.");var r={};return r[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:i({},r,this.hierarchicalFacetsRefinements)})},removeHierarchicalFacetRefinement:function(e){if(!this.isHierarchicalFacetRefined(e))return this;var t={};return t[e]=[],this.setQueryParameters({hierarchicalFacetsRefinements:i({},t,this.hierarchicalFacetsRefinements)})},toggleTagRefinement:function(e){return this.isTagRefined(e)?this.removeTagRefinement(e):this.addTagRefinement(e)},isDisjunctiveFacet:function(e){return this.disjunctiveFacets.indexOf(e)>-1},isHierarchicalFacet:function(e){return void 0!==this.getHierarchicalFacetByName(e)},isConjunctiveFacet:function(e){return this.facets.indexOf(e)>-1},isFacetRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsRefinements,e,t)},isExcludeRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsExcludes,e,t)},isDisjunctiveFacetRefined:function(e,t){return!!this.isDisjunctiveFacet(e)&&f.isRefined(this.disjunctiveFacetsRefinements,e,t)},isHierarchicalFacetRefined:function(e,t){if(!this.isHierarchicalFacet(e))return!1;var r=this.getHierarchicalRefinement(e);return t?-1!==r.indexOf(t):r.length>0},isNumericRefined:function(e,t,r){if(void 0===r&&void 0===t)return!!this.numericRefinements[e];var n=this.numericRefinements[e]&&void 0!==this.numericRefinements[e][t];if(void 0===r||!n)return n;var i,a,u=c(r),o=void 0!==(i=this.numericRefinements[e][t],a=u,s(i,(function(e){return l(e,a)})));return n&&o},isTagRefined:function(e){return-1!==this.tagRefinements.indexOf(e)},getRefinedDisjunctiveFacets:function(){var e=this,t=a(Object.keys(this.numericRefinements).filter((function(t){return Object.keys(e.numericRefinements[t]).length>0})),this.disjunctiveFacets);return Object.keys(this.disjunctiveFacetsRefinements).filter((function(t){return e.disjunctiveFacetsRefinements[t].length>0})).concat(t).concat(this.getRefinedHierarchicalFacets())},getRefinedHierarchicalFacets:function(){var e=this;return a(this.hierarchicalFacets.map((function(e){return e.name})),Object.keys(this.hierarchicalFacetsRefinements).filter((function(t){return e.hierarchicalFacetsRefinements[t].length>0})))},getUnrefinedDisjunctiveFacets:function(){var e=this.getRefinedDisjunctiveFacets();return this.disjunctiveFacets.filter((function(t){return-1===e.indexOf(t)}))},managedParameters:["index","facets","disjunctiveFacets","facetsRefinements","hierarchicalFacets","facetsExcludes","disjunctiveFacetsRefinements","numericRefinements","tagRefinements","hierarchicalFacetsRefinements"],getQueryParams:function(){var e=this.managedParameters,t={},r=this;return Object.keys(this).forEach((function(n){var i=r[n];-1===e.indexOf(n)&&void 0!==i&&(t[n]=i)})),t},setQueryParameter:function(e,t){if(this[e]===t)return this;var r={};return r[e]=t,this.setQueryParameters(r)},setQueryParameters:function(e){if(!e)return this;var t=m.validate(this,e);if(t)throw t;var r=this,n=m._parseNumbers(e),i=Object.keys(this).reduce((function(e,t){return e[t]=r[t],e}),{}),a=Object.keys(n).reduce((function(e,t){var r=void 0!==e[t],i=void 0!==n[t];return r&&!i?u(e,[t]):(i&&(e[t]=n[t]),e)}),i);return new this.constructor(a)},resetPage:function(){return void 0===this.page?this:this.setPage(0)},_getHierarchicalFacetSortBy:function(e){return e.sortBy||["isRefined:desc","name:asc"]},_getHierarchicalFacetSeparator:function(e){return e.separator||" > "},_getHierarchicalRootPath:function(e){return e.rootPath||null},_getHierarchicalShowParentLevel:function(e){return"boolean"!=typeof e.showParentLevel||e.showParentLevel},getHierarchicalFacetByName:function(e){return s(this.hierarchicalFacets,(function(t){return t.name===e}))},getHierarchicalFacetBreadcrumb:function(e){if(!this.isHierarchicalFacet(e))return[];var t=this.getHierarchicalRefinement(e)[0];if(!t)return[];var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e));return t.split(r).map((function(e){return e.trim()}))},toString:function(){return JSON.stringify(this,null,2)}},e.exports=m},210:function(e,t,r){"use strict";e.exports=function(e){return function(t,r){var s=e.hierarchicalFacets[r],c=e.hierarchicalFacetsRefinements[s.name]&&e.hierarchicalFacetsRefinements[s.name][0]||"",u=e._getHierarchicalFacetSeparator(s),o=e._getHierarchicalRootPath(s),h=e._getHierarchicalShowParentLevel(s),f=a(e._getHierarchicalFacetSortBy(s)),l=t.every((function(e){return e.exhaustive})),m=function(e,t,r,a,s){return function(c,u,o){var h=c;if(o>0){var f=0;for(h=c;f-1})));if(o){var h=o.attributes.indexOf(t),f=u(e.hierarchicalFacets,(function(e){return e.name===o.name}));a.hierarchicalFacets[f][h]={attribute:t,data:s,exhaustive:r.exhaustiveFacetsCount}}else{var v,g=-1!==e.disjunctiveFacets.indexOf(t),y=-1!==e.facets.indexOf(t);g&&(v=d[t],a.disjunctiveFacets[v]={name:t,data:s,exhaustive:r.exhaustiveFacetsCount},l(a.disjunctiveFacets[v],r.facets_stats,t)),y&&(v=m[t],a.facets[v]={name:t,data:s,exhaustive:r.exhaustiveFacetsCount},l(a.facets[v],r.facets_stats,t))}})),this.hierarchicalFacets=s(this.hierarchicalFacets),o.forEach((function(s){var c=t[v],o=c&&c.facets?c.facets:{},h=e.getHierarchicalFacetByName(s);Object.keys(o).forEach((function(t){var s,f=o[t];if(h){s=u(e.hierarchicalFacets,(function(e){return e.name===h.name}));var m=u(a.hierarchicalFacets[s],(function(e){return e.attribute===t}));if(-1===m)return;a.hierarchicalFacets[s][m].data=n({},a.hierarchicalFacets[s][m].data,f)}else{s=d[t];var v=r.facets&&r.facets[t]||{};a.disjunctiveFacets[s]={name:t,data:i({},f,v),exhaustive:c.exhaustiveFacetsCount},l(a.disjunctiveFacets[s],c.facets_stats,t),e.disjunctiveFacetsRefinements[t]&&e.disjunctiveFacetsRefinements[t].forEach((function(r){!a.disjunctiveFacets[s].data[r]&&e.disjunctiveFacetsRefinements[t].indexOf(r)>-1&&(a.disjunctiveFacets[s].data[r]=0)}))}})),v++})),e.getRefinedHierarchicalFacets().forEach((function(r){var n=e.getHierarchicalFacetByName(r),s=e._getHierarchicalFacetSeparator(n),c=e.getHierarchicalRefinement(r);if(!(0===c.length||c[0].split(s).length<2)){var o=t[v],h=o&&o.facets?o.facets:{};Object.keys(h).forEach((function(t){var r=h[t],o=u(e.hierarchicalFacets,(function(e){return e.name===n.name})),f=u(a.hierarchicalFacets[o],(function(e){return e.attribute===t}));if(-1!==f){var l={};if(c.length>0){var m=c[0].split(s)[0];l[m]=a.hierarchicalFacets[o][f].data[m]}a.hierarchicalFacets[o][f].data=i(l,r,a.hierarchicalFacets[o][f].data)}})),v++}})),Object.keys(e.facetsExcludes).forEach((function(t){var n=e.facetsExcludes[t],i=m[t];a.facets[i]={name:t,data:r.facets[t],exhaustive:r.exhaustiveFacetsCount},n.forEach((function(e){a.facets[i]=a.facets[i]||{name:t},a.facets[i].data=a.facets[i].data||{},a.facets[i].data[e]=0}))})),this.hierarchicalFacets=this.hierarchicalFacets.map(h(e)),this.facets=s(this.facets),this.disjunctiveFacets=s(this.disjunctiveFacets),this._state=e}function d(e,t,r,n){if(n=n||0,Array.isArray(t))return e(t,r[n]);if(!t.data||0===t.data.length)return t;var a=t.data.map((function(t){return d(e,t,r,n+1)})),s=e(a,r[n]);return i({data:s},t)}function v(e,t){var r=c(e,(function(e){return e.name===t}));return r&&r.stats}function p(e,t,r,n,i){var a=c(i,(function(e){return e.name===r})),s=a&&a.data&&a.data[n]?a.data[n]:0,u=a&&a.exhaustive||!1;return{type:t,attributeName:r,name:n,count:s,exhaustive:u}}m.prototype.getFacetByName=function(e){function t(t){return t.name===e}return c(this.facets,t)||c(this.disjunctiveFacets,t)||c(this.hierarchicalFacets,t)},m.DEFAULT_SORT=["isRefined:desc","count:desc","name:asc"],m.prototype.getFacetValues=function(e,t){var r=function(e,t){function r(e){return e.name===t}if(e._state.isConjunctiveFacet(t)){var n=c(e.facets,r);return n?Object.keys(n.data).map((function(r){return{name:r,count:n.data[r],isRefined:e._state.isFacetRefined(t,r),isExcluded:e._state.isExcludeRefined(t,r)}})):[]}if(e._state.isDisjunctiveFacet(t)){var i=c(e.disjunctiveFacets,r);return i?Object.keys(i.data).map((function(r){return{name:r,count:i.data[r],isRefined:e._state.isDisjunctiveFacetRefined(t,r)}})):[]}if(e._state.isHierarchicalFacet(t))return c(e.hierarchicalFacets,r)}(this,e);if(r){var n,s=i({},t,{sortBy:m.DEFAULT_SORT,facetOrdering:!(t&&t.sortBy)}),u=this;if(Array.isArray(r))n=[e];else n=u._state.getHierarchicalFacetByName(r.name).attributes;return d((function(e,t){if(s.facetOrdering){var r=function(e,t){return e.renderingContent&&e.renderingContent.facetOrdering&&e.renderingContent.facetOrdering.values&&e.renderingContent.facetOrdering.values[t]}(u,t);if(Boolean(r))return function(e,t){var r=[],n=[],i=(t.order||[]).reduce((function(e,t,r){return e[t]=r,e}),{});e.forEach((function(e){var t=e.path||e.name;void 0!==i[t]?r[i[t]]=e:n.push(e)})),r=r.filter((function(e){return e}));var s,c=t.sortRemainingBy;return"hidden"===c?r:(s="alpha"===c?[["path","name"],["asc","asc"]]:[["count"],["desc"]],r.concat(a(n,s[0],s[1])))}(e,r)}if(Array.isArray(s.sortBy)){var n=o(s.sortBy,m.DEFAULT_SORT);return a(e,n[0],n[1])}if("function"==typeof s.sortBy)return function(e,t){return t.sort(e)}(s.sortBy,e);throw new Error("options.sortBy is optional but if defined it must be either an array of string (predicates) or a sorting function")}),r,n)}},m.prototype.getFacetStats=function(e){return this._state.isConjunctiveFacet(e)?v(this.facets,e):this._state.isDisjunctiveFacet(e)?v(this.disjunctiveFacets,e):void 0},m.prototype.getRefinements=function(){var e=this._state,t=this,r=[];return Object.keys(e.facetsRefinements).forEach((function(n){e.facetsRefinements[n].forEach((function(i){r.push(p(e,"facet",n,i,t.facets))}))})),Object.keys(e.facetsExcludes).forEach((function(n){e.facetsExcludes[n].forEach((function(i){r.push(p(e,"exclude",n,i,t.facets))}))})),Object.keys(e.disjunctiveFacetsRefinements).forEach((function(n){e.disjunctiveFacetsRefinements[n].forEach((function(i){r.push(p(e,"disjunctive",n,i,t.disjunctiveFacets))}))})),Object.keys(e.hierarchicalFacetsRefinements).forEach((function(n){e.hierarchicalFacetsRefinements[n].forEach((function(i){r.push(function(e,t,r,n){var i=e.getHierarchicalFacetByName(t),a=e._getHierarchicalFacetSeparator(i),s=r.split(a),u=c(n,(function(e){return e.name===t})),o=s.reduce((function(e,t){var r=e&&c(e.data,(function(e){return e.name===t}));return void 0!==r?r:e}),u),h=o&&o.count||0,f=o&&o.exhaustive||!1,l=o&&o.path||"";return{type:"hierarchical",attributeName:t,name:l,count:h,exhaustive:f}}(e,n,i,t.hierarchicalFacets))}))})),Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t];Object.keys(n).forEach((function(e){n[e].forEach((function(n){r.push({type:"numeric",attributeName:t,name:n,numericValue:n,operator:e})}))}))})),e.tagRefinements.forEach((function(e){r.push({type:"tag",attributeName:"_tags",name:e})})),r},e.exports=m},9374:function(e,t,r){"use strict";var n=r(7775),i=r(3076),a=r(8078),s=r(6394),c=r(7187),u=r(4853),o=r(116),h=r(9803),f=r(185),l=r(4336);function m(e,t,r){"function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+l+")"),this.setClient(e);var i=r||{};i.index=t,this.state=n.make(i),this.lastResults=null,this._queryId=0,this._lastQueryIdReceived=-1,this.derivedHelpers=[],this._currentNbQueries=0}function d(e){if(e<0)throw new Error("Page requested below 0.");return this._change({state:this.state.setPage(e),isPageReset:!1}),this}function v(){return this.state.page}u(m,c.EventEmitter),m.prototype.search=function(){return this._search({onlyWithDerivedHelpers:!1}),this},m.prototype.searchOnlyWithDerivedHelpers=function(){return this._search({onlyWithDerivedHelpers:!0}),this},m.prototype.getQuery=function(){var e=this.state;return s._getHitsSearchParams(e)},m.prototype.searchOnce=function(e,t){var r=e?this.state.setQueryParameters(e):this.state,n=s._getQueries(r.index,r),a=this;if(this._currentNbQueries++,this.emit("searchOnce",{state:r}),!t)return this.client.search(n).then((function(e){return a._currentNbQueries--,0===a._currentNbQueries&&a.emit("searchQueueEmpty"),{content:new i(r,e.results),state:r,_originalResponse:e}}),(function(e){throw a._currentNbQueries--,0===a._currentNbQueries&&a.emit("searchQueueEmpty"),e}));this.client.search(n).then((function(e){a._currentNbQueries--,0===a._currentNbQueries&&a.emit("searchQueueEmpty"),t(null,new i(r,e.results),r)})).catch((function(e){a._currentNbQueries--,0===a._currentNbQueries&&a.emit("searchQueueEmpty"),t(e,null,r)}))},m.prototype.findAnswers=function(e){var t=this.state,r=this.derivedHelpers[0];if(!r)return Promise.resolve([]);var n=r.getModifiedState(t),i=f({attributesForPrediction:e.attributesForPrediction,nbHits:e.nbHits},{params:h(s._getHitsSearchParams(n),["attributesToSnippet","hitsPerPage","restrictSearchableAttributes","snippetEllipsisText"])}),a="search for answers was called, but this client does not have a function client.initIndex(index).findAnswers";if("function"!=typeof this.client.initIndex)throw new Error(a);var c=this.client.initIndex(n.index);if("function"!=typeof c.findAnswers)throw new Error(a);return c.findAnswers(n.query,e.queryLanguages,i)},m.prototype.searchForFacetValues=function(e,t,r,n){var i="function"==typeof this.client.searchForFacetValues;if(!i&&"function"!=typeof this.client.initIndex)throw new Error("search for facet values (searchable) was called, but this client does not have a function client.searchForFacetValues or client.initIndex(index).searchForFacetValues");var a=this.state.setQueryParameters(n||{}),c=a.isDisjunctiveFacet(e),u=s.getSearchForFacetQuery(e,t,r,a);this._currentNbQueries++;var o=this;return this.emit("searchForFacetValues",{state:a,facet:e,query:t}),(i?this.client.searchForFacetValues([{indexName:a.index,params:u}]):this.client.initIndex(a.index).searchForFacetValues(u)).then((function(t){return o._currentNbQueries--,0===o._currentNbQueries&&o.emit("searchQueueEmpty"),(t=Array.isArray(t)?t[0]:t).facetHits.forEach((function(t){t.isRefined=c?a.isDisjunctiveFacetRefined(e,t.value):a.isFacetRefined(e,t.value)})),t}),(function(e){throw o._currentNbQueries--,0===o._currentNbQueries&&o.emit("searchQueueEmpty"),e}))},m.prototype.setQuery=function(e){return this._change({state:this.state.resetPage().setQuery(e),isPageReset:!0}),this},m.prototype.clearRefinements=function(e){return this._change({state:this.state.resetPage().clearRefinements(e),isPageReset:!0}),this},m.prototype.clearTags=function(){return this._change({state:this.state.resetPage().clearTags(),isPageReset:!0}),this},m.prototype.addDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.addDisjunctiveRefine=function(){return this.addDisjunctiveFacetRefinement.apply(this,arguments)},m.prototype.addHierarchicalFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addHierarchicalFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.addNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().addNumericRefinement(e,t,r),isPageReset:!0}),this},m.prototype.addFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.addRefine=function(){return this.addFacetRefinement.apply(this,arguments)},m.prototype.addFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().addExcludeRefinement(e,t),isPageReset:!0}),this},m.prototype.addExclude=function(){return this.addFacetExclusion.apply(this,arguments)},m.prototype.addTag=function(e){return this._change({state:this.state.resetPage().addTagRefinement(e),isPageReset:!0}),this},m.prototype.removeNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().removeNumericRefinement(e,t,r),isPageReset:!0}),this},m.prototype.removeDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.removeDisjunctiveRefine=function(){return this.removeDisjunctiveFacetRefinement.apply(this,arguments)},m.prototype.removeHierarchicalFacetRefinement=function(e){return this._change({state:this.state.resetPage().removeHierarchicalFacetRefinement(e),isPageReset:!0}),this},m.prototype.removeFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.removeRefine=function(){return this.removeFacetRefinement.apply(this,arguments)},m.prototype.removeFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().removeExcludeRefinement(e,t),isPageReset:!0}),this},m.prototype.removeExclude=function(){return this.removeFacetExclusion.apply(this,arguments)},m.prototype.removeTag=function(e){return this._change({state:this.state.resetPage().removeTagRefinement(e),isPageReset:!0}),this},m.prototype.toggleFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().toggleExcludeFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.toggleExclude=function(){return this.toggleFacetExclusion.apply(this,arguments)},m.prototype.toggleRefinement=function(e,t){return this.toggleFacetRefinement(e,t)},m.prototype.toggleFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().toggleFacetRefinement(e,t),isPageReset:!0}),this},m.prototype.toggleRefine=function(){return this.toggleFacetRefinement.apply(this,arguments)},m.prototype.toggleTag=function(e){return this._change({state:this.state.resetPage().toggleTagRefinement(e),isPageReset:!0}),this},m.prototype.nextPage=function(){var e=this.state.page||0;return this.setPage(e+1)},m.prototype.previousPage=function(){var e=this.state.page||0;return this.setPage(e-1)},m.prototype.setCurrentPage=d,m.prototype.setPage=d,m.prototype.setIndex=function(e){return this._change({state:this.state.resetPage().setIndex(e),isPageReset:!0}),this},m.prototype.setQueryParameter=function(e,t){return this._change({state:this.state.resetPage().setQueryParameter(e,t),isPageReset:!0}),this},m.prototype.setState=function(e){return this._change({state:n.make(e),isPageReset:!1}),this},m.prototype.overrideStateWithoutTriggeringChangeEvent=function(e){return this.state=new n(e),this},m.prototype.hasRefinements=function(e){return!!o(this.state.getNumericRefinements(e))||(this.state.isConjunctiveFacet(e)?this.state.isFacetRefined(e):this.state.isDisjunctiveFacet(e)?this.state.isDisjunctiveFacetRefined(e):!!this.state.isHierarchicalFacet(e)&&this.state.isHierarchicalFacetRefined(e))},m.prototype.isExcluded=function(e,t){return this.state.isExcludeRefined(e,t)},m.prototype.isDisjunctiveRefined=function(e,t){return this.state.isDisjunctiveFacetRefined(e,t)},m.prototype.hasTag=function(e){return this.state.isTagRefined(e)},m.prototype.isTagRefined=function(){return this.hasTagRefinements.apply(this,arguments)},m.prototype.getIndex=function(){return this.state.index},m.prototype.getCurrentPage=v,m.prototype.getPage=v,m.prototype.getTags=function(){return this.state.tagRefinements},m.prototype.getRefinements=function(e){var t=[];if(this.state.isConjunctiveFacet(e))this.state.getConjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"conjunctive"})})),this.state.getExcludeRefinements(e).forEach((function(e){t.push({value:e,type:"exclude"})}));else if(this.state.isDisjunctiveFacet(e)){this.state.getDisjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"disjunctive"})}))}var r=this.state.getNumericRefinements(e);return Object.keys(r).forEach((function(e){var n=r[e];t.push({value:n,operator:e,type:"numeric"})})),t},m.prototype.getNumericRefinement=function(e,t){return this.state.getNumericRefinement(e,t)},m.prototype.getHierarchicalFacetBreadcrumb=function(e){return this.state.getHierarchicalFacetBreadcrumb(e)},m.prototype._search=function(e){var t=this.state,r=[],n=[];e.onlyWithDerivedHelpers||(n=s._getQueries(t.index,t),r.push({state:t,queriesCount:n.length,helper:this}),this.emit("search",{state:t,results:this.lastResults}));var i=this.derivedHelpers.map((function(e){var n=e.getModifiedState(t),i=s._getQueries(n.index,n);return r.push({state:n,queriesCount:i.length,helper:e}),e.emit("search",{state:n,results:e.lastResults}),i})),a=Array.prototype.concat.apply(n,i),c=this._queryId++;this._currentNbQueries++;try{this.client.search(a).then(this._dispatchAlgoliaResponse.bind(this,r,c)).catch(this._dispatchAlgoliaError.bind(this,c))}catch(u){this.emit("error",{error:u})}},m.prototype._dispatchAlgoliaResponse=function(e,t,r){if(!(t0},m.prototype._change=function(e){var t=e.state,r=e.isPageReset;t!==this.state&&(this.state=t,this.emit("change",{state:this.state,results:this.lastResults,isPageReset:r}))},m.prototype.clearCache=function(){return this.client.clearCache&&this.client.clearCache(),this},m.prototype.setClient=function(e){return this.client===e||("function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+l+")"),this.client=e),this},m.prototype.getClient=function(){return this.client},m.prototype.derive=function(e){var t=new a(this,e);return this.derivedHelpers.push(t),t},m.prototype.detachDerivedHelper=function(e){var t=this.derivedHelpers.indexOf(e);if(-1===t)throw new Error("Derived helper already detached");this.derivedHelpers.splice(t,1)},m.prototype.hasPendingRequests=function(){return this._currentNbQueries>0},e.exports=m},4587:function(e){"use strict";e.exports=function(e){return Array.isArray(e)?e.filter(Boolean):[]}},2344:function(e){"use strict";e.exports=function(){var e=Array.prototype.slice.call(arguments);return e.reduceRight((function(e,t){return Object.keys(Object(t)).forEach((function(r){void 0!==t[r]&&(void 0!==e[r]&&delete e[r],e[r]=t[r])})),e}),{})}},7888:function(e){"use strict";e.exports=function(e,t){if(Array.isArray(e))for(var r=0;r1||!a?(e[0].push(i[0]),e[1].push(i[1]),e):(e[0].push(a[0]),e[1].push(a[1]),e)}),[[],[]])}},4853:function(e){"use strict";e.exports=function(e,t){e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}},2686:function(e){"use strict";e.exports=function(e,t){return e.filter((function(r,n){return t.indexOf(r)>-1&&e.indexOf(r)===n}))}},185:function(e){"use strict";function t(e){return"function"==typeof e||Array.isArray(e)||"[object Object]"===Object.prototype.toString.call(e)}function r(e,n){if(e===n)return e;for(var i in n)if(Object.prototype.hasOwnProperty.call(n,i)&&"__proto__"!==i){var a=n[i],s=e[i];void 0!==s&&void 0===a||(t(s)&&t(a)?e[i]=r(s,a):e[i]="object"==typeof(c=a)&&null!==c?r(Array.isArray(c)?[]:{},c):c)}var c;return e}e.exports=function(e){t(e)||(e={});for(var n=1,i=arguments.length;n0}},9803:function(e){"use strict";e.exports=function(e,t){if(null===e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n=0||(i[r]=e[r]);return i}},2148:function(e){"use strict";function t(e,t){if(e!==t){var r=void 0!==e,n=null===e,i=void 0!==t,a=null===t;if(!a&&e>t||n&&i||!r)return 1;if(!n&&e=n.length?a:"desc"===n[i]?-a:a}return e.index-r.index})),i.map((function(e){return e.value}))}},8023:function(e){"use strict";e.exports=function e(t){if("number"==typeof t)return t;if("string"==typeof t)return parseFloat(t);if(Array.isArray(t))return t.map(e);throw new Error("The value should be a number, a parsable string or an array of those.")}},6394:function(e,t,r){"use strict";var n=r(185),i={_getQueries:function(e,t){var r=[];return r.push({indexName:e,params:i._getHitsSearchParams(t)}),t.getRefinedDisjunctiveFacets().forEach((function(n){r.push({indexName:e,params:i._getDisjunctiveFacetSearchParams(t,n)})})),t.getRefinedHierarchicalFacets().forEach((function(n){var a=t.getHierarchicalFacetByName(n),s=t.getHierarchicalRefinement(n),c=t._getHierarchicalFacetSeparator(a);s.length>0&&s[0].split(c).length>1&&r.push({indexName:e,params:i._getDisjunctiveFacetSearchParams(t,n,!0)})})),r},_getHitsSearchParams:function(e){var t=e.facets.concat(e.disjunctiveFacets).concat(i._getHitsHierarchicalFacetsAttributes(e)),r=i._getFacetFilters(e),a=i._getNumericFilters(e),s=i._getTagFilters(e),c={facets:t.indexOf("*")>-1?["*"]:t,tagFilters:s};return r.length>0&&(c.facetFilters=r),a.length>0&&(c.numericFilters=a),n({},e.getQueryParams(),c)},_getDisjunctiveFacetSearchParams:function(e,t,r){var a=i._getFacetFilters(e,t,r),s=i._getNumericFilters(e,t),c={hitsPerPage:1,page:0,attributesToRetrieve:[],attributesToHighlight:[],attributesToSnippet:[],tagFilters:i._getTagFilters(e),analytics:!1,clickAnalytics:!1},u=e.getHierarchicalFacetByName(t);return c.facets=u?i._getDisjunctiveHierarchicalFacetAttribute(e,u,r):t,s.length>0&&(c.numericFilters=s),a.length>0&&(c.facetFilters=a),n({},e.getQueryParams(),c)},_getNumericFilters:function(e,t){if(e.numericFilters)return e.numericFilters;var r=[];return Object.keys(e.numericRefinements).forEach((function(n){var i=e.numericRefinements[n]||{};Object.keys(i).forEach((function(e){var a=i[e]||[];t!==n&&a.forEach((function(t){if(Array.isArray(t)){var i=t.map((function(t){return n+e+t}));r.push(i)}else r.push(n+e+t)}))}))})),r},_getTagFilters:function(e){return e.tagFilters?e.tagFilters:e.tagRefinements.join(",")},_getFacetFilters:function(e,t,r){var n=[],i=e.facetsRefinements||{};Object.keys(i).forEach((function(e){(i[e]||[]).forEach((function(t){n.push(e+":"+t)}))}));var a=e.facetsExcludes||{};Object.keys(a).forEach((function(e){(a[e]||[]).forEach((function(t){n.push(e+":-"+t)}))}));var s=e.disjunctiveFacetsRefinements||{};Object.keys(s).forEach((function(e){var r=s[e]||[];if(e!==t&&r&&0!==r.length){var i=[];r.forEach((function(t){i.push(e+":"+t)})),n.push(i)}}));var c=e.hierarchicalFacetsRefinements||{};return Object.keys(c).forEach((function(i){var a=(c[i]||[])[0];if(void 0!==a){var s,u,o=e.getHierarchicalFacetByName(i),h=e._getHierarchicalFacetSeparator(o),f=e._getHierarchicalRootPath(o);if(t===i){if(-1===a.indexOf(h)||!f&&!0===r||f&&f.split(h).length===a.split(h).length)return;f?(u=f.split(h).length-1,a=f):(u=a.split(h).length-2,a=a.slice(0,a.lastIndexOf(h))),s=o.attributes[u]}else u=a.split(h).length-1,s=o.attributes[u];s&&n.push([s+":"+a])}})),n},_getHitsHierarchicalFacetsAttributes:function(e){return e.hierarchicalFacets.reduce((function(t,r){var n=e.getHierarchicalRefinement(r.name)[0];if(!n)return t.push(r.attributes[0]),t;var i=e._getHierarchicalFacetSeparator(r),a=n.split(i).length,s=r.attributes.slice(0,a+1);return t.concat(s)}),[])},_getDisjunctiveHierarchicalFacetAttribute:function(e,t,r){var n=e._getHierarchicalFacetSeparator(t);if(!0===r){var i=e._getHierarchicalRootPath(t),a=0;return i&&(a=i.split(n).length),[t.attributes[a]]}var s=(e.getHierarchicalRefinement(t.name)[0]||"").split(n).length-1;return t.attributes.slice(0,s+1)},getSearchForFacetQuery:function(e,t,r,a){var s=a.isDisjunctiveFacet(e)?a.clearRefinements(e):a,c={facetQuery:t,facetName:e};return"number"==typeof r&&(c.maxFacetHits=r),n({},i._getHitsSearchParams(s),c)}};e.exports=i},6801:function(e){"use strict";e.exports=function(e){return null!==e&&/^[a-zA-Z0-9_-]{1,64}$/.test(e)}},4336:function(e){"use strict";e.exports="3.6.2"},290:function(e){e.exports=function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(r){for(var n=1;n=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}function i(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var r=[],n=!0,i=!1,a=void 0;try{for(var s,c=e[Symbol.iterator]();!(n=(s=c.next()).done)&&(r.push(s.value),!t||r.length!==t);n=!0);}catch(e){i=!0,a=e}finally{try{n||null==c.return||c.return()}finally{if(i)throw a}}return r}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){var r=JSON.stringify(e),n=a()[r];return Promise.all([n||t(),void 0!==n])})).then((function(e){var t=i(e,2),n=t[0],a=t[1];return Promise.all([n,a||r.miss(n)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var i=a();return i[JSON.stringify(e)]=t,n().setItem(r,JSON.stringify(i)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=a();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function c(e){var t=a(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return t().then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,i).catch((function(){return c({caches:t}).get(e,n,i)}))},set:function(e,n){return r.set(e,n).catch((function(){return c({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return c({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return c({caches:t}).clear()}))}}}function u(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);var s=n(),c=i&&i.miss||function(){return Promise.resolve()};return s.then((function(e){return c(e)})).then((function(){return s}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function o(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function h(e,t){return t?(Object.keys(t).forEach((function(r){e[r]=t[r](e)})),e):e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var d={Read:1,Write:2,Any:3},v=1,p=2,g=3;function y(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:v;return r(r({},e),{},{status:t,lastUpdate:Date.now()})}function R(e){return"string"==typeof e?{protocol:"https",url:e,accept:d.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||d.Any}}var F="GET",b="POST";function P(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(y(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===v||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===g&&Date.now()-e.lastUpdate<=12e4}(e)})),i=[].concat(a(r),a(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:i.length>0?i.map((function(e){return R(e)})):t}}))}function j(e,t,n,i){var s=[],c=function(e,t){if(e.method!==F&&(void 0!==e.data||void 0!==t.data)){var n=Array.isArray(e.data)?e.data:r(r({},e.data),t.data);return JSON.stringify(n)}}(n,i),u=function(e,t){var n=r(r({},e.headers),t.headers),i={};return Object.keys(n).forEach((function(e){var t=n[e];i[e.toLowerCase()]=t})),i}(e,i),o=n.method,h=n.method!==F?{}:r(r({},n.data),i.data),f=r(r(r({"x-algolia-agent":e.userAgent.value},e.queryParameters),h),i.queryParameters),l=0,m=function t(r,a){var h=r.pop();if(void 0===h)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:O(s)};var m={data:c,headers:u,method:o,url:E(h,n.path,f),connectTimeout:a(l,e.timeouts.connect),responseTimeout:a(l,i.timeout)},d=function(e){var t={request:m,response:e,host:h,triesLeft:r.length};return s.push(t),t},v={onSuccess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var i=d(n);return n.isTimedOut&&l++,Promise.all([e.logger.info("Retryable failure",w(i)),e.hostsCache.set(h,y(h,n.isTimedOut?g:p))]).then((function(){return t(r,a)}))},onFail:function(e){throw d(e),function(e,t){var r=e.content,n=e.status,i=r;try{i=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(i,n,t)}(e,O(s))}};return e.requester.send(m).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&0==~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSuccess(e):t.onFail(e)}(e,v)}))};return P(e.hostsCache,t).then((function(e){return m(a(e.statelessHosts).reverse(),e.getTimeout)}))}function _(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function E(e,t,r){var n=x(r),i="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(i+="?".concat(n)),i}function x(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function O(e){return e.map((function(e){return w(e)}))}function w(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},e),{},{request:r(r({},e.request),{},{headers:r(r({},e.request.headers),t)})})}var N=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===l.WithinHeaders?n:{}},queryParameters:function(){return e===l.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:l.WithinHeaders,t,e.apiKey),a=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,a=e.requestsCache,s=e.responsesCache,c=e.timeouts,u=e.userAgent,o=e.hosts,h=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:a,responsesCache:s,timeouts:c,userAgent:u,headers:e.headers,queryParameters:h,hosts:o.map((function(e){return R(e)})),read:function(e,t){var r=m(t,f.timeouts.read),n=function(){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var a={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(a,(function(){return f.requestsCache.get(a,(function(){return f.requestsCache.set(a,n()).then((function(e){return Promise.all([f.requestsCache.delete(a),e])}),(function(e){return Promise.all([f.requestsCache.delete(a),Promise.reject(e)])})).then((function(e){var t=i(e,2);return t[0],t[1]}))}))}),{miss:function(e){return f.responsesCache.set(a,e)}})},write:function(e,t){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Write)})),e,m(t,f.timeouts.write))}};return f}(r(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:d.Read},{url:"".concat(t,".algolia.net"),accept:d.Write}].concat(o([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:r(r({},n.queryParameters()),e.queryParameters)}));return h({transporter:a,appId:t,addAlgoliaAgent:function(e,t){a.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},e.methods)},A=function(e){return function(t,r){return t.method===F?e.transporter.read(t,r):e.transporter.write(t,r)}},H=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return h({transporter:e.transporter,appId:e.appId,indexName:t},r.methods)}},S=function(e){return function(t,n){var i=t.map((function(e){return r(r({},e),{},{params:x(e.params||{})})}));return e.transporter.read({method:b,path:"1/indexes/*/queries",data:{requests:i},cacheable:!0},n)}},T=function(e){return function(t,i){return Promise.all(t.map((function(t){var a=t.params,s=a.facetName,c=a.facetQuery,u=n(a,["facetName","facetQuery"]);return H(e)(t.indexName,{methods:{searchForFacetValues:k}}).searchForFacetValues(s,c,r(r({},i),u))})))}},Q=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n)}},C=function(e){return function(t,r){return e.transporter.read({method:b,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},k=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},D=1,I=2,q=3;function L(e,t,n){var i,a={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,i=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},a=i(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(a),n=i(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(a),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(a),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(i=q,{debug:function(e,t){return D>=i&&console.debug(e,t),Promise.resolve()},info:function(e,t){return I>=i&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:u(),requestsCache:u({serializable:!1}),hostsCache:c({caches:[s({key:"".concat("4.11.0","-").concat(e)}),u()]}),userAgent:_("4.11.0").add({segment:"Browser",version:"lite"}),authMode:l.WithinQueryParameters};return N(r(r(r({},a),n),{},{methods:{search:S,searchForFacetValues:T,multipleQueries:S,multipleSearchForFacetValues:T,customRequest:A,initIndex:function(e){return function(t){return H(e)(t,{methods:{search:C,searchForFacetValues:k,findAnswers:Q}})}}}}))}return L.version="4.11.0",L}()},9172:function(e,t,r){"use strict";r.r(t),r.d(t,{default:function(){return T}});var n=r(7294),i=r(290),a=r.n(i),s=r(8131),c=r.n(s),u=r(6010),o=r(2859),h=r(9960),f=r(412),l=r(6681),m=r(2263),d=r(907),v=r(9565),p=r(8882),g=r(5999),y="searchQueryInput_dLdO",R="searchVersionInput_oJeg",F="searchResultsColumn_V1kT",b="algoliaLogo_ieE9",P="algoliaLogoPathFill_NLBU",j="searchResultItem_f0c5",_="searchResultItemHeading_59Ih",E="searchResultItemPath_utd2",x="searchResultItemSummary_EzNh",O="searchQueryColumn_qeTZ",w="searchVersionColumn_2Kfj",N="searchLogoColumn_8GYL",A="loadingSpinner_CN74",H="loader_-Se+";function S(e){var t=e.docsSearchVersionsHelpers,r=Object.entries(t.allDocsData).filter((function(e){return e[1].versions.length>1}));return n.createElement("div",{className:(0,u.Z)("col","col--3","padding-left--none",w)},r.map((function(e){var i=e[0],a=e[1],s=r.length>1?i+": ":"";return n.createElement("select",{key:i,onChange:function(e){return t.setSearchVersion(i,e.target.value)},defaultValue:t.searchVersions[i],className:R},a.versions.map((function(e,t){return n.createElement("option",{key:t,label:""+s+e.label,value:e.name})})))})))}var T=function(){var e,t,r,i,s,R,w=(0,m.Z)(),T=w.siteConfig.themeConfig.algolia,Q=T.appId,C=T.apiKey,k=T.indexName,D=T.externalUrlRegex,I=w.i18n.currentLocale,q=(e=(0,l.c2)().selectMessage,function(t){return e(t,(0,g.I)({id:"theme.SearchPage.documentsFound.plurals",description:'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One document found|{count} documents found"},{count:t}))}),L=(t=(0,d._r)(),r=(0,n.useState)((function(){return Object.entries(t).reduce((function(e,t){var r,n=t[0],i=t[1];return Object.assign({},e,((r={})[n]=i.versions[0].name,r))}),{})})),i=r[0],s=r[1],R=Object.values(t).some((function(e){return e.versions.length>1})),{allDocsData:t,versioningEnabled:R,searchVersions:i,setSearchVersion:function(e,t){return s((function(r){var n;return Object.assign({},r,((n={})[e]=t,n))}))}}),V=(0,v.Z)(),B=V.searchQuery,z=V.setSearchQuery,M={items:[],query:null,totalResults:null,totalPages:null,lastPage:null,hasMore:null,loading:null},J=(0,n.useReducer)((function(e,t){switch(t.type){case"reset":return M;case"loading":return Object.assign({},e,{loading:!0});case"update":return B!==t.value.query?e:Object.assign({},t.value,{items:0===t.value.lastPage?t.value.items:e.items.concat(t.value.items)});case"advance":var r=e.totalPages>e.lastPage+1;return Object.assign({},e,{lastPage:r?e.lastPage+1:e.lastPage,hasMore:r});default:return e}}),M),U=J[0],W=J[1],Z=a()(Q,C),K=c()(Z,k,{hitsPerPage:15,advancedSyntax:!0,disjunctiveFacets:["language","docusaurus_tag"]});K.on("result",(function(e){var t=e.results,r=t.query,n=t.hits,i=t.page,a=t.nbHits,s=t.nbPages;if(""!==r&&n instanceof Array){var c=function(e){return e.replace(/algolia-docsearch-suggestion--highlight/g,"search-result-match")},u=n.map((function(e){var t=e.url,r=e._highlightResult.hierarchy,n=e._snippetResult,i=void 0===n?{}:n,a=new URL(t),s=Object.keys(r).map((function(e){return c(r[e].value)}));return{title:s.pop(),url:(0,l.Fx)(D,a.href)?a.href:a.pathname+a.hash,summary:i.content?c(i.content.value)+"...":"",breadcrumbs:s}}));W({type:"update",value:{items:u,query:r,totalResults:a,totalPages:s,lastPage:i,hasMore:s>i+1,loading:!1}})}else W({type:"reset"})}));var G=(0,n.useState)(null),X=G[0],Y=G[1],$=(0,n.useRef)(0),ee=(0,n.useRef)(f.Z.canUseDOM&&new IntersectionObserver((function(e){var t=e[0],r=t.isIntersecting,n=t.boundingClientRect.y;r&&$.current>n&&W({type:"advance"}),$.current=n}),{threshold:1})),te=function(){return B?(0,g.I)({id:"theme.SearchPage.existingResultsTitle",message:'Search results for "{query}"',description:"The search page title for non-empty query"},{query:B}):(0,g.I)({id:"theme.SearchPage.emptyResultsTitle",message:"Search the documentation",description:"The search page title for empty query"})},re=(0,l.ed)((function(e){void 0===e&&(e=0),K.addDisjunctiveFacetRefinement("docusaurus_tag","default"),K.addDisjunctiveFacetRefinement("language",I),Object.entries(L.searchVersions).forEach((function(e){var t=e[0],r=e[1];K.addDisjunctiveFacetRefinement("docusaurus_tag","docs-"+t+"-"+r)})),K.setQuery(B).setPage(e).search()}));return(0,n.useEffect)((function(){if(X){var e=ee.current;return e?(e.observe(X),function(){return e.unobserve(X)}):function(){return!0}}}),[X]),(0,n.useEffect)((function(){W({type:"reset"}),B&&(W({type:"loading"}),setTimeout((function(){re()}),300))}),[B,L.searchVersions,re]),(0,n.useEffect)((function(){U.lastPage&&0!==U.lastPage&&re(U.lastPage)}),[re,U.lastPage]),n.createElement(p.Z,{wrapperClassName:"search-page-wrapper"},n.createElement(o.Z,null,n.createElement("title",null,(0,l.pe)(te())),n.createElement("meta",{property:"robots",content:"noindex, follow"})),n.createElement("div",{className:"container margin-vert--lg"},n.createElement("h1",null,te()),n.createElement("form",{className:"row",onSubmit:function(e){return e.preventDefault()}},n.createElement("div",{className:(0,u.Z)("col",O,{"col--9":L.versioningEnabled,"col--12":!L.versioningEnabled})},n.createElement("input",{type:"search",name:"q",className:y,placeholder:(0,g.I)({id:"theme.SearchPage.inputPlaceholder",message:"Type your search here",description:"The placeholder for search page input"}),"aria-label":(0,g.I)({id:"theme.SearchPage.inputLabel",message:"Search",description:"The ARIA label for search page input"}),onChange:function(e){return z(e.target.value)},value:B,autoComplete:"off",autoFocus:!0})),L.versioningEnabled&&n.createElement(S,{docsSearchVersionsHelpers:L})),n.createElement("div",{className:"row"},n.createElement("div",{className:(0,u.Z)("col","col--8",F)},!!U.totalResults&&q(U.totalResults)),n.createElement("div",{className:(0,u.Z)("col","col--4","text--right",N)},n.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://www.algolia.com/","aria-label":(0,g.I)({id:"theme.SearchPage.algoliaLabel",message:"Search by Algolia",description:"The ARIA label for Algolia mention"})},n.createElement("svg",{viewBox:"0 0 168 24",className:b},n.createElement("g",{fill:"none"},n.createElement("path",{className:P,d:"M120.925 18.804c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 0 0-1.574-.199 5.7 5.7 0 0 0-.897.069 2.699 2.699 0 0 0-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 0 1-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 0 1-1.471-.636 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 0 1 1.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 0 1 1.82-.185 8.404 8.404 0 0 1 1.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 0 0-.384-.73 1.784 1.784 0 0 0-.724-.493 3.164 3.164 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 0 0-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 0 1 2.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 0 0-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 0 0-.814.24 1.46 1.46 0 0 0-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 0 1 .233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 0 1-1.471-.635 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 0 1 2.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 0 0-.109-.875 1.873 1.873 0 0 0-.384-.731 1.784 1.784 0 0 0-.724-.492 3.165 3.165 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 0 0-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 0 1 2.073-.177zm-8.034-1.271a1.626 1.626 0 0 1-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 0 1-1.128 1.906 4.986 4.986 0 0 1-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 0 1-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 0 1-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 0 1 1.15-1.892 5.133 5.133 0 0 1 1.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 0 1 1.753 1.216 5.644 5.644 0 0 1 1.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 0 0-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 0 1-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 0 1-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 0 1 2.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17zM6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 0 0-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 0 1-.582-.271 13.67 13.67 0 0 1-.55-.287 4.275 4.275 0 0 1-.567-.351 6.92 6.92 0 0 1-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 0 1-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 0 0-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 0 0-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 0 0-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 0 1-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z"}),n.createElement("path",{fill:"#5468FF",d:"M78.988.938h16.594a2.968 2.968 0 0 1 2.966 2.966V20.5a2.967 2.967 0 0 1-2.966 2.964H78.988a2.967 2.967 0 0 1-2.966-2.964V3.897A2.961 2.961 0 0 1 78.988.938z"}),n.createElement("path",{fill:"white",d:"M89.632 5.967v-.772a.978.978 0 0 0-.978-.977h-2.28a.978.978 0 0 0-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 0 1 1.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 0 0-1.382 0l-.465.465a.973.973 0 0 0 0 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 0 0-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 0 1-4.49-4.482 4.488 4.488 0 0 1 4.49-4.482 4.488 4.488 0 0 1 4.489 4.482 4.484 4.484 0 0 1-4.49 4.482m0-10.85a6.363 6.363 0 1 0 0 12.729 6.37 6.37 0 0 0 6.372-6.368 6.358 6.358 0 0 0-6.371-6.36"})))))),U.items.length>0?n.createElement("main",null,U.items.map((function(e,t){var r=e.title,i=e.url,a=e.summary,s=e.breadcrumbs;return n.createElement("article",{key:t,className:j},n.createElement("h2",{className:_},n.createElement(h.Z,{to:i,dangerouslySetInnerHTML:{__html:r}})),s.length>0&&n.createElement("nav",{"aria-label":"breadcrumbs"},n.createElement("ul",{className:(0,u.Z)("breadcrumbs",E)},s.map((function(e,t){return n.createElement("li",{key:t,className:"breadcrumbs__item",dangerouslySetInnerHTML:{__html:e}})})))),a&&n.createElement("p",{className:x,dangerouslySetInnerHTML:{__html:a}}))}))):[B&&!U.loading&&n.createElement("p",{key:"no-results"},n.createElement(g.Z,{id:"theme.SearchPage.noResultsText",description:"The paragraph for empty search result"},"No results were found")),!!U.loading&&n.createElement("div",{key:"spinner",className:A})],U.hasMore&&n.createElement("div",{className:H,ref:Y},n.createElement(g.Z,{id:"theme.SearchPage.fetchingNewResults",description:"The paragraph for fetching new search results"},"Fetching new results..."))))}},7187:function(e){function t(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function n(e){return"object"==typeof e&&null!==e}function i(e){return void 0===e}e.exports=t,t.EventEmitter=t,t.prototype._events=void 0,t.prototype._maxListeners=void 0,t.defaultMaxListeners=10,t.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},t.prototype.emit=function(e){var t,a,s,c,u,o;if(this._events||(this._events={}),"error"===e&&(!this._events.error||n(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var h=new Error('Uncaught, unspecified "error" event. ('+t+")");throw h.context=t,h}if(i(a=this._events[e]))return!1;if(r(a))switch(arguments.length){case 1:a.call(this);break;case 2:a.call(this,arguments[1]);break;case 3:a.call(this,arguments[1],arguments[2]);break;default:c=Array.prototype.slice.call(arguments,1),a.apply(this,c)}else if(n(a))for(c=Array.prototype.slice.call(arguments,1),s=(o=a.slice()).length,u=0;u0&&this._events[e].length>s&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},t.prototype.on=t.prototype.addListener,t.prototype.once=function(e,t){if(!r(t))throw TypeError("listener must be a function");var n=!1;function i(){this.removeListener(e,i),n||(n=!0,t.apply(this,arguments))}return i.listener=t,this.on(e,i),this},t.prototype.removeListener=function(e,t){var i,a,s,c;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(s=(i=this._events[e]).length,a=-1,i===t||r(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(n(i)){for(c=s;c-- >0;)if(i[c]===t||i[c].listener&&i[c].listener===t){a=c;break}if(a<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(a,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},t.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r(n=this._events[e]))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},t.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},t.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},t.listenerCount=function(e,t){return e.listenerCount(t)}}}]); \ No newline at end of file diff --git a/assets/js/9e4ef427.3bbe91d9.js.LICENSE.txt b/assets/js/20efc167.a0a53068.js.LICENSE.txt similarity index 100% rename from assets/js/9e4ef427.3bbe91d9.js.LICENSE.txt rename to assets/js/20efc167.a0a53068.js.LICENSE.txt diff --git a/assets/js/26ea2a44.3098b877.js b/assets/js/26ea2a44.3098b877.js new file mode 100644 index 0000000..102ef52 --- /dev/null +++ b/assets/js/26ea2a44.3098b877.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkfoomo=self.webpackChunkfoomo||[]).push([[1435],{3905:function(A,e,t){t.d(e,{Zo:function(){return u},kt:function(){return p}});var n=t(7294);function l(A,e,t){return e in A?Object.defineProperty(A,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):A[e]=t,A}function o(A,e){var t=Object.keys(A);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(A);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(A,e).enumerable}))),t.push.apply(t,n)}return t}function a(A){for(var e=1;e=0||(l[t]=A[t]);return l}(A,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(A);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(A,t)&&(l[t]=A[t])}return l}var r=n.createContext({}),s=function(A){var e=n.useContext(r),t=e;return A&&(t="function"==typeof A?A(e):a(a({},e),A)),t},u=function(A){var e=s(A.components);return n.createElement(r.Provider,{value:e},A.children)},g={inlineCode:"code",wrapper:function(A){var e=A.children;return n.createElement(n.Fragment,{},e)}},c=n.forwardRef((function(A,e){var t=A.components,l=A.mdxType,o=A.originalType,r=A.parentName,u=i(A,["components","mdxType","originalType","parentName"]),c=s(t),p=l,d=c["".concat(r,".").concat(p)]||c[p]||g[p]||o;return t?n.createElement(d,a(a({ref:e},u),{},{components:t})):n.createElement(d,a({ref:e},u))}));function p(A,e){var t=arguments,l=e&&e.mdxType;if("string"==typeof A||l){var o=t.length,a=new Array(o);a[0]=c;var i={};for(var r in e)hasOwnProperty.call(e,r)&&(i[r]=e[r]);i.originalType=A,i.mdxType="string"==typeof A?A:l,a[1]=i;for(var s=2;s More bytes = longer download times"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"JS parse and compile time"),": more code you load, more the browser must parse.-> JS gets parsed and compiled on the main thread, when the main thread is busy, the page can't respond to user input"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"JS execution time"),": optimally you will only pack the code that you expect to execute. The more code you want to execute the longer it will take. It's possible that your page won't be interactive until some of this completes.-> JS is also executed on the main thread, if your page runs a lot of code before it's really needed, that also delays your Time to Interactive"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Memory consumption"),": everything fills up the space -> code itself, runtime variables, DOM elements created, etc.-> Pages appear slow when it consumes a lot of memory. Memory leaks can cause your page to freeze up completely!!")),(0,o.kt)("h2",{id:"what-is-the-recommended-bundle-size"},"What is the recommended bundle size?"),(0,o.kt)("p",null,"AS SMALL AS POSSIBLE! I experienced that is not really possible to give a precise answer because each application is different. Generally you want the resources on initial load to be as small as possible, so that you decrease the initial load time, and then load more resources as needed on the fly."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Mr Chao",src:t(5266).Z})),(0,o.kt)("h2",{id:"what-do-we-do-then"},"What do we do then?"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Meh",src:t(7872).Z})),(0,o.kt)("h2",{id:"how-to-start-decreasing-the-bundle-size"},"How to start decreasing the bundle size?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Measure"),": first of all you want to measure. The first step is to use Lighthouse and try to understand the results. It will give you a couple of interesting metrics and some tips. Time to interactive (TTI)\xa0is a good reflection of your bundle size because your bundle needs to be evaluated entirely before a user can interact with your web app."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Analyze"),": Consists on analyzing the bundle in order to detect critical chunks. A useful tool is Webpack Bundle Analyzer.")),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Stonks",src:t(4285).Z})),(0,o.kt)("h2",{id:"breaking-up-the-bundle"},"Breaking up the bundle..."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Monitor network requests"),": These happens between our FCP and TTI. As the initial request for data often occurs when our components initially mount."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Reduce the total dom nodes"),": the less the page needs to render, the less time it takes."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Moving work off the main thread"),": By moving heavy computations to a web worker, the computation will be run on a separate thread, and not block the actual rendering of the page"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Caching"),": Even if not useful for users on first page landing, caching data, bundles, and assets can make subsequent visits way fast")),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Breaking Bad",src:t(6231).Z})),(0,o.kt)("h2",{id:"which-strategies-can-we-adopt"},"Which strategies can we adopt?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Minification and Dead Code Elimination"),": These processes are often summed up as\xa0minifying\xa0or\xa0uglifying."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Tree shaking"),": Tree shaking is dead code elimination on a project or library. Always try to use deps which support \u201ctree shaking\u201d, Bundlephobia could be your friend in this case."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Code Splitting and Lazy Loading"),": Code splitting consists on taking a collection of modules and remove them from the main JS bundle. Lazy loading means we can load this newly created bundle later on."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Replace/rewrite large dependencies"),": Consider replacing or rewriting libraries that are large in size where you might not need all of its functionalities (Moment.js for example)."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Feature module import"),": Check to see if you are using only a feature module of the library that can be imported alone without importing the whole library (Lodash for example).")),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Strategy",src:t(7474).Z})),(0,o.kt)("h2",{id:"useful-tools-to-help-you-reducing-bundle-size"},"Useful tools to help you reducing bundle size"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Lighthouse"),": automated tool for improving the performance, quality, and correctness of your web apps"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Bundlephobia"),": Bundlephobia\xa0helps you find the performance impact of npm packages"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Webpack Bundle Analyzer"),": analyzes your bundle"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"VS Code"),": Import Cost plugin -> Display import/require package size in the editor")),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Tools",src:t(5430).Z})),(0,o.kt)("h2",{id:"conclusion"},"Conclusion"),(0,o.kt)("p",null,"Performance cannot be stripped down to a single metric such as bundle size. It would be great!\nUnfortunately there is no single place to measure all of them.I think metrics like the\xa0Core Web Vitals and a general look at bundle size should be considered as a starting point.\nYou will cry... A lot... But don\u2019t give up!"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"The End",src:t(6090).Z})))}p.isMDXComponent=!0},6231:function(A,e){e.Z="data:image/webp;base64,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"},4509:function(A,e,t){e.Z=t.p+"assets/images/bundle_everywhere-12122e37ab5ca6bcdd61061c4dc32fd4.webp"},1649:function(A,e){e.Z="data:image/webp;base64,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FzF4MYb5dPUHhs5cr4W48fbG0YBO8KzHr+LA17KHdZxYMTAAUpcIp1VnAxgo31955bEsLblDFuBy5dlIEDsrWBpK464x+XXAKVkwXRr/6wHYa71OvfyxCA1GDVeOMppgCM+SdSSV+Z4ZOovufzwbrFiK3sBdeld88AOcgwYxb7qpz7mhGS+zB64o5jXBTZSyA0MDXdYQvBoDLJ20qMaLfoJFEqWGz2rC81rxT/bY7gBgPtFqMlpyIMYi4u3Yf1172FNN4/W/xvmZprZO3IbwFq9PQMoJbQXQrwxVYYZwvWGXERPk2Uhlz9gRWmzNaVqkp7mubKLzLAUJ6lcuebTvMqkcxJJymwmZtTUr5Gxvd/HWyOx2AAfyO55mL93wAKh7ARoMajGsPnAMsEfBuYIWIdlP2J4tFsRWmhppa6AQ0cfFbM4a8+RPS2EsWikEK0LhB4GwUWRPGqjgRduFXpKdIIclPO1V8FWUIErCbCAPvTG621JcUfAF9zBHAyEDUplreZZ7sJWMytQpAAkQo1oYHokzkMAkASVnsb09gWQHFj9DRXBQN7QHdbarq61G9+bdIH7RjBlmBo2PkcAwx6UQB2Gs+3fjaO2CxPFOSFo3qLw54OIXVcwaQOoFyZksQpx38MAMv8LX68Pl6brrz7OlB1oNcsJNDiE7+FeHZ/8/I0oZAAAARVhJRlYAAABNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAADkoYABwAAABIAAABEoAIABAAAAAEAAAGaoAMABAAAAAEAAAEUAAAAAEFTQ0lJAAAAU2NyZWVuc2hvdFhNUCDAAQAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4yNzY8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NDEwPC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6VXNlckNvbW1lbnQ+U2NyZWVuc2hvdDwvZXhpZjpVc2VyQ29tbWVudD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cg=="},7872:function(A,e,t){e.Z=t.p+"assets/images/meh-3b42aead7d2246467fd0101518403734.webp"},5266:function(A,e){e.Z="data:image/webp;base64,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"},4285:function(A,e){e.Z="data:image/webp;base64,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"},7474:function(A,e){e.Z="data:image/webp;base64,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"},6090:function(A,e){e.Z="data:image/webp;base64,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"},5430:function(A,e,t){e.Z=t.p+"assets/images/tools-91886b41cefeef7cc35b5cd21c43d2ba.webp"}}]); \ No newline at end of file diff --git a/assets/js/37e97a4e.0b478ffc.js b/assets/js/37e97a4e.2a4d577e.js similarity index 85% rename from assets/js/37e97a4e.0b478ffc.js rename to assets/js/37e97a4e.2a4d577e.js index 9b200f9..5204a86 100644 --- a/assets/js/37e97a4e.0b478ffc.js +++ b/assets/js/37e97a4e.2a4d577e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfoomo=self.webpackChunkfoomo||[]).push([[8735],{3905:function(e,t,r){r.d(t,{Zo:function(){return c},kt:function(){return h}});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(r),h=o,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||a;return r?n.createElement(m,i(i({ref:t},c),{},{components:r})):n.createElement(m,i({ref:t},c))}));function h(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:o,i[1]=s;for(var p=2;p\n ...\n // include Partytown and set custom path due to multiple frontends\n \n // tag 3rd party script with partytown type\n

Awesome list of software

A list of commercial and open source software we use, because it is awesome.


desktop software

devtools

IDEs

creative tools

cli utilities

k8s / docker

backup

software as a service

productivity / collaboration

CMS

- - + + \ No newline at end of file diff --git a/blog.html b/blog.html index 9137639..c0cddc8 100644 --- a/blog.html +++ b/blog.html @@ -7,12 +7,15 @@ Blog | foomo project docs - - + +
-

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

Nicola Turcato

Intro

JavaScript is parsed, compiled and executed in the main thread of the browser. Which means that users have to wait for all of this before they can interact with the website.

Frontend performance optimization is critical because it accounts for around 80-90% of user response time (10-20% backend). +So when a user is waiting for a page to load, around 80-90% of the time is due to frontend related code and assets.

Nobody likes waiting…

A study found that if a site takes longer than 4 seconds to load, up to 25% of users would abandon the site.

Sending large JavaScript payloads impacts the speed of your site significantly.

Mazzarri

What is a "bundle"?

Your frontend application needs a bunch of JS files to run. These files can be in the format of internal dependency like the JS files you have written yourself. But they can also be external dependencies you use to build your application.

JS bundling is an optimization technique to reduce the number of server requests for JavaScript files. Bundling accomplishes this by merging multiple JA files together into one file to reduce the number of page requests.

Bundle Everywhere

Performance implications

  • Time to transmit over the network: considering slow connections with some mobile devices, it's possible that your page will not be interactive until it loads.-> More bytes = longer download times
  • JS parse and compile time: more code you load, more the browser must parse.-> JS gets parsed and compiled on the main thread, when the main thread is busy, the page can't respond to user input
  • JS execution time: optimally you will only pack the code that you expect to execute. The more code you want to execute the longer it will take. It's possible that your page won't be interactive until some of this completes.-> JS is also executed on the main thread, if your page runs a lot of code before it's really needed, that also delays your Time to Interactive
  • Memory consumption: everything fills up the space -> code itself, runtime variables, DOM elements created, etc.-> Pages appear slow when it consumes a lot of memory. Memory leaks can cause your page to freeze up completely!!

AS SMALL AS POSSIBLE! I experienced that is not really possible to give a precise answer because each application is different. Generally you want the resources on initial load to be as small as possible, so that you decrease the initial load time, and then load more resources as needed on the fly.

Mr Chao

What do we do then?

Meh

How to start decreasing the bundle size?

  • Measure: first of all you want to measure. The first step is to use Lighthouse and try to understand the results. It will give you a couple of interesting metrics and some tips. Time to interactive (TTI) is a good reflection of your bundle size because your bundle needs to be evaluated entirely before a user can interact with your web app.
  • Analyze: Consists on analyzing the bundle in order to detect critical chunks. A useful tool is Webpack Bundle Analyzer.

Stonks

Breaking up the bundle...

  • Monitor network requests: These happens between our FCP and TTI. As the initial request for data often occurs when our components initially mount.
  • Reduce the total dom nodes: the less the page needs to render, the less time it takes.
  • Moving work off the main thread: By moving heavy computations to a web worker, the computation will be run on a separate thread, and not block the actual rendering of the page
  • Caching: Even if not useful for users on first page landing, caching data, bundles, and assets can make subsequent visits way fast

Breaking Bad

Which strategies can we adopt?

  • Minification and Dead Code Elimination: These processes are often summed up as minifying or uglifying.
  • Tree shaking: Tree shaking is dead code elimination on a project or library. Always try to use deps which support “tree shaking”, Bundlephobia could be your friend in this case.
  • Code Splitting and Lazy Loading: Code splitting consists on taking a collection of modules and remove them from the main JS bundle. Lazy loading means we can load this newly created bundle later on.
  • Replace/rewrite large dependencies: Consider replacing or rewriting libraries that are large in size where you might not need all of its functionalities (Moment.js for example).
  • Feature module import: Check to see if you are using only a feature module of the library that can be imported alone without importing the whole library (Lodash for example).

Strategy

Useful tools to help you reducing bundle size

  • Lighthouse: automated tool for improving the performance, quality, and correctness of your web apps
  • Bundlephobia: Bundlephobia helps you find the performance impact of npm packages
  • Webpack Bundle Analyzer: analyzes your bundle
  • VS Code: Import Cost plugin -> Display import/require package size in the editor

Tools

Conclusion

Performance cannot be stripped down to a single metric such as bundle size. It would be great! +Unfortunately there is no single place to measure all of them.I think metrics like the Core Web Vitals and a general look at bundle size should be considered as a starting point. +You will cry... A lot... But don’t give up!

The End

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! Prometheus returns us a 503, a trusty way of saying I'm not ready, and I'm probably going to die soon. And since we're running in kubernetes I'm going to die soon, again and again. And you're getting reports from your colleagues that prometheus is not responding. @@ -35,7 +38,7 @@ We need to deal with it, so that our prometheus instance can breathe again. In t https://github.com/blugelabs/bluge // next iteration of bleve

projects using bluge

All bleeding edge afaik atm - but definitely good places to look at bluge usage

https://github.com/prabhatsharma/zinc https://github.com/mosuka/phalanx

Look ma I made a vector database

Gotta take a look at this one - will report later

https://github.com/semi-technologies/weaviate

Marko Trebižan

Issue with performance

When building an ecommerce site or an application where performance is a great deal for the users, you need to keep your application fast and responsive. Frontend developers have already many use-cases when the UI becomes laggy and this increases when 3rd party scripts are being included, such as Google Tag Manager or various Live chats (e.g. Intercom).

This does not only influences the users when using the site but also Lighthouse score gets lower which also influences page rankings. So the most naive and easy way for this is to defer loading of such scripts but when you need to get all the data from the start of the application, such tactic is not an option. So what else can we do?

Partytown to the rescue

Developers at BuilderIO created an library Partytown that would allow relocating resources from 3rd party scripts off the main thread. We won't dive into specifics how it works, because they explain it nicely on their GitHub page.

In our stack we use Next.js React framework and we will go through the basic steps that will allow us to include Partytown for Google Tag Manager.

Setup

Partytown script needs to be located inside our application and live on the same domain. Since we're using monorepo structure, we need to copy this script across all our frontend application. For that we used CopyPlugin webpack plugin in our Next.js config file:

config.plugins.push(
...
new CopyPlugin({
patterns: [
{
// we copy script from node_modules partytown package to `~partytown` folder in our package that serves static files
from: path.join(path.dirname(require.resolve('@builder.io/partytown')), 'lib'),
// paths for SSR and client side rendering differ
to: path.join(`${isServer ? '..' : '.'}/static/assets/`, '~partytown'),
},
],
})
);

Partytown's requirement is that it needs to know what script should it load into own web worker. For that we set script type to text/partytown. This will prevent script to load on initial load.

Inside _document.tsx we add this:

<Head>
...
// include Partytown and set custom path due to multiple frontends
<Partytown lib={`${addTrailingSlash(this.props.basePath)}_next/static/assets/~partytown/`} debug={false} />
// tag 3rd party script with partytown type
<script type="text/partytown" src={`https://www.googletagmanager.com/gtm.js?id=${id}`} />
...
</Head>

Results

So now, does it work? We used one of our large Ecommerce sites to test the landing Lighthouse score.

This was before adding Partytown:

Lighthouse before Partytown

Here you can see 2 critical things: almost 1s of total blocking time (TBT) and 9s of time to interactive (TTI).

After we added Partytown, we got this:

Lighthouse after Partytown

Time to interactive went from 9s to 6.1s which is almost 33% improvement and total blocking time was reduce by more than 50%! We were more than impressed how easy it was to improve our performances.

Side note: Both screenshots were compressed using Squoosh App.

Next steps

After successful testing of Partytown for Google Tag Manager script, we are more than interested in trying it out on our other scripts. One important topic will be to test Partytown with other service-worker related libraries and how to use them together.

Jan Halfar

A few years ago we abandoned the previous version of https://www.foomo.org as we did not want to maintain the old wordpress installation and the project was only living in README.md in the repos living under https://www.github.com/foomo .

As things have grown over time we have decided to re-launch a website / cross project documentation.

So welcome back and enjoy the view to the past:

blast from the past

- - + + \ No newline at end of file diff --git a/blog/archive.html b/blog/archive.html index 7e9785e..a22b9ec 100644 --- a/blog/archive.html +++ b/blog/archive.html @@ -7,13 +7,13 @@ Archive | foomo project docs - - + + - - +
+ + \ No newline at end of file diff --git a/blog/atom.xml b/blog/atom.xml index 39a374a..c16c83b 100644 --- a/blog/atom.xml +++ b/blog/atom.xml @@ -2,11 +2,26 @@ https://www.foomo.org/blog foomo project docs Blog - 2022-01-25T00:00:00.000Z + 2022-03-17T00:00:00.000Z https://github.com/jpmonette/feed foomo project docs Blog https://www.foomo.org/img/favicon.ico + + <![CDATA[Why bundle size is important?]]> + why-bundle-size-is-important + + 2022-03-17T00:00:00.000Z + + Intro

JavaScript is parsed, compiled and executed in the main thread of the browser. Which means that users have to wait for all of this before they can interact with the website.

Frontend performance optimization is critical because it accounts for around 80-90% of user response time (10-20% backend). +So when a user is waiting for a page to load, around 80-90% of the time is due to frontend related code and assets.

Nobody likes waiting…

A study found that if a site takes longer than 4 seconds to load, up to 25% of users would abandon the site.

Sending large JavaScript payloads impacts the speed of your site significantly.

Mazzarri

What is a "bundle"?

Your frontend application needs a bunch of JS files to run. These files can be in the format of internal dependency like the JS files you have written yourself. But they can also be external dependencies you use to build your application.

JS bundling is an optimization technique to reduce the number of server requests for JavaScript files. Bundling accomplishes this by merging multiple JA files together into one file to reduce the number of page requests.

Bundle Everywhere

Performance implications

  • Time to transmit over the network: considering slow connections with some mobile devices, it's possible that your page will not be interactive until it loads.-> More bytes = longer download times
  • JS parse and compile time: more code you load, more the browser must parse.-> JS gets parsed and compiled on the main thread, when the main thread is busy, the page can't respond to user input
  • JS execution time: optimally you will only pack the code that you expect to execute. The more code you want to execute the longer it will take. It's possible that your page won't be interactive until some of this completes.-> JS is also executed on the main thread, if your page runs a lot of code before it's really needed, that also delays your Time to Interactive
  • Memory consumption: everything fills up the space -> code itself, runtime variables, DOM elements created, etc.-> Pages appear slow when it consumes a lot of memory. Memory leaks can cause your page to freeze up completely!!

What is the recommended bundle size?

AS SMALL AS POSSIBLE! I experienced that is not really possible to give a precise answer because each application is different. Generally you want the resources on initial load to be as small as possible, so that you decrease the initial load time, and then load more resources as needed on the fly.

Mr Chao

What do we do then?

Meh

How to start decreasing the bundle size?

  • Measure: first of all you want to measure. The first step is to use Lighthouse and try to understand the results. It will give you a couple of interesting metrics and some tips. Time to interactive (TTI) is a good reflection of your bundle size because your bundle needs to be evaluated entirely before a user can interact with your web app.
  • Analyze: Consists on analyzing the bundle in order to detect critical chunks. A useful tool is Webpack Bundle Analyzer.

Stonks

Breaking up the bundle...

  • Monitor network requests: These happens between our FCP and TTI. As the initial request for data often occurs when our components initially mount.
  • Reduce the total dom nodes: the less the page needs to render, the less time it takes.
  • Moving work off the main thread: By moving heavy computations to a web worker, the computation will be run on a separate thread, and not block the actual rendering of the page
  • Caching: Even if not useful for users on first page landing, caching data, bundles, and assets can make subsequent visits way fast

Breaking Bad

Which strategies can we adopt?

  • Minification and Dead Code Elimination: These processes are often summed up as minifying or uglifying.
  • Tree shaking: Tree shaking is dead code elimination on a project or library. Always try to use deps which support “tree shaking”, Bundlephobia could be your friend in this case.
  • Code Splitting and Lazy Loading: Code splitting consists on taking a collection of modules and remove them from the main JS bundle. Lazy loading means we can load this newly created bundle later on.
  • Replace/rewrite large dependencies: Consider replacing or rewriting libraries that are large in size where you might not need all of its functionalities (Moment.js for example).
  • Feature module import: Check to see if you are using only a feature module of the library that can be imported alone without importing the whole library (Lodash for example).

Strategy

Useful tools to help you reducing bundle size

  • Lighthouse: automated tool for improving the performance, quality, and correctness of your web apps
  • Bundlephobia: Bundlephobia helps you find the performance impact of npm packages
  • Webpack Bundle Analyzer: analyzes your bundle
  • VS Code: Import Cost plugin -> Display import/require package size in the editor

Tools

Conclusion

Performance cannot be stripped down to a single metric such as bundle size. It would be great! +Unfortunately there is no single place to measure all of them.I think metrics like the Core Web Vitals and a general look at bundle size should be considered as a starting point. +You will cry... A lot... But don’t give up!

The End

]]>
+ + Nicola Turcato + https://github.com/nicolaturcato + +
<![CDATA[Prometheus Is Out Of Memory. Again.]]> prometheus-cardinality-issues diff --git a/blog/debugging-go-map-races-in-k8s.html b/blog/debugging-go-map-races-in-k8s.html index 9e4d749..ff8f56e 100644 --- a/blog/debugging-go-map-races-in-k8s.html +++ b/blog/debugging-go-map-races-in-k8s.html @@ -7,13 +7,13 @@ debugging Go map races in k8s | foomo project docs - - + + - - +
+ + \ No newline at end of file diff --git a/blog/impact-of-3rd-party-scripts-on-performance.html b/blog/impact-of-3rd-party-scripts-on-performance.html index ebe137c..5c9c9ca 100644 --- a/blog/impact-of-3rd-party-scripts-on-performance.html +++ b/blog/impact-of-3rd-party-scripts-on-performance.html @@ -7,14 +7,14 @@ Impact of 3rd party scripts on performance | foomo project docs - - + +
-

Impact of 3rd party scripts on performance

Marko Trebižan

Issue with performance

When building an ecommerce site or an application where performance is a great deal for the users, you need to keep your application fast and responsive. Frontend developers have already many use-cases when the UI becomes laggy and this increases when 3rd party scripts are being included, such as Google Tag Manager or various Live chats (e.g. Intercom).

This does not only influences the users when using the site but also Lighthouse score gets lower which also influences page rankings. So the most naive and easy way for this is to defer loading of such scripts but when you need to get all the data from the start of the application, such tactic is not an option. So what else can we do?

Partytown to the rescue

Developers at BuilderIO created an library Partytown that would allow relocating resources from 3rd party scripts off the main thread. +

Impact of 3rd party scripts on performance

Marko Trebižan

Issue with performance

When building an ecommerce site or an application where performance is a great deal for the users, you need to keep your application fast and responsive. Frontend developers have already many use-cases when the UI becomes laggy and this increases when 3rd party scripts are being included, such as Google Tag Manager or various Live chats (e.g. Intercom).

This does not only influences the users when using the site but also Lighthouse score gets lower which also influences page rankings. So the most naive and easy way for this is to defer loading of such scripts but when you need to get all the data from the start of the application, such tactic is not an option. So what else can we do?

Partytown to the rescue

Developers at BuilderIO created an library Partytown that would allow relocating resources from 3rd party scripts off the main thread. We won't dive into specifics how it works, because they explain it nicely on their GitHub page.

In our stack we use Next.js React framework and we will go through the basic steps that will allow us to include Partytown for Google Tag Manager.

Setup

Partytown script needs to be located inside our application and live on the same domain. Since we're using monorepo structure, we need to copy this script across all our frontend application. For that we used CopyPlugin webpack plugin in our Next.js config file:

config.plugins.push(
...
new CopyPlugin({
patterns: [
{
// we copy script from node_modules partytown package to `~partytown` folder in our package that serves static files
from: path.join(path.dirname(require.resolve('@builder.io/partytown')), 'lib'),
// paths for SSR and client side rendering differ
to: path.join(`${isServer ? '..' : '.'}/static/assets/`, '~partytown'),
},
],
})
);

Partytown's requirement is that it needs to know what script should it load into own web worker. For that we set script type to text/partytown. This will prevent script to load on initial load.

Inside _document.tsx we add this:

<Head>
...
// include Partytown and set custom path due to multiple frontends
<Partytown lib={`${addTrailingSlash(this.props.basePath)}_next/static/assets/~partytown/`} debug={false} />
// tag 3rd party script with partytown type
<script type="text/partytown" src={`https://www.googletagmanager.com/gtm.js?id=${id}`} />
...
</Head>

Results

So now, does it work? We used one of our large Ecommerce sites to test the landing Lighthouse score.

This was before adding Partytown:

Lighthouse before Partytown

Here you can see 2 critical things: almost 1s of total blocking time (TBT) and 9s of time to interactive (TTI).

After we added Partytown, we got this:

Lighthouse after Partytown

Time to interactive went from 9s to 6.1s which is almost 33% improvement and total blocking time was reduce by more than 50%! We were more than impressed how easy it was to improve our performances.

Side note: Both screenshots were compressed using Squoosh App.

Next steps

After successful testing of Partytown for Google Tag Manager script, we are more than interested in trying it out on our other scripts. One important topic will be to test Partytown with other service-worker related libraries and how to use them together.

- - + + \ No newline at end of file diff --git a/blog/prometheus-cardinality-issues.html b/blog/prometheus-cardinality-issues.html index cb6764f..973efa5 100644 --- a/blog/prometheus-cardinality-issues.html +++ b/blog/prometheus-cardinality-issues.html @@ -7,12 +7,12 @@ Prometheus Is Out Of Memory. Again. | foomo project docs - - + +
-

Prometheus Is Out Of Memory. Again.

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

Prometheus Is Out Of Memory. Again.

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! Prometheus returns us a 503, a trusty way of saying I'm not ready, and I'm probably going to die soon. And since we're running in kubernetes I'm going to die soon, again and again. And you're getting reports from your colleagues that prometheus is not responding. @@ -31,8 +31,8 @@ But, imagine someone starts scraping your website for potential vulnerabilities. Or to quote user naveen17797 Scientists predict the number of js frameworks may exceed human population by 2020,at that point of time random string generators will be used to name those frameworks.

The point to this story is, be very mindful of how you use labels and cardinality in prometheus, since that will indeed have great impact on your prometheus performance.

The Solution

Since this has never happened to me (never-ever) I found the following solution to be handy. Since we can't get prometheus up and running to utilize PromQL to detect the potential issues, we have to find another way to detect high cardinality. Therefore, we might want to get our hands dirty with some kubectl exec -it -n monitoring pods/prometheus-prometheus-kube-prometheus-prometheus-0 -- sh, and run the prometheus tsdb analysis too.

/prometheus $ promtool tsdb analyze .

Which produced the result.

> Block ID: 01FT8E8YY4THHZ2S7C3G04GJMG
> Duration: 1h59m59.997s
> Series: 564171
> Label names: 285
> Postings (unique label pairs): 21139
> Postings entries (total label pairs): 6423664
>
> ...
>
> Highest cardinality metric names:
> 11340 haproxy_server_http_responses_total
> ...

We see the potential issue here, where the haproxy_server_http_responses_total metric is having a super-high cardinality which is growing. -We need to deal with it, so that our prometheus instance can breathe again. In this particular case, the solution was updating the haproxy.

... or burn it, up to you.

Flame Thrower

The Further Reading

  1. WAL Definition
  2. WAL & Checkpoints
  3. Using TSDB
  4. Biggest Metrics
  5. Cardinality
- - +We need to deal with it, so that our prometheus instance can breathe again. In this particular case, the solution was updating the haproxy.

... or burn it, up to you.

Flame Thrower

The Further Reading

  1. WAL Definition
  2. WAL & Checkpoints
  3. Using TSDB
  4. Biggest Metrics
  5. Cardinality
+ + \ No newline at end of file diff --git a/blog/rss.xml b/blog/rss.xml index be41445..af3c285 100644 --- a/blog/rss.xml +++ b/blog/rss.xml @@ -4,9 +4,20 @@ foomo project docs Blog https://www.foomo.org/blog foomo project docs Blog - Tue, 25 Jan 2022 00:00:00 GMT + Thu, 17 Mar 2022 00:00:00 GMT https://validator.w3.org/feed/docs/rss2.html https://github.com/jpmonette/feed + + <![CDATA[Why bundle size is important?]]> + https://www.foomo.org/blog/why-bundle-size-is-important + why-bundle-size-is-important + Thu, 17 Mar 2022 00:00:00 GMT + + Intro

JavaScript is parsed, compiled and executed in the main thread of the browser. Which means that users have to wait for all of this before they can interact with the website.

Frontend performance optimization is critical because it accounts for around 80-90% of user response time (10-20% backend). +So when a user is waiting for a page to load, around 80-90% of the time is due to frontend related code and assets.

Nobody likes waiting…

A study found that if a site takes longer than 4 seconds to load, up to 25% of users would abandon the site.

Sending large JavaScript payloads impacts the speed of your site significantly.

Mazzarri

What is a "bundle"?

Your frontend application needs a bunch of JS files to run. These files can be in the format of internal dependency like the JS files you have written yourself. But they can also be external dependencies you use to build your application.

JS bundling is an optimization technique to reduce the number of server requests for JavaScript files. Bundling accomplishes this by merging multiple JA files together into one file to reduce the number of page requests.

Bundle Everywhere

Performance implications

  • Time to transmit over the network: considering slow connections with some mobile devices, it's possible that your page will not be interactive until it loads.-> More bytes = longer download times
  • JS parse and compile time: more code you load, more the browser must parse.-> JS gets parsed and compiled on the main thread, when the main thread is busy, the page can't respond to user input
  • JS execution time: optimally you will only pack the code that you expect to execute. The more code you want to execute the longer it will take. It's possible that your page won't be interactive until some of this completes.-> JS is also executed on the main thread, if your page runs a lot of code before it's really needed, that also delays your Time to Interactive
  • Memory consumption: everything fills up the space -> code itself, runtime variables, DOM elements created, etc.-> Pages appear slow when it consumes a lot of memory. Memory leaks can cause your page to freeze up completely!!

What is the recommended bundle size?

AS SMALL AS POSSIBLE! I experienced that is not really possible to give a precise answer because each application is different. Generally you want the resources on initial load to be as small as possible, so that you decrease the initial load time, and then load more resources as needed on the fly.

Mr Chao

What do we do then?

Meh

How to start decreasing the bundle size?

  • Measure: first of all you want to measure. The first step is to use Lighthouse and try to understand the results. It will give you a couple of interesting metrics and some tips. Time to interactive (TTI) is a good reflection of your bundle size because your bundle needs to be evaluated entirely before a user can interact with your web app.
  • Analyze: Consists on analyzing the bundle in order to detect critical chunks. A useful tool is Webpack Bundle Analyzer.

Stonks

Breaking up the bundle...

  • Monitor network requests: These happens between our FCP and TTI. As the initial request for data often occurs when our components initially mount.
  • Reduce the total dom nodes: the less the page needs to render, the less time it takes.
  • Moving work off the main thread: By moving heavy computations to a web worker, the computation will be run on a separate thread, and not block the actual rendering of the page
  • Caching: Even if not useful for users on first page landing, caching data, bundles, and assets can make subsequent visits way fast

Breaking Bad

Which strategies can we adopt?

  • Minification and Dead Code Elimination: These processes are often summed up as minifying or uglifying.
  • Tree shaking: Tree shaking is dead code elimination on a project or library. Always try to use deps which support “tree shaking”, Bundlephobia could be your friend in this case.
  • Code Splitting and Lazy Loading: Code splitting consists on taking a collection of modules and remove them from the main JS bundle. Lazy loading means we can load this newly created bundle later on.
  • Replace/rewrite large dependencies: Consider replacing or rewriting libraries that are large in size where you might not need all of its functionalities (Moment.js for example).
  • Feature module import: Check to see if you are using only a feature module of the library that can be imported alone without importing the whole library (Lodash for example).

Strategy

Useful tools to help you reducing bundle size

  • Lighthouse: automated tool for improving the performance, quality, and correctness of your web apps
  • Bundlephobia: Bundlephobia helps you find the performance impact of npm packages
  • Webpack Bundle Analyzer: analyzes your bundle
  • VS Code: Import Cost plugin -> Display import/require package size in the editor

Tools

Conclusion

Performance cannot be stripped down to a single metric such as bundle size. It would be great! +Unfortunately there is no single place to measure all of them.I think metrics like the Core Web Vitals and a general look at bundle size should be considered as a starting point. +You will cry... A lot... But don’t give up!

The End

]]>
+
<![CDATA[Prometheus Is Out Of Memory. Again.]]> https://www.foomo.org/blog/prometheus-cardinality-issues diff --git a/blog/searching-for-search-engines.html b/blog/searching-for-search-engines.html index bfdc977..8caee0b 100644 --- a/blog/searching-for-search-engines.html +++ b/blog/searching-for-search-engines.html @@ -7,15 +7,15 @@ The never ending search a search engine 2022-01 edition | foomo project docs - - + +
-

The never ending search a search engine 2022-01 edition

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve +

The never ending search a search engine 2022-01 edition

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve https://github.com/blugelabs/bluge // next iteration of bleve

projects using bluge

All bleeding edge afaik atm - but definitely good places to look at bluge usage

https://github.com/prabhatsharma/zinc https://github.com/mosuka/phalanx

Look ma I made a vector database

Gotta take a look at this one - will report later

https://github.com/semi-technologies/weaviate

- - + + \ No newline at end of file diff --git a/blog/tags.html b/blog/tags.html index 35192c1..75aa6f7 100644 --- a/blog/tags.html +++ b/blog/tags.html @@ -7,13 +7,13 @@ Tags | foomo project docs - - + + - - +
+ + \ No newline at end of file diff --git a/blog/tags/backend.html b/blog/tags/backend.html index 2422c11..584f836 100644 --- a/blog/tags/backend.html +++ b/blog/tags/backend.html @@ -7,15 +7,15 @@ 2 posts tagged with "backend" | foomo project docs - - + +
-

2 posts tagged with "backend"

View All Tags

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve +

2 posts tagged with "backend"

View All Tags

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve https://github.com/blugelabs/bluge // next iteration of bleve

projects using bluge

All bleeding edge afaik atm - but definitely good places to look at bluge usage

https://github.com/prabhatsharma/zinc https://github.com/mosuka/phalanx

Look ma I made a vector database

Gotta take a look at this one - will report later

https://github.com/semi-technologies/weaviate

- - + + \ No newline at end of file diff --git a/blog/tags/bundle-size.html b/blog/tags/bundle-size.html new file mode 100644 index 0000000..bb2aeaf --- /dev/null +++ b/blog/tags/bundle-size.html @@ -0,0 +1,22 @@ + + + + + + + + +One post tagged with "bundle size" | foomo project docs + + + + +
+

One post tagged with "bundle size"

View All Tags

Nicola Turcato

Intro

JavaScript is parsed, compiled and executed in the main thread of the browser. Which means that users have to wait for all of this before they can interact with the website.

Frontend performance optimization is critical because it accounts for around 80-90% of user response time (10-20% backend). +So when a user is waiting for a page to load, around 80-90% of the time is due to frontend related code and assets.

Nobody likes waiting…

A study found that if a site takes longer than 4 seconds to load, up to 25% of users would abandon the site.

Sending large JavaScript payloads impacts the speed of your site significantly.

Mazzarri

What is a "bundle"?

Your frontend application needs a bunch of JS files to run. These files can be in the format of internal dependency like the JS files you have written yourself. But they can also be external dependencies you use to build your application.

JS bundling is an optimization technique to reduce the number of server requests for JavaScript files. Bundling accomplishes this by merging multiple JA files together into one file to reduce the number of page requests.

Bundle Everywhere

Performance implications

  • Time to transmit over the network: considering slow connections with some mobile devices, it's possible that your page will not be interactive until it loads.-> More bytes = longer download times
  • JS parse and compile time: more code you load, more the browser must parse.-> JS gets parsed and compiled on the main thread, when the main thread is busy, the page can't respond to user input
  • JS execution time: optimally you will only pack the code that you expect to execute. The more code you want to execute the longer it will take. It's possible that your page won't be interactive until some of this completes.-> JS is also executed on the main thread, if your page runs a lot of code before it's really needed, that also delays your Time to Interactive
  • Memory consumption: everything fills up the space -> code itself, runtime variables, DOM elements created, etc.-> Pages appear slow when it consumes a lot of memory. Memory leaks can cause your page to freeze up completely!!

AS SMALL AS POSSIBLE! I experienced that is not really possible to give a precise answer because each application is different. Generally you want the resources on initial load to be as small as possible, so that you decrease the initial load time, and then load more resources as needed on the fly.

Mr Chao

What do we do then?

Meh

How to start decreasing the bundle size?

  • Measure: first of all you want to measure. The first step is to use Lighthouse and try to understand the results. It will give you a couple of interesting metrics and some tips. Time to interactive (TTI) is a good reflection of your bundle size because your bundle needs to be evaluated entirely before a user can interact with your web app.
  • Analyze: Consists on analyzing the bundle in order to detect critical chunks. A useful tool is Webpack Bundle Analyzer.

Stonks

Breaking up the bundle...

  • Monitor network requests: These happens between our FCP and TTI. As the initial request for data often occurs when our components initially mount.
  • Reduce the total dom nodes: the less the page needs to render, the less time it takes.
  • Moving work off the main thread: By moving heavy computations to a web worker, the computation will be run on a separate thread, and not block the actual rendering of the page
  • Caching: Even if not useful for users on first page landing, caching data, bundles, and assets can make subsequent visits way fast

Breaking Bad

Which strategies can we adopt?

  • Minification and Dead Code Elimination: These processes are often summed up as minifying or uglifying.
  • Tree shaking: Tree shaking is dead code elimination on a project or library. Always try to use deps which support “tree shaking”, Bundlephobia could be your friend in this case.
  • Code Splitting and Lazy Loading: Code splitting consists on taking a collection of modules and remove them from the main JS bundle. Lazy loading means we can load this newly created bundle later on.
  • Replace/rewrite large dependencies: Consider replacing or rewriting libraries that are large in size where you might not need all of its functionalities (Moment.js for example).
  • Feature module import: Check to see if you are using only a feature module of the library that can be imported alone without importing the whole library (Lodash for example).

Strategy

Useful tools to help you reducing bundle size

  • Lighthouse: automated tool for improving the performance, quality, and correctness of your web apps
  • Bundlephobia: Bundlephobia helps you find the performance impact of npm packages
  • Webpack Bundle Analyzer: analyzes your bundle
  • VS Code: Import Cost plugin -> Display import/require package size in the editor

Tools

Conclusion

Performance cannot be stripped down to a single metric such as bundle size. It would be great! +Unfortunately there is no single place to measure all of them.I think metrics like the Core Web Vitals and a general look at bundle size should be considered as a starting point. +You will cry... A lot... But don’t give up!

The End

+ + + + \ No newline at end of file diff --git a/blog/tags/bundle.html b/blog/tags/bundle.html new file mode 100644 index 0000000..cf8667b --- /dev/null +++ b/blog/tags/bundle.html @@ -0,0 +1,22 @@ + + + + + + + + +One post tagged with "bundle" | foomo project docs + + + + +
+

One post tagged with "bundle"

View All Tags

Nicola Turcato

Intro

JavaScript is parsed, compiled and executed in the main thread of the browser. Which means that users have to wait for all of this before they can interact with the website.

Frontend performance optimization is critical because it accounts for around 80-90% of user response time (10-20% backend). +So when a user is waiting for a page to load, around 80-90% of the time is due to frontend related code and assets.

Nobody likes waiting…

A study found that if a site takes longer than 4 seconds to load, up to 25% of users would abandon the site.

Sending large JavaScript payloads impacts the speed of your site significantly.

Mazzarri

What is a "bundle"?

Your frontend application needs a bunch of JS files to run. These files can be in the format of internal dependency like the JS files you have written yourself. But they can also be external dependencies you use to build your application.

JS bundling is an optimization technique to reduce the number of server requests for JavaScript files. Bundling accomplishes this by merging multiple JA files together into one file to reduce the number of page requests.

Bundle Everywhere

Performance implications

  • Time to transmit over the network: considering slow connections with some mobile devices, it's possible that your page will not be interactive until it loads.-> More bytes = longer download times
  • JS parse and compile time: more code you load, more the browser must parse.-> JS gets parsed and compiled on the main thread, when the main thread is busy, the page can't respond to user input
  • JS execution time: optimally you will only pack the code that you expect to execute. The more code you want to execute the longer it will take. It's possible that your page won't be interactive until some of this completes.-> JS is also executed on the main thread, if your page runs a lot of code before it's really needed, that also delays your Time to Interactive
  • Memory consumption: everything fills up the space -> code itself, runtime variables, DOM elements created, etc.-> Pages appear slow when it consumes a lot of memory. Memory leaks can cause your page to freeze up completely!!

AS SMALL AS POSSIBLE! I experienced that is not really possible to give a precise answer because each application is different. Generally you want the resources on initial load to be as small as possible, so that you decrease the initial load time, and then load more resources as needed on the fly.

Mr Chao

What do we do then?

Meh

How to start decreasing the bundle size?

  • Measure: first of all you want to measure. The first step is to use Lighthouse and try to understand the results. It will give you a couple of interesting metrics and some tips. Time to interactive (TTI) is a good reflection of your bundle size because your bundle needs to be evaluated entirely before a user can interact with your web app.
  • Analyze: Consists on analyzing the bundle in order to detect critical chunks. A useful tool is Webpack Bundle Analyzer.

Stonks

Breaking up the bundle...

  • Monitor network requests: These happens between our FCP and TTI. As the initial request for data often occurs when our components initially mount.
  • Reduce the total dom nodes: the less the page needs to render, the less time it takes.
  • Moving work off the main thread: By moving heavy computations to a web worker, the computation will be run on a separate thread, and not block the actual rendering of the page
  • Caching: Even if not useful for users on first page landing, caching data, bundles, and assets can make subsequent visits way fast

Breaking Bad

Which strategies can we adopt?

  • Minification and Dead Code Elimination: These processes are often summed up as minifying or uglifying.
  • Tree shaking: Tree shaking is dead code elimination on a project or library. Always try to use deps which support “tree shaking”, Bundlephobia could be your friend in this case.
  • Code Splitting and Lazy Loading: Code splitting consists on taking a collection of modules and remove them from the main JS bundle. Lazy loading means we can load this newly created bundle later on.
  • Replace/rewrite large dependencies: Consider replacing or rewriting libraries that are large in size where you might not need all of its functionalities (Moment.js for example).
  • Feature module import: Check to see if you are using only a feature module of the library that can be imported alone without importing the whole library (Lodash for example).

Strategy

Useful tools to help you reducing bundle size

  • Lighthouse: automated tool for improving the performance, quality, and correctness of your web apps
  • Bundlephobia: Bundlephobia helps you find the performance impact of npm packages
  • Webpack Bundle Analyzer: analyzes your bundle
  • VS Code: Import Cost plugin -> Display import/require package size in the editor

Tools

Conclusion

Performance cannot be stripped down to a single metric such as bundle size. It would be great! +Unfortunately there is no single place to measure all of them.I think metrics like the Core Web Vitals and a general look at bundle size should be considered as a starting point. +You will cry... A lot... But don’t give up!

The End

+ + + + \ No newline at end of file diff --git a/blog/tags/cardinality.html b/blog/tags/cardinality.html index 9834865..bd1edfa 100644 --- a/blog/tags/cardinality.html +++ b/blog/tags/cardinality.html @@ -7,12 +7,12 @@ One post tagged with "cardinality" | foomo project docs - - + +
-

One post tagged with "cardinality"

View All Tags

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

- - + + \ No newline at end of file diff --git a/blog/tags/debugging.html b/blog/tags/debugging.html index 1ce5156..3a9b470 100644 --- a/blog/tags/debugging.html +++ b/blog/tags/debugging.html @@ -7,13 +7,13 @@ One post tagged with "debugging" | foomo project docs - - + + - - +
+ + \ No newline at end of file diff --git a/blog/tags/devops.html b/blog/tags/devops.html index 304b2b1..171fd46 100644 --- a/blog/tags/devops.html +++ b/blog/tags/devops.html @@ -7,12 +7,12 @@ One post tagged with "devops" | foomo project docs - - + +
-

One post tagged with "devops"

View All Tags

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

- - + + \ No newline at end of file diff --git a/blog/tags/foomo.html b/blog/tags/foomo.html index b27ffe4..69b03a6 100644 --- a/blog/tags/foomo.html +++ b/blog/tags/foomo.html @@ -7,13 +7,13 @@ One post tagged with "foomo" | foomo project docs - - + +
-

One post tagged with "foomo"

View All Tags
- - +

One post tagged with "foomo"

View All Tags
+ + \ No newline at end of file diff --git a/blog/tags/frontend.html b/blog/tags/frontend.html index 6e0fe39..168cb5e 100644 --- a/blog/tags/frontend.html +++ b/blog/tags/frontend.html @@ -7,14 +7,14 @@ One post tagged with "frontend" | foomo project docs - - + +
-

One post tagged with "frontend"

View All Tags

Marko Trebižan

Issue with performance

When building an ecommerce site or an application where performance is a great deal for the users, you need to keep your application fast and responsive. Frontend developers have already many use-cases when the UI becomes laggy and this increases when 3rd party scripts are being included, such as Google Tag Manager or various Live chats (e.g. Intercom).

This does not only influences the users when using the site but also Lighthouse score gets lower which also influences page rankings. So the most naive and easy way for this is to defer loading of such scripts but when you need to get all the data from the start of the application, such tactic is not an option. So what else can we do?

Partytown to the rescue

Developers at BuilderIO created an library Partytown that would allow relocating resources from 3rd party scripts off the main thread. +

One post tagged with "frontend"

View All Tags

Marko Trebižan

Issue with performance

When building an ecommerce site or an application where performance is a great deal for the users, you need to keep your application fast and responsive. Frontend developers have already many use-cases when the UI becomes laggy and this increases when 3rd party scripts are being included, such as Google Tag Manager or various Live chats (e.g. Intercom).

This does not only influences the users when using the site but also Lighthouse score gets lower which also influences page rankings. So the most naive and easy way for this is to defer loading of such scripts but when you need to get all the data from the start of the application, such tactic is not an option. So what else can we do?

Partytown to the rescue

Developers at BuilderIO created an library Partytown that would allow relocating resources from 3rd party scripts off the main thread. We won't dive into specifics how it works, because they explain it nicely on their GitHub page.

In our stack we use Next.js React framework and we will go through the basic steps that will allow us to include Partytown for Google Tag Manager.

Setup

Partytown script needs to be located inside our application and live on the same domain. Since we're using monorepo structure, we need to copy this script across all our frontend application. For that we used CopyPlugin webpack plugin in our Next.js config file:

config.plugins.push(
...
new CopyPlugin({
patterns: [
{
// we copy script from node_modules partytown package to `~partytown` folder in our package that serves static files
from: path.join(path.dirname(require.resolve('@builder.io/partytown')), 'lib'),
// paths for SSR and client side rendering differ
to: path.join(`${isServer ? '..' : '.'}/static/assets/`, '~partytown'),
},
],
})
);

Partytown's requirement is that it needs to know what script should it load into own web worker. For that we set script type to text/partytown. This will prevent script to load on initial load.

Inside _document.tsx we add this:

<Head>
...
// include Partytown and set custom path due to multiple frontends
<Partytown lib={`${addTrailingSlash(this.props.basePath)}_next/static/assets/~partytown/`} debug={false} />
// tag 3rd party script with partytown type
<script type="text/partytown" src={`https://www.googletagmanager.com/gtm.js?id=${id}`} />
...
</Head>

Results

So now, does it work? We used one of our large Ecommerce sites to test the landing Lighthouse score.

This was before adding Partytown:

Lighthouse before Partytown

Here you can see 2 critical things: almost 1s of total blocking time (TBT) and 9s of time to interactive (TTI).

After we added Partytown, we got this:

Lighthouse after Partytown

Time to interactive went from 9s to 6.1s which is almost 33% improvement and total blocking time was reduce by more than 50%! We were more than impressed how easy it was to improve our performances.

Side note: Both screenshots were compressed using Squoosh App.

Next steps

After successful testing of Partytown for Google Tag Manager script, we are more than interested in trying it out on our other scripts. One important topic will be to test Partytown with other service-worker related libraries and how to use them together.

- - + + \ No newline at end of file diff --git a/blog/tags/go.html b/blog/tags/go.html index e9f3d73..21ba2fb 100644 --- a/blog/tags/go.html +++ b/blog/tags/go.html @@ -7,15 +7,15 @@ 2 posts tagged with "go" | foomo project docs - - + +
-

2 posts tagged with "go"

View All Tags

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve +

2 posts tagged with "go"

View All Tags

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve https://github.com/blugelabs/bluge // next iteration of bleve

projects using bluge

All bleeding edge afaik atm - but definitely good places to look at bluge usage

https://github.com/prabhatsharma/zinc https://github.com/mosuka/phalanx

Look ma I made a vector database

Gotta take a look at this one - will report later

https://github.com/semi-technologies/weaviate

- - + + \ No newline at end of file diff --git a/blog/tags/javascript.html b/blog/tags/javascript.html new file mode 100644 index 0000000..ec6dbf2 --- /dev/null +++ b/blog/tags/javascript.html @@ -0,0 +1,22 @@ + + + + + + + + +One post tagged with "javascript" | foomo project docs + + + + +
+

One post tagged with "javascript"

View All Tags

Nicola Turcato

Intro

JavaScript is parsed, compiled and executed in the main thread of the browser. Which means that users have to wait for all of this before they can interact with the website.

Frontend performance optimization is critical because it accounts for around 80-90% of user response time (10-20% backend). +So when a user is waiting for a page to load, around 80-90% of the time is due to frontend related code and assets.

Nobody likes waiting…

A study found that if a site takes longer than 4 seconds to load, up to 25% of users would abandon the site.

Sending large JavaScript payloads impacts the speed of your site significantly.

Mazzarri

What is a "bundle"?

Your frontend application needs a bunch of JS files to run. These files can be in the format of internal dependency like the JS files you have written yourself. But they can also be external dependencies you use to build your application.

JS bundling is an optimization technique to reduce the number of server requests for JavaScript files. Bundling accomplishes this by merging multiple JA files together into one file to reduce the number of page requests.

Bundle Everywhere

Performance implications

  • Time to transmit over the network: considering slow connections with some mobile devices, it's possible that your page will not be interactive until it loads.-> More bytes = longer download times
  • JS parse and compile time: more code you load, more the browser must parse.-> JS gets parsed and compiled on the main thread, when the main thread is busy, the page can't respond to user input
  • JS execution time: optimally you will only pack the code that you expect to execute. The more code you want to execute the longer it will take. It's possible that your page won't be interactive until some of this completes.-> JS is also executed on the main thread, if your page runs a lot of code before it's really needed, that also delays your Time to Interactive
  • Memory consumption: everything fills up the space -> code itself, runtime variables, DOM elements created, etc.-> Pages appear slow when it consumes a lot of memory. Memory leaks can cause your page to freeze up completely!!

AS SMALL AS POSSIBLE! I experienced that is not really possible to give a precise answer because each application is different. Generally you want the resources on initial load to be as small as possible, so that you decrease the initial load time, and then load more resources as needed on the fly.

Mr Chao

What do we do then?

Meh

How to start decreasing the bundle size?

  • Measure: first of all you want to measure. The first step is to use Lighthouse and try to understand the results. It will give you a couple of interesting metrics and some tips. Time to interactive (TTI) is a good reflection of your bundle size because your bundle needs to be evaluated entirely before a user can interact with your web app.
  • Analyze: Consists on analyzing the bundle in order to detect critical chunks. A useful tool is Webpack Bundle Analyzer.

Stonks

Breaking up the bundle...

  • Monitor network requests: These happens between our FCP and TTI. As the initial request for data often occurs when our components initially mount.
  • Reduce the total dom nodes: the less the page needs to render, the less time it takes.
  • Moving work off the main thread: By moving heavy computations to a web worker, the computation will be run on a separate thread, and not block the actual rendering of the page
  • Caching: Even if not useful for users on first page landing, caching data, bundles, and assets can make subsequent visits way fast

Breaking Bad

Which strategies can we adopt?

  • Minification and Dead Code Elimination: These processes are often summed up as minifying or uglifying.
  • Tree shaking: Tree shaking is dead code elimination on a project or library. Always try to use deps which support “tree shaking”, Bundlephobia could be your friend in this case.
  • Code Splitting and Lazy Loading: Code splitting consists on taking a collection of modules and remove them from the main JS bundle. Lazy loading means we can load this newly created bundle later on.
  • Replace/rewrite large dependencies: Consider replacing or rewriting libraries that are large in size where you might not need all of its functionalities (Moment.js for example).
  • Feature module import: Check to see if you are using only a feature module of the library that can be imported alone without importing the whole library (Lodash for example).

Strategy

Useful tools to help you reducing bundle size

  • Lighthouse: automated tool for improving the performance, quality, and correctness of your web apps
  • Bundlephobia: Bundlephobia helps you find the performance impact of npm packages
  • Webpack Bundle Analyzer: analyzes your bundle
  • VS Code: Import Cost plugin -> Display import/require package size in the editor

Tools

Conclusion

Performance cannot be stripped down to a single metric such as bundle size. It would be great! +Unfortunately there is no single place to measure all of them.I think metrics like the Core Web Vitals and a general look at bundle size should be considered as a starting point. +You will cry... A lot... But don’t give up!

The End

+ + + + \ No newline at end of file diff --git a/blog/tags/k-8-s.html b/blog/tags/k-8-s.html index 8abc3e8..e80358d 100644 --- a/blog/tags/k-8-s.html +++ b/blog/tags/k-8-s.html @@ -7,12 +7,12 @@ One post tagged with "k8s" | foomo project docs - - + +
-

One post tagged with "k8s"

View All Tags

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

- - + + \ No newline at end of file diff --git a/blog/tags/memory.html b/blog/tags/memory.html index 3e009ab..c994fce 100644 --- a/blog/tags/memory.html +++ b/blog/tags/memory.html @@ -7,12 +7,12 @@ One post tagged with "memory" | foomo project docs - - + +
-

One post tagged with "memory"

View All Tags

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

- - + + \ No newline at end of file diff --git a/blog/tags/oom.html b/blog/tags/oom.html index 40cfad3..602297d 100644 --- a/blog/tags/oom.html +++ b/blog/tags/oom.html @@ -7,12 +7,12 @@ One post tagged with "oom" | foomo project docs - - + +
-

One post tagged with "oom"

View All Tags

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

- - + + \ No newline at end of file diff --git a/blog/tags/ops.html b/blog/tags/ops.html index 9ee436e..1912a7f 100644 --- a/blog/tags/ops.html +++ b/blog/tags/ops.html @@ -7,12 +7,12 @@ One post tagged with "ops" | foomo project docs - - + +
-

One post tagged with "ops"

View All Tags

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

- - + + \ No newline at end of file diff --git a/blog/tags/performance.html b/blog/tags/performance.html index 13a25f2..39339f7 100644 --- a/blog/tags/performance.html +++ b/blog/tags/performance.html @@ -7,14 +7,14 @@ One post tagged with "performance" | foomo project docs - - + +
-

One post tagged with "performance"

View All Tags

Marko Trebižan

Issue with performance

When building an ecommerce site or an application where performance is a great deal for the users, you need to keep your application fast and responsive. Frontend developers have already many use-cases when the UI becomes laggy and this increases when 3rd party scripts are being included, such as Google Tag Manager or various Live chats (e.g. Intercom).

This does not only influences the users when using the site but also Lighthouse score gets lower which also influences page rankings. So the most naive and easy way for this is to defer loading of such scripts but when you need to get all the data from the start of the application, such tactic is not an option. So what else can we do?

Partytown to the rescue

Developers at BuilderIO created an library Partytown that would allow relocating resources from 3rd party scripts off the main thread. +

One post tagged with "performance"

View All Tags

Marko Trebižan

Issue with performance

When building an ecommerce site or an application where performance is a great deal for the users, you need to keep your application fast and responsive. Frontend developers have already many use-cases when the UI becomes laggy and this increases when 3rd party scripts are being included, such as Google Tag Manager or various Live chats (e.g. Intercom).

This does not only influences the users when using the site but also Lighthouse score gets lower which also influences page rankings. So the most naive and easy way for this is to defer loading of such scripts but when you need to get all the data from the start of the application, such tactic is not an option. So what else can we do?

Partytown to the rescue

Developers at BuilderIO created an library Partytown that would allow relocating resources from 3rd party scripts off the main thread. We won't dive into specifics how it works, because they explain it nicely on their GitHub page.

In our stack we use Next.js React framework and we will go through the basic steps that will allow us to include Partytown for Google Tag Manager.

Setup

Partytown script needs to be located inside our application and live on the same domain. Since we're using monorepo structure, we need to copy this script across all our frontend application. For that we used CopyPlugin webpack plugin in our Next.js config file:

config.plugins.push(
...
new CopyPlugin({
patterns: [
{
// we copy script from node_modules partytown package to `~partytown` folder in our package that serves static files
from: path.join(path.dirname(require.resolve('@builder.io/partytown')), 'lib'),
// paths for SSR and client side rendering differ
to: path.join(`${isServer ? '..' : '.'}/static/assets/`, '~partytown'),
},
],
})
);

Partytown's requirement is that it needs to know what script should it load into own web worker. For that we set script type to text/partytown. This will prevent script to load on initial load.

Inside _document.tsx we add this:

<Head>
...
// include Partytown and set custom path due to multiple frontends
<Partytown lib={`${addTrailingSlash(this.props.basePath)}_next/static/assets/~partytown/`} debug={false} />
// tag 3rd party script with partytown type
<script type="text/partytown" src={`https://www.googletagmanager.com/gtm.js?id=${id}`} />
...
</Head>

Results

So now, does it work? We used one of our large Ecommerce sites to test the landing Lighthouse score.

This was before adding Partytown:

Lighthouse before Partytown

Here you can see 2 critical things: almost 1s of total blocking time (TBT) and 9s of time to interactive (TTI).

After we added Partytown, we got this:

Lighthouse after Partytown

Time to interactive went from 9s to 6.1s which is almost 33% improvement and total blocking time was reduce by more than 50%! We were more than impressed how easy it was to improve our performances.

Side note: Both screenshots were compressed using Squoosh App.

Next steps

After successful testing of Partytown for Google Tag Manager script, we are more than interested in trying it out on our other scripts. One important topic will be to test Partytown with other service-worker related libraries and how to use them together.

- - + + \ No newline at end of file diff --git a/blog/tags/prometheus.html b/blog/tags/prometheus.html index 33a89d3..22dbafe 100644 --- a/blog/tags/prometheus.html +++ b/blog/tags/prometheus.html @@ -7,12 +7,12 @@ One post tagged with "prometheus" | foomo project docs - - + +
-

One post tagged with "prometheus"

View All Tags

The Annoyance

So, we've all been there. You go to your trusty grafana, search for some sweet metrics that you implemented and WHAM! +

- - + + \ No newline at end of file diff --git a/blog/tags/search-engine.html b/blog/tags/search-engine.html index bb2ae07..43ac6af 100644 --- a/blog/tags/search-engine.html +++ b/blog/tags/search-engine.html @@ -7,15 +7,15 @@ One post tagged with "search-engine" | foomo project docs - - + +
-

One post tagged with "search-engine"

View All Tags

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve +

One post tagged with "search-engine"

View All Tags

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve https://github.com/blugelabs/bluge // next iteration of bleve

projects using bluge

All bleeding edge afaik atm - but definitely good places to look at bluge usage

https://github.com/prabhatsharma/zinc https://github.com/mosuka/phalanx

Look ma I made a vector database

Gotta take a look at this one - will report later

https://github.com/semi-technologies/weaviate

- - + + \ No newline at end of file diff --git a/blog/tags/search.html b/blog/tags/search.html index 55d0add..9cd087d 100644 --- a/blog/tags/search.html +++ b/blog/tags/search.html @@ -7,15 +7,15 @@ One post tagged with "search" | foomo project docs - - + +
-

One post tagged with "search"

View All Tags

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve +

One post tagged with "search"

View All Tags

Jan Halfar

While building this website and integrating https://docsearch.algolia.com and evaluating another solution by a large company in parallel I could not help to search github and the web for the current state of search engines and search related services.

Since I had done the same thing about a year ago, I was surprised to see how quickly things are moving atm.

Algolia

I was blown away by the quality of https://www.algolia.com and I wish it was open source, but I guess, we all have to make a living ;)

To see how awesome a web (search) interface can be check out https://www.lacoste.com/us/#query=red%20jackets%20for%20men

Apart from that the UI/UX of their backend tools is fantastic.

Elastic

When it comes to https://www.elastic.com I am a bit nervous about the future of the licensing, despite the fact, that I understand their motivation. At the same time the https://opensearch.org does not seem to be an ampty threat.

typesense.org

I do not know, who was hiding under a rock, but I had not seen https://typesense.org before and they certainly have a bold claim: "The Open Source Algolia Alternative" / "The Easier To Use ElasticSearch Alternative"

When looking at https://github.com/typesense/typesense/graphs/contributors it seems, that Kishore Nallan has been working on this for a while. Unfourtunately I do not really see a lot of external contributions, C++ does not seem to attract a lot of contribution.

MeiliSearch

This Rust project https://www.meilisearch.com/ seems to be picking up speed and is definetly on the test short list. It is a fresh codebase with siginficant open source contributions and certainly will attract new developers with Rust and a modern architecture.

Go eco system

Obviously we are very interested in Go powered software and there are a few notable projects. ATM I do not see anything elastic or algolia like, that would be really mature.

bleve / bluge

Marty Schoch seems to be the man when it comes down to text indexing libraries in written in Go and bluge seems to be THE library, that is solid and modern, when implementing text search in your Go application.

https://github.com/blevesearch/bleve https://github.com/blugelabs/bluge // next iteration of bleve

projects using bluge

All bleeding edge afaik atm - but definitely good places to look at bluge usage

https://github.com/prabhatsharma/zinc https://github.com/mosuka/phalanx

Look ma I made a vector database

Gotta take a look at this one - will report later

https://github.com/semi-technologies/weaviate

- - + + \ No newline at end of file diff --git a/blog/welcome-back-2021.html b/blog/welcome-back-2021.html index 90bc609..4b384f3 100644 --- a/blog/welcome-back-2021.html +++ b/blog/welcome-back-2021.html @@ -7,13 +7,13 @@ Relaunching foomo.org | foomo project docs - - + +
-

Relaunching foomo.org

Jan Halfar

A few years ago we abandoned the previous version of https://www.foomo.org as we did not want to maintain the old wordpress installation and the project was only living in README.md in the repos living under https://www.github.com/foomo .

As things have grown over time we have decided to re-launch a website / cross project documentation.

So welcome back and enjoy the view to the past:

blast from the past

- - +

Relaunching foomo.org

Jan Halfar

A few years ago we abandoned the previous version of https://www.foomo.org as we did not want to maintain the old wordpress installation and the project was only living in README.md in the repos living under https://www.github.com/foomo .

As things have grown over time we have decided to re-launch a website / cross project documentation.

So welcome back and enjoy the view to the past:

blast from the past

+ + \ No newline at end of file diff --git a/blog/why-bundle-size-is-important.html b/blog/why-bundle-size-is-important.html new file mode 100644 index 0000000..dddee56 --- /dev/null +++ b/blog/why-bundle-size-is-important.html @@ -0,0 +1,22 @@ + + + + + + + + +Why bundle size is important? | foomo project docs + + + + +
+

Why bundle size is important?

Nicola Turcato

Intro

JavaScript is parsed, compiled and executed in the main thread of the browser. Which means that users have to wait for all of this before they can interact with the website.

Frontend performance optimization is critical because it accounts for around 80-90% of user response time (10-20% backend). +So when a user is waiting for a page to load, around 80-90% of the time is due to frontend related code and assets.

Nobody likes waiting…

A study found that if a site takes longer than 4 seconds to load, up to 25% of users would abandon the site.

Sending large JavaScript payloads impacts the speed of your site significantly.

Mazzarri

What is a "bundle"?

Your frontend application needs a bunch of JS files to run. These files can be in the format of internal dependency like the JS files you have written yourself. But they can also be external dependencies you use to build your application.

JS bundling is an optimization technique to reduce the number of server requests for JavaScript files. Bundling accomplishes this by merging multiple JA files together into one file to reduce the number of page requests.

Bundle Everywhere

Performance implications

  • Time to transmit over the network: considering slow connections with some mobile devices, it's possible that your page will not be interactive until it loads.-> More bytes = longer download times
  • JS parse and compile time: more code you load, more the browser must parse.-> JS gets parsed and compiled on the main thread, when the main thread is busy, the page can't respond to user input
  • JS execution time: optimally you will only pack the code that you expect to execute. The more code you want to execute the longer it will take. It's possible that your page won't be interactive until some of this completes.-> JS is also executed on the main thread, if your page runs a lot of code before it's really needed, that also delays your Time to Interactive
  • Memory consumption: everything fills up the space -> code itself, runtime variables, DOM elements created, etc.-> Pages appear slow when it consumes a lot of memory. Memory leaks can cause your page to freeze up completely!!

AS SMALL AS POSSIBLE! I experienced that is not really possible to give a precise answer because each application is different. Generally you want the resources on initial load to be as small as possible, so that you decrease the initial load time, and then load more resources as needed on the fly.

Mr Chao

What do we do then?

Meh

How to start decreasing the bundle size?

  • Measure: first of all you want to measure. The first step is to use Lighthouse and try to understand the results. It will give you a couple of interesting metrics and some tips. Time to interactive (TTI) is a good reflection of your bundle size because your bundle needs to be evaluated entirely before a user can interact with your web app.
  • Analyze: Consists on analyzing the bundle in order to detect critical chunks. A useful tool is Webpack Bundle Analyzer.

Stonks

Breaking up the bundle...

  • Monitor network requests: These happens between our FCP and TTI. As the initial request for data often occurs when our components initially mount.
  • Reduce the total dom nodes: the less the page needs to render, the less time it takes.
  • Moving work off the main thread: By moving heavy computations to a web worker, the computation will be run on a separate thread, and not block the actual rendering of the page
  • Caching: Even if not useful for users on first page landing, caching data, bundles, and assets can make subsequent visits way fast

Breaking Bad

Which strategies can we adopt?

  • Minification and Dead Code Elimination: These processes are often summed up as minifying or uglifying.
  • Tree shaking: Tree shaking is dead code elimination on a project or library. Always try to use deps which support “tree shaking”, Bundlephobia could be your friend in this case.
  • Code Splitting and Lazy Loading: Code splitting consists on taking a collection of modules and remove them from the main JS bundle. Lazy loading means we can load this newly created bundle later on.
  • Replace/rewrite large dependencies: Consider replacing or rewriting libraries that are large in size where you might not need all of its functionalities (Moment.js for example).
  • Feature module import: Check to see if you are using only a feature module of the library that can be imported alone without importing the whole library (Lodash for example).

Strategy

Useful tools to help you reducing bundle size

  • Lighthouse: automated tool for improving the performance, quality, and correctness of your web apps
  • Bundlephobia: Bundlephobia helps you find the performance impact of npm packages
  • Webpack Bundle Analyzer: analyzes your bundle
  • VS Code: Import Cost plugin -> Display import/require package size in the editor

Tools

Conclusion

Performance cannot be stripped down to a single metric such as bundle size. It would be great! +Unfortunately there is no single place to measure all of them.I think metrics like the Core Web Vitals and a general look at bundle size should be considered as a starting point. +You will cry... A lot... But don’t give up!

The End

+ + + + \ No newline at end of file diff --git a/docs/backend/go-by-example/map-racing.html b/docs/backend/go-by-example/map-racing.html index 6d1c182..cb1eb5f 100644 --- a/docs/backend/go-by-example/map-racing.html +++ b/docs/backend/go-by-example/map-racing.html @@ -7,13 +7,13 @@ map races | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/backend/go-by-example/nil-maps.html b/docs/backend/go-by-example/nil-maps.html index 750d0fd..e570ef2 100644 --- a/docs/backend/go-by-example/nil-maps.html +++ b/docs/backend/go-by-example/nil-maps.html @@ -7,14 +7,14 @@ what you should now about nil maps | foomo project docs - - + +
- - + + \ No newline at end of file diff --git a/docs/backend/go-by-example/panic-and-recover.html b/docs/backend/go-by-example/panic-and-recover.html index a02a980..ccb006e 100644 --- a/docs/backend/go-by-example/panic-and-recover.html +++ b/docs/backend/go-by-example/panic-and-recover.html @@ -7,13 +7,13 @@ panic and recover | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/backend/go-by-example/ranging.html b/docs/backend/go-by-example/ranging.html index fb11dfb..7ea54fd 100644 --- a/docs/backend/go-by-example/ranging.html +++ b/docs/backend/go-by-example/ranging.html @@ -7,14 +7,14 @@ ranging and looping | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/backend/go-by-example/yaml-magic.html b/docs/backend/go-by-example/yaml-magic.html index 34db950..e2c0a4e 100644 --- a/docs/backend/go-by-example/yaml-magic.html +++ b/docs/backend/go-by-example/yaml-magic.html @@ -7,14 +7,14 @@ yaml magic | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/backend/gograpple.html b/docs/backend/gograpple.html index ab3b250..d68734f 100644 --- a/docs/backend/gograpple.html +++ b/docs/backend/gograpple.html @@ -7,13 +7,13 @@ Gograpple | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/backend/intro.html b/docs/backend/intro.html index 5bc5641..6ca844a 100644 --- a/docs/backend/intro.html +++ b/docs/backend/intro.html @@ -7,14 +7,14 @@ building backend services with Go and foomo | foomo project docs - - + +
- - + + \ No newline at end of file diff --git a/docs/backend/rtfm.html b/docs/backend/rtfm.html index c54bd1e..1a593ce 100644 --- a/docs/backend/rtfm.html +++ b/docs/backend/rtfm.html @@ -7,13 +7,13 @@ External documentation resources | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/backend/setup.html b/docs/backend/setup.html index bf82987..a2b0bd9 100644 --- a/docs/backend/setup.html +++ b/docs/backend/setup.html @@ -7,13 +7,13 @@ setup your workspace | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/devops/bookmarks.html b/docs/devops/bookmarks.html index 40b3f16..46e5411 100644 --- a/docs/devops/bookmarks.html +++ b/docs/devops/bookmarks.html @@ -7,13 +7,13 @@ Bookmarks | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/devops/intro.html b/docs/devops/intro.html index 6939481..db5b268 100644 --- a/docs/devops/intro.html +++ b/docs/devops/intro.html @@ -7,13 +7,13 @@ How we run applications in the cloud | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/devops/k8s.html b/docs/devops/k8s.html index e57f8e1..8833932 100644 --- a/docs/devops/k8s.html +++ b/docs/devops/k8s.html @@ -7,13 +7,13 @@ k8s kubernetes | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/devops/kubernetes/spot-instance-node-pools.html b/docs/devops/kubernetes/spot-instance-node-pools.html index 1439ce4..ff3b61c 100644 --- a/docs/devops/kubernetes/spot-instance-node-pools.html +++ b/docs/devops/kubernetes/spot-instance-node-pools.html @@ -7,8 +7,8 @@ Spot Instance Node Pools | foomo project docs - - + +
@@ -16,7 +16,7 @@ What could happen is that nodes that are hosting the applications start terminating, and our application becomes unresponsive until the application is re-located to another node. To avoid that situation, for the instances we need to configure pod disruption budget on our helm deployments.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: application-name
spec:
maxAvailable: 50%
selector:
matchLabels:
app: application-name

For more details check out here

Setting Up Termination Handling

Setting Up K8s Cron Shutdown Cleanup

- - + + \ No newline at end of file diff --git a/docs/devops/monitoring/grafana.html b/docs/devops/monitoring/grafana.html index a8ea0c7..04747ab 100644 --- a/docs/devops/monitoring/grafana.html +++ b/docs/devops/monitoring/grafana.html @@ -7,13 +7,13 @@ Grafana | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/devops/monitoring/intro.html b/docs/devops/monitoring/intro.html index e4bf96d..3b295d1 100644 --- a/docs/devops/monitoring/intro.html +++ b/docs/devops/monitoring/intro.html @@ -7,13 +7,13 @@ Monitoring and Alerting | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/devops/monitoring/jaeger.html b/docs/devops/monitoring/jaeger.html index 186fda3..54b624f 100644 --- a/docs/devops/monitoring/jaeger.html +++ b/docs/devops/monitoring/jaeger.html @@ -7,13 +7,13 @@ Jaeger | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/frontend/css.html b/docs/frontend/css.html index dad350c..1fec80f 100644 --- a/docs/frontend/css.html +++ b/docs/frontend/css.html @@ -7,13 +7,13 @@ CSS | foomo project docs - - + +
- - + + \ No newline at end of file diff --git a/docs/frontend/debugging_js.html b/docs/frontend/debugging_js.html index 7872ba8..7337046 100644 --- a/docs/frontend/debugging_js.html +++ b/docs/frontend/debugging_js.html @@ -7,13 +7,13 @@ Debugging in JavaScript | foomo project docs - - + +

Debugging in JavaScript

Debugging experience is very important because it can save you hours of depressing search for a bug.

console logging

Probably 95% of devs nowadays still use console.log since it's the most convenient way of outputting something. There are also some nicer ways to output something, especially when having an array of object. In that case it's much nicer to use console.table(array) because it will create a nice table with all fields.

Sometimes a debugger in the browser won't create a breakpoint like you want it or you can't find a source file where you would want. A nice trick is to add a debugger keyword in your code which will instantly stop executing script on that place (but only if you have devtools open).

Bisecting

When you can't find what causes an error, a very common approach is doing bisection. This is simply removing half of the code and see if it still works or not. If it works, then the bug is in the removed code, otherwise start removing other half in existing code.

Chrome/Firefox devtools

Today's browsers have really good devtools and we can't imagine developing without them. And they all nice of helper tricks that ease our development and especially debugging.

... TODO: @themre

- - + + \ No newline at end of file diff --git a/docs/frontend/intro.html b/docs/frontend/intro.html index f291208..93bfab0 100644 --- a/docs/frontend/intro.html +++ b/docs/frontend/intro.html @@ -7,13 +7,13 @@ Frontend Guide | foomo project docs - - + +

Frontend Guide

In this section you will find a guide on how to develop frontends with the foomo stack. Please also see the general guide.

Let me share a few thoughts on frontend development from our journey @bestbytes the company behind https://www.foomo.org .

Web development has been a wild ride since the beginning of the www in the mid 1990s. Today we take it as granted, that the default way to build applications is with web technologies.

Not too long ago this seemed absurd, since browsers were meant to share scientific research papers and therefore were extremely limited in their capabilities.

It was the era of experimentation, that turned the web into the application runtime, which it is today. Plugins like Macromedias flash inspired the rich APIs we can use today, when building web applications.

A little history

The current stack is the result of a more than 20 year journey.

Last millenium

The open source eco system was in its infancy, there was no github (is that really open source as it should be 🤔), there was not even git, there were no real web frameworks and agile methodologies were an exotic nerd topic.

Browsers would sometimes render things in a recognisable way and a table was the way to render your layout. Reliable interactivity could only result from a server round trip and calling JavaScript had a good chance to crash your browser.

Security in browsers was a complete nightmare, it was a time, when one tab could access anothers tabs dom 🤯

Early 2000s

As Microsoft had won the browser wars, we were stuck with IE 6 and like others we were building web applications with the limited resources we had. JavaScript frameworks were still

The plugin era / FLASH

As browsers were slow, buggy and inconsistent FLASH presented this amazing way to build highly interactive websites. It was the time of loaders, which people accepted, because amazing experiences awaited them: animated vector graphics (artists went wild ...), games, the first videos, client server communications, sockets and a canvas API.

Also ActionScript especially AS3 felt so superior to JavaScript at the time.

Flex

Flex used the capabilities of the flash player to provide a fantastic developer experience to build RIAs (rich internet applications). The resulting productivity, application performance and features were unparalled in the JavaScript eco system until long after the demise of the flash player.

After "thoughts on flash"

After the release of the iPhone and the beginning of the walled garden era flash was one of the initial victims. Just for the record, I definitely prefer an independent eco system, which the web is at least to a certain extent, but it certainly was not noble motives, that were driving Apple when pushing for HTML5 in their thoughts on flash.

HTML5

At its arrival HTML5 could not deliver on the many promises, that were made around it. Browser compatibilty was a nightmare, JavaScript performance was poor, the eco system was in its infancy.

As we left the flash eco system we stopped by RequireJS and were using BACKBONE.JS as we felt extremely burnt by Adobe, after they had dropped their whole eco system like a hot potatoe once Apple had declared the end of flash.

TypeScript and the wild framework years

Despite the fact, that we were very sceptic about trusting large vendors, we adopted TypeScript right after it was initially released and we have remained happy users of it until the present day.

The early years of the Node.js community were extremely wild, there was jokes about the number of frameworks released per day. The number of languages that compiled to JavaScript exploded and it just seemed impossible to keep up with the changing environment.

2020s

As we wake up today as frontend developers, we do not expect, that we will keep on doing things as we do them today until the end of our careers, but we at least see a chance, that the code base of a project will not be outdated with delivery of a MVP.

- - + + \ No newline at end of file diff --git a/docs/frontend/performance.html b/docs/frontend/performance.html index e069e21..ff49e1c 100644 --- a/docs/frontend/performance.html +++ b/docs/frontend/performance.html @@ -7,14 +7,14 @@ Performance | foomo project docs - - + +

Performance

JS

JS is nowadays extremely fast and yet we have many performance issues. Here you can find few common mistakes that occur in JS that can decrease performance.

Extensive use of .map, .filter

Let's say you have a large list of objects and you would like to filter them and transform them in some form. Usually we do this:

const largeArray = [ .... ]
largeArray.map(obj => transformObj(obj)).filter(omitBadObject)

In the above case we first loop through whole set, transform it and then filter things out. Not only does this goes through all the items twice, but it also first time goes through all the items and then filters them. One optimization would be to first filter them and then transform them, but ideally we should just use a normal for loop or forEach where you go through items only once.

const finalArray = []
largeArray.forEach(obj => {
if (omitBadObject(obj)) {
finalArray.push(transformObj(obj))
}
})

This code will skip another loop of items.

- - + + \ No newline at end of file diff --git a/docs/frontend/pitfalls.html b/docs/frontend/pitfalls.html index d4a48dd..8b54281 100644 --- a/docs/frontend/pitfalls.html +++ b/docs/frontend/pitfalls.html @@ -7,13 +7,13 @@ Pitfalls | foomo project docs - - + +

Pitfalls

This section is very important to avoid dangerous bugs in your code. Of course each of our languages or libraries in our stack has many advantages, but they came with dangerous pitfalls.

JavaScript

This section is probably too small to write all the dangerous things in JavaScript, but we hope developers won't do some crazy things like concatenating numbers and strings and such sort of forbidden things will be catched by TS.

But nevertheless, very often we run into issues that are hard to debug.

Mutation

Mutation in JS is a very common problem and thus leads to dangerous bugs.

A very common mutation occurs in spreading. So if you spread an object and it's deeply nested, you need to know that this will only create a shallow copy. So that means that deeply nested fields will still be referenced by the original object. If you need to do a immutable instance we advice in using either klona or immer.

When doing sorting on the array like [1,2,3].sort(...), this does mutate the original array. Devs are used to create new array with .map or .filter, but this here is not the case. So be careful with that. Also do not forget that objects in the array will have a reference to objects in the original array and thus they also needs to be cloned.

Have in mind that doing immutability costs and sometimes it's better to mutate, but also know that in React if you don't create a new reference, setting state won't react. So always have in mind pros and cons of doing mutation.

typeof

typeof is used for checking type of some variables. So when checking if a variable is an array of an object, we try to use typeof. But we should be very careful since typeof works nicely on simple primitive types like number, string, boolean.

When you try to check whether a variable is an object or an array, you try to use typeof. But both are object. So in this case we should use Array.isArray(variable). But be careful, because also null is an object! If you want to deep dive into this, read here.

Numbers are also fun when it comes to NaN. If you check isNaN with typeof, it's actually a number! So for this use-case you need to use Number.isNaN(myNum).

- - + + \ No newline at end of file diff --git a/docs/frontend/rtfm.html b/docs/frontend/rtfm.html index be35298..baa6b88 100644 --- a/docs/frontend/rtfm.html +++ b/docs/frontend/rtfm.html @@ -7,13 +7,13 @@ External documentation resources | foomo project docs - - + +

External documentation resources

Runtime / browser

In general the Mozilla Developer Network - MDN is a great resource, if you want to know, what your browser is capable of.

Once you found out, how great an API is, the question to answer will be "can I use" feature X. https://caniuse.com/ is a great resource to find the answers, when trying to understand, if a browser API / feature is ready to use for your audience.

JavaScript

JavaScript historically has a very bad reputation. Please enjoy the following classic piece of infotainment: https://www.destroyallsoftware.com/talks/wat

As JavaScript has been massively iterated on, the runtimes hav ecome crazy fast and the language keeps on evolving.

The (mostly functional) subset of the language, that is being used in modern JavaScript / TypeScript projects to is highly expressive and reads well.

Please take the time and learn about

  • functional programming
  • variable scope
  • modern JavaScript syntax
    • arrow functions
    • new keywords
    • spreading
    • ...
  • promises

CSS

  • CSS block model
  • flex box

Browser APIs

  • canvas
  • fetch
  • local storage
  • websockets
  • sse server side events
  • built in types

TypeScript

- - + + \ No newline at end of file diff --git a/docs/frontend/setup.html b/docs/frontend/setup.html index 899d669..9c475f3 100644 --- a/docs/frontend/setup.html +++ b/docs/frontend/setup.html @@ -7,13 +7,13 @@ Setup | foomo project docs - - + +

Frontend setup

How to setup your machine for frontend development

general topics

setting up your IDE

  • vscode

frontend specific

  • yarn / npm / package.json
  • nvm
  • browser extensions
    • preact
    • redux
    • (google analytics)

debugging with emulators / devices

  • xcode
  • android studio

Install software

Mac

First of all install brew from https://brew.sh

brew install nvm
brew cask install iterm2

Linux

Windows

Install Linux ;)

- - + + \ No newline at end of file diff --git a/docs/frontend/stack.html b/docs/frontend/stack.html index 9ed3b5a..44854a9 100644 --- a/docs/frontend/stack.html +++ b/docs/frontend/stack.html @@ -7,13 +7,13 @@ Stack | foomo project docs - - + +

Frontend Stack

Our frontend stack is permanently changing as the underlying eco system does. We are trying to adopt technologies at the "Slope of Enlightenment" in the hype cycle.

Former iterations of our stack were MVC or MVVM frontend frameworks. Since the arrival of React and state mangement libraries like Redux and Zustand we have been building reactive applications.

Reactive frontends are fun to develop and they scale.

TypeScript

Is our language of choice to build frontends for web applications.

We have adopted TypeScript very early, right after its initial public release in 2012. Here is a list of motives:

  • it is a superset JavaScript
  • it does not try to replace JavaScript like many other languages, which compile to JavaScript, it tries to complement and improve it, while staying compatible
  • good type system
  • great tooling

While it seemed to be crazy to trust Microsoft as a friendly open source company, we have not been disappointed so far.

React / Preact

Declarative components and views, fast to develop and fast at runtime.

gotsrpc

Since we are building services in Go and not with Node.js we have created a light weight RPC framework to integrate TypeScript with Go.

When creating TS definitions on the Go side we follow camel case convention of naming fields e.g. lastDateModified instead of LastDateModified.

- - + + \ No newline at end of file diff --git a/docs/frontend/typescript/objects.html b/docs/frontend/typescript/objects.html index 0388d03..90b73d3 100644 --- a/docs/frontend/typescript/objects.html +++ b/docs/frontend/typescript/objects.html @@ -7,15 +7,15 @@ Object declaration syntax in TypeScript | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/frontend/typescript/spreading.html b/docs/frontend/typescript/spreading.html index 390cd75..fcc4740 100644 --- a/docs/frontend/typescript/spreading.html +++ b/docs/frontend/typescript/spreading.html @@ -7,8 +7,8 @@ Spreading | foomo project docs - - + +
@@ -167,7 +167,7 @@ If you have a deeply nested object or array, nested entities will still hold a r } }
Result
Loading...
- - + + \ No newline at end of file diff --git a/docs/frontend/vscode.html b/docs/frontend/vscode.html index 6cbe861..19ea68c 100644 --- a/docs/frontend/vscode.html +++ b/docs/frontend/vscode.html @@ -7,13 +7,13 @@ vscode | foomo project docs - - + +
- - + + \ No newline at end of file diff --git a/docs/general/essentials.html b/docs/general/essentials.html index 085f3f2..1e5f77d 100644 --- a/docs/general/essentials.html +++ b/docs/general/essentials.html @@ -7,13 +7,13 @@ (Random) essentials | foomo project docs - - + +

(Random) essentials

Markdown

Learn markdown(this is a markdown document 🤓)

Vim

Vim is everywhere so no matter if you ssh into a place or try to edit a file in a container, you are going to need it.

Here is a super minimal cheat sheet:

# edit/create a file
vim path/file

Now the shortcuts:

shortcutfunctionnote
:h<enter>helpa bit overwhelming
:q<enter>quitimmediate instinct after looking at help 🤣
:q!<enter>quit ignoring changes! means, that you actually mean it and can be combined with a lot of commands
:w<enter>write / save file
:x<enter> save and exit
:x!<enter> force save and exit
11Ggo to line 11
$ go to last char in line
dddelete line
x delete char
i enter insert modethat is where you can actually edit stuff - press escape to exit insert mode
<esc>exit insert mode
<ctrl>vvisual blockthen use cursors to edit selection
xcut
ppaste

ssh

allows you to remotely and securely log into computers - man ssh should be available on any shell.

digital ocean has a decent intro into ssh https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys

There is a lot of other tutorials - your typical use cases will be:

  • logging into other computers
  • executing commands on those computers
  • tunneling network connections

Once ssh is set up correctly scp, git and a lot of other programs, that rely on ssh under the covers are fun to use too.

git

https://git-scm.com/doc

github

Yes despite the fact, that m$ bought them, we use them and you have to enable 2fa

Some data formats

yaml

https://yaml.org/ some love it for good a reason, some hate it for another good reason, but atm there is just no way around it.

json

https://www.json.org/json-en.html similar love and hate situation like with yaml - also no way out.

CSV

If you think parsing or serializing CSV is trivial, you have been warned.

https://datatracker.ietf.org/doc/html/rfc4180

protocol buffers

Fast, compact not human readable - not necessary for most use cases

https://developers.google.com/protocol-buffers

xml

https://www.w3.org/TR/REC-xml/ only little love here

- - + + \ No newline at end of file diff --git a/docs/general/intro.html b/docs/general/intro.html index 109f912..977e24e 100644 --- a/docs/general/intro.html +++ b/docs/general/intro.html @@ -7,13 +7,13 @@ General guide | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/general/package-managers.html b/docs/general/package-managers.html index 0450a43..5966467 100644 --- a/docs/general/package-managers.html +++ b/docs/general/package-managers.html @@ -7,13 +7,13 @@ Package managers | foomo project docs - - + +

Package managers

Whenever you can, do not manage software on your computer manually ...

  • comfort
  • versions
  • security

macOS

On the mac https://brew.sh/ has become the de facto standard - we use it to distribute binaries of some of our open source projects as well.

Windows

...

- - + + \ No newline at end of file diff --git a/docs/general/security.html b/docs/general/security.html index 544f0ed..acbe9a9 100644 --- a/docs/general/security.html +++ b/docs/general/security.html @@ -7,13 +7,13 @@ Security | foomo project docs - - + +

Security

TODO: @dreadl0ck knock yourself out

OS / Application setup

  • disable telemetry whereever possible

Keep your data safe

  • encrypt your file system to make sure so that if your computer gets stolen at least your data remain secure
  • make sure to have multiple backups in different places i.e. one backup disk at home and one in the office
- - + + \ No newline at end of file diff --git a/docs/general/setup/computer.html b/docs/general/setup/computer.html index 3cc2361..ae1216c 100644 --- a/docs/general/setup/computer.html +++ b/docs/general/setup/computer.html @@ -7,13 +7,13 @@ Computer | foomo project docs - - + +

Setting up your computer

This is a general setup guide for your computer. Make sure that you setup your worpkplace properly too.

Privacy and security

Follow the instructions on security when you setup and maintain your system.

Install software

Mac

First of all install brew from https://brew.sh

brew cask install iterm2

Linux

Windows

Install Linux ;)

- - + + \ No newline at end of file diff --git a/docs/general/setup/workplace.html b/docs/general/setup/workplace.html index a0b3a78..f239a32 100644 --- a/docs/general/setup/workplace.html +++ b/docs/general/setup/workplace.html @@ -7,13 +7,13 @@ Workplace | foomo project docs - - + +

Setting up your workplace

No matter where you work, you need a proper workplace:

  • ergonomic office chair / desk combination
  • large high pixel density display
  • ergonomic input devices
  • good lighting
  • correct position in the room

Make sure that you take the time to set up your workplace well, your health depends upon it.

- - + + \ No newline at end of file diff --git a/docs/general/utilities/k9s.html b/docs/general/utilities/k9s.html index 0011864..407399a 100644 --- a/docs/general/utilities/k9s.html +++ b/docs/general/utilities/k9s.html @@ -7,13 +7,13 @@ k9s | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/general/work/general.html b/docs/general/work/general.html index 581a684..dd4fd75 100644 --- a/docs/general/work/general.html +++ b/docs/general/work/general.html @@ -7,13 +7,13 @@ Working as a software developer | foomo project docs - - + +

Working as a software developer

Working as a software developer in a sustainable way is challenging - here are a few observations of healthy habits:

  • do not work too much
  • physical exercise is essential
  • clearly separate between working and not working
  • reflect and iterate on your working habits
- - + + \ No newline at end of file diff --git a/docs/general/work/remote-work.html b/docs/general/work/remote-work.html index 0d2b5e8..59ff0e6 100644 --- a/docs/general/work/remote-work.html +++ b/docs/general/work/remote-work.html @@ -7,13 +7,13 @@ Working remotely | foomo project docs - - + +

Working remotely

Especially since the beginning of the corona pandemy working remotely has become a very important topic. The foomo team has extensive experience working remotely as we are a distributed team.

Disclaimer: we are almost exclusively working in one timezone.

Requirements

  • fast and reliable internet connection
  • a proper workplace

The good parts

  • no commute
  • less distractions from team members

The bad parts

  • harder to separate between work and your private life
  • less informal communication with teammates
  • less human interaction

When working from home

  • make sure, that you have a routine, that still takes you to work
    • fixed working hours
    • "go to work" and "leave work" even if you do not leave your home
    • if possible use a room, that is for work only
    • have clear rules for your family / roomates, when at work
  • when communication with teammates use video calls
  • take time for your teammates and have a virtual coffee break with someone at least once a day
  • invest half the time, that you save by not communiting to exercise
- - + + \ No newline at end of file diff --git a/docs/project-management/intro.html b/docs/project-management/intro.html index 0905594..b3d1988 100644 --- a/docs/project-management/intro.html +++ b/docs/project-management/intro.html @@ -7,13 +7,13 @@ Project Managament | foomo project docs - - + +

Project Managament

We scrumming in our way ...

Values

  • project managers manage projects not people

Epics

Epics are the starting point ....

- - + + \ No newline at end of file diff --git a/docs/project-management/responsibility.html b/docs/project-management/responsibility.html index 5c3bb41..930ac77 100644 --- a/docs/project-management/responsibility.html +++ b/docs/project-management/responsibility.html @@ -7,13 +7,13 @@ Responsibility | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/projects/architecture.html b/docs/projects/architecture.html index cd3822c..8dc603d 100644 --- a/docs/projects/architecture.html +++ b/docs/projects/architecture.html @@ -7,13 +7,13 @@ Architecture overview | foomo project docs - - + +

Architecture overview

backend services

When it comes to writing backend services we have decided for Go https://go.dev - let me list the main reasons why - Go is:

  • simple and fun
  • fast when compiling
  • fast at runtime
  • friendly to your machines
  • friendly to you as a programmer
  • equipped with a top notch runtime
  • extremely well balanced in its design as a language, that is highly consumable for humans and machines
  • not about the features it has
  • about what has been left out
  • easy to read
  • sustainable

Foomo projects supporting development with Go

  • keel - opinionated way to run services
  • gotsrpc - rpc framework / code generator
  • gograpple - human friendly way to debug go programs running in k8s
  • webgrapple - a development proxy

Frontends

Foomo projects supporting development with Next.js

- - + + \ No newline at end of file diff --git a/docs/projects/cms/contentful.html b/docs/projects/cms/contentful.html index 6456142..0d105a3 100644 --- a/docs/projects/cms/contentful.html +++ b/docs/projects/cms/contentful.html @@ -7,13 +7,13 @@ contentful | foomo project docs - - + +
- - + + \ No newline at end of file diff --git a/docs/projects/cms/contentserver.html b/docs/projects/cms/contentserver.html index 4eedf1a..6cd61ec 100644 --- a/docs/projects/cms/contentserver.html +++ b/docs/projects/cms/contentserver.html @@ -7,13 +7,13 @@ contentserver | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/projects/cms/intro.html b/docs/projects/cms/intro.html index 72172ab..32f9d37 100644 --- a/docs/projects/cms/intro.html +++ b/docs/projects/cms/intro.html @@ -7,13 +7,13 @@ Intro | foomo project docs - - + +

Intro

The foomo team has extensive experience with a wide range of CMS systems. Our long journey in the field has brought us very close to the https://jamstack.org . We almost exclusively work with https://app.contentful.com/ but we are watching others like https://www.stripe.com/ very closely.

Expectations and challenges

  • application developers want an environment, that ensures maximum productivity, they do not think of semantic structures, they think of routes
  • customers expect maximum control and flexibility when working with content and do not distinguish between content and applications

The need for dynamic rendering

If you can - render static content and distribute it with a CDN.

There are use cases though, where static site generation does not work like

  • highly personalized content
  • mixing content with entities from other systems, that have a different life cycle, like products

Application routes vs semantic URL structures

Bridging the conceptual gap between sematic content and applications.

Content especially when created with a focus on SEO comes as a semantic graph. This typically conflicts with how application developers see the world.

e-commerce as an example

Let us take a look at a real world example:

application route / ingressapp developers viewSEO URL requirement
/content:id/content/1/
/content/2/mens
/category:id/category/1/mens/shirts
/category/2/mens/shirts/business
/product:id/product/1/mens-shirt-awesome-blue-medium
/store:id/store/1/mens/stores/london-perfect-shirts
/store/2/kids/stores/lego-paradise

our approach

contentserver allows you to resolve URIs to mime types, which can be handled by applications.

Let us return to our ecommerce example.

model content

mime typecms entityapplication eg k8s service
application/x-pagepagehttps://frontend_service_page
application/x-categorycategoryhttps://frontend_service_category
application/x-storestorehttps://frontend_service_store

export contentent to contentserver

contentserver allows you to export your content tree as json

resolving URIs

Use standard application routing whereever possible, since it is the most efficient option.

Once all standard URI resolution fails, query contentserver and it will return the resolved node


Now you have the mime-type and you know which application can handle it.

- - + + \ No newline at end of file diff --git a/docs/projects/gotsrpc.html b/docs/projects/gotsrpc.html index 7f3ccbe..344e4de 100644 --- a/docs/projects/gotsrpc.html +++ b/docs/projects/gotsrpc.html @@ -7,13 +7,13 @@ gotsrpc | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/projects/intro.html b/docs/projects/intro.html index 50d00a4..00b79e8 100644 --- a/docs/projects/intro.html +++ b/docs/projects/intro.html @@ -7,13 +7,13 @@ foomo project overview | foomo project docs - - + +

foomo project overview

"Stuff we wrote, because nobody else wanted to"

All foomo projects are available here https://github.com/foomo also see architecture

We are using the best industry standards and only fill in our own bits, when necessary.

The foomo project maintains libraries, utilities and daemons, which power most projects at https://www.bestbytes.com

Projects running on the foomo stack typically are

  • relatively large with hundreds of thousands of lines of code
  • composed of dozens of microservices
  • written / maintained by dozens of contributors
  • using Go on the server side
  • using Next.js / TypeScript on the client side
  • running on k8s
  • deeply integrated with a headless CMS
  • built with a project specific frontend component set

Everything is loosely coupled, since we know, that the only constant is change.

- - + + \ No newline at end of file diff --git a/docs/projects/libraries/keel.html b/docs/projects/libraries/keel.html index 92d1fe8..df6a311 100644 --- a/docs/projects/libraries/keel.html +++ b/docs/projects/libraries/keel.html @@ -7,13 +7,13 @@ keel | foomo project docs - - + + - - +
+ + \ No newline at end of file diff --git a/docs/projects/pagespeed-exporter.html b/docs/projects/pagespeed-exporter.html index 39df174..e76f030 100644 --- a/docs/projects/pagespeed-exporter.html +++ b/docs/projects/pagespeed-exporter.html @@ -7,13 +7,13 @@ pagespeed exporter | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/projects/site-reliability.html b/docs/projects/site-reliability.html index 9a2ff1b..b6433e4 100644 --- a/docs/projects/site-reliability.html +++ b/docs/projects/site-reliability.html @@ -7,13 +7,13 @@ Site reliability | foomo project docs - - + + - - +
+ + \ No newline at end of file diff --git a/docs/projects/utilities/gograpple.html b/docs/projects/utilities/gograpple.html index ac6e717..ec7489f 100644 --- a/docs/projects/utilities/gograpple.html +++ b/docs/projects/utilities/gograpple.html @@ -7,13 +7,13 @@ gograpple | foomo project docs - - + + - - +
+ + \ No newline at end of file diff --git a/docs/projects/webgrapple.html b/docs/projects/webgrapple.html index b5e179f..7259905 100644 --- a/docs/projects/webgrapple.html +++ b/docs/projects/webgrapple.html @@ -7,13 +7,13 @@ webgrapple | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/tags.html b/docs/tags.html index 75da002..dea0526 100644 --- a/docs/tags.html +++ b/docs/tags.html @@ -7,13 +7,13 @@ Tags | foomo project docs - - + + - - + + \ No newline at end of file diff --git a/docs/tags/frontend.html b/docs/tags/frontend.html index db50c4c..8cd504d 100644 --- a/docs/tags/frontend.html +++ b/docs/tags/frontend.html @@ -7,13 +7,13 @@ One doc tagged with "frontend" | foomo project docs - - + +

One doc tagged with "frontend"

View All Tags

Stack

Our frontend stack is permanently changing as the underlying eco system does. We are trying to adopt technologies at the "Slope of Enlightenment" in the hype cycle.

- - + + \ No newline at end of file diff --git a/docs/tags/overview.html b/docs/tags/overview.html index 0145236..3d1f80f 100644 --- a/docs/tags/overview.html +++ b/docs/tags/overview.html @@ -7,13 +7,13 @@ One doc tagged with "overview" | foomo project docs - - + +

One doc tagged with "overview"

View All Tags

Stack

Our frontend stack is permanently changing as the underlying eco system does. We are trying to adopt technologies at the "Slope of Enlightenment" in the hype cycle.

- - + + \ No newline at end of file diff --git a/etc/imprint.html b/etc/imprint.html index 3794758..e1b0a10 100644 --- a/etc/imprint.html +++ b/etc/imprint.html @@ -7,8 +7,8 @@ foomo project docs - - + +
@@ -20,7 +20,7 @@ E-Mail: Haftung für Inhalte

Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.

Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.

Quellenangaben: Disclaimer eRecht24 - https://www.e-recht24.de/muster-disclaimer.html

Website-Design, Texte, Grafiken und Layout Copyright © 1998 - today bestbytes. ALLE RECHTE VORBEHALTEN. Das Kopieren oder die Reproduktion der gesamten Website bzw. von Teilen dieser Website ist untersagt, es sei denn, bestbytes hat dem vorher schriftlich oder elektronisch zugestimmt. Alle Markenzeichen und Logos, die auf dieser Internetseite verwendet werden, sind urheberrechtlich geschützt.

- - + + \ No newline at end of file diff --git a/index.html b/index.html index 6ff190e..2d01ad6 100644 --- a/index.html +++ b/index.html @@ -7,13 +7,13 @@ Hello from foomo project docs | foomo project docs - - + +

foomo project docs

Stuff we wrote, because nobody else wanted to


foomo is an open source project, that has been maintained by the bestbytes team since 2011. It provides a wide range of utilities, libraries and daemons, that help us to tackle challenging projects.

foomo can help, if you are

  • using Go to write services
  • building frontends with TypeScript and Next.js
  • running your software on k8s
  • looking for a solution to deeply integrate your frontends with a headless cms
If more than two points apply, it will actually help a LOT

General guides

no matter if frontend or backend - there is somtehing for everyone in here

Frontend guides

Build frontends with TypeScript, Next.js, styled components, gotsrpc

Backend guides

Write fast and reliable services in Go and run them in the cloud

Projects

Foomo projects - libraries, utilities, friendly daemons and more

CMS

foomo has extensive support for headless CMS Systems

Architecture

Show me the big picture - how does foomo integrate into the k8s and Next.js eco system

Awesome Software

a curated list of software we use in the cloud, on our desktops and our devices

DevOps

our approach to run cloud native applications where they belong

Blog

random information about programming, our ecosystem and misc fun topics

- - + + \ No newline at end of file diff --git a/search.html b/search.html index 3d27c4b..bd32fd9 100644 --- a/search.html +++ b/search.html @@ -7,13 +7,13 @@ Search the documentation | foomo project docs - - + +

Search the documentation

- - + + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index bc06335..941d9a3 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1 +1 @@ -https://www.foomo.org/awesome-softwareweekly0.5https://www.foomo.org/blogweekly0.5https://www.foomo.org/blog/archiveweekly0.5https://www.foomo.org/blog/debugging-go-map-races-in-k8sweekly0.5https://www.foomo.org/blog/impact-of-3rd-party-scripts-on-performanceweekly0.5https://www.foomo.org/blog/prometheus-cardinality-issuesweekly0.5https://www.foomo.org/blog/searching-for-search-enginesweekly0.5https://www.foomo.org/blog/tagsweekly0.5https://www.foomo.org/blog/tags/backendweekly0.5https://www.foomo.org/blog/tags/cardinalityweekly0.5https://www.foomo.org/blog/tags/debuggingweekly0.5https://www.foomo.org/blog/tags/devopsweekly0.5https://www.foomo.org/blog/tags/foomoweekly0.5https://www.foomo.org/blog/tags/frontendweekly0.5https://www.foomo.org/blog/tags/goweekly0.5https://www.foomo.org/blog/tags/k-8-sweekly0.5https://www.foomo.org/blog/tags/memoryweekly0.5https://www.foomo.org/blog/tags/oomweekly0.5https://www.foomo.org/blog/tags/opsweekly0.5https://www.foomo.org/blog/tags/performanceweekly0.5https://www.foomo.org/blog/tags/prometheusweekly0.5https://www.foomo.org/blog/tags/searchweekly0.5https://www.foomo.org/blog/tags/search-engineweekly0.5https://www.foomo.org/blog/welcome-back-2021weekly0.5https://www.foomo.org/docs/tagsweekly0.5https://www.foomo.org/docs/tags/frontendweekly0.5https://www.foomo.org/docs/tags/overviewweekly0.5https://www.foomo.org/etc/imprintweekly0.5https://www.foomo.org/searchweekly0.5https://www.foomo.org/docs/backend/go-by-example/map-racingweekly0.5https://www.foomo.org/docs/backend/go-by-example/nil-mapsweekly0.5https://www.foomo.org/docs/backend/go-by-example/panic-and-recoverweekly0.5https://www.foomo.org/docs/backend/go-by-example/rangingweekly0.5https://www.foomo.org/docs/backend/go-by-example/yaml-magicweekly0.5https://www.foomo.org/docs/backend/gograppleweekly0.5https://www.foomo.org/docs/backend/introweekly0.5https://www.foomo.org/docs/backend/rtfmweekly0.5https://www.foomo.org/docs/backend/setupweekly0.5https://www.foomo.org/docs/devops/bookmarksweekly0.5https://www.foomo.org/docs/devops/introweekly0.5https://www.foomo.org/docs/devops/k8sweekly0.5https://www.foomo.org/docs/devops/kubernetes/spot-instance-node-poolsweekly0.5https://www.foomo.org/docs/devops/monitoring/grafanaweekly0.5https://www.foomo.org/docs/devops/monitoring/introweekly0.5https://www.foomo.org/docs/devops/monitoring/jaegerweekly0.5https://www.foomo.org/docs/frontend/cssweekly0.5https://www.foomo.org/docs/frontend/debugging_jsweekly0.5https://www.foomo.org/docs/frontend/introweekly0.5https://www.foomo.org/docs/frontend/performanceweekly0.5https://www.foomo.org/docs/frontend/pitfallsweekly0.5https://www.foomo.org/docs/frontend/rtfmweekly0.5https://www.foomo.org/docs/frontend/setupweekly0.5https://www.foomo.org/docs/frontend/stackweekly0.5https://www.foomo.org/docs/frontend/typescript/objectsweekly0.5https://www.foomo.org/docs/frontend/typescript/spreadingweekly0.5https://www.foomo.org/docs/frontend/vscodeweekly0.5https://www.foomo.org/docs/general/essentialsweekly0.5https://www.foomo.org/docs/general/introweekly0.5https://www.foomo.org/docs/general/package-managersweekly0.5https://www.foomo.org/docs/general/securityweekly0.5https://www.foomo.org/docs/general/setup/computerweekly0.5https://www.foomo.org/docs/general/setup/workplaceweekly0.5https://www.foomo.org/docs/general/utilities/k9sweekly0.5https://www.foomo.org/docs/general/work/generalweekly0.5https://www.foomo.org/docs/general/work/remote-workweekly0.5https://www.foomo.org/docs/project-management/introweekly0.5https://www.foomo.org/docs/project-management/responsibilityweekly0.5https://www.foomo.org/docs/projects/architectureweekly0.5https://www.foomo.org/docs/projects/cms/contentfulweekly0.5https://www.foomo.org/docs/projects/cms/contentserverweekly0.5https://www.foomo.org/docs/projects/cms/introweekly0.5https://www.foomo.org/docs/projects/gotsrpcweekly0.5https://www.foomo.org/docs/projects/introweekly0.5https://www.foomo.org/docs/projects/libraries/keelweekly0.5https://www.foomo.org/docs/projects/pagespeed-exporterweekly0.5https://www.foomo.org/docs/projects/site-reliabilityweekly0.5https://www.foomo.org/docs/projects/utilities/gograppleweekly0.5https://www.foomo.org/docs/projects/webgrappleweekly0.5https://www.foomo.org/weekly0.5 \ No newline at end of file +https://www.foomo.org/awesome-softwareweekly0.5https://www.foomo.org/blogweekly0.5https://www.foomo.org/blog/archiveweekly0.5https://www.foomo.org/blog/debugging-go-map-races-in-k8sweekly0.5https://www.foomo.org/blog/impact-of-3rd-party-scripts-on-performanceweekly0.5https://www.foomo.org/blog/prometheus-cardinality-issuesweekly0.5https://www.foomo.org/blog/searching-for-search-enginesweekly0.5https://www.foomo.org/blog/tagsweekly0.5https://www.foomo.org/blog/tags/backendweekly0.5https://www.foomo.org/blog/tags/bundleweekly0.5https://www.foomo.org/blog/tags/bundle-sizeweekly0.5https://www.foomo.org/blog/tags/cardinalityweekly0.5https://www.foomo.org/blog/tags/debuggingweekly0.5https://www.foomo.org/blog/tags/devopsweekly0.5https://www.foomo.org/blog/tags/foomoweekly0.5https://www.foomo.org/blog/tags/frontendweekly0.5https://www.foomo.org/blog/tags/goweekly0.5https://www.foomo.org/blog/tags/javascriptweekly0.5https://www.foomo.org/blog/tags/k-8-sweekly0.5https://www.foomo.org/blog/tags/memoryweekly0.5https://www.foomo.org/blog/tags/oomweekly0.5https://www.foomo.org/blog/tags/opsweekly0.5https://www.foomo.org/blog/tags/performanceweekly0.5https://www.foomo.org/blog/tags/prometheusweekly0.5https://www.foomo.org/blog/tags/searchweekly0.5https://www.foomo.org/blog/tags/search-engineweekly0.5https://www.foomo.org/blog/welcome-back-2021weekly0.5https://www.foomo.org/blog/why-bundle-size-is-importantweekly0.5https://www.foomo.org/docs/tagsweekly0.5https://www.foomo.org/docs/tags/frontendweekly0.5https://www.foomo.org/docs/tags/overviewweekly0.5https://www.foomo.org/etc/imprintweekly0.5https://www.foomo.org/searchweekly0.5https://www.foomo.org/docs/backend/go-by-example/map-racingweekly0.5https://www.foomo.org/docs/backend/go-by-example/nil-mapsweekly0.5https://www.foomo.org/docs/backend/go-by-example/panic-and-recoverweekly0.5https://www.foomo.org/docs/backend/go-by-example/rangingweekly0.5https://www.foomo.org/docs/backend/go-by-example/yaml-magicweekly0.5https://www.foomo.org/docs/backend/gograppleweekly0.5https://www.foomo.org/docs/backend/introweekly0.5https://www.foomo.org/docs/backend/rtfmweekly0.5https://www.foomo.org/docs/backend/setupweekly0.5https://www.foomo.org/docs/devops/bookmarksweekly0.5https://www.foomo.org/docs/devops/introweekly0.5https://www.foomo.org/docs/devops/k8sweekly0.5https://www.foomo.org/docs/devops/kubernetes/spot-instance-node-poolsweekly0.5https://www.foomo.org/docs/devops/monitoring/grafanaweekly0.5https://www.foomo.org/docs/devops/monitoring/introweekly0.5https://www.foomo.org/docs/devops/monitoring/jaegerweekly0.5https://www.foomo.org/docs/frontend/cssweekly0.5https://www.foomo.org/docs/frontend/debugging_jsweekly0.5https://www.foomo.org/docs/frontend/introweekly0.5https://www.foomo.org/docs/frontend/performanceweekly0.5https://www.foomo.org/docs/frontend/pitfallsweekly0.5https://www.foomo.org/docs/frontend/rtfmweekly0.5https://www.foomo.org/docs/frontend/setupweekly0.5https://www.foomo.org/docs/frontend/stackweekly0.5https://www.foomo.org/docs/frontend/typescript/objectsweekly0.5https://www.foomo.org/docs/frontend/typescript/spreadingweekly0.5https://www.foomo.org/docs/frontend/vscodeweekly0.5https://www.foomo.org/docs/general/essentialsweekly0.5https://www.foomo.org/docs/general/introweekly0.5https://www.foomo.org/docs/general/package-managersweekly0.5https://www.foomo.org/docs/general/securityweekly0.5https://www.foomo.org/docs/general/setup/computerweekly0.5https://www.foomo.org/docs/general/setup/workplaceweekly0.5https://www.foomo.org/docs/general/utilities/k9sweekly0.5https://www.foomo.org/docs/general/work/generalweekly0.5https://www.foomo.org/docs/general/work/remote-workweekly0.5https://www.foomo.org/docs/project-management/introweekly0.5https://www.foomo.org/docs/project-management/responsibilityweekly0.5https://www.foomo.org/docs/projects/architectureweekly0.5https://www.foomo.org/docs/projects/cms/contentfulweekly0.5https://www.foomo.org/docs/projects/cms/contentserverweekly0.5https://www.foomo.org/docs/projects/cms/introweekly0.5https://www.foomo.org/docs/projects/gotsrpcweekly0.5https://www.foomo.org/docs/projects/introweekly0.5https://www.foomo.org/docs/projects/libraries/keelweekly0.5https://www.foomo.org/docs/projects/pagespeed-exporterweekly0.5https://www.foomo.org/docs/projects/site-reliabilityweekly0.5https://www.foomo.org/docs/projects/utilities/gograppleweekly0.5https://www.foomo.org/docs/projects/webgrappleweekly0.5https://www.foomo.org/weekly0.5 \ No newline at end of file