UNPKG

itemsjs

Version:

Created to perform fast search on small json dataset (up to 1000 elements).

1,689 lines (1,431 loc) 154 kB
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>ItemsJS</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta name="robots" content="noindex, nofollow"> <meta name="googlebot" content="noindex, nofollow"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script type="text/javascript" src="/js/lib/dummy.js" ></script> <link rel="stylesheet" type="text/css" href="/css/result-light.css"> <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css"> <script type="text/javascript" src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script> <script type="text/javascript" src="https://cdn.rawgit.com/itemsapi/itemsapi-example-data/master/jsfiddle/imdb.js"></script> <style id="compiled-css" type="text/css"> /* EOS */ </style> <script id="insert"></script> </head> <body> <div id="el"> <nav class="navbar navbar-default navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="#" v-on:click="reset()">ItemsJS movies</a> </div> <div id="navbar"> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" v-model="query" class="form-control" placeholder="Search"> </div> </form> </div><!--/.nav-collapse --> </div> </nav> <div class="container" style="margin-top: 50px;"> <h1>List of items ({{ searchResult.pagination.total }})</h1> <p class="text-muted">Search performed in {{ searchResult.timings.search }} ms, facets in {{ searchResult.timings.facets }} ms</p> <div class="breadcrumbs" style="margin: 0 0 10px 0; " v-if="selected_filters.length"> <span v-for="filter in selected_filters" class="label label-default" v-on:click="remove_filter(filter.facet, filter.name)" style="margin-right: 5px; cursor: pointer;">{{ filter.name }} <span class="glyphicon glyphicon-remove"></span> </span> <span class="label label-default pull-right" v-on:click="reset()" style="cursor: pointer; margin-right: 0;">Clear filters <span class="glyphicon glyphicon-remove"></span> </span> </div> <div class="clearfix"></div> <div class="" style="margin-bottom: 10px;"> <select class="form-control pull-left" style="width: auto; margin-top: 0px;" v-model="sort"> <option disabled value="">Select sort</option> <option v-for="option in sort_keys" v-bind:value="option"> {{ option }} </option> </select> <select class="form-control pull-left" style="width: auto; margin-top: 0px; margin-left: 5px;" v-model="per_page"> <option disabled value="">Select listing size</option> <option value="10">10</option> <option value="20">20</option> <option value="50">50</option> <option value="100">100</option> </select> <div class="clearfix"></div> </div> <div class="clearfix"></div> <div class="row"> <div class="col-md-2 col-xs-2"> <div v-for="facet in searchResult.data.aggregations"> <h5 style="margin-bottom: 5px;"><strong style="color: #337ab7;">{{ facet.title }}</strong></h5> <ul class="browse-list list-unstyled long-list" style="margin-bottom: 0;"> <li v-for="bucket in facet.buckets"> <div class="checkbox block" style="margin-top: 0; margin-bottom: 0;"> <label> <input class="checkbox" type="checkbox" v-model="filters[facet.name]" v-bind:value="bucket.key"> {{ bucket.key }} ({{ bucket.doc_count }}) </label> </div> </li> </ul> </div> </div> <div class="col-md-10 col-xs-10"> <div class="breadcrumbs"></div> <div class="clearfix"></div> <!--<h3>List of items ({{ searchResult.pagination.total }})</h3>--> <table class="table table-striped"> <tbody> <tr v-for="item of searchResult.data.items"> <td><img style="width: 100px;" v-bind:src="item.image"></td> <td></td> <td> <b>{{ item.name }}</b> <br /> {{ item.description }} </td> <td>{{ item.year }}</td> <td> <span style="font-size: 12px; display: block; float: left; background-color: #dbebf2; border-radius: 5px; padding: 1px 3px 1px 3px; margin: 2px;" v-for="tag in item.tags">{{ tag }}</span> </td> </tr> </tbody> </table> <div class="clearfix"></div> </div> <div class="clearfix" style="margin-bottom: 100px;"></div> </div> </div> </div> <script type="text/javascript">//<![CDATA[ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.itemsjs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ 'use strict'; module.exports = require('./src/index'); },{"./src/index":7}],2:[function(require,module,exports){ /* FastBitSet.js : a fast bit set implementation in JavaScript. * (c) the authors * Licensed under the Apache License, Version 2.0. * * Speed-optimized BitSet implementation for modern browsers and JavaScript engines. * * A BitSet is an ideal data structure to implement a Set when values being stored are * reasonably small integers. It can be orders of magnitude faster than a generic set implementation. * The FastBitSet implementation optimizes for speed, leveraging commonly available features * like typed arrays. * * Simple usage : * // const FastBitSet = require("fastbitset");// if you use node * const b = new FastBitSet();// initially empty * b.add(1);// add the value "1" * b.has(1); // check that the value is present! (will return true) * b.add(2); * console.log(""+b);// should display {1,2} * b.add(10); * b.array(); // would return [1,2,10] * * let c = new FastBitSet([1,2,3,10]); // create bitset initialized with values 1,2,3,10 * c.difference(b); // from c, remove elements that are in b (modifies c) * c.difference2(b); // from c, remove elements that are in b (modifies b) * c.change(b); // c will contain elements that are in b or in c, but not both * const su = c.union_size(b);// compute the size of the union (bitsets are unchanged) * c.union(b); // c will contain all elements that are in c and b * const s1 = c.intersection_size(b);// compute the size of the intersection (bitsets are unchanged) * c.intersection(b); // c will only contain elements that are in both c and b * c = b.clone(); // create a (deep) copy of b and assign it to c. * c.equals(b); // check whether c and b are equal * * See README.md file for a more complete description. * * You can install the library under node with the command line * npm install fastbitset */ "use strict"; // you can provide an iterable function FastBitSet(iterable) { this.words = []; if (iterable) { if (Symbol && Symbol.iterator && iterable[Symbol.iterator] !== undefined) { const iterator = iterable[Symbol.iterator](); let current = iterator.next(); while (!current.done) { this.add(current.value); current = iterator.next(); } } else { for (let i = 0; i < iterable.length; i++) { this.add(iterable[i]); } } } } // Creates a bitmap from words FastBitSet.prototype.fromWords = function (words) { const bitSet = Object.create(FastBitSet.prototype); bitSet.words = words; return bitSet; }; // Add the value (Set the bit at index to true) FastBitSet.prototype.add = function (index) { this.resize(index); this.words[index >>> 5] |= 1 << index; }; // If the value was not in the set, add it, otherwise remove it (flip bit at index) FastBitSet.prototype.flip = function (index) { this.resize(index); this.words[index >>> 5] ^= 1 << index; }; // Remove all values, reset memory usage FastBitSet.prototype.clear = function () { this.words.length = 0; }; // Set the bit at index to false FastBitSet.prototype.remove = function (index) { this.resize(index); this.words[index >>> 5] &= ~(1 << index); }; // Return true if no bit is set FastBitSet.prototype.isEmpty = function (index) { const c = this.words.length; for (let i = 0; i < c; i++) { if (this.words[i] !== 0) return false; } return true; }; // Is the value contained in the set? Is the bit at index true or false? Returns a boolean FastBitSet.prototype.has = function (index) { return (this.words[index >>> 5] & (1 << index)) !== 0; }; // Tries to add the value (Set the bit at index to true), return 1 if the // value was added, return 0 if the value was already present FastBitSet.prototype.checkedAdd = function (index) { this.resize(index); const word = this.words[index >>> 5]; const newword = word | (1 << index); this.words[index >>> 5] = newword; return (newword ^ word) >>> index; }; // Reduce the memory usage to a minimum FastBitSet.prototype.trim = function (index) { let nl = this.words.length; while (nl > 0 && this.words[nl - 1] === 0) { nl--; } this.words = this.words.slice(0, nl); }; // Resize the bitset so that we can write a value at index FastBitSet.prototype.resize = function (index) { const count = (index + 32) >>> 5; // just what is needed for (let i = this.words.length; i < count; i++) this.words[i] = 0; }; // fast function to compute the Hamming weight of a 32-bit unsigned integer FastBitSet.prototype.hammingWeight = function (v) { v -= (v >>> 1) & 0x55555555; // works with signed or unsigned shifts v = (v & 0x33333333) + ((v >>> 2) & 0x33333333); return (((v + (v >>> 4)) & 0xf0f0f0f) * 0x1010101) >>> 24; }; // fast function to compute the Hamming weight of four 32-bit unsigned integers FastBitSet.prototype.hammingWeight4 = function (v1, v2, v3, v4) { v1 -= (v1 >>> 1) & 0x55555555; // works with signed or unsigned shifts v2 -= (v2 >>> 1) & 0x55555555; // works with signed or unsigned shifts v3 -= (v3 >>> 1) & 0x55555555; // works with signed or unsigned shifts v4 -= (v4 >>> 1) & 0x55555555; // works with signed or unsigned shifts v1 = (v1 & 0x33333333) + ((v1 >>> 2) & 0x33333333); v2 = (v2 & 0x33333333) + ((v2 >>> 2) & 0x33333333); v3 = (v3 & 0x33333333) + ((v3 >>> 2) & 0x33333333); v4 = (v4 & 0x33333333) + ((v4 >>> 2) & 0x33333333); v1 = (v1 + (v1 >>> 4)) & 0xf0f0f0f; v2 = (v2 + (v2 >>> 4)) & 0xf0f0f0f; v3 = (v3 + (v3 >>> 4)) & 0xf0f0f0f; v4 = (v4 + (v4 >>> 4)) & 0xf0f0f0f; return ((v1 + v2 + v3 + v4) * 0x1010101) >>> 24; }; // How many values stored in the set? How many set bits? FastBitSet.prototype.size = function () { let answer = 0; const c = this.words.length; const w = this.words; for (let i = 0; i < c; i++) { answer += this.hammingWeight(w[i]); } return answer; }; // Return an array with the set bit locations (values) FastBitSet.prototype.array = function () { const answer = new Array(this.size()); let pos = 0 | 0; const c = this.words.length; for (let k = 0; k < c; ++k) { let w = this.words[k]; while (w != 0) { const t = w & -w; answer[pos++] = (k << 5) + this.hammingWeight((t - 1) | 0); w ^= t; } } return answer; }; // Return an array with the set bit locations (values) FastBitSet.prototype.forEach = function (fnc) { const c = this.words.length; for (let k = 0; k < c; ++k) { let w = this.words[k]; while (w != 0) { const t = w & -w; fnc((k << 5) + this.hammingWeight((t - 1) | 0)); w ^= t; } } }; // Returns an iterator of set bit locations (values) FastBitSet.prototype[Symbol.iterator] = function* () { const c = this.words.length; for (let k = 0; k < c; ++k) { let w = this.words[k]; while (w != 0) { const t = w & -w; yield (k << 5) + this.hammingWeight((t - 1) | 0); w ^= t; } } }; // Creates a copy of this bitmap FastBitSet.prototype.clone = function () { const clone = Object.create(FastBitSet.prototype); clone.words = this.words.slice(); return clone; }; // Check if this bitset intersects with another one, // no bitmap is modified FastBitSet.prototype.intersects = function (otherbitmap) { const newcount = Math.min(this.words.length, otherbitmap.words.length); for (let k = 0 | 0; k < newcount; ++k) { if ((this.words[k] & otherbitmap.words[k]) !== 0) return true; } return false; }; // Computes the intersection between this bitset and another one, // the current bitmap is modified (and returned by the function) FastBitSet.prototype.intersection = function (otherbitmap) { const newcount = Math.min(this.words.length, otherbitmap.words.length); let k = 0 | 0; for (; k + 7 < newcount; k += 8) { this.words[k] &= otherbitmap.words[k]; this.words[k + 1] &= otherbitmap.words[k + 1]; this.words[k + 2] &= otherbitmap.words[k + 2]; this.words[k + 3] &= otherbitmap.words[k + 3]; this.words[k + 4] &= otherbitmap.words[k + 4]; this.words[k + 5] &= otherbitmap.words[k + 5]; this.words[k + 6] &= otherbitmap.words[k + 6]; this.words[k + 7] &= otherbitmap.words[k + 7]; } for (; k < newcount; ++k) { this.words[k] &= otherbitmap.words[k]; } const c = this.words.length; for (k = newcount; k < c; ++k) { this.words[k] = 0; } return this; }; // Computes the size of the intersection between this bitset and another one FastBitSet.prototype.intersection_size = function (otherbitmap) { const newcount = Math.min(this.words.length, otherbitmap.words.length); let answer = 0 | 0; for (let k = 0 | 0; k < newcount; ++k) { answer += this.hammingWeight(this.words[k] & otherbitmap.words[k]); } return answer; }; // Computes the intersection between this bitset and another one, // a new bitmap is generated FastBitSet.prototype.new_intersection = function (otherbitmap) { const answer = Object.create(FastBitSet.prototype); const count = Math.min(this.words.length, otherbitmap.words.length); answer.words = new Array(count); let k = 0 | 0; for (; k + 7 < count; k += 8) { answer.words[k] = this.words[k] & otherbitmap.words[k]; answer.words[k + 1] = this.words[k + 1] & otherbitmap.words[k + 1]; answer.words[k + 2] = this.words[k + 2] & otherbitmap.words[k + 2]; answer.words[k + 3] = this.words[k + 3] & otherbitmap.words[k + 3]; answer.words[k + 4] = this.words[k + 4] & otherbitmap.words[k + 4]; answer.words[k + 5] = this.words[k + 5] & otherbitmap.words[k + 5]; answer.words[k + 6] = this.words[k + 6] & otherbitmap.words[k + 6]; answer.words[k + 7] = this.words[k + 7] & otherbitmap.words[k + 7]; } for (; k < count; ++k) { answer.words[k] = this.words[k] & otherbitmap.words[k]; } return answer; }; // Computes the intersection between this bitset and another one, // the current bitmap is modified FastBitSet.prototype.equals = function (otherbitmap) { const mcount = Math.min(this.words.length, otherbitmap.words.length); for (let k = 0 | 0; k < mcount; ++k) { if (this.words[k] != otherbitmap.words[k]) return false; } if (this.words.length < otherbitmap.words.length) { const c = otherbitmap.words.length; for (let k = this.words.length; k < c; ++k) { if (otherbitmap.words[k] != 0) return false; } } else if (otherbitmap.words.length < this.words.length) { const c = this.words.length; for (let k = otherbitmap.words.length; k < c; ++k) { if (this.words[k] != 0) return false; } } return true; }; // Computes the difference between this bitset and another one, // the current bitset is modified (and returned by the function) // (for this set A and other set B, // this computes A = A - B and returns A) FastBitSet.prototype.difference = function (otherbitmap) { const newcount = Math.min(this.words.length, otherbitmap.words.length); let k = 0 | 0; for (; k + 7 < newcount; k += 8) { this.words[k] &= ~otherbitmap.words[k]; this.words[k + 1] &= ~otherbitmap.words[k + 1]; this.words[k + 2] &= ~otherbitmap.words[k + 2]; this.words[k + 3] &= ~otherbitmap.words[k + 3]; this.words[k + 4] &= ~otherbitmap.words[k + 4]; this.words[k + 5] &= ~otherbitmap.words[k + 5]; this.words[k + 6] &= ~otherbitmap.words[k + 6]; this.words[k + 7] &= ~otherbitmap.words[k + 7]; } for (; k < newcount; ++k) { this.words[k] &= ~otherbitmap.words[k]; } return this; }; // Computes the difference between this bitset and another one, // the other bitset is modified (and returned by the function) // (for this set A and other set B, // this computes B = A - B and returns B) FastBitSet.prototype.difference2 = function (otherbitmap) { const mincount = Math.min(this.words.length, otherbitmap.words.length); let k = 0 | 0; for (; k + 7 < mincount; k += 8) { otherbitmap.words[k] = this.words[k] & ~otherbitmap.words[k]; otherbitmap.words[k + 1] = this.words[k + 1] & ~otherbitmap.words[k + 1]; otherbitmap.words[k + 2] = this.words[k + 2] & ~otherbitmap.words[k + 2]; otherbitmap.words[k + 3] = this.words[k + 3] & ~otherbitmap.words[k + 3]; otherbitmap.words[k + 4] = this.words[k + 4] & ~otherbitmap.words[k + 4]; otherbitmap.words[k + 5] = this.words[k + 5] & ~otherbitmap.words[k + 5]; otherbitmap.words[k + 6] = this.words[k + 6] & ~otherbitmap.words[k + 6]; otherbitmap.words[k + 7] = this.words[k + 7] & ~otherbitmap.words[k + 7]; } for (; k < mincount; ++k) { otherbitmap.words[k] = this.words[k] & ~otherbitmap.words[k]; } // remaining words are all part of difference for (k = this.words.length - 1; k >= mincount; --k) { otherbitmap.words[k] = this.words[k]; } otherbitmap.words = otherbitmap.words.slice(0, this.words.length); return otherbitmap; }; // Computes the difference between this bitset and another one, // a new bitmap is generated FastBitSet.prototype.new_difference = function (otherbitmap) { return this.clone().difference(otherbitmap); // should be fast enough }; // Computes the size of the difference between this bitset and another one FastBitSet.prototype.difference_size = function (otherbitmap) { const newcount = Math.min(this.words.length, otherbitmap.words.length); let answer = 0 | 0; let k = 0 | 0; for (; k < newcount; ++k) { answer += this.hammingWeight(this.words[k] & ~otherbitmap.words[k]); } const c = this.words.length; for (; k < c; ++k) { answer += this.hammingWeight(this.words[k]); } return answer; }; // Computes the changed elements (XOR) between this bitset and another one, // the current bitset is modified (and returned by the function) FastBitSet.prototype.change = function (otherbitmap) { const mincount = Math.min(this.words.length, otherbitmap.words.length); let k = 0 | 0; for (; k + 7 < mincount; k += 8) { this.words[k] ^= otherbitmap.words[k]; this.words[k + 1] ^= otherbitmap.words[k + 1]; this.words[k + 2] ^= otherbitmap.words[k + 2]; this.words[k + 3] ^= otherbitmap.words[k + 3]; this.words[k + 4] ^= otherbitmap.words[k + 4]; this.words[k + 5] ^= otherbitmap.words[k + 5]; this.words[k + 6] ^= otherbitmap.words[k + 6]; this.words[k + 7] ^= otherbitmap.words[k + 7]; } for (; k < mincount; ++k) { this.words[k] ^= otherbitmap.words[k]; } // remaining words are all part of change for (k = otherbitmap.words.length - 1; k >= mincount; --k) { this.words[k] = otherbitmap.words[k]; } return this; }; // Computes the change between this bitset and another one, // a new bitmap is generated FastBitSet.prototype.new_change = function (otherbitmap) { const answer = Object.create(FastBitSet.prototype); const count = Math.max(this.words.length, otherbitmap.words.length); answer.words = new Array(count); const mcount = Math.min(this.words.length, otherbitmap.words.length); let k = 0; for (; k + 7 < mcount; k += 8) { answer.words[k] = this.words[k] ^ otherbitmap.words[k]; answer.words[k + 1] = this.words[k + 1] ^ otherbitmap.words[k + 1]; answer.words[k + 2] = this.words[k + 2] ^ otherbitmap.words[k + 2]; answer.words[k + 3] = this.words[k + 3] ^ otherbitmap.words[k + 3]; answer.words[k + 4] = this.words[k + 4] ^ otherbitmap.words[k + 4]; answer.words[k + 5] = this.words[k + 5] ^ otherbitmap.words[k + 5]; answer.words[k + 6] = this.words[k + 6] ^ otherbitmap.words[k + 6]; answer.words[k + 7] = this.words[k + 7] ^ otherbitmap.words[k + 7]; } for (; k < mcount; ++k) { answer.words[k] = this.words[k] ^ otherbitmap.words[k]; } const c = this.words.length; for (k = mcount; k < c; ++k) { answer.words[k] = this.words[k]; } const c2 = otherbitmap.words.length; for (k = mcount; k < c2; ++k) { answer.words[k] = otherbitmap.words[k]; } return answer; }; // Computes the number of changed elements between this bitset and another one FastBitSet.prototype.change_size = function (otherbitmap) { const mincount = Math.min(this.words.length, otherbitmap.words.length); let answer = 0 | 0; let k = 0 | 0; for (; k < mincount; ++k) { answer += this.hammingWeight(this.words[k] ^ otherbitmap.words[k]); } const longer = this.words.length > otherbitmap.words.length ? this : otherbitmap; const c = longer.words.length; for (; k < c; ++k) { answer += this.hammingWeight(longer.words[k]); } return answer; }; // Returns a string representation FastBitSet.prototype.toString = function () { return "{" + this.array().join(",") + "}"; }; // Computes the union between this bitset and another one, // the current bitset is modified (and returned by the function) FastBitSet.prototype.union = function (otherbitmap) { const mcount = Math.min(this.words.length, otherbitmap.words.length); let k = 0 | 0; for (; k + 7 < mcount; k += 8) { this.words[k] |= otherbitmap.words[k]; this.words[k + 1] |= otherbitmap.words[k + 1]; this.words[k + 2] |= otherbitmap.words[k + 2]; this.words[k + 3] |= otherbitmap.words[k + 3]; this.words[k + 4] |= otherbitmap.words[k + 4]; this.words[k + 5] |= otherbitmap.words[k + 5]; this.words[k + 6] |= otherbitmap.words[k + 6]; this.words[k + 7] |= otherbitmap.words[k + 7]; } for (; k < mcount; ++k) { this.words[k] |= otherbitmap.words[k]; } if (this.words.length < otherbitmap.words.length) { this.resize((otherbitmap.words.length << 5) - 1); const c = otherbitmap.words.length; for (let k = mcount; k < c; ++k) { this.words[k] = otherbitmap.words[k]; } } return this; }; FastBitSet.prototype.new_union = function (otherbitmap) { const answer = Object.create(FastBitSet.prototype); const count = Math.max(this.words.length, otherbitmap.words.length); answer.words = new Array(count); const mcount = Math.min(this.words.length, otherbitmap.words.length); let k = 0; for (; k + 7 < mcount; k += 8) { answer.words[k] = this.words[k] | otherbitmap.words[k]; answer.words[k + 1] = this.words[k + 1] | otherbitmap.words[k + 1]; answer.words[k + 2] = this.words[k + 2] | otherbitmap.words[k + 2]; answer.words[k + 3] = this.words[k + 3] | otherbitmap.words[k + 3]; answer.words[k + 4] = this.words[k + 4] | otherbitmap.words[k + 4]; answer.words[k + 5] = this.words[k + 5] | otherbitmap.words[k + 5]; answer.words[k + 6] = this.words[k + 6] | otherbitmap.words[k + 6]; answer.words[k + 7] = this.words[k + 7] | otherbitmap.words[k + 7]; } for (; k < mcount; ++k) { answer.words[k] = this.words[k] | otherbitmap.words[k]; } const c = this.words.length; for (k = mcount; k < c; ++k) { answer.words[k] = this.words[k]; } const c2 = otherbitmap.words.length; for (k = mcount; k < c2; ++k) { answer.words[k] = otherbitmap.words[k]; } return answer; }; // Computes the size union between this bitset and another one FastBitSet.prototype.union_size = function (otherbitmap) { const mcount = Math.min(this.words.length, otherbitmap.words.length); let answer = 0 | 0; for (let k = 0 | 0; k < mcount; ++k) { answer += this.hammingWeight(this.words[k] | otherbitmap.words[k]); } if (this.words.length < otherbitmap.words.length) { const c = otherbitmap.words.length; for (let k = this.words.length; k < c; ++k) { answer += this.hammingWeight(otherbitmap.words[k] | 0); } } else { const c = this.words.length; for (let k = otherbitmap.words.length; k < c; ++k) { answer += this.hammingWeight(this.words[k] | 0); } } return answer; }; /////////////// module.exports = FastBitSet; },{}],3:[function(require,module,exports){ /** * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 1.0.0 * Copyright (C) 2017 Oliver Nightingale * @license MIT */ ;(function(){ /** * Convenience function for instantiating a new lunr index and configuring it * with the default pipeline functions and the passed config function. * * When using this convenience function a new index will be created with the * following functions already in the pipeline: * * lunr.StopWordFilter - filters out any stop words before they enter the * index * * lunr.stemmer - stems the tokens before entering the index. * * Example: * * var idx = lunr(function () { * this.field('title', 10) * this.field('tags', 100) * this.field('body') * * this.ref('cid') * * this.pipeline.add(function () { * // some custom pipeline function * }) * * }) * * @param {Function} config A function that will be called with the new instance * of the lunr.Index as both its context and first parameter. It can be used to * customize the instance of new lunr.Index. * @namespace * @module * @returns {lunr.Index} * */ var lunr = function (config) { var idx = new lunr.Index idx.pipeline.add( lunr.trimmer, lunr.stopWordFilter, lunr.stemmer ) if (config) config.call(idx, idx) return idx } lunr.version = "1.0.0" /*! * lunr.utils * Copyright (C) 2017 Oliver Nightingale */ /** * A namespace containing utils for the rest of the lunr library */ lunr.utils = {} /** * Print a warning message to the console. * * @param {String} message The message to be printed. * @memberOf Utils */ lunr.utils.warn = (function (global) { return function (message) { if (global.console && console.warn) { console.warn(message) } } })(this) /** * Convert an object to a string. * * In the case of `null` and `undefined` the function returns * the empty string, in all other cases the result of calling * `toString` on the passed object is returned. * * @param {Any} obj The object to convert to a string. * @return {String} string representation of the passed object. * @memberOf Utils */ lunr.utils.asString = function (obj) { if (obj === void 0 || obj === null) { return "" } else { return obj.toString() } } /*! * lunr.EventEmitter * Copyright (C) 2017 Oliver Nightingale */ /** * lunr.EventEmitter is an event emitter for lunr. It manages adding and removing event handlers and triggering events and their handlers. * * @constructor */ lunr.EventEmitter = function () { this.events = {} } /** * Binds a handler function to a specific event(s). * * Can bind a single function to many different events in one call. * * @param {String} [eventName] The name(s) of events to bind this function to. * @param {Function} fn The function to call when an event is fired. * @memberOf EventEmitter */ lunr.EventEmitter.prototype.addListener = function () { var args = Array.prototype.slice.call(arguments), fn = args.pop(), names = args if (typeof fn !== "function") throw new TypeError ("last argument must be a function") names.forEach(function (name) { if (!this.hasHandler(name)) this.events[name] = [] this.events[name].push(fn) }, this) } /** * Removes a handler function from a specific event. * * @param {String} eventName The name of the event to remove this function from. * @param {Function} fn The function to remove from an event. * @memberOf EventEmitter */ lunr.EventEmitter.prototype.removeListener = function (name, fn) { if (!this.hasHandler(name)) return var fnIndex = this.events[name].indexOf(fn) this.events[name].splice(fnIndex, 1) if (!this.events[name].length) delete this.events[name] } /** * Calls all functions bound to the given event. * * Additional data can be passed to the event handler as arguments to `emit` * after the event name. * * @param {String} eventName The name of the event to emit. * @memberOf EventEmitter */ lunr.EventEmitter.prototype.emit = function (name) { if (!this.hasHandler(name)) return var args = Array.prototype.slice.call(arguments, 1) this.events[name].forEach(function (fn) { fn.apply(undefined, args) }) } /** * Checks whether a handler has ever been stored against an event. * * @param {String} eventName The name of the event to check. * @private * @memberOf EventEmitter */ lunr.EventEmitter.prototype.hasHandler = function (name) { return name in this.events } /*! * lunr.tokenizer * Copyright (C) 2017 Oliver Nightingale */ /** * A function for splitting a string into tokens ready to be inserted into * the search index. Uses `lunr.tokenizer.separator` to split strings, change * the value of this property to change how strings are split into tokens. * * @module * @param {String} obj The string to convert into tokens * @see lunr.tokenizer.separator * @returns {Array} */ lunr.tokenizer = function (obj) { if (!arguments.length || obj == null || obj == undefined) return [] if (Array.isArray(obj)) return obj.map(function (t) { return lunr.utils.asString(t).toLowerCase() }) return obj.toString().trim().toLowerCase().split(lunr.tokenizer.separator) } /** * The sperator used to split a string into tokens. Override this property to change the behaviour of * `lunr.tokenizer` behaviour when tokenizing strings. By default this splits on whitespace and hyphens. * * @static * @see lunr.tokenizer */ lunr.tokenizer.separator = /[\s\-]+/ /** * Loads a previously serialised tokenizer. * * A tokenizer function to be loaded must already be registered with lunr.tokenizer. * If the serialised tokenizer has not been registered then an error will be thrown. * * @param {String} label The label of the serialised tokenizer. * @returns {Function} * @memberOf tokenizer */ lunr.tokenizer.load = function (label) { var fn = this.registeredFunctions[label] if (!fn) { throw new Error('Cannot load un-registered function: ' + label) } return fn } lunr.tokenizer.label = 'default' lunr.tokenizer.registeredFunctions = { 'default': lunr.tokenizer } /** * Register a tokenizer function. * * Functions that are used as tokenizers should be registered if they are to be used with a serialised index. * * Registering a function does not add it to an index, functions must still be associated with a specific index for them to be used when indexing and searching documents. * * @param {Function} fn The function to register. * @param {String} label The label to register this function with * @memberOf tokenizer */ lunr.tokenizer.registerFunction = function (fn, label) { if (label in this.registeredFunctions) { lunr.utils.warn('Overwriting existing tokenizer: ' + label) } fn.label = label this.registeredFunctions[label] = fn } /*! * lunr.Pipeline * Copyright (C) 2017 Oliver Nightingale */ /** * lunr.Pipelines maintain an ordered list of functions to be applied to all * tokens in documents entering the search index and queries being ran against * the index. * * An instance of lunr.Index created with the lunr shortcut will contain a * pipeline with a stop word filter and an English language stemmer. Extra * functions can be added before or after either of these functions or these * default functions can be removed. * * When run the pipeline will call each function in turn, passing a token, the * index of that token in the original list of all tokens and finally a list of * all the original tokens. * * The output of functions in the pipeline will be passed to the next function * in the pipeline. To exclude a token from entering the index the function * should return undefined, the rest of the pipeline will not be called with * this token. * * For serialisation of pipelines to work, all functions used in an instance of * a pipeline should be registered with lunr.Pipeline. Registered functions can * then be loaded. If trying to load a serialised pipeline that uses functions * that are not registered an error will be thrown. * * If not planning on serialising the pipeline then registering pipeline functions * is not necessary. * * @constructor */ lunr.Pipeline = function () { this._stack = [] } lunr.Pipeline.registeredFunctions = {} /** * Register a function with the pipeline. * * Functions that are used in the pipeline should be registered if the pipeline * needs to be serialised, or a serialised pipeline needs to be loaded. * * Registering a function does not add it to a pipeline, functions must still be * added to instances of the pipeline for them to be used when running a pipeline. * * @param {Function} fn The function to check for. * @param {String} label The label to register this function with * @memberOf Pipeline */ lunr.Pipeline.registerFunction = function (fn, label) { if (label in this.registeredFunctions) { lunr.utils.warn('Overwriting existing registered function: ' + label) } fn.label = label lunr.Pipeline.registeredFunctions[fn.label] = fn } /** * Warns if the function is not registered as a Pipeline function. * * @param {Function} fn The function to check for. * @private * @memberOf Pipeline */ lunr.Pipeline.warnIfFunctionNotRegistered = function (fn) { var isRegistered = fn.label && (fn.label in this.registeredFunctions) if (!isRegistered) { lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\n', fn) } } /** * Loads a previously serialised pipeline. * * All functions to be loaded must already be registered with lunr.Pipeline. * If any function from the serialised data has not been registered then an * error will be thrown. * * @param {Object} serialised The serialised pipeline to load. * @returns {lunr.Pipeline} * @memberOf Pipeline */ lunr.Pipeline.load = function (serialised) { var pipeline = new lunr.Pipeline serialised.forEach(function (fnName) { var fn = lunr.Pipeline.registeredFunctions[fnName] if (fn) { pipeline.add(fn) } else { throw new Error('Cannot load un-registered function: ' + fnName) } }) return pipeline } /** * Adds new functions to the end of the pipeline. * * Logs a warning if the function has not been registered. * * @param {Function} functions Any number of functions to add to the pipeline. * @memberOf Pipeline */ lunr.Pipeline.prototype.add = function () { var fns = Array.prototype.slice.call(arguments) fns.forEach(function (fn) { lunr.Pipeline.warnIfFunctionNotRegistered(fn) this._stack.push(fn) }, this) } /** * Adds a single function after a function that already exists in the * pipeline. * * Logs a warning if the function has not been registered. * * @param {Function} existingFn A function that already exists in the pipeline. * @param {Function} newFn The new function to add to the pipeline. * @memberOf Pipeline */ lunr.Pipeline.prototype.after = function (existingFn, newFn) { lunr.Pipeline.warnIfFunctionNotRegistered(newFn) var pos = this._stack.indexOf(existingFn) if (pos == -1) { throw new Error('Cannot find existingFn') } pos = pos + 1 this._stack.splice(pos, 0, newFn) } /** * Adds a single function before a function that already exists in the * pipeline. * * Logs a warning if the function has not been registered. * * @param {Function} existingFn A function that already exists in the pipeline. * @param {Function} newFn The new function to add to the pipeline. * @memberOf Pipeline */ lunr.Pipeline.prototype.before = function (existingFn, newFn) { lunr.Pipeline.warnIfFunctionNotRegistered(newFn) var pos = this._stack.indexOf(existingFn) if (pos == -1) { throw new Error('Cannot find existingFn') } this._stack.splice(pos, 0, newFn) } /** * Removes a function from the pipeline. * * @param {Function} fn The function to remove from the pipeline. * @memberOf Pipeline */ lunr.Pipeline.prototype.remove = function (fn) { var pos = this._stack.indexOf(fn) if (pos == -1) { return } this._stack.splice(pos, 1) } /** * Runs the current list of functions that make up the pipeline against the * passed tokens. * * @param {Array} tokens The tokens to run through the pipeline. * @returns {Array} * @memberOf Pipeline */ lunr.Pipeline.prototype.run = function (tokens) { var out = [], tokenLength = tokens.length, stackLength = this._stack.length for (var i = 0; i < tokenLength; i++) { var token = tokens[i] for (var j = 0; j < stackLength; j++) { token = this._stack[j](token, i, tokens) if (token === void 0 || token === '') break }; if (token !== void 0 && token !== '') out.push(token) }; return out } /** * Resets the pipeline by removing any existing processors. * * @memberOf Pipeline */ lunr.Pipeline.prototype.reset = function () { this._stack = [] } /** * Returns a representation of the pipeline ready for serialisation. * * Logs a warning if the function has not been registered. * * @returns {Array} * @memberOf Pipeline */ lunr.Pipeline.prototype.toJSON = function () { return this._stack.map(function (fn) { lunr.Pipeline.warnIfFunctionNotRegistered(fn) return fn.label }) } /*! * lunr.Vector * Copyright (C) 2017 Oliver Nightingale */ /** * lunr.Vectors implement vector related operations for * a series of elements. * * @constructor */ lunr.Vector = function () { this._magnitude = null this.list = undefined this.length = 0 } /** * lunr.Vector.Node is a simple struct for each node * in a lunr.Vector. * * @private * @param {Number} The index of the node in the vector. * @param {Object} The data at this node in the vector. * @param {lunr.Vector.Node} The node directly after this node in the vector. * @constructor * @memberOf Vector */ lunr.Vector.Node = function (idx, val, next) { this.idx = idx this.val = val this.next = next } /** * Inserts a new value at a position in a vector. * * @param {Number} The index at which to insert a value. * @param {Object} The object to insert in the vector. * @memberOf Vector. */ lunr.Vector.prototype.insert = function (idx, val) { this._magnitude = undefined; var list = this.list if (!list) { this.list = new lunr.Vector.Node (idx, val, list) return this.length++ } if (idx < list.idx) { this.list = new lunr.Vector.Node (idx, val, list) return this.length++ } var prev = list, next = list.next while (next != undefined) { if (idx < next.idx) { prev.next = new lunr.Vector.Node (idx, val, next) return this.length++ } prev = next, next = next.next } prev.next = new lunr.Vector.Node (idx, val, next) return this.length++ } /** * Calculates the magnitude of this vector. * * @returns {Number} * @memberOf Vector */ lunr.Vector.prototype.magnitude = function () { if (this._magnitude) return this._magnitude var node = this.list, sumOfSquares = 0, val while (node) { val = node.val sumOfSquares += val * val node = node.next } return this._magnitude = Math.sqrt(sumOfSquares) } /** * Calculates the dot product of this vector and another vector. * * @param {lunr.Vector} otherVector The vector to compute the dot product with. * @returns {Number} * @memberOf Vector */ lunr.Vector.prototype.dot = function (otherVector) { var node = this.list, otherNode = otherVector.list, dotProduct = 0 while (node && otherNode) { if (node.idx < otherNode.idx) { node = node.next } else if (node.idx > otherNode.idx) { otherNode = otherNode.next } else { dotProduct += node.val * otherNode.val node = node.next otherNode = otherNode.next } } return dotProduct } /** * Calculates the cosine similarity between this vector and another * vector. * * @param {lunr.Vector} otherVector The other vector to calculate the * similarity with. * @returns {Number} * @memberOf Vector */ lunr.Vector.prototype.similarity = function (otherVector) { return this.dot(otherVector) / (this.magnitude() * otherVector.magnitude()) } /*! * lunr.SortedSet * Copyright (C) 2017 Oliver Nightingale */ /** * lunr.SortedSets are used to maintain an array of uniq values in a sorted * order. * * @constructor */ lunr.SortedSet = function () { this.length = 0 this.elements = [] } /** * Loads a previously serialised sorted set. * * @param {Array} serialisedData The serialised set to load. * @returns {lunr.SortedSet} * @memberOf SortedSet */ lunr.SortedSet.load = function (serialisedData) { var set = new this set.elements = serialisedData set.length = serialisedData.length return set } /** * Inserts new items into the set in the correct position to maintain the * order. * * @param {Object} The objects to add to this set. * @memberOf SortedSet */ lunr.SortedSet.prototype.add = function () { var i, element for (i = 0; i < arguments.length; i++) { element = arguments[i] if (~this.indexOf(element)) continue this.elements.splice(this.locationFor(element), 0, element) } this.length = this.elements.length } /** * Converts this sorted set into an array. * * @returns {Array} * @memberOf SortedSet */ lunr.SortedSet.prototype.toArray = function () { return this.elements.slice() } /** * Creates a new array with the results of calling a provided function on every * element in this sorted set. * * Delegates to Array.prototype.map and has the same signature. * * @param {Function} fn The function that is called on each element of the * set. * @param {Object} ctx An optional object that can be used as the context * for the function fn. * @returns {Array} * @memberOf SortedSet */ lunr.SortedSet.prototype.map = function (fn, ctx) { return this.elements.map(fn, ctx) } /** * Executes a provided function once per sorted set element. * * Delegates to Array.prototype.forEach and has the same signature. * * @param {Function} fn The function that is called on each element of the * set. * @param {Object} ctx An optional object that can be used as the context * @memberOf SortedSet * for the function fn. */ lunr.SortedSet.prototype.forEach = function (fn, ctx) { return this.elements.forEach(fn, ctx) } /** * Returns the index at which a given element can be found in the * sorted set, or -1 if it is not present. * * @param {Object} elem The object to locate in the sorted set. * @returns {Number} * @memberOf SortedSet */ lunr.SortedSet.prototype.indexOf = function (elem) { var start = 0, end = this.elements.length, sectionLength = end - start, pivot = start + Math.floor(sectionLength / 2), pivotElem = this.elements[pivot] while (sectionLength > 1) { if (pivotElem === elem) return pivot if (pivotElem < elem) start = pivot if (pivotElem > elem) end = pivot sectionLength = end - start pivot = start + Math.floor(sectionLength / 2) pivotElem = this.elements[pivot] } if (pivotElem === elem) return pivot return -1 } /** * Returns the position within the sorted set that an element should be * inserted at to maintain the current order of the set. * * This function assumes that the element to search for does not already exist * in the sorted set. * * @param {Object} elem The elem to find the position for in the set * @returns {Number} * @memberOf SortedSet */ lunr.SortedSet.prototype.locationFor = function (elem) { var start = 0, end = this.elements.length, sectionLength = end - start, pivot = start + Math.floor(sectionLength / 2), pivotElem = this.elements[pivot] while (sectionLength > 1) { if (pivotElem < elem) start = pivot if (pivotElem > elem) end = pivot sectionLength = end - start pivot = start + Math.floor(sectionLength / 2) pivotElem = this.elements[pivot] } if (pivotElem > elem) return pivot if (pivotElem < elem) return pivot + 1 } /** * Creates a new lunr.SortedSet that contains the elements in the intersection * of this set and the passed set. * * @param {lunr.SortedSet} otherSet The set to intersect with this set. * @returns {lunr.SortedSet} * @memberOf SortedSet */ lunr.SortedSet.prototype.intersect = function (otherSet) { var intersectSet = new lunr.SortedSet, i = 0, j = 0, a_len = this.length, b_len = otherSet.length, a = this.elements, b = otherSet.elements while (true) { if (i > a_len - 1 || j > b_len - 1) break if (a[i] === b[j]) { intersectSet.add(a[i]) i++, j++ continue } if (a[i] < b[j]) { i++ continue } if (a[i] > b[j]) { j++ continue } }; return intersectSet } /** * Makes a copy of this set * * @returns {lunr.SortedSet} * @memberOf SortedSet */ lunr.SortedSet.prototype.clone = function () { var clone = new lunr.SortedSet clone.elements = this.toArray() clone.length = clone.elements.length return clone } /** * Creates a new lunr.SortedSet that contains the elements in the union * of this set and the passed set. * * @param {lunr.SortedSet} otherSet The set to union with this set. * @returns {lunr.SortedSet} * @memberOf SortedSet */ lunr.SortedSet.prototype.union = function (otherSet) { var longSet, shortSet, unionSet if (this.length >= otherSet.length) { longSet = this, shortSet = otherSet } else { longSet = otherSet, shortSet = this } unionSet = longSet.clone() for(var i = 0, shortSetElements = shortSet.toArray(); i < shortSetElements.length; i++){ unionSet.add(shortSetElements[i]) } return unionSet } /** * Returns a representation of the sorted set ready for serialisation. * * @returns {Array} * @memberOf SortedSet */ lunr.SortedSet.prototype.toJSON = function () { return this.toArray() } /*! * lunr.Index * Copyright (C) 2017 Oliver Nightingale */ /** * lunr.Index is object that manages a search index. It contains the indexes * and stores all the tokens and document lookups. It also provides the main * user facing API for the library. * * @constructor */ lunr.Index = function () { this._fields = [] this._ref = 'id' this.pipeline = new lunr.Pipeline this.documentStore = new lunr.Store this.tokenStore = new lunr.TokenStore this.corpusTokens = new lunr.SortedSet this.eventEmitter = new lunr.EventEmitter this.tokenizerFn = lunr.tokenizer this._idfCache = {} this.on('add', 'remove', 'update', (function () { this._idfCache = {} }).bind(this)) } /** * Bind a handler to events being emitted by the index. * * The handler can be bound to many events at the same time. * * @param {String} [eventName] The name(s) of events to bind the function to. * @param {Function} fn The serialised set to load. * @memberOf Index */ lunr.Index.prototype.on = function () { var args = Array.prototype.slice.call(arguments) return this.eventEmitter.addListener.apply(this.eventEmitter, args) } /** * Removes a handler from an event being emitted by the index. * * @param {String} eventName The name of events to remove the function from. * @param {Function} fn The serialised set to load. * @memberOf Index */ lunr.Index.prototype.off = function (name, fn) { return this.eventEmitter.removeListener(name, fn) } /** * Loads a previously serialised index. * * Issues a warning if the index being imported was serialised * by a different version of lunr. * * @param {Object} serialisedData The serialised set to load. * @returns {lunr.Index} * @memberOf Index */ lunr.Index.load = function (serialisedData) { if (serialisedData.version !== lunr.version) { lunr.utils.warn('version mismatch: current ' + lunr.version + ' importing ' + serialisedData.version) } var idx = new this idx._fields = serialisedData.fields idx._ref = serialisedData.ref idx.tokenizer(lunr.tokenizer.load(serialisedData.tokeniz