├── .gitignore ├── build.js ├── config.js ├── index.html ├── package.json ├── readme.md └── src ├── config.js ├── css ├── content.css ├── fonts.css └── layout.css ├── domhandler.js ├── index.js ├── mod ├── domconsole.js ├── events.js ├── localforage.min.js ├── sdm.js ├── shortcuts.js ├── tabbing.js └── utils.js └── spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | jspm_packages/ 3 | dist/ 4 | spec_cache.html 5 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | var jspm = require('jspm'); 2 | var fs = require('fs'); 3 | var less = require('less'); 4 | jspm.setPackagePath('.'); 5 | jspm.bundleSFX('src/index', 'dist/index.js', { 6 | minify: true, 7 | mangled: true 8 | }).then(function () { 9 | console.log('jspm bundling complete, adding localforage'); 10 | }).then(function () { 11 | fs.writeFileSync( 12 | 'dist/index.js', 13 | Buffer.concat([ 14 | fs.readFileSync('./src/mod/localforage.min.js'), 15 | fs.readFileSync('./dist/index.js') 16 | ]) 17 | ); 18 | }).then(function () { 19 | less.render( 20 | [ 21 | fs.readFileSync('./src/css/layout.css') + '', 22 | fs.readFileSync('./src/css/content.css') + '' 23 | ].join('\n'), 24 | { 25 | fileName: 'build.css', 26 | compress: 'true' 27 | } 28 | ).then(function (output) { 29 | fs.writeFileSync( 30 | 'dist/build.css', 31 | output.css 32 | ); 33 | console.log('bundled css. finished build'); 34 | }); 35 | }); -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | System.config({ 2 | "baseURL": "/", 3 | "transpiler": "babel", 4 | "babelOptions": { 5 | "optional": [ 6 | "runtime" 7 | ], 8 | "blacklist": [ 9 | "asyncToGenerator", 10 | "bluebirdCoroutines", 11 | "es3.memberExpressionLiterals", 12 | "es3.propertyLiterals", 13 | "es5.properties.mutators", 14 | // "es6.arrowFunctions", 15 | // "es6.blockScoping", 16 | // "es6.classes", 17 | // "es6.constants", 18 | // "es6.destructuring", 19 | // "es6.forOf", 20 | // "es6.modules", 21 | // "es6.objectSuper", 22 | // "es6.parameters.default", 23 | // "es6.parameters.rest", 24 | // "es6.properties.computed", 25 | // "es6.properties.shorthand", 26 | "es6.regex.sticky", 27 | "es6.regex.unicode", 28 | // "es6.spec.blockScoping", 29 | "es6.spec.symbols", 30 | // "es6.spec.templateLiterals", 31 | // "es6.spread", 32 | // "es6.tailCall", 33 | // "es6.templateLiterals", 34 | "es7.asyncFunctions", 35 | "es7.classProperties", 36 | "es7.comprehensions", 37 | "es7.decorators", 38 | "es7.doExpressions", 39 | "es7.exponentiationOperator", 40 | "es7.exportExtensions", 41 | "es7.objectRestSpread", 42 | "es7.trailingFunctionCommas", 43 | "flow", 44 | "jscript", 45 | // "ludicrous", 46 | "minification.deadCodeElimination", 47 | // "minification.memberExpressionLiterals", 48 | // "minification.propertyLiterals", 49 | "optimisation.flow.forOf", 50 | "optimisation.react.constantElements", 51 | "optimisation.react.inlineElements", 52 | "react", 53 | "reactCompat", 54 | // "regenerator", 55 | // "runtime", 56 | "spec.blockScopedFunctions", 57 | "spec.functionName", 58 | "spec.protoToAssign", 59 | "spec.undefinedToVoid", 60 | "strict", 61 | "utility.inlineEnvironmentVariables", 62 | "minification.constantFolding", 63 | // "utility.removeConsole", 64 | "minification.removeDebugger", 65 | "validation.react", 66 | "validation.undeclaredVariableCheck" 67 | ] 68 | }, 69 | "paths": { 70 | "*": "*.js", 71 | "github:*": "jspm_packages/github/*.js", 72 | "npm:*": "jspm_packages/npm/*.js" 73 | } 74 | }); 75 | 76 | System.config({ 77 | "map": { 78 | "babel": "npm:babel-core@5.5.8", 79 | "babel-runtime": "npm:babel-runtime@5.5.8", 80 | "core-js": "npm:core-js@0.9.18", 81 | "fetch": "github:github/fetch@0.9.0", 82 | "less": "github:aaike/jspm-less-plugin@0.0.5", 83 | "localforage": "npm:localforage@1.2.3", 84 | "github:aaike/jspm-less-plugin@0.0.5": { 85 | "less.js": "github:distros/less@2.4.0" 86 | }, 87 | "github:jspm/nodelibs-path@0.1.0": { 88 | "path-browserify": "npm:path-browserify@0.0.0" 89 | }, 90 | "github:jspm/nodelibs-process@0.1.1": { 91 | "process": "npm:process@0.10.1" 92 | }, 93 | "npm:asap@1.0.0": { 94 | "process": "github:jspm/nodelibs-process@0.1.1" 95 | }, 96 | "npm:babel-runtime@5.5.8": { 97 | "process": "github:jspm/nodelibs-process@0.1.1" 98 | }, 99 | "npm:core-js@0.9.18": { 100 | "fs": "github:jspm/nodelibs-fs@0.1.2", 101 | "process": "github:jspm/nodelibs-process@0.1.1", 102 | "systemjs-json": "github:systemjs/plugin-json@0.1.0" 103 | }, 104 | "npm:localforage@1.2.3": { 105 | "path": "github:jspm/nodelibs-path@0.1.0", 106 | "process": "github:jspm/nodelibs-process@0.1.1", 107 | "promise": "npm:promise@5.0.0" 108 | }, 109 | "npm:path-browserify@0.0.0": { 110 | "process": "github:jspm/nodelibs-process@0.1.1" 111 | }, 112 | "npm:promise@5.0.0": { 113 | "asap": "npm:asap@1.0.0" 114 | } 115 | } 116 | }); 117 | 118 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | especser 6 | 7 | 8 | 9 | 10 |
11 | especser 12 |
13 | 14 | 15 |
16 |
17 | 18 | 19 | 20 |
21 |
22 |
23 | 27 |
28 |
especser is an in-browser app to browse and read the ECMA-262 ECMAScript Standard Specification Edition 6.0.
Written by Awal Garg aka Rash. on github at https://github.com/awalGarg/especser/
29 |
30 |
31 |

32 | 
33 | 
36 | 
37 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "especser",
 3 |   "version": "1.0.0",
 4 |   "description": "browse the es spec",
 5 |   "main": "index.js",
 6 |   "scripts": {
 7 |     "test": "echo \"Error: no test specified\" && exit 1"
 8 |   },
 9 |   "author": "Awal Garg aka Rash ",
10 |   "license": "WTFPL",
11 |   "repository": {
12 |     "type": "git",
13 |     "url": "https://github.com/awalGarg/especser/"
14 |   },
15 |   "jspm": {
16 |     "directories": {},
17 |     "dependencies": {
18 |       "fetch": "github:github/fetch@^0.9.0",
19 |       "less": "github:aaike/jspm-less-plugin@^0.0.5",
20 |       "localforage": "npm:localforage@^1.2.3"
21 |     },
22 |     "devDependencies": {
23 |       "babel": "npm:babel-core@^5.1.13",
24 |       "babel-runtime": "npm:babel-runtime@^5.1.13",
25 |       "core-js": "npm:core-js@^0.9.4"
26 |     }
27 |   },
28 |   "devDependencies": {
29 |     "jspm": "^0.15.7",
30 |     "less": "^2.5.1"
31 |   }
32 | }
33 | 


--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
 1 | #especser
 2 | 
 3 | especser is an in browser app to browse and read the ECMA-262 standard's 6th edition for ECMAScript standardized by ECMAInternational
 4 | 
 5 | ##why
 6 | 
 7 | the es specs are pretty much awful to read. even more awful to navigate. especser presents the spec in an easy on eyes way, with fuzzy searching of the different sections in the spec, tabbed browsing support, internal routing of links etc.
 8 | 
 9 | ##how
10 | 
11 | 1. goto http://awalGarg.github.io/especser
12 | 2. click the update button on the corner
13 | 	3. this will fetch the spec directly from http://ecma-international.org/ecma-262/6.0/index.html, pass it through some weirdo functions, store a json map and different parts of the spec in indexedDB
14 | 	4. you only have to do this once, and the spec will only be fetched once
15 | 5. you can search for stuff you want. use up/down arrow keys to select one of the results and hit enter (or click on one of the search result)
16 | 6. press `Ctrl+P` to toggle the top-bar
17 | 7. opened tabs are shown on the sidebar on the left.
18 | 8. top of the content is shown a path to the present page. you can click on any link in between to open that
19 | 9. bottom of the content is shown a list of links to sub-sections for the page if any
20 | 10. click on the large index number at the top-left of any content page and copy the url in the address bar to share a perma-link to that section with anyone else
21 | 11. links inside the spec are internal. so clicking on any link inside the spec will open that section within the app
22 | 12. you can remove the data from indexedDB by clicking the clear store button
23 | 13. keep hitting the down arrow key while searching to extract more results
24 | 14. if your search starts with `sec: `, it will list all those sections and subsections. if a query follows, only sections matching it will be listed.
25 | 
26 | ##running locally
27 | 
28 | - clone repo
29 | - `npm install`
30 | - `jspm install`
31 | - `iojs build.js`
32 | - start a webserver in the project root
33 | - open the url to the server
34 | 
35 | ##screenshots
36 | 
37 | ofcourse
38 | 
39 | ![seeing a simple page in especser with some tabs open](http://i.imgur.com/lkIcVon.png)
40 | 
41 | ![searching for something](http://i.imgur.com/xz0eNK2.png)
42 | 
43 | ##license
44 | 
45 | WTFPL


--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | export let config = {
2 | 	// SPEC_URL: '/spec_cache.html',
3 | 	SPEC_URL: 'http://crossorigin.me/http://www.ecma-international.org/ecma-262/6.0/index.html',
4 | 	IDBstoreName: 'sec'
5 | };


--------------------------------------------------------------------------------
/src/css/content.css:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * directly copied from ecmascript's own css
  3 |  */
  4 | .tab-content { /* this one is slightly modified... maaybe */
  5 | 	background-color: #fdfdfc;
  6 |     color: #333333;
  7 |     font-family: Cambria, Palatino Linotype, Palatino, Liberation Serif, serif;
  8 |     font-size: 17px;
  9 |     line-height: 135%;
 10 |     padding: 1rem;
 11 | 
 12 | 	h1 {
 13 | 		font-size: 110%;
 14 | 		margin-bottom: 0.8em;
 15 | 		padding-bottom: 0.2em;
 16 | 		position: sticky;
 17 | 		top: 0;
 18 | 		z-index: 1;
 19 | 		background-color: #fdfdfc;
 20 | 		box-shadow: 0 0 6px #fdfdfc;
 21 | 		margin-left: -7em;
 22 | 		padding-left: 7em;
 23 | 	}
 24 | 
 25 | 	.stern.warning {
 26 | 	  font-weight: bold;
 27 | 	  text-transform: uppercase;
 28 | 	}
 29 | 
 30 | 	p.ECMAaddress {
 31 | 	  margin-bottom: 0em;
 32 | 	  margin-top: 0em;
 33 | 	}
 34 | 
 35 | 	p.normalBullet {
 36 | 	  margin-left: 4em;
 37 | 	  text-indent: -1.7em;
 38 | 	  margin-top: 0em;
 39 | 	  margin-bottom: 0.25em;
 40 | 	}
 41 | 
 42 | 	p.normalBulletSubstep {
 43 | 	  margin-left: 6em;
 44 | 	  text-indent: -1em;
 45 | 	  margin-top: 0em;
 46 | 	  margin-bottom: 0.25em;
 47 | 	}
 48 | 
 49 | 	pre.NoteCode {
 50 | 	  margin-bottom: 0em;
 51 | 	  margin-top: 0em;
 52 | 	}
 53 | 
 54 | 	div.note {
 55 | 	  margin: 1em 0 1em 6em;
 56 | 	}
 57 | 
 58 | 	span.nh {
 59 | 	  float: left;
 60 | 	  width: 6em;
 61 | 	  margin-left: -6em;
 62 | 	}
 63 | 
 64 | 	figure {
 65 | 	  display: block;
 66 | 	  margin: 1em 0 3em 0;
 67 | 	}
 68 | 
 69 | 	figure object {
 70 | 	  display: block;
 71 | 	  margin: 0 auto;
 72 | 	}
 73 | 
 74 | 	figure table.real-table {
 75 | 	  margin: 0 auto;
 76 | 	}
 77 | 
 78 | 	figure figcaption {
 79 | 	  display: block;
 80 | 	  color: #555555;
 81 | 	  font-weight: bold;
 82 | 	  text-align: center;
 83 | 	  margin-bottom: 0.25em;
 84 | 	}
 85 | 
 86 | 	figcaption :target {
 87 | 	  /* When a user visits #table-1, slide the caption down
 88 | 	         so it won't be obscured by a sticky heading (issue #73).
 89 | 	         Thanks to Claude Pache for this "nasty trick" (his words). */
 90 | 	  display: inline-block;
 91 | 	  padding-top: 2em;
 92 | 	  margin-top: -2em;
 93 | 	}
 94 | 
 95 | 	table.real-table {
 96 | 	  border-collapse: collapse;
 97 | 	}
 98 | 
 99 | 	table.real-table td, table.real-table th {
100 | 	  border: 1px solid black;
101 | 	  padding: 0.4em;
102 | 	  vertical-align: baseline;
103 | 	}
104 | 
105 | 	table.real-table th {
106 | 	  background-color: #eeeeee;
107 | 	}
108 | 
109 | 	table.lightweight-table {
110 | 	  border-collapse: collapse;
111 | 	  margin: 0 0 0 1.5em;
112 | 	}
113 | 
114 | 	table.lightweight-table td, table.lightweight-table th {
115 | 	  border: none;
116 | 	  padding: 0 0.5em;
117 | 	  vertical-align: baseline;
118 | 	}
119 | 
120 | 	div.display {
121 | 	  margin: 1em 0 1em 2em;
122 | 	}
123 | 
124 | 	div.gp {
125 | 	  margin-left: 2.4em;
126 | 	  margin-top: 0.9em;
127 | 	}
128 | 
129 | 	div.gp.prod {
130 | 	  margin-left: 0;
131 | 	}
132 | 
133 | 	div.rhs {
134 | 	  margin-left: 2.4em;
135 | 	  margin-right: -10em;
136 | 	}
137 | 
138 | 	div.pile {
139 | 	  margin-left: 2.4em;
140 | 	  max-width: 40em;
141 | 	}
142 | 
143 | 	div.keyword.pile code {
144 | 	  float: left;
145 | 	  width: 25%;
146 | 	}
147 | 
148 | 	div.keyword5.pile code {
149 | 	  float: left;
150 | 	  width: 20%;
151 | 	}
152 | 
153 | 	div.operator.pile code {
154 | 	  float: left;
155 | 	  width: 16%;
156 | 	}
157 | 
158 | 	div.end-pile {
159 | 	  clear: both;
160 | 	}
161 | 
162 | 	sub.g-opt {
163 | 	  color: #d1009e;
164 | 	  /* sort of magenta */
165 | 	}
166 | 
167 | 	sub.g-params {
168 | 	  color: #49a08a;
169 | 	  /* sort of aqua */
170 | 	}
171 | 
172 | 	code {
173 | 	  /* including code.t, meaning "terminal" or "token" */
174 | 	  font-weight: bold;
175 | 	  color: #555555;
176 | 	}
177 | 
178 | 	span.nt {
179 | 	  /* nonterminal */
180 | 	  font-family: Times New Roman, Times, FreeSerif, serif;
181 | 	  font-style: italic;
182 | 	}
183 | 
184 | 	span.geq {
185 | 	  font-weight: bold;
186 | 	}
187 | 
188 | 	span.grhsmod {
189 | 	  /* right-hand side modifier, like "one of", "but not" */
190 | 	  font-weight: bold;
191 | 	  color: #555555;
192 | 	}
193 | 
194 | 	span.grhsannot {
195 | 	  /* right-hand side annotation, like "[empty]" */
196 | 	  font-family: Helvetica, Arial, Liberation Sans, sans-serif;
197 | 	  font-size: smaller;
198 | 	}
199 | 
200 | 	span.chgloss {
201 | 	  /* gloss for a character, like "asterisk" */
202 | 	  font-style: italic;
203 | 	}
204 | 
205 | 	span.gprose {
206 | 	  font-family: Helvetica, Arial, Liberation Sans, sans-serif;
207 | 	  font-size: 90%;
208 | 	}
209 | 
210 | 	div.gsumxref {
211 | 	  /* grammar summary cross-reference, used in Annex A */
212 | 	  width: 8em;
213 | 	  float: right;
214 | 	}
215 | 
216 | 	span.prod {
217 | 	  margin-left: 5pt;
218 | 	  margin-right: 5pt;
219 | 	}
220 | 
221 | 	div.rhs > code.t,
222 | 	div.rhs > span.nt,
223 | 	div.rhs > span.grhsannot,
224 | 	div.rhs > span.grhsmod,
225 | 	div.rhs > span.chgloss,
226 | 	div.rhs > span.gprose,
227 | 	div.rhs > var,
228 | 	.prod > span.geq,
229 | 	.prod > code.t,
230 | 	.prod > span.nt,
231 | 	.prod > span.grhsannot,
232 | 	.prod > span.grhsmod,
233 | 	.prod > span.chgloss,
234 | 	.prod > span.gprose,
235 | 	div.rhs > var {
236 | 	  margin-left: 5pt;
237 | 	}
238 | 
239 | 	div.rhs > code.t:first-child,
240 | 	div.rhs > span.nt:first-child,
241 | 	div.rhs > span.grhsannot:first-child,
242 | 	div.rhs > span.grhsmod:first-child,
243 | 	div.rhs > span.chgloss:first-child,
244 | 	div.rhs > span.gprose:first-child,
245 | 	div.rhs > var:first-child,
246 | 	.prod > span.geq:first-child,
247 | 	.prod > code.t:first-child,
248 | 	.prod > span.nt:first-child,
249 | 	.prod > span.grhsannot:first-child,
250 | 	.prod > span.grhsmod:first-child,
251 | 	.prod > span.chprose:first-child,
252 | 	.prod > span.gprose:first-child,
253 | 	.prod > var:first-child {
254 | 	  margin-left: 0;
255 | 	}
256 | 
257 | 	ul > li {
258 | 	  list-style-type: disc;
259 | 	}
260 | 
261 | 	ul > li > p {
262 | 	  margin-bottom: 0.25em;
263 | 	  margin-top: 0em;
264 | 	}
265 | 
266 | 	ol.proc {
267 | 	  margin-top: 0.5em;
268 | 	}
269 | 
270 | 	ol.proc > li {
271 | 	  list-style-type: decimal;
272 | 	}
273 | 
274 | 	ol.proc > li > ol.block > li {
275 | 	  list-style-type: lower-latin;
276 | 	}
277 | 
278 | 	.tab-content
279 | 	ol.proc > li > ol.block > li > ol.block > li {
280 | 	  list-style-type: lower-roman;
281 | 	}
282 | 
283 | 	ol.proc > li > ol.block > li > ol.block > li >
284 | 	ol.block > li {
285 | 	  list-style-type: decimal;
286 | 	}
287 | 
288 | 	ol.proc > li > ol.block > li > ol.block > li >
289 | 	ol.block > li > ol.block > li {
290 | 	  list-style-type: lower-latin;
291 | 	}
292 | 
293 | 	.tab-content
294 | 	ol.proc > li > ol.block > li > ol.block > li >
295 | 	ol.block > li > ol.block > li > ol.block > li {
296 | 	  list-style-type: lower-roman;
297 | 	}
298 | 
299 | 	p.special1 {
300 | 	  padding-left: +3em;
301 | 	  text-indent: -1em;
302 | 	}
303 | 
304 | 	p.special2 {
305 | 	  padding-left: +11em;
306 | 	  text-indent: -1em;
307 | 	}
308 | 
309 | 	p.special3 {
310 | 	  padding-left: +6em;
311 | 	  text-indent: -1em;
312 | 	}
313 | 
314 | 	p.special4 {
315 | 	  padding-left: +3em;
316 | 	  text-indent: -1em;
317 | 	}
318 | }


--------------------------------------------------------------------------------
/src/css/fonts.css:
--------------------------------------------------------------------------------
1 | /*!
2 |  * Copyright 2013
3 |  * Open Sans is licensed under the Apache License version 2.0.
4 |  */
5 | @font-face{font-family:'Open Sans';src:url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAADQIABMAAAAATeQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABqAAAABwAAAAcYxf7GUdERUYAAAHEAAAAHQAAACAApAAER1BPUwAAAeQAAAJDAAAENjlYHbFHU1VCAAAEKAAAADgAAABQkzyCS09TLzIAAARgAAAAYAAAAGCg5X47Y21hcAAABMAAAADTAAABijB5dyBjdnQgAAAFlAAAAEYAAABGE4kNCWZwZ20AAAXcAAABsQAAAmVTtC+nZ2FzcAAAB5AAAAAIAAAACAAAABBnbHlmAAAHmAAAJgcAADiU9e+LHmhlYWQAAC2gAAAAMwAAADYCMbBEaGhlYQAALdQAAAAfAAAAJBAZBnVobXR4AAAt9AAAAVoAAAHc3oErI2xvY2EAAC9QAAAA3gAAAPC1L8S4bWF4cAAAMDAAAAAgAAAAIAGUAZduYW1lAAAwUAAAAdYAAAQoZx+MQ3Bvc3QAADIoAAABDQAAAboUdTmdcHJlcAAAMzgAAADIAAABdkDIrc53ZWJmAAA0AAAAAAYAAAAGdj9RfwAAAAEAAAAAzD2izwAAAADJNTGLAAAAAM2lJr542mNgZGBg4ANiCQYQYGJgBMIyIGYB8xgACVwAqQAAAHjajZO/b1JRFMe/7z2IQAegUQdDOhhErak22IQfpQ4GAdEYoLSllBp/pHFoQ1LSxTA38W9g8A/oQBzd2R19i0Nnc2dHn5/3AmjEwZBPzjn3nHu+9/DulSUpprbeKFSuPG/rxtv3gxNl3g2OjpU9eX3W1yOFqJHnya/9H986Phr0FfG9gJDswEZkOf2g8p5e8bvQJ32Fb1bMWofHVg3bxfsAH+2EvWKvWOv2mf1FF/al/d2JwLJ96aSIiImyTsTp8Es5HfotK+2dKqe7KkARSrqqsjdWxTtXFWpQ9yZqQBNaxNvYNnYHuwsdsLSmz4oq4420ClnYgBz9856rAvVFKIHF6lhLCpOLQYb8KqxZMfa57HODfQWqiuDviSqOl4R0kJ2QNWSNNolL2C0IzXvN+vjnGrIep0cSbjKj38FX76HeW9iRgzy9Cthi0HuisOI/fygJaWbyFX21VNA1EZxr1vl0sR/rZXQq5KpQgzo06NSEFv42to3dwe7Sq4PdZ28XDqAHh+g4KLqouSgZXSMaEY2m2mO0DdoGbYO2QddF10XXRddF16Br0DXouugadF10DboGXaPrf/1X5wsTlVGsQBVqUGft9/0YTe/HaHo/xsH9OKQmtHA+m69g+ApGV+be4txBHWeJge8N8YbYPyfzp/EnibLeIt/65+yzqvC8anar/Fkt3lmY1SXFlVBSad1SRrd1h9x9PVBWD7XB98zzWora5K1s8drLeqKKanqqZ3qhhpp03daO9rSvrg7U08tfsOl3TwB42mNgZGBg4GLwYfBjYHFx8wlhkEquLMphUEkvSs1m0MtJLMljsGBgAaph+P8fSOBnAQEAaFQPkgADA/8BkAAFAAQFmgUzAAABHwWaBTMAAAPRAGYB8QgCAgsGBgMFBAICBOAAAu9AACBbAAAAKAAAAAAxQVNDAEAADeAABmb+ZgAACGICUyAAAZ8AAAAABEgFtgAAACAAAnjaY2BgYGaAYBkGRgYQaAHyGMF8FoYMIC3GIAAUYQOyeBnqGBYwrFXgUhBR0FeIf8Dw/z9YBy+DAlicQUEALs74/+v/x/8P/d/2IOVB/APXB2IKZVDzsQBGoOkwSUYmIMGErgDoRBZWNnYOTi5uHl4+fgFBIWERUTFxCUkpaRlZOXkFRSVlFVU1dQ1NLW0dXT19A0MjYxNTM3MLSytrG1s7ewdHJ2cXVzd3D08vbx9fP/+AwKDgkNCw8IjIqOiY2Lj4hEQG6oEkMFlUTJouAPzyLSAAAAAESAW2AJgA3QBlAHUAeQCBAIcAiwCRAJMASwCqAMQAdwB7AIMAhwCUAJ0ApgCqALAAtABgAJoArgCoAJYAoQCfAEQFEQAAeNpdUbtOW0EQ3Q0PA4HE2CA52hSzmZDGe6EFCcTVjWJkO4XlCGk3cpGLcQEfQIFEDdqvGaChpEibBiEXSHxCPiESM2uIojQ7O7NzzpkzS8qRqnfpa89T5ySQwt0GzTb9Tki1swD3pOvrjYy0gwdabGb0ynX7/gsGm9GUO2oA5T1vKQ8ZTTuBWrSn/tH8Cob7/B/zOxi0NNP01DoJ6SEE5ptxS4PvGc26yw/6gtXhYjAwpJim4i4/plL+tzTnasuwtZHRvIMzEfnJNEBTa20Emv7UIdXzcRRLkMumsTaYmLL+JBPBhcl0VVO1zPjawV2ys+hggyrNgQfYw1Z5DB4ODyYU0rckyiwNEfZiq8QIEZMcCjnl3Mn+pED5SBLGvElKO+OGtQbGkdfAoDZPs/88m01tbx3C+FkcwXe/GUs6+MiG2hgRYjtiKYAJREJGVfmGGs+9LAbkUvvPQJSA5fGPf50ItO7YRDyXtXUOMVYIen7b3PLLirtWuc6LQndvqmqo0inN+17OvscDnh4Lw0FjwZvP+/5Kgfo8LK40aA4EQ3o3ev+iteqIq7wXPrIn07+xWgAAAAABAAH//wAPeNq1W3l4FFW2r1tLd/Waql7TCQlpmiRAME26CSFiAJFNRgUxoCCDCIiII4iAG6MIDGgEQbawKyJGDFGrOk2AiMiiIiogLlHGJZ/i4PTIIC4zCqQv75xb3Ulk5n3f++cRuqu6qlP3nHPP8ju/e8Px3ECO4ydLoziBM3PFOuHCV8XMYvCfEd0kfXFVTODhlNMFvCzh5ZjZ1KnlqhjB61E1qOYH1eBAPo92JuvoVGnUhR0DxaMcPJJbd+kUqZIaOCvn5MZwMRvPFWlyOM6LnCIWES0jrHFNcSmDU8Wi1KHeIXFyke7MSmjOsO7IStS7nDZnkW7PSOgKKdIdTtWly3x5OafbeNWlOcp7lJT1jEZ8Xo8p1KnAHRVC6x68sl//8p4DXcejd017YvCA/kP6SasvfonyLBJqeA3kQT2v5GIcyiNG44LIyWKRZooQkE4TmnQehucV3QwDmrISugWOZhhNJyIM3KMERyHwWtTY5S4ytLHrVKkheY5XkudwjCjHif+GMbK5juRGLpbFcUUxry8QjUZjZhgvJtvscB7nSJbZUVTPqx1yOvujOicn6j3+zOzO/khcEtktQcntiLckuGWyWB1wi2h5YS2rSQ+4E1rAkE92J2Jm2VpU398sWsC6iu6Dq1646vXhVa8brnoV3QZX7e6EHiRFWq+sxr4Hf57FeYusjX0/+/lbPNGylHo+y+yGcdm7Cd9hkHpLQIYTn1Jv9dnc+Kh6h9cOX1DYu8rePfiO3/Gz78BvZbLfgmdmp5/TIf2cHPxOfW76mx3xutBf4QVUUlHRCh1ycjsWX/ZP65+Fpi8NuoPwigrs5Q2yV8iNrzK4FSUdB9LvSdHIJSNJSeXiSiLT5gEkmx6trKqkJ0Y+MWIrCQ+gJ8gr80nlPBKn1+FrHq2bT0eSV/AF18F1wUMWXqoS7SYXl8cVcldwt3NabljLjuqiNaF1icRyRTRubo4F3Lg4rMlNetCZ0IKKnkOKYqKtcyQS0Tu4EjGHuwucah0UvRtMQKYzoYfx2A2cSVXQi8Vc8GIOvbg0l0TVYlLas1dZadTr85sLCtVcHvza7A2Vgmt7fH7VSUiv0p4FhQtvOjnm6AvvvTh/946eazZs3jTs/V3z7/3wobEzJk0hw06Oeax2U36Y7L667omF210NcWnQwj42ekPktrm3PKH7/94cEqqvG9eVLFT+2FKdu2HomO4cJ3FTL50xXSG9x9k4Lxfg8rkSbgMX86H3huBN72pOxPzovwK86W5TIm7JCAmOIt1iTsRzwuw0x5wgWgSDGl1Nsyu6ihEEpyZFz4LTAjgtUPTucJoHvhiFo2pXXfUWwRfo7C/XuxfAB39OKBM+cLrFB5+y8gq64y13Dnww2VUOPoAb9OzVGvNlHl80oiqhTiY3iVrI5XfQXnBv6pqVKzatX71045PDbtq27aZhc4WiVS2fkJNrVi57dv3qZeurhlVWjhhRWTlM5E+dPvv5t4mzzbW1pJKM3H6xUmq4MIzsPnX6+69OJc5+teOlF1/e8cIL6CMzL52RPpKOch25rlwp9xAXC6C9ctBeIXsiZkVTRS1glF7MKHnORL05D/NbN19Cy1P0HpjR4NSh6B6MWnCPMjj2APfYaRVyQgUKaKs5VC2/XPO4Yqo/qxx9JhpSXQ2c2eHPKrgibY6yYr40rbqZ9CVlUd5MQoVOkrZDGXHy6EN9iWGQmUvioyo6v/nq1sYnNpO1va/xbx9YRYr+tuf+X6o//Wfdxvk/Pkv/MGNc9/lDb55/x52jx8wgcxe8M+W2idPKq7e/uObunX+kD/V9cRL9ZjX9MjZt3MdvzKnaQLYPHDOF/2jQI7f8Yd5N198+AeOIYM4l/VjO7Whk3FS6JZqYzrW6RIpSaRVTKmZT43dH0r18EH7XwWVyzPEIVAW0pDkzoWcYv6S4yqImCBOXP1TAj9y4cuvTK1Yv2bJqA19CLOTYKwdo5JdztNfrteRt45kV8Ex7+plc+pm2Jl1se2bU51IV3hzq5SrtyVdsXbVh48otS1avkBpepSX0PPxcuX0vee/cL+SY8czR/DzRafJAlcvgNCGMlQ2rFT6qTBKiQr5fcpttpNA9Ooc8XnSwiCzLogt/q9O2aD+JAxpmkCV0zoyGjrRxPJlGq8eTwfjMqdwpsat4COJxJKdxYc0c1QnkHikS4wjmHs5qKYoRDk+JgGnIHtasTRof0S0QZWIkZrHiPYsZvma14KmVs4C7GWKVBlWo3N6gGlKnkg1LyCY6eQn/1JOkjlY+SUeTWkOvfvQ3cg93lpMhH4AMOHMWnDkLmzkJarIV3FUSIIXJrDD2gsnwm3hzv+yrHQ0ZWRNL6W9TSWScfzL99T54XiU5yffjZ4IvdMLn6URI4AtdQecIeEYGPj/tDqVBbyX5npxctw5lYViC+wnsUcyBACgLgIjUgWkPWMJkYAnjkNK1rF1GWFdRfuXVA8qj10y7ZtCga64e3M/Q0wOF+3Pmoz7wCYxhwhwDxDJkiZIo8fDBmmQz5gKGbaZcOiNeAbFv4/yAn2IWDPoMW8LIj14bKJVpZEIny4QuzIQQ3wE4uiDn6RYBQ9mbAacmrryceXI0gn4X6sS3P59y9pezv/7w7zP/3l69rWbNmppt1fyX5FFyH32UrqSL6JNkHpwfoF+SQtIHfvJpM9NpLwj5HsNehVxMbNPJFtbEJl3wJXQ7iCKICGvMBqyB+hNSe5Y5iXkvWbh0q+zt+bG4hBRdGCa6Fsz2Ftex504GfJMPdSLA3WDYSvcLiVgGam2xgtZZYc3UpLuciZjLhF7nCoADmlx4akIHzAaD6n4OXIaUaxYVcrrDxZJYtJT05Y3cZC40pgxSmDfonUzma/f2Xvborc9PvuXds8f+samJ7ufPLScLY+uevmlO1VXDZ27/KLaEnvuAHpY3MBnHw9xkg4yF3BQulo8yQtmOZaKMqjURt1ryM6FcWXGSujBxO8EkOfOaVD0b5HZmo7BOCwjbFYUV81mJBmF10qm8XLO69NyOcFTVmMebXV6eLt55qhIMlbZWHHNhX5LKx95c4vWIwU4F42/7dAKZS8c/vXLHO6senVB7T+XY7xd8cmbz01ot/Yr+a/aBPs+ES0hXYl2+dvHdD/ccfO+QGw/VLo3lyr74yhNfh9DvisD+06R9MK8uboLhdzEe0ypns/AOxLM6JyQYmHWHNUuTZo/osjehCZGYzNKAbIIJsTDIaMEJwcojW0BFBUF1amJ4VctAnywFn4h6Q+AXAPJ7loVM5iK+QTt58tlkMx+0yj26kRErhC9buq6lGhmxlpxeHp+QiqlFMAc54H9Z3J+NuqiLEB0OnANFSMTdloAD5sCNLpMN2a1J90F0dDDQab+3L2xhoNRR7NTs+yVdyT7v1NT9nG5Xi4tJvR1wYgoTEt1nBhd2ZjAwFUjPVIzYfG0zA1OiBDuZC90IFsG1RK+HC3VaNPiDO7RDtOq2Z0eX8Z8md+XPuu87YqHN9Nc+W66I1mwmkZwyvm49vdb/t8OnKAXbzwGdwuBXPq4zdxcX86BW2dZUzMuWREzCE5MtEXcGPYiInDKol8/ygB9czBbR/Iqei7AH4q8Ajrl+gDWy4PRgoVdVaLhQj2A2XOXsqs2o7goXjPi94FO8EE0FRqgTV+YxNENnc5I5ZDgZOvPq6yd9/5vdPv3sW6fOf3yK/rt2xKrxyzavXDG2egw/k7xKdriXB+jn9O26s+9/Sy+SUXvujE2tf2lFzbAFRtyAbxXBnJkgP8ekdM5AfyKaOazLGA0EPUQoN/IzCZHxwtFk7W5+vJSzftGF41IO4iLAkmJXZqdOkK2npSyVBQaS8XndERKFDasA+vErWghjT4JzKayH2CUE0mglrSvesoG5ECx1BeSzU+Y9WXlOBhG7Z8FnTrKpeQUpIJTPEHQq7jDsfgcEAQ+1x0BQm5588Pu33vnH4lWxavrlP1q2vbh2Tc2mg2sWh+9/dvkDK+Y9sozMubj0hp33Pvt647Y/xa4d9drchpNHdz+4eOnDt68d0n8jv2TcXwZc9eS4Ox54EGNzGuiNudEP9fKuVE1wgtY2PLGni0MIUpA324L+4UVLFDBLZIKumYreESJAjehmCIZC7BTA2rrNDtmmo1pvcQpepnYI/cPMudSU0hzo6/KCixeWgqIud6gN9qGqxfDJNI279MGa5geTU2cPHDHl3L9s9rKG+w5+u+3pVbeuv2XkqtuWbxKavyXyevr54ZYaz/IsSELRm27++4dPvzDsscF3xabsbu3nxcmsRyhrV4Uh08SdqULsQ20g6aSKsKakz3T/f5RjFTr3ywrz/XPbl2fhtccfZ1WaZ1hkEYwtQ97rxWlKOG5LjcjSXNxh8AeCwwL4GqGJJwVNoONWyst/B0+E1nFbgUrXB2DgKyva4RXxbzh2Cov9BFjsJMQFBxnRayHeqcKBlp8EJ79uImleQ5+iu9eijA+QA2JAOMX4hSwD4VgSDEXgPMthZBJSyIbA6wFha8t4YSs5UFVF1ldVGXmz3VhlpRZSimNltPwoHPhpLRlM5qyhwYkMf2RfOiWUg69lcwXcdI6VAD3TntA6h+O5KcMUhjVnk+5wJepVZwdnUTxozAh0G160jTehd0lRKrHM3M5gIy2o6rwLjl5XzOq2sGYjExrUmOTAOodVAVtVtzGDgBOcJIeEsGNNR5TZ3UbGZL9+7I2PC6979I6r5w+d+MSQhXOHV9++IUXOSFMn7d1x7YxJ00ffd1uw15y1lbNmj5wyI7/kYpXB2HBMx4cuDTbtluLQW/WDKqJFw3qxnMD5tkf13mZooSJaRVgPwFlhWBcx1/ZnsVQECLjIYEJ6eRJaL0UPGVSJfjUcQ71UV3+LXXQHCot7RPuwiHIXQ1brUa5X9IbWSuYUX0aoCFNyQNU6GNisczAiulBp0KzQCLDSnoDSfH7B62HZhe8c6iTyXszWZV5TKI8jcD2boFkeaiJLCfcpGb7rli1TR99vk7usmVL90pn9A+sGBRbdet9q+oPeTBteIQNI+MNv9v9C19AZfOmh4y7n0FELVvF9iEiqm3fS+pPLziyYeuPNE49q73OXAj7azRf7tG4nUVbtoS99TY/T3aMXVZLlZD4l5UTyxJkN4Z+kSHvBI51cdwOxaUKUJfa4SeYIZCET5vdUy6ITGSxhB51LAPOGhKDgDgoFhSYzP2A5309rSDbEz5GTtcGQr6u098JAcoKG+WnkrdGPTJhl8CZHoIbsgxrihCyYx92ZwoiIjFktybMn4pl+Nmwm4q8gm7AMKI6ZES1D0d0wQbZAQuvAKgK0ZJ3gQgdEyRYZ3dEPp5qtXMtUoeCCS+a5NAnBoxrMExnUElWPGMoPGoUxWGqcFJEjZDMUK3HFEnI9/fUsrSMlev2u1wA1Z8af0fZfkBpe2bvgpYC1nH7+5hcrqlY+8djTMxfPvQfi8RHI6cdZLatI1bEMwLsiw7toN7+B8gMJPRPNl+EB+VwMgnBmFYNGdGkmlqVdnaMRvxncgVMVyNiGjzzyEun32em6oTU1P9IEcZxf/+a6Zvo6fY7/8htSubty5Q30DZqgX9PDZWvKyRMwn2Bf6Rawr8ypXO+UdS32lHVVO0jkYhJZwKQWBXsgXQLh3CicijAvbS6UIlgYNY6hI2Q/GUUepg/Q5d8fJz1IBMb8269SA11MX6bVdP4qUkTySS7phDkKZBB+Axls3JC0BEJKAhGwnWS4lYTmsbcKgy0pa1ctNksR9KlGb5pq0oxm1HgdEcLJufz45FZ+kdSwlnatTp5eZ+TG9LgWrn+7Po2NKUtsTBnHtP6XMaFFTg1ou2zA1uFgsGRibXK5MRbMu1TB8uuDKfyaYW+b97jbExARv+J4HdIukKa8AMrGVEa/qm4YMSfFc8VESwA9wqfqZhM6cwbiVV+57nGDf9uhCwS30cz/xWWMSYqUqeDQKuQe8Jtd5Jbv/vHugLd30X/Rj0mQZK5bQfeQH2efe4bG6TL+82/JzTtHV1fSg/Q0/YweC5GD65Ll+QVkiWFHqSObv36pjGA2MoImReOClVlSaJs9G1iSj2g2BREg2JShk/S84QIA9o1gyFqBr61toVJDciU//cIwXkuOaJ03Mov118HL+mt8vABPw5fU+sQjtak2myOXJtB5ZCrja67gYiaU0RbWeRTOGdakJl12GrSNztvYeoBmMoqUmUE+eBjWosItQ66fdGft/vj4Xp94HpwJT79l34nstGxigtmix2W2EKO/NwBTmeFfXbCUlxuiIuUYImYQmV97JBnnJ76T/H49WKCI/yS5qOUt/q0nkod+57tSOgujhVN2MKXtEBOYtwoSeI25zcBeeDrEwoVvN7Ta0wRKcG5cVWHPMjuirTNINA97nhu6PjebMzZhWPPdKHwGwCFNVut5yYEoWjMbCNNQLSbYMsoN5YJQAAxGIAQqhnxe9QjhyHGZfERrnTK1V1FFdkoNF4eJMFnCK1v3XfhJUjZ83DI+LaPUj8k4MmVXR0pC23+T0OH9Twl13glHB5hbTIunCxkpy5NoQSFUYJzhlHD7hRyZN0vPHmz5WlZAris7rLyvn8spDLkwTHzvs3jLAVYPMa73Xc7b2NO8jdDG2wTaeJtAO94Gpz7F23Cm8lR7ZsRnHteet3mETCADSR8ykW6mb2JKjyd//Pm3X3/6Ock3kztIFb2XbqHP0elkCZlCP6VHSYR0I4WkhBprZ+iXU1muc3ED2mc7F1RQ2YhRGSuouzXbWSOY8Z0gKXKZHvRWlxWCQkxlfKiMwVAg1TRiSZzLd6Yn6Om69d+8u+8IFG06+qsfkgf4EyufW7GM2YpuY7bKgCx4ExdzoK3caVsF2lKfArZSDLyFtsJ851OgRRFsDgt6GISkFUGWA4SxIKi6zHRIVRPz/2K+b46Rcb/SU2X/mwm/o0sH0GoyjP9vhjTseBzsaIee5daUJ8qGJ+peMKXNwUxpQ1P6Whk7RySdyxGD+FMJXLeawSElFZTgdAfmG0jWXrUdAlEk0CTY3sYriIMQ+lfy1BH6DD2eiG/f8fqXUsOx4/SrKckZ/ITkFv6n5ctXPMZiBvtHHmpOZ2R22LKLCNZWUVSfYDAJAOgDztbVvzynQSOYoZDsFO2qLzeE9s5TdbeHESIhgxDxqfXE6cljJINLc7fjRaA5LEy1zAybmLyeXOJnfFUob9rYj6fW1lUsX/n+q/TEX3eV7tzx+Lrei6pOv0z/fo62hLcVdJ8/67rbR/a89p3nXnpnxOrrZt953e03lozcW33gM6aPC2w/FmzPVltN7fkETTAWW01NugRpT2JUoSQgVSi1UoVt3RLy1C5xKC2plTquXXvha6kje34jxHIAnq9CNxrLQHuZUkhIs0bTQAjSqiYobBEXZpYBTAsy1hmsJcQC0Vop0Bsba985uOedWvoh/Q1+mnlZeKVl8K4339ot7G654QL9huQZORj+iYcYvwo1zYq6seVkcxQpVuRWOZ1LBx9kK5+/VxkC6jgZcWWnzleSG3Ylf9wuNbTc8PyGrc8JdVjtCEQZZ74OnhngDhmYQ1Oj7LExIjuj0ShjV0ElAvFGjEjPgHjLNlizA5fOdWasGadogf1O+IbG7288+ME/++JVSVOLnZpnv27xnpc0GW48/88TcMOmeZR6l0d1F9W78T0G73lP5j0ZMkFfWA5QlovzFpfbwxZhyS4eqcJA6mOagnOSFH3IBRDl2Lysgrij7pTWeHCD8gSczQSxnh3/rocvu5SY4sTdI+guPR2nD22nJ709ia8H/QbN8tC+DbteFR5qmbfx0LL3hUVQXz66+m3PXza3RNFOMti+mtXsgraI5tPVzx42KjWP9UK0snphIcb/kIXI5DTts5fcTabvpH3I3w8A5L2Xb+Ebk6/z1ySva6H8wuQjqfmdy3A24AJz6/wKUbb8YW5ibD4uf5jMoDyPyhsnON0wFgGXbSQLyeLdNLMOAEE+/3nL/OQRPozrWvDsfiy3F6frd7qnEAwAy1CqbjbYWAC4qoEIo6UkiORB0DtSkJOK8EbLb0LuInHd+kUX70phgxq6l5/BYg5iwoDH1gRSEZKVcRC4TGJm6ywIaSD40p+ESDrgUtC4hhyhzSRI95ouPHUhuAye7YeE+mV6nURI26TdOglOsv95PlTTit+4KN1LWpg8gNkNFUEecxiiw5DH3ARDI0eEQpgUnUC8EsgMSlowc5o38QcZ/g1GQahmEK6sQWp+6rzJGKeELxRD0gHOBNkgBatSlCVb2cCZLyGxSeTLdXQpjfGFwoaWKXwi6UeM2ULfEjZcGgp6+XH9Dndj4KudYmYwiSg80zJx90KOkCrxpOAyBWH+8jkYBTe0OJBwgcaDNOl8RsKYPt7Mpq9HCSmNQlL1horhV9/Lu6/79KtjJrt30M7SQM/9WKPGXzojHBXHQtx35uZyMRda1o9ukWNJxBwE/cOSiPOd/EiZ86ZWTjkrM6FlKXoeYbOn+FgVdqkJyHysLGRhBFis2CarMbPDj82Hy6V5wFl5PysEmhmLGWAsKNBYj/PLGI+TXrtQQ4XtuMReFcj4jOfdjTMerno5euOB2998fW5QHvn8w8/veeWeiRv1mrdfJWFynWIaOH9u5bzukVf2Jz2b7rx2+/qx42vXTzKb7wFdNahxc0wewIUdudtTuMbJlpGsiZiMuuZY0QHYXhfQ0eNj2NutJCBRsV0EgMZxGwvrmqBysCY7S4VGACteDugVN0FploxFJUzrZmTNDVhRUBgyu9ttC9BqZHn2t5/98GPT3fpV9lB4Q+366urNtdUmD108745t9CT9CX4+GT7yKT7/u8PNJ5o+PAS+Ngvma4k4rj0ngOQuCm+1t3ECzss4AWsrJyCkGjzkAXx+czF0dKwMISfQiZtFLP8a/swV0bIFERp7fkvV09NfPEsv8jnETbp38j/ly6Gj3/2sz6pykg/2BFnEMrCnC+w5hYvZ0Z4KiuSzpkRCe1pa7el2MswNeFaTI0isY1/HtmuEmVUDYNV6SXCyrQd2FeQEo/rAqJxJcjpSCxIA0/zRMEHsXRgy4YJlyj+YUWeda2p+wGEWax73WWb97dMf6jasqV2/sXblRj5IMkj3rcOvJ/vOn1n1Iikgjg+b9hwLJQ6fYpgXdXGBXd1cFuqiohq2tGUzrYm4R1aRNvdYjFUjjrV/mieC+56wezBlsjUk3SuzTobZ2qTqDuYaNhWmwYmNBbaJHmPbDZsCVw4JIhwq86Kzc+6goQaRvjh2LumQ9mzXX75l84yf6XcaX7F0wV8289nEQnrTH7+668A7w1YXBEkX8tDmF431UVwAcZo6ch70bjfzbpRelSEJRzQV8psjEeMJQpQUL+wNa262cO/CrSCRmMvN1k0VAENutm7qRjDkQ0+yOtlSO0JQM1uCKStVgingBjownJTzJrn95jlFEwaOH0v8NFEjHP7DVRVkdWhRx0eeHDK/pVw4zHi6QuoRS8DW3aBOXI14Q0Ux+0ngHZFYBjs3J7QuBuVaCr5hh1wT1vtg9hkQ1uxNem9for6ot10GQOdlFaYIDr0VLRepO5MnAW2tnuvBS3oFzIkfvl7ir4Cv50Ovdw1c6W1nS0l6rsnoCyrUXWpWRqcuxX36ofP5jUxVWgxJLJ9j7DR8W8ty6aZc+NRH1S0d4NjPpdv9WOT9uAuG7Z9KA9qgN70EVAi41teHIDWN67CtC0JFpJOJ+W5pTzBh4WOzu5X3HzTq7s/eHj2IzH2vQ/cv9pcUTRs29mDsDfoF/funiS3VS08cmb7u8MxHxy6Y/fO/5zzaOHlllntE6VVju4W2/yl+yHNXZmjmkOf2y71HXVFUvbzhjS2rx4x75O4xg/4kXDXr/jO/Psp8RIP6PxBi1scNb+uNLWhzVyr3GRnEx3Kf5jOgnsPH8onu4xiLpznByqwZdWGal0zlbfkunb1V5sjQodTI1pKds48cqXl4wcvPQnLrOqr38Fvf+CBZyr+1+C97mxhHwXNbQbgpUjPgqgyuPJVLsPxA+oAeHCZeSS3u6CaocRkgDx6xS8pIsyLc7zdnIb7e2rtblyuv7NKtt7NGmlle2qt377KyC4fFoRdxTenSCuphY9q5TG4QdAmpyODBEL6wruCoASR6IDJ0GUZ0w4hYBWQJRlR8qD9vZZR1mvkR0ngeF8Ta7webMeiaG66toZ/c1oeoaZlo3DPqZrHlokL3BswDU9Kl5ygH5khhO0VxjuzGHLH5UY2+16hNyBEo6TngdAs7dbabDgTBBk2kbZPlolvIxLfoQPL5EfrIIyZPy+GyWRWTyAP0iuQS3vQnOoVL+wgZDeMb+6a41LgpxgzsgK82xkyrMXnOn0n9nuk9iOsQrgoxbKlmITcEksfMhLma3hGNCw1YZ/a0EDyJhwIQUrCT0LN8DFS4UqvU+bhiwhuBingCgILmwgzK6R057PFFizVdav3oeHn+/3C/Nj98PFsO75hGyHC5pPGBxj01996/cXXNvQ9sWiEOrR4xtnH05Dc+BJ88snBhbE9yEx5f+yR5oC1mQC9PK59ka6eVrliNTGogBqYPwAXc4oJrx8hMeAwloKbpIm54MaYMqaU22X8fNCBsdPfMt9+BoKnbAgLeOIZJBxHT2ARSGfVqIsiEvpvmkpR02fVZDdcFiRxOtsfPndoDhO6LXEhqDxBSJa17gKAaIZcE3sq33744i9jPniYZ9Kezq779c932559/6aUXnq/h8wloSI/Ri/QX+tGThH/5wy8+/+jEySbEWZDf5zB7BbESMe4GSmg7k+WyvoBonVpxljeSNhw6ghVEDaUMFxMVVkyzVd3sQKFzMwESiFZFFQxIkDZgK8zyeQOknQJm7XG/3L92+l//aUAt+4baZc89t3J7NU89pp7VY0fQJvqzAbUmjKYVovrd4dPvHv288T2GC0CXMtAFMc6dXBu8QTXaMI71cowD3ZkWgK7Gx1ZCzC7WdiDGsSJyBIiDGplVXWIapUCOwym1BzllKQa0DeSUlaZBztcPWTIX1tgcs777+Gzd+uqaddKmlxjIcZDi2urz75NPJg9+kXQjluMnYx/ln373VMqPhULQReH6plm91hmxY/PXmlpwLozcwjMegdPtjKDFlra9z6Z4G1WrcssVdXdee6V/YM9Fr4tD37t7tn1DxmfPJeMpbkmYBeN25u7gYl62c8WS8lTZmu4oND9AQi+DhLhLxeVN7VIBPL1TkDO82Z2wMLvUmEmR2OpwthdE8zM6mTO5cN8uYlspvUX3MkoJC3GadyooLOan/XWf/lKfFxbf/+AVk5cdqvr22F8fHr6zcsHSGc+tn99P6LN449DHBw67unvf3qVDnr5nfc2gDV2KbxrV/9a+5aP+xHJCx0tn+O3SYKijDxtYS7fjJhymE8NbMYntc5JEwFKIuVhh9TYxl8C1IW96i6SWEYl52fYoL4AtdBchK4GtIBZcwZvq8O1uxnMggswAEGY0d+7SfiTqRexluAdiyLwA6bh58ATSlx4cP7L7yMzsu7rRg8LhEYP+Qecn506a5jDPc6hkOL/UyPXbII+Ui0MhVm8xIpW1gLopFa6MzPL+B5nlYwS1AwLWEWYZDmktPQPX7x0qAF1OJ6bU1qjLiK50V7dtO2S2Z2uqMi3RnbPfOUzm8keT5YAHPuH7X9y96sbR+1I8CA+y2ZDnsrGenzDCpY1o4WytPJfb54/2ciENEDszwinb5rwfoxMOikOT9387sJRcz/eAos94BFMIntmByFysA2OVs6FG4YPriUV1dfbD03MMqiuTUV2IMVyQj3INqusgf86Xpro6GFSXsL+xgjuz1aC6soudWtZ+wInnkemqOPfDKbzuBPitZeyXNJeiufc3HhTOeRkBRpR6ngjuosaKx89OZFdMSr3ZhH+vkKHUKxnIisEX2lixGNxs9wm+AQdul5zFCyZzhpLmxkh/m+zOyu7w+6sp0gzM1gHzKuvKkTnJIhjOZYw1gxO0oQB51GQWQv5Xps2QZVuJ60j8zd4eWQy9UUdPvHXE3VPuknt8vziUTqIj/lC+s5Sfk1xSN6dzNf/Fxd38wj4nXr0tOQ/9qxDmUGZz2J4vI/83vqyQrKALXydBkvcaXUhW7KVH6bt8Ce+n48i2ZCJ5nOylA2EMyOOiCcbwckVc2kXQMV1WRqyz3T+6y8GIV42DGqy0coSGtuiRbP9SP8LHzg13y46bTsdo18GvPXHdsLKBO66tAC9a3nRb9Ff+zxfz9mxUF9n3bzK4NOEeGNfSuq5mlhMxEXOAIP8nl6YJ6uVMGj86eZz/Lhnj/zhTGD1/fkvj/PQ+8QNSA9eBm8QZ29YsBiT1GnQaQb3ARwNNuCLqYrv7Yq4Aa918+Jc4kViAdW8B7N5yWZx48c8+AhCfRGVhqVkAKNqZHUr7klIVUqYXErnH7AUc4vH5vcV4saBiwezPGk43N8+Zue+DR8lPT/HjJpDIxrolpgP05KeF9sJP6adTxvFL+doNJDx1DEfIWarwcxl2zOLaw0aoJ/gyYCN27+TsU1SRxV9bjDw0FHTGPcM5qLMTdXaAsjmMq0upTvDvYIQmzRrRs0BnNRLLElDLLNA5JmSx1cscUB/QekfU2cecKgv3FKm6bDbW86wq69cMlctKC+BQWBpJ6YylzGMyD50xe/rM5lO7P7p/wcOPHt23mx83hXS970EPqEsKD5iWvLKeHrv9Vv6pMVPpifU7eGPvFD9C7CpUQn55g8MNLZwSjbJpkyP1XkuGXKR5okg/6qI9EsGFPkaDQD45s+fgeZZPPMWaXIwASHSdR1JBcZ1v/D5x6CqWFUSlXhIhK9Sb8R15c9WjMN4c3mNwqx1vbi6PwWU8U8u5esmsug3+XJTMsqL+nj83lhMBUkMHpaaLCrYtflYrGSkE5RJ38U2d/PTAmWMGTAz3eqzXlGVDHx36h7E9SufxI9be06GgQ3b/8urpwby8zGt+t9ee+91Oeu7/755Y2e6eyP3untz+ntzuHtaXIeIQvFeiBlU8v7jnfwCPHS49AHjaY2BkYGBglJz1T/vQ0Xh+m68M8hwMIHB2qdo+GP0/4Z8ARwibIpDLwcAEEgUAgncM0gB42mNgZGDgSPq7Fkiu+J/wfwVHCANQBAWUAwCbOgagAHjaNZC/SwJhHMafe9/vnQc1RAgOEnE4ODiESINIuAg1i9gmERKHECFHRIRTCDWKIE4OEtF4U0NESzXcFCLSnyBBRDQ0BfbcqcOH5/3+et/3+apPlGwAEgdUSAp9vY22mUFOuri0enDNdzSNV7RVDWWyIw1UWXONXxRVFxXloK++EWfuiDySOqmRDGmT00XskkbU76C4iM9C1SdIxrI4N9cAcwuBuYqWOUEgHnEYjxlPEagCSc0O5IP5NIJYHoFlkwJaMlroD2t1NOQY65x7kGcg5iIpA9hyQa8d+hjiln9OUHNSRVb3Zn8yMK75Xk2m8PUbPKonLXjqHhtyiDTf9JWFobJmHclFZz/WhB/mZRL1++GMLnF+RJ9jbLJ2Iwqw8khIlnfYUPoJZW1zj67xRd0L/Ue75y41/VsOsFS1AhhXxJyDF2qeuj/vXyJ3qNgkrIX9sgv8A9eiZ0kAAHjaY2Bg0IHCEoZljF1MTExzmPWYfZjLmBcwn2LhYTFhCWJpYJnF8opVjDWD9RqbFtsUdhZ2DfYlHCIcQRwTOJZwHOO4xenD+Y5LjauP6xq3BHcIdxf3Dx4DHj+eOp5NPDd4tXjLeE/x8fDl8R3h1+GP4Z/Ff0QgQqBLYIfAM0ERQT3BJMEGwRmCB4TMhGYI3RN2EV4m/EtkhyiLqJ1ol+gp0WdiQWJzxF6JB4hvE/8kESNxQJJP0kLyg5SSVJxUl9QLaRbpFOlXQPgDO5RhkxGRUZIxkLEDQy8AJJxEIgAAAAEAAAB3AEIABQAAAAAAAgABAAIAFgAAAQABUQAAAAB42p1TzS4DURg90xYVlFhIFxYTqy50TJWkEZEUjUgaEho2NtNpVelfptNQa0/gGWy8gngANlYewQN4BOd+c1uqtZHJd3vuN+d893zfnQKYxRPCMCKTADxGgA3McxfgEGK40ziMTdxrHMES3jQeQxyfGo9jzohqPIEHI65xFAnjWeMpZIwPjadxFlrUeIb4RuMYCqF3jV+wEE5o/Ao7vIVdVFFh+IxblFGCyXC4d4hcNNFClz0o1gWzJh4Zq7CRYiQ1SmGZ2T2ym+TVWMfEDrFHtVodqd9EAxYOmSsTmThmvoE2jrivoEOdQ26WGVcYJa4eeUnGsMrENjVVqpRn5cYeyRqsfiI129qN0lmi7Sl7ulGVqrKqufjSk/JXl6pXzDVxPjQDR7owhdXlb1GynjhS1XxxE0y9Kqe5klHTD/aXdO4Jt8TV7c+xTd/Dkxo9c3VvPrMbWOFzLY/F94NqV2stQXUy/6vz2WtLuirLpCvkBlO3pGad08lLN2XpJOi/86MPnzw1qSzrOOQFu0GN+uJ+3+YqT7D/9P1dyxLPFb6tDdRsM5PHPueYwwFvPidfuKp5yrdF3rA6x9ffjY0CXfd8Kt9p5kxGmmevybqOTP//kv4CJwynrwAAeNptztdKQ2EQhdFv0ntP7L33c066PZrE3ns3oCkgIkoQX0sfUEPyX7pvFrMHhsFEM79lyvyXTxCTmDFjwYoNOw6cuHDjwYsPPwGChAgTIUqMNtrpoJMuuumhlz76GWCQIYYZYZQxxplgkimmmWGWOTR0DOIkSJIiTYYs8yywyBLLrLBKjjXWyVOgyAabbLHNDrvssc8BhxxxzAmnnHHOBZdccc0Nt9xxzwOPlMQiVrGJXRziFJe4xSNe8YlfAhKUkIT55kciEpWYrfLy9VbV7fXXmqZp+ZY5TdmcjcZCqSsNZVyZUCaVKWVamVFmlbmWurqr665yrVJ/f34qfVRblVFsmWxaaLzwBzKjRioAAAB42kXOyw7BUBgE4B7Vi1tVW7TiUmkk4iR4CLqxEas28RzWNpasxM47/LXydkw4frv5ZjGZp3idSJy1DdnbrBDikhepKbMxufmGgh3CMR+QKfeZRnq8Jl2uqByvH7pfkh8YQPkHEzBSBQswVwo2YC0VKoA9V6gClaFCDagOFOpAra/QAOrJF4IcdaWJ1pmVZKGnB9AFmyNmC3RvTA9sLZg+6M2ZAej/p9pgMGV2wPaE2QU7d2YIdhNmBIZXZg+MvB9zCuQb32JoOQABUX92PgAA) format("woff");font-weight:normal;font-style:normal}@font-face{font-family:'Open Sans';src:url(data:application/font-woff;charset=utf-8;base64,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) format("woff");font-weight:bold;font-style:normal}@font-face{font-family:'Open Sans';src:url(data:application/font-woff;charset=utf-8;base64,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) format("woff");font-weight:normal;font-style:italic}@font-face{font-family:'Open Sans';src:url(data:application/font-woff;charset=utf-8;base64,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) format("woff");font-weight:bold;font-style:italic}


--------------------------------------------------------------------------------
/src/css/layout.css:
--------------------------------------------------------------------------------
  1 | *, *:after, *:before {
  2 |     box-sizing: border-box;
  3 |     outline: 0px;
  4 |     margin: 0px;
  5 | }
  6 | input, form, fieldset, div, p, section, body, html {
  7 |     padding: 0px;
  8 | }
  9 | body {
 10 |     background-color: #303030;
 11 |     color: #c9c9c9;
 12 |     font: normal 1em/1.7 "Open Sans", Helvetica, Arial, sans-serif;
 13 |     height: 100vh;
 14 |     width: 100vw;
 15 |     word-wrap: break-word;
 16 |     overflow-wrap: break-word;
 17 |     display: flex;
 18 |     flex-direction: column;
 19 | }
 20 | 
 21 | /* layout */
 22 | #top-bar {
 23 |     background: #212121;
 24 |     width: 100%;
 25 |     display: flex;
 26 |     border: 1px solid #333;
 27 |     position: absolute;
 28 |     z-index: 5;
 29 | 
 30 |     .logoish {
 31 |         color: inherit;
 32 |         padding: 0 1rem;
 33 |         font-style: italic;
 34 |         text-shadow: 0px 0px 0.2rem;
 35 |         text-decoration: none;
 36 |     }
 37 | 
 38 |     #search-form {
 39 |         flex-grow: 1;
 40 |         height: 2rem;
 41 |         line-height: 100%;
 42 |         background-color: inherit;
 43 | 
 44 |         input {
 45 |             width: 100%;
 46 |             height: 2rem;
 47 |             border-radius: 0;
 48 |             border: 1px solid #333;
 49 |             border-width: 0px 1px 0px 0px;
 50 |             font: inherit;
 51 |             font-size:  0.875rem;
 52 |             background-color: rgba(0, 0, 0, 0.5);
 53 |             color: #fff;
 54 |             padding: 0em 1rem;
 55 |             position: relative;
 56 |         }
 57 |         #search-results {
 58 |             background-color: inherit;
 59 |             border: 1px solid #333;
 60 |             padding: 0;
 61 |             list-style: none;
 62 |             max-height: 80vh;
 63 |             overflow-y: auto;
 64 | 
 65 |             .result {
 66 |                 display: block;
 67 |                 padding: 0.5rem 1rem;
 68 |                 font-size: 0.875rem;
 69 |                 color: inherit;
 70 |                 text-decoration: none;
 71 | 
 72 |                 .result-heading {
 73 |                     font-weight: normal;
 74 |                 }
 75 |                 .result-path, .result-index {
 76 |                     font-size: small;
 77 |                     padding-right: 0.5rem;
 78 |                 }
 79 |             }
 80 |             .result.active {
 81 |                 background-color: #4C4C4C;
 82 |             }
 83 |         }
 84 |     }
 85 |     .option-box {
 86 |         white-space: nowrap;
 87 |         margin: 0 1em;
 88 | 
 89 |         button {
 90 |             background: transparent;
 91 |             color: inherit;
 92 |             border-width: 0px;
 93 |             font: inherit;
 94 |             font-size: 0.8rem;
 95 |             padding: 0 0.2rem;
 96 |             cursor: pointer;
 97 |         }
 98 |     }
 99 | }
100 | 
101 | .content-wrapper {
102 |     display: flex;
103 |     flex-grow: 1;
104 |     position: relative;
105 | 
106 |     #sidebar {
107 |         position: relative;
108 |         min-width: 20vw;
109 |         max-width: 20vw;
110 |         border-right: 1px solid rgba(255, 255, 255, 0.2);
111 |         position: relative;
112 |         overflow-y: auto;
113 | 
114 |         #open-tab-descriptors {
115 |             list-style: none;
116 |             color: inherit;
117 |             padding: 0;
118 |             font-size: 0.875rem;
119 |             white-space: nowrap;
120 | 
121 |             li {
122 |                 height: 2.5rem;
123 |                 border: 1px inset #6b6b6b;
124 |                 display: flex;
125 |                 align-items: center;
126 |                 font-weight: bold;
127 |                 padding: 0;
128 |                 border-width: 1px 0px;
129 | 
130 |                 div.tab-descriptor.link-tab-descriptor {
131 |                     display: flex;
132 |                     text-overflow: ellipsis;
133 |                     overflow: hidden;
134 |                     align-items: center;
135 |                     width: 100%;
136 |                     padding: 0 1rem;
137 |                     height: 100%;
138 | 
139 |                     a.link-tab-activate {
140 |                         flex-grow: 1;
141 |                         color: inherit;
142 |                         text-decoration: inherit;
143 |                         text-overflow: ellipsis;
144 |                         overflow: hidden;
145 |                     }
146 | 
147 |                     span.tab-close {
148 |                         display: inline-block;
149 |                         margin-left: auto;
150 |                     }
151 | 
152 |                     span.tab-close:before {
153 |                         content: '✕';
154 |                     }
155 |                 }
156 | 
157 |                 div.tab-descriptor.link-tab-descriptor.active {
158 |                     background-color: #232323;
159 |                 }
160 |             }
161 | 
162 |             li:first-of-type {
163 |                 border-top: 1px inset #111;
164 |             }
165 |         }
166 | 
167 |     }
168 | 
169 |     #content {
170 |         flex-grow: 1;
171 |         overflow-x: hidden;
172 |         overflow-y: auto;
173 |         position: relative;
174 |     }
175 | 
176 |     .__info {
177 |         border: 1px solid #111;
178 |         background: #232323;
179 |         color: white;
180 |         padding: 0.5rem 1rem;
181 |         border-radius: 0.3rem;
182 |         font: normal 0.875rem 'Open Sans';
183 | 
184 |         a {
185 |             text-decoration: inherit;
186 |             color: inherit;
187 |             font-weight: inherit;
188 |         }
189 | 
190 |         .__info-path a {
191 |             margin-right: 0.5rem;
192 |         }
193 | 
194 |         .__info-path a:after {
195 |             content: '»';
196 |             margin-left: 0.5rem;
197 |         }
198 | 
199 |         .__info-path a:last-of-type:after {
200 |             content: '';
201 |         }
202 | 
203 |         .__info-label {
204 |             display: inline-block;
205 |             line-height: 200%;
206 |         }
207 |     }
208 | 
209 |     .__info:first-of-type {
210 |         margin-bottom: 2rem;
211 |     }
212 | 
213 |     .__info:last-of-type {
214 |         margin-top: 2rem;
215 |     }
216 | 
217 | 
218 |     .__info-children span {
219 |         margin-right: 0.5rem;
220 |     }
221 | 
222 | }
223 | 
224 | #console {
225 |     position: absolute;
226 |     bottom: 0;
227 |     width: 100%;
228 |     color: white;
229 |     background-color: #111;
230 | }
231 | 
232 | /* meta classes */
233 | .abs {
234 |     position: absolute;
235 | }
236 | .hidden {
237 |     display: none!important;
238 | }
239 | .reveal-on-parent-hover {
240 |     display: none;
241 | }
242 | *:hover .reveal-on-parent-hover {
243 |     display: block;
244 | }
245 | .static-background {
246 |     bottom: 10px;
247 |     background-color: inherit;
248 |     position: fixed;
249 |     display: flex;
250 |     justify-content: center;
251 |     align-items: center;
252 |     padding: 0 1rem;
253 |     opacity: 0.5;
254 |     z-index: -1;
255 | }
256 | 


--------------------------------------------------------------------------------
/src/domhandler.js:
--------------------------------------------------------------------------------
  1 | import * as Spec from './spec';
  2 | import * as Shortcuts from './mod/shortcuts';
  3 | import * as Utils from './mod/utils';
  4 | import {domconsole} from './mod/domconsole';
  5 | 
  6 | /**
  7 |  * helpers for handlers
  8 |  */
  9 | 
 10 | function emphasizeSearch (search, text) {
 11 | 	return text.replace(RegExp(Utils.re.escape(search), 'gi'), '$&');
 12 | }
 13 | 
 14 | /**
 15 |  * event handlers
 16 |  */
 17 | 
 18 | // a live nodelist increases performance in the following event handlers
 19 | let results = document.getElementById('search-results').getElementsByClassName('result');
 20 | let inputBox = $.nam('search');
 21 | let active = inputBox;
 22 | let resultsGenerator;
 23 | let resultsBox = $.id('search-results');
 24 | 
 25 | function createResultList (results, val) {
 26 | 	return results.map(res => $.make('li', {
 27 | 			childNodes: [$.make('a', {
 28 | 				classList: ['result', 'link-newtab'],
 29 | 				href: `#${encodeURIComponent(res.index)}`,
 30 | 				dataset: {
 31 | 					index: res.index
 32 | 				},
 33 | 				on: {
 34 | 					click: function (e) {
 35 | 						e.preventDefault();
 36 | 						active.classList.remove('active');
 37 | 						this.classList.add('active');
 38 | 						active = this;
 39 | 						form$onEnter.call($.id('search-form'), {target: inputBox});
 40 | 					}
 41 | 				},
 42 | 				childNodes: [
 43 | 					$.make('h4', {
 44 | 						classList: ['result-heading'],
 45 | 						innerHTML: emphasizeSearch(val, res.title)
 46 | 					}),
 47 | 					$.make('span', {
 48 | 						classList: ['result-index'],
 49 | 						textContent: res.index
 50 | 					}),
 51 | 					$.make('span', {
 52 | 						classList: ['result-path'],
 53 | 						textContent: Spec.indexToPath(res.index)
 54 | 					})
 55 | 				]
 56 | 			})]
 57 | 		}));
 58 | }
 59 | 
 60 | function input$onInput () {
 61 | 	let val = this.value.trim();
 62 | 	resultsGenerator = Spec.search(val);
 63 | 	active = inputBox;
 64 | 
 65 | 	let resultList = createResultList(resultsGenerator.next().value, val);
 66 | 
 67 | 	$$.tag('li', resultsBox).forEach($.remove);
 68 | 
 69 | 	resultList.forEach(el => $.append(el, resultsBox));
 70 | }
 71 | 
 72 | function form$onKeyDown (ev) {
 73 | 	const DOWN_ARROW = 40;
 74 | 	const UP_ARROW = 38;
 75 | 	const ENTER_KEY = 13;
 76 | 	const ESC_KEY = 27;
 77 | 
 78 | 	switch (ev.keyCode || ev.which) {
 79 | 		case DOWN_ARROW:
 80 | 			ev.preventDefault();
 81 | 			form$onDownArrow.call(this);
 82 | 			break;
 83 | 		case UP_ARROW:
 84 | 			ev.preventDefault();
 85 | 			form$onUpArrow.call(this);
 86 | 			break;
 87 | 		case ENTER_KEY:
 88 | 			ev.preventDefault();
 89 | 			ev.stopImmediatePropagation();
 90 | 			form$onEnter.call(this, ev);
 91 | 			break;
 92 | 		case ESC_KEY:
 93 | 			ev.preventDefault();
 94 | 			ev.stopImmediatePropagation();
 95 | 			form$onEscape.call(this);
 96 | 			break;
 97 | 	}
 98 | }
 99 | 
100 | function form$onDownArrow () {
101 | 	if (active === inputBox) {
102 | 		return results[0] && simulateFocus(results[0]);
103 | 	}
104 | 	if (active.classList.contains('result')) {
105 | 		if (active === resultsBox.lastElementChild.firstElementChild) {
106 | 			let moreResults = resultsGenerator.next();
107 | 			if (moreResults.done) return;
108 | 			if (moreResults.value.length) {
109 | 				let resultList = createResultList(moreResults.value, inputBox.value.trim());
110 | 				resultList.forEach(el => $.append(el, resultsBox));
111 | 				simulateFocus(resultList[0].firstChild);
112 | 				return;
113 | 			}
114 | 			return;
115 | 		}
116 | 		try {
117 | 			return simulateFocus(active.parentNode.nextElementSibling.firstChild);
118 | 		} catch (er) {}
119 | 	}
120 | }
121 | 
122 | function form$onUpArrow () {
123 | 	if (active === inputBox) {
124 | 		let lastResult = results[results.length - 1];
125 | 		if (lastResult) {
126 | 			return simulateFocus(lastResult);
127 | 		}
128 | 		else return;
129 | 	}
130 | 	if (active.classList.contains('result')) {
131 | 		if (active === results[0]) {
132 | 			return;
133 | 		}
134 | 		try {
135 | 			return simulateFocus(active.parentNode.previousElementSibling.firstChild);
136 | 		} catch (err) {}
137 | 	}
138 | }
139 | 
140 | function form$onEnter (ev) {
141 | 	let target = ev.target || ev.srcElement;
142 | 	if (target !== inputBox) return;
143 | 
144 | 	if (!active.classList.contains('result')) return;
145 | 	target = active;
146 | 	openTab(target.dataset.index);
147 | 	form$onEscape.call(this);
148 | }
149 | 
150 | function form$onEscape () {
151 | 	this.parentNode.classList.add('hidden');
152 | }
153 | 
154 | function simulateFocus (el) {
155 | 	active.classList.remove('active');
156 | 	el.classList.add('active');
157 | 	active = el;
158 | 	el.scrollIntoView();
159 | }
160 | 
161 | function window$loaded (ev) {
162 | 	if (window.localStorage.getItem('lastIndexed')) {
163 | 		Spec.initialize().then(_ => app$navigated.call(this, ev));
164 | 	}
165 | 	else {
166 | 		domconsole.log('hi! especser is an app to search the ECMAScript specification ed6.0. please click update to cache spec for the first time.');
167 | 	}
168 | }
169 | 
170 | function app$navigated (ev) {
171 | 	let newIndex = window.location.hash.replace('#', '').trim();
172 | 	let frame = Spec.indexToFrame(newIndex);
173 | 	if (frame) {
174 | 		Promise.resolve(openTab(newIndex)).then(_ => $.id('top-bar').classList.add('hidden'));
175 | 	}
176 | }
177 | 
178 | /**
179 |  * attach the above awesomeness to dom!
180 |  */
181 | 
182 | inputBox.addEventListener('input', Utils.throttle(input$onInput, 200, inputBox, 'discard-repeats'), true);
183 | $.id('search-form').addEventListener('keydown', form$onKeyDown, false);
184 | $.id('btn-update').addEventListener('click', Spec.initialize, false);
185 | $.id('btn-clear').addEventListener('click', Spec.clear, false);
186 | window.addEventListener('hashchange', app$navigated, false);
187 | window.addEventListener('load', window$loaded);
188 | 
189 | /**
190 |  * tab creation, previewing, and handling
191 |  */
192 | 
193 | import {TabGroup, Tab} from './mod/tabbing';
194 | 
195 | let group = new TabGroup();
196 | 
197 | let content = $.id('content');
198 | let suspendedTabs = $.id('suspended-tabs');
199 | let descriptorList = $.id('open-tab-descriptors');
200 | 
201 | let state = {
202 | 	open: Object.create(null),
203 | 	tokenToIndexMap: Object.create(null),
204 | 	get activeTabIndex () {
205 | 		let el = $.cl('tab-content', content);
206 | 		if (!el) return;
207 | 		return el.dataset.secIndex;
208 | 	}
209 | };
210 | 
211 | function openTab (index) {
212 | 	if (index in state.open) {
213 | 		return group.open(state.open[index]);
214 | 	}
215 | 
216 | 	let tabData = Spec.indexToFrame(index);
217 | 
218 | 	let descriptor = createDescriptor(tabData);
219 | 	descriptorList.appendChild(descriptor);
220 | 	descriptor.scrollIntoView();
221 | 
222 | 	let tab = new Tab(tabData.title, tabData.path, index);
223 | 	let tabToken = group.attach(tab);
224 | 
225 | 	state.open[index] = tabToken;
226 | 	state.tokenToIndexMap[tabToken] = index;
227 | }
228 | 
229 | function createDescriptor (res) {
230 | 	return $.make('li', {
231 | 		childNodes: [
232 | 			$.make('div', {
233 | 				classList: ['tab-descriptor', 'link-tab-descriptor', 'active'],
234 | 				childNodes: [
235 | 					$.make('a', {
236 | 						textContent: res.title,
237 | 						href: `#${res.index}`,
238 | 						dataset: {
239 | 							index: res.index
240 | 						},
241 | 						classList: ['link-tab-activate']
242 | 					}),
243 | 					$.make('span', {
244 | 						classList: ['tab-close'],
245 | 						on: {
246 | 							click: function () {
247 | 								group.detach(state.open[res.index]);
248 | 								$.remove(this.parentNode.parentNode);
249 | 							}
250 | 						}
251 | 					})
252 | 				]
253 | 			})
254 | 		]
255 | 	});
256 | }
257 | 
258 | function closeTab (index) {
259 | 	if (!(index in state.open)) {
260 | 		return;
261 | 	}
262 | 	group.detach(state.open[index]);
263 | 	delete state.tokenToIndexMap[token];
264 | 	delete state.open[index];
265 | }
266 | 
267 | function storeAsSuspended (index, data) {
268 | 	if (!data) return;
269 | 	$.remove(data);
270 | 	$.apply(data, {
271 | 		classList: ['tab-content'],
272 | 		dataset: {
273 | 			secIndex: index
274 | 		}
275 | 	});
276 | 	suspendedTabs.appendChild(data);
277 | }
278 | 
279 | function getDescriptor (index) {
280 | 	return $.data('index=', index, descriptorList).parentNode.parentNode;
281 | }
282 | 
283 | function suspendActiveTab () {
284 | 	let index = state.activeTabIndex;
285 | 	if (!index) return;
286 | 	let data = $.data('sec-index=', index, content);
287 | 	storeAsSuspended(index, data);
288 | }
289 | 
290 | function getFromSuspended (index) {
291 | 	return $.data('sec-index=', index, suspendedTabs);
292 | }
293 | 
294 | function onAttach ({id: token}) {
295 | 	let index = group.tabs[token].meta;
296 | 
297 | 	let el = generateView(Spec.indexToFrame(index));
298 | 	el.then(data => storeAsSuspended(index, data)).then(_ => group.open(token));
299 | }
300 | 
301 | function onOpen ({id: token}) {
302 | 	let index = group.tabs[token].meta;
303 | 	suspendActiveTab();
304 | 	content.appendChild(getFromSuspended(index));
305 | 	$.cl('tab-descriptor', getDescriptor(index)).classList.add('active');
306 | }
307 | 
308 | function onClose ({id: token}) {
309 | 	suspendActiveTab();
310 | 	$.cl('active', descriptorList).classList.remove('active');
311 | }
312 | 
313 | function onDetach ({id: token}) {
314 | 	$.remove(getFromSuspended(state.tokenToIndexMap[token]));
315 | 	group.restoreLast();
316 | }
317 | 
318 | group.events.on('open', onOpen);
319 | group.events.on('close', onClose);
320 | group.events.on('attach', onAttach);
321 | group.events.on('detach', onDetach);
322 | 
323 | function generateView (res) {
324 | 	let path = Spec.indexToPath(res.index);
325 | 	let info = $.make('div', {
326 | 		classList: ['__info'],
327 | 		childNodes: [
328 | 			$.make('span', {classList: ['__info-label'], textContent: 'Path till here'}),
329 | 			$.make('h4', {
330 | 				classList: ['__info-path'],
331 | 				childNodes: [...res.path.map(place => $.make('a', {
332 | 					href: `#${place}`,
333 | 					textContent: Spec.indexToFrame(place).title
334 | 				}))]
335 | 			})
336 | 		]
337 | 	});
338 | 	let children = $.make('div', {
339 | 		classList: ['__info'],
340 | 		childNodes: [
341 | 			$.make('span', {classList: ['__info-label'], textContent: 'Topics inside'}),
342 | 			$.make('h4', {
343 | 				classList: ['__info-children'],
344 | 				childNodes: res.children.length ? [...res.children.map(child => $.make('div', {
345 | 					childNodes: [
346 | 						$.make('span', {
347 | 							classList: ['__info-children-index'],
348 | 							textContent: child
349 | 						}),
350 | 						$.make('a', {
351 | 							classList: ['__info-children-anchor'],
352 | 							href: `#${child}`,
353 | 							textContent: Spec.indexToFrame(child).title
354 | 						})
355 | 					]
356 | 				}))] : [$.make('span', {textContent: 'none'})]
357 | 			})
358 | 		]
359 | 	});
360 | 	let content = $.make('div', {
361 | 		classList: ['tab-content'],
362 | 		childNodes: [info]
363 | 	});
364 | 	return Spec.Store.getItem(res.index).then(
365 | 		html => {
366 | 			content.insertAdjacentHTML('beforeend', html);
367 | 			content.appendChild(children);
368 | 			return content;
369 | 		}
370 | 	);
371 | }
372 | 


--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
 1 | import * as Shortcuts from './mod/shortcuts';
 2 | import './mod/sdm';
 3 | import './domhandler';
 4 | import * as Spec from './spec';
 5 | import {domconsole} from './mod/domconsole';
 6 | 
 7 | let topbar = $.id('top-bar'), search = $.nam('search');
 8 | 
 9 | Shortcuts.register({modifier: 'Ctrl', key: 'P'}, function (e) {
10 | 	e.preventDefault();
11 | 	topbar.classList.toggle('hidden');
12 | 	if (topbar.classList.contains('hidden')) return;
13 | 	search.focus();
14 | });
15 | 
16 | Shortcuts.register({key: 'Esc'}, function (e) {
17 | 	e.preventDefault();
18 | 	topbar.classList.add('hidden');
19 | });
20 | 


--------------------------------------------------------------------------------
/src/mod/domconsole.js:
--------------------------------------------------------------------------------
 1 | let c = $.id('console');
 2 | export let domconsole = {
 3 | 	log (...args) {
 4 | 		c.classList.remove('hidden');
 5 | 		c.style.color = '';
 6 | 		c.textContent = args.join(' ');
 7 | 	},
 8 | 	error (...args) {
 9 | 		c.classList.remove('hidden');
10 | 		c.style.color = 'red';
11 | 		c.textContent = args.join(' ');
12 | 	},
13 | 	clear () {
14 | 		c.style.color = '';
15 | 		c.textContent = '';
16 | 	}
17 | }


--------------------------------------------------------------------------------
/src/mod/events.js:
--------------------------------------------------------------------------------
 1 | export class EventEmitter {
 2 | 
 3 | 	constructor () {
 4 | 		this.events = {
 5 | 			any: []
 6 | 		};
 7 | 	}
 8 | 
 9 | 	on (event, listener) {
10 | 		if (!this.events[event]) {
11 | 			this.events[event] = [];
12 | 		}
13 | 		this.events[event].push(listener);
14 | 	}
15 | 
16 | 	once (event, listener) {
17 | 		let that = this;
18 | 		this.on(event, function oneTimeListener (...data) {
19 | 			listener.apply(null, data);
20 | 			that.off(event, oneTimeListener);
21 | 		});
22 | 	}
23 | 
24 | 	off (event, listener) {
25 | 		if (!this.events[event]) {
26 | 			return;
27 | 		}
28 | 		if (!listener) {
29 | 			this.events[event] = [];
30 | 			return;
31 | 		}
32 | 		let s = this.events[event];
33 | 		let i = s.indexOf(listener);
34 | 		if (i === -1) {
35 | 			return;
36 | 		}
37 | 		s.splice(i, 1);
38 | 	}
39 | 
40 | 	emit (event, ...data) {
41 | 		let s = this.events[event];
42 | 		if (!s || !s.length) return;
43 | 		return Promise.all(
44 | 			s.map(
45 | 				fn => Promise.resolve(
46 | 					fn.apply(null, data)
47 | 				)
48 | 			)
49 | 		);
50 | 	}
51 | 
52 | }
53 | 


--------------------------------------------------------------------------------
/src/mod/localforage.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 |     localForage -- Offline Storage, Improved
3 |     Version 1.2.2
4 |     https://mozilla.github.io/localForage
5 |     (c) 2013-2015 Mozilla, Apache License 2.0
6 | */
7 | !function(){var a,b,c,d;!function(){var e={},f={};a=function(a,b,c){e[a]={deps:b,callback:c}},d=c=b=function(a){function c(b){if("."!==b.charAt(0))return b;for(var c=b.split("/"),d=a.split("/").slice(0,-1),e=0,f=c.length;f>e;e++){var g=c[e];if(".."===g)d.pop();else{if("."===g)continue;d.push(g)}}return d.join("/")}if(d._eak_seen=e,f[a])return f[a];if(f[a]={},!e[a])throw new Error("Could not find module "+a);for(var g,h=e[a],i=h.deps,j=h.callback,k=[],l=0,m=i.length;m>l;l++)k.push("exports"===i[l]?g={}:b(c(i[l])));var n=j.apply(this,k);return f[a]=g||n}}(),a("promise/all",["./utils","exports"],function(a,b){"use strict";function c(a){var b=this;if(!d(a))throw new TypeError("You must pass an array to all.");return new b(function(b,c){function d(a){return function(b){f(a,b)}}function f(a,c){h[a]=c,0===--i&&b(h)}var g,h=[],i=a.length;0===i&&b([]);for(var j=0;jb;b+=4)c=e.indexOf(a[b]),d=e.indexOf(a[b+1]),f=e.indexOf(a[b+2]),g=e.indexOf(a[b+3]),l[j++]=c<<2|d>>4,l[j++]=(15&d)<<4|f>>2,l[j++]=(3&f)<<6|63&g;return k}function d(a){var b,c=new Uint8Array(a),d="";for(b=0;b>2],d+=e[(3&c[b])<<4|c[b+1]>>4],d+=e[(15&c[b+1])<<2|c[b+2]>>6],d+=e[63&c[b+2]];return c.length%3===2?d=d.substring(0,d.length-1)+"=":c.length%3===1&&(d=d.substring(0,d.length-2)+"=="),d}var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",f="__lfsc__:",g=f.length,h="arbf",i="blob",j="si08",k="ui08",l="uic8",m="si16",n="si32",o="ur16",p="ui32",q="fl32",r="fl64",s=g+h.length,t={serialize:a,deserialize:b,stringToBuffer:c,bufferToString:d};"undefined"!=typeof module&&module.exports?module.exports=t:"function"==typeof define&&define.amd?define("localforageSerializer",function(){return t}):this.localforageSerializer=t}.call(window),function(){"use strict";function a(a){var b=this,c={db:null};if(a)for(var d in a)c[d]=a[d];return new k(function(a,d){var e=l.open(c.name,c.version);e.onerror=function(){d(e.error)},e.onupgradeneeded=function(){e.result.createObjectStore(c.storeName)},e.onsuccess=function(){c.db=e.result,b._dbInfo=c,a()}})}function b(a,b){var c=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var d=new k(function(b,d){c.ready().then(function(){var e=c._dbInfo,f=e.db.transaction(e.storeName,"readonly").objectStore(e.storeName),g=f.get(a);g.onsuccess=function(){var a=g.result;void 0===a&&(a=null),b(a)},g.onerror=function(){d(g.error)}})["catch"](d)});return j(d,b),d}function c(a,b){var c=this,d=new k(function(b,d){c.ready().then(function(){var e=c._dbInfo,f=e.db.transaction(e.storeName,"readonly").objectStore(e.storeName),g=f.openCursor(),h=1;g.onsuccess=function(){var c=g.result;if(c){var d=a(c.value,c.key,h++);void 0!==d?b(d):c["continue"]()}else b()},g.onerror=function(){d(g.error)}})["catch"](d)});return j(d,b),d}function d(a,b,c){var d=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var e=new k(function(c,e){d.ready().then(function(){var f=d._dbInfo,g=f.db.transaction(f.storeName,"readwrite"),h=g.objectStore(f.storeName);null===b&&(b=void 0);var i=h.put(b,a);g.oncomplete=function(){void 0===b&&(b=null),c(b)},g.onabort=g.onerror=function(){var a=i.error?i.error:i.transaction.error;e(a)}})["catch"](e)});return j(e,c),e}function e(a,b){var c=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var d=new k(function(b,d){c.ready().then(function(){var e=c._dbInfo,f=e.db.transaction(e.storeName,"readwrite"),g=f.objectStore(e.storeName),h=g["delete"](a);f.oncomplete=function(){b()},f.onerror=function(){d(h.error)},f.onabort=function(){var a=h.error?h.error:h.transaction.error;d(a)}})["catch"](d)});return j(d,b),d}function f(a){var b=this,c=new k(function(a,c){b.ready().then(function(){var d=b._dbInfo,e=d.db.transaction(d.storeName,"readwrite"),f=e.objectStore(d.storeName),g=f.clear();e.oncomplete=function(){a()},e.onabort=e.onerror=function(){var a=g.error?g.error:g.transaction.error;c(a)}})["catch"](c)});return j(c,a),c}function g(a){var b=this,c=new k(function(a,c){b.ready().then(function(){var d=b._dbInfo,e=d.db.transaction(d.storeName,"readonly").objectStore(d.storeName),f=e.count();f.onsuccess=function(){a(f.result)},f.onerror=function(){c(f.error)}})["catch"](c)});return j(c,a),c}function h(a,b){var c=this,d=new k(function(b,d){return 0>a?void b(null):void c.ready().then(function(){var e=c._dbInfo,f=e.db.transaction(e.storeName,"readonly").objectStore(e.storeName),g=!1,h=f.openCursor();h.onsuccess=function(){var c=h.result;return c?void(0===a?b(c.key):g?b(c.key):(g=!0,c.advance(a))):void b(null)},h.onerror=function(){d(h.error)}})["catch"](d)});return j(d,b),d}function i(a){var b=this,c=new k(function(a,c){b.ready().then(function(){var d=b._dbInfo,e=d.db.transaction(d.storeName,"readonly").objectStore(d.storeName),f=e.openCursor(),g=[];f.onsuccess=function(){var b=f.result;return b?(g.push(b.key),void b["continue"]()):void a(g)},f.onerror=function(){c(f.error)}})["catch"](c)});return j(c,a),c}function j(a,b){b&&a.then(function(a){b(null,a)},function(a){b(a)})}var k="undefined"!=typeof module&&module.exports?require("promise"):this.Promise,l=l||this.indexedDB||this.webkitIndexedDB||this.mozIndexedDB||this.OIndexedDB||this.msIndexedDB;if(l){var m={_driver:"asyncStorage",_initStorage:a,iterate:c,getItem:b,setItem:d,removeItem:e,clear:f,length:g,key:h,keys:i};"undefined"!=typeof module&&module.exports?module.exports=m:"function"==typeof define&&define.amd?define("asyncStorage",function(){return m}):this.asyncStorage=m}}.call(window),function(){"use strict";function a(a){var b=this,c={};if(a)for(var d in a)c[d]=a[d];c.keyPrefix=c.name+"/",b._dbInfo=c;var e=new k(function(a){q===p.DEFINE?require(["localforageSerializer"],a):a(q===p.EXPORT?require("./../utils/serializer"):l.localforageSerializer)});return e.then(function(a){return m=a,k.resolve()})}function b(a){var b=this,c=b.ready().then(function(){for(var a=b._dbInfo.keyPrefix,c=n.length-1;c>=0;c--){var d=n.key(c);0===d.indexOf(a)&&n.removeItem(d)}});return j(c,a),c}function c(a,b){var c=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var d=c.ready().then(function(){var b=c._dbInfo,d=n.getItem(b.keyPrefix+a);return d&&(d=m.deserialize(d)),d});return j(d,b),d}function d(a,b){var c=this,d=c.ready().then(function(){for(var b=c._dbInfo.keyPrefix,d=b.length,e=n.length,f=0;e>f;f++){var g=n.key(f),h=n.getItem(g);if(h&&(h=m.deserialize(h)),h=a(h,g.substring(d),f+1),void 0!==h)return h}});return j(d,b),d}function e(a,b){var c=this,d=c.ready().then(function(){var b,d=c._dbInfo;try{b=n.key(a)}catch(e){b=null}return b&&(b=b.substring(d.keyPrefix.length)),b});return j(d,b),d}function f(a){var b=this,c=b.ready().then(function(){for(var a=b._dbInfo,c=n.length,d=[],e=0;c>e;e++)0===n.key(e).indexOf(a.keyPrefix)&&d.push(n.key(e).substring(a.keyPrefix.length));return d});return j(c,a),c}function g(a){var b=this,c=b.keys().then(function(a){return a.length});return j(c,a),c}function h(a,b){var c=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var d=c.ready().then(function(){var b=c._dbInfo;n.removeItem(b.keyPrefix+a)});return j(d,b),d}function i(a,b,c){var d=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var e=d.ready().then(function(){void 0===b&&(b=null);var c=b;return new k(function(e,f){m.serialize(b,function(b,g){if(g)f(g);else try{var h=d._dbInfo;n.setItem(h.keyPrefix+a,b),e(c)}catch(i){("QuotaExceededError"===i.name||"NS_ERROR_DOM_QUOTA_REACHED"===i.name)&&f(i),f(i)}})})});return j(e,c),e}function j(a,b){b&&a.then(function(a){b(null,a)},function(a){b(a)})}var k="undefined"!=typeof module&&module.exports?require("promise"):this.Promise,l=this,m=null,n=null;try{if(!(this.localStorage&&"setItem"in this.localStorage))return;n=this.localStorage}catch(o){return}var p={DEFINE:1,EXPORT:2,WINDOW:3},q=p.WINDOW;"undefined"!=typeof module&&module.exports?q=p.EXPORT:"function"==typeof define&&define.amd&&(q=p.DEFINE);var r={_driver:"localStorageWrapper",_initStorage:a,iterate:d,getItem:c,setItem:i,removeItem:h,clear:b,length:g,key:e,keys:f};q===p.EXPORT?module.exports=r:q===p.DEFINE?define("localStorageWrapper",function(){return r}):this.localStorageWrapper=r}.call(window),function(){"use strict";function a(a){var b=this,c={db:null};if(a)for(var d in a)c[d]="string"!=typeof a[d]?a[d].toString():a[d];var e=new k(function(a){p===o.DEFINE?require(["localforageSerializer"],a):a(p===o.EXPORT?require("./../utils/serializer"):l.localforageSerializer)}),f=new k(function(d,e){try{c.db=n(c.name,String(c.version),c.description,c.size)}catch(f){return b.setDriver(b.LOCALSTORAGE).then(function(){return b._initStorage(a)}).then(d)["catch"](e)}c.db.transaction(function(a){a.executeSql("CREATE TABLE IF NOT EXISTS "+c.storeName+" (id INTEGER PRIMARY KEY, key unique, value)",[],function(){b._dbInfo=c,d()},function(a,b){e(b)})})});return e.then(function(a){return m=a,f})}function b(a,b){var c=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var d=new k(function(b,d){c.ready().then(function(){var e=c._dbInfo;e.db.transaction(function(c){c.executeSql("SELECT * FROM "+e.storeName+" WHERE key = ? LIMIT 1",[a],function(a,c){var d=c.rows.length?c.rows.item(0).value:null;d&&(d=m.deserialize(d)),b(d)},function(a,b){d(b)})})})["catch"](d)});return j(d,b),d}function c(a,b){var c=this,d=new k(function(b,d){c.ready().then(function(){var e=c._dbInfo;e.db.transaction(function(c){c.executeSql("SELECT * FROM "+e.storeName,[],function(c,d){for(var e=d.rows,f=e.length,g=0;f>g;g++){var h=e.item(g),i=h.value;if(i&&(i=m.deserialize(i)),i=a(i,h.key,g+1),void 0!==i)return void b(i)}b()},function(a,b){d(b)})})})["catch"](d)});return j(d,b),d}function d(a,b,c){var d=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var e=new k(function(c,e){d.ready().then(function(){void 0===b&&(b=null);var f=b;m.serialize(b,function(b,g){if(g)e(g);else{var h=d._dbInfo;h.db.transaction(function(d){d.executeSql("INSERT OR REPLACE INTO "+h.storeName+" (key, value) VALUES (?, ?)",[a,b],function(){c(f)},function(a,b){e(b)})},function(a){a.code===a.QUOTA_ERR&&e(a)})}})})["catch"](e)});return j(e,c),e}function e(a,b){var c=this;"string"!=typeof a&&(window.console.warn(a+" used as a key, but it is not a string."),a=String(a));var d=new k(function(b,d){c.ready().then(function(){var e=c._dbInfo;e.db.transaction(function(c){c.executeSql("DELETE FROM "+e.storeName+" WHERE key = ?",[a],function(){b()},function(a,b){d(b)})})})["catch"](d)});return j(d,b),d}function f(a){var b=this,c=new k(function(a,c){b.ready().then(function(){var d=b._dbInfo;d.db.transaction(function(b){b.executeSql("DELETE FROM "+d.storeName,[],function(){a()},function(a,b){c(b)})})})["catch"](c)});return j(c,a),c}function g(a){var b=this,c=new k(function(a,c){b.ready().then(function(){var d=b._dbInfo;d.db.transaction(function(b){b.executeSql("SELECT COUNT(key) as c FROM "+d.storeName,[],function(b,c){var d=c.rows.item(0).c;a(d)},function(a,b){c(b)})})})["catch"](c)});return j(c,a),c}function h(a,b){var c=this,d=new k(function(b,d){c.ready().then(function(){var e=c._dbInfo;e.db.transaction(function(c){c.executeSql("SELECT key FROM "+e.storeName+" WHERE id = ? LIMIT 1",[a+1],function(a,c){var d=c.rows.length?c.rows.item(0).key:null;b(d)},function(a,b){d(b)})})})["catch"](d)});return j(d,b),d}function i(a){var b=this,c=new k(function(a,c){b.ready().then(function(){var d=b._dbInfo;d.db.transaction(function(b){b.executeSql("SELECT key FROM "+d.storeName,[],function(b,c){for(var d=[],e=0;e
  6 |      * License WTFPL
  7 |      */
  8 |     
  9 |     "use strict";
 10 |     
 11 |     function slice (stuff) {
 12 |         return stuff && Array.prototype.slice.call(stuff);
 13 |     }
 14 |     
 15 |     function type (stuff) {
 16 |         return ({}).toString.call(stuff).replace('[object ', '').replace(']', '').toLowerCase();
 17 |     }
 18 | 
 19 |     var $ = window.$ = function (sel, parent) {
 20 |         return (parent||document).querySelector(sel);
 21 |     };
 22 |     var $$ = window.$$ = function (sel, parent) {
 23 |         return slice((parent||document).querySelectorAll(sel));
 24 |     };
 25 |     function wrapQuotes (val) {
 26 |         if (val) return '"' + val + '"';
 27 |         return val;
 28 |     }
 29 |     $.id = function (id, parent) {
 30 |         return (parent || document).getElementById(id);
 31 |     };
 32 |     $.cl = function (cl, parent) {
 33 |         return $$.cl(cl, parent)[0];
 34 |     };
 35 |     $.nam = function (nam, parent) {
 36 |         return $$.nam(nam, parent)[0];
 37 |     };
 38 |     $.tag = function (tag, parent) {
 39 |         return $$.tag(tag, parent)[0];
 40 |     };
 41 |     $.attr = function (attr, val, parent) {
 42 |         if (typeof val === 'undefined') val = '';
 43 |         return (parent||document).querySelector('[' + attr + wrapQuotes(val) + ']');
 44 |     };
 45 |     $.data = function (set, val, parent) {
 46 |         return $.attr('data-' + set, val, parent);
 47 |     };
 48 |     
 49 |     $$.cl = function (cl, parent) {
 50 |         return slice((parent||document).getElementsByClassName(cl));
 51 |     };
 52 |     $$.nam = function (nam, parent) {
 53 |         return slice((parent||document).getElementsByName(nam));
 54 |     };
 55 |     $$.tag = function (tag, parent) {
 56 |         return slice((parent||document).getElementsByTagName(tag));
 57 |     };
 58 |     $$.attr = function (attr, val, parent) {
 59 |         if (typeof val === 'undefined') val = '';
 60 |         return slice((parent||document).querySelectorAll('[' + attr + wrapQuotes(val) + ']'));
 61 |     };
 62 |     $$.data = function (set, val, parent) {
 63 |         return $$.attr('data-' + set, val, parent);
 64 |     };
 65 |     
 66 |     function assignProps (obj, stuff) {
 67 |         if (obj && stuff) Object.keys(stuff).forEach(function (key) {
 68 |             obj[key] = stuff[key];
 69 |         });
 70 |     }
 71 |     
 72 |     $.apply = function (el, opts) {
 73 | 
 74 |         if (!opts) return el;
 75 | 
 76 |         assignProps(el.style, opts.style);
 77 |         delete opts.style;
 78 |         assignProps(el.dataset, opts.dataset);
 79 |         delete opts.dataset;
 80 |         if (opts.classList) opts.classList.forEach(function (cl) {
 81 |             el.classList.add(cl);
 82 |         });
 83 |         delete opts.dataset;
 84 |         if (opts.childNodes) opts.childNodes.forEach(function (child) {
 85 |             el.appendChild(child);
 86 |         });
 87 |         delete opts.childNodes;
 88 |         var events = opts.on;
 89 |         if (events) Object.keys(events).forEach(function (ev) {
 90 |             var det = events[ev];
 91 |             if (type(det) !== 'array') det = [det];
 92 |             det.forEach(function(li) {
 93 |                 var maybeCapture = type(li) === 'array';
 94 |                 el.addEventListener(
 95 |                     ev,
 96 |                     maybeCapture ? li[0] : li,
 97 |                     maybeCapture ? li[1] : false
 98 |                 );
 99 |             });
100 |         });
101 |         delete opts.on;
102 |         if (opts.attributes) Object.keys(opts.attributes).forEach(function (attr) {
103 |             el.setAttribute(attr, opts.attributes[attr]);
104 |         });
105 | 
106 |         
107 |         Object.keys(opts).forEach(function (key) {
108 |             try {
109 |                 el[key] = opts[key];
110 |             }
111 |             catch (e) {}
112 |         });
113 |         
114 |         return el;
115 | 
116 |     };
117 |     
118 |     $.make = function make (sign, opts) {
119 |         
120 |         if (sign === '#text') return document.createTextNode(opts);
121 | 
122 |         if (sign === '#frag') return $.apply(
123 |             document.createDocumentFragment(),
124 |             {childNodes: opts && opts.childNodes}
125 |         );
126 |         
127 |         var el;
128 |         
129 |         if (typeof sign === 'string') {
130 |             el = document.createElement(sign);
131 |         }
132 |         else {
133 |             el = sign.cloneNode(opts && opts.deep);
134 |         }
135 | 
136 |         if (!opts) return el;
137 | 
138 |         delete opts.deep;
139 |         
140 |         return $.apply(el, opts);
141 |     };
142 | 
143 |     $.append = function (elem, refElem, position) {
144 |         position = (position || "bottom").toLowerCase();
145 | 
146 |         if (position === "top") {
147 |             if (!refElem.childNodes.length) return refElem.appendChild(elem);
148 |             return refElem.insertBefore(elem, refElem.firstChild);
149 |         }
150 |         else if (position === "bottom") {
151 |             return refElem.appendChild(elem);
152 |         }
153 |         else if (position === "before") {
154 |             return refElem.parentNode.insertBefore(elem, refElem);
155 |         }
156 |         else if (position === "after") {
157 |             if (!refElem.nextElementSibling) return refElem.parentNode.appendChild(elem);
158 |             return refElem.parentNode.insertBefore(elem, refElem.nextElementSibling);
159 |         }
160 |         else if (position === "replace") {
161 |             return refElem.parentNode.replaceChild(elem, refElem);
162 |         }
163 |         else {
164 |             throw new Error('Unknown position specified. Expected "top", "bottom", "before", "after" or "replace".');
165 |         }
166 | 
167 |     };
168 | 
169 |     $.remove = function (node) {
170 |         if (typeof node === 'string') node = $(node);
171 |         if (node && node.parentNode) node.parentNode.removeChild(node);
172 |     };
173 | 
174 | })(window, document);


--------------------------------------------------------------------------------
/src/mod/shortcuts.js:
--------------------------------------------------------------------------------
 1 | let shortcuts = {
 2 | 	keypress: {},
 3 | 	keydown: {}
 4 | };
 5 | 
 6 | let Key_Mappings = {
 7 | 	F: 70,
 8 | 	P: 80,
 9 | 	ESC: 27
10 | };
11 | 
12 | document.addEventListener('keypress', handler, true);
13 | document.addEventListener('keydown', handler, true);
14 | 
15 | function handler (ev) {
16 | 	let mods = [];
17 | 	if (ev.altKey) mods.push('alt');
18 | 	if (ev.ctrlKey) mods.push('ctrl');
19 | 	if (ev.shiftKey) mods.push('shift');
20 | 	mods = mods.sort();
21 | 	let keyCode = ev.keyCode;
22 | 	let id = `${mods.join('+')}:${keyCode}`;
23 | 
24 | 	if (shortcuts[ev.type].hasOwnProperty(id)) {
25 | 		let {callback, thisArg, args} = shortcuts[ev.type][id];
26 | 		callback.call(thisArg, ev, ...args);
27 | 	}
28 | }
29 | 
30 | function findKeyCode (key) {
31 | 	return Key_Mappings[key.toUpperCase()];
32 | }
33 | 
34 | function parseKey ({modifier = [], key = ''}) {
35 | 	if (!Array.isArray(modifier)) modifier = [modifier];
36 | 	let mods = modifier.map(m => m.toLowerCase()).sort();
37 | 	let evType, keyCode;
38 | 	if (!modifier.length && String(key).length === 1) {
39 | 		evType = 'keypress';
40 | 		keyCode = key.toLowerCase().charCodeAt();
41 | 	}
42 | 	else {
43 | 		evType = 'keydown';
44 | 		keyCode = key;
45 | 		if (!Number(key)) {
46 | 			keyCode = findKeyCode(key);
47 | 		}
48 | 	}
49 | 	if (!keyCode) throw new Error(`Unable to parse key definition. Passed modifier: ${modifier}. Passed Key: ${key}.`);
50 | 	let id = `${mods.join('+')}:${keyCode}`;
51 | 	return { mods, id, keyCode, evType, key };
52 | }
53 | 
54 | export function register (definition, callback, thisArg, ...args) {
55 | 	let descriptor = parseKey(definition);
56 | 	let data = {callback, thisArg, args};
57 | 	shortcuts[descriptor.evType][descriptor.id] = data;
58 | }
59 | 
60 | export function remove (definition) {
61 | 	let {evType, id} = parseKey(definition);
62 | 	delete shortcuts[evType][id];
63 | }
64 | 
65 | export function removeAll () {
66 | 	shortcuts = {
67 | 		keypress: {},
68 | 		keydown: {}
69 | 	};
70 | }


--------------------------------------------------------------------------------
/src/mod/tabbing.js:
--------------------------------------------------------------------------------
  1 | /*jslint esnext: true*/
  2 | 
  3 | import {EventEmitter} from './events';
  4 | 
  5 | let Utils = {
  6 | 	randString () {
  7 | 		return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/x/g, function () {
  8 | 			return String.fromCharCode(Math.floor(Math.random()*120)+1);
  9 | 		});
 10 | 	}
 11 | };
 12 | 
 13 | export class TabGroup {
 14 | 
 15 | 	constructor () {
 16 | 		this.events = new EventEmitter();
 17 | 		this.tabs = Object.create(null);
 18 | 		this.store = new WeakMap();
 19 | 		this.activeTabId = null;
 20 | 		this.history = [];
 21 | 	}
 22 | 
 23 | 	attach (tab) {
 24 | 		if (!(tab instanceof Tab)) {
 25 | 			throw new Error('Expected tab to be of instance Tab. Unknown type passed.');
 26 | 		}
 27 | 		if (this.store.has(tab)) {
 28 | 			throw new Error('Tab is already in this TabGroup. Aborting.');
 29 | 		}
 30 | 		let id = Utils.randString();
 31 | 		this.tabs[id] = tab;
 32 | 		this.store.set(tab, id);
 33 | 		this.status = {
 34 | 			type: 'attach',
 35 | 			id
 36 | 		};
 37 | 		return id;
 38 | 	}
 39 | 
 40 | 	detach (thing) {
 41 | 		let {tab, id} = this.find(thing);
 42 | 		if (this.activeTabId === id) {
 43 | 			this.close(thing);
 44 | 		}
 45 | 		delete this.tabs[id];
 46 | 		this.status = {
 47 | 			type: 'detach',
 48 | 			id
 49 | 		};
 50 | 		this.store.delete(tab);
 51 | 	}
 52 | 
 53 | 	open (thing) {
 54 | 		let {tab, id} = this.find(thing);
 55 | 		if (this.activeTabId === id) return;
 56 | 		if (this.activeTabId) {
 57 | 			this.close(this.activeTabId);
 58 | 		}
 59 | 		this.activeTabId = id;
 60 | 		this.status = {
 61 | 			type: 'open',
 62 | 			id
 63 | 		};
 64 | 	}
 65 | 
 66 | 	close (thing) {
 67 | 		let {tab, id} = this.find(thing);
 68 | 		if (this.activeTabId !== id) return;
 69 | 		this.activeTabId = null;
 70 | 		this.status = {
 71 | 			type: 'close',
 72 | 			id
 73 | 		};
 74 | 	}
 75 | 
 76 | 	restoreLast () {
 77 | 		let last;
 78 | 		for (let i = this.history.length - 1; i >= 0; i--) {
 79 | 			let desc = this.history[i];
 80 | 			if (desc.type === 'close' && typeof this.tabs[desc.id] !== 'undefined') {
 81 | 				last = desc.id;
 82 | 				break;
 83 | 			}
 84 | 		}
 85 | 		if (!last) {
 86 | 			return;
 87 | 		}
 88 | 		this.open(last);
 89 | 	}
 90 | 
 91 | 	find (thing) {
 92 | 		let tab, id;
 93 | 		if (typeof thing === 'string') {
 94 | 			if (typeof this.tabs[thing] === 'undefined') {
 95 | 				throw new Error('TabGroup contains no tab with id ' + thing);
 96 | 			}
 97 | 			tab = this.tabs[thing];
 98 | 			id = thing;
 99 | 		} else if (thing instanceof Tab) {
100 | 			if (this.store.has(thing)) {
101 | 				tab = thing;
102 | 				id = this.store.get(thing);
103 | 			} else {
104 | 				throw new Error('This tab is not a part of this TabGroup.');
105 | 			}
106 | 		} else {
107 | 			throw new Error('Unidentified object passed.');
108 | 		}
109 | 		return {tab, id};
110 | 	}
111 | 
112 | 	set status (stat) {
113 | 		let type = stat.type;
114 | 		if (!type) throw new Error('Unable to set status. No valid type found.');
115 | 
116 | 		this.history.push(stat);
117 | 		this.events.emit(type, stat);
118 | 	}
119 | 
120 | 	get status () {
121 | 		return this.history[this.history.length - 1];
122 | 	}
123 | 
124 | }
125 | 
126 | export class Tab {
127 | 
128 | 	constructor (title, description, meta) {
129 | 		this.title = title;
130 | 		this.description = description;
131 | 		this.meta = meta;
132 | 	}
133 | 
134 | 	attachTo (group) {
135 | 		if (!(group instanceof TabGroup)) {
136 | 			throw new Error('Expected group to be instance of TabGroup. Unidentifiable object passed.');
137 | 		}
138 | 		group.attach(this);
139 | 	}
140 | 
141 | }


--------------------------------------------------------------------------------
/src/mod/utils.js:
--------------------------------------------------------------------------------
 1 | export function frag (html) {
 2 | 	let doc = new DOMParser().parseFromString(html, 'text/html');
 3 | 	let frag = doc.createDocumentFragment();
 4 | 	let body = doc.body;
 5 | 	while (body.firstChild) {
 6 | 		frag.appendChild(body.firstChild);
 7 | 	}
 8 | 	return frag;
 9 | }
10 | 
11 | export function throttle (fn, time, thisArg, repeatAction) {
12 |   
13 |   let lastRun = false;
14 |   let nextTime = 0;
15 |   
16 |   return function throttled (...args) {
17 |     let now = Date.now();
18 |     return new Promise(function (resolve) {
19 |       if (!lastRun) {
20 |         lastRun = now;
21 |         return resolve(fn.apply(thisArg, args));
22 |       }
23 |       if ((now - lastRun) <= time) {
24 |         if (repeatAction === 'discard-repeats') return;
25 |         nextTime += time - (now - lastRun);
26 |         return setTimeout(function () {
27 |           lastRun = Date.now();
28 |           return resolve(fn.apply(thisArg, args));
29 |         }, nextTime);
30 |       }
31 |       lastRun = now;
32 |       return resolve(fn.apply(thisArg, args));
33 |     });
34 |   };
35 |   
36 | }
37 | 
38 | export let re = {
39 |   escape: function RegexpEscape (s) {
40 |     return String(s).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
41 |   }
42 | }


--------------------------------------------------------------------------------
/src/spec.js:
--------------------------------------------------------------------------------
  1 | import 'fetch';
  2 | import * as Utils from './mod/utils';
  3 | import {domconsole} from './mod/domconsole';
  4 | import {config} from './config';
  5 | // storage stuff
  6 | 
  7 | export let Store = localforage.createInstance({
  8 | 	name: 'especser',
  9 | 	storeName: config.IDBstoreName
 10 | });
 11 | 
 12 | export let Data = {
 13 | 	indexToId: {}, // 4.6.5: #sec-foo
 14 | 	idToIndex: {}, // #sec-foo: 4.6.5...
 15 | 	indexToFrameIndex: {}, // eg: 2.1.3 maps to 17 where 17 is the index of the corresponding frame inside stack
 16 | 	stack: [] // contains frames containing data
 17 | };
 18 | 
 19 | export function indexToPath (index) {
 20 | 	let pathNums = index.split('.');
 21 | 	return pathNums.map((_, i, arr) => arr.slice(0, i + 1).join('.')).map(
 22 | 		num => Data.stack[Data.indexToFrameIndex[num]].title
 23 | 	).join(' | ');
 24 | }
 25 | 
 26 | export function indexToFrame (index) {
 27 | 	try {
 28 | 		return Data.stack[Data.indexToFrameIndex[index]];
 29 | 	} catch (err) { return null; }
 30 | }
 31 | 
 32 | // functions to scrape spec
 33 | 
 34 | function fetchSpec (url = config.SPEC_URL) {
 35 | 	console.log('sending request to %s', url);
 36 | 	let f = fetch(
 37 | 		url
 38 | 	).then(res => res.text())
 39 | 	.then(html => new DOMParser().parseFromString(html, 'text/html'));
 40 | 	return f;
 41 | }
 42 | 
 43 | // replaces multiple simultaneous whitespace characters with single space
 44 | function normalize (string) {
 45 | 	return string.replace(/(?:\n+|\s+)/g, ' ');
 46 | }
 47 | 
 48 | // *internal* takes list element, secnum (whatever) and extracts a title value
 49 | function extractText (el, secnum) {
 50 | 	let c = $.cl('toc', el);
 51 | 	let title = '';
 52 | 	let nextEl = secnum.nextSibling;
 53 | 	while (nextEl && nextEl.nodeName.toLowerCase() !== 'ol') {
 54 | 		title += nextEl.textContent;
 55 | 		nextEl = nextEl.nextSibling;
 56 | 	}
 57 | 	return normalize(title.trim());
 58 | }
 59 | 
 60 | function parseIndex (doc) {
 61 | 	let elements = $$('span.secnum[id^="sec-"]', doc);
 62 | 
 63 | 	elements.forEach(function (secnum, stackIndex) {
 64 | 
 65 | 		let index = secnum.textContent;
 66 | 		let isAnnex = false;
 67 | 		if (index.startsWith('Annex')) {
 68 | 			index = index.replace('Annex', '').trim();
 69 | 			isAnnex = true;
 70 | 		}
 71 | 
 72 | 		let path = index.split('.');
 73 | 		path = path.reduce(function (path, place) {
 74 | 			let curr = path[path.length - 1];
 75 | 			path.push(curr + '.' + place);
 76 | 			return path;
 77 | 		}, [path.shift()]);
 78 | 
 79 | 		let id = secnum.firstChild.getAttribute('href').replace('#', '');
 80 | 
 81 | 		let title = secnum.parentNode.textContent;
 82 | 
 83 | 		if (isAnnex) {
 84 | 			title = title.replace('Annex ' + index, '').trim();
 85 | 		}
 86 | 		else {
 87 | 			title = title.replace(index, '').trim();
 88 | 		}
 89 | 
 90 | 		let children = [];
 91 | 		let def = {index, id, title, children, path, stackIndex};
 92 | 		Data.stack.push(def);
 93 | 
 94 | 		Data.indexToId[index] = id;
 95 | 		Data.idToIndex[id] = index;
 96 | 		Data.indexToFrameIndex[index] = stackIndex;
 97 | 
 98 | 		let parent = path[path.length - 2];
 99 | 		if (parent) {
100 | 			Data.stack[Data.indexToFrameIndex[parent]].children.push(index);
101 | 		}
102 | 
103 | 	});
104 | 
105 | 	return doc;
106 | 
107 | }
108 | 
109 | function processStack (doc) {
110 | 	console.log('starting stack processing of %s frames', Data.stack.length);
111 | 	return Promise.all(Data.stack.map( // we have to defer this because if #8.5 refers to #9.5, the index will not be found
112 | 		frame => Store.setItem(frame.index, extractMaterial(frame.id, doc))
113 | 	)).then(
114 | 		_ => Store.setItem('appdata', Data)
115 | 	);
116 | }
117 | 
118 | // *internal* conditionally assigns data-index attribute to element and returns modified element
119 | function assignIndex (el) {
120 | 	let id = el.getAttribute('href');
121 | 	if (!id || !id.startsWith('#')) return el;
122 | 	let index = Data.idToIndex[id.replace('#', '')];
123 | 	if (!index) return el;
124 | 	el.setAttribute('href', '#' + index);
125 | 	el.dataset.index = index;
126 | 	el.classList.add('link-newtab');
127 | 	return el;
128 | }
129 | 
130 | function extractMaterial (hash, content) {
131 | 	let c = $.id(hash.replace('#', ''), content);
132 | 	let f = $.cl('front', c);
133 | 	let container = f || c;
134 | 	let clone = container.cloneNode(true);
135 | 	$$.attr('id', undefined, clone).forEach(el => {el.removeAttribute('id');});
136 | 	$$.attr('href^=', '#', clone).forEach(assignIndex);
137 | 	return clone.innerHTML;
138 | }
139 | 
140 | export function update () {
141 | 	console.log('update started');
142 | 	domconsole.log('fetching latest version of spec and caching locally. this might take a while.')
143 | 	return fetchSpec().then(parseIndex).then(processStack).then(
144 | 		_ => window.localStorage.setItem('lastIndexed', Date.now())
145 | 	).then(
146 | 		_ => {
147 | 			console.log('stack processed and saved in indexeddb. marked lastindex in localstorage');
148 | 			domconsole.log('caching and parsing completed! you can search for stuff and browse the spec now! :) (double click here to hide me)');
149 | 			$.id('console').addEventListener('dblclick', function removeMe () {
150 | 				this.classList.add('hidden');
151 | 				this.removeEventListener('dblclick', removeMe);
152 | 			}, false);
153 | 			window.dispatchEvent(new Event('hashchange'));
154 | 		}
155 | 	);
156 | }
157 | 
158 | export function initialize () {
159 | 	console.log('initializing especser. we have ignition!');
160 | 	if (window.localStorage.getItem('lastIndexed')) {
161 | 		return Store.getItem('appdata').then(val => {
162 | 			Data = val;
163 | 			console.log('retrieved appdata from indexeddb from %s', localStorage.getItem('lastIndexed'));
164 | 		});
165 | 	}
166 | 	console.log('this session is brand new. starting update threads!');
167 | 	return update();
168 | }
169 | 
170 | export function clear () {
171 | 	console.log('I have got orders from high command to evacuate all data from the ship.');
172 | 	domconsole.log('clearing store. this might take some time.');
173 | 	Data = {
174 | 		indexToId: {},
175 | 		idToIndex: {},
176 | 		indexToFrameIndex: {},
177 | 		stack: []
178 | 	};
179 | 	Store.clear().then(_ => localStorage.removeItem('lastIndexed')).then(
180 | 		_ => domconsole.log('store was emptied. click update to cache spec again.')
181 | 	);
182 | }
183 | 
184 | // spec usage API to be exposed
185 | 
186 | const MAX_RESULTS = 8;
187 | 
188 | // *internal* query to be found in name
189 | function fuzzySearch (name, query, max = MAX_RESULTS) {
190 | 	let pos = -1;
191 | 	for (let i = 0, len = query.length; i < len; i++) {
192 | 		let char = query[i];
193 | 		if (!char.trim()) continue; // removing whitespace
194 | 		pos = name.indexOf(char, pos+1);
195 | 		if (pos === -1) return false;
196 | 	}
197 | 	return true;
198 | }
199 | 
200 | const RE_SEC = /^sec:\s*(?:(?:\d+\.?)+,?\s*)+\b/i;
201 | 
202 | /*
203 | 
204 | ^ # start of string											|||||
205 | sec: # "sec:"												|||||
206 | \s* # forgive whitespace									|||||
207 | (?: # begin matching set of indices					|||||		|||||
208 | 	(?: # begin matching individaul indices		|||||	|||||		|||||
209 | 		\d+ # one or more digits				|||||	|||||		|||||
210 | 		\.? # followed by a period				|||||	|||||		|||||
211 | 	)+ # and done								|||||	|||||		|||||
212 | 	,? # and maybe commas							|||||		|||||
213 | 	\s* # and maybe whitespace						|||||		|||||
214 | )+ # 1 or more times								|||||		|||||
215 | \b # and word boundary so trailing commas aren't matched	|||||
216 | 
217 | */
218 | 
219 | function* executeSearch (stack, query, max = MAX_RESULTS) {
220 | 
221 | 	query = (query + '').trim().toLowerCase();
222 | 	if (!query) return [];
223 | 
224 | 	let index = query.match(RE_SEC), selectedStack = [];
225 | 
226 | 	if (index && index[0]) {
227 | 		let indices = index[0].replace('sec:', '').trim().split(/,\s*/);
228 | 
229 | 		// initializing selectedStack with parent indices and all there children
230 | 		// our stack is pretty large. so not using closures here
231 | 		for (let i = 0; i < indices.length; i++) {
232 | 			let frame = indexToFrame(indices[i]);
233 | 			if (!frame) continue;
234 | 			indices.push(...frame.children);
235 | 			selectedStack.push(frame);
236 | 		}
237 | 		query = query.replace(RE_SEC, '').replace(/[.,]/g, '').trim();
238 | 		if (!query) return selectedStack; // we return it here itself because the stack will likely not be large
239 | 	} else {
240 | 		selectedStack = stack;
241 | 	}
242 | 
243 | 	for (
244 | 		let i = 0, len = selectedStack.length,
245 | 		results = [], fuzzyResults = [];
246 | 		i < len;
247 | 		i++
248 | 	) {
249 | 		let title = selectedStack[i].title.toLowerCase();
250 | 		if (title.indexOf(query) >= 0) {
251 | 			results.push(selectedStack[i]);
252 | 		}
253 | 		else if (fuzzySearch(title, query)) {
254 | 			fuzzyResults.push(selectedStack[i]);
255 | 		}
256 | 		if (results.length >= max) {
257 | 			yield results;
258 | 			results = [];
259 | 			continue;
260 | 		}
261 | 		else if (i >= len - 1) {
262 | 			results.push(...fuzzyResults.slice(0, (max - results.length) - 1));
263 | 			yield results;
264 | 			results = [];
265 | 			continue;
266 | 		}
267 | 	}
268 | 	return [];
269 | 
270 | }
271 | 
272 | export function search (query) {
273 | 	return executeSearch(Data.stack, query);
274 | };
275 | 


--------------------------------------------------------------------------------