arctic-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +36 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +98 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +28 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/core-api.gemspec +41 -0
  14. data/documentation/.editorconfig +15 -0
  15. data/documentation/.gitignore +24 -0
  16. data/documentation/.travis.yml +10 -0
  17. data/documentation/CHANGELOG.md +137 -0
  18. data/documentation/CODE_OF_CONDUCT.md +46 -0
  19. data/documentation/Gemfile +11 -0
  20. data/documentation/Gemfile.lock +129 -0
  21. data/documentation/LICENSE +13 -0
  22. data/documentation/Procfile +1 -0
  23. data/documentation/README.md +118 -0
  24. data/documentation/config.rb +57 -0
  25. data/documentation/deploy.sh +215 -0
  26. data/documentation/font-selection.json +148 -0
  27. data/documentation/lib/multilang.rb +16 -0
  28. data/documentation/lib/nesting_unique_head.rb +22 -0
  29. data/documentation/lib/toc_data.rb +30 -0
  30. data/documentation/lib/unique_head.rb +24 -0
  31. data/documentation/source/fonts/slate.eot +0 -0
  32. data/documentation/source/fonts/slate.svg +14 -0
  33. data/documentation/source/fonts/slate.ttf +0 -0
  34. data/documentation/source/fonts/slate.woff +0 -0
  35. data/documentation/source/fonts/slate.woff2 +0 -0
  36. data/documentation/source/images/logo.png +0 -0
  37. data/documentation/source/images/navbar.png +0 -0
  38. data/documentation/source/includes/_errors.md +17 -0
  39. data/documentation/source/index.html.md +179 -0
  40. data/documentation/source/javascripts/all.js +2 -0
  41. data/documentation/source/javascripts/all_nosearch.js +16 -0
  42. data/documentation/source/javascripts/app/_lang.js +164 -0
  43. data/documentation/source/javascripts/app/_search.js +98 -0
  44. data/documentation/source/javascripts/app/_toc.js +114 -0
  45. data/documentation/source/javascripts/lib/_energize.js +169 -0
  46. data/documentation/source/javascripts/lib/_imagesloaded.min.js +7 -0
  47. data/documentation/source/javascripts/lib/_jquery.highlight.js +108 -0
  48. data/documentation/source/javascripts/lib/_jquery.js +9831 -0
  49. data/documentation/source/javascripts/lib/_lunr.js +1910 -0
  50. data/documentation/source/layouts/layout.erb +116 -0
  51. data/documentation/source/stylesheets/_icon-font.scss +38 -0
  52. data/documentation/source/stylesheets/_normalize.scss +427 -0
  53. data/documentation/source/stylesheets/_rtl.scss +140 -0
  54. data/documentation/source/stylesheets/_variables.scss +103 -0
  55. data/documentation/source/stylesheets/_variables2.scss +147 -0
  56. data/documentation/source/stylesheets/print.css.scss +148 -0
  57. data/documentation/source/stylesheets/screen.css.scss +707 -0
  58. data/lib/arctic/ui.rb +21 -0
  59. data/lib/arctic/ui/api.rb +69 -0
  60. data/lib/arctic/ui/configuration.rb +26 -0
  61. data/lib/arctic/ui/version.rb +5 -0
  62. metadata +288 -0
@@ -0,0 +1,1910 @@
1
+ /**
2
+ * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.5.7
3
+ * Copyright (C) 2014 Oliver Nightingale
4
+ * MIT Licensed
5
+ * @license
6
+ */
7
+
8
+ (function(){
9
+
10
+ /**
11
+ * Convenience function for instantiating a new lunr index and configuring it
12
+ * with the default pipeline functions and the passed config function.
13
+ *
14
+ * When using this convenience function a new index will be created with the
15
+ * following functions already in the pipeline:
16
+ *
17
+ * lunr.StopWordFilter - filters out any stop words before they enter the
18
+ * index
19
+ *
20
+ * lunr.stemmer - stems the tokens before entering the index.
21
+ *
22
+ * Example:
23
+ *
24
+ * var idx = lunr(function () {
25
+ * this.field('title', 10)
26
+ * this.field('tags', 100)
27
+ * this.field('body')
28
+ *
29
+ * this.ref('cid')
30
+ *
31
+ * this.pipeline.add(function () {
32
+ * // some custom pipeline function
33
+ * })
34
+ *
35
+ * })
36
+ *
37
+ * @param {Function} config A function that will be called with the new instance
38
+ * of the lunr.Index as both its context and first parameter. It can be used to
39
+ * customize the instance of new lunr.Index.
40
+ * @namespace
41
+ * @module
42
+ * @returns {lunr.Index}
43
+ *
44
+ */
45
+ var lunr = function (config) {
46
+ var idx = new lunr.Index
47
+
48
+ idx.pipeline.add(
49
+ lunr.trimmer,
50
+ lunr.stopWordFilter,
51
+ lunr.stemmer
52
+ )
53
+
54
+ if (config) config.call(idx, idx)
55
+
56
+ return idx
57
+ }
58
+
59
+ lunr.version = "0.5.7"
60
+ /*!
61
+ * lunr.utils
62
+ * Copyright (C) 2014 Oliver Nightingale
63
+ */
64
+
65
+ /**
66
+ * A namespace containing utils for the rest of the lunr library
67
+ */
68
+ lunr.utils = {}
69
+
70
+ /**
71
+ * Print a warning message to the console.
72
+ *
73
+ * @param {String} message The message to be printed.
74
+ * @memberOf Utils
75
+ */
76
+ lunr.utils.warn = (function (global) {
77
+ return function (message) {
78
+ if (global.console && console.warn) {
79
+ console.warn(message)
80
+ }
81
+ }
82
+ })(this)
83
+
84
+ /*!
85
+ * lunr.EventEmitter
86
+ * Copyright (C) 2014 Oliver Nightingale
87
+ */
88
+
89
+ /**
90
+ * lunr.EventEmitter is an event emitter for lunr. It manages adding and removing event handlers and triggering events and their handlers.
91
+ *
92
+ * @constructor
93
+ */
94
+ lunr.EventEmitter = function () {
95
+ this.events = {}
96
+ }
97
+
98
+ /**
99
+ * Binds a handler function to a specific event(s).
100
+ *
101
+ * Can bind a single function to many different events in one call.
102
+ *
103
+ * @param {String} [eventName] The name(s) of events to bind this function to.
104
+ * @param {Function} handler The function to call when an event is fired.
105
+ * @memberOf EventEmitter
106
+ */
107
+ lunr.EventEmitter.prototype.addListener = function () {
108
+ var args = Array.prototype.slice.call(arguments),
109
+ fn = args.pop(),
110
+ names = args
111
+
112
+ if (typeof fn !== "function") throw new TypeError ("last argument must be a function")
113
+
114
+ names.forEach(function (name) {
115
+ if (!this.hasHandler(name)) this.events[name] = []
116
+ this.events[name].push(fn)
117
+ }, this)
118
+ }
119
+
120
+ /**
121
+ * Removes a handler function from a specific event.
122
+ *
123
+ * @param {String} eventName The name of the event to remove this function from.
124
+ * @param {Function} handler The function to remove from an event.
125
+ * @memberOf EventEmitter
126
+ */
127
+ lunr.EventEmitter.prototype.removeListener = function (name, fn) {
128
+ if (!this.hasHandler(name)) return
129
+
130
+ var fnIndex = this.events[name].indexOf(fn)
131
+ this.events[name].splice(fnIndex, 1)
132
+
133
+ if (!this.events[name].length) delete this.events[name]
134
+ }
135
+
136
+ /**
137
+ * Calls all functions bound to the given event.
138
+ *
139
+ * Additional data can be passed to the event handler as arguments to `emit`
140
+ * after the event name.
141
+ *
142
+ * @param {String} eventName The name of the event to emit.
143
+ * @memberOf EventEmitter
144
+ */
145
+ lunr.EventEmitter.prototype.emit = function (name) {
146
+ if (!this.hasHandler(name)) return
147
+
148
+ var args = Array.prototype.slice.call(arguments, 1)
149
+
150
+ this.events[name].forEach(function (fn) {
151
+ fn.apply(undefined, args)
152
+ })
153
+ }
154
+
155
+ /**
156
+ * Checks whether a handler has ever been stored against an event.
157
+ *
158
+ * @param {String} eventName The name of the event to check.
159
+ * @private
160
+ * @memberOf EventEmitter
161
+ */
162
+ lunr.EventEmitter.prototype.hasHandler = function (name) {
163
+ return name in this.events
164
+ }
165
+
166
+ /*!
167
+ * lunr.tokenizer
168
+ * Copyright (C) 2014 Oliver Nightingale
169
+ */
170
+
171
+ /**
172
+ * A function for splitting a string into tokens ready to be inserted into
173
+ * the search index.
174
+ *
175
+ * @module
176
+ * @param {String} obj The string to convert into tokens
177
+ * @returns {Array}
178
+ */
179
+ lunr.tokenizer = function (obj) {
180
+ if (!arguments.length || obj == null || obj == undefined) return []
181
+ if (Array.isArray(obj)) return obj.map(function (t) { return t.toLowerCase() })
182
+
183
+ var str = obj.toString().replace(/^\s+/, '')
184
+
185
+ for (var i = str.length - 1; i >= 0; i--) {
186
+ if (/\S/.test(str.charAt(i))) {
187
+ str = str.substring(0, i + 1)
188
+ break
189
+ }
190
+ }
191
+
192
+ return str
193
+ .split(/(?:\s+|\-)/)
194
+ .filter(function (token) {
195
+ return !!token
196
+ })
197
+ .map(function (token) {
198
+ return token.toLowerCase()
199
+ })
200
+ }
201
+ /*!
202
+ * lunr.Pipeline
203
+ * Copyright (C) 2014 Oliver Nightingale
204
+ */
205
+
206
+ /**
207
+ * lunr.Pipelines maintain an ordered list of functions to be applied to all
208
+ * tokens in documents entering the search index and queries being ran against
209
+ * the index.
210
+ *
211
+ * An instance of lunr.Index created with the lunr shortcut will contain a
212
+ * pipeline with a stop word filter and an English language stemmer. Extra
213
+ * functions can be added before or after either of these functions or these
214
+ * default functions can be removed.
215
+ *
216
+ * When run the pipeline will call each function in turn, passing a token, the
217
+ * index of that token in the original list of all tokens and finally a list of
218
+ * all the original tokens.
219
+ *
220
+ * The output of functions in the pipeline will be passed to the next function
221
+ * in the pipeline. To exclude a token from entering the index the function
222
+ * should return undefined, the rest of the pipeline will not be called with
223
+ * this token.
224
+ *
225
+ * For serialisation of pipelines to work, all functions used in an instance of
226
+ * a pipeline should be registered with lunr.Pipeline. Registered functions can
227
+ * then be loaded. If trying to load a serialised pipeline that uses functions
228
+ * that are not registered an error will be thrown.
229
+ *
230
+ * If not planning on serialising the pipeline then registering pipeline functions
231
+ * is not necessary.
232
+ *
233
+ * @constructor
234
+ */
235
+ lunr.Pipeline = function () {
236
+ this._stack = []
237
+ }
238
+
239
+ lunr.Pipeline.registeredFunctions = {}
240
+
241
+ /**
242
+ * Register a function with the pipeline.
243
+ *
244
+ * Functions that are used in the pipeline should be registered if the pipeline
245
+ * needs to be serialised, or a serialised pipeline needs to be loaded.
246
+ *
247
+ * Registering a function does not add it to a pipeline, functions must still be
248
+ * added to instances of the pipeline for them to be used when running a pipeline.
249
+ *
250
+ * @param {Function} fn The function to check for.
251
+ * @param {String} label The label to register this function with
252
+ * @memberOf Pipeline
253
+ */
254
+ lunr.Pipeline.registerFunction = function (fn, label) {
255
+ if (label in this.registeredFunctions) {
256
+ lunr.utils.warn('Overwriting existing registered function: ' + label)
257
+ }
258
+
259
+ fn.label = label
260
+ lunr.Pipeline.registeredFunctions[fn.label] = fn
261
+ }
262
+
263
+ /**
264
+ * Warns if the function is not registered as a Pipeline function.
265
+ *
266
+ * @param {Function} fn The function to check for.
267
+ * @private
268
+ * @memberOf Pipeline
269
+ */
270
+ lunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {
271
+ var isRegistered = fn.label && (fn.label in this.registeredFunctions)
272
+
273
+ if (!isRegistered) {
274
+ lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\n', fn)
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Loads a previously serialised pipeline.
280
+ *
281
+ * All functions to be loaded must already be registered with lunr.Pipeline.
282
+ * If any function from the serialised data has not been registered then an
283
+ * error will be thrown.
284
+ *
285
+ * @param {Object} serialised The serialised pipeline to load.
286
+ * @returns {lunr.Pipeline}
287
+ * @memberOf Pipeline
288
+ */
289
+ lunr.Pipeline.load = function (serialised) {
290
+ var pipeline = new lunr.Pipeline
291
+
292
+ serialised.forEach(function (fnName) {
293
+ var fn = lunr.Pipeline.registeredFunctions[fnName]
294
+
295
+ if (fn) {
296
+ pipeline.add(fn)
297
+ } else {
298
+ throw new Error ('Cannot load un-registered function: ' + fnName)
299
+ }
300
+ })
301
+
302
+ return pipeline
303
+ }
304
+
305
+ /**
306
+ * Adds new functions to the end of the pipeline.
307
+ *
308
+ * Logs a warning if the function has not been registered.
309
+ *
310
+ * @param {Function} functions Any number of functions to add to the pipeline.
311
+ * @memberOf Pipeline
312
+ */
313
+ lunr.Pipeline.prototype.add = function () {
314
+ var fns = Array.prototype.slice.call(arguments)
315
+
316
+ fns.forEach(function (fn) {
317
+ lunr.Pipeline.warnIfFunctionNotRegistered(fn)
318
+ this._stack.push(fn)
319
+ }, this)
320
+ }
321
+
322
+ /**
323
+ * Adds a single function after a function that already exists in the
324
+ * pipeline.
325
+ *
326
+ * Logs a warning if the function has not been registered.
327
+ *
328
+ * @param {Function} existingFn A function that already exists in the pipeline.
329
+ * @param {Function} newFn The new function to add to the pipeline.
330
+ * @memberOf Pipeline
331
+ */
332
+ lunr.Pipeline.prototype.after = function (existingFn, newFn) {
333
+ lunr.Pipeline.warnIfFunctionNotRegistered(newFn)
334
+
335
+ var pos = this._stack.indexOf(existingFn) + 1
336
+ this._stack.splice(pos, 0, newFn)
337
+ }
338
+
339
+ /**
340
+ * Adds a single function before a function that already exists in the
341
+ * pipeline.
342
+ *
343
+ * Logs a warning if the function has not been registered.
344
+ *
345
+ * @param {Function} existingFn A function that already exists in the pipeline.
346
+ * @param {Function} newFn The new function to add to the pipeline.
347
+ * @memberOf Pipeline
348
+ */
349
+ lunr.Pipeline.prototype.before = function (existingFn, newFn) {
350
+ lunr.Pipeline.warnIfFunctionNotRegistered(newFn)
351
+
352
+ var pos = this._stack.indexOf(existingFn)
353
+ this._stack.splice(pos, 0, newFn)
354
+ }
355
+
356
+ /**
357
+ * Removes a function from the pipeline.
358
+ *
359
+ * @param {Function} fn The function to remove from the pipeline.
360
+ * @memberOf Pipeline
361
+ */
362
+ lunr.Pipeline.prototype.remove = function (fn) {
363
+ var pos = this._stack.indexOf(fn)
364
+ this._stack.splice(pos, 1)
365
+ }
366
+
367
+ /**
368
+ * Runs the current list of functions that make up the pipeline against the
369
+ * passed tokens.
370
+ *
371
+ * @param {Array} tokens The tokens to run through the pipeline.
372
+ * @returns {Array}
373
+ * @memberOf Pipeline
374
+ */
375
+ lunr.Pipeline.prototype.run = function (tokens) {
376
+ var out = [],
377
+ tokenLength = tokens.length,
378
+ stackLength = this._stack.length
379
+
380
+ for (var i = 0; i < tokenLength; i++) {
381
+ var token = tokens[i]
382
+
383
+ for (var j = 0; j < stackLength; j++) {
384
+ token = this._stack[j](token, i, tokens)
385
+ if (token === void 0) break
386
+ };
387
+
388
+ if (token !== void 0) out.push(token)
389
+ };
390
+
391
+ return out
392
+ }
393
+
394
+ /**
395
+ * Resets the pipeline by removing any existing processors.
396
+ *
397
+ * @memberOf Pipeline
398
+ */
399
+ lunr.Pipeline.prototype.reset = function () {
400
+ this._stack = []
401
+ }
402
+
403
+ /**
404
+ * Returns a representation of the pipeline ready for serialisation.
405
+ *
406
+ * Logs a warning if the function has not been registered.
407
+ *
408
+ * @returns {Array}
409
+ * @memberOf Pipeline
410
+ */
411
+ lunr.Pipeline.prototype.toJSON = function () {
412
+ return this._stack.map(function (fn) {
413
+ lunr.Pipeline.warnIfFunctionNotRegistered(fn)
414
+
415
+ return fn.label
416
+ })
417
+ }
418
+ /*!
419
+ * lunr.Vector
420
+ * Copyright (C) 2014 Oliver Nightingale
421
+ */
422
+
423
+ /**
424
+ * lunr.Vectors implement vector related operations for
425
+ * a series of elements.
426
+ *
427
+ * @constructor
428
+ */
429
+ lunr.Vector = function () {
430
+ this._magnitude = null
431
+ this.list = undefined
432
+ this.length = 0
433
+ }
434
+
435
+ /**
436
+ * lunr.Vector.Node is a simple struct for each node
437
+ * in a lunr.Vector.
438
+ *
439
+ * @private
440
+ * @param {Number} The index of the node in the vector.
441
+ * @param {Object} The data at this node in the vector.
442
+ * @param {lunr.Vector.Node} The node directly after this node in the vector.
443
+ * @constructor
444
+ * @memberOf Vector
445
+ */
446
+ lunr.Vector.Node = function (idx, val, next) {
447
+ this.idx = idx
448
+ this.val = val
449
+ this.next = next
450
+ }
451
+
452
+ /**
453
+ * Inserts a new value at a position in a vector.
454
+ *
455
+ * @param {Number} The index at which to insert a value.
456
+ * @param {Object} The object to insert in the vector.
457
+ * @memberOf Vector.
458
+ */
459
+ lunr.Vector.prototype.insert = function (idx, val) {
460
+ var list = this.list
461
+
462
+ if (!list) {
463
+ this.list = new lunr.Vector.Node (idx, val, list)
464
+ return this.length++
465
+ }
466
+
467
+ var prev = list,
468
+ next = list.next
469
+
470
+ while (next != undefined) {
471
+ if (idx < next.idx) {
472
+ prev.next = new lunr.Vector.Node (idx, val, next)
473
+ return this.length++
474
+ }
475
+
476
+ prev = next, next = next.next
477
+ }
478
+
479
+ prev.next = new lunr.Vector.Node (idx, val, next)
480
+ return this.length++
481
+ }
482
+
483
+ /**
484
+ * Calculates the magnitude of this vector.
485
+ *
486
+ * @returns {Number}
487
+ * @memberOf Vector
488
+ */
489
+ lunr.Vector.prototype.magnitude = function () {
490
+ if (this._magniture) return this._magnitude
491
+ var node = this.list,
492
+ sumOfSquares = 0,
493
+ val
494
+
495
+ while (node) {
496
+ val = node.val
497
+ sumOfSquares += val * val
498
+ node = node.next
499
+ }
500
+
501
+ return this._magnitude = Math.sqrt(sumOfSquares)
502
+ }
503
+
504
+ /**
505
+ * Calculates the dot product of this vector and another vector.
506
+ *
507
+ * @param {lunr.Vector} otherVector The vector to compute the dot product with.
508
+ * @returns {Number}
509
+ * @memberOf Vector
510
+ */
511
+ lunr.Vector.prototype.dot = function (otherVector) {
512
+ var node = this.list,
513
+ otherNode = otherVector.list,
514
+ dotProduct = 0
515
+
516
+ while (node && otherNode) {
517
+ if (node.idx < otherNode.idx) {
518
+ node = node.next
519
+ } else if (node.idx > otherNode.idx) {
520
+ otherNode = otherNode.next
521
+ } else {
522
+ dotProduct += node.val * otherNode.val
523
+ node = node.next
524
+ otherNode = otherNode.next
525
+ }
526
+ }
527
+
528
+ return dotProduct
529
+ }
530
+
531
+ /**
532
+ * Calculates the cosine similarity between this vector and another
533
+ * vector.
534
+ *
535
+ * @param {lunr.Vector} otherVector The other vector to calculate the
536
+ * similarity with.
537
+ * @returns {Number}
538
+ * @memberOf Vector
539
+ */
540
+ lunr.Vector.prototype.similarity = function (otherVector) {
541
+ return this.dot(otherVector) / (this.magnitude() * otherVector.magnitude())
542
+ }
543
+ /*!
544
+ * lunr.SortedSet
545
+ * Copyright (C) 2014 Oliver Nightingale
546
+ */
547
+
548
+ /**
549
+ * lunr.SortedSets are used to maintain an array of uniq values in a sorted
550
+ * order.
551
+ *
552
+ * @constructor
553
+ */
554
+ lunr.SortedSet = function () {
555
+ this.length = 0
556
+ this.elements = []
557
+ }
558
+
559
+ /**
560
+ * Loads a previously serialised sorted set.
561
+ *
562
+ * @param {Array} serialisedData The serialised set to load.
563
+ * @returns {lunr.SortedSet}
564
+ * @memberOf SortedSet
565
+ */
566
+ lunr.SortedSet.load = function (serialisedData) {
567
+ var set = new this
568
+
569
+ set.elements = serialisedData
570
+ set.length = serialisedData.length
571
+
572
+ return set
573
+ }
574
+
575
+ /**
576
+ * Inserts new items into the set in the correct position to maintain the
577
+ * order.
578
+ *
579
+ * @param {Object} The objects to add to this set.
580
+ * @memberOf SortedSet
581
+ */
582
+ lunr.SortedSet.prototype.add = function () {
583
+ Array.prototype.slice.call(arguments).forEach(function (element) {
584
+ if (~this.indexOf(element)) return
585
+ this.elements.splice(this.locationFor(element), 0, element)
586
+ }, this)
587
+
588
+ this.length = this.elements.length
589
+ }
590
+
591
+ /**
592
+ * Converts this sorted set into an array.
593
+ *
594
+ * @returns {Array}
595
+ * @memberOf SortedSet
596
+ */
597
+ lunr.SortedSet.prototype.toArray = function () {
598
+ return this.elements.slice()
599
+ }
600
+
601
+ /**
602
+ * Creates a new array with the results of calling a provided function on every
603
+ * element in this sorted set.
604
+ *
605
+ * Delegates to Array.prototype.map and has the same signature.
606
+ *
607
+ * @param {Function} fn The function that is called on each element of the
608
+ * set.
609
+ * @param {Object} ctx An optional object that can be used as the context
610
+ * for the function fn.
611
+ * @returns {Array}
612
+ * @memberOf SortedSet
613
+ */
614
+ lunr.SortedSet.prototype.map = function (fn, ctx) {
615
+ return this.elements.map(fn, ctx)
616
+ }
617
+
618
+ /**
619
+ * Executes a provided function once per sorted set element.
620
+ *
621
+ * Delegates to Array.prototype.forEach and has the same signature.
622
+ *
623
+ * @param {Function} fn The function that is called on each element of the
624
+ * set.
625
+ * @param {Object} ctx An optional object that can be used as the context
626
+ * @memberOf SortedSet
627
+ * for the function fn.
628
+ */
629
+ lunr.SortedSet.prototype.forEach = function (fn, ctx) {
630
+ return this.elements.forEach(fn, ctx)
631
+ }
632
+
633
+ /**
634
+ * Returns the index at which a given element can be found in the
635
+ * sorted set, or -1 if it is not present.
636
+ *
637
+ * @param {Object} elem The object to locate in the sorted set.
638
+ * @param {Number} start An optional index at which to start searching from
639
+ * within the set.
640
+ * @param {Number} end An optional index at which to stop search from within
641
+ * the set.
642
+ * @returns {Number}
643
+ * @memberOf SortedSet
644
+ */
645
+ lunr.SortedSet.prototype.indexOf = function (elem, start, end) {
646
+ var start = start || 0,
647
+ end = end || this.elements.length,
648
+ sectionLength = end - start,
649
+ pivot = start + Math.floor(sectionLength / 2),
650
+ pivotElem = this.elements[pivot]
651
+
652
+ if (sectionLength <= 1) {
653
+ if (pivotElem === elem) {
654
+ return pivot
655
+ } else {
656
+ return -1
657
+ }
658
+ }
659
+
660
+ if (pivotElem < elem) return this.indexOf(elem, pivot, end)
661
+ if (pivotElem > elem) return this.indexOf(elem, start, pivot)
662
+ if (pivotElem === elem) return pivot
663
+ }
664
+
665
+ /**
666
+ * Returns the position within the sorted set that an element should be
667
+ * inserted at to maintain the current order of the set.
668
+ *
669
+ * This function assumes that the element to search for does not already exist
670
+ * in the sorted set.
671
+ *
672
+ * @param {Object} elem The elem to find the position for in the set
673
+ * @param {Number} start An optional index at which to start searching from
674
+ * within the set.
675
+ * @param {Number} end An optional index at which to stop search from within
676
+ * the set.
677
+ * @returns {Number}
678
+ * @memberOf SortedSet
679
+ */
680
+ lunr.SortedSet.prototype.locationFor = function (elem, start, end) {
681
+ var start = start || 0,
682
+ end = end || this.elements.length,
683
+ sectionLength = end - start,
684
+ pivot = start + Math.floor(sectionLength / 2),
685
+ pivotElem = this.elements[pivot]
686
+
687
+ if (sectionLength <= 1) {
688
+ if (pivotElem > elem) return pivot
689
+ if (pivotElem < elem) return pivot + 1
690
+ }
691
+
692
+ if (pivotElem < elem) return this.locationFor(elem, pivot, end)
693
+ if (pivotElem > elem) return this.locationFor(elem, start, pivot)
694
+ }
695
+
696
+ /**
697
+ * Creates a new lunr.SortedSet that contains the elements in the intersection
698
+ * of this set and the passed set.
699
+ *
700
+ * @param {lunr.SortedSet} otherSet The set to intersect with this set.
701
+ * @returns {lunr.SortedSet}
702
+ * @memberOf SortedSet
703
+ */
704
+ lunr.SortedSet.prototype.intersect = function (otherSet) {
705
+ var intersectSet = new lunr.SortedSet,
706
+ i = 0, j = 0,
707
+ a_len = this.length, b_len = otherSet.length,
708
+ a = this.elements, b = otherSet.elements
709
+
710
+ while (true) {
711
+ if (i > a_len - 1 || j > b_len - 1) break
712
+
713
+ if (a[i] === b[j]) {
714
+ intersectSet.add(a[i])
715
+ i++, j++
716
+ continue
717
+ }
718
+
719
+ if (a[i] < b[j]) {
720
+ i++
721
+ continue
722
+ }
723
+
724
+ if (a[i] > b[j]) {
725
+ j++
726
+ continue
727
+ }
728
+ };
729
+
730
+ return intersectSet
731
+ }
732
+
733
+ /**
734
+ * Makes a copy of this set
735
+ *
736
+ * @returns {lunr.SortedSet}
737
+ * @memberOf SortedSet
738
+ */
739
+ lunr.SortedSet.prototype.clone = function () {
740
+ var clone = new lunr.SortedSet
741
+
742
+ clone.elements = this.toArray()
743
+ clone.length = clone.elements.length
744
+
745
+ return clone
746
+ }
747
+
748
+ /**
749
+ * Creates a new lunr.SortedSet that contains the elements in the union
750
+ * of this set and the passed set.
751
+ *
752
+ * @param {lunr.SortedSet} otherSet The set to union with this set.
753
+ * @returns {lunr.SortedSet}
754
+ * @memberOf SortedSet
755
+ */
756
+ lunr.SortedSet.prototype.union = function (otherSet) {
757
+ var longSet, shortSet, unionSet
758
+
759
+ if (this.length >= otherSet.length) {
760
+ longSet = this, shortSet = otherSet
761
+ } else {
762
+ longSet = otherSet, shortSet = this
763
+ }
764
+
765
+ unionSet = longSet.clone()
766
+
767
+ unionSet.add.apply(unionSet, shortSet.toArray())
768
+
769
+ return unionSet
770
+ }
771
+
772
+ /**
773
+ * Returns a representation of the sorted set ready for serialisation.
774
+ *
775
+ * @returns {Array}
776
+ * @memberOf SortedSet
777
+ */
778
+ lunr.SortedSet.prototype.toJSON = function () {
779
+ return this.toArray()
780
+ }
781
+ /*!
782
+ * lunr.Index
783
+ * Copyright (C) 2014 Oliver Nightingale
784
+ */
785
+
786
+ /**
787
+ * lunr.Index is object that manages a search index. It contains the indexes
788
+ * and stores all the tokens and document lookups. It also provides the main
789
+ * user facing API for the library.
790
+ *
791
+ * @constructor
792
+ */
793
+ lunr.Index = function () {
794
+ this._fields = []
795
+ this._ref = 'id'
796
+ this.pipeline = new lunr.Pipeline
797
+ this.documentStore = new lunr.Store
798
+ this.tokenStore = new lunr.TokenStore
799
+ this.corpusTokens = new lunr.SortedSet
800
+ this.eventEmitter = new lunr.EventEmitter
801
+
802
+ this._idfCache = {}
803
+
804
+ this.on('add', 'remove', 'update', (function () {
805
+ this._idfCache = {}
806
+ }).bind(this))
807
+ }
808
+
809
+ /**
810
+ * Bind a handler to events being emitted by the index.
811
+ *
812
+ * The handler can be bound to many events at the same time.
813
+ *
814
+ * @param {String} [eventName] The name(s) of events to bind the function to.
815
+ * @param {Function} handler The serialised set to load.
816
+ * @memberOf Index
817
+ */
818
+ lunr.Index.prototype.on = function () {
819
+ var args = Array.prototype.slice.call(arguments)
820
+ return this.eventEmitter.addListener.apply(this.eventEmitter, args)
821
+ }
822
+
823
+ /**
824
+ * Removes a handler from an event being emitted by the index.
825
+ *
826
+ * @param {String} eventName The name of events to remove the function from.
827
+ * @param {Function} handler The serialised set to load.
828
+ * @memberOf Index
829
+ */
830
+ lunr.Index.prototype.off = function (name, fn) {
831
+ return this.eventEmitter.removeListener(name, fn)
832
+ }
833
+
834
+ /**
835
+ * Loads a previously serialised index.
836
+ *
837
+ * Issues a warning if the index being imported was serialised
838
+ * by a different version of lunr.
839
+ *
840
+ * @param {Object} serialisedData The serialised set to load.
841
+ * @returns {lunr.Index}
842
+ * @memberOf Index
843
+ */
844
+ lunr.Index.load = function (serialisedData) {
845
+ if (serialisedData.version !== lunr.version) {
846
+ lunr.utils.warn('version mismatch: current ' + lunr.version + ' importing ' + serialisedData.version)
847
+ }
848
+
849
+ var idx = new this
850
+
851
+ idx._fields = serialisedData.fields
852
+ idx._ref = serialisedData.ref
853
+
854
+ idx.documentStore = lunr.Store.load(serialisedData.documentStore)
855
+ idx.tokenStore = lunr.TokenStore.load(serialisedData.tokenStore)
856
+ idx.corpusTokens = lunr.SortedSet.load(serialisedData.corpusTokens)
857
+ idx.pipeline = lunr.Pipeline.load(serialisedData.pipeline)
858
+
859
+ return idx
860
+ }
861
+
862
+ /**
863
+ * Adds a field to the list of fields that will be searchable within documents
864
+ * in the index.
865
+ *
866
+ * An optional boost param can be passed to affect how much tokens in this field
867
+ * rank in search results, by default the boost value is 1.
868
+ *
869
+ * Fields should be added before any documents are added to the index, fields
870
+ * that are added after documents are added to the index will only apply to new
871
+ * documents added to the index.
872
+ *
873
+ * @param {String} fieldName The name of the field within the document that
874
+ * should be indexed
875
+ * @param {Number} boost An optional boost that can be applied to terms in this
876
+ * field.
877
+ * @returns {lunr.Index}
878
+ * @memberOf Index
879
+ */
880
+ lunr.Index.prototype.field = function (fieldName, opts) {
881
+ var opts = opts || {},
882
+ field = { name: fieldName, boost: opts.boost || 1 }
883
+
884
+ this._fields.push(field)
885
+ return this
886
+ }
887
+
888
+ /**
889
+ * Sets the property used to uniquely identify documents added to the index,
890
+ * by default this property is 'id'.
891
+ *
892
+ * This should only be changed before adding documents to the index, changing
893
+ * the ref property without resetting the index can lead to unexpected results.
894
+ *
895
+ * @param {String} refName The property to use to uniquely identify the
896
+ * documents in the index.
897
+ * @param {Boolean} emitEvent Whether to emit add events, defaults to true
898
+ * @returns {lunr.Index}
899
+ * @memberOf Index
900
+ */
901
+ lunr.Index.prototype.ref = function (refName) {
902
+ this._ref = refName
903
+ return this
904
+ }
905
+
906
+ /**
907
+ * Add a document to the index.
908
+ *
909
+ * This is the way new documents enter the index, this function will run the
910
+ * fields from the document through the index's pipeline and then add it to
911
+ * the index, it will then show up in search results.
912
+ *
913
+ * An 'add' event is emitted with the document that has been added and the index
914
+ * the document has been added to. This event can be silenced by passing false
915
+ * as the second argument to add.
916
+ *
917
+ * @param {Object} doc The document to add to the index.
918
+ * @param {Boolean} emitEvent Whether or not to emit events, default true.
919
+ * @memberOf Index
920
+ */
921
+ lunr.Index.prototype.add = function (doc, emitEvent) {
922
+ var docTokens = {},
923
+ allDocumentTokens = new lunr.SortedSet,
924
+ docRef = doc[this._ref],
925
+ emitEvent = emitEvent === undefined ? true : emitEvent
926
+
927
+ this._fields.forEach(function (field) {
928
+ var fieldTokens = this.pipeline.run(lunr.tokenizer(doc[field.name]))
929
+
930
+ docTokens[field.name] = fieldTokens
931
+ lunr.SortedSet.prototype.add.apply(allDocumentTokens, fieldTokens)
932
+ }, this)
933
+
934
+ this.documentStore.set(docRef, allDocumentTokens)
935
+ lunr.SortedSet.prototype.add.apply(this.corpusTokens, allDocumentTokens.toArray())
936
+
937
+ for (var i = 0; i < allDocumentTokens.length; i++) {
938
+ var token = allDocumentTokens.elements[i]
939
+ var tf = this._fields.reduce(function (memo, field) {
940
+ var fieldLength = docTokens[field.name].length
941
+
942
+ if (!fieldLength) return memo
943
+
944
+ var tokenCount = docTokens[field.name].filter(function (t) { return t === token }).length
945
+
946
+ return memo + (tokenCount / fieldLength * field.boost)
947
+ }, 0)
948
+
949
+ this.tokenStore.add(token, { ref: docRef, tf: tf })
950
+ };
951
+
952
+ if (emitEvent) this.eventEmitter.emit('add', doc, this)
953
+ }
954
+
955
+ /**
956
+ * Removes a document from the index.
957
+ *
958
+ * To make sure documents no longer show up in search results they can be
959
+ * removed from the index using this method.
960
+ *
961
+ * The document passed only needs to have the same ref property value as the
962
+ * document that was added to the index, they could be completely different
963
+ * objects.
964
+ *
965
+ * A 'remove' event is emitted with the document that has been removed and the index
966
+ * the document has been removed from. This event can be silenced by passing false
967
+ * as the second argument to remove.
968
+ *
969
+ * @param {Object} doc The document to remove from the index.
970
+ * @param {Boolean} emitEvent Whether to emit remove events, defaults to true
971
+ * @memberOf Index
972
+ */
973
+ lunr.Index.prototype.remove = function (doc, emitEvent) {
974
+ var docRef = doc[this._ref],
975
+ emitEvent = emitEvent === undefined ? true : emitEvent
976
+
977
+ if (!this.documentStore.has(docRef)) return
978
+
979
+ var docTokens = this.documentStore.get(docRef)
980
+
981
+ this.documentStore.remove(docRef)
982
+
983
+ docTokens.forEach(function (token) {
984
+ this.tokenStore.remove(token, docRef)
985
+ }, this)
986
+
987
+ if (emitEvent) this.eventEmitter.emit('remove', doc, this)
988
+ }
989
+
990
+ /**
991
+ * Updates a document in the index.
992
+ *
993
+ * When a document contained within the index gets updated, fields changed,
994
+ * added or removed, to make sure it correctly matched against search queries,
995
+ * it should be updated in the index.
996
+ *
997
+ * This method is just a wrapper around `remove` and `add`
998
+ *
999
+ * An 'update' event is emitted with the document that has been updated and the index.
1000
+ * This event can be silenced by passing false as the second argument to update. Only
1001
+ * an update event will be fired, the 'add' and 'remove' events of the underlying calls
1002
+ * are silenced.
1003
+ *
1004
+ * @param {Object} doc The document to update in the index.
1005
+ * @param {Boolean} emitEvent Whether to emit update events, defaults to true
1006
+ * @see Index.prototype.remove
1007
+ * @see Index.prototype.add
1008
+ * @memberOf Index
1009
+ */
1010
+ lunr.Index.prototype.update = function (doc, emitEvent) {
1011
+ var emitEvent = emitEvent === undefined ? true : emitEvent
1012
+
1013
+ this.remove(doc, false)
1014
+ this.add(doc, false)
1015
+
1016
+ if (emitEvent) this.eventEmitter.emit('update', doc, this)
1017
+ }
1018
+
1019
+ /**
1020
+ * Calculates the inverse document frequency for a token within the index.
1021
+ *
1022
+ * @param {String} token The token to calculate the idf of.
1023
+ * @see Index.prototype.idf
1024
+ * @private
1025
+ * @memberOf Index
1026
+ */
1027
+ lunr.Index.prototype.idf = function (term) {
1028
+ var cacheKey = "@" + term
1029
+ if (Object.prototype.hasOwnProperty.call(this._idfCache, cacheKey)) return this._idfCache[cacheKey]
1030
+
1031
+ var documentFrequency = this.tokenStore.count(term),
1032
+ idf = 1
1033
+
1034
+ if (documentFrequency > 0) {
1035
+ idf = 1 + Math.log(this.tokenStore.length / documentFrequency)
1036
+ }
1037
+
1038
+ return this._idfCache[cacheKey] = idf
1039
+ }
1040
+
1041
+ /**
1042
+ * Searches the index using the passed query.
1043
+ *
1044
+ * Queries should be a string, multiple words are allowed and will lead to an
1045
+ * AND based query, e.g. `idx.search('foo bar')` will run a search for
1046
+ * documents containing both 'foo' and 'bar'.
1047
+ *
1048
+ * All query tokens are passed through the same pipeline that document tokens
1049
+ * are passed through, so any language processing involved will be run on every
1050
+ * query term.
1051
+ *
1052
+ * Each query term is expanded, so that the term 'he' might be expanded to
1053
+ * 'hello' and 'help' if those terms were already included in the index.
1054
+ *
1055
+ * Matching documents are returned as an array of objects, each object contains
1056
+ * the matching document ref, as set for this index, and the similarity score
1057
+ * for this document against the query.
1058
+ *
1059
+ * @param {String} query The query to search the index with.
1060
+ * @returns {Object}
1061
+ * @see Index.prototype.idf
1062
+ * @see Index.prototype.documentVector
1063
+ * @memberOf Index
1064
+ */
1065
+ lunr.Index.prototype.search = function (query) {
1066
+ var queryTokens = this.pipeline.run(lunr.tokenizer(query)),
1067
+ queryVector = new lunr.Vector,
1068
+ documentSets = [],
1069
+ fieldBoosts = this._fields.reduce(function (memo, f) { return memo + f.boost }, 0)
1070
+
1071
+ var hasSomeToken = queryTokens.some(function (token) {
1072
+ return this.tokenStore.has(token)
1073
+ }, this)
1074
+
1075
+ if (!hasSomeToken) return []
1076
+
1077
+ queryTokens
1078
+ .forEach(function (token, i, tokens) {
1079
+ var tf = 1 / tokens.length * this._fields.length * fieldBoosts,
1080
+ self = this
1081
+
1082
+ var set = this.tokenStore.expand(token).reduce(function (memo, key) {
1083
+ var pos = self.corpusTokens.indexOf(key),
1084
+ idf = self.idf(key),
1085
+ similarityBoost = 1,
1086
+ set = new lunr.SortedSet
1087
+
1088
+ // if the expanded key is not an exact match to the token then
1089
+ // penalise the score for this key by how different the key is
1090
+ // to the token.
1091
+ if (key !== token) {
1092
+ var diff = Math.max(3, key.length - token.length)
1093
+ similarityBoost = 1 / Math.log(diff)
1094
+ }
1095
+
1096
+ // calculate the query tf-idf score for this token
1097
+ // applying an similarityBoost to ensure exact matches
1098
+ // these rank higher than expanded terms
1099
+ if (pos > -1) queryVector.insert(pos, tf * idf * similarityBoost)
1100
+
1101
+ // add all the documents that have this key into a set
1102
+ Object.keys(self.tokenStore.get(key)).forEach(function (ref) { set.add(ref) })
1103
+
1104
+ return memo.union(set)
1105
+ }, new lunr.SortedSet)
1106
+
1107
+ documentSets.push(set)
1108
+ }, this)
1109
+
1110
+ var documentSet = documentSets.reduce(function (memo, set) {
1111
+ return memo.intersect(set)
1112
+ })
1113
+
1114
+ return documentSet
1115
+ .map(function (ref) {
1116
+ return { ref: ref, score: queryVector.similarity(this.documentVector(ref)) }
1117
+ }, this)
1118
+ .sort(function (a, b) {
1119
+ return b.score - a.score
1120
+ })
1121
+ }
1122
+
1123
+ /**
1124
+ * Generates a vector containing all the tokens in the document matching the
1125
+ * passed documentRef.
1126
+ *
1127
+ * The vector contains the tf-idf score for each token contained in the
1128
+ * document with the passed documentRef. The vector will contain an element
1129
+ * for every token in the indexes corpus, if the document does not contain that
1130
+ * token the element will be 0.
1131
+ *
1132
+ * @param {Object} documentRef The ref to find the document with.
1133
+ * @returns {lunr.Vector}
1134
+ * @private
1135
+ * @memberOf Index
1136
+ */
1137
+ lunr.Index.prototype.documentVector = function (documentRef) {
1138
+ var documentTokens = this.documentStore.get(documentRef),
1139
+ documentTokensLength = documentTokens.length,
1140
+ documentVector = new lunr.Vector
1141
+
1142
+ for (var i = 0; i < documentTokensLength; i++) {
1143
+ var token = documentTokens.elements[i],
1144
+ tf = this.tokenStore.get(token)[documentRef].tf,
1145
+ idf = this.idf(token)
1146
+
1147
+ documentVector.insert(this.corpusTokens.indexOf(token), tf * idf)
1148
+ };
1149
+
1150
+ return documentVector
1151
+ }
1152
+
1153
+ /**
1154
+ * Returns a representation of the index ready for serialisation.
1155
+ *
1156
+ * @returns {Object}
1157
+ * @memberOf Index
1158
+ */
1159
+ lunr.Index.prototype.toJSON = function () {
1160
+ return {
1161
+ version: lunr.version,
1162
+ fields: this._fields,
1163
+ ref: this._ref,
1164
+ documentStore: this.documentStore.toJSON(),
1165
+ tokenStore: this.tokenStore.toJSON(),
1166
+ corpusTokens: this.corpusTokens.toJSON(),
1167
+ pipeline: this.pipeline.toJSON()
1168
+ }
1169
+ }
1170
+
1171
+ /**
1172
+ * Applies a plugin to the current index.
1173
+ *
1174
+ * A plugin is a function that is called with the index as its context.
1175
+ * Plugins can be used to customise or extend the behaviour the index
1176
+ * in some way. A plugin is just a function, that encapsulated the custom
1177
+ * behaviour that should be applied to the index.
1178
+ *
1179
+ * The plugin function will be called with the index as its argument, additional
1180
+ * arguments can also be passed when calling use. The function will be called
1181
+ * with the index as its context.
1182
+ *
1183
+ * Example:
1184
+ *
1185
+ * var myPlugin = function (idx, arg1, arg2) {
1186
+ * // `this` is the index to be extended
1187
+ * // apply any extensions etc here.
1188
+ * }
1189
+ *
1190
+ * var idx = lunr(function () {
1191
+ * this.use(myPlugin, 'arg1', 'arg2')
1192
+ * })
1193
+ *
1194
+ * @param {Function} plugin The plugin to apply.
1195
+ * @memberOf Index
1196
+ */
1197
+ lunr.Index.prototype.use = function (plugin) {
1198
+ var args = Array.prototype.slice.call(arguments, 1)
1199
+ args.unshift(this)
1200
+ plugin.apply(this, args)
1201
+ }
1202
+ /*!
1203
+ * lunr.Store
1204
+ * Copyright (C) 2014 Oliver Nightingale
1205
+ */
1206
+
1207
+ /**
1208
+ * lunr.Store is a simple key-value store used for storing sets of tokens for
1209
+ * documents stored in index.
1210
+ *
1211
+ * @constructor
1212
+ * @module
1213
+ */
1214
+ lunr.Store = function () {
1215
+ this.store = {}
1216
+ this.length = 0
1217
+ }
1218
+
1219
+ /**
1220
+ * Loads a previously serialised store
1221
+ *
1222
+ * @param {Object} serialisedData The serialised store to load.
1223
+ * @returns {lunr.Store}
1224
+ * @memberOf Store
1225
+ */
1226
+ lunr.Store.load = function (serialisedData) {
1227
+ var store = new this
1228
+
1229
+ store.length = serialisedData.length
1230
+ store.store = Object.keys(serialisedData.store).reduce(function (memo, key) {
1231
+ memo[key] = lunr.SortedSet.load(serialisedData.store[key])
1232
+ return memo
1233
+ }, {})
1234
+
1235
+ return store
1236
+ }
1237
+
1238
+ /**
1239
+ * Stores the given tokens in the store against the given id.
1240
+ *
1241
+ * @param {Object} id The key used to store the tokens against.
1242
+ * @param {Object} tokens The tokens to store against the key.
1243
+ * @memberOf Store
1244
+ */
1245
+ lunr.Store.prototype.set = function (id, tokens) {
1246
+ if (!this.has(id)) this.length++
1247
+ this.store[id] = tokens
1248
+ }
1249
+
1250
+ /**
1251
+ * Retrieves the tokens from the store for a given key.
1252
+ *
1253
+ * @param {Object} id The key to lookup and retrieve from the store.
1254
+ * @returns {Object}
1255
+ * @memberOf Store
1256
+ */
1257
+ lunr.Store.prototype.get = function (id) {
1258
+ return this.store[id]
1259
+ }
1260
+
1261
+ /**
1262
+ * Checks whether the store contains a key.
1263
+ *
1264
+ * @param {Object} id The id to look up in the store.
1265
+ * @returns {Boolean}
1266
+ * @memberOf Store
1267
+ */
1268
+ lunr.Store.prototype.has = function (id) {
1269
+ return id in this.store
1270
+ }
1271
+
1272
+ /**
1273
+ * Removes the value for a key in the store.
1274
+ *
1275
+ * @param {Object} id The id to remove from the store.
1276
+ * @memberOf Store
1277
+ */
1278
+ lunr.Store.prototype.remove = function (id) {
1279
+ if (!this.has(id)) return
1280
+
1281
+ delete this.store[id]
1282
+ this.length--
1283
+ }
1284
+
1285
+ /**
1286
+ * Returns a representation of the store ready for serialisation.
1287
+ *
1288
+ * @returns {Object}
1289
+ * @memberOf Store
1290
+ */
1291
+ lunr.Store.prototype.toJSON = function () {
1292
+ return {
1293
+ store: this.store,
1294
+ length: this.length
1295
+ }
1296
+ }
1297
+
1298
+ /*!
1299
+ * lunr.stemmer
1300
+ * Copyright (C) 2014 Oliver Nightingale
1301
+ * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt
1302
+ */
1303
+
1304
+ /**
1305
+ * lunr.stemmer is an english language stemmer, this is a JavaScript
1306
+ * implementation of the PorterStemmer taken from http://tartaurs.org/~martin
1307
+ *
1308
+ * @module
1309
+ * @param {String} str The string to stem
1310
+ * @returns {String}
1311
+ * @see lunr.Pipeline
1312
+ */
1313
+ lunr.stemmer = (function(){
1314
+ var step2list = {
1315
+ "ational" : "ate",
1316
+ "tional" : "tion",
1317
+ "enci" : "ence",
1318
+ "anci" : "ance",
1319
+ "izer" : "ize",
1320
+ "bli" : "ble",
1321
+ "alli" : "al",
1322
+ "entli" : "ent",
1323
+ "eli" : "e",
1324
+ "ousli" : "ous",
1325
+ "ization" : "ize",
1326
+ "ation" : "ate",
1327
+ "ator" : "ate",
1328
+ "alism" : "al",
1329
+ "iveness" : "ive",
1330
+ "fulness" : "ful",
1331
+ "ousness" : "ous",
1332
+ "aliti" : "al",
1333
+ "iviti" : "ive",
1334
+ "biliti" : "ble",
1335
+ "logi" : "log"
1336
+ },
1337
+
1338
+ step3list = {
1339
+ "icate" : "ic",
1340
+ "ative" : "",
1341
+ "alize" : "al",
1342
+ "iciti" : "ic",
1343
+ "ical" : "ic",
1344
+ "ful" : "",
1345
+ "ness" : ""
1346
+ },
1347
+
1348
+ c = "[^aeiou]", // consonant
1349
+ v = "[aeiouy]", // vowel
1350
+ C = c + "[^aeiouy]*", // consonant sequence
1351
+ V = v + "[aeiou]*", // vowel sequence
1352
+
1353
+ mgr0 = "^(" + C + ")?" + V + C, // [C]VC... is m>0
1354
+ meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$", // [C]VC[V] is m=1
1355
+ mgr1 = "^(" + C + ")?" + V + C + V + C, // [C]VCVC... is m>1
1356
+ s_v = "^(" + C + ")?" + v; // vowel in stem
1357
+
1358
+ var re_mgr0 = new RegExp(mgr0);
1359
+ var re_mgr1 = new RegExp(mgr1);
1360
+ var re_meq1 = new RegExp(meq1);
1361
+ var re_s_v = new RegExp(s_v);
1362
+
1363
+ var re_1a = /^(.+?)(ss|i)es$/;
1364
+ var re2_1a = /^(.+?)([^s])s$/;
1365
+ var re_1b = /^(.+?)eed$/;
1366
+ var re2_1b = /^(.+?)(ed|ing)$/;
1367
+ var re_1b_2 = /.$/;
1368
+ var re2_1b_2 = /(at|bl|iz)$/;
1369
+ var re3_1b_2 = new RegExp("([^aeiouylsz])\\1$");
1370
+ var re4_1b_2 = new RegExp("^" + C + v + "[^aeiouwxy]$");
1371
+
1372
+ var re_1c = /^(.+?[^aeiou])y$/;
1373
+ var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
1374
+
1375
+ var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
1376
+
1377
+ var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
1378
+ var re2_4 = /^(.+?)(s|t)(ion)$/;
1379
+
1380
+ var re_5 = /^(.+?)e$/;
1381
+ var re_5_1 = /ll$/;
1382
+ var re3_5 = new RegExp("^" + C + v + "[^aeiouwxy]$");
1383
+
1384
+ var porterStemmer = function porterStemmer(w) {
1385
+ var stem,
1386
+ suffix,
1387
+ firstch,
1388
+ re,
1389
+ re2,
1390
+ re3,
1391
+ re4;
1392
+
1393
+ if (w.length < 3) { return w; }
1394
+
1395
+ firstch = w.substr(0,1);
1396
+ if (firstch == "y") {
1397
+ w = firstch.toUpperCase() + w.substr(1);
1398
+ }
1399
+
1400
+ // Step 1a
1401
+ re = re_1a
1402
+ re2 = re2_1a;
1403
+
1404
+ if (re.test(w)) { w = w.replace(re,"$1$2"); }
1405
+ else if (re2.test(w)) { w = w.replace(re2,"$1$2"); }
1406
+
1407
+ // Step 1b
1408
+ re = re_1b;
1409
+ re2 = re2_1b;
1410
+ if (re.test(w)) {
1411
+ var fp = re.exec(w);
1412
+ re = re_mgr0;
1413
+ if (re.test(fp[1])) {
1414
+ re = re_1b_2;
1415
+ w = w.replace(re,"");
1416
+ }
1417
+ } else if (re2.test(w)) {
1418
+ var fp = re2.exec(w);
1419
+ stem = fp[1];
1420
+ re2 = re_s_v;
1421
+ if (re2.test(stem)) {
1422
+ w = stem;
1423
+ re2 = re2_1b_2;
1424
+ re3 = re3_1b_2;
1425
+ re4 = re4_1b_2;
1426
+ if (re2.test(w)) { w = w + "e"; }
1427
+ else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,""); }
1428
+ else if (re4.test(w)) { w = w + "e"; }
1429
+ }
1430
+ }
1431
+
1432
+ // 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)
1433
+ re = re_1c;
1434
+ if (re.test(w)) {
1435
+ var fp = re.exec(w);
1436
+ stem = fp[1];
1437
+ w = stem + "i";
1438
+ }
1439
+
1440
+ // Step 2
1441
+ re = re_2;
1442
+ if (re.test(w)) {
1443
+ var fp = re.exec(w);
1444
+ stem = fp[1];
1445
+ suffix = fp[2];
1446
+ re = re_mgr0;
1447
+ if (re.test(stem)) {
1448
+ w = stem + step2list[suffix];
1449
+ }
1450
+ }
1451
+
1452
+ // Step 3
1453
+ re = re_3;
1454
+ if (re.test(w)) {
1455
+ var fp = re.exec(w);
1456
+ stem = fp[1];
1457
+ suffix = fp[2];
1458
+ re = re_mgr0;
1459
+ if (re.test(stem)) {
1460
+ w = stem + step3list[suffix];
1461
+ }
1462
+ }
1463
+
1464
+ // Step 4
1465
+ re = re_4;
1466
+ re2 = re2_4;
1467
+ if (re.test(w)) {
1468
+ var fp = re.exec(w);
1469
+ stem = fp[1];
1470
+ re = re_mgr1;
1471
+ if (re.test(stem)) {
1472
+ w = stem;
1473
+ }
1474
+ } else if (re2.test(w)) {
1475
+ var fp = re2.exec(w);
1476
+ stem = fp[1] + fp[2];
1477
+ re2 = re_mgr1;
1478
+ if (re2.test(stem)) {
1479
+ w = stem;
1480
+ }
1481
+ }
1482
+
1483
+ // Step 5
1484
+ re = re_5;
1485
+ if (re.test(w)) {
1486
+ var fp = re.exec(w);
1487
+ stem = fp[1];
1488
+ re = re_mgr1;
1489
+ re2 = re_meq1;
1490
+ re3 = re3_5;
1491
+ if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {
1492
+ w = stem;
1493
+ }
1494
+ }
1495
+
1496
+ re = re_5_1;
1497
+ re2 = re_mgr1;
1498
+ if (re.test(w) && re2.test(w)) {
1499
+ re = re_1b_2;
1500
+ w = w.replace(re,"");
1501
+ }
1502
+
1503
+ // and turn initial Y back to y
1504
+
1505
+ if (firstch == "y") {
1506
+ w = firstch.toLowerCase() + w.substr(1);
1507
+ }
1508
+
1509
+ return w;
1510
+ };
1511
+
1512
+ return porterStemmer;
1513
+ })();
1514
+
1515
+ lunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer')
1516
+ /*!
1517
+ * lunr.stopWordFilter
1518
+ * Copyright (C) 2014 Oliver Nightingale
1519
+ */
1520
+
1521
+ /**
1522
+ * lunr.stopWordFilter is an English language stop word list filter, any words
1523
+ * contained in the list will not be passed through the filter.
1524
+ *
1525
+ * This is intended to be used in the Pipeline. If the token does not pass the
1526
+ * filter then undefined will be returned.
1527
+ *
1528
+ * @module
1529
+ * @param {String} token The token to pass through the filter
1530
+ * @returns {String}
1531
+ * @see lunr.Pipeline
1532
+ */
1533
+ lunr.stopWordFilter = function (token) {
1534
+ if (lunr.stopWordFilter.stopWords.indexOf(token) === -1) return token
1535
+ }
1536
+
1537
+ lunr.stopWordFilter.stopWords = new lunr.SortedSet
1538
+ lunr.stopWordFilter.stopWords.length = 119
1539
+ lunr.stopWordFilter.stopWords.elements = [
1540
+ "",
1541
+ "a",
1542
+ "able",
1543
+ "about",
1544
+ "across",
1545
+ "after",
1546
+ "all",
1547
+ "almost",
1548
+ "also",
1549
+ "am",
1550
+ "among",
1551
+ "an",
1552
+ "and",
1553
+ "any",
1554
+ "are",
1555
+ "as",
1556
+ "at",
1557
+ "be",
1558
+ "because",
1559
+ "been",
1560
+ "but",
1561
+ "by",
1562
+ "can",
1563
+ "cannot",
1564
+ "could",
1565
+ "dear",
1566
+ "did",
1567
+ "do",
1568
+ "does",
1569
+ "either",
1570
+ "else",
1571
+ "ever",
1572
+ "every",
1573
+ "for",
1574
+ "from",
1575
+ "get",
1576
+ "got",
1577
+ "had",
1578
+ "has",
1579
+ "have",
1580
+ "he",
1581
+ "her",
1582
+ "hers",
1583
+ "him",
1584
+ "his",
1585
+ "how",
1586
+ "however",
1587
+ "i",
1588
+ "if",
1589
+ "in",
1590
+ "into",
1591
+ "is",
1592
+ "it",
1593
+ "its",
1594
+ "just",
1595
+ "least",
1596
+ "let",
1597
+ "like",
1598
+ "likely",
1599
+ "may",
1600
+ "me",
1601
+ "might",
1602
+ "most",
1603
+ "must",
1604
+ "my",
1605
+ "neither",
1606
+ "no",
1607
+ "nor",
1608
+ "not",
1609
+ "of",
1610
+ "off",
1611
+ "often",
1612
+ "on",
1613
+ "only",
1614
+ "or",
1615
+ "other",
1616
+ "our",
1617
+ "own",
1618
+ "rather",
1619
+ "said",
1620
+ "say",
1621
+ "says",
1622
+ "she",
1623
+ "should",
1624
+ "since",
1625
+ "so",
1626
+ "some",
1627
+ "than",
1628
+ "that",
1629
+ "the",
1630
+ "their",
1631
+ "them",
1632
+ "then",
1633
+ "there",
1634
+ "these",
1635
+ "they",
1636
+ "this",
1637
+ "tis",
1638
+ "to",
1639
+ "too",
1640
+ "twas",
1641
+ "us",
1642
+ "wants",
1643
+ "was",
1644
+ "we",
1645
+ "were",
1646
+ "what",
1647
+ "when",
1648
+ "where",
1649
+ "which",
1650
+ "while",
1651
+ "who",
1652
+ "whom",
1653
+ "why",
1654
+ "will",
1655
+ "with",
1656
+ "would",
1657
+ "yet",
1658
+ "you",
1659
+ "your"
1660
+ ]
1661
+
1662
+ lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter')
1663
+ /*!
1664
+ * lunr.trimmer
1665
+ * Copyright (C) 2014 Oliver Nightingale
1666
+ */
1667
+
1668
+ /**
1669
+ * lunr.trimmer is a pipeline function for trimming non word
1670
+ * characters from the begining and end of tokens before they
1671
+ * enter the index.
1672
+ *
1673
+ * This implementation may not work correctly for non latin
1674
+ * characters and should either be removed or adapted for use
1675
+ * with languages with non-latin characters.
1676
+ *
1677
+ * @module
1678
+ * @param {String} token The token to pass through the filter
1679
+ * @returns {String}
1680
+ * @see lunr.Pipeline
1681
+ */
1682
+ lunr.trimmer = function (token) {
1683
+ return token
1684
+ .replace(/^\W+/, '')
1685
+ .replace(/\W+$/, '')
1686
+ }
1687
+
1688
+ lunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer')
1689
+ /*!
1690
+ * lunr.stemmer
1691
+ * Copyright (C) 2014 Oliver Nightingale
1692
+ * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt
1693
+ */
1694
+
1695
+ /**
1696
+ * lunr.TokenStore is used for efficient storing and lookup of the reverse
1697
+ * index of token to document ref.
1698
+ *
1699
+ * @constructor
1700
+ */
1701
+ lunr.TokenStore = function () {
1702
+ this.root = { docs: {} }
1703
+ this.length = 0
1704
+ }
1705
+
1706
+ /**
1707
+ * Loads a previously serialised token store
1708
+ *
1709
+ * @param {Object} serialisedData The serialised token store to load.
1710
+ * @returns {lunr.TokenStore}
1711
+ * @memberOf TokenStore
1712
+ */
1713
+ lunr.TokenStore.load = function (serialisedData) {
1714
+ var store = new this
1715
+
1716
+ store.root = serialisedData.root
1717
+ store.length = serialisedData.length
1718
+
1719
+ return store
1720
+ }
1721
+
1722
+ /**
1723
+ * Adds a new token doc pair to the store.
1724
+ *
1725
+ * By default this function starts at the root of the current store, however
1726
+ * it can start at any node of any token store if required.
1727
+ *
1728
+ * @param {String} token The token to store the doc under
1729
+ * @param {Object} doc The doc to store against the token
1730
+ * @param {Object} root An optional node at which to start looking for the
1731
+ * correct place to enter the doc, by default the root of this lunr.TokenStore
1732
+ * is used.
1733
+ * @memberOf TokenStore
1734
+ */
1735
+ lunr.TokenStore.prototype.add = function (token, doc, root) {
1736
+ var root = root || this.root,
1737
+ key = token[0],
1738
+ rest = token.slice(1)
1739
+
1740
+ if (!(key in root)) root[key] = {docs: {}}
1741
+
1742
+ if (rest.length === 0) {
1743
+ root[key].docs[doc.ref] = doc
1744
+ this.length += 1
1745
+ return
1746
+ } else {
1747
+ return this.add(rest, doc, root[key])
1748
+ }
1749
+ }
1750
+
1751
+ /**
1752
+ * Checks whether this key is contained within this lunr.TokenStore.
1753
+ *
1754
+ * By default this function starts at the root of the current store, however
1755
+ * it can start at any node of any token store if required.
1756
+ *
1757
+ * @param {String} token The token to check for
1758
+ * @param {Object} root An optional node at which to start
1759
+ * @memberOf TokenStore
1760
+ */
1761
+ lunr.TokenStore.prototype.has = function (token) {
1762
+ if (!token) return false
1763
+
1764
+ var node = this.root
1765
+
1766
+ for (var i = 0; i < token.length; i++) {
1767
+ if (!node[token[i]]) return false
1768
+
1769
+ node = node[token[i]]
1770
+ }
1771
+
1772
+ return true
1773
+ }
1774
+
1775
+ /**
1776
+ * Retrieve a node from the token store for a given token.
1777
+ *
1778
+ * By default this function starts at the root of the current store, however
1779
+ * it can start at any node of any token store if required.
1780
+ *
1781
+ * @param {String} token The token to get the node for.
1782
+ * @param {Object} root An optional node at which to start.
1783
+ * @returns {Object}
1784
+ * @see TokenStore.prototype.get
1785
+ * @memberOf TokenStore
1786
+ */
1787
+ lunr.TokenStore.prototype.getNode = function (token) {
1788
+ if (!token) return {}
1789
+
1790
+ var node = this.root
1791
+
1792
+ for (var i = 0; i < token.length; i++) {
1793
+ if (!node[token[i]]) return {}
1794
+
1795
+ node = node[token[i]]
1796
+ }
1797
+
1798
+ return node
1799
+ }
1800
+
1801
+ /**
1802
+ * Retrieve the documents for a node for the given token.
1803
+ *
1804
+ * By default this function starts at the root of the current store, however
1805
+ * it can start at any node of any token store if required.
1806
+ *
1807
+ * @param {String} token The token to get the documents for.
1808
+ * @param {Object} root An optional node at which to start.
1809
+ * @returns {Object}
1810
+ * @memberOf TokenStore
1811
+ */
1812
+ lunr.TokenStore.prototype.get = function (token, root) {
1813
+ return this.getNode(token, root).docs || {}
1814
+ }
1815
+
1816
+ lunr.TokenStore.prototype.count = function (token, root) {
1817
+ return Object.keys(this.get(token, root)).length
1818
+ }
1819
+
1820
+ /**
1821
+ * Remove the document identified by ref from the token in the store.
1822
+ *
1823
+ * By default this function starts at the root of the current store, however
1824
+ * it can start at any node of any token store if required.
1825
+ *
1826
+ * @param {String} token The token to get the documents for.
1827
+ * @param {String} ref The ref of the document to remove from this token.
1828
+ * @param {Object} root An optional node at which to start.
1829
+ * @returns {Object}
1830
+ * @memberOf TokenStore
1831
+ */
1832
+ lunr.TokenStore.prototype.remove = function (token, ref) {
1833
+ if (!token) return
1834
+ var node = this.root
1835
+
1836
+ for (var i = 0; i < token.length; i++) {
1837
+ if (!(token[i] in node)) return
1838
+ node = node[token[i]]
1839
+ }
1840
+
1841
+ delete node.docs[ref]
1842
+ }
1843
+
1844
+ /**
1845
+ * Find all the possible suffixes of the passed token using tokens
1846
+ * currently in the store.
1847
+ *
1848
+ * @param {String} token The token to expand.
1849
+ * @returns {Array}
1850
+ * @memberOf TokenStore
1851
+ */
1852
+ lunr.TokenStore.prototype.expand = function (token, memo) {
1853
+ var root = this.getNode(token),
1854
+ docs = root.docs || {},
1855
+ memo = memo || []
1856
+
1857
+ if (Object.keys(docs).length) memo.push(token)
1858
+
1859
+ Object.keys(root)
1860
+ .forEach(function (key) {
1861
+ if (key === 'docs') return
1862
+
1863
+ memo.concat(this.expand(token + key, memo))
1864
+ }, this)
1865
+
1866
+ return memo
1867
+ }
1868
+
1869
+ /**
1870
+ * Returns a representation of the token store ready for serialisation.
1871
+ *
1872
+ * @returns {Object}
1873
+ * @memberOf TokenStore
1874
+ */
1875
+ lunr.TokenStore.prototype.toJSON = function () {
1876
+ return {
1877
+ root: this.root,
1878
+ length: this.length
1879
+ }
1880
+ }
1881
+
1882
+
1883
+ /**
1884
+ * export the module via AMD, CommonJS or as a browser global
1885
+ * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js
1886
+ */
1887
+ ;(function (root, factory) {
1888
+ if (typeof define === 'function' && define.amd) {
1889
+ // AMD. Register as an anonymous module.
1890
+ define(factory)
1891
+ } else if (typeof exports === 'object') {
1892
+ /**
1893
+ * Node. Does not work with strict CommonJS, but
1894
+ * only CommonJS-like enviroments that support module.exports,
1895
+ * like Node.
1896
+ */
1897
+ module.exports = factory()
1898
+ } else {
1899
+ // Browser globals (root is window)
1900
+ root.lunr = factory()
1901
+ }
1902
+ }(this, function () {
1903
+ /**
1904
+ * Just return a value to define the module export.
1905
+ * This example returns an object, but the module
1906
+ * can return a function as the exported value.
1907
+ */
1908
+ return lunr
1909
+ }))
1910
+ })()