This commit is contained in:
2025-05-12 05:38:44 +09:00
parent dced21c3f8
commit 6d78bfa46e
8120 changed files with 1161564 additions and 0 deletions

1
book/node_modules/lunr/.npmignore generated vendored Normal file
View File

@@ -0,0 +1 @@
/node_modules

7
book/node_modules/lunr/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,7 @@
language: node_js
before_script: "node server.js 3000 &"
script: "phantomjs test/env/runner.js http://localhost:3000/test"
node_js:
- "0.8"
- "0.10"
- "0.12"

128
book/node_modules/lunr/CHANGELOG.mdown generated vendored Normal file
View File

@@ -0,0 +1,128 @@
# Changelog
## 0.5.12
* Implement `lunr.stopWordFilter` with an object instead of using `lunr.SortedSet` [#170](https://github.com/olivernn/lunr.js/pull/170), resulting in a performance boost for the text processing pipeline, thanks to [Brian Vaughn](https://github.com/bvaughn).
* Ensure that `lunr.trimmer` does not introduce empty tokens into the index, [#166](https://github.com/olivernn/lunr.js/pull/166), thanks to [janeisklar](https://github.com/janeisklar)
## 0.5.11
* Fix [bug](https://github.com/olivernn/lunr.js/issues/162) when using the unminified build of lunr in some project builds, thanks [Alessio Michelini](https://github.com/darkmavis1980)
## 0.5.10
* Fix bug in IDF calculation, thanks to [weixsong](https://github.com/weixsong) for discovering the issue.
* Documentation fixes [#111](https://github.com/olivernn/lunr.js/pull/111) thanks [Chris Van](https://github.com/cvan).
* Remove version from bower.json as it is not needed [#160](https://github.com/olivernn/lunr.js/pull/160), thanks [Kevin Kirsche](https://github.com/kkirsche)
* Fix link to augment.js on the home page [#159](https://github.com/olivernn/lunr.js/issues/159), thanks [Gábor Nádai](https://github.com/mefiblogger)
## 0.5.9
* Remove recursion from SortedSet#indexOf and SortedSet#locationFor to gain small performance gains in Index#search and Index#add
* Fix incorrect handling of non existant functions when adding/removing from a Pipeline [#146](https://github.com/olivernn/lunr.js/issues/146) thanks to [weixsong](https://github.com/weixsong)
## 0.5.8
* Fix typo when referencing Martin Porter's home page http://tartarus.org/~martin/ [#132](https://github.com/olivernn/lunr.js/pull/132) thanks [James Aylett](https://github.com/jaylett)
* Performance improvement for tokenizer [#139](https://github.com/olivernn/lunr.js/pull/139) thanks [Arun Srinivasan](https://github.com/satchmorun)
* Fix vector magnitude caching bug :flushed: [#142](https://github.com/olivernn/lunr.js/pull/142) thanks [Richard Poole](https://github.com/richardpoole)
* Fix vector insertion bug that prevented lesser ordered nodes to be inserted into a vector [#143](https://github.com/olivernn/lunr.js/pull/143) thanks [Richard Poole](https://github.com/richardpoole)
* Fix inefficient use of arguments in SortedSet add method, thanks to [Max Nordlund](https://github.com/maxnordlund).
* Fix deprecated use of path.exists in test server [#141](https://github.com/olivernn/lunr.js/pull/141) thanks [wei song](https://github.com/weixsong)
## 0.5.7
* Performance improvement for stemmer [#124](https://github.com/olivernn/lunr.js/pull/124) thanks [Tony Jacobs](https://github.com/tony-jacobs)
## 0.5.6
* Performance improvement when add documents to the index [#114](https://github.com/olivernn/lunr.js/pull/114) thanks [Alex Holmes](https://github.com/alex2)
## 0.5.5
* Fix bug in tokenizer introduced in 0.5.4 [#101](https://github.com/olivernn/lunr.js/pull/101) thanks [Nolan Lawson](https://github.com/nolanlawson)
## 0.5.4
* Tokenizer also splits on hyphens [#98](https://github.com/olivernn/lunr.js/pull/98/files) thanks [Nolan Lawson](https://github.com/nolanlawson)
## 0.5.3
* Correctly stem words ending with the letter 'y' [#84](https://github.com/olivernn/lunr.js/pull/84) thanks [Mihai Valentin](https://github.com/MihaiValentin)
* Improve build tools and dev dependency installation [#78](https://github.com/olivernn/lunr.js/pull/78) thanks [Ben Pickles](https://github.com/benpickles)
## 0.5.2
* Use npm they said, it'll be easy they said.
## 0.5.1
* Because [npm issues](https://github.com/olivernn/lunr.js/issues/77) :(
## 0.5.0
* Add plugin support to enable i18n and other extensions to lunr.
* Add AMD support [#72](https://github.com/olivernn/lunr.js/issues/72) thanks [lnwdr](https://github.com/lnwdr).
* lunr.Vector now implemented using linked lists for better performance especially in indexes with large numbers of unique tokens.
* Build system clean up.
## 0.4.5
* Fix performance regression introduced in 0.4.4 by fixing #64.
## 0.4.4
* Fix bug [#64](https://github.com/olivernn/lunr.js/issues/64) idf cache should handle tokens with the same name as object properties, thanks [gitgrimbo](https://github.com/gitgrimbo).
* Intersperse source files with a semicolon as part of the build process, fixes [#61](https://github.com/olivernn/lunr.js/issues/61), thanks [shyndman](https://github.com/shyndman).
## 0.4.3
* Fix bug [#49](https://github.com/olivernn/lunr.js/issues/49) tokenizer should handle null and undefined as arguments, thanks [jona](https://github.com/jona).
## 0.4.2
* Fix bug [#47](https://github.com/olivernn/lunr.js/issues/47) tokenizer converts its input to a string before trying to split it into tokens, thanks [mikhailkozlov](https://github.com/mikhailkozlov).
## 0.4.1
* Fix bug [#41](https://github.com/olivernn/lunr.js/issues/41) that caused issues when indexing mixed case tags, thanks [Aptary](https://github.com/Aptary)
## 0.4.0
* Add index mutation events ('add', 'update' and 'remove').
* Performance improvements to searching.
* Penalise non-exact matches so exact matches are better ranked than expanded matches.
## 0.3.3
* Fix bug [#32](https://github.com/olivernn/lunr.js/pull/32) which prevented lunr being used where a `console` object is not present, thanks [Tony Marklove](https://github.com/jjbananas) and [wyuenho](https://github.com/wyuenho)
## 0.3.2
* Fix bug [#27](https://github.com/olivernn/lunr.js/pull/27) when trying to calculate tf with empty fields, thanks [Gambhiro](https://github.com/gambhiro)
## 0.3.1
* Fix bug [#24](https://github.com/olivernn/lunr.js/pull/24) that caused an error when trying to remove a non-existant document from the index, thanks [Jesús Leganés Combarro](https://github.com/piranna)
## 0.3.0
* Implement [JSON serialisation](https://github.com/olivernn/lunr.js/pull/14), allows indexes to be loaded and dumped, thanks [ssured](https://github.com/ssured).
* Performance improvements to searching and indexing.
* Fix bug [#15](https://github.com/olivernn/lunr.js/pull/15) with tokeniser that added stray empty white space to the index, thanks [ssured](https://github.com/ssured).
## 0.2.3
* Fix issue with searching for a term not in the index [#12](https://github.com/olivernn/lunr.js/issues/12), thanks [mcnerthney](https://github.com/mcnerthney) and [makoto](https://github.com/makoto)
## 0.2.2
* Boost exact term matches so they are better ranked than expanded term matches, fixes [#10](https://github.com/olivernn/lunr.js/issues/10), thanks [ssured](https://github.com/ssured)
## 0.2.1
* Changes to the build process.
* Add component.json and package.json
* Add phantomjs test runner
* Remove redundant attributes
* Many [spelling corrections](https://github.com/olivernn/lunr.js/pull/8), thanks [Pascal Borreli](https://github.com/pborreli)

1
book/node_modules/lunr/CNAME generated vendored Normal file
View File

@@ -0,0 +1 @@
lunrjs.com

20
book/node_modules/lunr/CONTRIBUTING.mdown generated vendored Normal file
View File

@@ -0,0 +1,20 @@
Contributions are very welcome. To make the process as easy as possible please follow these steps:
* Open an issue detailing the bug you've found, or the feature you wish to add. Simplified working examples using something like [jsFiddle](http://jsfiddle.net) make it easier to diagnose your problem.
* Add tests for your code (so I don't accidentally break it in the future).
* Don't change version numbers or make new builds as part of your changes.
* Don't change the built versions of the library; only make changes to code in the `lib` directory.
# Developer Dependencies
A JavaScript runtime is required for building the library.
Run the tests (using PhantomJS):
make test
The tests can also be run in the browser by starting the test server:
make server
This will start a server on port 3000, the tests are then available at `/test`.

19
book/node_modules/lunr/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (C) 2013 by Oliver Nightingale
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

68
book/node_modules/lunr/Makefile generated vendored Normal file
View File

@@ -0,0 +1,68 @@
SRC = lib/lunr.js \
lib/utils.js \
lib/event_emitter.js \
lib/tokenizer.js \
lib/pipeline.js \
lib/vector.js \
lib/sorted_set.js \
lib/index.js \
lib/document_store.js \
lib/stemmer.js \
lib/stop_word_filter.js \
lib/trimmer.js \
lib/token_store.js \
YEAR = $(shell date +%Y)
VERSION = $(shell cat VERSION)
SERVER_PORT ?= 3000
TEST_PORT ?= 32423
DOX ?= ./node_modules/.bin/dox
DOX_TEMPLATE ?= ./node_modules/.bin/dox-template
NODE ?= /usr/local/bin/node
NPM ?= /usr/local/bin/npm
PHANTOMJS ?= ./node_modules/.bin/phantomjs
UGLIFYJS ?= ./node_modules/.bin/uglifyjs
all: node_modules lunr.js lunr.min.js docs bower.json package.json component.json example
lunr.js: $(SRC)
cat build/wrapper_start $^ build/wrapper_end | \
sed "s/@YEAR/${YEAR}/" | \
sed "s/@VERSION/${VERSION}/" > $@
lunr.min.js: lunr.js
${UGLIFYJS} --compress --mangle --comments < $< > $@
%.json: build/%.json.template
cat $< | sed "s/@VERSION/${VERSION}/" > $@
size: lunr.min.js
@gzip -c lunr.min.js | wc -c
server:
${NODE} server.js ${SERVER_PORT}
test: node_modules
@./test/runner.sh ${TEST_PORT}
docs: node_modules
${DOX} < lunr.js | ${DOX_TEMPLATE} -n lunr.js -r ${VERSION} > docs/index.html
clean:
rm -f lunr{.min,}.js
rm *.json
rm example/example_index.json
reset:
git checkout lunr.* *.json docs/index.html example/example_index.json
example: lunr.min.js
${NODE} example/index_builder.js
node_modules: package.json
${NPM} -s install
.PHONY: test clean docs reset example

65
book/node_modules/lunr/README.mdown generated vendored Normal file
View File

@@ -0,0 +1,65 @@
# Lunr.js
[![Join the chat at https://gitter.im/olivernn/lunr.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/olivernn/lunr.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/olivernn/lunr.js.png?branch=master)](https://travis-ci.org/olivernn/lunr.js)
A bit like Solr, but much smaller and not as bright.
## Example
A very simple search index can be created using the following:
```javascript
var idx = lunr(function () {
this.field('title', { boost: 10 })
this.field('body')
})
```
Adding documents to be indexed is as simple as:
```javascript
var doc = {
"title": "Twelfth-Night",
"body": "If music be the food of love, play on: Give me excess of it…",
"author": "William Shakespeare",
"id": 1
}
idx.add(doc)
```
Then searching is as simple:
```javascript
idx.search("love")
```
This returns a list of matching documents with a score of how closely they match the search query:
```javascript
[{
"ref": 1,
"score": 0.87533
}]
```
[API documentation](http://lunrjs.com/docs) is available, as well as a [full working example](http://lunrjs.com/example/).
## Description
Lunr.js is a small, full-text search library for use in the browser. It indexes JSON documents and provides a simple search interface for retrieving documents that best match text queries.
## Why
For web applications with all their data already sitting in the client, it makes sense to be able to search that data on the client too. It saves adding extra, compacted services on the server. A local search index will be quicker, there is no network overhead, and will remain available and useable even without a network connection.
## Installation
Simply include the lunr.js source file in the page that you want to use it. Lunr.js is supported in all modern browsers.
Browsers that do not support ES5 will require a JavaScript shim for Lunr to work. You can either use [Augment.js](https://github.com/olivernn/augment.js), [ES5-Shim](https://github.com/kriskowal/es5-shim) or any library that patches old browsers to provide an ES5 compatible JavaScript environment.
## Contributing
See the [`CONTRIBUTING.mdown` file](CONTRIBUTING.mdown).

1
book/node_modules/lunr/VERSION generated vendored Normal file
View File

@@ -0,0 +1 @@
0.5.12

11
book/node_modules/lunr/bower.json generated vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"name": "lunr.js",
"version": "0.5.12",
"main": "lunr.js",
"ignore": [
"tests/",
"perf/",
"build/",
"docs/"
]
}

11
book/node_modules/lunr/build/bower.json.template generated vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"name": "lunr.js",
"version": "@VERSION",
"main": "lunr.js",
"ignore": [
"tests/",
"perf/",
"build/",
"docs/"
]
}

9
book/node_modules/lunr/build/component.json.template generated vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"name": "lunr",
"repo": "olivernn/lunr.js",
"version": "@VERSION",
"description": "Simple full-text search in your browser.",
"license": "MIT",
"main": "lunr.js",
"scripts": ["lunr.js"]
}

24
book/node_modules/lunr/build/package.json.template generated vendored Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "lunr",
"description": "Simple full-text search in your browser.",
"version": "@VERSION",
"author": "Oliver Nightingale",
"keywords": ["search"],
"homepage": "http://lunrjs.com",
"bugs": "http://github.com/olivernn/lunr.js/issues",
"main": "lunr.js",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/olivernn/lunr.js.git"
},
"devDependencies": {
"dox": "0.4.4",
"dox-template": "0.1.1",
"phantomjs": "1.8.1-3",
"uglify-js": "2.4.13"
},
"scripts": {
"test": "make test"
}
}

79
book/node_modules/lunr/build/release.sh generated vendored Executable file
View File

@@ -0,0 +1,79 @@
#!/usr/bin/env bash
file_has_changed () {
if [ ! -f $1 ]; then
return 1
fi
for f in `git ls-files --modified`; do
[[ "$f" == "$1" ]] && return 0
done
return 1
}
version_is_unique () {
for v in `git tag -l`; do
[[ "$v" == "v$1" ]] && return 1
done
return 0
}
on_master_branch () {
[[ $(git symbolic-ref --short -q HEAD) == "master" ]] && return 0
return 1
}
version=$(cat VERSION)
previous_version=$(git describe --abbrev=0)
if ! on_master_branch; then
echo -e "\033[0;31mRefusing to release from non master branch.\033[0m"
exit 1
fi
if ! file_has_changed "VERSION"; then
echo -e "\033[0;31mRefusing to release because VERSION has not changed.\033[0m"
exit 1
fi
if ! file_has_changed "CHANGELOG.mdown"; then
echo -e "\033[0;31mRefusing to release because CHANGELOG.ms has not been updated.\033[0m"
exit 1
fi
if ! file_has_changed "package.json"; then
echo -e "\033[0;31mRefusing to release because package.json has not been updated.\033[0m"
exit 1
fi
if ! version_is_unique $version; then
echo -e "\033[0;31mRefusing to release because VERSION is not unique.\033[0m"
exit 1
fi
echo -e "\033[1mAbout to release v$version with the following changes:\033[0m"
git log --date=short --pretty=format:"%ad %h%x09%an%x09%s" $previous_version..HEAD
echo
echo -e "\033[1mThe following files will be part of the release commit:\033[0m"
git ls-files --modified
echo
read -e -p "Are you sure you want to release? " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo -e "\033[0;32mReleasing...\033[0m"
echo
git commit -a -m "Build version $version"
git tag -a v$version -m "Version $version"
git push origin master
git push --tags
npm publish
else
echo -e "\033[0;31mCancelling...\033[0m"
fi

29
book/node_modules/lunr/build/wrapper_end generated vendored Normal file
View File

@@ -0,0 +1,29 @@
/**
* export the module via AMD, CommonJS or as a browser global
* Export code from https://github.com/umdjs/umd/blob/master/returnExports.js
*/
;(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(factory)
} else if (typeof exports === 'object') {
/**
* Node. Does not work with strict CommonJS, but
* only CommonJS-like enviroments that support module.exports,
* like Node.
*/
module.exports = factory()
} else {
// Browser globals (root is window)
root.lunr = factory()
}
}(this, function () {
/**
* Just return a value to define the module export.
* This example returns an object, but the module
* can return a function as the exported value.
*/
return lunr
}))
})();

9
book/node_modules/lunr/build/wrapper_start generated vendored Normal file
View File

@@ -0,0 +1,9 @@
/**
* lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - @VERSION
* Copyright (C) @YEAR Oliver Nightingale
* MIT Licensed
* @license
*/
;(function(){

9
book/node_modules/lunr/component.json generated vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"name": "lunr",
"repo": "olivernn/lunr.js",
"version": "0.5.12",
"description": "Simple full-text search in your browser.",
"license": "MIT",
"main": "lunr.js",
"scripts": ["lunr.js"]
}

3383
book/node_modules/lunr/docs/index.html generated vendored Normal file

File diff suppressed because one or more lines are too long

89
book/node_modules/lunr/example/app.js generated vendored Normal file
View File

@@ -0,0 +1,89 @@
require([
'/example/jquery.js',
'/example/mustache.js',
'../lunr.js',
'text!templates/question_view.mustache',
'text!templates/question_list.mustache',
'text!example_data.json',
'text!example_index.json'
], function (_, Mustache, lunr, questionView, questionList, data, indexDump) {
var renderQuestionList = function (qs) {
$("#question-list-container")
.empty()
.append(Mustache.to_html(questionList, {questions: qs}))
}
var renderQuestionView = function (question) {
$("#question-view-container")
.empty()
.append(Mustache.to_html(questionView, question))
}
window.profile = function (term) {
console.profile('search')
idx.search(term)
console.profileEnd('search')
}
window.search = function (term) {
console.time('search')
idx.search(term)
console.timeEnd('search')
}
var indexDump = JSON.parse(indexDump)
console.time('load')
window.idx = lunr.Index.load(indexDump)
console.timeEnd('load')
var questions = JSON.parse(data).questions.map(function (raw) {
return {
id: raw.question_id,
title: raw.title,
body: raw.body,
tags: raw.tags.join(' ')
}
})
renderQuestionList(questions)
renderQuestionView(questions[0])
$('a.all').bind('click', function () {
renderQuestionList(questions)
$('input').val('')
})
var debounce = function (fn) {
var timeout
return function () {
var args = Array.prototype.slice.call(arguments),
ctx = this
clearTimeout(timeout)
timeout = setTimeout(function () {
fn.apply(ctx, args)
}, 100)
}
}
$('input').bind('keyup', debounce(function () {
if ($(this).val() < 2) return
var query = $(this).val()
var results = idx.search(query).map(function (result) {
return questions.filter(function (q) { return q.id === parseInt(result.ref, 10) })[0]
})
renderQuestionList(results)
}))
$("#question-list-container").delegate('li', 'click', function () {
var li = $(this)
var id = li.data('question-id')
renderQuestionView(questions.filter(function (question) {
return (question.id == id)
})[0])
})
})

3016
book/node_modules/lunr/example/example_data.json generated vendored Normal file

File diff suppressed because one or more lines are too long

1
book/node_modules/lunr/example/example_index.json generated vendored Normal file

File diff suppressed because one or more lines are too long

81
book/node_modules/lunr/example/index.html generated vendored Normal file
View File

@@ -0,0 +1,81 @@
<head>
<script data-main="/example/app.js" src="/example/require.js"></script>
<style type="text/css" media="screen">
body {
background-color: #081f28;
color: #708284;
font-family: 'Helvetica Neue';
font-size: 16px;
}
a {
color: #2076c7;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
input {
width: 200px;
font-size: 1.4em;
}
#wrap {
width: 960px;
margin-left: auto;
margin-right: auto;
}
#question-list-container {
float: left;
width: 30%;
}
#question-view-container {
float: right;
width: 65%;
}
.loading {
color: #D11c24;
font-size: 0.9em;
border: 1px solid #D11c24;
padding: 10px;
}
.controls {
padding-top: 30px;
padding-bottom: 10px;
border-top: 3px dashed #708284;
}
</style>
</head>
<body>
<div id="wrap">
<header>
<h1>Lunr.js Example</h1>
</header>
<article>
<p>This demo consists of 100 questions taken from stack overflow, they are listed on the left hand side. Clicking on the headings will display the full question on the right hand side of the page.</p>
<p>Each question contains a heading, a list of tags and the body of the question. All three fields are in the index and you can search using any words you want.</p>
</article>
<div class="controls">
<input type="search" placeholder="Search..."></input>
<a class="all" href="#">All</a>
</div>
<div class="questions">
<div id='question-list-container'></div>
<div id='question-view-container'></div>
</div>
</div>
</body>

34
book/node_modules/lunr/example/index_builder.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
var lunr = require('./../lunr.js'),
fs = require('fs')
var idx = lunr(function () {
this.ref('id')
this.field('title', { boost: 10 })
this.field('tags', { boost: 100 })
this.field('body')
})
fs.readFile('./example/example_data.json', function (err, data) {
if (err) throw err
var raw = JSON.parse(data)
var questions = raw.questions.map(function (q) {
return {
id: q.question_id,
title: q.title,
body: q.body,
tags: q.tags.join(' ')
}
})
questions.forEach(function (question) {
idx.add(question)
})
fs.writeFile('./example/example_index.json', JSON.stringify(idx), function (err) {
if (err) throw err
console.log('done')
})
})

4
book/node_modules/lunr/example/jquery.js generated vendored Normal file

File diff suppressed because one or more lines are too long

570
book/node_modules/lunr/example/mustache.js generated vendored Normal file
View File

@@ -0,0 +1,570 @@
/*!
* mustache.js - Logic-less {{mustache}} templates with JavaScript
* http://github.com/janl/mustache.js
*/
/*global define: false*/
(function (root, factory) {
if (typeof exports === "object" && exports) {
factory(exports); // CommonJS
} else {
var mustache = {};
factory(mustache);
if (typeof define === "function" && define.amd) {
define(mustache); // AMD
} else {
root.Mustache = mustache; // <script>
}
}
}(this, function (mustache) {
// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
// See https://github.com/janl/mustache.js/issues/189
var RegExp_test = RegExp.prototype.test;
function testRegExp(re, string) {
return RegExp_test.call(re, string);
}
var nonSpaceRe = /\S/;
function isWhitespace(string) {
return !testRegExp(nonSpaceRe, string);
}
var Object_toString = Object.prototype.toString;
var isArray = Array.isArray || function (object) {
return Object_toString.call(object) === '[object Array]';
};
function isFunction(object) {
return typeof object === 'function';
}
function escapeRegExp(string) {
return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
var entityMap = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': '&quot;',
"'": '&#39;',
"/": '&#x2F;'
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'\/]/g, function (s) {
return entityMap[s];
});
}
function escapeTags(tags) {
if (!isArray(tags) || tags.length !== 2) {
throw new Error('Invalid tags: ' + tags);
}
return [
new RegExp(escapeRegExp(tags[0]) + "\\s*"),
new RegExp("\\s*" + escapeRegExp(tags[1]))
];
}
var whiteRe = /\s*/;
var spaceRe = /\s+/;
var equalsRe = /\s*=/;
var curlyRe = /\s*\}/;
var tagRe = /#|\^|\/|>|\{|&|=|!/;
/**
* Breaks up the given `template` string into a tree of tokens. If the `tags`
* argument is given here it must be an array with two string values: the
* opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
* course, the default is to use mustaches (i.e. mustache.tags).
*
* A token is an array with at least 4 elements. The first element is the
* mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
* did not contain a symbol (i.e. {{myValue}}) this element is "name". For
* all text that appears outside a symbol this element is "text".
*
* The second element of a token is its "value". For mustache tags this is
* whatever else was inside the tag besides the opening symbol. For text tokens
* this is the text itself.
*
* The third and fourth elements of the token are the start and end indices,
* respectively, of the token in the original template.
*
* Tokens that are the root node of a subtree contain two more elements: 1) an
* array of tokens in the subtree and 2) the index in the original template at
* which the closing tag for that section begins.
*/
function parseTemplate(template, tags) {
tags = tags || mustache.tags;
template = template || '';
if (typeof tags === 'string') {
tags = tags.split(spaceRe);
}
var tagRes = escapeTags(tags);
var scanner = new Scanner(template);
var sections = []; // Stack to hold section tokens
var tokens = []; // Buffer to hold the tokens
var spaces = []; // Indices of whitespace tokens on the current line
var hasTag = false; // Is there a {{tag}} on the current line?
var nonSpace = false; // Is there a non-space char on the current line?
// Strips all whitespace tokens array for the current line
// if there was a {{#tag}} on it and otherwise only space.
function stripSpace() {
if (hasTag && !nonSpace) {
while (spaces.length) {
delete tokens[spaces.pop()];
}
} else {
spaces = [];
}
hasTag = false;
nonSpace = false;
}
var start, type, value, chr, token, openSection;
while (!scanner.eos()) {
start = scanner.pos;
// Match any text between tags.
value = scanner.scanUntil(tagRes[0]);
if (value) {
for (var i = 0, len = value.length; i < len; ++i) {
chr = value.charAt(i);
if (isWhitespace(chr)) {
spaces.push(tokens.length);
} else {
nonSpace = true;
}
tokens.push(['text', chr, start, start + 1]);
start += 1;
// Check for whitespace on the current line.
if (chr === '\n') {
stripSpace();
}
}
}
// Match the opening tag.
if (!scanner.scan(tagRes[0])) break;
hasTag = true;
// Get the tag type.
type = scanner.scan(tagRe) || 'name';
scanner.scan(whiteRe);
// Get the tag value.
if (type === '=') {
value = scanner.scanUntil(equalsRe);
scanner.scan(equalsRe);
scanner.scanUntil(tagRes[1]);
} else if (type === '{') {
value = scanner.scanUntil(new RegExp('\\s*' + escapeRegExp('}' + tags[1])));
scanner.scan(curlyRe);
scanner.scanUntil(tagRes[1]);
type = '&';
} else {
value = scanner.scanUntil(tagRes[1]);
}
// Match the closing tag.
if (!scanner.scan(tagRes[1])) {
throw new Error('Unclosed tag at ' + scanner.pos);
}
token = [ type, value, start, scanner.pos ];
tokens.push(token);
if (type === '#' || type === '^') {
sections.push(token);
} else if (type === '/') {
// Check section nesting.
openSection = sections.pop();
if (!openSection) {
throw new Error('Unopened section "' + value + '" at ' + start);
}
if (openSection[1] !== value) {
throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
}
} else if (type === 'name' || type === '{' || type === '&') {
nonSpace = true;
} else if (type === '=') {
// Set the tags for the next time around.
tagRes = escapeTags(tags = value.split(spaceRe));
}
}
// Make sure there are no open sections when we're done.
openSection = sections.pop();
if (openSection) {
throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
}
return nestTokens(squashTokens(tokens));
}
/**
* Combines the values of consecutive text tokens in the given `tokens` array
* to a single token.
*/
function squashTokens(tokens) {
var squashedTokens = [];
var token, lastToken;
for (var i = 0, len = tokens.length; i < len; ++i) {
token = tokens[i];
if (token) {
if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
lastToken[1] += token[1];
lastToken[3] = token[3];
} else {
squashedTokens.push(token);
lastToken = token;
}
}
}
return squashedTokens;
}
/**
* Forms the given array of `tokens` into a nested tree structure where
* tokens that represent a section have two additional items: 1) an array of
* all tokens that appear in that section and 2) the index in the original
* template that represents the end of that section.
*/
function nestTokens(tokens) {
var nestedTokens = [];
var collector = nestedTokens;
var sections = [];
var token, section;
for (var i = 0, len = tokens.length; i < len; ++i) {
token = tokens[i];
switch (token[0]) {
case '#':
case '^':
collector.push(token);
sections.push(token);
collector = token[4] = [];
break;
case '/':
section = sections.pop();
section[5] = token[2];
collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
break;
default:
collector.push(token);
}
}
return nestedTokens;
}
/**
* A simple string scanner that is used by the template parser to find
* tokens in template strings.
*/
function Scanner(string) {
this.string = string;
this.tail = string;
this.pos = 0;
}
/**
* Returns `true` if the tail is empty (end of string).
*/
Scanner.prototype.eos = function () {
return this.tail === "";
};
/**
* Tries to match the given regular expression at the current position.
* Returns the matched text if it can match, the empty string otherwise.
*/
Scanner.prototype.scan = function (re) {
var match = this.tail.match(re);
if (match && match.index === 0) {
var string = match[0];
this.tail = this.tail.substring(string.length);
this.pos += string.length;
return string;
}
return "";
};
/**
* Skips all text until the given regular expression can be matched. Returns
* the skipped string, which is the entire tail if no match can be made.
*/
Scanner.prototype.scanUntil = function (re) {
var index = this.tail.search(re), match;
switch (index) {
case -1:
match = this.tail;
this.tail = "";
break;
case 0:
match = "";
break;
default:
match = this.tail.substring(0, index);
this.tail = this.tail.substring(index);
}
this.pos += match.length;
return match;
};
/**
* Represents a rendering context by wrapping a view object and
* maintaining a reference to the parent context.
*/
function Context(view, parentContext) {
this.view = view == null ? {} : view;
this.cache = { '.': this.view };
this.parent = parentContext;
}
/**
* Creates a new context using the given view with this context
* as the parent.
*/
Context.prototype.push = function (view) {
return new Context(view, this);
};
/**
* Returns the value of the given name in this context, traversing
* up the context hierarchy if the value is absent in this context's view.
*/
Context.prototype.lookup = function (name) {
var value;
if (name in this.cache) {
value = this.cache[name];
} else {
var context = this;
while (context) {
if (name.indexOf('.') > 0) {
value = context.view;
var names = name.split('.'), i = 0;
while (value != null && i < names.length) {
value = value[names[i++]];
}
} else {
value = context.view[name];
}
if (value != null) break;
context = context.parent;
}
this.cache[name] = value;
}
if (isFunction(value)) {
value = value.call(this.view);
}
return value;
};
/**
* A Writer knows how to take a stream of tokens and render them to a
* string, given a context. It also maintains a cache of templates to
* avoid the need to parse the same template twice.
*/
function Writer() {
this.cache = {};
}
/**
* Clears all cached templates in this writer.
*/
Writer.prototype.clearCache = function () {
this.cache = {};
};
/**
* Parses and caches the given `template` and returns the array of tokens
* that is generated from the parse.
*/
Writer.prototype.parse = function (template, tags) {
var cache = this.cache;
var tokens = cache[template];
if (tokens == null) {
tokens = cache[template] = parseTemplate(template, tags);
}
return tokens;
};
/**
* High-level method that is used to render the given `template` with
* the given `view`.
*
* The optional `partials` argument may be an object that contains the
* names and templates of partials that are used in the template. It may
* also be a function that is used to load partial templates on the fly
* that takes a single argument: the name of the partial.
*/
Writer.prototype.render = function (template, view, partials) {
var tokens = this.parse(template);
var context = (view instanceof Context) ? view : new Context(view);
return this.renderTokens(tokens, context, partials, template);
};
/**
* Low-level method that renders the given array of `tokens` using
* the given `context` and `partials`.
*
* Note: The `originalTemplate` is only ever used to extract the portion
* of the original template that was contained in a higher-order section.
* If the template doesn't use higher-order sections, this argument may
* be omitted.
*/
Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) {
var buffer = '';
// This function is used to render an arbitrary template
// in the current context by higher-order sections.
var self = this;
function subRender(template) {
return self.render(template, context, partials);
}
var token, value;
for (var i = 0, len = tokens.length; i < len; ++i) {
token = tokens[i];
switch (token[0]) {
case '#':
value = context.lookup(token[1]);
if (!value) continue;
if (isArray(value)) {
for (var j = 0, jlen = value.length; j < jlen; ++j) {
buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
}
} else if (typeof value === 'object' || typeof value === 'string') {
buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
} else if (isFunction(value)) {
if (typeof originalTemplate !== 'string') {
throw new Error('Cannot use higher-order sections without the original template');
}
// Extract the portion of the original template that the section contains.
value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
if (value != null) buffer += value;
} else {
buffer += this.renderTokens(token[4], context, partials, originalTemplate);
}
break;
case '^':
value = context.lookup(token[1]);
// Use JavaScript's definition of falsy. Include empty arrays.
// See https://github.com/janl/mustache.js/issues/186
if (!value || (isArray(value) && value.length === 0)) {
buffer += this.renderTokens(token[4], context, partials, originalTemplate);
}
break;
case '>':
if (!partials) continue;
value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
if (value != null) buffer += this.renderTokens(this.parse(value), context, partials, value);
break;
case '&':
value = context.lookup(token[1]);
if (value != null) buffer += value;
break;
case 'name':
value = context.lookup(token[1]);
if (value != null) buffer += mustache.escape(value);
break;
case 'text':
buffer += token[1];
break;
}
}
return buffer;
};
mustache.name = "mustache.js";
mustache.version = "0.8.1";
mustache.tags = [ "{{", "}}" ];
// All high-level mustache.* functions use this writer.
var defaultWriter = new Writer();
/**
* Clears all cached templates in the default writer.
*/
mustache.clearCache = function () {
return defaultWriter.clearCache();
};
/**
* Parses and caches the given template in the default writer and returns the
* array of tokens it contains. Doing this ahead of time avoids the need to
* parse templates on the fly as they are rendered.
*/
mustache.parse = function (template, tags) {
return defaultWriter.parse(template, tags);
};
/**
* Renders the `template` with the given `view` and `partials` using the
* default writer.
*/
mustache.render = function (template, view, partials) {
return defaultWriter.render(template, view, partials);
};
// This is here for backwards compatibility with 0.4.x.
mustache.to_html = function (template, view, partials, send) {
var result = mustache.render(template, view, partials);
if (isFunction(send)) {
send(result);
} else {
return result;
}
};
// Export the escaping function so that the user may override it.
// See https://github.com/janl/mustache.js/issues/244
mustache.escape = escapeHtml;
// Export these mainly for testing, but also for advanced usage.
mustache.Scanner = Scanner;
mustache.Context = Context;
mustache.Writer = Writer;
}));

36
book/node_modules/lunr/example/require.js generated vendored Normal file
View File

@@ -0,0 +1,36 @@
/*
RequireJS 2.1.11 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
Available via the MIT or new BSD license.
see: http://github.com/jrburke/requirejs for details
*/
var requirejs,require,define;
(function(ca){function G(b){return"[object Function]"===M.call(b)}function H(b){return"[object Array]"===M.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function U(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function s(b,c){return ga.call(b,c)}function j(b,c){return s(b,c)&&b[c]}function B(b,c){for(var d in b)if(s(b,d)&&c(b[d],d))break}function V(b,c,d,g){c&&B(c,function(c,h){if(d||!s(b,h))g&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
RegExp)?(b[h]||(b[h]={}),V(b[h],c,d,g)):b[h]=c});return b}function t(b,c){return function(){return c.apply(b,arguments)}}function da(b){throw b;}function ea(b){if(!b)return b;var c=ca;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,g){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=g;d&&(c.originalError=d);return c}function ha(b){function c(a,e,b){var f,n,c,d,g,h,i,I=e&&e.split("/");n=I;var m=l.map,k=m&&m["*"];if(a&&"."===a.charAt(0))if(e){n=
I.slice(0,I.length-1);a=a.split("/");e=a.length-1;l.nodeIdCompat&&R.test(a[e])&&(a[e]=a[e].replace(R,""));n=a=n.concat(a);d=n.length;for(e=0;e<d;e++)if(c=n[e],"."===c)n.splice(e,1),e-=1;else if(".."===c)if(1===e&&(".."===n[2]||".."===n[0]))break;else 0<e&&(n.splice(e-1,2),e-=2);a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if(b&&m&&(I||k)){n=a.split("/");e=n.length;a:for(;0<e;e-=1){d=n.slice(0,e).join("/");if(I)for(c=I.length;0<c;c-=1)if(b=j(m,I.slice(0,c).join("/")))if(b=j(b,d)){f=b;
g=e;break a}!h&&(k&&j(k,d))&&(h=j(k,d),i=e)}!f&&h&&(f=h,g=i);f&&(n.splice(0,g,f),a=n.join("/"))}return(f=j(l.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(e){if(e.getAttribute("data-requiremodule")===a&&e.getAttribute("data-requirecontext")===i.contextName)return e.parentNode.removeChild(e),!0})}function g(a){var e=j(l.paths,a);if(e&&H(e)&&1<e.length)return e.shift(),i.require.undef(a),i.require([a]),!0}function u(a){var e,b=a?a.indexOf("!"):-1;-1<b&&(e=a.substring(0,
b),a=a.substring(b+1,a.length));return[e,a]}function m(a,e,b,f){var n,d,g=null,h=e?e.name:null,l=a,m=!0,k="";a||(m=!1,a="_@r"+(M+=1));a=u(a);g=a[0];a=a[1];g&&(g=c(g,h,f),d=j(p,g));a&&(g?k=d&&d.normalize?d.normalize(a,function(a){return c(a,h,f)}):c(a,h,f):(k=c(a,h,f),a=u(k),g=a[0],k=a[1],b=!0,n=i.nameToUrl(k)));b=g&&!d&&!b?"_unnormalized"+(Q+=1):"";return{prefix:g,name:k,parentMap:e,unnormalized:!!b,url:n,originalName:l,isDefine:m,id:(g?g+"!"+k:k)+b}}function q(a){var e=a.id,b=j(k,e);b||(b=k[e]=new i.Module(a));
return b}function r(a,e,b){var f=a.id,n=j(k,f);if(s(p,f)&&(!n||n.defineEmitComplete))"defined"===e&&b(p[f]);else if(n=q(a),n.error&&"error"===e)b(n.error);else n.on(e,b)}function w(a,e){var b=a.requireModules,f=!1;if(e)e(a);else if(v(b,function(e){if(e=j(k,e))e.error=a,e.events.error&&(f=!0,e.emit("error",a))}),!f)h.onError(a)}function x(){S.length&&(ia.apply(A,[A.length,0].concat(S)),S=[])}function y(a){delete k[a];delete W[a]}function F(a,e,b){var f=a.map.id;a.error?a.emit("error",a.error):(e[f]=
!0,v(a.depMaps,function(f,c){var d=f.id,g=j(k,d);g&&(!a.depMatched[c]&&!b[d])&&(j(e,d)?(a.defineDep(c,p[d]),a.check()):F(g,e,b))}),b[f]=!0)}function D(){var a,e,b=(a=1E3*l.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],c=[],h=!1,k=!0;if(!X){X=!0;B(W,function(a){var i=a.map,m=i.id;if(a.enabled&&(i.isDefine||c.push(a),!a.error))if(!a.inited&&b)g(m)?h=e=!0:(f.push(m),d(m));else if(!a.inited&&(a.fetched&&i.isDefine)&&(h=!0,!i.prefix))return k=!1});if(b&&f.length)return a=C("timeout","Load timeout for modules: "+
f,null,f),a.contextName=i.contextName,w(a);k&&v(c,function(a){F(a,{},{})});if((!b||e)&&h)if((z||fa)&&!Y)Y=setTimeout(function(){Y=0;D()},50);X=!1}}function E(a){s(p,a[0])||q(m(a[0],null,!0)).init(a[1],a[2])}function K(a){var a=a.currentTarget||a.srcElement,e=i.onScriptLoad;a.detachEvent&&!Z?a.detachEvent("onreadystatechange",e):a.removeEventListener("load",e,!1);e=i.onScriptError;(!a.detachEvent||Z)&&a.removeEventListener("error",e,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function L(){var a;
for(x();A.length;){a=A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var X,$,i,N,Y,l={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},k={},W={},aa={},A=[],p={},T={},ba={},M=1,Q=1;N={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?p[a.map.id]=a.exports:a.exports=p[a.map.id]={}},module:function(a){return a.module?
a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){return j(l.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};$=function(a){this.events=j(aa,a.id)||{};this.map=a;this.shim=j(l.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};$.prototype={init:function(a,e,b,f){f=f||{};if(!this.inited){this.factory=e;if(b)this.on("error",b);else this.events.error&&(b=t(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=
b;this.inited=!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,e){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=e)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],t(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
this.map.url;T[a]||(T[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,e,b=this.map.id;e=this.depExports;var f=this.exports,c=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(c)){if(this.events.error&&this.map.isDefine||h.onError!==da)try{f=i.execCb(b,c,e,f)}catch(d){a=d}else f=i.execCb(b,c,e,f);this.map.isDefine&&void 0===f&&((e=this.module)?f=e.exports:this.usingExports&&
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=c;this.exports=f;if(this.map.isDefine&&!this.ignore&&(p[b]=f,h.onResourceLoad))h.onResourceLoad(i,this.map,this.depMaps);y(b);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
this.map,b=a.id,d=m(a.prefix);this.depMaps.push(d);r(d,"defined",t(this,function(f){var d,g;g=j(ba,this.map.id);var J=this.map.name,u=this.map.parentMap?this.map.parentMap.name:null,p=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(J=f.normalize(J,function(a){return c(a,u,!0)})||""),f=m(a.prefix+"!"+J,this.map.parentMap),r(f,"defined",t(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),g=j(k,f.id)){this.depMaps.push(f);
if(this.events.error)g.on("error",t(this,function(a){this.emit("error",a)}));g.enable()}}else g?(this.map.url=i.nameToUrl(g),this.load()):(d=t(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),d.error=t(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(k,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),d.fromText=t(this,function(f,c){var g=a.name,J=m(g),k=O;c&&(f=c);k&&(O=!1);q(J);s(l.config,b)&&(l.config[g]=l.config[b]);try{h.exec(f)}catch(j){return w(C("fromtexteval",
"fromText eval for "+b+" failed: "+j,j,[b]))}k&&(O=!0);this.depMaps.push(J);i.completeLoad(g);p([g],d)}),f.load(a.name,p,d,l))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){W[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,t(this,function(a,b){var c,f;if("string"===typeof a){a=m(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=j(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;r(a,"defined",t(this,function(a){this.defineDep(b,
a);this.check()}));this.errback&&r(a,"error",t(this,this.errback))}c=a.id;f=k[c];!s(N,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,t(this,function(a){var b=j(k,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:l,contextName:b,registry:k,defined:p,urlFetched:T,defQueue:A,Module:$,makeModuleMap:m,
nextTick:h.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=l.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(l[b]||(l[b]={}),V(l[b],a,!0,!0)):l[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(ba[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),l.shim=b);a.packages&&v(a.packages,function(a){var b,
a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(l.paths[b]=a.location);l.pkgs[b]=a.name+"/"+(a.main||"main").replace(ja,"").replace(R,"")});B(k,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=m(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ca,arguments));return b||a.exports&&ea(a.exports)}},makeRequire:function(a,e){function g(f,c,d){var j,l;e.enableBuildCallback&&(c&&G(c))&&(c.__requireJsBuild=
!0);if("string"===typeof f){if(G(c))return w(C("requireargs","Invalid require call"),d);if(a&&s(N,f))return N[f](k[a.id]);if(h.get)return h.get(i,f,a,g);j=m(f,a,!1,!0);j=j.id;return!s(p,j)?w(C("notloaded",'Module name "'+j+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):p[j]}L();i.nextTick(function(){L();l=q(m(null,a));l.skipMap=e.skipMap;l.init(f,c,d,{enabled:!0});D()});return g}e=e||{};V(g,{isBrowser:z,toUrl:function(b){var e,d=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==
d&&(!("."===g||".."===g)||1<d))e=b.substring(d,b.length),b=b.substring(0,d);return i.nameToUrl(c(b,a&&a.id,!0),e,!0)},defined:function(b){return s(p,m(b,a,!1,!0).id)},specified:function(b){b=m(b,a,!1,!0).id;return s(p,b)||s(k,b)}});a||(g.undef=function(b){x();var c=m(b,a,!0),e=j(k,b);d(b);delete p[b];delete T[c.url];delete aa[b];U(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&(aa[b]=e.events),y(b))});return g},enable:function(a){j(k,a.id)&&q(a).enable()},completeLoad:function(a){var b,
c,f=j(l.shim,a)||{},d=f.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=j(k,a);if(!b&&!s(p,a)&&c&&!c.inited){if(l.enforceDefine&&(!d||!ea(d)))return g(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,f.deps||[],f.exportsFn])}D()},nameToUrl:function(a,b,c){var f,d,g;(f=j(l.pkgs,a))&&(a=f);if(f=j(ba,a))return i.nameToUrl(f,b,c);if(h.jsExtRegExp.test(a))f=a+(b||"");else{f=l.paths;a=a.split("/");for(d=a.length;0<d;d-=1)if(g=a.slice(0,
d).join("/"),g=j(f,g)){H(g)&&(g=g[0]);a.splice(0,d,g);break}f=a.join("/");f+=b||(/^data\:|\?/.test(f)||c?"":".js");f=("/"===f.charAt(0)||f.match(/^[\w\+\.\-]+:/)?"":l.baseUrl)+f}return l.urlArgs?f+((-1===f.indexOf("?")?"?":"&")+l.urlArgs):f},load:function(a,b){h.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ka.test((a.currentTarget||a.srcElement).readyState))P=null,a=K(a),i.completeLoad(a.id)},onScriptError:function(a){var b=K(a);if(!g(b.id))return w(C("scripterror",
"Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var h,x,y,D,K,E,P,L,q,Q,la=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ma=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,R=/\.js$/,ja=/^\.\//;x=Object.prototype;var M=x.toString,ga=x.hasOwnProperty,ia=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),fa=!z&&"undefined"!==typeof importScripts,ka=z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,
Z="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},r={},S=[],O=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;r=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(r=require,require=void 0);h=requirejs=function(b,c,d,g){var u,m="_";!H(b)&&"string"!==typeof b&&(u=b,H(c)?(b=c,c=d,d=g):b=[]);u&&u.context&&(m=u.context);(g=j(F,m))||(g=F[m]=h.s.newContext(m));u&&g.configure(u);return g.require(b,c,d)};h.config=function(b){return h(b)};
h.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=h);h.version="2.1.11";h.jsExtRegExp=/^\/|:|\?|\.js$/;h.isBrowser=z;x=h.s={contexts:F,newContext:ha};h({});v(["toUrl","undef","defined","specified"],function(b){h[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=x.head=D.parentNode;h.onError=da;h.createNode=function(b){var c=
b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};h.load=function(b,c,d){var g=b&&b.config||{};if(z)return g=h.createNode(g,c,d),g.setAttribute("data-requirecontext",b.contextName),g.setAttribute("data-requiremodule",c),g.attachEvent&&!(g.attachEvent.toString&&0>g.attachEvent.toString().indexOf("[native code"))&&!Z?(O=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)):
(g.addEventListener("load",b.onScriptLoad,!1),g.addEventListener("error",b.onScriptError,!1)),g.src=d,L=g,D?y.insertBefore(g,D):y.appendChild(g),L=null,g;if(fa)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};z&&!r.skipDataMain&&U(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(K=b.getAttribute("data-main"))return q=K,r.baseUrl||(E=q.split("/"),q=E.pop(),Q=E.length?E.join("/")+"/":"./",r.baseUrl=
Q),q=q.replace(R,""),h.jsExtRegExp.test(q)&&(q=K),r.deps=r.deps?r.deps.concat(q):[q],!0});define=function(b,c,d){var g,h;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(O){if(!(g=L))P&&"interactive"===P.readyState||U(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return P=b}),g=P;g&&(b||
(b=g.getAttribute("data-requiremodule")),h=F[g.getAttribute("data-requirecontext")])}(h?h.defQueue:S).push([b,c,d])};define.amd={jQuery:!0};h.exec=function(b){return eval(b)};h(r)}})(this);

View File

@@ -0,0 +1,10 @@
<div>
<ul>
{{#questions}}
<li data-question-id="{{id}}">
<h2><a href="#">{{title}}</a></h2>
<p>{{tags}}</p>
</li>
{{/questions}}
</ul>
</div>

View File

@@ -0,0 +1,5 @@
<div>
<h1>{{title}}</h1>
<p>{{tags}}</p>
<div>{{{body}}}</div>
</div>

386
book/node_modules/lunr/example/text.js generated vendored Normal file
View File

@@ -0,0 +1,386 @@
/**
* @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/requirejs/text for details
*/
/*jslint regexp: true */
/*global require, XMLHttpRequest, ActiveXObject,
define, window, process, Packages,
java, location, Components, FileUtils */
define(['module'], function (module) {
'use strict';
var text, fs, Cc, Ci, xpcIsWindows,
progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,
hasLocation = typeof location !== 'undefined' && location.href,
defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
defaultHostName = hasLocation && location.hostname,
defaultPort = hasLocation && (location.port || undefined),
buildMap = {},
masterConfig = (module.config && module.config()) || {};
text = {
version: '2.0.10',
strip: function (content) {
//Strips <?xml ...?> declarations so that external SVG and XML
//documents can be added to a document without worry. Also, if the string
//is an HTML document, only the part inside the body tag is returned.
if (content) {
content = content.replace(xmlRegExp, "");
var matches = content.match(bodyRegExp);
if (matches) {
content = matches[1];
}
} else {
content = "";
}
return content;
},
jsEscape: function (content) {
return content.replace(/(['\\])/g, '\\$1')
.replace(/[\f]/g, "\\f")
.replace(/[\b]/g, "\\b")
.replace(/[\n]/g, "\\n")
.replace(/[\t]/g, "\\t")
.replace(/[\r]/g, "\\r")
.replace(/[\u2028]/g, "\\u2028")
.replace(/[\u2029]/g, "\\u2029");
},
createXhr: masterConfig.createXhr || function () {
//Would love to dump the ActiveX crap in here. Need IE 6 to die first.
var xhr, i, progId;
if (typeof XMLHttpRequest !== "undefined") {
return new XMLHttpRequest();
} else if (typeof ActiveXObject !== "undefined") {
for (i = 0; i < 3; i += 1) {
progId = progIds[i];
try {
xhr = new ActiveXObject(progId);
} catch (e) {}
if (xhr) {
progIds = [progId]; // so faster next time
break;
}
}
}
return xhr;
},
/**
* Parses a resource name into its component parts. Resource names
* look like: module/name.ext!strip, where the !strip part is
* optional.
* @param {String} name the resource name
* @returns {Object} with properties "moduleName", "ext" and "strip"
* where strip is a boolean.
*/
parseName: function (name) {
var modName, ext, temp,
strip = false,
index = name.indexOf("."),
isRelative = name.indexOf('./') === 0 ||
name.indexOf('../') === 0;
if (index !== -1 && (!isRelative || index > 1)) {
modName = name.substring(0, index);
ext = name.substring(index + 1, name.length);
} else {
modName = name;
}
temp = ext || modName;
index = temp.indexOf("!");
if (index !== -1) {
//Pull off the strip arg.
strip = temp.substring(index + 1) === "strip";
temp = temp.substring(0, index);
if (ext) {
ext = temp;
} else {
modName = temp;
}
}
return {
moduleName: modName,
ext: ext,
strip: strip
};
},
xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,
/**
* Is an URL on another domain. Only works for browser use, returns
* false in non-browser environments. Only used to know if an
* optimized .js version of a text resource should be loaded
* instead.
* @param {String} url
* @returns Boolean
*/
useXhr: function (url, protocol, hostname, port) {
var uProtocol, uHostName, uPort,
match = text.xdRegExp.exec(url);
if (!match) {
return true;
}
uProtocol = match[2];
uHostName = match[3];
uHostName = uHostName.split(':');
uPort = uHostName[1];
uHostName = uHostName[0];
return (!uProtocol || uProtocol === protocol) &&
(!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&
((!uPort && !uHostName) || uPort === port);
},
finishLoad: function (name, strip, content, onLoad) {
content = strip ? text.strip(content) : content;
if (masterConfig.isBuild) {
buildMap[name] = content;
}
onLoad(content);
},
load: function (name, req, onLoad, config) {
//Name has format: some.module.filext!strip
//The strip part is optional.
//if strip is present, then that means only get the string contents
//inside a body tag in an HTML string. For XML/SVG content it means
//removing the <?xml ...?> declarations so the content can be inserted
//into the current doc without problems.
// Do not bother with the work if a build and text will
// not be inlined.
if (config.isBuild && !config.inlineText) {
onLoad();
return;
}
masterConfig.isBuild = config.isBuild;
var parsed = text.parseName(name),
nonStripName = parsed.moduleName +
(parsed.ext ? '.' + parsed.ext : ''),
url = req.toUrl(nonStripName),
useXhr = (masterConfig.useXhr) ||
text.useXhr;
// Do not load if it is an empty: url
if (url.indexOf('empty:') === 0) {
onLoad();
return;
}
//Load the text. Use XHR if possible and in a browser.
if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
text.get(url, function (content) {
text.finishLoad(name, parsed.strip, content, onLoad);
}, function (err) {
if (onLoad.error) {
onLoad.error(err);
}
});
} else {
//Need to fetch the resource across domains. Assume
//the resource has been optimized into a JS module. Fetch
//by the module name + extension, but do not include the
//!strip part to avoid file system issues.
req([nonStripName], function (content) {
text.finishLoad(parsed.moduleName + '.' + parsed.ext,
parsed.strip, content, onLoad);
});
}
},
write: function (pluginName, moduleName, write, config) {
if (buildMap.hasOwnProperty(moduleName)) {
var content = text.jsEscape(buildMap[moduleName]);
write.asModule(pluginName + "!" + moduleName,
"define(function () { return '" +
content +
"';});\n");
}
},
writeFile: function (pluginName, moduleName, req, write, config) {
var parsed = text.parseName(moduleName),
extPart = parsed.ext ? '.' + parsed.ext : '',
nonStripName = parsed.moduleName + extPart,
//Use a '.js' file name so that it indicates it is a
//script that can be loaded across domains.
fileName = req.toUrl(parsed.moduleName + extPart) + '.js';
//Leverage own load() method to load plugin value, but only
//write out values that do not have the strip argument,
//to avoid any potential issues with ! in file names.
text.load(nonStripName, req, function (value) {
//Use own write() method to construct full module value.
//But need to create shell that translates writeFile's
//write() to the right interface.
var textWrite = function (contents) {
return write(fileName, contents);
};
textWrite.asModule = function (moduleName, contents) {
return write.asModule(moduleName, fileName, contents);
};
text.write(pluginName, nonStripName, textWrite, config);
}, config);
}
};
if (masterConfig.env === 'node' || (!masterConfig.env &&
typeof process !== "undefined" &&
process.versions &&
!!process.versions.node &&
!process.versions['node-webkit'])) {
//Using special require.nodeRequire, something added by r.js.
fs = require.nodeRequire('fs');
text.get = function (url, callback, errback) {
try {
var file = fs.readFileSync(url, 'utf8');
//Remove BOM (Byte Mark Order) from utf8 files if it is there.
if (file.indexOf('\uFEFF') === 0) {
file = file.substring(1);
}
callback(file);
} catch (e) {
errback(e);
}
};
} else if (masterConfig.env === 'xhr' || (!masterConfig.env &&
text.createXhr())) {
text.get = function (url, callback, errback, headers) {
var xhr = text.createXhr(), header;
xhr.open('GET', url, true);
//Allow plugins direct access to xhr headers
if (headers) {
for (header in headers) {
if (headers.hasOwnProperty(header)) {
xhr.setRequestHeader(header.toLowerCase(), headers[header]);
}
}
}
//Allow overrides specified in config
if (masterConfig.onXhr) {
masterConfig.onXhr(xhr, url);
}
xhr.onreadystatechange = function (evt) {
var status, err;
//Do not explicitly handle errors, those should be
//visible via console output in the browser.
if (xhr.readyState === 4) {
status = xhr.status;
if (status > 399 && status < 600) {
//An http 4xx or 5xx error. Signal an error.
err = new Error(url + ' HTTP status: ' + status);
err.xhr = xhr;
errback(err);
} else {
callback(xhr.responseText);
}
if (masterConfig.onXhrComplete) {
masterConfig.onXhrComplete(xhr, url);
}
}
};
xhr.send(null);
};
} else if (masterConfig.env === 'rhino' || (!masterConfig.env &&
typeof Packages !== 'undefined' && typeof java !== 'undefined')) {
//Why Java, why is this so awkward?
text.get = function (url, callback) {
var stringBuffer, line,
encoding = "utf-8",
file = new java.io.File(url),
lineSeparator = java.lang.System.getProperty("line.separator"),
input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
content = '';
try {
stringBuffer = new java.lang.StringBuffer();
line = input.readLine();
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
// http://www.unicode.org/faq/utf_bom.html
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
if (line && line.length() && line.charAt(0) === 0xfeff) {
// Eat the BOM, since we've already found the encoding on this file,
// and we plan to concatenating this buffer with others; the BOM should
// only appear at the top of a file.
line = line.substring(1);
}
if (line !== null) {
stringBuffer.append(line);
}
while ((line = input.readLine()) !== null) {
stringBuffer.append(lineSeparator);
stringBuffer.append(line);
}
//Make sure we return a JavaScript string and not a Java string.
content = String(stringBuffer.toString()); //String
} finally {
input.close();
}
callback(content);
};
} else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&
typeof Components !== 'undefined' && Components.classes &&
Components.interfaces)) {
//Avert your gaze!
Cc = Components.classes,
Ci = Components.interfaces;
Components.utils['import']('resource://gre/modules/FileUtils.jsm');
xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);
text.get = function (url, callback) {
var inStream, convertStream, fileObj,
readData = {};
if (xpcIsWindows) {
url = url.replace(/\//g, '\\');
}
fileObj = new FileUtils.File(url);
//XPCOM, you so crazy
try {
inStream = Cc['@mozilla.org/network/file-input-stream;1']
.createInstance(Ci.nsIFileInputStream);
inStream.init(fileObj, 1, 0, false);
convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']
.createInstance(Ci.nsIConverterInputStream);
convertStream.init(inStream, "utf-8", inStream.available(),
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
convertStream.readString(inStream.available(), readData);
convertStream.close();
inStream.close();
callback(readData.value);
} catch (e) {
throw new Error((fileObj && fileObj.path || '') + ': ' + e);
}
};
}
return text;
});

305
book/node_modules/lunr/index.html generated vendored Normal file
View File

@@ -0,0 +1,305 @@
<!DOCTYPE html>
<html>
<head>
<title>lunr.js - A bit like Solr, but much smaller and not as bright</title>
<link rel="stylesheet" href="/styles.css" type="text/css">
<script type="text/javascript" src="/lunr.min.js">
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-25695442-4']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div class='wrap'>
<header>
<h1>lunr<span>.js</span></h1>
<h2>Simple full-text search in your browser</h2>
</header>
<nav>
<ul>
<li><a href="/docs">Docs</a></li>
<li><a href="/example">Examples</a></li>
<li><a href="http://github.com/olivernn/lunr.js">Code</a></li>
</ul>
</nav>
<section class="columns">
<article>
<header>
<h3>Get Started</h3>
</header>
<p>Open your browser's <a id="developer-tools" target="_blank">developer tools</a> on this page to follow along.</p>
<p>Set up an index for your notes:</p>
<pre>
var index = lunr(function () {
this.field('title', {boost: 10})
this.field('body')
this.ref('id')
})</pre>
<p>Add documents to your index</p>
<pre>
index.add({
id: 1,
title: 'Foo',
body: 'Foo foo foo!'
})
index.add({
id: 2,
title: 'Bar',
body: 'Bar bar bar!'
})</pre>
<p>Search your documents</p>
<pre>
index.search('foo')</pre>
</article>
<article>
<header>
<h3>About</h3>
</header>
<p>lunr.js is a simple full text search engine for your client side applications. It is designed to be small, yet full featured, enabling you to provide a great search experience without the need for external, server side, search services.</p>
<p>lunr.js has no external dependencies, although it does require a modern browser with ES5 support. In older browsers you can use an ES5 shim, such as <a href="https://olivernn.github.io/augment.js/">augment.js</a>, to provide any missing JavaScript functionality.</p>
</article>
<article class="download">
<header>
<h3>Download</h3>
</header>
<ul>
<li><a href="https://raw.github.com/olivernn/lunr.js/master/lunr.js">lunr.js</a> - uncompressed</li>
<li><a href="https://raw.github.com/olivernn/lunr.js/master/lunr.min.js">lunr.min.js</a> - minified</li>
</ul>
</article>
</section>
<section>
<article>
<header>
<h3>Pipeline</h3>
</header>
<p>Every document and search query that enters lunr is passed through a text <a href="/docs#Pipeline">processing pipeline</a>. The pipeline is simply a stack of functions that perform some processing on the text. Pipeline functions act on the text one token at a time, and what they return is passed to the next function in the pipeline.</p>
<p>By default lunr adds a <a href="/docs#stopWordFilter">stop word filter</a> and <a href="/docs#stemmer">stemmer</a> to the pipeline. You can also add your own processors or remove the default ones depending on your requirements. The stemmer currently used is an English language stemmer, which could be replaced with a non-English language stemmer if required, or a <a href="http://en.wikipedia.org/wiki/Metaphone">Metaphoning</a> processor could be added.</p>
<pre>
var index = lunr(function () {
this.pipeline.add(function (token, tokenIndex, tokens) {
// text processing in here
})
this.pipeline.after(lunr.stopWordFilter, function (token, tokenIndex, tokens) {
// text processing in here
})
})
</pre>
<p>Functions in the pipeline are called with three arguments: the current token being processed; the index of that token in the array of tokens, and the whole list of tokens part of the document being processed. This enables simple unigram processing of tokens as well as more sophisticated n-gram processing.</p>
<p>The function should return the processed version of the text, which will in turn be passed to the next function in the pipeline. Returning <code>undefined</code> will prevent any further processing of the token, and that token will not make it to the index.</p>
</article>
</section>
<section class="columns">
<article>
<header>
<h3>Tokenization</h3>
</header>
<p>Tokenization is how lunr converts documents and searches into individual tokens, ready to be run through the text processing pipeline and entered or looked up in the index.</p>
<p>The default tokenizer included with lunr is designed to handle general english text well, although application, or language specific tokenizers can be used instead.</p>
</article>
<article>
<header>
<h3>Stemming</h3>
</header>
<p>Stemming increases the recall of the search index by reducing related words down to their stem, so that non-exact search terms still match relevant documents. For example 'search', 'searching' and 'searched' all get reduced to the stem 'search'.</p>
<p>lunr automatically includes a stemmer based on <a href="http://tartarus.org/martin/PorterStemmer/">Martin Porter's</a> algorithms.</p>
</article>
<article>
<header>
<h3>Stop words</h3>
</header>
<p>Stop words are words that are very common and are not useful in differentiating between documents. These are automatically removed by lunr. This helps to reduce the size of the index and improve search speed and accuracy.</p>
<p>The default stop word filter contains a large list of very common words in English. For best results a corpus specific stop word filter can also be added to the pipeline. The search algorithm already penalises more common words, but preventing them from entering the index at all can be very beneficial for both space and speed performance.</p>
</article>
</section>
<footer>
<ul>
<li>Code by <a href="http://twitter.com/olivernn">Oliver Nightingale</a></li>
<li><a href="http://github.com/olivernn/lunr.js">Code</a></li>
<li><a href="/docs">Documentation</a></li>
<li><a href="http://github.com/olivernn/lunr.js/issues">Issues</a></li>
</ul>
</footer>
</div>
<script>
(function (ua) {
// some _really_ basic browser sniffing to choose the right dev tools link.
var consoleSrc,
CHROME = /Chrome/,
CHROMIUM = /Chromium/,
FIREFOX = /Firefox/,
MSIE = /MSIE/
OPERA = /(OPR|Opera)/,
SAFARI = /Safari/,
SEAMONKEY = /Seamonkey/
switch (true) {
case FIREFOX.test(ua) && !SEAMONKEY.test(ua):
// firefox
consoleSrc = "https://developer.mozilla.org/en-US/docs/Tools/Web_Console"
break
case CHROME.test(ua):
// chrome
consoleSrc = "https://developer.chrome.com/devtools"
break
case SAFARI.test(ua) && !CHROME.test(ua) && !CHROMIUM.test(ua):
// safari
consoleSrc = "https://developer.apple.com/library/safari/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/GettingStarted/GettingStarted.html#//apple_ref/doc/uid/TP40007874-CH2-SW1"
break
case OPERA.test(ua):
// opera
consoleSrc = "http://www.opera.com/dragonfly/"
break
case MSIE.test(ua):
// IE
consoleSrc = "http://msdn.microsoft.com/en-us/library/ie/hh673541(v=vs.85).aspx"
break
}
if (consoleSrc) document.getElementById('developer-tools').href = consoleSrc
})(navigator.userAgent)
</script>
<script>
(function (hijs) {
//
// hijs - JavaScript Syntax Highlighter
//
// Copyright (c) 2010 Alexis Sellier
//
// All elements which match this will be syntax highlighted.
var selector = hijs || 'pre';
var keywords = ('var function if else for while break switch case do new null in with void '
+'continue delete return this true false throw catch typeof with instanceof').split(' '),
special = ('eval window document undefined NaN Infinity parseInt parseFloat '
+'encodeURI decodeURI encodeURIComponent decodeURIComponent').split(' ');
// Syntax definition
// The key becomes the class name of the <span>
// around the matched block of code.
var syntax = [
['comment', /(\/\*(?:[^*\n]|\*+[^\/*])*\*+\/)/g],
['comment', /(\/\/[^\n]*)/g],
['string' , /("(?:(?!")[^\\\n]|\\.)*"|'(?:(?!')[^\\\n]|\\.)*')/g],
['regexp' , /(\/.+\/[mgi]*)(?!\s*\w)/g],
['class' , /\b([A-Z][a-zA-Z]+)\b/g],
['number' , /\b([0-9]+(?:\.[0-9]+)?)\b/g],
['keyword', new(RegExp)('\\b(' + keywords.join('|') + ')\\b', 'g')],
['special', new(RegExp)('\\b(' + special.join('|') + ')\\b', 'g')]
];
var nodes, table = {};
if (/^[a-z]+$/.test(selector)) {
nodes = document.getElementsByTagName(selector);
} else if (/^\.[\w-]+$/.test(selector)) {
nodes = document.getElementsByClassName(selector.slice(1));
} else if (document.querySelectorAll) {
nodes = document.querySelectorAll(selector);
} else {
nodes = [];
}
for (var i = 0, children; i < nodes.length; i++) {
children = nodes[i].childNodes;
for (var j = 0, str; j < children.length; j++) {
code = children[j];
if (code.length >= 0) { // It's a text node
// Don't highlight command-line snippets
if (! /^\$/.test(code.nodeValue.trim())) {
syntax.forEach(function (s) {
var k = s[0], v = s[1];
code.nodeValue = code.nodeValue.replace(v, function (_, m) {
return '\u00ab' + encode(k) + '\u00b7'
+ encode(m) +
'\u00b7' + encode(k) + '\u00bb';
});
});
}
}
}
}
for (var i = 0; i < nodes.length; i++) {
nodes[i].innerHTML =
nodes[i].innerHTML.replace(/\u00ab(.+?)\u00b7(.+?)\u00b7\1\u00bb/g, function (_, name, value) {
value = value.replace(/\u00ab[^\u00b7]+\u00b7/g, '').replace(/\u00b7[^\u00bb]+\u00bb/g, '');
return '<span class="' + decode(name) + '">' + escape(decode(value)) + '</span>';
});
}
function escape(str) {
return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
// Encode ASCII characters to, and from Braille
function encode (str, encoded) {
table[encoded = str.split('').map(function (s) {
if (s.charCodeAt(0) > 127) { return s }
return String.fromCharCode(s.charCodeAt(0) + 0x2800);
}).join('')] = str;
return encoded;
}
function decode (str) {
if (str in table) {
return table[str];
} else {
return str.trim().split('').map(function (s) {
if (s.charCodeAt(0) - 0x2800 > 127) { return s }
return String.fromCharCode(s.charCodeAt(0) - 0x2800);
}).join('');
}
}
})(window.hijs);
</script>
</body>
</html>

1
book/node_modules/lunr/lib/.tern-port generated vendored Normal file
View File

@@ -0,0 +1 @@
51108

96
book/node_modules/lunr/lib/document_store.js generated vendored Normal file
View File

@@ -0,0 +1,96 @@
/*!
* lunr.Store
* Copyright (C) @YEAR Oliver Nightingale
*/
/**
* lunr.Store is a simple key-value store used for storing sets of tokens for
* documents stored in index.
*
* @constructor
* @module
*/
lunr.Store = function () {
this.store = {}
this.length = 0
}
/**
* Loads a previously serialised store
*
* @param {Object} serialisedData The serialised store to load.
* @returns {lunr.Store}
* @memberOf Store
*/
lunr.Store.load = function (serialisedData) {
var store = new this
store.length = serialisedData.length
store.store = Object.keys(serialisedData.store).reduce(function (memo, key) {
memo[key] = lunr.SortedSet.load(serialisedData.store[key])
return memo
}, {})
return store
}
/**
* Stores the given tokens in the store against the given id.
*
* @param {Object} id The key used to store the tokens against.
* @param {Object} tokens The tokens to store against the key.
* @memberOf Store
*/
lunr.Store.prototype.set = function (id, tokens) {
if (!this.has(id)) this.length++
this.store[id] = tokens
}
/**
* Retrieves the tokens from the store for a given key.
*
* @param {Object} id The key to lookup and retrieve from the store.
* @returns {Object}
* @memberOf Store
*/
lunr.Store.prototype.get = function (id) {
return this.store[id]
}
/**
* Checks whether the store contains a key.
*
* @param {Object} id The id to look up in the store.
* @returns {Boolean}
* @memberOf Store
*/
lunr.Store.prototype.has = function (id) {
return id in this.store
}
/**
* Removes the value for a key in the store.
*
* @param {Object} id The id to remove from the store.
* @memberOf Store
*/
lunr.Store.prototype.remove = function (id) {
if (!this.has(id)) return
delete this.store[id]
this.length--
}
/**
* Returns a representation of the store ready for serialisation.
*
* @returns {Object}
* @memberOf Store
*/
lunr.Store.prototype.toJSON = function () {
return {
store: this.store,
length: this.length
}
}

82
book/node_modules/lunr/lib/event_emitter.js generated vendored Normal file
View File

@@ -0,0 +1,82 @@
/*!
* lunr.EventEmitter
* Copyright (C) @YEAR 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
}

421
book/node_modules/lunr/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,421 @@
/*!
* lunr.Index
* Copyright (C) @YEAR 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._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.documentStore = lunr.Store.load(serialisedData.documentStore)
idx.tokenStore = lunr.TokenStore.load(serialisedData.tokenStore)
idx.corpusTokens = lunr.SortedSet.load(serialisedData.corpusTokens)
idx.pipeline = lunr.Pipeline.load(serialisedData.pipeline)
return idx
}
/**
* Adds a field to the list of fields that will be searchable within documents
* in the index.
*
* An optional boost param can be passed to affect how much tokens in this field
* rank in search results, by default the boost value is 1.
*
* Fields should be added before any documents are added to the index, fields
* that are added after documents are added to the index will only apply to new
* documents added to the index.
*
* @param {String} fieldName The name of the field within the document that
* should be indexed
* @param {Number} boost An optional boost that can be applied to terms in this
* field.
* @returns {lunr.Index}
* @memberOf Index
*/
lunr.Index.prototype.field = function (fieldName, opts) {
var opts = opts || {},
field = { name: fieldName, boost: opts.boost || 1 }
this._fields.push(field)
return this
}
/**
* Sets the property used to uniquely identify documents added to the index,
* by default this property is 'id'.
*
* This should only be changed before adding documents to the index, changing
* the ref property without resetting the index can lead to unexpected results.
*
* @param {String} refName The property to use to uniquely identify the
* documents in the index.
* @param {Boolean} emitEvent Whether to emit add events, defaults to true
* @returns {lunr.Index}
* @memberOf Index
*/
lunr.Index.prototype.ref = function (refName) {
this._ref = refName
return this
}
/**
* Add a document to the index.
*
* This is the way new documents enter the index, this function will run the
* fields from the document through the index's pipeline and then add it to
* the index, it will then show up in search results.
*
* An 'add' event is emitted with the document that has been added and the index
* the document has been added to. This event can be silenced by passing false
* as the second argument to add.
*
* @param {Object} doc The document to add to the index.
* @param {Boolean} emitEvent Whether or not to emit events, default true.
* @memberOf Index
*/
lunr.Index.prototype.add = function (doc, emitEvent) {
var docTokens = {},
allDocumentTokens = new lunr.SortedSet,
docRef = doc[this._ref],
emitEvent = emitEvent === undefined ? true : emitEvent
this._fields.forEach(function (field) {
var fieldTokens = this.pipeline.run(lunr.tokenizer(doc[field.name]))
docTokens[field.name] = fieldTokens
lunr.SortedSet.prototype.add.apply(allDocumentTokens, fieldTokens)
}, this)
this.documentStore.set(docRef, allDocumentTokens)
lunr.SortedSet.prototype.add.apply(this.corpusTokens, allDocumentTokens.toArray())
for (var i = 0; i < allDocumentTokens.length; i++) {
var token = allDocumentTokens.elements[i]
var tf = this._fields.reduce(function (memo, field) {
var fieldLength = docTokens[field.name].length
if (!fieldLength) return memo
var tokenCount = docTokens[field.name].filter(function (t) { return t === token }).length
return memo + (tokenCount / fieldLength * field.boost)
}, 0)
this.tokenStore.add(token, { ref: docRef, tf: tf })
};
if (emitEvent) this.eventEmitter.emit('add', doc, this)
}
/**
* Removes a document from the index.
*
* To make sure documents no longer show up in search results they can be
* removed from the index using this method.
*
* The document passed only needs to have the same ref property value as the
* document that was added to the index, they could be completely different
* objects.
*
* A 'remove' event is emitted with the document that has been removed and the index
* the document has been removed from. This event can be silenced by passing false
* as the second argument to remove.
*
* @param {Object} doc The document to remove from the index.
* @param {Boolean} emitEvent Whether to emit remove events, defaults to true
* @memberOf Index
*/
lunr.Index.prototype.remove = function (doc, emitEvent) {
var docRef = doc[this._ref],
emitEvent = emitEvent === undefined ? true : emitEvent
if (!this.documentStore.has(docRef)) return
var docTokens = this.documentStore.get(docRef)
this.documentStore.remove(docRef)
docTokens.forEach(function (token) {
this.tokenStore.remove(token, docRef)
}, this)
if (emitEvent) this.eventEmitter.emit('remove', doc, this)
}
/**
* Updates a document in the index.
*
* When a document contained within the index gets updated, fields changed,
* added or removed, to make sure it correctly matched against search queries,
* it should be updated in the index.
*
* This method is just a wrapper around `remove` and `add`
*
* An 'update' event is emitted with the document that has been updated and the index.
* This event can be silenced by passing false as the second argument to update. Only
* an update event will be fired, the 'add' and 'remove' events of the underlying calls
* are silenced.
*
* @param {Object} doc The document to update in the index.
* @param {Boolean} emitEvent Whether to emit update events, defaults to true
* @see Index.prototype.remove
* @see Index.prototype.add
* @memberOf Index
*/
lunr.Index.prototype.update = function (doc, emitEvent) {
var emitEvent = emitEvent === undefined ? true : emitEvent
this.remove(doc, false)
this.add(doc, false)
if (emitEvent) this.eventEmitter.emit('update', doc, this)
}
/**
* Calculates the inverse document frequency for a token within the index.
*
* @param {String} token The token to calculate the idf of.
* @see Index.prototype.idf
* @private
* @memberOf Index
*/
lunr.Index.prototype.idf = function (term) {
var cacheKey = "@" + term
if (Object.prototype.hasOwnProperty.call(this._idfCache, cacheKey)) return this._idfCache[cacheKey]
var documentFrequency = this.tokenStore.count(term),
idf = 1
if (documentFrequency > 0) {
idf = 1 + Math.log(this.documentStore.length / documentFrequency)
}
return this._idfCache[cacheKey] = idf
}
/**
* Searches the index using the passed query.
*
* Queries should be a string, multiple words are allowed and will lead to an
* AND based query, e.g. `idx.search('foo bar')` will run a search for
* documents containing both 'foo' and 'bar'.
*
* All query tokens are passed through the same pipeline that document tokens
* are passed through, so any language processing involved will be run on every
* query term.
*
* Each query term is expanded, so that the term 'he' might be expanded to
* 'hello' and 'help' if those terms were already included in the index.
*
* Matching documents are returned as an array of objects, each object contains
* the matching document ref, as set for this index, and the similarity score
* for this document against the query.
*
* @param {String} query The query to search the index with.
* @returns {Object}
* @see Index.prototype.idf
* @see Index.prototype.documentVector
* @memberOf Index
*/
lunr.Index.prototype.search = function (query) {
var queryTokens = this.pipeline.run(lunr.tokenizer(query)),
queryVector = new lunr.Vector,
documentSets = [],
fieldBoosts = this._fields.reduce(function (memo, f) { return memo + f.boost }, 0)
var hasSomeToken = queryTokens.some(function (token) {
return this.tokenStore.has(token)
}, this)
if (!hasSomeToken) return []
queryTokens
.forEach(function (token, i, tokens) {
var tf = 1 / tokens.length * this._fields.length * fieldBoosts,
self = this
var set = this.tokenStore.expand(token).reduce(function (memo, key) {
var pos = self.corpusTokens.indexOf(key),
idf = self.idf(key),
similarityBoost = 1,
set = new lunr.SortedSet
// if the expanded key is not an exact match to the token then
// penalise the score for this key by how different the key is
// to the token.
if (key !== token) {
var diff = Math.max(3, key.length - token.length)
similarityBoost = 1 / Math.log(diff)
}
// calculate the query tf-idf score for this token
// applying an similarityBoost to ensure exact matches
// these rank higher than expanded terms
if (pos > -1) queryVector.insert(pos, tf * idf * similarityBoost)
// add all the documents that have this key into a set
Object.keys(self.tokenStore.get(key)).forEach(function (ref) { set.add(ref) })
return memo.union(set)
}, new lunr.SortedSet)
documentSets.push(set)
}, this)
var documentSet = documentSets.reduce(function (memo, set) {
return memo.intersect(set)
})
return documentSet
.map(function (ref) {
return { ref: ref, score: queryVector.similarity(this.documentVector(ref)) }
}, this)
.sort(function (a, b) {
return b.score - a.score
})
}
/**
* Generates a vector containing all the tokens in the document matching the
* passed documentRef.
*
* The vector contains the tf-idf score for each token contained in the
* document with the passed documentRef. The vector will contain an element
* for every token in the indexes corpus, if the document does not contain that
* token the element will be 0.
*
* @param {Object} documentRef The ref to find the document with.
* @returns {lunr.Vector}
* @private
* @memberOf Index
*/
lunr.Index.prototype.documentVector = function (documentRef) {
var documentTokens = this.documentStore.get(documentRef),
documentTokensLength = documentTokens.length,
documentVector = new lunr.Vector
for (var i = 0; i < documentTokensLength; i++) {
var token = documentTokens.elements[i],
tf = this.tokenStore.get(token)[documentRef].tf,
idf = this.idf(token)
documentVector.insert(this.corpusTokens.indexOf(token), tf * idf)
};
return documentVector
}
/**
* Returns a representation of the index ready for serialisation.
*
* @returns {Object}
* @memberOf Index
*/
lunr.Index.prototype.toJSON = function () {
return {
version: lunr.version,
fields: this._fields,
ref: this._ref,
documentStore: this.documentStore.toJSON(),
tokenStore: this.tokenStore.toJSON(),
corpusTokens: this.corpusTokens.toJSON(),
pipeline: this.pipeline.toJSON()
}
}
/**
* Applies a plugin to the current index.
*
* A plugin is a function that is called with the index as its context.
* Plugins can be used to customise or extend the behaviour the index
* in some way. A plugin is just a function, that encapsulated the custom
* behaviour that should be applied to the index.
*
* The plugin function will be called with the index as its argument, additional
* arguments can also be passed when calling use. The function will be called
* with the index as its context.
*
* Example:
*
* var myPlugin = function (idx, arg1, arg2) {
* // `this` is the index to be extended
* // apply any extensions etc here.
* }
*
* var idx = lunr(function () {
* this.use(myPlugin, 'arg1', 'arg2')
* })
*
* @param {Function} plugin The plugin to apply.
* @memberOf Index
*/
lunr.Index.prototype.use = function (plugin) {
var args = Array.prototype.slice.call(arguments, 1)
args.unshift(this)
plugin.apply(this, args)
}

50
book/node_modules/lunr/lib/lunr.js generated vendored Normal file
View File

@@ -0,0 +1,50 @@
/**
* 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 = "@VERSION"

230
book/node_modules/lunr/lib/pipeline.js generated vendored Normal file
View File

@@ -0,0 +1,230 @@
/*!
* lunr.Pipeline
* Copyright (C) @YEAR 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) break
};
if (token !== void 0) 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
})
}

240
book/node_modules/lunr/lib/sorted_set.js generated vendored Normal file
View File

@@ -0,0 +1,240 @@
/*!
* lunr.SortedSet
* Copyright (C) @YEAR 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()
unionSet.add.apply(unionSet, shortSet.toArray())
return unionSet
}
/**
* Returns a representation of the sorted set ready for serialisation.
*
* @returns {Array}
* @memberOf SortedSet
*/
lunr.SortedSet.prototype.toJSON = function () {
return this.toArray()
}

218
book/node_modules/lunr/lib/stemmer.js generated vendored Normal file
View File

@@ -0,0 +1,218 @@
/*!
* lunr.stemmer
* Copyright (C) @YEAR Oliver Nightingale
* Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt
*/
/**
* lunr.stemmer is an english language stemmer, this is a JavaScript
* implementation of the PorterStemmer taken from http://tartarus.org/~martin
*
* @module
* @param {String} str The string to stem
* @returns {String}
* @see lunr.Pipeline
*/
lunr.stemmer = (function(){
var step2list = {
"ational" : "ate",
"tional" : "tion",
"enci" : "ence",
"anci" : "ance",
"izer" : "ize",
"bli" : "ble",
"alli" : "al",
"entli" : "ent",
"eli" : "e",
"ousli" : "ous",
"ization" : "ize",
"ation" : "ate",
"ator" : "ate",
"alism" : "al",
"iveness" : "ive",
"fulness" : "ful",
"ousness" : "ous",
"aliti" : "al",
"iviti" : "ive",
"biliti" : "ble",
"logi" : "log"
},
step3list = {
"icate" : "ic",
"ative" : "",
"alize" : "al",
"iciti" : "ic",
"ical" : "ic",
"ful" : "",
"ness" : ""
},
c = "[^aeiou]", // consonant
v = "[aeiouy]", // vowel
C = c + "[^aeiouy]*", // consonant sequence
V = v + "[aeiou]*", // vowel sequence
mgr0 = "^(" + C + ")?" + V + C, // [C]VC... is m>0
meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$", // [C]VC[V] is m=1
mgr1 = "^(" + C + ")?" + V + C + V + C, // [C]VCVC... is m>1
s_v = "^(" + C + ")?" + v; // vowel in stem
var re_mgr0 = new RegExp(mgr0);
var re_mgr1 = new RegExp(mgr1);
var re_meq1 = new RegExp(meq1);
var re_s_v = new RegExp(s_v);
var re_1a = /^(.+?)(ss|i)es$/;
var re2_1a = /^(.+?)([^s])s$/;
var re_1b = /^(.+?)eed$/;
var re2_1b = /^(.+?)(ed|ing)$/;
var re_1b_2 = /.$/;
var re2_1b_2 = /(at|bl|iz)$/;
var re3_1b_2 = new RegExp("([^aeiouylsz])\\1$");
var re4_1b_2 = new RegExp("^" + C + v + "[^aeiouwxy]$");
var re_1c = /^(.+?[^aeiou])y$/;
var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
var re2_4 = /^(.+?)(s|t)(ion)$/;
var re_5 = /^(.+?)e$/;
var re_5_1 = /ll$/;
var re3_5 = new RegExp("^" + C + v + "[^aeiouwxy]$");
var porterStemmer = function porterStemmer(w) {
var stem,
suffix,
firstch,
re,
re2,
re3,
re4;
if (w.length < 3) { return w; }
firstch = w.substr(0,1);
if (firstch == "y") {
w = firstch.toUpperCase() + w.substr(1);
}
// Step 1a
re = re_1a
re2 = re2_1a;
if (re.test(w)) { w = w.replace(re,"$1$2"); }
else if (re2.test(w)) { w = w.replace(re2,"$1$2"); }
// Step 1b
re = re_1b;
re2 = re2_1b;
if (re.test(w)) {
var fp = re.exec(w);
re = re_mgr0;
if (re.test(fp[1])) {
re = re_1b_2;
w = w.replace(re,"");
}
} else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = re_s_v;
if (re2.test(stem)) {
w = stem;
re2 = re2_1b_2;
re3 = re3_1b_2;
re4 = re4_1b_2;
if (re2.test(w)) { w = w + "e"; }
else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,""); }
else if (re4.test(w)) { w = w + "e"; }
}
}
// Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say)
re = re_1c;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
w = stem + "i";
}
// Step 2
re = re_2;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = re_mgr0;
if (re.test(stem)) {
w = stem + step2list[suffix];
}
}
// Step 3
re = re_3;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = re_mgr0;
if (re.test(stem)) {
w = stem + step3list[suffix];
}
}
// Step 4
re = re_4;
re2 = re2_4;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = re_mgr1;
if (re.test(stem)) {
w = stem;
}
} else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = re_mgr1;
if (re2.test(stem)) {
w = stem;
}
}
// Step 5
re = re_5;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = re_mgr1;
re2 = re_meq1;
re3 = re3_5;
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {
w = stem;
}
}
re = re_5_1;
re2 = re_mgr1;
if (re.test(w) && re2.test(w)) {
re = re_1b_2;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y") {
w = firstch.toLowerCase() + w.substr(1);
}
return w;
};
return porterStemmer;
})();
lunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer')

144
book/node_modules/lunr/lib/stop_word_filter.js generated vendored Normal file
View File

@@ -0,0 +1,144 @@
/*!
* lunr.stopWordFilter
* Copyright (C) @YEAR Oliver Nightingale
*/
/**
* lunr.stopWordFilter is an English language stop word list filter, any words
* contained in the list will not be passed through the filter.
*
* This is intended to be used in the Pipeline. If the token does not pass the
* filter then undefined will be returned.
*
* @module
* @param {String} token The token to pass through the filter
* @returns {String}
* @see lunr.Pipeline
*/
lunr.stopWordFilter = function (token) {
if (token && lunr.stopWordFilter.stopWords[token] !== token) return token;
}
lunr.stopWordFilter.stopWords = {
'a': 'a',
'able': 'able',
'about': 'about',
'across': 'across',
'after': 'after',
'all': 'all',
'almost': 'almost',
'also': 'also',
'am': 'am',
'among': 'among',
'an': 'an',
'and': 'and',
'any': 'any',
'are': 'are',
'as': 'as',
'at': 'at',
'be': 'be',
'because': 'because',
'been': 'been',
'but': 'but',
'by': 'by',
'can': 'can',
'cannot': 'cannot',
'could': 'could',
'dear': 'dear',
'did': 'did',
'do': 'do',
'does': 'does',
'either': 'either',
'else': 'else',
'ever': 'ever',
'every': 'every',
'for': 'for',
'from': 'from',
'get': 'get',
'got': 'got',
'had': 'had',
'has': 'has',
'have': 'have',
'he': 'he',
'her': 'her',
'hers': 'hers',
'him': 'him',
'his': 'his',
'how': 'how',
'however': 'however',
'i': 'i',
'if': 'if',
'in': 'in',
'into': 'into',
'is': 'is',
'it': 'it',
'its': 'its',
'just': 'just',
'least': 'least',
'let': 'let',
'like': 'like',
'likely': 'likely',
'may': 'may',
'me': 'me',
'might': 'might',
'most': 'most',
'must': 'must',
'my': 'my',
'neither': 'neither',
'no': 'no',
'nor': 'nor',
'not': 'not',
'of': 'of',
'off': 'off',
'often': 'often',
'on': 'on',
'only': 'only',
'or': 'or',
'other': 'other',
'our': 'our',
'own': 'own',
'rather': 'rather',
'said': 'said',
'say': 'say',
'says': 'says',
'she': 'she',
'should': 'should',
'since': 'since',
'so': 'so',
'some': 'some',
'than': 'than',
'that': 'that',
'the': 'the',
'their': 'their',
'them': 'them',
'then': 'then',
'there': 'there',
'these': 'these',
'they': 'they',
'this': 'this',
'tis': 'tis',
'to': 'to',
'too': 'too',
'twas': 'twas',
'us': 'us',
'wants': 'wants',
'was': 'was',
'we': 'we',
'were': 'were',
'what': 'what',
'when': 'when',
'where': 'where',
'which': 'which',
'while': 'while',
'who': 'who',
'whom': 'whom',
'why': 'why',
'will': 'will',
'with': 'with',
'would': 'would',
'yet': 'yet',
'you': 'you',
'your': 'your'
}
lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter')

193
book/node_modules/lunr/lib/token_store.js generated vendored Normal file
View File

@@ -0,0 +1,193 @@
/*!
* lunr.stemmer
* Copyright (C) @YEAR Oliver Nightingale
* Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt
*/
/**
* lunr.TokenStore is used for efficient storing and lookup of the reverse
* index of token to document ref.
*
* @constructor
*/
lunr.TokenStore = function () {
this.root = { docs: {} }
this.length = 0
}
/**
* Loads a previously serialised token store
*
* @param {Object} serialisedData The serialised token store to load.
* @returns {lunr.TokenStore}
* @memberOf TokenStore
*/
lunr.TokenStore.load = function (serialisedData) {
var store = new this
store.root = serialisedData.root
store.length = serialisedData.length
return store
}
/**
* Adds a new token doc pair to the store.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to store the doc under
* @param {Object} doc The doc to store against the token
* @param {Object} root An optional node at which to start looking for the
* correct place to enter the doc, by default the root of this lunr.TokenStore
* is used.
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.add = function (token, doc, root) {
var root = root || this.root,
key = token[0],
rest = token.slice(1)
if (!(key in root)) root[key] = {docs: {}}
if (rest.length === 0) {
root[key].docs[doc.ref] = doc
this.length += 1
return
} else {
return this.add(rest, doc, root[key])
}
}
/**
* Checks whether this key is contained within this lunr.TokenStore.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to check for
* @param {Object} root An optional node at which to start
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.has = function (token) {
if (!token) return false
var node = this.root
for (var i = 0; i < token.length; i++) {
if (!node[token[i]]) return false
node = node[token[i]]
}
return true
}
/**
* Retrieve a node from the token store for a given token.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the node for.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @see TokenStore.prototype.get
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.getNode = function (token) {
if (!token) return {}
var node = this.root
for (var i = 0; i < token.length; i++) {
if (!node[token[i]]) return {}
node = node[token[i]]
}
return node
}
/**
* Retrieve the documents for a node for the given token.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the documents for.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.get = function (token, root) {
return this.getNode(token, root).docs || {}
}
lunr.TokenStore.prototype.count = function (token, root) {
return Object.keys(this.get(token, root)).length
}
/**
* Remove the document identified by ref from the token in the store.
*
* By default this function starts at the root of the current store, however
* it can start at any node of any token store if required.
*
* @param {String} token The token to get the documents for.
* @param {String} ref The ref of the document to remove from this token.
* @param {Object} root An optional node at which to start.
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.remove = function (token, ref) {
if (!token) return
var node = this.root
for (var i = 0; i < token.length; i++) {
if (!(token[i] in node)) return
node = node[token[i]]
}
delete node.docs[ref]
}
/**
* Find all the possible suffixes of the passed token using tokens
* currently in the store.
*
* @param {String} token The token to expand.
* @returns {Array}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.expand = function (token, memo) {
var root = this.getNode(token),
docs = root.docs || {},
memo = memo || []
if (Object.keys(docs).length) memo.push(token)
Object.keys(root)
.forEach(function (key) {
if (key === 'docs') return
memo.concat(this.expand(token + key, memo))
}, this)
return memo
}
/**
* Returns a representation of the token store ready for serialisation.
*
* @returns {Object}
* @memberOf TokenStore
*/
lunr.TokenStore.prototype.toJSON = function () {
return {
root: this.root,
length: this.length
}
}

20
book/node_modules/lunr/lib/tokenizer.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/*!
* lunr.tokenizer
* Copyright (C) @YEAR Oliver Nightingale
*/
/**
* A function for splitting a string into tokens ready to be inserted into
* the search index.
*
* @module
* @param {String} obj The string to convert into tokens
* @returns {Array}
*/
lunr.tokenizer = function (obj) {
if (!arguments.length || obj == null || obj == undefined) return []
if (Array.isArray(obj)) return obj.map(function (t) { return t.toLowerCase() })
return obj.toString().trim().toLowerCase().split(/[\s\-]+/)
}

26
book/node_modules/lunr/lib/trimmer.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
/*!
* lunr.trimmer
* Copyright (C) @YEAR Oliver Nightingale
*/
/**
* lunr.trimmer is a pipeline function for trimming non word
* characters from the begining and end of tokens before they
* enter the index.
*
* This implementation may not work correctly for non latin
* characters and should either be removed or adapted for use
* with languages with non-latin characters.
*
* @module
* @param {String} token The token to pass through the filter
* @returns {String}
* @see lunr.Pipeline
*/
lunr.trimmer = function (token) {
var result = token.replace(/^\W+/, '')
.replace(/\W+$/, '')
return result === '' ? undefined : result
}
lunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer')

24
book/node_modules/lunr/lib/utils.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
/*!
* lunr.utils
* Copyright (C) @YEAR 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)

131
book/node_modules/lunr/lib/vector.js generated vendored Normal file
View File

@@ -0,0 +1,131 @@
/*!
* lunr.Vector
* Copyright (C) @YEAR 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())
}

1913
book/node_modules/lunr/lunr.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

7
book/node_modules/lunr/lunr.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

47
book/node_modules/lunr/notes generated vendored Normal file
View File

@@ -0,0 +1,47 @@
1 - "Mr. Green killed Colonel Mustard in the study with the candlestick. Mr. Green is not a very nice fellow."
2 - "Professor Plumb has a green plant in his study."
3 - "Miss Scarlett watered Professor Plumb's green plant while he was away from his office last week."
l1 = 19
l2 = 9
l3 = 16
q1 - "green"
q1 = [0.0, 0.71]
1 = [0.0, 0.0747]
2 = [0.0, 0.1555]
3 = [0.0, 0.0875]
green : total count = 4, idf = 0.71
mr : total count = 2, idf = 1.40
the : total count = 2, idf = 1.40
plant : total count = 2, idf = 1.40
q2 = "Mr. Green"
q2 = [1.4, 0.71]
1 = [0.147, 0.0747]
2 = [0, 0.1555]
3 = [0, 0.0875]
q3 = "the green plant"
q3 = [0.5, 0.25, 0.5]
1 = [1, 0.5, 0]
2 = [0, 0.25, 0.5]
3 = [0, 0.25, 0.5]
Inverse Index as a trie
values are {docId: score} where score is the sum of tf across fields, with multipliers applied
when querying calculate the idf and multiply it by the tf
for a multi term query generate a vector using the idf
find all the documents that match both queries, and generate a tf*idf
word: {
totalCount: 123,
docs:
}

1806
book/node_modules/lunr/out/data.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

24
book/node_modules/lunr/package.json generated vendored Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "lunr",
"description": "Simple full-text search in your browser.",
"version": "0.5.12",
"author": "Oliver Nightingale",
"keywords": ["search"],
"homepage": "http://lunrjs.com",
"bugs": "http://github.com/olivernn/lunr.js/issues",
"main": "lunr.js",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/olivernn/lunr.js.git"
},
"devDependencies": {
"dox": "0.4.4",
"dox-template": "0.1.1",
"phantomjs": "1.8.1-3",
"uglify-js": "2.4.13"
},
"scripts": {
"test": "make test"
}
}

16
book/node_modules/lunr/perf/document_store_test.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
(function () {
var setup = function () {
var store = new lunr.Store,
tokens = ['foo', 'bar', 'baz']
}
bench('documentStore#set', function () {
for (var i = 0; i < 1000; i++) {
store.set(i, tokens)
}
}, { setup: setup })
})()

79
book/node_modules/lunr/perf/env/bench.js generated vendored Normal file
View File

@@ -0,0 +1,79 @@
(function () {
var BenchView = function (benchmark) {
this.benchmark = benchmark
var benchmarkTemplate = $('#benchmark-template').text()
this.html = $(Mustache.to_html(benchmarkTemplate, benchmark))
this.benchmark.on('start', this.started.bind(this))
this.benchmark.on('complete', this.completed.bind(this))
this.benchmark.on('error', this.errored.bind(this))
this.html.find('button').bind('click', function () {
benchmark.run({async: true})
})
}
BenchView.prototype.started = function () {
this.html
.addClass('is-running')
.find('.status')
.html('Running&hellip;')
}
BenchView.prototype.completed = function () {
this.html
.removeClass('is-running')
.find('.status')
.text('Done')
.end()
.find('.ops-per-sec')
.text(Benchmark.formatNumber(this.benchmark.hz.toFixed(2)))
}
BenchView.prototype.errored = function () {
this.html
.removeClass('is-running')
.addClass('is-errored')
.find('.status')
.text('Error')
throw(this.benchmark.error)
}
benchmarks = []
var bench = function (name, testFn, options) {
var benchmark = new Benchmark(name, testFn, options)
benchmarks.push(benchmark)
}
bench.runAll = function () {
for (var i = 1; i < benchmarks.length; i++) {
var benchmark = benchmarks[i],
prev = benchmarks[i - 1]
prev.on('complete', function () {
console.log(benchmark)
benchmark.run({async: true})
})
}
benchmarks[0].run({async: true})
}
$(document).ready(function () {
var benchmarksContainer = $('#benchmarks tbody')
benchmarks.forEach(function (benchmark) {
var benchView = new BenchView (benchmark)
benchmarksContainer.append(benchView.html)
})
$('button.run').click(function () {
//bench.runAll()
})
})
window.bench = bench
})()

3919
book/node_modules/lunr/perf/env/benchmark.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

8176
book/node_modules/lunr/perf/env/jquery.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

325
book/node_modules/lunr/perf/env/mustache.js generated vendored Normal file
View File

@@ -0,0 +1,325 @@
/*
mustache.js — Logic-less templates in JavaScript
See http://mustache.github.com/ for more info.
*/
var Mustache = function() {
var Renderer = function() {};
Renderer.prototype = {
otag: "{{",
ctag: "}}",
pragmas: {},
buffer: [],
pragmas_implemented: {
"IMPLICIT-ITERATOR": true
},
context: {},
render: function(template, context, partials, in_recursion) {
// reset buffer & set context
if(!in_recursion) {
this.context = context;
this.buffer = []; // TODO: make this non-lazy
}
// fail fast
if(!this.includes("", template)) {
if(in_recursion) {
return template;
} else {
this.send(template);
return;
}
}
template = this.render_pragmas(template);
var html = this.render_section(template, context, partials);
if(in_recursion) {
return this.render_tags(html, context, partials, in_recursion);
}
this.render_tags(html, context, partials, in_recursion);
},
/*
Sends parsed lines
*/
send: function(line) {
if(line != "") {
this.buffer.push(line);
}
},
/*
Looks for %PRAGMAS
*/
render_pragmas: function(template) {
// no pragmas
if(!this.includes("%", template)) {
return template;
}
var that = this;
var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
this.ctag);
return template.replace(regex, function(match, pragma, options) {
if(!that.pragmas_implemented[pragma]) {
throw({message:
"This implementation of mustache doesn't understand the '" +
pragma + "' pragma"});
}
that.pragmas[pragma] = {};
if(options) {
var opts = options.split("=");
that.pragmas[pragma][opts[0]] = opts[1];
}
return "";
// ignore unknown pragmas silently
});
},
/*
Tries to find a partial in the curent scope and render it
*/
render_partial: function(name, context, partials) {
name = this.trim(name);
if(!partials || partials[name] === undefined) {
throw({message: "unknown_partial '" + name + "'"});
}
if(typeof(context[name]) != "object") {
return this.render(partials[name], context, partials, true);
}
return this.render(partials[name], context[name], partials, true);
},
/*
Renders inverted (^) and normal (#) sections
*/
render_section: function(template, context, partials) {
if(!this.includes("#", template) && !this.includes("^", template)) {
return template;
}
var that = this;
// CSW - Added "+?" so it finds the tighest bound, not the widest
var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
"\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
"\\s*", "mg");
// for each {{#foo}}{{/foo}} section do...
return template.replace(regex, function(match, type, name, content) {
var value = that.find(name, context);
if(type == "^") { // inverted section
if(!value || that.is_array(value) && value.length === 0) {
// false or empty list, render it
return that.render(content, context, partials, true);
} else {
return "";
}
} else if(type == "#") { // normal section
if(that.is_array(value)) { // Enumerable, Let's loop!
return that.map(value, function(row) {
return that.render(content, that.create_context(row),
partials, true);
}).join("");
} else if(that.is_object(value)) { // Object, Use it as subcontext!
return that.render(content, that.create_context(value),
partials, true);
} else if(typeof value === "function") {
// higher order section
return value.call(context, content, function(text) {
return that.render(text, context, partials, true);
});
} else if(value) { // boolean section
return that.render(content, context, partials, true);
} else {
return "";
}
}
});
},
/*
Replace {{foo}} and friends with values from our view
*/
render_tags: function(template, context, partials, in_recursion) {
// tit for tat
var that = this;
var new_regex = function() {
return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
that.ctag + "+", "g");
};
var regex = new_regex();
var tag_replace_callback = function(match, operator, name) {
switch(operator) {
case "!": // ignore comments
return "";
case "=": // set new delimiters, rebuild the replace regexp
that.set_delimiters(name);
regex = new_regex();
return "";
case ">": // render partial
return that.render_partial(name, context, partials);
case "{": // the triple mustache is unescaped
return that.find(name, context);
default: // escape the value
return that.escape(that.find(name, context));
}
};
var lines = template.split("\n");
for(var i = 0; i < lines.length; i++) {
lines[i] = lines[i].replace(regex, tag_replace_callback, this);
if(!in_recursion) {
this.send(lines[i]);
}
}
if(in_recursion) {
return lines.join("\n");
}
},
set_delimiters: function(delimiters) {
var dels = delimiters.split(" ");
this.otag = this.escape_regex(dels[0]);
this.ctag = this.escape_regex(dels[1]);
},
escape_regex: function(text) {
// thank you Simon Willison
if(!arguments.callee.sRE) {
var specials = [
'/', '.', '*', '+', '?', '|',
'(', ')', '[', ']', '{', '}', '\\'
];
arguments.callee.sRE = new RegExp(
'(\\' + specials.join('|\\') + ')', 'g'
);
}
return text.replace(arguments.callee.sRE, '\\$1');
},
/*
find `name` in current `context`. That is find me a value
from the view object
*/
find: function(name, context) {
name = this.trim(name);
// Checks whether a value is thruthy or false or 0
function is_kinda_truthy(bool) {
return bool === false || bool === 0 || bool;
}
var value;
if(is_kinda_truthy(context[name])) {
value = context[name];
} else if(is_kinda_truthy(this.context[name])) {
value = this.context[name];
}
if(typeof value === "function") {
return value.apply(context);
}
if(value !== undefined) {
return value;
}
// silently ignore unknown variables
return "";
},
// Utility methods
/* includes tag */
includes: function(needle, haystack) {
return haystack.indexOf(this.otag + needle) != -1;
},
/*
Does away with nasty characters
*/
escape: function(s) {
s = String(s === null ? "" : s);
return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
switch(s) {
case "&": return "&amp;";
case "\\": return "\\\\";
case '"': return '&quot;';
case "'": return '&#39;';
case "<": return "&lt;";
case ">": return "&gt;";
default: return s;
}
});
},
// by @langalex, support for arrays of strings
create_context: function(_context) {
if(this.is_object(_context)) {
return _context;
} else {
var iterator = ".";
if(this.pragmas["IMPLICIT-ITERATOR"]) {
iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
}
var ctx = {};
ctx[iterator] = _context;
return ctx;
}
},
is_object: function(a) {
return a && typeof a == "object";
},
is_array: function(a) {
return Object.prototype.toString.call(a) === '[object Array]';
},
/*
Gets rid of leading and trailing whitespace
*/
trim: function(s) {
return s.replace(/^\s*|\s*$/g, "");
},
/*
Why, why, why? Because IE. Cry, cry cry.
*/
map: function(array, fn) {
if (typeof array.map == "function") {
return array.map(fn);
} else {
var r = [];
var l = array.length;
for(var i = 0; i < l; i++) {
r.push(fn(array[i]));
}
return r;
}
}
};
return({
name: "mustache.js",
version: "0.3.1-dev",
/*
Turns a template and view into HTML
*/
to_html: function(template, view, partials, send_fun) {
var renderer = new Renderer();
if(send_fun) {
renderer.send = send_fun;
}
renderer.render(template, view, partials);
if(!send_fun) {
return renderer.buffer.join("\n");
}
}
});
}();

22
book/node_modules/lunr/perf/env/styles.css generated vendored Normal file
View File

@@ -0,0 +1,22 @@
#benchmarks li.is-running {
color: green
}
#benchmarks li.is-errored .results,
#benchmarks li.is-running .results,
#benchmarks li.is-pending .results {
display: none
}
#benchmarks li.is-complete .results {
display: block;
}
#benchmarks li.is-pending .idle {
display: block;
}
#benchmarks li.is-complete .running,
#benchmarks li.is-pending .running {
display: none
}

1
book/node_modules/lunr/perf/fixtures/questions.js generated vendored Normal file

File diff suppressed because one or more lines are too long

7
book/node_modules/lunr/perf/foo_test.js generated vendored Normal file
View File

@@ -0,0 +1,7 @@
bench('addition', function () {
return 1 + 1
})
bench('subtraction', function () {
return 1 - 1
})

74
book/node_modules/lunr/perf/index.html generated vendored Normal file
View File

@@ -0,0 +1,74 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Lunr tests</title>
<link rel="stylesheet" href="/perf/env/styles.css">
<!-- dependencies -->
<script src="/perf/env/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/env/mustache.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/env/benchmark.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/env/bench.js" type="text/javascript" charset="utf-8"></script>
<!-- fixtures -->
<script src="/perf/fixtures/questions.js" type="text/javascript" charset="utf-8"></script>
<script src="/test/fixtures/stemming_vocab.json" type="text/javascript" charset="utf-8"></script>
<!-- Lunr -->
<script src="/lib/lunr.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/utils.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/tokenizer.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/pipeline.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/vector.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/sorted_set.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/event_emitter.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/index.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/document_store.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/stemmer.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/stop_word_filter.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/token_store.js" type="text/javascript" charset="utf-8"></script>
<!-- Tests -->
<script src="/perf/index_test.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/vector_test.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/token_store_test.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/sorted_set_test.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/document_store_test.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/stemmer_test.js" type="text/javascript" charset="utf-8"></script>
<script src="/perf/tokenizer_test.js" type="text/javascript" charset="utf-8"></script>
<script id="benchmark-template" type="text/mustache">
<tr>
<td>{{name}}</td>
<td class="status">Ready</td>
<td class="ops-per-sec">N/A</td>
<td class="actions">
<button class="run">Run</button>
</td>
</tr>
</script>
<script>
</script>
</head>
<body>
<header>
<h1>Lunr.js Performance Tests</h1>
<button class="run">Run!</button>
</header>
<table id="benchmarks">
<thead>
<tr>
<td>Name</td>
<td>Status</td>
<td>Result</td>
</tr>
</thead>
<tbody></tbody>
</table>
</body>
</html>

28
book/node_modules/lunr/perf/index_test.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
(function () {
var setup = function () {
var testDoc = {
id: 1,
title: 'Adding story from last story in the sprint',
body: 'So that I am not confused where the story is going to end up As a user I want the the add a story button from the last story in the sprint to create a story at the top of the backlog and not extend the sprint temporarily the add story button inserts a story at the top of the backlog. "add a new story here" prompts are not shown for stories that are currently in a sprint',
tags: 'foo bar'
}
questionsIdx.version = lunr.version
var idx = lunr.Index.load(questionsIdx)
}
bench('index#add', function () {
idx.add(testDoc)
}, { setup: setup })
bench('index#search uncommon word', function () {
idx.search('checkbox')
}, { setup: setup })
bench('index#search common word', function () {
idx.search('javascript')
}, { setup: setup })
})()

28
book/node_modules/lunr/perf/pipeline_test.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
var suite = new Benchmark.Suite,
elements = [],
fn1 = function (t) { return t },
fn2 = function (t) { return t },
pipeline = new lunr.Pipeline
for (var i = 0; i < 10000; i++) {
elements[i] = Math.random() * 100
};
pipeline.add(fn1, fn2)
suite.add('pipeline#run', function () {
pipeline.run(elements)
})
suite.on('cycle', function (e) {
console.log(e.target.name)
})
suite.on('complete', function (e) {
suite.forEach(function (s) {
console.log(s.name, s.count)
})
})
suite.run({async: true})

29
book/node_modules/lunr/perf/set_index_of_test.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
var suite = new Benchmark.Suite,
set = new lunr.SortedSet
for (var i = 0; i < 1000; i++) {
set.add(Math.random() * 100)
};
suite.add('native indexOf', function () {
set.elements.indexOf(50)
})
suite.add('bsearch indexOf', function () {
set.indexOf(50)
})
suite.on('cycle', function (e) {
console.log(e.target.name)
})
suite.on('complete', function (e) {
suite.forEach(function (s) {
console.log(s.name, s.count)
})
var fastest = this.filter('fastest').pluck('name')
console.log('fastest is: ', fastest)
})
suite.run({async: true})

26
book/node_modules/lunr/perf/sorted_set_test.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
(function () {
var setup = function () {
var filledSet = new lunr.SortedSet
for (var i = 0; i < 10000; i++) {
filledSet.add(i * 2)
}
}
bench('sortedSet#add non-duplicate', function () {
var sortedSet = new lunr.SortedSet
sortedSet.elements = filledSet.elements
sortedSet.add(3131)
}, { setup: setup })
bench('sortedSet#add duplicate', function () {
var sortedSet = new lunr.SortedSet
sortedSet.elements = filledSet.elements
sortedSet.add(2000)
}, { setup: setup })
bench("sortedSet#indexOf", function () {
filledSet.indexOf(321)
}, { setup: setup })
})()

7
book/node_modules/lunr/perf/stemmer_test.js generated vendored Normal file
View File

@@ -0,0 +1,7 @@
(function () {
bench("stemmer", function () {
Object.keys(stemmingFixture).forEach(function (word) {
lunr.stemmer(word)
})
})
})()

21
book/node_modules/lunr/perf/token_store_test.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
(function () {
var setup = function () {
questionsIdx.version = lunr.version
var store = lunr.TokenStore.load(questionsIdx.tokenStore)
}
bench('tokenStore#getNode', function () {
store.getNode('javascript')
}, { setup: setup })
bench('tokenStore#has non existant term', function () {
store.has('qwertyuiop')
}, { setup: setup })
bench('tokenStore#has term exists', function () {
store.has('javascript')
}, { setup: setup })
})()

9
book/node_modules/lunr/perf/tokenizer_test.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
(function () {
var setup = function () {
var lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"
}
bench("tokeniser", function () {
lunr.tokenizer(lorem)
}, { setup: setup })
})()

34
book/node_modules/lunr/perf/vector_test.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
(function () {
var setup = function () {
var index, val
var v1 = new lunr.Vector,
v2 = new lunr.Vector
for (var i = 0; i < 1000; i++) {
index = Math.floor(i + Math.random() * 100)
val = Math.random() * 100
v1.insert(i, val)
}
for (var i = 0; i < 1000; i++) {
index = Math.floor(i + Math.random() * 100)
val = Math.random() * 100
v2.insert(i, val)
}
}
bench('vector#magnitude', function () {
v1.magnitude()
}, { setup: setup })
bench('vector#dot', function () {
v1.dot(v2)
}, { setup: setup })
bench('vector#similarity', function () {
v1.similarity(v2)
}, { setup: setup })
})()

44
book/node_modules/lunr/server.js generated vendored Normal file
View File

@@ -0,0 +1,44 @@
var http = require('http'),
url = require('url'),
join = require('path').join,
extname = require('path').extname,
join = require('path').join,
fs = require('fs'),
port = process.argv[2] || 3000
var mime = {
'html': 'text/html',
'css': 'text/css',
'js': 'application/javascript',
}
http.createServer(function(req, res){
console.log(' \033[90m%s \033[36m%s\033[m', req.method, req.url)
var pathname = url.parse(req.url).pathname,
path = join(process.cwd(), pathname)
function notFound() {
res.statusCode = 404
res.end("404 Not Found\n")
}
function error(err) {
res.statusCode = 500
res.end(err.message + "\n")
}
fs.exists(path, function(exists){
if (!exists) return notFound()
fs.stat(path, function(err, stat){
if (err) return error()
if (stat.isDirectory()) path = join(path, 'index.html')
res.setHeader('Cache-Control', 'no-cache')
res.setHeader('Content-Type', mime[path.split('.').slice(-1)] || 'application/octet-stream')
fs.createReadStream(path).pipe(res)
})
})
}).listen(port)
console.log('\n Server listening on %d\n', port)

133
book/node_modules/lunr/styles.css generated vendored Normal file
View File

@@ -0,0 +1,133 @@
body {
background-color: #081f28;
color: #708284;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-size: 18px;
}
h1 {
margin: 0;
padding: 0;
font-size: 4em;
}
a {
color: #2076c7;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
h2 {
font-weight: normal;
font-size: 1.2em;
}
h3 {
font-size: 2.6em;
margin: 0;
}
h1, h2 {
margin: 0;
}
header span {
font-size: 0.5em;
font-weight: normal;
}
nav ul {
margin: 0;
padding: 6px 0 0 3px;
}
nav li {
list-style: none;
display: inline;
padding-right: 12px;
font-weight: bold;
font-size: 0.9em;
}
footer ul {
list-style: none;
padding: 12px 0;
}
footer ul li {
float: left;
margin-right: 40px;
font-size: 0.8em;
font-weight: bold;
}
.wrap {
width: 960px;
margin: 20px auto 0 auto;
}
header {
border-top: 4px solid #708284;
padding: 4px 0 12px 0;
}
article header {
border-top: 2px solid #708284;
}
pre {
border-radius: 2px;
background-color: #03262f;
padding: 6px 0;
color: #819090;
}
p {
line-height: 1.4em;
}
section {
margin-top: 40px;
}
section.columns {
-webkit-column-count: 2;
-webkit-column-gap: 50px;
-webkit-hyphens: auto;
min-height: 720px;
font-size: 18px;
}
.download ul {
list-style: none;
padding: 0;
}
.download li {
font-size: 1.2em;
}
pre .keyword, pre .special {
font-weight: bold;
color: #2076c7
}
pre .string, pre .regexp {
color: #728a06
}
pre .class {
color: #A57707;
}
pre .number {
color: #D11c24
}
pre .comment {
color: grey;
font-style: italic;
}

748
book/node_modules/lunr/succinct_trie.js generated vendored Normal file
View File

@@ -0,0 +1,748 @@
/*
A Succinct Trie for Javascript
By Steve Hanov
Released to the public domain.
This file contains functions for creating a succinctly encoded trie structure
from a list of words. The trie is encoded to a succinct bit string using the
method of Jacobson (1989). The bitstring is then encoded using BASE-64.
The resulting trie does not have to be decoded to be used. This file also
contains functions for looking up a word in the BASE-64 encoded data, in
O(mlogn) time, where m is the number of letters in the target word, and n is
the number of nodes in the trie.
Objects for encoding:
TrieNode
Trie
BitWriter
Objects for decoding:
BitString
FrozenTrieNode
FrozenTrie
QUICK USAGE:
Suppose we let data be some output of the demo encoder:
var data = {
"nodeCount": 37,
"directory": "BMIg",
"trie": "v2qqqqqqqpIUn4A5JZyBZ4ggCKh55ZZgBA5ZZd5vIEl1wx8g8A"
};
var frozenTrie = new FrozenTrie( Data.trie, Data.directory, Data.nodeCount);
alert( frozenTrie.lookup( "hello" ) ); // outputs true
alert( frozenTrie.lookup( "kwijibo" ) ); // outputs false
*/
// Configure the bit writing and reading functions to work natively in BASE-64
// encoding. That way, we don't have to convert back and forth to bytes.
var BASE64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
/**
The width of each unit of the encoding, in bits. Here we use 6, for base-64
encoding.
*/
var W = 6;
/**
Returns the character unit that represents the given value. If this were
binary data, we would simply return id.
*/
function CHR(id)
{
return BASE64[id];
}
/**
Returns the decimal value of the given character unit.
*/
var BASE64_CACHE = {"A" : 0, "B" : 1, "C" : 2, "D" : 3, "E" : 4, "F" : 5, "G" :
6, "H" : 7, "I" : 8, "J" : 9, "K" : 10, "L" : 11, "M" : 12, "N" : 13, "O" :
14, "P" : 15, "Q" : 16, "R" : 17, "S" : 18, "T" : 19, "U" : 20, "V" :
21, "W" : 22, "X" : 23, "Y" : 24, "Z" : 25, "a" : 26, "b" : 27, "c" :
28, "d" : 29, "e" : 30, "f" : 31, "g" : 32, "h" : 33, "i" : 34, "j" :
35, "k" : 36, "l" : 37, "m" : 38, "n" : 39, "o" : 40, "p" : 41, "q" :
42, "r" : 43, "s" : 44, "t" : 45, "u" : 46, "v" : 47, "w" : 48, "x" :
49, "y" : 50, "z" : 51, "0" : 52, "1" : 53, "2" : 54, "3" : 55, "4" :
56, "5" : 57, "6" : 58, "7" : 59, "8" : 60, "9" : 61, "-" : 62, "_" :
63};
function ORD(ch)
{
// Used to be: return BASE64.indexOf(ch);
return BASE64_CACHE[ch];
}
/**
Fixed values for the L1 and L2 table sizes in the Rank Directory
*/
var L1 = 32*32;
var L2 = 32;
/**
The BitWriter will create a stream of bytes, letting you write a certain
number of bits at a time. This is part of the encoder, so it is not
optimized for memory or speed.
*/
function BitWriter()
{
this.init();
}
BitWriter.prototype =
{
init: function() {
this.bits = [];
},
/**
Write some data to the bit string. The number of bits must be 32 or
fewer.
*/
write: function( data, numBits ) {
for( var i = numBits - 1; i >= 0; i-- ) {
if ( data & ( 1 << i ) ) {
this.bits.push(1);
} else {
this.bits.push(0);
}
}
},
/**
Get the bitstring represented as a javascript string of bytes
*/
getData: function() {
var chars = [];
var b = 0;
var i = 0;
for ( var j = 0; j < this.bits.length; j++ ) {
b = ( b << 1 ) | this.bits[j];
i += 1;
if ( i === W ) {
chars.push( CHR(b) );
i = b = 0;
}
}
if ( i ) {
chars.push( CHR(b << ( W - i )) );
}
return chars.join("");
},
/**
Returns the bits as a human readable binary string for debugging
*/
getDebugString: function(group) {
var chars = [];
var i = 0;
for( var j = 0; j < this.bits.length; j++ ) {
chars.push( "" + this.bits[j] );
i++;
if ( i === group ) {
chars.push( ' ' );
i = 0;
}
}
return chars.join("");
}
};
/**
Given a string of data (eg, in BASE-64), the BitString class supports
reading or counting a number of bits from an arbitrary position in the
string.
*/
function BitString( str )
{
this.init( str );
}
BitString.MaskTop = [
0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00
];
BitString.BitsInByte = [
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2,
3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3,
3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,
4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,
3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,
6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4,
4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,
6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3,
4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6,
6, 7, 6, 7, 7, 8
];
BitString.prototype = {
init: function( str ) {
this.bytes = str;
this.length = this.bytes.length * W;
},
/**
Returns the internal string of bytes
*/
getData: function() {
return this.bytes;
},
/**
Returns a decimal number, consisting of a certain number, n, of bits
starting at a certain position, p.
*/
get: function( p, n ) {
// case 1: bits lie within the given byte
if ( ( p % W ) + n <= W ) {
return ( ORD( this.bytes[ p / W | 0 ] ) & BitString.MaskTop[ p % W ] ) >>
( W - p % W - n );
// case 2: bits lie incompletely in the given byte
} else {
var result = ( ORD( this.bytes[ p / W | 0 ] ) &
BitString.MaskTop[ p % W ] );
var l = W - p % W;
p += l;
n -= l;
while ( n >= W ) {
result = (result << W) | ORD( this.bytes[ p / W | 0 ] );
p += W;
n -= W;
}
if ( n > 0 ) {
result = (result << n) | ( ORD( this.bytes[ p / W | 0 ] ) >>
( W - n ) );
}
return result;
}
},
/**
Counts the number of bits set to 1 starting at position p and
ending at position p + n
*/
count: function( p, n ) {
var count = 0;
while( n >= 8 ) {
count += BitString.BitsInByte[ this.get( p, 8 ) ];
p += 8;
n -= 8;
}
return count + BitString.BitsInByte[ this.get( p, n ) ];
},
/**
Returns the number of bits set to 1 up to and including position x.
This is the slow implementation used for testing.
*/
rank: function( x ) {
var rank = 0;
for( var i = 0; i <= x; i++ ) {
if ( this.get(i, 1) ) {
rank++;
}
}
return rank;
}
};
/**
The rank directory allows you to build an index to quickly compute the
rank() and select() functions. The index can itself be encoded as a binary
string.
*/
function RankDirectory( directoryData, bitData, numBits, l1Size, l2Size )
{
this.init(directoryData, bitData, numBits, l1Size, l2Size);
}
/**
Used to build a rank directory from the given input string.
@param data A javascript string containing the data, as readable using the
BitString object.
@param numBits The number of bits to index.
@param l1Size The number of bits that each entry in the Level 1 table
summarizes. This should be a multiple of l2Size.
@param l2Size The number of bits that each entry in the Level 2 table
summarizes.
*/
RankDirectory.Create = function( data, numBits, l1Size, l2Size ) {
var bits = new BitString( data );
var p = 0;
var i = 0;
var count1 = 0, count2 = 0;
var l1bits = Math.ceil( Math.log( numBits ) / Math.log(2) );
var l2bits = Math.ceil( Math.log( l1Size ) / Math.log(2) );
var directory = new BitWriter();
while( p + l2Size <= numBits ) {
count2 += bits.count( p, l2Size );
i += l2Size;
p += l2Size;
if ( i === l1Size ) {
count1 += count2;
directory.write( count1, l1bits );
count2 = 0;
i = 0;
} else {
directory.write( count2, l2bits );
}
}
return new RankDirectory( directory.getData(), data, numBits, l1Size, l2Size );
};
RankDirectory.prototype = {
init: function( directoryData, bitData, numBits, l1Size, l2Size ) {
this.directory = new BitString( directoryData );
this.data = new BitString( bitData );
this.l1Size = l1Size;
this.l2Size = l2Size;
this.l1Bits = Math.ceil( Math.log( numBits ) / Math.log( 2 ) );
this.l2Bits = Math.ceil( Math.log( l1Size ) / Math.log( 2 ) );
this.sectionBits = (l1Size / l2Size - 1) * this.l2Bits + this.l1Bits;
this.numBits = numBits;
},
/**
Returns the string representation of the directory.
*/
getData: function() {
return this.directory.getData();
},
/**
Returns the number of 1 or 0 bits (depending on the "which" parameter) to
to and including position x.
*/
rank: function( which, x ) {
if ( which === 0 ) {
return x - this.rank( 1, x ) + 1;
}
var rank = 0;
var o = x;
var sectionPos = 0;
if ( o >= this.l1Size ) {
sectionPos = ( o / this.l1Size | 0 ) * this.sectionBits;
rank = this.directory.get( sectionPos - this.l1Bits, this.l1Bits );
o = o % this.l1Size;
}
if ( o >= this.l2Size ) {
sectionPos += ( o / this.l2Size | 0 ) * this.l2Bits;
rank += this.directory.get( sectionPos - this.l2Bits, this.l2Bits );
}
rank += this.data.count( x - x % this.l2Size, x % this.l2Size + 1 );
return rank;
},
/**
Returns the position of the y'th 0 or 1 bit, depending on the "which"
parameter.
*/
select: function( which, y ) {
var high = this.numBits;
var low = -1;
var val = -1;
while ( high - low > 1 ) {
var probe = (high + low) / 2 | 0;
var r = this.rank( which, probe );
if ( r === y ) {
// We have to continue searching after we have found it,
// because we want the _first_ occurrence.
val = probe;
high = probe;
} else if ( r < y ) {
low = probe;
} else {
high = probe;
}
}
return val;
}
};
/**
A Trie node, for use in building the encoding trie. This is not needed for
the decoder.
*/
function TrieNode( letter )
{
this.letter = letter;
this.final = false;
this.children = [];
}
function Trie()
{
this.init();
}
Trie.prototype = {
init: function() {
this.previousWord = "";
this.root = new TrieNode(' ');
this.cache = [ this.root ];
this.nodeCount = 1;
},
/**
Returns the number of nodes in the trie
*/
getNodeCount: function() {
return this.nodeCount;
},
/**
Inserts a word into the trie. This function is fastest if the words are
inserted in alphabetical order.
*/
insert: function( word ) {
var commonPrefix = 0;
for( var i = 0; i < Math.min( word.length, this.previousWord.length );
i++ )
{
if ( word[i] !== this.previousWord[i] ) { break; }
commonPrefix += 1;
}
this.cache.length = commonPrefix + 1;
var node = this.cache[ this.cache.length - 1 ];
for( i = commonPrefix; i < word.length; i++ ) {
var next = new TrieNode( word[i] );
this.nodeCount++;
node.children.push( next );
this.cache.push( next );
node = next;
}
node.final = true;
this.previousWord = word;
},
/**
Apply a function to each node, traversing the trie in level order.
*/
apply: function( fn )
{
var level = [ this.root ];
while( level.length > 0 ) {
var node = level.shift();
for( var i = 0; i < node.children.length; i++ ) {
level.push( node.children[i] );
}
fn( node );
}
},
/**
Encode the trie and all of its nodes. Returns a string representing the
encoded data.
*/
encode: function()
{
// Write the unary encoding of the tree in level order.
var bits = new BitWriter();
bits.write( 0x02, 2 );
this.apply( function( node ) {
for( var i = 0; i < node.children.length; i++ ) {
bits.write( 1, 1 );
}
bits.write( 0, 1 );
});
// Write the data for each node, using 6 bits for node. 1 bit stores
// the "final" indicator. The other 5 bits store one of the 26 letters
// of the alphabet.
var a = ("a").charCodeAt(0);
this.apply( function( node ) {
var value = node.letter.charCodeAt(0) - a;
if ( node.final ) {
value |= 0x20;
}
bits.write( value, 6 );
});
return bits.getData();
}
};
/**
This class is used for traversing the succinctly encoded trie.
*/
function FrozenTrieNode( trie, index, letter, final, firstChild, childCount )
{
this.trie = trie;
this.index = index;
this.letter = letter;
this.final = final;
this.firstChild = firstChild;
this.childCount = childCount;
}
FrozenTrieNode.prototype = {
/**
Returns the number of children.
*/
getChildCount: function()
{
return this.childCount;
},
/**
Returns the FrozenTrieNode for the given child.
@param index The 0-based index of the child of this node. For example, if
the node has 5 children, and you wanted the 0th one, pass in 0.
*/
getChild: function(index)
{
return this.trie.getNodeByIndex( this.firstChild + index );
}
};
/**
The FrozenTrie is used for looking up words in the encoded trie.
@param data A string representing the encoded trie.
@param directoryData A string representing the RankDirectory. The global L1
and L2 constants are used to determine the L1Size and L2size.
@param nodeCount The number of nodes in the trie.
*/
function FrozenTrie( data, directoryData, nodeCount )
{
this.init( data, directoryData, nodeCount );
}
FrozenTrie.prototype = {
init: function( data, directoryData, nodeCount )
{
this.data = new BitString( data );
this.directory = new RankDirectory( directoryData, data,
nodeCount * 2 + 1, L1, L2 );
// The position of the first bit of the data in 0th node. In non-root
// nodes, this would contain 6-bit letters.
this.letterStart = nodeCount * 2 + 1;
},
/**
Retrieve the FrozenTrieNode of the trie, given its index in level-order.
This is a private function that you don't have to use.
*/
getNodeByIndex: function( index )
{
// retrieve the 6-bit letter.
var final = this.data.get( this.letterStart + index * 6, 1 ) === 1;
var letter = String.fromCharCode(
this.data.get( this.letterStart + index * 6 + 1, 5 ) +
'a'.charCodeAt(0));
var firstChild = this.directory.select( 0, index+1 ) - index;
// Since the nodes are in level order, this nodes children must go up
// until the next node's children start.
var childOfNextNode = this.directory.select( 0, index + 2 ) - index - 1;
return new FrozenTrieNode( this, index, letter, final, firstChild,
childOfNextNode - firstChild );
},
/**
Retrieve the root node. You can use this node to obtain all of the other
nodes in the trie.
*/
getRoot: function()
{
return this.getNodeByIndex( 0 );
},
/**
Look-up a word in the trie. Returns true if and only if the word exists
in the trie.
*/
lookup: function( word )
{
var node = this.getRoot();
for ( var i = 0; i < word.length; i++ ) {
var child;
var j = 0;
for ( ; j < node.getChildCount(); j++ ) {
child = node.getChild( j );
if ( child.letter === word[i] ) {
break;
}
}
if ( j === node.getChildCount() ) {
return false;
}
node = child;
}
return node.final;
}
};
/**************************************************************************************************
DEMONSTATION APPLICATION FUNCTIONS
*************************************************************************************************/
/**
Load a dictionary asynchronously.
*/
function loadDictionary()
{
var xmlHttpReq;
try {
xmlHttpReq = new XMLHttpRequest();
} catch ( trymicrosoft ) {
try {
xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch(othermicrosoft) {
try {
xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch(failed) {
xmlHttpReq = null;
}
}
}
strUrl = "ospd3.txt";
xmlHttpReq.open("GET", "ospd3.txt", true);
xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xmlHttpReq.onreadystatechange = function() {
if (xmlHttpReq.readyState === 4) {
if (xmlHttpReq.status === 200 ) {
document.getElementById("input").value =
xmlHttpReq.responseText;
} else if ( xmlHttpReq.message ) {
alert( xmlHttpReq.message );
} else {
alert( "Network error. Check internet connection" );
}
}
};
xmlHttpReq.send("");
}
/**
Encode the trie in the input text box.
*/
function go()
{
// create a trie
var trie = new Trie();
// split the words of the input up. Sort them for faster trie insertion.
var words = document.getElementById("input").value.split(/\s+/);
words.sort();
var regex = /^[a-z]+$/;
for ( var i = 0; i < words.length; i++ ) {
// To save space, our encoding handles only the letters a-z. Ignore
// words that contain other characters.
var word = words[i].toLowerCase();
if ( word.match( /^[a-z]+$/ ) ) {
trie.insert( word );
}
}
// Encode the trie.
var trieData = trie.encode();
// Encode the rank directory
var directory = RankDirectory.Create( trieData, trie.getNodeCount() * 2 +
1, L1, L2 );
var output;
output = '{\n "nodeCount": ' + trie.getNodeCount() + ",\n";
output += ' "directory": "' + directory.getData() + '",\n';
output += ' "trie": "' + trieData + '"\n';
output += "}\n";
document.getElementById("output").value = output;
document.getElementById("encodeStatus").innerHTML =
"Encoded " + document.getElementById("input").value.length +
" bytes to " + output.length + " bytes.";
}
/**
Decode the data in the output textarea, and use it to check if a word exists
in the dictionary.
*/
function lookup()
{
var status = "";
try
{
var json = eval( '(' + document.getElementById("output").value + ")" );
var ftrie = new FrozenTrie( json.trie, json.directory, json.nodeCount
);
var word = document.getElementById("lookup").value;
if ( ftrie.lookup( document.getElementById("lookup").value ) ) {
status = '"' + word + "' is in the dictionary.";
} else {
status = '"' + word + "' IS NOT in the dictionary.";
}
} catch ( e ) {
status = "Error. Have you encoded the dictionary yet?";
}
document.getElementById("status").innerHTML = status;
}

8
book/node_modules/lunr/test/env/augment.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

16
book/node_modules/lunr/test/env/jquery.js generated vendored Normal file

File diff suppressed because one or more lines are too long

235
book/node_modules/lunr/test/env/qunit.css generated vendored Normal file
View File

@@ -0,0 +1,235 @@
/**
* QUnit v1.10.0 - A JavaScript Unit Testing Framework
*
* http://qunitjs.com
*
* Copyright 2012 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
-webkit-border-top-right-radius: 5px;
-webkit-border-top-left-radius: 5px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-testrunner-toolbar label {
display: inline-block;
padding: 0 .5em 0 .1em;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
overflow: hidden;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
#qunit-modulefilter-container {
float: right;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
padding: 5px;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #3c510c;
background-color: #fff;
border-left: 10px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 10px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
#qunit-testresult .module-name {
font-weight: bold;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}

1977
book/node_modules/lunr/test/env/qunit.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

125
book/node_modules/lunr/test/env/runner.js generated vendored Normal file
View File

@@ -0,0 +1,125 @@
/*
* QtWebKit-powered headless test runner using PhantomJS
*
* PhantomJS binaries: http://phantomjs.org/download.html
* Requires PhantomJS 1.6+ (1.7+ recommended)
*
* Run with:
* phantomjs runner.js [url-of-your-qunit-testsuite]
*
* e.g.
* phantomjs runner.js http://localhost/qunit/test/index.html
*/
(function() {
'use strict';
var args = require('system').args;
// arg[0]: scriptName, args[1...]: arguments
if (args.length !== 2) {
console.error('Usage:\n phantomjs runner.js [url-of-your-qunit-testsuite]');
phantom.exit(1);
}
var url = args[1],
page = require('webpage').create();
// Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`)
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.onInitialized = function() {
page.evaluate(addLogging);
};
page.onCallback = function(message) {
var result,
failed;
if (message) {
if (message.name === 'QUnit.done') {
result = message.data;
failed = !result || result.failed;
phantom.exit(failed ? 1 : 0);
}
}
};
page.open(url, function(status) {
if (status !== 'success') {
console.error('Unable to access network: ' + status);
phantom.exit(1);
} else {
// Cannot do this verification with the 'DOMContentLoaded' handler because it
// will be too late to attach it if a page does not have any script tags.
var qunitMissing = page.evaluate(function() { return (typeof QUnit === 'undefined' || !QUnit); });
if (qunitMissing) {
console.error('The `QUnit` object is not present on this page.');
phantom.exit(1);
}
// Do nothing... the callback mechanism will handle everything!
}
});
function addLogging() {
window.document.addEventListener('DOMContentLoaded', function() {
var current_test_assertions = [];
QUnit.log(function(details) {
var response;
// Ignore passing assertions
if (details.result) {
return;
}
response = details.message || '';
if (typeof details.expected !== 'undefined') {
if (response) {
response += ', ';
}
response += 'expected: ' + details.expected + ', but was: ' + details.actual;
if (details.source) {
response += "\n" + details.source;
}
}
current_test_assertions.push('Failed assertion: ' + response);
});
QUnit.testDone(function(result) {
var i,
len,
name = result.module + ': ' + result.name;
if (result.failed) {
console.log('Test failed: ' + name);
for (i = 0, len = current_test_assertions.length; i < len; i++) {
console.log(' ' + current_test_assertions[i]);
}
}
current_test_assertions.length = 0;
});
QUnit.done(function(result) {
console.log('Took ' + result.runtime + 'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.');
if (typeof window.callPhantom === 'function') {
window.callPhantom({
'name': 'QUnit.done',
'data': result
});
}
});
}, false);
}
})();

75
book/node_modules/lunr/test/event_emitter_test.js generated vendored Normal file
View File

@@ -0,0 +1,75 @@
module('lunr.EventEmitter')
test('adding an event listener', function () {
var emitter = new lunr.EventEmitter,
handler = function () {}
emitter.addListener('test', handler)
ok('test' in emitter.events)
ok(emitter.events.test.indexOf(handler) > -1)
})
test('adding a listener to multiple events', function () {
var emitter = new lunr.EventEmitter,
handler = function () {}
emitter.addListener('foo', 'bar', 'baz', handler)
ok('foo' in emitter.events)
ok('bar' in emitter.events)
ok('baz' in emitter.events)
ok(emitter.events.foo.indexOf(handler) > -1)
ok(emitter.events.bar.indexOf(handler) > -1)
ok(emitter.events.baz.indexOf(handler) > -1)
})
test('removing a single event listener', function () {
var emitter = new lunr.EventEmitter,
handler = function () {}
emitter.addListener('test', handler)
ok('test' in emitter.events)
ok(emitter.events.test.indexOf(handler) > -1)
emitter.removeListener('test', handler)
ok(!('test' in emitter.events))
})
test('removing a single event listener from many listeners', function () {
var emitter = new lunr.EventEmitter,
handler = function () {},
otherHandler = function () {}
emitter.addListener('test', handler)
emitter.addListener('test', otherHandler)
ok('test' in emitter.events)
ok(emitter.events.test.indexOf(handler) > -1)
emitter.removeListener('test', handler)
ok('test' in emitter.events)
equal(emitter.events.test.indexOf(handler), -1)
ok(emitter.events.test.indexOf(otherHandler) > -1)
})
test('emitting events', function () {
var emitter = new lunr.EventEmitter,
callbackCalled = false,
callbackArguments = [],
callback = function () {
callbackArguments = Array.prototype.slice.call(arguments)
callbackCalled = true
}
emitter.emit('test', 1, 'a')
emitter.addListener('test', callback)
emitter.emit('test', 1, 'a')
ok(callbackCalled)
deepEqual(callbackArguments, [1, 'a'])
})

View File

@@ -0,0 +1 @@
var stemmingFixture = {"consign":"consign","consigned":"consign","consigning":"consign","consignment":"consign","consist":"consist","consisted":"consist","consistency":"consist","consistent":"consist","consistently":"consist","consisting":"consist","consists":"consist","consolation":"consol","consolations":"consol","consolatory":"consolatori","console":"consol","consoled":"consol","consoles":"consol","consolidate":"consolid","consolidated":"consolid","consolidating":"consolid","consoling":"consol","consols":"consol","consonant":"conson","consort":"consort","consorted":"consort","consorting":"consort","conspicuous":"conspicu","conspicuously":"conspicu","conspiracy":"conspiraci","conspirator":"conspir","conspirators":"conspir","conspire":"conspir","conspired":"conspir","conspiring":"conspir","constable":"constabl","constables":"constabl","constance":"constanc","constancy":"constanc","constant":"constant","knack":"knack","knackeries":"knackeri","knacks":"knack","knag":"knag","knave":"knave","knaves":"knave","knavish":"knavish","kneaded":"knead","kneading":"knead","knee":"knee","kneel":"kneel","kneeled":"kneel","kneeling":"kneel","kneels":"kneel","knees":"knee","knell":"knell","knelt":"knelt","knew":"knew","knick":"knick","knif":"knif","knife":"knife","knight":"knight","knights":"knight","knit":"knit","knits":"knit","knitted":"knit","knitting":"knit","knives":"knive","knob":"knob","knobs":"knob","knock":"knock","knocked":"knock","knocker":"knocker","knockers":"knocker","knocking":"knock","knocks":"knock","knopp":"knopp","knot":"knot","knots":"knot","lay":"lay","try":"tri"}

52
book/node_modules/lunr/test/index.html generated vendored Normal file
View File

@@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Lunr tests</title>
<!-- dependencies -->
<script src="/test/env/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="/test/env/augment.min.js" type="text/javascript" charset="utf-8"></script>
<!-- QUnit -->
<script src="/test/env/qunit.js"></script>
<link rel="stylesheet" href="/test/env/qunit.css" type="text/css" media="screen" />
<!-- Lunr -->
<script src="/lib/lunr.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/utils.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/tokenizer.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/pipeline.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/vector.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/sorted_set.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/event_emitter.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/index.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/document_store.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/stemmer.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/stop_word_filter.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/trimmer.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/token_store.js" type="text/javascript" charset="utf-8"></script>
<!-- Fixtures -->
<script src="/test/fixtures/stemming_vocab.json"></script>
<!-- Tests -->
<script src="/test/tokenizer_test.js"></script>
<script src="/test/pipeline_test.js"></script>
<script src="/test/vector_test.js"></script>
<script src="/test/sorted_set_test.js"></script>
<script src="/test/event_emitter_test.js"></script>
<script src="/test/index_test.js"></script>
<script src="/test/store_test.js"></script>
<script src="/test/search_test.js"></script>
<script src="/test/serialisation_test.js"></script>
<script src="/test/stemmer_test.js"></script>
<script src="/test/stop_word_filter_test.js"></script>
<script src="/test/lunr_test.js"></script>
<script src="/test/token_store_test.js"></script>
<script src="/test/trimmer_test.js"></script>
</head>
<body>
<div id="qunit"></div>
</body>
</html>

336
book/node_modules/lunr/test/index_test.js generated vendored Normal file
View File

@@ -0,0 +1,336 @@
module('lunr.Index')
test("defining what fields to index", function () {
var idx = new lunr.Index
idx.field('foo')
deepEqual(idx._fields[0], {name: 'foo', boost: 1})
})
test("giving a particular field a weighting", function () {
var idx = new lunr.Index
idx.field('foo', { boost: 10 })
deepEqual(idx._fields[0], {name: 'foo', boost: 10})
})
test('default reference should be id', function () {
var idx = new lunr.Index
equal(idx._ref, 'id')
})
test("defining the reference field for the index", function () {
var idx = new lunr.Index
idx.ref('foo')
deepEqual(idx._ref, 'foo')
})
test('adding a document to the index', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'this is a test'}
idx.field('body')
idx.add(doc)
equal(idx.documentStore.length, 1)
ok(!!idx.documentStore.get(1))
})
test('adding a document with an empty field', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'test', title: ''}
idx.field('title')
idx.field('body')
idx.add(doc)
ok(!isNaN(idx.tokenStore.get('test')[1].tf))
})
test('ignore empty tokens', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'test ???'}
idx.field('body')
idx.pipeline.add(lunr.trimmer)
idx.add(doc)
var tokens = idx.documentStore.get(1).toArray()
equal(tokens.length, 1)
deepEqual(tokens, ['test']) // ??? should be ignored
})
test('triggering add events', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'this is a test'},
callbackCalled = false,
callbackArgs = []
idx.on('add', function (doc, index) {
callbackCalled = true
callbackArgs = Array.prototype.slice.call(arguments)
})
idx.field('body')
idx.add(doc)
ok(callbackCalled)
equal(callbackArgs.length, 2)
deepEqual(callbackArgs[0], doc)
deepEqual(callbackArgs[1], idx)
})
test('silencing add events', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'this is a test'},
callbackCalled = false,
callbackArgs = []
idx.on('add', function (doc, index) {
callbackCalled = true
callbackArgs = Array.prototype.slice.call(arguments)
})
idx.field('body')
idx.add(doc, false)
ok(!callbackCalled)
})
test('removing a document from the index', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'this is a test'}
idx.field('body')
equal(idx.documentStore.length, 0)
idx.add(doc)
equal(idx.documentStore.length, 1)
idx.remove(doc)
equal(idx.documentStore.length, 0)
})
test('triggering remove events', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'this is a test'},
callbackCalled = false,
callbackArgs = []
idx.on('remove', function (doc, index) {
callbackCalled = true
callbackArgs = Array.prototype.slice.call(arguments)
})
idx.field('body')
idx.add(doc)
idx.remove(doc)
ok(callbackCalled)
equal(callbackArgs.length, 2)
deepEqual(callbackArgs[0], doc)
deepEqual(callbackArgs[1], idx)
})
test('silencing remove events', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'this is a test'},
callbackCalled = false,
callbackArgs = []
idx.on('remove', function (doc, index) {
callbackCalled = true
callbackArgs = Array.prototype.slice.call(arguments)
})
idx.field('body')
idx.add(doc)
idx.remove(doc, false)
ok(!callbackCalled)
})
test('removing a non-existent document from the index', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'this is a test'},
doc2 = {id: 2, body: 'i dont exist'},
callbackCalled = false
idx.on('remove', function (doc, index) {
callbackCalled = true
})
idx.field('body')
equal(idx.documentStore.length, 0)
idx.add(doc)
equal(idx.documentStore.length, 1)
idx.remove(doc2)
equal(idx.documentStore.length, 1)
ok(!callbackCalled)
})
test('updating a document', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'foo'}
idx.field('body')
idx.add(doc)
equal(idx.documentStore.length, 1)
ok(idx.tokenStore.has('foo'))
doc.body = 'bar'
idx.update(doc)
equal(idx.documentStore.length, 1)
ok(idx.tokenStore.has('bar'))
})
test('emitting update events', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'foo'},
addCallbackCalled = false,
removeCallbackCalled = false,
updateCallbackCalled = false,
callbackArgs = []
idx.field('body')
idx.add(doc)
equal(idx.documentStore.length, 1)
ok(idx.tokenStore.has('foo'))
idx.on('update', function (doc, index) {
updateCallbackCalled = true
callbackArgs = Array.prototype.slice.call(arguments)
})
idx.on('add', function () {
addCallbackCalled = true
})
idx.on('remove', function () {
removeCallbackCalled = true
})
doc.body = 'bar'
idx.update(doc)
ok(updateCallbackCalled)
equal(callbackArgs.length, 2)
deepEqual(callbackArgs[0], doc)
deepEqual(callbackArgs[1], idx)
ok(!addCallbackCalled)
ok(!removeCallbackCalled)
})
test('silencing update events', function () {
var idx = new lunr.Index,
doc = {id: 1, body: 'foo'},
callbackCalled = false
idx.field('body')
idx.add(doc)
equal(idx.documentStore.length, 1)
ok(idx.tokenStore.has('foo'))
idx.on('update', function (doc, index) {
callbackCalled = true
})
doc.body = 'bar'
idx.update(doc, false)
ok(!callbackCalled)
})
test('serialising', function () {
var idx = new lunr.Index,
mockDocumentStore = { toJSON: function () { return 'documentStore' }},
mockTokenStore = { toJSON: function () { return 'tokenStore' }},
mockCorpusTokens = { toJSON: function () { return 'corpusTokens' }},
mockPipeline = { toJSON: function () { return 'pipeline' }}
idx.documentStore = mockDocumentStore
idx.tokenStore = mockTokenStore
idx.corpusTokens = mockCorpusTokens
idx.pipeline = mockPipeline
idx.ref('id')
idx.field('title', { boost: 10 })
idx.field('body')
deepEqual(idx.toJSON(), {
version: '@VERSION', // this is what the lunr version is set to before being built
fields: [
{ name: 'title', boost: 10 },
{ name: 'body', boost: 1 }
],
ref: 'id',
documentStore: 'documentStore',
tokenStore: 'tokenStore',
corpusTokens: 'corpusTokens',
pipeline: 'pipeline'
})
})
test('loading a serialised index', function () {
var serialisedData = {
version: '@VERSION', // this is what the lunr version is set to before being built
fields: [
{ name: 'title', boost: 10 },
{ name: 'body', boost: 1 }
],
ref: 'id',
documentStore: { store: {}, length: 0 },
tokenStore: { root: {}, length: 0 },
corpusTokens: [],
pipeline: ['stopWordFilter', 'stemmer']
}
var idx = lunr.Index.load(serialisedData)
deepEqual(idx._fields, serialisedData.fields)
equal(idx._ref, 'id')
})
test('idf cache with reserved words', function () {
var idx = new lunr.Index
var troublesomeTokens = [
'constructor',
'__proto__',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'toLocaleString',
'toString',
'valueOf'
]
troublesomeTokens.forEach(function (token) {
equal(typeof(idx.idf(token)), 'number', 'Using token: ' + token)
})
})
test('using a plugin', function () {
var idx = new lunr.Index,
ctx, args,
plugin = function () {
ctx = this
args = Array.prototype.slice.call(arguments)
this.pluginLoaded = true
}
idx.use(plugin, 'foo', 'bar')
equal(ctx, idx)
deepEqual(args, [idx, 'foo', 'bar'])
ok(idx.pluginLoaded)
})

37
book/node_modules/lunr/test/lunr_test.js generated vendored Normal file
View File

@@ -0,0 +1,37 @@
module('lunr')
test('returns a new instance of lunr.Index', function () {
var index = lunr()
equal(index.constructor, lunr.Index)
})
test('should set up the pipeline', function () {
var index = lunr(),
stack = index.pipeline._stack
equal(stack.length, 3)
equal(stack.indexOf(lunr.trimmer), 0)
equal(stack.indexOf(lunr.stopWordFilter), 1)
equal(stack.indexOf(lunr.stemmer), 2)
})
test('passing a config fn which is called with the new index', function () {
var configCtx, configArg
var index = lunr(function (idx) {
configCtx = this
configArg = idx
this.ref('cid')
this.field('title', 10)
this.field('body')
})
equal(configCtx, index)
equal(configArg, index)
equal(index._ref, 'cid')
equal(index._fields.length, 2)
})

227
book/node_modules/lunr/test/pipeline_test.js generated vendored Normal file
View File

@@ -0,0 +1,227 @@
module('lunr.Pipeline', {
setup: function () {
this.existingRegisteredFunctions = lunr.Pipeline.registeredFunctions
lunr.Pipeline.registeredFunctions = {}
this.existingWarnIfFunctionNotRegistered = lunr.Pipeline.warnIfFunctionNotRegistered
lunr.Pipeline.warnIfFunctionNotRegistered = $.noop
},
teardown: function () {
lunr.Pipeline.registeredFunctions = this.existingRegisteredFunctions
lunr.Pipeline.warnIfFunctionNotRegistered = this.existingWarnIfFunctionNotRegistered
}
})
test("adding a new item to the pipeline", function () {
var pipeline = new lunr.Pipeline
equal(pipeline._stack.length, 0)
pipeline.add($.noop)
equal(pipeline._stack.length, 1)
})
test("adding multiple items to the pipeline in one go", function () {
var pipeline = new lunr.Pipeline
pipeline.add($.noop, $.noop)
equal(pipeline._stack.length, 2)
})
test("removing an item from the pipeline", function () {
var pipeline = new lunr.Pipeline,
fn = $.noop
pipeline.add(fn)
equal(pipeline._stack.length, 1)
pipeline.remove(fn)
equal(pipeline._stack.length, 0)
})
test("removing a nonexistent item from the pipeline", function () {
var pipeline = new lunr.Pipeline,
fn1 = $.noop,
fn2 = function () {}
pipeline.add(fn1)
equal(pipeline._stack.length, 1)
pipeline.remove(fn2)
equal(pipeline._stack.length, 1)
})
test("adding an item to the pipeline before another item", function () {
var pipeline = new lunr.Pipeline,
fn1 = $.noop,
fn2 = function () {}
pipeline.add(fn1)
pipeline.before(fn1, fn2)
deepEqual(pipeline._stack, [fn2, fn1])
})
test("adding an item to the pipeline before nonexistent item", function () {
var pipeline = new lunr.Pipeline,
fn1 = $.noop,
fn2 = function () {},
fn3 = function () {}
pipeline.add(fn1, fn2)
throws(function () {
pipeline.before(fn3, fn1)
})
deepEqual(pipeline._stack, [fn1, fn2])
})
test("adding an item to the pipeline after another item", function () {
var pipeline = new lunr.Pipeline,
fn1 = $.noop,
fn2 = function () {},
fn3 = function () {}
pipeline.add(fn1, fn2)
pipeline.after(fn1, fn3)
deepEqual(pipeline._stack, [fn1, fn3, fn2])
})
test("adding an item to the pipeline after nonexistent item", function () {
var pipeline = new lunr.Pipeline,
fn1 = $.noop,
fn2 = function () {},
fn3 = function () {}
pipeline.add(fn1, fn2)
throws(function () {
pipeline.after(fn3, fn1)
})
deepEqual(pipeline._stack, [fn1, fn2])
})
test("run calls each member of the pipeline for each input", function () {
var pipeline = new lunr.Pipeline,
count1 = 0, count2 = 0,
fn1 = function (token) { count1++ ; return token },
fn2 = function (token) { count2++ ; return token }
pipeline.add(fn1, fn2)
pipeline.run([1,2,3])
equal(count1, 3)
equal(count2, 3)
})
test("run should pass three inputs to the pipeline fn", function () {
var pipeline = new lunr.Pipeline,
input, index, arr,
fn1 = function () { input = arguments[0], index = arguments[1], arr = arguments[2] }
pipeline.add(fn1)
pipeline.run(['a'])
equal(input, 'a')
equal(index, 0)
deepEqual(arr, ['a'])
})
test("run should pass the output of one into the input of the next", function () {
var pipeline = new lunr.Pipeline,
output,
fn1 = function (t1) { return t1.toUpperCase() },
fn2 = function (t2) { output = t2 }
pipeline.add(fn1)
pipeline.add(fn2)
pipeline.run(['a'])
equal(output, 'A')
})
test("run should return the result of running the entire pipeline on each element", function () {
var pipeline = new lunr.Pipeline,
fn1 = function (t1) { return t1.toUpperCase() }
pipeline.add(fn1)
deepEqual(pipeline.run(['a']), ['A'])
})
test("run should filter out any undefined values at each stage in the pipeline", function () {
var pipeline = new lunr.Pipeline,
fn2Count = 0,
fn1 = function (t) { if (t < 5) return t },
fn2 = function (t) { fn2Count++ ; return t }
pipeline.add(fn1, fn2)
var output = pipeline.run([0,1,2,3,4,5,6,7,8,9])
equal(fn2Count, 5)
equal(output.length, 5)
})
test('toJSON', function () {
var pipeline = new lunr.Pipeline,
fn1 = function () {},
fn2 = function () {}
lunr.Pipeline.registerFunction(fn1, 'fn1')
lunr.Pipeline.registerFunction(fn2, 'fn2')
pipeline.add(fn1, fn2)
deepEqual(pipeline.toJSON(), ['fn1', 'fn2'])
})
test('registering a pipeline function', function () {
var fn1 = function () {}
equal(Object.keys(lunr.Pipeline.registeredFunctions).length, 0)
lunr.Pipeline.registerFunction(fn1, 'fn1')
equal(fn1.label, 'fn1')
equal(Object.keys(lunr.Pipeline.registeredFunctions).length, 1)
deepEqual(lunr.Pipeline.registeredFunctions['fn1'], fn1)
})
test('load', function () {
var fn1 = function () {},
fn2 = function () {}
lunr.Pipeline.registerFunction(fn1, 'fn1')
lunr.Pipeline.registerFunction(fn2, 'fn2')
var serialised = ['fn1', 'fn2']
var pipeline = lunr.Pipeline.load(serialised)
equal(pipeline._stack.length, 2)
deepEqual(pipeline._stack[0], fn1)
deepEqual(pipeline._stack[1], fn2)
})
test('loading an un-registered pipeline function', function () {
var serialised = ['fn1']
throws(function () {
lunr.Pipeline.load(serialised)
})
})
test('resetting the pipeline', function () {
var fn1 = function () {},
fn2 = function () {},
pipeline = new lunr.Pipeline
pipeline.add(fn1, fn2)
deepEqual(pipeline._stack, [fn1, fn2])
pipeline.reset()
deepEqual(pipeline._stack, [])
})

9
book/node_modules/lunr/test/runner.sh generated vendored Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
NODE=/usr/local/bin/node
PHANTOMJS=./node_modules/.bin/phantomjs
SERVER_PORT=${1:-54545}
echo "Starting test server at http://localhost:$SERVER_PORT"
$NODE server.js "$SERVER_PORT" > /dev/null 2>&1 &
$PHANTOMJS ./test/env/runner.js "http://localhost:$SERVER_PORT/test" 2> /dev/null

77
book/node_modules/lunr/test/search_test.js generated vendored Normal file
View File

@@ -0,0 +1,77 @@
module('search', {
setup: function () {
var idx = new lunr.Index
idx.field('body')
idx.field('title', { boost: 10 })
;([{
id: 'a',
title: 'Mr. Green kills Colonel Mustard',
body: 'Mr. Green killed Colonel Mustard in the study with the candlestick. Mr. Green is not a very nice fellow.',
wordCount: 19
},{
id: 'b',
title: 'Plumb waters plant',
body: 'Professor Plumb has a green plant in his study',
wordCount: 9
},{
id: 'c',
title: 'Scarlett helps Professor',
body: 'Miss Scarlett watered Professor Plumbs green plant while he was away from his office last week.',
wordCount: 16
},{
id: 'd',
title: 'title',
body: 'handsome',
},{
id: 'e',
title: 'title',
body: 'hand',
}]).forEach(function (doc) { idx.add(doc) })
this.idx = idx
}
})
test('returning the correct results', function () {
var results = this.idx.search('green plant')
equal(results.length, 2)
equal(results[0].ref, 'b')
})
test('search term not in the index', function () {
var results = this.idx.search('foo')
equal(results.length, 0)
})
test('one search term not in the index', function () {
var results = this.idx.search('foo green')
equal(results.length, 0)
})
test('search contains one term not in the index', function () {
var results = this.idx.search('green foo')
equal(results.length, 0)
})
test('search takes into account boosts', function () {
var results = this.idx.search('professor')
equal(results.length, 2)
equal(results[0].ref, 'c')
ok(results[0].score > 10 * results[1].score)
})
test('search boosts exact matches', function () {
var results = this.idx.search('hand')
equal(results.length, 2)
equal(results[0].ref, 'e')
ok(results[0].score > results[1].score)
})

46
book/node_modules/lunr/test/serialisation_test.js generated vendored Normal file
View File

@@ -0,0 +1,46 @@
module('serialisation', {
setup: function () {
this.corpus = [{
id: 'a',
title: 'Mr. Green kills Colonel Mustard',
body: 'Mr. Green killed Colonel Mustard in the study with the candlestick. Mr. Green is not a very nice fellow.'
},{
id: 'b',
title: 'Plumb waters plant',
body: 'Professor Plumb has a green plant in his study'
},{
id: 'c',
title: 'Scarlett helps Professor',
body: 'Miss Scarlett watered Professor Plumbs green plant while he was away from his office last week.'
}]
}
})
test('dumping and loading an index', function () {
var idx = new lunr.Index
idx.field('title', { boost: 10 })
idx.field('body')
this.corpus.forEach(function (doc) { idx.add(doc) })
var dumpedIdx = JSON.stringify(idx),
clonedIdx = lunr.Index.load(JSON.parse(dumpedIdx))
deepEqual(idx.search('green plant'), clonedIdx.search('green plant'))
})
test('dumping and loading an index with a populated pipeline', function () {
var idx = lunr(function () {
this.field('title', { boost: 10 })
this.field('body')
})
this.corpus.forEach(function (doc) { idx.add(doc) })
var dumpedIdx = JSON.stringify(idx),
clonedIdx = lunr.Index.load(JSON.parse(dumpedIdx))
deepEqual(idx.pipeline._stack, clonedIdx.pipeline._stack)
deepEqual(idx.search('water'), clonedIdx.search('water'))
})

21
book/node_modules/lunr/test/size.html generated vendored Normal file
View File

@@ -0,0 +1,21 @@
<script src="/test/env/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="/words.json"></script>
<script src="/lib/lunr.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/token_store.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/reverse_index.js" type="text/javascript" charset="utf-8"></script>
<script src="/lib/ternary_tree.js" type="text/javascript" charset="utf-8"></script>
<script>
tokenStore = new lunr.TokenStore
ternaryTree = new lunr.TernaryTree
reverseIndex = new lunr.ReverseIndex
words.forEach(function (word) {
ternaryTree.add(word)
reverseIndex.set(word, 1, 1)
tokenStore.add(word, {ref: 1, tf: 1})
})
</script>

118
book/node_modules/lunr/test/sorted_set_test.js generated vendored Normal file
View File

@@ -0,0 +1,118 @@
module('lunr.SortedSet')
test('adding an element that doesn\'t exist into the set', function () {
var set = new lunr.SortedSet
equal(set.length, 0)
set.add('foo')
equal(set.length, 1)
})
test('adding an element that does exist into the set', function () {
var set = new lunr.SortedSet
set.add('foo')
equal(set.length, 1)
set.add('foo')
equal(set.length, 1)
})
test('sort is maintained when adding elements to the set', function () {
var set = new lunr.SortedSet
set.add('b')
set.add('d')
set.add('a')
set.add('c')
deepEqual(set.elements, ['a', 'b', 'c', 'd'])
})
test('adding more than one element to the set in one go', function () {
var set = new lunr.SortedSet
set.add('foo', 'bar', 'baz', 'foo')
equal(set.length, 3)
})
test('converting to an array', function () {
var set = new lunr.SortedSet
set.add('foo', 'bar', 'baz')
deepEqual(set.toArray(), ['bar', 'baz', 'foo'])
})
test('mapping the set', function () {
var set = new lunr.SortedSet, a = []
set.add('foo', 'bar')
set.forEach(function (t) { a.push(t) })
deepEqual(a, ['bar', 'foo'])
})
test('getting the index of an item in the set', function () {
var set = new lunr.SortedSet
equal(set.indexOf('non member'), -1)
set.add('foo')
equal(set.indexOf('foo'), 0)
equal(set.indexOf('non member'), -1)
set.add('bar')
equal(set.indexOf('foo'), 1)
equal(set.indexOf('bar'), 0)
equal(set.indexOf('non member'), -1)
})
test('intersecting this set with another set', function () {
var set1 = new lunr.SortedSet,
set2 = new lunr.SortedSet,
setIntersect
set1.add('foo', 'bar')
set2.add('baz', 'foo')
setIntersect = set1.intersect(set2)
ok(setIntersect.indexOf('foo') > -1)
ok(setIntersect.indexOf('bar') == -1)
ok(setIntersect.indexOf('baz') == -1)
})
test('unioning this set with another set', function () {
var set1 = new lunr.SortedSet,
set2 = new lunr.SortedSet,
setUnion
set1.add('foo', 'bar')
set2.add('baz', 'foo')
setUnion = set1.union(set2)
ok(setUnion.indexOf('foo') > -1)
ok(setUnion.indexOf('bar') > -1)
ok(setUnion.indexOf('baz') > -1)
equal(setUnion.length ,3)
})
test('serialising', function () {
var emptySet = new lunr.SortedSet,
nonEmptySet = new lunr.SortedSet
nonEmptySet.add(1,2,3,4)
deepEqual(emptySet.toJSON(), [])
deepEqual(nonEmptySet.toJSON(), [1,2,3,4])
})
test('loading serialised dump', function () {
var serialisedData = [1,2,3,4],
set = lunr.SortedSet.load(serialisedData)
equal(set.length, 4)
deepEqual(set.elements, [1,2,3,4])
})

14
book/node_modules/lunr/test/stemmer_test.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
module('lunr.stemmer')
test('should stem words correctly', function () {
Object.keys(stemmingFixture).forEach(function (testWord) {
var expected = stemmingFixture[testWord]
equal(lunr.stemmer(testWord), expected)
})
})
test('should be registered with lunr.Pipeline', function () {
equal(lunr.stemmer.label, 'stemmer')
deepEqual(lunr.Pipeline.registeredFunctions['stemmer'], lunr.stemmer)
})

30
book/node_modules/lunr/test/stop_word_filter_test.js generated vendored Normal file
View File

@@ -0,0 +1,30 @@
module('lunr.stopWordFilter')
test('stops stop words', function () {
var stopWords = ['the', 'and', 'but', 'than', 'when']
stopWords.forEach(function (word) {
equal(lunr.stopWordFilter(word), undefined)
})
})
test('non stop words pass through', function () {
var nonStopWords = ['interesting', 'words', 'pass', 'through']
nonStopWords.forEach(function (word) {
equal(lunr.stopWordFilter(word), word)
})
})
test('should not filter Object.prototype terms', function () {
var nonStopWords = ['constructor', 'hasOwnProperty', 'toString', 'valueOf']
nonStopWords.forEach(function (word) {
equal(lunr.stopWordFilter(word), word)
})
})
test('should be registered with lunr.Pipeline', function () {
equal(lunr.stopWordFilter.label, 'stopWordFilter')
deepEqual(lunr.Pipeline.registeredFunctions['stopWordFilter'], lunr.stopWordFilter)
})

17
book/node_modules/lunr/test/store_node_test.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
module('store node')
test("get all children", function() {
var node = new lunr.StoreNode,
childNode = node.at('a'),
otherChildNode = node.at('a'),
grandChildNode = childNode.at('a')
childNode.push('childNode')
otherChildNode.push('otherChildNode')
grandChildNode.push('grandChildNode')
equal(node.allChildren().length, 3)
ok(node.allChildren().indexOf(childNode) > -1)
ok(node.allChildren().indexOf(otherChildNode) > -1)
ok(node.allChildren().indexOf(grandChildNode) > -1)
})

60
book/node_modules/lunr/test/store_test.js generated vendored Normal file
View File

@@ -0,0 +1,60 @@
module('lunr.Store')
test('adding document tokens to the document store', function () {
var docStore = new lunr.Store,
tokens = ['eggs', 'ham']
docStore.set(1, tokens)
deepEqual(docStore.get(1), tokens)
})
test('getting the number of items in the document store', function () {
var docStore = new lunr.Store
equal(docStore.length, 0)
docStore.set(1, 'foo')
equal(docStore.length, 1)
})
test('checking whether the store contains a key', function () {
var store = new lunr.Store
ok(!store.has('foo'))
store.set('foo', 1)
ok(store.has('foo'))
})
test('removing an element from the store', function () {
var store = new lunr.Store
store.set('foo', 1)
ok(store.has('foo'))
equal(store.length, 1)
store.remove('foo')
ok(!store.has('foo'))
equal(store.length, 0)
})
test('serialising', function () {
var store = new lunr.Store
deepEqual(store.toJSON(), { store: {}, length: 0 })
store.set(1, ['eggs', 'ham'])
deepEqual(store.toJSON(), { store: { 1: ['eggs', 'ham'] }, length: 1 })
})
test('loading serialised data', function () {
var serialisedData = {
length: 1,
store: {
1: ['eggs', 'ham']
}
}
var store = lunr.Store.load(serialisedData)
equal(store.length, 1)
deepEqual(store.get(1), lunr.SortedSet.load(['eggs', 'ham']))
})

23
book/node_modules/lunr/test/test_helper.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
var helpers = require('./../lib/helpers')
var extensions = function () {
this.equalNumber = function (lambdaNum, num, desc) {
return this.equal.call(this, helpers.toNumber(lambdaNum), num, desc)
},
this.isTrue = function (lambdaBool, desc) {
return this.ok.call(this, helpers.toBoolean(lambdaBool), desc)
},
this.isFalse = function (lambdaBool, desc) {
return this.ok.call(this, !helpers.toBoolean(lambdaBool), desc)
}
}
module.exports = function (testName, testFn) {
module.exports[testName] = function (test) {
extensions.call(test)
testFn.call(test, test)
test.done()
}
}

177
book/node_modules/lunr/test/token_store_test.js generated vendored Normal file
View File

@@ -0,0 +1,177 @@
module('lunr.TokenStore')
test('adding a token to the store', function () {
var store = new lunr.TokenStore,
doc = { ref: 123, tf: 1 },
token = 'foo'
store.add(token, doc)
ok(store.root['f']['o']['o']['docs'][123] === doc)
equal(store.length, 1)
})
test('adding another document to the token', function () {
var store = new lunr.TokenStore,
doc1 = { ref: 123, tf: 1 },
doc2 = { ref: 456, tf: 1 },
token = 'foo'
store.add(token, doc1)
store.add(token, doc2)
ok(store.root['f']['o']['o']['docs'][123] === doc1)
ok(store.root['f']['o']['o']['docs'][456] === doc2)
})
test('checking if a token exists in the store', function () {
var store = new lunr.TokenStore,
doc = { ref: 123, tf: 1 },
token = 'foo'
store.add(token, doc)
ok(store.has(token))
})
test('checking if a token does not exist in the store', function () {
var store = new lunr.TokenStore,
doc = { ref: 123, tf: 1 },
token = 'foo'
ok(!store.has('bar'))
store.add(token, doc)
ok(!store.has('bar'))
})
test('retrieving items from the store', function () {
var store = new lunr.TokenStore,
doc = { ref: 123, tf: 1 },
token = 'foo'
store.add(token, doc)
deepEqual(store.get(token), {
'123': doc
})
deepEqual(store.get(''), {})
})
test('retrieving items that do not exist in the store', function () {
var store = new lunr.TokenStore
deepEqual(store.get('foo'), {})
})
test('counting items in the store', function () {
var store = new lunr.TokenStore,
doc1 = { ref: 123, tf: 1 },
doc2 = { ref: 456, tf: 1 },
doc3 = { ref: 789, tf: 1 }
store.add('foo', doc1)
store.add('foo', doc2)
store.add('bar', doc3)
equal(store.count('foo'), 2)
equal(store.count('bar'), 1)
equal(store.count('baz'), 0)
})
test('removing a document from the token store', function () {
var store = new lunr.TokenStore,
doc = { ref: 123, tf: 1 }
deepEqual(store.get('foo'), {})
store.add('foo', doc)
deepEqual(store.get('foo'), {
'123': doc
})
store.remove('foo', 123)
deepEqual(store.get('foo'), {})
})
test('removing a document that is not in the store', function () {
var store = new lunr.TokenStore,
doc1 = { ref: 123, tf: 1 },
doc2 = { ref: 567, tf: 1 }
store.add('foo', doc1)
store.add('bar', doc2)
store.remove('foo', 456)
deepEqual(store.get('foo'), { 123: doc1 })
})
test('removing a document from a key that does not exist', function () {
var store = new lunr.TokenStore
store.remove('foo', 123)
ok(!store.has('foo'))
})
test('expand a token into all descendent tokens', function () {
var store = new lunr.TokenStore,
doc = { ref: 123, tf: 1 }
store.add('hell', doc)
store.add('hello', doc)
store.add('help', doc)
store.add('held', doc)
store.add('foo', doc)
store.add('bar', doc)
var tokens = store.expand('hel')
deepEqual(tokens, ['hell', 'hello', 'help', 'held'])
})
test('serialisation', function () {
var store = new lunr.TokenStore
deepEqual(store.toJSON(), { root: { docs: {} }, length: 0 })
store.add('foo', { ref: 123, tf: 1 })
deepEqual(store.toJSON(),
{
root: {
docs: {},
f: {
docs: {},
o: {
docs: {},
o: {
docs: { 123: { ref: 123, tf: 1 } }
}
}
}
},
length: 1
}
)
})
test('loading a serialised story', function () {
var serialisedData = {
root: {
docs: {},
f: {
docs: {},
o: {
docs: {},
o: {
docs: { 123: { ref: 123, tf: 1 } }
}
}
}
},
length: 1
}
var store = lunr.TokenStore.load(serialisedData),
documents = store.get('foo')
equal(store.length, 1)
deepEqual(documents, { 123: { ref: 123, tf: 1 }})
})

65
book/node_modules/lunr/test/tokenizer_test.js generated vendored Normal file
View File

@@ -0,0 +1,65 @@
module('lunr.tokenizer')
test("splitting simple strings into tokens", function () {
var simpleString = "this is a simple string",
tokens = lunr.tokenizer(simpleString)
deepEqual(tokens, ['this', 'is', 'a', 'simple', 'string'])
})
test('downcasing tokens', function () {
var simpleString = 'FOO BAR',
tags = ['Foo', 'BAR']
deepEqual(lunr.tokenizer(simpleString), ['foo', 'bar'])
deepEqual(lunr.tokenizer(tags), ['foo', 'bar'])
})
test('handling arrays', function () {
var tags = ['foo', 'bar'],
tokens = lunr.tokenizer(tags)
deepEqual(tokens, tags)
})
test('handling multiple white spaces', function () {
var testString = ' foo bar ',
tokens = lunr.tokenizer(testString)
deepEqual(tokens, ['foo', 'bar'])
})
test('handling null-like arguments', function () {
deepEqual(lunr.tokenizer(), [])
deepEqual(lunr.tokenizer(null), [])
deepEqual(lunr.tokenizer(undefined), [])
})
test('calling to string on passed val', function () {
var date = new Date (Date.UTC(2013, 0, 1, 12)),
obj = {
toString: function () { return 'custom object' }
}
equal(lunr.tokenizer(41), '41')
equal(lunr.tokenizer(false), 'false')
deepEqual(lunr.tokenizer(obj), ['custom', 'object'])
// slicing here to avoid asserting on the timezone part of the date
// that will be different whereever the test is run.
deepEqual(lunr.tokenizer(date).slice(0, 4), ['tue', 'jan', '01', '2013'])
})
test("splitting strings with hyphens", function () {
var simpleString = "take the New York-San Francisco flight",
tokens = lunr.tokenizer(simpleString)
deepEqual(tokens, ['take', 'the', 'new', 'york', 'san', 'francisco', 'flight'])
})
test("splitting strings with hyphens and spaces", function () {
var simpleString = "Solve for A - B",
tokens = lunr.tokenizer(simpleString)
deepEqual(tokens, ['solve', 'for', 'a', 'b'])
})

32
book/node_modules/lunr/test/trimmer_test.js generated vendored Normal file
View File

@@ -0,0 +1,32 @@
module('lunr.trimmer')
test('latin characters', function () {
var token = 'hello'
equal(lunr.trimmer(token), token)
})
test('removing leading and trailing punctuation', function () {
var fullStop = 'hello.',
innerApostrophe = "it's",
trailingApostrophe = "james'",
exclamationMark = 'stop!',
comma = 'first,',
brackets = '[tag]'
deepEqual(lunr.trimmer(fullStop), 'hello')
deepEqual(lunr.trimmer(innerApostrophe), "it's")
deepEqual(lunr.trimmer(trailingApostrophe), "james")
deepEqual(lunr.trimmer(exclamationMark), 'stop')
deepEqual(lunr.trimmer(comma), 'first')
deepEqual(lunr.trimmer(brackets), 'tag')
})
test('should be registered with lunr.Pipeline', function () {
equal(lunr.trimmer.label, 'trimmer')
deepEqual(lunr.Pipeline.registeredFunctions['trimmer'], lunr.trimmer)
})
test('empty tokens should return undefined', function () {
var token = '???'
equal(lunr.trimmer(token), void 0)
})

64
book/node_modules/lunr/test/vector_test.js generated vendored Normal file
View File

@@ -0,0 +1,64 @@
module("lunr.Vector")
test("calculating the magnitude of a vector", function () {
var vector = new lunr.Vector,
elements = [4,5,6]
elements.forEach(function (el, i) { vector.insert(i, el) })
equal(vector.magnitude(), Math.sqrt(77))
})
test("calculating the dot product with another vector", function () {
var v1 = new lunr.Vector,
v2 = new lunr.Vector,
els1 = [1, 3, -5],
els2 = [4, -2, -1]
els1.forEach(function (el, i) { v1.insert(i, el) })
els2.forEach(function (el, i) { v2.insert(i, el) })
equal(v1.dot(v2), 3)
})
test("calculating the similarity between two vectors", function () {
var v1 = new lunr.Vector,
v2 = new lunr.Vector,
els1 = [1, 3, -5],
els2 = [4, -2, -1]
els1.forEach(function (el, i) { v1.insert(i, el) })
els2.forEach(function (el, i) { v2.insert(i, el) })
var similarity = v1.similarity(v2),
roundedSimilarity = Math.round(similarity * 1000) / 1000
equal(roundedSimilarity, 0.111)
})
test("inserting an element invalidates the magnitude cache", function () {
var vector = new lunr.Vector,
elements = [4,5,6]
elements.forEach(function (el, i) { vector.insert(i, el) })
equal(vector.magnitude(), Math.sqrt(77))
vector.insert(3, 7)
equal(vector.magnitude(), Math.sqrt(126))
})
test("inserted elements are kept in index order", function () {
var vector = new lunr.Vector,
elements = [6,5,4]
vector.insert(2, 4)
vector.insert(1, 5)
vector.insert(0, 6)
equal(vector.list.idx, 0)
equal(vector.list.next.idx, 1)
equal(vector.list.next.next.idx, 2)
})