├── .eslintignore ├── test ├── global │ ├── index.js │ └── Chai.js ├── middlewares │ ├── WalkMiddleware.js │ └── PersonMiddleware.js ├── person │ └── Person.js └── specs │ └── Middleware.spec.js ├── .babelrc ├── docs ├── html │ ├── img │ │ ├── glyphicons-halflings.png │ │ └── glyphicons-halflings-white.png │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── scripts │ │ ├── prettify │ │ │ ├── lang-css.js │ │ │ ├── Apache-License-2.0.txt │ │ │ └── prettify.js │ │ ├── fulltext-search.js │ │ ├── fulltext-search-ui.js │ │ ├── toc.js │ │ └── lunr.min.js │ ├── styles │ │ ├── prettify-tomorrow.css │ │ ├── sunlight.default.css │ │ └── sunlight.dark.css │ ├── classes.list.html │ ├── global.html │ ├── quicksearch.html │ ├── index.html │ └── MiddlewareManager.html ├── jsdoc.conf.json └── API.md ├── .travis.yml ├── .editorconfig ├── index.html ├── gulp-tasks ├── lint.js ├── test.js ├── clean.js ├── default.js ├── server.js ├── docs.js └── build.js ├── .gitignore ├── gulpfile.js ├── package.json ├── .eslintrc.js ├── dist ├── middleware.min.js └── middleware.js ├── README.md └── lib └── Middleware.js /.eslintignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/global/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import './Chai'; 3 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "env" 4 | ], 5 | "plugins": [ 6 | "transform-class-properties" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /docs/html/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/js-middleware/HEAD/docs/html/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /docs/html/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/js-middleware/HEAD/docs/html/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /test/global/Chai.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import {assert, expect} from 'chai'; 3 | 4 | global.assert = assert; 5 | global.expect = expect; 6 | -------------------------------------------------------------------------------- /docs/html/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/js-middleware/HEAD/docs/html/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/html/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/js-middleware/HEAD/docs/html/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/html/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/js-middleware/HEAD/docs/html/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/html/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/js-middleware/HEAD/docs/html/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | 5 | install: 6 | - npm install -g gulp 7 | - npm install 8 | 9 | script: 10 | - gulp test 11 | -------------------------------------------------------------------------------- /test/middlewares/WalkMiddleware.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // a middleware function for walk function 3 | const WalkMiddleware = target => next => step => { 4 | step += 1; 5 | return next(step); 6 | } 7 | export default WalkMiddleware; 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /test/person/Person.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default class Person { 4 | 5 | constructor() { 6 | this.step = 0; 7 | this.word = ''; 8 | } 9 | 10 | walk(step) { 11 | this.step = step; 12 | } 13 | 14 | speak(word) { 15 | this.word = word; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JS Middleware 7 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /gulp-tasks/lint.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | var $ = require('gulp-load-plugins')(); 3 | 4 | gulp.task('lint', 'Lint JS files.', function () { 5 | return gulp.src(['gulpfile.js', 'gulp-tasks/**/*.js', 'lib/**/*.js']) 6 | .pipe($.eslint()) 7 | .pipe($.eslint.format()) 8 | .pipe($.eslint.failAfterError()); 9 | }); 10 | 11 | 12 | -------------------------------------------------------------------------------- /gulp-tasks/test.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | var $ = require('gulp-load-plugins')(); 3 | 4 | gulp.task('test', 'Run test cases.', function () { 5 | return gulp.src(['test/**/*.spec.js'], {read: false}) 6 | .pipe($.mocha({ 7 | require: ['test/global/index.js'], 8 | compilers: 'js:babel-core/register' 9 | })) 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /docs/jsdoc.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true 4 | }, 5 | "opts": { 6 | "destination": "./docs/html" 7 | }, 8 | "plugins": [ 9 | "plugins/markdown" 10 | ], 11 | "templates": { 12 | "systemName": "js-middleware", 13 | "linenums": true, 14 | "sort": false, 15 | "dateFormat": "YYYY-MM-DD", 16 | "theme": "cosmo" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /gulp-tasks/clean.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | var del = require('del'); 3 | var runSequence = require('run-sequence'); 4 | 5 | gulp.task('clean:dist', 'Cleans dist files.', function () { 6 | return del(['./dist/**'], {force: true}); 7 | }); 8 | 9 | gulp.task('clean:docs', 'Cleans docs files.', function () { 10 | return del(['./docs/html/**', './docs/*.md'], {force: true}); 11 | }); 12 | 13 | gulp.task('clean', 'Cleans files.', function (cb) { 14 | runSequence('clean:dist', 'clean:docs', cb); 15 | }); 16 | -------------------------------------------------------------------------------- /gulp-tasks/default.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | var $ = require('gulp-load-plugins')(); 3 | var runSequence = require('run-sequence'); 4 | 5 | function watch() { 6 | return gulp.watch(['lib/**/*.js', './README.md'], function (event) { 7 | $.util.log($.util.colors.bold('File ' + event.path + ' was ' + event.type + ', running tasks...')); 8 | runSequence('lint', 'build', 'mini', 'docs'); 9 | }); 10 | } 11 | 12 | gulp.task('watch', 'Watches for changes in files, re-lint, re-build & re-docs.', watch); 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | .DS_Store 7 | Thumbs.db 8 | .sass-cache 9 | .idea 10 | .vscode 11 | lib-cov 12 | *.seed 13 | *.log 14 | *.csv 15 | *.dat 16 | *.out 17 | *.pid 18 | *.gz 19 | 20 | pids 21 | logs 22 | results 23 | 24 | npm-debug.log 25 | node_modules 26 | -------------------------------------------------------------------------------- /gulp-tasks/server.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | var browserSync = require('browser-sync').create(); 3 | 4 | gulp.task('server', 'Starts a HTTP server for debug.', function () { 5 | browserSync.init({ 6 | open: false, 7 | notify: false, 8 | cors: true, 9 | reloadDelay: 2000, 10 | ghostMode: false, 11 | logPrefix: 'Debug Server', 12 | proxy: 'localhost', 13 | serveStatic: ['./'] 14 | }); 15 | 16 | gulp.watch(['./*.html'], browserSync.reload); 17 | gulp.watch(['./statics/**/*'], browserSync.reload); 18 | gulp.watch(['./dist/*.js'], browserSync.reload); 19 | }); 20 | -------------------------------------------------------------------------------- /gulp-tasks/docs.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | var $ = require('gulp-load-plugins')(); 3 | var fs = require('fs-then-native'); 4 | var jsdoc2md = require('jsdoc-to-markdown'); 5 | var runSequence = require('run-sequence'); 6 | 7 | var config = require('../docs/jsdoc.conf.json'); 8 | gulp.task('docs:html', 'Builds HTML documentation.', function (cb) { 9 | gulp.src(['README.md', './lib/**/*.js', '!./lib/index.js'], {read: false}) 10 | .pipe($.jsdoc3(config, cb)); 11 | }); 12 | 13 | gulp.task('docs:md', 'Builds markdown documentation.', function () { 14 | return jsdoc2md.render({files: ['./lib/**/*.js']}) 15 | .then(function (output) { 16 | fs.writeFile('docs/API.md', output) 17 | }); 18 | }); 19 | 20 | gulp.task('docs', 'Builds documentation.', function (cb) { 21 | runSequence('docs:md', 'docs:html', cb); 22 | }); 23 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* eslint-disable no-console */ 3 | try { 4 | var gulp = require('gulp-help')(require('gulp')); 5 | var $ = require('gulp-load-plugins')(); 6 | var runSequence = require('run-sequence'); 7 | var requireDir = require('require-dir'); 8 | requireDir('./gulp-tasks'); 9 | } catch (e) { 10 | console.log(e.toString()); 11 | console.log('>>>> Failed to require dependency modules'); 12 | console.log('>>>> Please try "npm install"'); 13 | process.exit(1); 14 | } 15 | 16 | // Run tasks: clean, lint, build, docs, watch, server 17 | gulp.task('default', function (cb) { 18 | $.util.log( 19 | 'Building the library and documentation, and watching for changes in files...' 20 | ); 21 | runSequence('clean', 'lint', 'build', 'mini', 'docs', 'watch', 'server', function () { 22 | cb(); 23 | $.util.log( 24 | $.util.colors.green('All set! Please run "gulp help" to see all build command usages.'), '\n' 25 | ); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /docs/html/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([ 2 | ["pln", /^[\t\n\f\r ]+/, null, " \t\r\n "] 3 | ], [ 4 | ["str", /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], 5 | ["str", /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], 6 | ["lang-css-str", /^url\(([^"')]*)\)/i], 7 | ["kwd", /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, null], 8 | ["lang-css-kw", /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i], 9 | ["com", /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], 10 | ["com", /^(?:<\!--|--\>)/], 11 | ["lit", /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], 12 | ["lit", /^#[\da-f]{3,6}/i], 13 | ["pln", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], 14 | ["pun", /^[^\s\w"']+/] 15 | ]), ["css"]); 16 | PR.registerLangHandler(PR.createSimpleLexer([], [ 17 | ["kwd", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i] 18 | ]), ["css-kw"]); 19 | PR.registerLangHandler(PR.createSimpleLexer([], [ 20 | ["str", /^[^"')]+/] 21 | ]), ["css-str"]); -------------------------------------------------------------------------------- /docs/html/scripts/fulltext-search.js: -------------------------------------------------------------------------------- 1 | window.Searcher = (function() { 2 | function Searcher() { 3 | this._index = lunr(function () { 4 | this.field('title', {boost: 10}) 5 | this.field('body') 6 | this.ref('id') 7 | }) ; 8 | 9 | this._indexContent = undefined; 10 | } 11 | 12 | Searcher.prototype.init = function() { 13 | var self = this; 14 | 15 | $("script[type='text/x-docstrap-searchdb']").each(function(idx, item) { 16 | self._indexContent = JSON.parse(item.innerHTML); 17 | 18 | for (var entryId in self._indexContent) { 19 | self._index.add(self._indexContent[entryId]); 20 | } 21 | }); 22 | }; 23 | 24 | Searcher.prototype.search = function(searchTerm) { 25 | var results = [], 26 | searchResults = this._index.search(searchTerm); 27 | 28 | for (var idx = 0; idx < searchResults.length; idx++) { 29 | results.push(this._indexContent[searchResults[idx].ref]) 30 | } 31 | 32 | return results; 33 | }; 34 | 35 | return new Searcher(); 36 | })(); -------------------------------------------------------------------------------- /test/middlewares/PersonMiddleware.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export const PersonMiddleware1 = { 4 | walk: target => next => step => { 5 | step += 1; 6 | return next(step); 7 | }, 8 | speak: target => next => word => { 9 | word = 'from middleware: ' + word; 10 | return next(word); 11 | } 12 | }; 13 | 14 | export class PersonMiddleware2 { 15 | constructor() { 16 | // Define function names for middleware target. 17 | this.middlewareMethods = ['walk', 'speak']; 18 | } 19 | 20 | walk(target) { 21 | return next => step => { 22 | step += 1; 23 | return next(step); 24 | } 25 | } 26 | 27 | speak(target) { 28 | return next => word => { 29 | word = 'from middleware: ' + word; 30 | return next(word); 31 | } 32 | } 33 | } 34 | 35 | export class PersonMiddleware3 { 36 | // Prefix/Postfix method name by an underscore will ignore 37 | _getWord(word) { 38 | return 'from middleware: ' + word; 39 | } 40 | 41 | walk(target) { 42 | return next => step => { 43 | step += 1; 44 | return next(step); 45 | } 46 | } 47 | 48 | speak(target) { 49 | return next => word => { 50 | word = this._getWord(); 51 | return next(word); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /gulp-tasks/build.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | var $ = require('gulp-load-plugins')(); 3 | var browserify = require('browserify'); 4 | var babelify = require('babelify'); 5 | var bundleCollapser = require('bundle-collapser/plugin'); 6 | var derequire = require('derequire'); 7 | var source = require('vinyl-source-stream'); 8 | var map = require('vinyl-map'); 9 | var buffer = require('vinyl-buffer'); 10 | var configs = require('../package.json'); 11 | 12 | gulp.task('build', 'Builds the library.', function (cb) { 13 | var production = $.util.env.type === 'production'; 14 | var b = browserify({ 15 | debug: !production, 16 | entries: './lib/Middleware.js', 17 | paths: ['./lib'], 18 | standalone: configs.name 19 | }); 20 | 21 | // transform to babel 22 | b.transform(babelify); 23 | 24 | // convert bundle paths to IDS to save bytes in browserify bundles 25 | b.plugin(bundleCollapser); 26 | 27 | b.bundle() 28 | .on('error', function (err) { 29 | $.util.log($.util.colors.bold('Build Failed!')); 30 | cb(err); 31 | }) 32 | .pipe(source('middleware.js')) 33 | .pipe(map(function (code) { 34 | return derequire(code); 35 | })) 36 | .pipe(buffer()) 37 | .pipe(gulp.dest('dist')) // for npm distribution 38 | .on('end', function () { 39 | cb(); 40 | }); 41 | }); 42 | 43 | gulp.task('mini', 'Minify the library.', function () { 44 | return gulp.src('./dist/middleware.js') 45 | .pipe($.uglify()) 46 | .pipe($.rename({ 47 | suffix: '.min' 48 | })) 49 | .pipe(gulp.dest('./dist')) 50 | .pipe($.size({title: 'min'})); 51 | }); 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-middleware", 3 | "description": "Powerful Javascript Middleware Pattern Implementation.", 4 | "version": "0.3.2", 5 | "license": "MIT", 6 | "main": "dist/middleware.js", 7 | "repository": "unbug/js-middleware", 8 | "author": { 9 | "name": "unbug", 10 | "email": "tidelgl@gmail.com", 11 | "url": "https://github.com/unbug" 12 | }, 13 | "keywords": [ 14 | "middleware", 15 | "javascript middleware", 16 | "redux middleware", 17 | "express middleware", 18 | "middleware pattern" 19 | ], 20 | "files": [ 21 | "README.md", 22 | "dist", 23 | "lib" 24 | ], 25 | "devDependencies": { 26 | "babel-core": "^6.24.1", 27 | "babel-eslint": "^6.1.2", 28 | "babel-plugin-add-module-exports": "^0.2.1", 29 | "babel-plugin-transform-class-properties": "^6.23.0", 30 | "babel-preset-env": "^1.4.0", 31 | "babelify": "^7.3.0", 32 | "browser-sync": "^2.18.8", 33 | "browserify": "^14.3.0", 34 | "bundle-collapser": "^1.2.1", 35 | "chai": "^3.5.0", 36 | "del": "^2.2.2", 37 | "derequire": "^2.0.6", 38 | "eslint": "^6.6.0", 39 | "fs-then-native": "^1.0.2", 40 | "gulp": "^3.9.1", 41 | "gulp-eslint": "^3.0.1", 42 | "gulp-help": "^1.6.1", 43 | "gulp-jsdoc3": "^1.0.1", 44 | "gulp-load-plugins": "^1.5.0", 45 | "gulp-mocha": "^4.3.0", 46 | "gulp-rename": "^1.2.2", 47 | "gulp-size": "^2.1.0", 48 | "gulp-uglify": "^2.1.2", 49 | "gulp-util": "^3.0.8", 50 | "gulp-watch": "^4.3.11", 51 | "jsdoc-to-markdown": "^2.0.1", 52 | "require-dir": "^0.3.1", 53 | "run-sequence": "^1.2.2", 54 | "vinyl-buffer": "^1.0.0", 55 | "vinyl-map": "^1.0.2", 56 | "vinyl-source-stream": "^1.1.0" 57 | }, 58 | "scripts": {} 59 | } 60 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'extends': 'eslint:recommended', 3 | 'rules': { 4 | 'no-unused-vars': [2, {'vars': 'all', 'args': 'none'}], 5 | 'no-empty': 0, 6 | 'consistent-this': [0, 'that'], 7 | 'comma-spacing': [2, {'before': false, 'after': true}], 8 | 'key-spacing': [2, {'beforeColon': false, 'afterColon': true, 'mode': 'minimum'}], 9 | 'space-before-function-paren': [2, {'anonymous': 'always', 'named': 'never'}], 10 | 'space-unary-ops': [2, {'words': false, 'nonwords': false}], 11 | 'space-in-parens': [2, 'never'], 12 | 'space-before-blocks': 2, 13 | 'keyword-spacing': 2, 14 | 15 | 'array-bracket-spacing': [2, 'never'], 16 | 'block-spacing': [2, 'always'], 17 | 'brace-style': [2, '1tbs', {'allowSingleLine': true}], 18 | 'camelcase': [2, {'properties': 'always'}], 19 | 'comma-style': [2, 'last'], 20 | 'computed-property-spacing': [2, 'never'], 21 | 'eol-last': 2, 22 | 'indent': [2, 2, {"SwitchCase": 1}], 23 | 'linebreak-style': [2, 'unix'], 24 | 'max-depth': [2, 5], 25 | 'max-len': [2, 120, 4, {'ignoreUrls': true}], 26 | 'max-nested-callbacks': [2, 4], 27 | 'max-params': [2, 8], 28 | 'max-statements': [2, 80], 29 | 'new-cap': [2, { 30 | 'newIsCap': true, 31 | 'capIsNew': false, 32 | 'newIsCapExceptions': ['gg', 'ctor'], 33 | }], 34 | 'new-parens': 2, 35 | 'no-array-constructor': 2, 36 | 'no-mixed-spaces-and-tabs': 2, 37 | 'no-new-object': 2, 38 | 'no-trailing-spaces': [1], 39 | 'one-var': [2, 'never'], 40 | 'operator-linebreak': [2, 'after'], 41 | 'quotes': [2, 'single', 'avoid-escape'], 42 | 'semi-spacing': [2, {'before': false, 'after': true}], 43 | 'space-infix-ops': 2, 44 | 'spaced-comment': 2 45 | }, 46 | 'env': { 47 | 'es6': true, 48 | 'node': true, 49 | 'browser': true, 50 | 'jasmine': true, 51 | 'jquery': true 52 | }, 53 | 'globals': { 54 | 'Promise': false 55 | }, 56 | "parser": "babel-eslint", 57 | 'parserOptions': { 58 | 'sourceType': 'module' 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /test/specs/Middleware.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import {MiddlewareManager} from '../../lib/Middleware'; 3 | import Person from '../person/Person'; 4 | import WalkMiddleware from '../middlewares/WalkMiddleware'; 5 | import {PersonMiddleware1, PersonMiddleware2, PersonMiddleware3} from '../middlewares/PersonMiddleware'; 6 | 7 | describe('Middleware: ', () => { 8 | let person; 9 | let middlewareManager; 10 | 11 | beforeEach(() => { 12 | person = new Person(); 13 | middlewareManager = new MiddlewareManager(person); 14 | }); 15 | 16 | afterEach(() => { 17 | person = null; 18 | middlewareManager = null; 19 | }); 20 | 21 | describe('middleware function: ', () => { 22 | it('should apply the middlweare function', () => { 23 | middlewareManager.use('walk', WalkMiddleware); 24 | const newStep = 3; 25 | person.walk(newStep); 26 | return assert.equal(person.step, newStep + 1); 27 | }); 28 | }); 29 | 30 | describe('middleware object: ', () => { 31 | it('should apply the middlweare object', () => { 32 | middlewareManager.use(PersonMiddleware1); 33 | const step = person.step; 34 | const newStep = 3; 35 | person.walk(newStep); 36 | person.speak('hello'); 37 | assert.equal(person.step, newStep + 1); 38 | assert.isTrue(/from middleware/g.test(person.word)); 39 | }); 40 | }); 41 | 42 | describe('middlewareMethods: ', () => { 43 | it('should apply the middlweare object', () => { 44 | middlewareManager.use(new PersonMiddleware2()); 45 | const newStep = 3; 46 | person.walk(newStep); 47 | person.speak('hello'); 48 | assert.equal(person.step, newStep + 1); 49 | assert.isTrue(/from middleware/g.test(person.word)); 50 | }); 51 | }); 52 | 53 | describe('middleware object with private method: ', () => { 54 | it('should apply the middlweare object', () => { 55 | middlewareManager.use(new PersonMiddleware3()); 56 | const newStep = 3; 57 | person.walk(newStep); 58 | person.speak('hello'); 59 | assert.equal(person.step, newStep + 1); 60 | assert.isTrue(/from middleware/g.test(person.word)); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /docs/html/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Menlo, Monaco, Consolas, monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /docs/html/scripts/fulltext-search-ui.js: -------------------------------------------------------------------------------- 1 | window.SearcherDisplay = (function($) { 2 | /** 3 | * This class provides support for displaying quick search text results to users. 4 | */ 5 | function SearcherDisplay() { } 6 | 7 | SearcherDisplay.prototype.init = function() { 8 | this._displayQuickSearch(); 9 | }; 10 | 11 | /** 12 | * This method creates the quick text search entry in navigation menu and wires all required events. 13 | */ 14 | SearcherDisplay.prototype._displayQuickSearch = function() { 15 | var quickSearch = $(document.createElement("iframe")), 16 | body = $("body"), 17 | self = this; 18 | 19 | quickSearch.attr("src", "quicksearch.html"); 20 | quickSearch.css("width", "0px"); 21 | quickSearch.css("height", "0px"); 22 | 23 | body.append(quickSearch); 24 | 25 | $(window).on("message", function(msg) { 26 | var msgData = msg.originalEvent.data; 27 | 28 | if (msgData.msgid != "docstrap.quicksearch.done") { 29 | return; 30 | } 31 | 32 | var results = msgData.results || []; 33 | 34 | self._displaySearchResults(results); 35 | }); 36 | 37 | function startSearch() { 38 | var searchTerms = $('#search-input').prop("value"); 39 | if (searchTerms) { 40 | quickSearch[0].contentWindow.postMessage({ 41 | "searchTerms": searchTerms, 42 | "msgid": "docstrap.quicksearch.start" 43 | }, "*"); 44 | } 45 | } 46 | 47 | $('#search-input').on('keyup', function(evt) { 48 | if (evt.keyCode != 13) { 49 | return; 50 | } 51 | startSearch(); 52 | return false; 53 | }); 54 | $('#search-submit').on('click', function() { 55 | startSearch(); 56 | return false; 57 | }); 58 | }; 59 | 60 | /** 61 | * This method displays the quick text search results in a modal dialog. 62 | */ 63 | SearcherDisplay.prototype._displaySearchResults = function(results) { 64 | var resultsHolder = $($("#searchResults").find(".modal-body")), 65 | fragment = document.createDocumentFragment(), 66 | resultsList = document.createElement("ul"); 67 | 68 | resultsHolder.empty(); 69 | 70 | for (var idx = 0; idx < results.length; idx++) { 71 | var result = results[idx], 72 | item = document.createElement("li"), 73 | link = document.createElement("a"); 74 | 75 | link.href = result.id; 76 | link.innerHTML = result.title; 77 | 78 | item.appendChild(link) 79 | resultsList.appendChild(item); 80 | } 81 | 82 | fragment.appendChild(resultsList); 83 | resultsHolder.append(fragment); 84 | 85 | $("#searchResults").modal({"show": true}); 86 | }; 87 | 88 | return new SearcherDisplay(); 89 | })($); 90 | -------------------------------------------------------------------------------- /dist/middleware.min.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.jsMiddleware=e()}}(function(){return function e(t,r,n){function o(f,u){if(!r[f]){if(!t[f]){var a="function"==typeof require&&require;if(!u&&a)return a(f,!0);if(i)return i(f,!0);var d=new Error("Cannot find module '"+f+"'");throw d.code="MODULE_NOT_FOUND",d}var l=r[f]={exports:{}};t[f][0].call(l.exports,function(e){var r=t[f][1][e];return o(r||e)},l,l.exports,e,t,r,n)}return r[f].exports}for(var i="function"==typeof require&&require,f=0;f1?i-1:0),u=1;u1?o-1:0),u=1;u1?r-1:0),o=1;o 32 | ``` 33 | 2. Or install the package 34 | ``` 35 | npm install --save js-middleware 36 | ``` 37 | and import it in your files 38 | ``` 39 | import {MiddlewareManager} from 'js-middleware'; 40 | ``` 41 | 42 | # Usages 43 | 44 | ## Basic 45 | We define a Person class. 46 | ``` 47 | // the target object 48 | class Person { 49 | // the target function 50 | walk(step) { 51 | this.step = step; 52 | } 53 | 54 | speak(word) { 55 | this.word = word; 56 | } 57 | } 58 | ``` 59 | Then we define a middleware function to print log. 60 | 61 | ``` 62 | // middleware for walk function 63 | const logger = target => next => (...args) => { 64 | console.log(`walk start, steps: ${args[0]}.`); 65 | const result = next(...args); 66 | console.log(`walk end.`); 67 | return result; 68 | } 69 | ``` 70 | Now we apply the log function as a middleware to a Person instance. 71 | 72 | ``` 73 | // apply middleware to target object 74 | const p = new Person(); 75 | const middlewareManager = new MiddlewareManager(p); 76 | middlewareManager.use('walk', logger); 77 | p.walk(3); 78 | ``` 79 | Whenever a Person instance call it's walk method, we'll see logs from the looger middleware. 80 | 81 | ## Middleware object 82 | We can also apply a middleware object to a target object. Middleware object is an object that contains function's name as same as the target object's function name. 83 | Function's name start or end with "_" will not be able to apply middleware. 84 | 85 | ``` 86 | const PersonMiddleware = { 87 | walk: target => next => step => { 88 | console.log(`walk start, steps: step.`); 89 | const result = next(step); 90 | console.log(`walk end.`); 91 | return result; 92 | }, 93 | speak: target => next => word => { 94 | word = 'this is a middleware trying to say: ' + word; 95 | return next(word); 96 | } 97 | } 98 | 99 | // apply middleware to target object 100 | const p = new Person(); 101 | const middlewareManager = new MiddlewareManager(p); 102 | middlewareManager.use(PersonMiddleware); 103 | p.walk(3); 104 | p.speak('hi'); 105 | ``` 106 | 107 | ## middlewareMethods 108 | In a class, function's name start or end with "_" will not be able to apply as middleware. 109 | Or we can use `middlewareMethods` to define function names for middleware target within a class. 110 | 111 | ``` 112 | class PersonMiddleware { 113 | constructor() { 114 | /** 115 | * Or Define function names for middleweare target. 116 | * @type {Array} 117 | */ 118 | this.middlewareMethods = ['walk', 'speak']; 119 | } 120 | // Function's name start or end with "_" will not be able to apply as middleware. 121 | _getPrefix() { 122 | return 'Middleware log: '; 123 | } 124 | log(text) { 125 | console.log('Middleware log: ' + text); 126 | } 127 | walk(target) { 128 | return next => step => { 129 | this.log(`walk start, steps: step.`); 130 | const result = next(step); 131 | this.log(`walk end.`); 132 | return result; 133 | } 134 | } 135 | speak(target) { 136 | return next => word => { 137 | this.log('this is a middleware tring to say: ' + word); 138 | return next(word); 139 | } 140 | } 141 | } 142 | 143 | // apply middleware to target object 144 | const p = new Person(); 145 | const middlewareManager = new MiddlewareManager(p); 146 | middlewareManager.use(new PersonMiddleware()) 147 | p.walk(3); 148 | p.speak('hi'); 149 | ``` 150 | 151 | # APIs 152 | 153 | ### .use(methodName, ...middlewares) 154 | Apply (register) middleware functions to the target function or apply (register) middleware objects. 155 | If the first argument is a middleware object, the rest arguments must be middleware objects. 156 | - **{string|object}** methodName String for target function name, object for a middleware object. 157 | - **{...function}** middlewares The middleware chain to be applied. 158 | - return **{object}** this 159 | 160 | # Build 161 | 1. Run `npm install` to install requirements. 162 | 163 | 2. Run `gulp` to builds the library, generates `dist/middleware.js` as the core script, watches for file changes, 164 | starts a HTTP server for debug. 165 | ``` 166 | Usage 167 | gulp [TASK] [OPTIONS...] 168 | 169 | Available tasks 170 | build Builds the library. 171 | clean Cleans files. 172 | clean:dist Cleans dist files. 173 | clean:docs Cleans docs files. 174 | default 175 | docs Builds documentation. 176 | docs:html Builds HTML documentation. 177 | docs:md Builds markdown documentation. 178 | help Display this help text. 179 | lint Lint JS files. 180 | mini Minify the library. 181 | server Starts a HTTP server for debug. 182 | test Run test cases. 183 | watch Watches for changes in files, re-lint, re-build & re-docs. 184 | ``` 185 | 3. Run `gulp docs` to build docs. View markdown docs with `docs/API.md`, or run `gulp server` to start a HTTP server 186 | and view HTML docs with [localhost:3000/docs/html/](localhost:3000/docs/html/). 187 | 188 | # Roadmap & Make contributions 189 | - Supports RegExp to match method names, pass the current method name as param to the current middleware. 190 | - **once(methodName, ...middlewares)** Apply middlewares only run once. 191 | - Be able to **unuse** middlewares. 192 | -------------------------------------------------------------------------------- /docs/html/scripts/toc.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var navbarHeight; 3 | var initialised = false; 4 | var navbarOffset; 5 | 6 | function elOffset($el) { 7 | return $el.offset().top - (navbarHeight + navbarOffset); 8 | } 9 | 10 | function scrollToHash(duringPageLoad) { 11 | var elScrollToId = location.hash.replace(/^#/, ''); 12 | var $el; 13 | 14 | function doScroll() { 15 | var offsetTop = elOffset($el); 16 | window.scrollTo(window.pageXOffset || window.scrollX, offsetTop); 17 | } 18 | 19 | if (elScrollToId) { 20 | $el = $(document.getElementById(elScrollToId)); 21 | 22 | if (!$el.length) { 23 | $el = $(document.getElementsByName(elScrollToId)); 24 | } 25 | 26 | if ($el.length) { 27 | if (duringPageLoad) { 28 | $(window).one('scroll', function() { 29 | setTimeout(doScroll, 100); 30 | }); 31 | } else { 32 | setTimeout(doScroll, 0); 33 | } 34 | } 35 | } 36 | } 37 | 38 | function init(opts) { 39 | if (initialised) { 40 | return; 41 | } 42 | initialised = true; 43 | navbarHeight = $('.navbar').height(); 44 | navbarOffset = opts.navbarOffset; 45 | 46 | // some browsers move the offset after changing location. 47 | // also catch external links coming in 48 | $(window).on("hashchange", scrollToHash.bind(null, false)); 49 | $(scrollToHash.bind(null, true)); 50 | } 51 | 52 | $.catchAnchorLinks = function(options) { 53 | var opts = $.extend({}, jQuery.fn.toc.defaults, options); 54 | init(opts); 55 | }; 56 | 57 | $.fn.toc = function(options) { 58 | var self = this; 59 | var opts = $.extend({}, jQuery.fn.toc.defaults, options); 60 | 61 | var container = $(opts.container); 62 | var tocs = []; 63 | var headings = $(opts.selectors, container); 64 | var headingOffsets = []; 65 | var activeClassName = 'active'; 66 | var ANCHOR_PREFIX = "__anchor"; 67 | var maxScrollTo; 68 | var visibleHeight; 69 | var headerHeight = 10; // so if the header is readable, its counted as shown 70 | init(); 71 | 72 | var scrollTo = function(e) { 73 | e.preventDefault(); 74 | var target = $(e.target); 75 | if (target.prop('tagName').toLowerCase() !== "a") { 76 | target = target.parent(); 77 | } 78 | var elScrollToId = target.attr('href').replace(/^#/, '') + ANCHOR_PREFIX; 79 | var $el = $(document.getElementById(elScrollToId)); 80 | 81 | var offsetTop = Math.min(maxScrollTo, elOffset($el)); 82 | 83 | $('body,html').animate({ scrollTop: offsetTop }, 400, 'swing', function() { 84 | location.hash = '#' + elScrollToId; 85 | }); 86 | 87 | $('a', self).removeClass(activeClassName); 88 | target.addClass(activeClassName); 89 | }; 90 | 91 | var calcHadingOffsets = function() { 92 | maxScrollTo = $("body").height() - $(window).height(); 93 | visibleHeight = $(window).height() - navbarHeight; 94 | headingOffsets = []; 95 | headings.each(function(i, heading) { 96 | var anchorSpan = $(heading).prev("span"); 97 | var top = 0; 98 | if (anchorSpan.length) { 99 | top = elOffset(anchorSpan); 100 | } 101 | headingOffsets.push(top > 0 ? top : 0); 102 | }); 103 | } 104 | 105 | //highlight on scroll 106 | var timeout; 107 | var highlightOnScroll = function(e) { 108 | if (!tocs.length) { 109 | return; 110 | } 111 | if (timeout) { 112 | clearTimeout(timeout); 113 | } 114 | timeout = setTimeout(function() { 115 | var top = $(window).scrollTop(), 116 | highlighted; 117 | for (var i = headingOffsets.length - 1; i >= 0; i--) { 118 | var isActive = tocs[i].hasClass(activeClassName); 119 | // at the end of the page, allow any shown header 120 | if (isActive && headingOffsets[i] >= maxScrollTo && top >= maxScrollTo) { 121 | return; 122 | } 123 | // if we have got to the first heading or the heading is the first one visible 124 | if (i === 0 || (headingOffsets[i] + headerHeight >= top && (headingOffsets[i - 1] + headerHeight <= top))) { 125 | // in the case that a heading takes up more than the visible height e.g. we are showing 126 | // only the one above, highlight the one above 127 | if (i > 0 && headingOffsets[i] - visibleHeight >= top) { 128 | i--; 129 | } 130 | $('a', self).removeClass(activeClassName); 131 | if (i >= 0) { 132 | highlighted = tocs[i].addClass(activeClassName); 133 | opts.onHighlight(highlighted); 134 | } 135 | break; 136 | } 137 | } 138 | }, 50); 139 | }; 140 | if (opts.highlightOnScroll) { 141 | $(window).bind('scroll', highlightOnScroll); 142 | $(window).bind('load resize', function() { 143 | calcHadingOffsets(); 144 | highlightOnScroll(); 145 | }); 146 | } 147 | 148 | return this.each(function() { 149 | //build TOC 150 | var el = $(this); 151 | var ul = $('
'); 152 | 153 | headings.each(function(i, heading) { 154 | var $h = $(heading); 155 | 156 | var anchor = $('').attr('id', opts.anchorName(i, heading, opts.prefix) + ANCHOR_PREFIX).insertBefore($h); 157 | 158 | var span = $('') 159 | .text(opts.headerText(i, heading, $h)); 160 | 161 | //build TOC item 162 | var a = $('') 163 | .append(span) 164 | .attr('href', '#' + opts.anchorName(i, heading, opts.prefix)) 165 | .bind('click', function(e) { 166 | scrollTo(e); 167 | el.trigger('selected', $(this).attr('href')); 168 | }); 169 | 170 | span.addClass(opts.itemClass(i, heading, $h, opts.prefix)); 171 | 172 | tocs.push(a); 173 | 174 | ul.append(a); 175 | }); 176 | el.html(ul); 177 | 178 | calcHadingOffsets(); 179 | }); 180 | }; 181 | 182 | 183 | jQuery.fn.toc.defaults = { 184 | container: 'body', 185 | selectors: 'h1,h2,h3', 186 | smoothScrolling: true, 187 | prefix: 'toc', 188 | onHighlight: function() {}, 189 | highlightOnScroll: true, 190 | navbarOffset: 0, 191 | anchorName: function(i, heading, prefix) { 192 | return prefix+i; 193 | }, 194 | headerText: function(i, heading, $heading) { 195 | return $heading.text(); 196 | }, 197 | itemClass: function(i, heading, $heading, prefix) { 198 | return prefix + '-' + $heading[0].tagName.toLowerCase(); 199 | } 200 | 201 | }; 202 | 203 | })(jQuery); 204 | -------------------------------------------------------------------------------- /docs/API.md: -------------------------------------------------------------------------------- 1 | ## Classes 2 | 3 |
4 |
MiddlewareManager
5 |

Manage middlewares for an object. 6 | Middleware functions are functions that have access to the target function and it's arguments, 7 | and the target object and the next middleware function in the target function cycle. 8 | The next middleware function is commonly denoted by a variable named next.

9 |

Middleware functions can perform the following tasks:

10 |
    11 |
  • Execute any code.
  • 12 |
  • Make changes to the function's arguments.
  • 13 |
  • End the target function.
  • 14 |
  • Call the next middleware in the stack.
  • 15 |
16 |

If the current middleware function does not end the target function cycle, 17 | it must call next() to pass control to the next middleware function. Otherwise, 18 | the target function will be left hanging.

19 |

e.g.

20 |
 const walk = target => next => (...args) => {
 21 |     this.log(`walk function start.`);
 22 |     const result = next(...args);
 23 |     this.log(`walk function end.`);
 24 |     return result;
 25 |   }
 26 | 

Middleware object is an object that contains function's name as same as the target object's function name.

27 |

e.g.

28 |
 const Logger = {
 29 |      walk: target => next => (...args) => {
 30 |        console.log(`walk function start.`);
 31 |        const result = next(...args);
 32 |        console.log(`walk function end.`);
 33 |        return result;
 34 |      }
 35 |   }
 36 | 

Function's name start or end with "_" will not be able to apply middleware.

37 |
38 |
MiddlewareManager
39 |
40 |
41 | 42 | ## Functions 43 | 44 |
45 |
compose(...funcs)function
46 |

Composes single-argument functions from right to left. The rightmost 47 | function can take multiple arguments as it provides the signature for 48 | the resulting composite function.

49 |
50 |
51 | 52 | 53 | 54 | ## MiddlewareManager 55 | Manage middlewares for an object. 56 | Middleware functions are functions that have access to the target function and it's arguments, 57 | and the target object and the next middleware function in the target function cycle. 58 | The next middleware function is commonly denoted by a variable named next. 59 | 60 | Middleware functions can perform the following tasks: 61 | - Execute any code. 62 | - Make changes to the function's arguments. 63 | - End the target function. 64 | - Call the next middleware in the stack. 65 | 66 | If the current middleware function does not end the target function cycle, 67 | it must call next() to pass control to the next middleware function. Otherwise, 68 | the target function will be left hanging. 69 | 70 | e.g. 71 | ``` 72 | const walk = target => next => (...args) => { 73 | this.log(`walk function start.`); 74 | const result = next(...args); 75 | this.log(`walk function end.`); 76 | return result; 77 | } 78 | ``` 79 | 80 | Middleware object is an object that contains function's name as same as the target object's function name. 81 | 82 | e.g. 83 | ``` 84 | const Logger = { 85 | walk: target => next => (...args) => { 86 | console.log(`walk function start.`); 87 | const result = next(...args); 88 | console.log(`walk function end.`); 89 | return result; 90 | } 91 | } 92 | ``` 93 | 94 | Function's name start or end with "_" will not be able to apply middleware. 95 | 96 | **Kind**: global class 97 | 98 | * [MiddlewareManager](#MiddlewareManager) 99 | * [new MiddlewareManager(target, ...middlewareObjects)](#new_MiddlewareManager_new) 100 | * [.use(methodName, ...middlewares)](#MiddlewareManager+use) ⇒ object 101 | 102 | 103 | 104 | ### new MiddlewareManager(target, ...middlewareObjects) 105 | **Returns**: object - this 106 | 107 | | Param | Type | Description | 108 | | --- | --- | --- | 109 | | target | object | The target object. | 110 | | ...middlewareObjects | object | Middleware objects. | 111 | 112 | 113 | 114 | ### middlewareManager.use(methodName, ...middlewares) ⇒ object 115 | Apply (register) middleware functions to the target function or apply (register) middleware objects. 116 | If the first argument is a middleware object, the rest arguments must be middleware objects. 117 | 118 | **Kind**: instance method of [MiddlewareManager](#MiddlewareManager) 119 | **Returns**: object - this 120 | 121 | | Param | Type | Description | 122 | | --- | --- | --- | 123 | | methodName | string | object | String for target function name, object for a middleware object. | 124 | | ...middlewares | function | object | The middleware chain to be applied. | 125 | 126 | 127 | 128 | ## MiddlewareManager 129 | **Kind**: global class 130 | 131 | * [MiddlewareManager](#MiddlewareManager) 132 | * [new MiddlewareManager(target, ...middlewareObjects)](#new_MiddlewareManager_new) 133 | * [.use(methodName, ...middlewares)](#MiddlewareManager+use) ⇒ object 134 | 135 | 136 | 137 | ### new MiddlewareManager(target, ...middlewareObjects) 138 | **Returns**: object - this 139 | 140 | | Param | Type | Description | 141 | | --- | --- | --- | 142 | | target | object | The target object. | 143 | | ...middlewareObjects | object | Middleware objects. | 144 | 145 | 146 | 147 | ### middlewareManager.use(methodName, ...middlewares) ⇒ object 148 | Apply (register) middleware functions to the target function or apply (register) middleware objects. 149 | If the first argument is a middleware object, the rest arguments must be middleware objects. 150 | 151 | **Kind**: instance method of [MiddlewareManager](#MiddlewareManager) 152 | **Returns**: object - this 153 | 154 | | Param | Type | Description | 155 | | --- | --- | --- | 156 | | methodName | string | object | String for target function name, object for a middleware object. | 157 | | ...middlewares | function | object | The middleware chain to be applied. | 158 | 159 | 160 | 161 | ## compose(...funcs) ⇒ function 162 | Composes single-argument functions from right to left. The rightmost 163 | function can take multiple arguments as it provides the signature for 164 | the resulting composite function. 165 | 166 | **Kind**: global function 167 | **Returns**: function - A function obtained by composing the argument functions 168 | from right to left. For example, compose(f, g, h) is identical to doing 169 | (...args) => f(g(h(...args))). 170 | 171 | | Param | Type | Description | 172 | | --- | --- | --- | 173 | | ...funcs | function | The functions to compose. | 174 | 175 | -------------------------------------------------------------------------------- /docs/html/classes.list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | js-middleware Classes 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 64 | 65 | 66 |
67 |
68 | 69 | 70 |
71 | 72 |
73 | 74 | 75 |

Classes

76 |
77 | 78 |
79 | 80 |

81 | 82 |

83 | 84 | 85 |
86 | 87 | 88 |
89 |
90 | 91 | 92 | 93 | 94 |
95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 |
131 | 132 | 133 | 134 | 135 |
136 | 137 | 138 | 139 | 140 | 141 | 142 |

Classes

143 | 144 |
145 |
MiddlewareManager
146 |
147 | 148 |
MiddlewareManager
149 |
150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 |
165 | 166 |
167 | 168 | 169 | 170 | 171 |
172 |
173 | 174 |
175 | 176 | 177 |
178 | 179 |
180 | 181 | 182 |
183 |
184 | 185 | 186 | 200 | 201 | 202 |
203 | 204 | 205 | 206 | Documentation generated by JSDoc 3.4.3 207 | 208 | on 2017-06-21 209 | 210 | using the DocStrap template. 211 | 212 |
213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 296 | 297 | 298 | 299 | -------------------------------------------------------------------------------- /lib/Middleware.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let middlewareManagerHash = []; 3 | 4 | /** 5 | * Composes single-argument functions from right to left. The rightmost 6 | * function can take multiple arguments as it provides the signature for 7 | * the resulting composite function. 8 | * 9 | * @param {...Function} funcs The functions to compose. 10 | * @returns {Function} A function obtained by composing the argument functions 11 | * from right to left. For example, compose(f, g, h) is identical to doing 12 | * (...args) => f(g(h(...args))). 13 | */ 14 | export function compose(...funcs) { 15 | if (funcs.length === 0) { 16 | return arg => arg; 17 | } 18 | 19 | funcs = funcs.filter(func => typeof func === 'function'); 20 | 21 | if (funcs.length === 1) { 22 | return funcs[0]; 23 | } 24 | 25 | const last = funcs[funcs.length - 1]; 26 | const rest = funcs.slice(0, -1); 27 | return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args)); 28 | } 29 | 30 | /** 31 | * Manage middlewares for an object. 32 | * Middleware functions are functions that have access to the target function and it's arguments, 33 | * and the target object and the next middleware function in the target function cycle. 34 | * The next middleware function is commonly denoted by a variable named next. 35 | * 36 | * Middleware functions can perform the following tasks: 37 | * - Execute any code. 38 | * - Make changes to the function's arguments. 39 | * - End the target function. 40 | * - Call the next middleware in the stack. 41 | * 42 | * If the current middleware function does not end the target function cycle, 43 | * it must call next() to pass control to the next middleware function. Otherwise, 44 | * the target function will be left hanging. 45 | * 46 | * e.g. 47 | * ``` 48 | * const walk = target => next => (...args) => { 49 | * this.log(`walk function start.`); 50 | * const result = next(...args); 51 | * this.log(`walk function end.`); 52 | * return result; 53 | * } 54 | * ``` 55 | * 56 | * Middleware object is an object that contains function's name as same as the target object's function name. 57 | * 58 | * e.g. 59 | * ``` 60 | * const Logger = { 61 | * walk: target => next => (...args) => { 62 | * console.log(`walk function start.`); 63 | * const result = next(...args); 64 | * console.log(`walk function end.`); 65 | * return result; 66 | * } 67 | * } 68 | * ``` 69 | * 70 | * Function's name start or end with "_" will not be able to apply middleware. 71 | * 72 | * @example 73 | * 74 | * ## Basic 75 | * 76 | * We define a Person class. 77 | * // the target object 78 | * class Person { 79 | * // the target function 80 | * walk(step) { 81 | * this.step = step; 82 | * } 83 | * 84 | * speak(word) { 85 | * this.word = word; 86 | * } 87 | * } 88 | * 89 | * Then we define a middleware function to print log. 90 | * 91 | * // middleware for walk function 92 | * const logger = target => next => (...args) => { 93 | * console.log(`walk start, steps: ${args[0]}.`); 94 | * const result = next(...args); 95 | * console.log(`walk end.`); 96 | * return result; 97 | * } 98 | * 99 | * Now we apply the log function as a middleware to a Person instance. 100 | * 101 | * // apply middleware to target object 102 | * const p = new Person(); 103 | * const middlewareManager = new MiddlewareManager(p); 104 | * middlewareManager.use('walk', logger); 105 | * p.walk(3); 106 | * 107 | * Whenever a Person instance call it's walk method, we'll see logs from the looger middleware. 108 | * 109 | * ## Middleware object 110 | * We can also apply a middleware object to a target object. 111 | * Middleware object is an object that contains function's name as same as the target object's function name. 112 | * 113 | * const PersonMiddleware = { 114 | * walk: target => next => step => { 115 | * console.log(`walk start, steps: step.`); 116 | * const result = next(step); 117 | * console.log(`walk end.`); 118 | * return result; 119 | * }, 120 | * speak: target => next => word => { 121 | * word = 'this is a middleware trying to say: ' + word; 122 | * return next(word); 123 | * } 124 | * } 125 | * 126 | * // apply middleware to target object 127 | * const p = new Person(); 128 | * const middlewareManager = new MiddlewareManager(p); 129 | * middlewareManager.use(PersonMiddleware); 130 | * p.walk(3); 131 | * p.speak('hi'); 132 | * 133 | * ## middlewareMethods 134 | * In a class, function's name start or end with "_" will not be able to apply as middleware. 135 | * Or we can use `middlewareMethods` to define function names for middleware target within a class. 136 | * 137 | * class PersonMiddleware { 138 | * constructor() { 139 | * // Or Define function names for middleware target. 140 | * this.middlewareMethods = ['walk', 'speak']; 141 | * } 142 | * // Function's name start or end with "_" will not be able to apply as middleware. 143 | * _getPrefix() { 144 | * return 'Middleware log: '; 145 | * } 146 | * log(text) { 147 | * console.log(this._getPrefix() + text); 148 | * } 149 | * walk(target) { 150 | * return next => step => { 151 | * this.log(`walk start, steps: step.`); 152 | * const result = next(step); 153 | * this.log(`walk end.`); 154 | * return result; 155 | * } 156 | * } 157 | * speak(target) { 158 | * return next => word => { 159 | * this.log('this is a middleware trying to say: ' + word); 160 | * return next(word); 161 | * } 162 | * } 163 | * } 164 | * 165 | * // apply middleware to target object 166 | * const p = new Person(); 167 | * const middlewareManager = new MiddlewareManager(p); 168 | * middlewareManager.use(new PersonMiddleware()) 169 | * p.walk(3); 170 | * p.speak('hi'); 171 | * 172 | */ 173 | export class MiddlewareManager { 174 | /** 175 | * @param {object} target The target object. 176 | * @param {...object} middlewareObjects Middleware objects. 177 | * @return {object} this 178 | */ 179 | constructor(target, ...middlewareObjects) { 180 | let instance = middlewareManagerHash.find(function (key) { 181 | return key._target === target; 182 | }); 183 | // a target can only has one MiddlewareManager instance 184 | if (instance === undefined) { 185 | this._target = target; 186 | this._methods = {}; 187 | this._methodMiddlewares = {}; 188 | middlewareManagerHash.push(this); 189 | instance = this; 190 | } 191 | instance.use(...middlewareObjects); 192 | 193 | return instance; 194 | } 195 | 196 | // Function's name start or end with "_" will not be able to apply middleware. 197 | _methodIsValid(methodName) { 198 | return !/^_+|_+$|constructor/g.test(methodName); 199 | } 200 | 201 | // Apply middleware to method 202 | _applyToMethod(methodName, ...middlewares) { 203 | if (typeof methodName === 'string' && this._methodIsValid(methodName)) { 204 | let method = this._methods[methodName] || this._target[methodName]; 205 | if (typeof method === 'function') { 206 | this._methods[methodName] = method; 207 | if (this._methodMiddlewares[methodName] === undefined) { 208 | this._methodMiddlewares[methodName] = []; 209 | } 210 | middlewares.forEach(middleware => 211 | typeof middleware === 'function' && this._methodMiddlewares[methodName].push(middleware(this._target)) 212 | ); 213 | this._target[methodName] = compose(...this._methodMiddlewares[methodName])(method.bind(this._target)); 214 | } 215 | } 216 | } 217 | 218 | /** 219 | * Apply (register) middleware functions to the target function or apply (register) middleware objects. 220 | * If the first argument is a middleware object, the rest arguments must be middleware objects. 221 | * 222 | * @param {string|object} methodName String for target function name, object for a middleware object. 223 | * @param {...function|...object} middlewares The middleware chain to be applied. 224 | * @return {object} this 225 | */ 226 | use(methodName, ...middlewares) { 227 | if (typeof methodName === 'object') { 228 | Array.prototype.slice.call(arguments).forEach(arg => { 229 | // A middleware object can specify target functions within middlewareMethods (Array). 230 | // e.g. obj.middlewareMethods = ['method1', 'method2']; 231 | // only method1 and method2 will be the target function. 232 | typeof arg === 'object' && 233 | (arg.middlewareMethods || 234 | (Object.keys(arg).length ? Object.keys(arg) : Object.getOwnPropertyNames(Object.getPrototypeOf(arg))) 235 | ).forEach(key => { 236 | typeof arg[key] === 'function' && this._methodIsValid(key) && this._applyToMethod(key, arg[key].bind(arg)); 237 | }); 238 | }); 239 | } else { 240 | this._applyToMethod(methodName, ...middlewares); 241 | } 242 | 243 | return this; 244 | } 245 | } 246 | 247 | if (typeof window !== 'undefined') { 248 | window['MiddlewareManager'] = MiddlewareManager; 249 | } 250 | -------------------------------------------------------------------------------- /docs/html/global.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | js-middleware Global 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 64 | 65 | 66 |
67 |
68 | 69 | 70 |
71 | 72 |
73 | 74 | 75 |

Global

76 |
77 | 78 |
79 | 80 |

81 | 82 |

83 | 84 | 85 |
86 | 87 | 88 |
89 |
90 | 91 | 92 | 93 | 94 |
95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 |
131 | 132 | 133 | 134 | 135 |
136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |

Methods

151 | 152 |
153 | 154 |
155 |
156 |

compose(funcs)

157 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |

Composes single-argument functions from right to left. The rightmost 165 | function can take multiple arguments as it provides the signature for 166 | the resulting composite function.

167 |
168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 |
Parameters:
177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 215 | 216 | 217 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 |
NameTypeArgumentDescription
funcs 207 | 208 | 209 | function 210 | 211 | 212 | 213 | 214 | 218 | 219 | 220 | 221 | 222 | 223 | <repeatable>
224 | 225 |

The functions to compose.

236 | 237 | 238 | 239 | 240 |
241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 |
277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 |
Returns:
291 | 292 | 293 |
294 |

A function obtained by composing the argument functions 295 | from right to left. For example, compose(f, g, h) is identical to doing 296 | (...args) => f(g(h(...args))).

297 |
298 | 299 | 300 | 301 |
302 |
303 | Type 304 |
305 |
306 | 307 | function 308 | 309 | 310 | 311 |
312 |
313 | 314 | 315 | 316 | 317 | 318 |
319 | 320 |
321 | 322 | 323 | 324 | 325 | 326 |
327 | 328 |
329 | 330 | 331 | 332 | 333 |
334 |
335 | 336 |
337 | 338 | 339 |
340 | 341 |
342 | 343 | 344 |
345 |
346 | 347 | 348 | 362 | 363 | 364 |
365 | 366 | 367 | 368 | Documentation generated by JSDoc 3.4.3 369 | 370 | on 2017-06-21 371 | 372 | using the DocStrap template. 373 | 374 |
375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 458 | 459 | 460 | 461 | -------------------------------------------------------------------------------- /docs/html/styles/sunlight.default.css: -------------------------------------------------------------------------------- 1 | /* global styles */ 2 | .sunlight-container { 3 | clear: both !important; 4 | position: relative !important; 5 | margin: 10px 0 !important; 6 | } 7 | .sunlight-code-container { 8 | clear: both !important; 9 | position: relative !important; 10 | border: none; 11 | border-color: #969696 !important; 12 | background-color: #FFFFFF !important; 13 | } 14 | .sunlight-highlighted, .sunlight-container, .sunlight-container textarea { 15 | font-family: Consolas, Inconsolata, Monaco, "Courier New" !important; 16 | font-size: 12px !important; 17 | line-height: 15px !important; 18 | } 19 | .sunlight-highlighted, .sunlight-container textarea { 20 | color: #000000 !important; 21 | margin: 0 !important; 22 | } 23 | .sunlight-container textarea { 24 | padding-left: 0 !important; 25 | margin-left: 0 !important; 26 | margin-right: 0 !important; 27 | padding-right: 0 !important; 28 | } 29 | .sunlight-code-container > .sunlight-highlighted { 30 | white-space: pre; 31 | overflow-x: auto; 32 | overflow-y: hidden; /* ie requires this wtf? */ 33 | } 34 | .sunlight-highlighted { 35 | z-index: 1; 36 | position: relative; 37 | } 38 | .sunlight-highlighted * { 39 | background: transparent; 40 | } 41 | .sunlight-line-number-margin { 42 | float: left !important; 43 | margin-right: 5px !important; 44 | margin-top: 0 !important; 45 | margin-bottom: 0 !important; 46 | padding: 0 !important; 47 | padding-right: 4px !important; 48 | padding-left: 4px !important; 49 | border-right: 1px solid #CCCCCC !important; 50 | background-color: #EEEEEE !important; 51 | color: #848484 !important; 52 | text-align: right !important; 53 | position: relative; 54 | z-index: 3; 55 | } 56 | .sunlight-highlighted a, .sunlight-line-number-margin a { 57 | border: none !important; 58 | text-decoration: none !important; 59 | font-weight: normal !important; 60 | font-style: normal !important; 61 | padding: 0 !important; 62 | } 63 | .sunlight-line-number-margin a { 64 | color: inherit !important; 65 | } 66 | .sunlight-line-highlight-overlay { 67 | position: absolute; 68 | top: 0; 69 | left: 0; 70 | width: 100%; 71 | z-index: 0; 72 | } 73 | .sunlight-line-highlight-overlay div { 74 | height: 15px; 75 | width: 100%; 76 | } 77 | .sunlight-line-highlight-overlay .sunlight-line-highlight-active { 78 | background-color: #E7FCFA; 79 | } 80 | 81 | /* menu */ 82 | .sunlight-menu { 83 | background-color: #FFFFCC; 84 | color: #000000; 85 | } 86 | .sunlight-menu ul { 87 | margin: 0 !important; 88 | padding: 0 !important; 89 | list-style-type: none !important; 90 | } 91 | .sunlight-menu li { 92 | float: right !important; 93 | margin-left: 5px !important; 94 | } 95 | .sunlight-menu a, .sunlight-menu img { 96 | color: #000099 !important; 97 | text-decoration: none !important; 98 | border: none !important; 99 | } 100 | 101 | 102 | 103 | 104 | .sunlight-string, 105 | .sunlight-char, 106 | .sunlight-heredoc, 107 | .sunlight-heredocDeclaration, 108 | .sunlight-nowdoc, 109 | .sunlight-longString, 110 | .sunlight-rawString, 111 | .sunlight-binaryString, 112 | .sunlight-rawLongString, 113 | .sunlight-binaryLongString, 114 | .sunlight-verbatimString, 115 | .sunlight-diff .sunlight-removed { 116 | color: #990000 !important; 117 | } 118 | 119 | .sunlight-ident, 120 | .sunlight-operator, 121 | .sunlight-punctuation, 122 | .sunlight-delimiter, 123 | .sunlight-diff .sunlight-unchanged { 124 | color: #000000 !important; 125 | } 126 | 127 | .sunlight-comment, 128 | .sunlight-xmlDocCommentContent, 129 | .sunlight-nginx .sunlight-ssiCommand, 130 | .sunlight-sln .sunlight-formatDeclaration, 131 | .sunlight-diff .sunlight-added { 132 | color: #009900 !important; 133 | } 134 | .sunlight-number, 135 | .sunlight-guid, 136 | .sunlight-cdata { 137 | color: #CC6600 !important; 138 | } 139 | 140 | .sunlight-named-ident, 141 | .sunlight-constant, 142 | .sunlight-javascript .sunlight-globalVariable, 143 | .sunlight-globalObject, 144 | .sunlight-python .sunlight-attribute, 145 | .sunlight-nginx .sunlight-context, 146 | .sunlight-httpd .sunlight-context, 147 | .sunlight-haskell .sunlight-class, 148 | .sunlight-haskell .sunlight-type, 149 | .sunlight-lisp .sunlight-declarationSpecifier, 150 | .sunlight-erlang .sunlight-userDefinedFunction, 151 | .sunlight-diff .sunlight-header { 152 | color: #2B91AF !important; 153 | } 154 | .sunlight-keyword, 155 | .sunlight-languageConstruct, 156 | .sunlight-css 157 | .sunlight-element, 158 | .sunlight-bash .sunlight-command, 159 | .sunlight-specialOperator, 160 | .sunlight-erlang .sunlight-moduleAttribute, 161 | .sunlight-xml .sunlight-tagName, 162 | .sunlight-xml .sunlight-operator, 163 | .sunlight-diff .sunlight-modified { 164 | color: #0000FF !important; 165 | } 166 | .sunlight-shortOpenTag, 167 | .sunlight-openTag, 168 | .sunlight-closeTag, 169 | .sunlight-xmlOpenTag, 170 | .sunlight-xmlCloseTag, 171 | .sunlight-aspOpenTag, 172 | .sunlight-aspCloseTag, 173 | .sunlight-label, 174 | .sunlight-css .sunlight-importantFlag { 175 | background-color: #FFFF99 !important; 176 | color: #000000 !important; 177 | } 178 | .sunlight-function, 179 | .sunlight-globalFunction, 180 | .sunlight-ruby .sunlight-specialFunction, 181 | .sunlight-objective-c .sunlight-messageDestination, 182 | .sunlight-6502asm .sunlight-illegalOpcode, 183 | .sunlight-powershell .sunlight-switch, 184 | .sunlight-lisp .sunlight-macro, 185 | .sunlight-lisp .sunlight-specialForm, 186 | .sunlight-lisp .sunlight-type, 187 | .sunlight-sln .sunlight-sectionName, 188 | .sunlight-diff .sunlight-rangeInfo { 189 | color: #B069AF !important; 190 | } 191 | 192 | .sunlight-variable, 193 | .sunlight-specialVariable, 194 | .sunlight-environmentVariable, 195 | .sunlight-objective-c .sunlight-messageArgumentName, 196 | .sunlight-lisp .sunlight-globalVariable, 197 | .sunlight-ruby .sunlight-globalVariable, 198 | .sunlight-ruby .sunlight-instanceVariable, 199 | .sunlight-sln .sunlight-operator { 200 | color: #325484 !important; 201 | } 202 | .sunlight-regexLiteral, 203 | .sunlight-lisp .sunlight-operator, 204 | .sunlight-6502asm .sunlight-pseudoOp, 205 | .sunlight-erlang .sunlight-macro { 206 | color: #FF00B2 !important; 207 | } 208 | .sunlight-specialVariable { 209 | font-style: italic !important; 210 | font-weight: bold !important; 211 | } 212 | .sunlight-csharp .sunlight-pragma, 213 | .sunlight-preprocessorDirective, 214 | .sunlight-vb .sunlight-compilerDirective, 215 | .sunlight-diff .sunlight-mergeHeader, 216 | .sunlight-diff .sunlight-noNewLine { 217 | color: #999999 !important; 218 | font-style: italic !important; 219 | } 220 | .sunlight-xmlDocCommentMeta, 221 | .sunlight-java .sunlight-annotation, 222 | .sunlight-scala .sunlight-annotation, 223 | .sunlight-docComment { 224 | color: #808080 !important; 225 | } 226 | .sunlight-quotedIdent, 227 | .sunlight-ruby .sunlight-subshellCommand, 228 | .sunlight-lisp .sunlight-keywordArgument, 229 | .sunlight-haskell .sunlight-infixOperator, 230 | .sunlight-erlang .sunlight-quotedAtom { 231 | color: #999900 !important; 232 | } 233 | 234 | 235 | 236 | /* xml */ 237 | .sunlight-xml .sunlight-string { 238 | color: #990099 !important; 239 | } 240 | .sunlight-xml .sunlight-attribute { 241 | color: #FF0000 !important; 242 | } 243 | .sunlight-xml .sunlight-entity { 244 | background-color: #EEEEEE !important; 245 | color: #000000 !important; 246 | border: 1px solid #000000 !important; 247 | } 248 | .sunlight-xml .sunlight-doctype { 249 | color: #2B91AF !important; 250 | } 251 | 252 | /* javascript */ 253 | .sunlight-javascript .sunlight-reservedWord { 254 | font-style: italic !important; 255 | } 256 | 257 | /* css */ 258 | .sunlight-css .sunlight-microsoftFilterPrefix { 259 | color: #FF00FF !important; 260 | } 261 | .sunlight-css .sunlight-rule { 262 | color: #0099FF !important; 263 | } 264 | .sunlight-css .sunlight-keyword { 265 | color: #4E65B8 !important; 266 | } 267 | .sunlight-css .sunlight-class { 268 | color: #FF0000 !important; 269 | } 270 | .sunlight-css .sunlight-id { 271 | color: #8A8E13 !important; 272 | } 273 | .sunlight-css .sunlight-pseudoClass, 274 | .sunlight-css .sunlight-pseudoElement { 275 | color: #368B87 !important; 276 | } 277 | 278 | /* bash */ 279 | .sunlight-bash .sunlight-hashBang { 280 | color: #3D97F5 !important; 281 | } 282 | .sunlight-bash .sunlight-verbatimCommand { 283 | color: #999900 !important; 284 | } 285 | .sunlight-bash .sunlight-variable, 286 | .sunlight-bash .sunlight-specialVariable { 287 | color: #FF0000 !important; 288 | } 289 | 290 | /* python */ 291 | .sunlight-python .sunlight-specialMethod { 292 | font-weight: bold !important; 293 | color: #A07DD3; 294 | } 295 | 296 | /* ruby */ 297 | .sunlight-ruby .sunlight-symbol { 298 | font-weight: bold !important; 299 | color: #ED7272 !important; 300 | } 301 | 302 | /* brainfuck */ 303 | .sunlight-brainfuck { 304 | font-weight: bold !important; 305 | color: #000000 !important; 306 | } 307 | .sunlight-brainfuck .sunlight-increment { 308 | background-color: #FF9900 !important; 309 | } 310 | .sunlight-brainfuck .sunlight-decrement { 311 | background-color: #FF99FF !important; 312 | } 313 | .sunlight-brainfuck .sunlight-incrementPointer { 314 | background-color: #FFFF99 !important; 315 | } 316 | .sunlight-brainfuck .sunlight-decrementPointer { 317 | background-color: #66CCFF !important; 318 | } 319 | .sunlight-brainfuck .sunlight-read { 320 | background-color: #FFFFFF !important; 321 | } 322 | .sunlight-brainfuck .sunlight-write { 323 | background-color: #99FF99 !important; 324 | } 325 | .sunlight-brainfuck .sunlight-openLoop, .sunlight-brainfuck .sunlight-closeLoop { 326 | background-color: #FFFFFF !important; 327 | } 328 | 329 | /* 6502 asm */ 330 | .sunlight-6502asm .sunlight-label { 331 | font-weight: bold !important; 332 | color: #000000 !important; 333 | background: none !important; 334 | } 335 | 336 | /* lisp */ 337 | .sunlight-lisp .sunlight-macro { 338 | font-style: italic !important; 339 | } 340 | 341 | /* erlang */ 342 | .sunlight-erlang .sunlight-atom { 343 | font-weight: bold !important; 344 | } -------------------------------------------------------------------------------- /docs/html/styles/sunlight.dark.css: -------------------------------------------------------------------------------- 1 | /* global styles */ 2 | .sunlight-container { 3 | clear: both !important; 4 | position: relative !important; 5 | margin: 10px 0 !important; 6 | } 7 | .sunlight-code-container { 8 | clear: both !important; 9 | position: relative !important; 10 | border: none; 11 | border-color: #626262 !important; 12 | background-color: #262626 !important; 13 | } 14 | .sunlight-highlighted, .sunlight-container, .sunlight-container textarea { 15 | font-family: Consolas, Inconsolata, Monaco, "Courier New" !important; 16 | font-size: 12px !important; 17 | line-height: 15px !important; 18 | } 19 | .sunlight-highlighted, .sunlight-container textarea { 20 | color: #FFFFFF !important; 21 | margin: 0 !important; 22 | } 23 | .sunlight-container textarea { 24 | padding-left: 0 !important; 25 | margin-left: 0 !important; 26 | margin-right: 0 !important; 27 | padding-right: 0 !important; 28 | } 29 | .sunlight-code-container > .sunlight-highlighted { 30 | white-space: pre; 31 | overflow-x: auto; 32 | overflow-y: hidden; /* ie requires this wtf? */ 33 | } 34 | .sunlight-highlighted { 35 | z-index: 1; 36 | position: relative; 37 | } 38 | .sunlight-highlighted * { 39 | background: transparent; 40 | } 41 | .sunlight-line-number-margin { 42 | float: left !important; 43 | margin-right: 5px !important; 44 | margin-top: 0 !important; 45 | margin-bottom: 0 !important; 46 | padding: 0 !important; 47 | padding-right: 4px !important; 48 | padding-left: 4px !important; 49 | border-right: 1px solid #9A9A9A !important; 50 | background-color: #3E3E3E !important; 51 | color: #9A9A9A !important; 52 | text-align: right !important; 53 | position: relative; 54 | z-index: 3; 55 | } 56 | .sunlight-highlighted a, .sunlight-line-number-margin a { 57 | border: none !important; 58 | text-decoration: none !important; 59 | font-style: normal !important; 60 | padding: 0 !important; 61 | } 62 | .sunlight-line-number-margin a { 63 | color: inherit !important; 64 | } 65 | .sunlight-line-highlight-overlay { 66 | position: absolute; 67 | top: 0; 68 | left: 0; 69 | width: 100%; 70 | z-index: 0; 71 | } 72 | .sunlight-line-highlight-overlay div { 73 | height: 15px; 74 | width: 100%; 75 | } 76 | .sunlight-line-highlight-overlay .sunlight-line-highlight-active { 77 | background-color: #4B4B4B; 78 | } 79 | 80 | /* menu */ 81 | .sunlight-menu { 82 | background-color: #FFFFCC; 83 | color: #000000; 84 | } 85 | .sunlight-menu ul { 86 | margin: 0 !important; 87 | padding: 0 !important; 88 | list-style-type: none !important; 89 | } 90 | .sunlight-menu li { 91 | float: right !important; 92 | margin-left: 5px !important; 93 | } 94 | .sunlight-menu a, .sunlight-menu img { 95 | color: #000099 !important; 96 | text-decoration: none !important; 97 | border: none !important; 98 | } 99 | 100 | 101 | 102 | 103 | .sunlight-string, 104 | .sunlight-char, 105 | .sunlight-heredoc, 106 | .sunlight-heredocDeclaration, 107 | .sunlight-nowdoc, 108 | .sunlight-longString, 109 | .sunlight-rawString, 110 | .sunlight-binaryString, 111 | .sunlight-verbatimString, 112 | .sunlight-rawLongString, 113 | .sunlight-binaryLongString, 114 | .sunlight-diff .sunlight-added { 115 | color: #55EB54 !important; 116 | } 117 | .sunlight-operator, 118 | .sunlight-punctuation, 119 | .sunlight-delimiter { 120 | color: #B1EDEC !important; 121 | } 122 | .sunlight-ident, 123 | .sunlight-diff .sunlight-unchanged { 124 | color: #E0E0E0 !important; 125 | font-weight: bold !important; 126 | } 127 | .sunlight-comment, 128 | .sunlight-xmlDocCommentContent, 129 | .sunlight-nginx .sunlight-ssiCommand, 130 | .sunlight-sln .sunlight-formatDeclaration, 131 | .sunlight-diff .sunlight-mergeHeader, 132 | .sunlight-diff .sunlight-noNewLine { 133 | color: #787D31 !important; 134 | } 135 | .sunlight-number, 136 | .sunlight-cdata, 137 | .sunlight-guid, 138 | .sunlight-diff .sunlight-modified { 139 | color: #F7BA7E !important; 140 | font-weight: bold !important; 141 | } 142 | .sunlight-named-ident, 143 | .sunlight-xml .sunlight-attribute, 144 | .sunlight-constant, 145 | .sunlight-javascript .sunlight-globalVariable, 146 | .sunlight-globalObject, 147 | .sunlight-css .sunlight-id, 148 | .sunlight-python .sunlight-attribute, 149 | .sunlight-nginx .sunlight-context, 150 | .sunlight-httpd .sunlight-context, 151 | .sunlight-lisp .sunlight-declarationSpecifier, 152 | .sunlight-erlang .sunlight-userDefinedFunction, 153 | .sunlight-diff .sunlight-removed { 154 | color: #FBBDEE !important; 155 | font-weight: bold !important; 156 | } 157 | .sunlight-keyword, 158 | .sunlight-languageConstruct, 159 | .sunlight-specialOperator, 160 | .sunlight-xml .sunlight-tagName, 161 | .sunlight-xml .sunlight-operator, 162 | .sunlight-bash .sunlight-command, 163 | .sunlight-erlang .sunlight-moduleAttribute { 164 | color: #A3CCF7 !important; 165 | font-weight: bold !important; 166 | } 167 | .sunlight-shortOpenTag, 168 | .sunlight-openTag, 169 | .sunlight-closeTag, 170 | .sunlight-xmlOpenTag, 171 | .sunlight-xmlCloseTag, 172 | .sunlight-aspOpenTag, 173 | .sunlight-aspCloseTag, 174 | .sunlight-label, 175 | .sunlight-css .sunlight-importantFlag { 176 | background-color: #7373C1 !important; 177 | } 178 | .sunlight-content { 179 | color: #FFFFFF !important; 180 | font-weight: bold !important; 181 | } 182 | .sunlight-function, 183 | .sunlight-globalFunction, 184 | .sunlight-objective-c .sunlight-messageDestination, 185 | .sunlight-ruby .sunlight-specialFunction, 186 | .sunlight-6502asm .sunlight-illegalOpcode, 187 | .sunlight-powershell .sunlight-switch, 188 | .sunlight-lisp .sunlight-macro, 189 | .sunlight-lisp .sunlight-specialForm, 190 | .sunlight-lisp .sunlight-type, 191 | .sunlight-sln .sunlight-sectionName, 192 | .sunlight-diff .sunlight-header { 193 | color: #C8BBF1 !important; 194 | font-weight: bold !important; 195 | } 196 | .sunlight-variable, 197 | .sunlight-environmentVariable, 198 | .sunlight-specialVariable, 199 | .sunlight-objective-c .sunlight-messageArgumentName, 200 | .sunlight-lisp .sunlight-globalVariable, 201 | .sunlight-ruby .sunlight-globalVariable, 202 | .sunlight-ruby .sunlight-instanceVariable { 203 | color: #F5E5B0 !important; 204 | font-weight: bold !important; 205 | } 206 | .sunlight-regexLiteral, 207 | .sunlight-lisp .sunlight-operator, 208 | .sunlight-6502asm .sunlight-pseudoOp, 209 | .sunlight-erlang .sunlight-macro, 210 | .sunlight-diff .sunlight-rangeInfo { 211 | color: #E0F16A !important; 212 | } 213 | .sunlight-specialVariable { 214 | font-style: italic !important; 215 | font-weight: bold !important; 216 | } 217 | .sunlight-csharp .sunlight-pragma, 218 | .sunlight-preprocessorDirective, 219 | .sunlight-vb .sunlight-compilerDirective { 220 | color: #666363 !important; 221 | font-style: italic !important; 222 | } 223 | .sunlight-xmlDocCommentMeta, 224 | .sunlight-java .sunlight-annotation, 225 | .sunlight-scala .sunlight-annotation, 226 | .sunlight-docComment { 227 | color: #666363 !important; 228 | } 229 | .sunlight-quotedIdent, 230 | .sunlight-ruby .sunlight-subshellCommand, 231 | .sunlight-lisp .sunlight-keywordArgument, 232 | .sunlight-haskell .sunlight-infixOperator, 233 | .sunlight-erlang .sunlight-quotedAtom { 234 | color: #F8CA16 !important; 235 | } 236 | 237 | 238 | 239 | 240 | /* html/xml */ 241 | .sunlight-xml .sunlight-tagName, 242 | .sunlight-xml .sunlight-operator, 243 | .sunlight-xml .sunlight-attribute { 244 | font-weight: normal !important; 245 | } 246 | .sunlight-doctype { 247 | color: #DEB9B2 !important; 248 | font-style: italic !important; 249 | } 250 | .sunlight-xml .sunlight-entity { 251 | background-color: #E6E585 !important; 252 | color: #000000 !important; 253 | } 254 | 255 | /* javascript */ 256 | .sunlight-javascript .sunlight-reservedWord { 257 | font-style: italic !important; 258 | } 259 | 260 | /* css */ 261 | .sunlight-css .sunlight-element { 262 | color: #E9EE97 !important; 263 | } 264 | .sunlight-css .sunlight-microsoftFilterPrefix { 265 | color: #C9FF9F !important; 266 | } 267 | .sunlight-css .sunlight-rule { 268 | color: #0099FF !important; 269 | } 270 | .sunlight-css .sunlight-class { 271 | color: #E78282 !important; 272 | } 273 | .sunlight-css .sunlight-pseudoClass, .sunlight-css .sunlight-pseudoElement { 274 | color: #73D693 !important; 275 | } 276 | 277 | /* bash */ 278 | .sunlight-bash .sunlight-hashBang { 279 | color: #FFFF00 !important; 280 | } 281 | 282 | .sunlight-bash .sunlight-verbatimCommand { 283 | color: #BBA4EE !important; 284 | } 285 | .sunlight-bash .sunlight-variable, 286 | .sunlight-bash .sunlight-specialVariable { 287 | color: #ED8585 !important; 288 | } 289 | 290 | /* python */ 291 | .sunlight-python .sunlight-specialMethod { 292 | font-weight: bold !important; 293 | color: #B0A3C2; 294 | } 295 | 296 | /* ruby */ 297 | .sunlight-ruby .sunlight-symbol { 298 | font-weight: bold !important; 299 | color: #90EEA2 !important; 300 | } 301 | 302 | /* brainfuck */ 303 | .sunlight-brainfuck { 304 | font-weight: bold !important; 305 | color: #000000 !important; 306 | } 307 | .sunlight-brainfuck .sunlight-increment { 308 | background-color: #FF9900 !important; 309 | } 310 | .sunlight-brainfuck .sunlight-decrement { 311 | background-color: #FF99FF !important; 312 | } 313 | .sunlight-brainfuck .sunlight-incrementPointer { 314 | background-color: #FFFF99 !important; 315 | } 316 | .sunlight-brainfuck .sunlight-decrementPointer { 317 | background-color: #66CCFF !important; 318 | } 319 | .sunlight-brainfuck .sunlight-read { 320 | background-color: #FFFFFF !important; 321 | } 322 | .sunlight-brainfuck .sunlight-write { 323 | background-color: #99FF99 !important; 324 | } 325 | .sunlight-brainfuck .sunlight-openLoop, .sunlight-brainfuck .sunlight-closeLoop { 326 | background-color: #FFFFFF !important; 327 | } 328 | 329 | /* 6502 asm */ 330 | .sunlight-6502asm .sunlight-label { 331 | background: none !important; 332 | color: #FFFFFF !important; 333 | text-decoration: underline !important; 334 | } 335 | 336 | /* lisp */ 337 | .sunlight-lisp .sunlight-macro { 338 | font-style: italic !important; 339 | } 340 | 341 | /* erlang */ 342 | .sunlight-erlang .sunlight-atom { 343 | color: #FFFFFF !important; 344 | font-weight: bold !important; 345 | } -------------------------------------------------------------------------------- /docs/html/quicksearch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/html/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | js-middleware Index 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 64 | 65 | 66 |
67 |
68 | 69 | 70 |
71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
96 |

js-middleware

Powerful Javascript Middleware Pattern implementation, apply middleweares to any object. 97 | A painless solution to make codes as scalable and maintainable as ReduxJS and ExpressJS.

98 |

Links

103 |

Overview

Middleware functions are functions that have access to the target function and it's arguments, 104 | and the target object and the next middleware function in the target function cycle. 105 | The next middleware function is commonly denoted by a variable named next.

106 |

Middleware functions can perform the following tasks:

107 |
    108 |
  • Execute any code.
  • 109 |
  • Make changes to the function's arguments.
  • 110 |
  • End the target function.
  • 111 |
  • Call the next middleware in the stack.

    112 |

    If the current middleware function does not end the target function cycle, 113 | it must call next() to pass control to the next middleware function. Otherwise, 114 | the target function will be left hanging.

    115 |
  • 116 |
117 |

Get started

    118 |
  1. window.MiddlewareManager is available for browsers by include 119 | dist/middleware.min.js file in your HTML.
    <script src="middleware.min.js"></script>
  2. 120 |
  3. Or install the package
    npm install --save js-middleware
    and import it in your files
    import {MiddlewareManager} from 'js-middleware';
  4. 121 |
122 |

Usages

Basic

We define a Person class.

123 |
// the target object
124 | class Person {
125 |   // the target function
126 |   walk(step) {
127 |     this.step = step;
128 |   }
129 | 
130 |   speak(word) {
131 |     this.word = word;
132 |   }
133 |  }

Then we define a middleware function to print log.

134 |
 // middleware for walk function
135 |  const logger = target => next => (...args) => {
136 |     console.log(`walk start, steps: ${args[0]}.`);
137 |     const result = next(...args);
138 |     console.log(`walk end.`);
139 |     return result;
140 |   }

Now we apply the log function as a middleware to a Person instance.

141 |
 // apply middleware to target object
142 |  const p = new Person();
143 |  const middlewareManager = new MiddlewareManager(p);
144 |  middlewareManager.use('walk', logger);
145 |  p.walk(3);

Whenever a Person instance call it's walk method, we'll see logs from the looger middleware.

146 |

Middleware object

We can also apply a middleware object to a target object. Middleware object is an object that contains function's name as same as the target object's function name. 147 | Function's name start or end with "_" will not be able to apply middleware.

148 |
const PersonMiddleware = {
149 |   walk: target => next => step => {
150 |     console.log(`walk start, steps: step.`);
151 |     const result = next(step);
152 |     console.log(`walk end.`);
153 |     return result;
154 |   },
155 |   speak: target => next => word => {
156 |     word = 'this is a middleware trying to say: ' + word;
157 |     return next(word);
158 |   }
159 | }
160 | 
161 |  // apply middleware to target object
162 |  const p = new Person();
163 |  const middlewareManager = new MiddlewareManager(p);
164 |  middlewareManager.use(PersonMiddleware);
165 |  p.walk(3);
166 |  p.speak('hi');

middlewareMethods

In a class, function's name start or end with "_" will not be able to apply as middleware. 167 | Or we can use middlewareMethods to define function names for middleware target within a class.

168 |
class PersonMiddleware {
169 |   constructor() {
170 |     /**
171 |      * Or Define function names for middleweare target.
172 |      * @type {Array}
173 |      */
174 |     this.middlewareMethods = ['walk', 'speak'];
175 |   }
176 |   // Function's name start or end with "_" will not be able to apply as middleware.
177 |   _getPrefix() {
178 |    return 'Middleware log: ';
179 |   }
180 |   log(text) {
181 |     console.log('Middleware log: ' + text);
182 |   }
183 |   walk(target) {
184 |     return next => step => {
185 |       this.log(`walk start, steps: step.`);
186 |       const result = next(step);
187 |       this.log(`walk end.`);
188 |       return result;
189 |     }
190 |   }
191 |   speak(target) {
192 |     return next => word => {
193 |       this.log('this is a middleware tring to say: ' + word);
194 |       return next(word);
195 |     }
196 |   }
197 | }
198 | 
199 |  // apply middleware to target object
200 |  const p = new Person();
201 |  const middlewareManager = new MiddlewareManager(p);
202 |  middlewareManager.use(new PersonMiddleware())
203 |  p.walk(3);
204 |  p.speak('hi');

APIs

.use(methodName, ...middlewares)

Apply (register) middleware functions to the target function or apply (register) middleware objects. 205 | If the first argument is a middleware object, the rest arguments must be middleware objects.

206 |
    207 |
  • {string|object} methodName String for target function name, object for a middleware object.
  • 208 |
  • {...function} middlewares The middleware chain to be applied.
  • 209 |
  • return {object} this
  • 210 |
211 |

Build

    212 |
  1. Run npm install to install requirements.

    213 |
  2. 214 |
  3. Run gulp to builds the library, generates dist/middleware.js as the core script, watches for file changes, 215 | starts a HTTP server for debug.

    216 |
    Usage
    217 |  gulp [TASK] [OPTIONS...]
    218 | 
    219 | Available tasks
    220 |  build       Builds the library.
    221 |  clean       Cleans files.
    222 |  clean:dist  Cleans dist files.
    223 |  clean:docs  Cleans docs files.
    224 |  default    
    225 |  docs        Builds documentation.
    226 |  docs:html   Builds HTML documentation.
    227 |  docs:md     Builds markdown documentation.
    228 |  help        Display this help text.
    229 |  lint        Lint JS files.
    230 |  mini        Minify the library.
    231 |  server      Starts a HTTP server for debug.
    232 |  test        Run test cases.
    233 |  watch       Watches for changes in files, re-lint, re-build & re-docs.
  4. 234 |
  5. Run gulp docs to build docs. View markdown docs with docs/API.md, or run gulp server to start a HTTP server 235 | and view HTML docs with localhost:3000/docs/html/.
  6. 236 |
237 |

Roadmap & Make contributions

    238 |
  • Supports RegExp to match method names, pass the current method name as param to the current middleware.
  • 239 |
  • once(methodName, ...middlewares) Apply middlewares only run once.
  • 240 |
  • Be able to unuse middlewares.
  • 241 |
242 |
243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 |
251 |
252 | 253 |
254 | 255 | 256 |
257 | 258 |
259 | 260 | 261 |
262 |
263 | 264 | 265 | 279 | 280 | 281 |
282 | 283 | 284 | 285 | Documentation generated by JSDoc 3.4.3 286 | 287 | on 2017-06-21 288 | 289 | using the DocStrap template. 290 | 291 |
292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 375 | 376 | 377 | 378 | -------------------------------------------------------------------------------- /docs/html/scripts/lunr.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.7.1 3 | * Copyright (C) 2016 Oliver Nightingale 4 | * @license MIT 5 | */ 6 | !function(){var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.7.1",t.utils={},t.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),t.utils.asString=function(t){return void 0===t||null===t?"":t.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},t.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},t.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},t.EventEmitter.prototype.hasHandler=function(t){return t in this.events},t.tokenizer=function(e){return arguments.length&&null!=e&&void 0!=e?Array.isArray(e)?e.map(function(e){return t.utils.asString(e).toLowerCase()}):e.toString().trim().toLowerCase().split(t.tokenizer.seperator):[]},t.tokenizer.seperator=/[\s\-]+/,t.tokenizer.load=function(t){var e=this.registeredFunctions[t];if(!e)throw new Error("Cannot load un-registered function: "+t);return e},t.tokenizer.label="default",t.tokenizer.registeredFunctions={"default":t.tokenizer},t.tokenizer.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing tokenizer: "+n),e.label=n,this.registeredFunctions[n]=e},t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.registeredFunctions[e];if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");this._stack.splice(i,0,n)},t.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);-1!=e&&this._stack.splice(e,1)},t.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,i=this._stack.length,r=0;n>r;r++){for(var o=t[r],s=0;i>s&&(o=this._stack[s](o,r,t),void 0!==o&&""!==o);s++);void 0!==o&&""!==o&&e.push(o)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(en.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t1;){if(o===t)return r;t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r]}return o===t?r:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,r=e+Math.floor(i/2),o=this.elements[r];i>1;)t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r];return o>t?r:t>o?r+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,r=0,o=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>o-1||r>s-1)break;a[i]!==h[r]?a[i]h[r]&&r++:(n.add(a[i]),i++,r++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone();for(var r=0,o=n.toArray();rp;p++)c[p]===a&&d++;h+=d/f*l.boost}}this.tokenStore.add(a,{ref:o,tf:h})}n&&this.eventEmitter.emit("add",e,this)},t.Index.prototype.remove=function(t,e){var n=t[this._ref],e=void 0===e?!0:e;if(this.documentStore.has(n)){var i=this.documentStore.get(n);this.documentStore.remove(n),i.forEach(function(t){this.tokenStore.remove(t,n)},this),e&&this.eventEmitter.emit("remove",t,this)}},t.Index.prototype.update=function(t,e){var e=void 0===e?!0:e;this.remove(t,!1),this.add(t,!1),e&&this.eventEmitter.emit("update",t,this)},t.Index.prototype.idf=function(t){var e="@"+t;if(Object.prototype.hasOwnProperty.call(this._idfCache,e))return this._idfCache[e];var n=this.tokenStore.count(t),i=1;return n>0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(this.tokenizerFn(e)),i=new t.Vector,r=[],o=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*o,h=this,u=this.tokenStore.expand(e).reduce(function(n,r){var o=h.corpusTokens.indexOf(r),s=h.idf(r),u=1,l=new t.SortedSet;if(r!==e){var c=Math.max(3,r.length-e.length);u=1/Math.log(c)}o>-1&&i.insert(o,a*s*u);for(var f=h.tokenStore.get(r),d=Object.keys(f),p=d.length,v=0;p>v;v++)l.add(f[d[v]].ref);return n.union(l)},new t.SortedSet);r.push(u)},this);var a=r.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,r=new t.Vector,o=0;i>o;o++){var s=n.elements[o],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);r.insert(this.corpusTokens.indexOf(s),a*h)}return r},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,tokenizer:this.tokenizerFn.label,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",r=n+"[^aeiouy]*",o=i+"[aeiou]*",s="^("+r+")?"+o+r,a="^("+r+")?"+o+r+"("+o+")?$",h="^("+r+")?"+o+r+o+r,u="^("+r+")?"+i,l=new RegExp(s),c=new RegExp(h),f=new RegExp(a),d=new RegExp(u),p=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,m=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),k=new RegExp("^"+r+i+"[^aeiouwxy]$"),x=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,F=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,_=/^(.+?)(s|t)(ion)$/,z=/^(.+?)e$/,O=/ll$/,P=new RegExp("^"+r+i+"[^aeiouwxy]$"),T=function(n){var i,r,o,s,a,h,u;if(n.length<3)return n;if(o=n.substr(0,1),"y"==o&&(n=o.toUpperCase()+n.substr(1)),s=p,a=v,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=g,a=m,s.test(n)){var T=s.exec(n);s=l,s.test(T[1])&&(s=y,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=d,a.test(i)&&(n=i,a=S,h=w,u=k,a.test(n)?n+="e":h.test(n)?(s=y,n=n.replace(s,"")):u.test(n)&&(n+="e"))}if(s=x,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+t[r])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+e[r])}if(s=F,a=_,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=z,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=P,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=O,a=c,s.test(n)&&a.test(n)&&(s=y,n=n.replace(s,"")),"y"==o&&(n=o.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.generateStopWordFilter=function(t){var e=t.reduce(function(t,e){return t[e]=e,t},{});return function(t){return t&&e[t]!==t?t:void 0}},t.stopWordFilter=t.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){return t.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t.charAt(0),r=t.slice(1);return i in n||(n[i]={docs:{}}),0===r.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(r,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;n 122 || (d < 65 || j > 90 || b.push([Math.max(65, j) | 32, Math.min(d, 90) | 32]), d < 97 || j > 122 || b.push([Math.max(97, j) & -33, Math.min(d, 122) & -33])) 29 | } 30 | } 31 | b.sort(function(a, f) { 32 | return a[0] - f[0] || f[1] - a[1] 33 | }); 34 | f = []; 35 | j = [NaN, NaN]; 36 | for (c = 0; c < b.length; ++c) i = b[c], i[0] <= j[1] + 1 ? j[1] = Math.max(j[1], i[1]) : f.push(j = i); 37 | b = ["["]; 38 | o && b.push("^"); 39 | b.push.apply(b, a); 40 | for (c = 0; c < f.length; ++c) i = f[c], b.push(e(i[0])), i[1] > i[0] && (i[1] + 1 > i[0] && b.push("-"), b.push(e(i[1]))); 41 | b.push("]"); 42 | return b.join("") 43 | } 44 | 45 | function y(a) { 46 | for (var f = a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g), b = f.length, d = [], c = 0, i = 0; c < b; ++c) { 47 | var j = f[c]; 48 | j === "(" ? ++i : "\\" === j.charAt(0) && (j = +j.substring(1)) && j <= i && (d[j] = -1) 49 | } 50 | for (c = 1; c < d.length; ++c) - 1 === d[c] && (d[c] = ++t); 51 | for (i = c = 0; c < b; ++c) j = f[c], j === "(" ? (++i, d[i] === void 0 && (f[c] = "(?:")) : "\\" === j.charAt(0) && (j = +j.substring(1)) && j <= i && (f[c] = "\\" + d[i]); 52 | for (i = c = 0; c < b; ++c)"^" === f[c] && "^" !== f[c + 1] && (f[c] = ""); 53 | if (a.ignoreCase && s) for (c = 0; c < b; ++c) j = f[c], a = j.charAt(0), j.length >= 2 && a === "[" ? f[c] = h(j) : a !== "\\" && (f[c] = j.replace(/[A-Za-z]/g, function(a) { 54 | a = a.charCodeAt(0); 55 | return "[" + String.fromCharCode(a & -33, a | 32) + "]" 56 | })); 57 | return f.join("") 58 | } 59 | for (var t = 0, s = !1, l = !1, p = 0, d = a.length; p < d; ++p) { 60 | var g = a[p]; 61 | if (g.ignoreCase) l = !0; 62 | else if (/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, ""))) { 63 | s = !0; 64 | l = !1; 65 | break 66 | } 67 | } 68 | for (var r = { 69 | b: 8, 70 | t: 9, 71 | n: 10, 72 | v: 11, 73 | f: 12, 74 | r: 13 75 | }, n = [], p = 0, d = a.length; p < d; ++p) { 76 | g = a[p]; 77 | if (g.global || g.multiline) throw Error("" + g); 78 | n.push("(?:" + y(g) + ")") 79 | } 80 | return RegExp(n.join("|"), l ? "gi" : "g") 81 | } 82 | 83 | function M(a) { 84 | function m(a) { 85 | switch (a.nodeType) { 86 | case 1: 87 | if (e.test(a.className)) break; 88 | for (var g = a.firstChild; g; g = g.nextSibling) m(g); 89 | g = a.nodeName; 90 | if ("BR" === g || "LI" === g) h[s] = "\n", t[s << 1] = y++, t[s++ << 1 | 1] = a; 91 | break; 92 | case 3: 93 | case 4: 94 | g = a.nodeValue, g.length && (g = p ? g.replace(/\r\n?/g, "\n") : g.replace(/[\t\n\r ]+/g, " "), h[s] = g, t[s << 1] = y, y += g.length, t[s++ << 1 | 1] = a) 95 | } 96 | } 97 | var e = /(?:^|\s)nocode(?:\s|$)/, 98 | h = [], 99 | y = 0, 100 | t = [], 101 | s = 0, 102 | l; 103 | a.currentStyle ? l = a.currentStyle.whiteSpace : window.getComputedStyle && (l = document.defaultView.getComputedStyle(a, q).getPropertyValue("white-space")); 104 | var p = l && "pre" === l.substring(0, 3); 105 | m(a); 106 | return { 107 | a: h.join("").replace(/\n$/, ""), 108 | c: t 109 | } 110 | } 111 | 112 | function B(a, m, e, h) { 113 | m && (a = { 114 | a: m, 115 | d: a 116 | }, e(a), h.push.apply(h, a.e)) 117 | } 118 | 119 | function x(a, m) { 120 | function e(a) { 121 | for (var l = a.d, p = [l, "pln"], d = 0, g = a.a.match(y) || [], r = {}, n = 0, z = g.length; n < z; ++n) { 122 | var f = g[n], 123 | b = r[f], 124 | o = void 0, 125 | c; 126 | if (typeof b === "string") c = !1; 127 | else { 128 | var i = h[f.charAt(0)]; 129 | if (i) o = f.match(i[1]), b = i[0]; 130 | else { 131 | for (c = 0; c < t; ++c) if (i = m[c], o = f.match(i[1])) { 132 | b = i[0]; 133 | break 134 | } 135 | o || (b = "pln") 136 | } 137 | if ((c = b.length >= 5 && "lang-" === b.substring(0, 5)) && !(o && typeof o[1] === "string")) c = !1, b = "src"; 138 | c || (r[f] = b) 139 | } 140 | i = d; 141 | d += f.length; 142 | if (c) { 143 | c = o[1]; 144 | var j = f.indexOf(c), 145 | k = j + c.length; 146 | o[2] && (k = f.length - o[2].length, j = k - c.length); 147 | b = b.substring(5); 148 | B(l + i, f.substring(0, j), e, p); 149 | B(l + i + j, c, C(b, c), p); 150 | B(l + i + k, f.substring(k), e, p) 151 | } else p.push(l + i, b) 152 | } 153 | a.e = p 154 | } 155 | var h = {}, 156 | y; 157 | (function() { 158 | for (var e = a.concat(m), l = [], p = {}, d = 0, g = e.length; d < g; ++d) { 159 | var r = e[d], 160 | n = r[3]; 161 | if (n) for (var k = n.length; --k >= 0;) h[n.charAt(k)] = r; 162 | r = r[1]; 163 | n = "" + r; 164 | p.hasOwnProperty(n) || (l.push(r), p[n] = q) 165 | } 166 | l.push(/[\S\s]/); 167 | y = L(l) 168 | })(); 169 | var t = m.length; 170 | return e 171 | } 172 | 173 | function u(a) { 174 | var m = [], 175 | e = []; 176 | a.tripleQuotedStrings ? m.push(["str", /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, q, "'\""]) : a.multiLineStrings ? m.push(["str", /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, q, "'\"`"]) : m.push(["str", /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, q, "\"'"]); 177 | a.verbatimStrings && e.push(["str", /^@"(?:[^"]|"")*(?:"|$)/, q]); 178 | var h = a.hashComments; 179 | h && (a.cStyleComments ? (h > 1 ? m.push(["com", /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, "#"]) : m.push(["com", /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/, q, "#"]), e.push(["str", /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, q])) : m.push(["com", /^#[^\n\r]*/, q, "#"])); 180 | a.cStyleComments && (e.push(["com", /^\/\/[^\n\r]*/, q]), e.push(["com", /^\/\*[\S\s]*?(?:\*\/|$)/, q])); 181 | a.regexLiterals && e.push(["lang-regex", /^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]); 182 | (h = a.types) && e.push(["typ", h]); 183 | a = ("" + a.keywords).replace(/^ | $/g, ""); 184 | a.length && e.push(["kwd", RegExp("^(?:" + a.replace(/[\s,]+/g, "|") + ")\\b"), q]); 185 | m.push(["pln", /^\s+/, q, " \r\n\t\xa0"]); 186 | e.push(["lit", /^@[$_a-z][\w$@]*/i, q], ["typ", /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], ["pln", /^[$_a-z][\w$@]*/i, q], ["lit", /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, q, "0123456789"], ["pln", /^\\[\S\s]?/, q], ["pun", /^.[^\s\w"-$'./@\\`]*/, q]); 187 | return x(m, e) 188 | } 189 | 190 | function D(a, m) { 191 | function e(a) { 192 | switch (a.nodeType) { 193 | case 1: 194 | if (k.test(a.className)) break; 195 | if ("BR" === a.nodeName) h(a), a.parentNode && a.parentNode.removeChild(a); 196 | else for (a = a.firstChild; a; a = a.nextSibling) e(a); 197 | break; 198 | case 3: 199 | case 4: 200 | if (p) { 201 | var b = a.nodeValue, 202 | d = b.match(t); 203 | if (d) { 204 | var c = b.substring(0, d.index); 205 | a.nodeValue = c; 206 | (b = b.substring(d.index + d[0].length)) && a.parentNode.insertBefore(s.createTextNode(b), a.nextSibling); 207 | h(a); 208 | c || a.parentNode.removeChild(a) 209 | } 210 | } 211 | } 212 | } 213 | 214 | function h(a) { 215 | function b(a, d) { 216 | var e = d ? a.cloneNode(!1) : a, 217 | f = a.parentNode; 218 | if (f) { 219 | var f = b(f, 1), 220 | g = a.nextSibling; 221 | f.appendChild(e); 222 | for (var h = g; h; h = g) g = h.nextSibling, f.appendChild(h) 223 | } 224 | return e 225 | } 226 | for (; !a.nextSibling;) if (a = a.parentNode, !a) return; 227 | for (var a = b(a.nextSibling, 0), e; 228 | (e = a.parentNode) && e.nodeType === 1;) a = e; 229 | d.push(a) 230 | } 231 | var k = /(?:^|\s)nocode(?:\s|$)/, 232 | t = /\r\n?|\n/, 233 | s = a.ownerDocument, 234 | l; 235 | a.currentStyle ? l = a.currentStyle.whiteSpace : window.getComputedStyle && (l = s.defaultView.getComputedStyle(a, q).getPropertyValue("white-space")); 236 | var p = l && "pre" === l.substring(0, 3); 237 | for (l = s.createElement("LI"); a.firstChild;) l.appendChild(a.firstChild); 238 | for (var d = [l], g = 0; g < d.length; ++g) e(d[g]); 239 | m === (m | 0) && d[0].setAttribute("value", m); 240 | var r = s.createElement("OL"); 241 | r.className = "linenums"; 242 | for (var n = Math.max(0, m - 1 | 0) || 0, g = 0, z = d.length; g < z; ++g) l = d[g], l.className = "L" + (g + n) % 10, l.firstChild || l.appendChild(s.createTextNode("\xa0")), r.appendChild(l); 243 | a.appendChild(r) 244 | } 245 | 246 | function k(a, m) { 247 | for (var e = m.length; --e >= 0;) { 248 | var h = m[e]; 249 | A.hasOwnProperty(h) ? window.console && console.warn("cannot override language handler %s", h) : A[h] = a 250 | } 251 | } 252 | 253 | function C(a, m) { 254 | if (!a || !A.hasOwnProperty(a)) a = /^\s*= o && (h += 2); 309 | e >= c && (a += 2) 310 | } 311 | } catch (w) { 312 | "console" in window && console.log(w && w.stack ? w.stack : w) 313 | } 314 | } 315 | var v = ["break,continue,do,else,for,if,return,while"], 316 | w = [ 317 | [v, "auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"], 318 | F = [w, "alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"], 319 | G = [w, "abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 320 | H = [G, "as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"], 321 | w = [w, "debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"], 322 | I = [v, "and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 323 | J = [v, "alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"], 324 | v = [v, "case,done,elif,esac,eval,fi,function,in,local,set,then,until"], 325 | K = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/, 326 | N = /\S/, 327 | O = u({ 328 | keywords: [F, H, w, "caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END" + I, J, v], 329 | hashComments: !0, 330 | cStyleComments: !0, 331 | multiLineStrings: !0, 332 | regexLiterals: !0 333 | }), 334 | A = {}; 335 | k(O, ["default-code"]); 336 | k(x([], [ 337 | ["pln", /^[^]*(?:>|$)/], 339 | ["com", /^<\!--[\S\s]*?(?:--\>|$)/], 340 | ["lang-", /^<\?([\S\s]+?)(?:\?>|$)/], 341 | ["lang-", /^<%([\S\s]+?)(?:%>|$)/], 342 | ["pun", /^(?:<[%?]|[%?]>)/], 343 | ["lang-", /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], 344 | ["lang-js", /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], 345 | ["lang-css", /^]*>([\S\s]*?)(<\/style\b[^>]*>)/i], 346 | ["lang-in.tag", /^(<\/?[a-z][^<>]*>)/i] 347 | ]), ["default-markup", "htm", "html", "mxml", "xhtml", "xml", "xsl"]); 348 | k(x([ 349 | ["pln", /^\s+/, q, " \t\r\n"], 350 | ["atv", /^(?:"[^"]*"?|'[^']*'?)/, q, "\"'"] 351 | ], [ 352 | ["tag", /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], 353 | ["atn", /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], 354 | ["lang-uq.val", /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], 355 | ["pun", /^[/<->]+/], 356 | ["lang-js", /^on\w+\s*=\s*"([^"]+)"/i], 357 | ["lang-js", /^on\w+\s*=\s*'([^']+)'/i], 358 | ["lang-js", /^on\w+\s*=\s*([^\s"'>]+)/i], 359 | ["lang-css", /^style\s*=\s*"([^"]+)"/i], 360 | ["lang-css", /^style\s*=\s*'([^']+)'/i], 361 | ["lang-css", /^style\s*=\s*([^\s"'>]+)/i] 362 | ]), ["in.tag"]); 363 | k(x([], [ 364 | ["atv", /^[\S\s]+/] 365 | ]), ["uq.val"]); 366 | k(u({ 367 | keywords: F, 368 | hashComments: !0, 369 | cStyleComments: !0, 370 | types: K 371 | }), ["c", "cc", "cpp", "cxx", "cyc", "m"]); 372 | k(u({ 373 | keywords: "null,true,false" 374 | }), ["json"]); 375 | k(u({ 376 | keywords: H, 377 | hashComments: !0, 378 | cStyleComments: !0, 379 | verbatimStrings: !0, 380 | types: K 381 | }), ["cs"]); 382 | k(u({ 383 | keywords: G, 384 | cStyleComments: !0 385 | }), ["java"]); 386 | k(u({ 387 | keywords: v, 388 | hashComments: !0, 389 | multiLineStrings: !0 390 | }), ["bsh", "csh", "sh"]); 391 | k(u({ 392 | keywords: I, 393 | hashComments: !0, 394 | multiLineStrings: !0, 395 | tripleQuotedStrings: !0 396 | }), ["cv", "py"]); 397 | k(u({ 398 | keywords: "caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END", 399 | hashComments: !0, 400 | multiLineStrings: !0, 401 | regexLiterals: !0 402 | }), ["perl", "pl", "pm"]); 403 | k(u({ 404 | keywords: J, 405 | hashComments: !0, 406 | multiLineStrings: !0, 407 | regexLiterals: !0 408 | }), ["rb"]); 409 | k(u({ 410 | keywords: w, 411 | cStyleComments: !0, 412 | regexLiterals: !0 413 | }), ["js"]); 414 | k(u({ 415 | keywords: "all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 416 | hashComments: 3, 417 | cStyleComments: !0, 418 | multilineStrings: !0, 419 | tripleQuotedStrings: !0, 420 | regexLiterals: !0 421 | }), ["coffee"]); 422 | k(x([], [ 423 | ["str", /^[\S\s]+/] 424 | ]), ["regex"]); 425 | window.prettyPrintOne = function(a, m, e) { 426 | var h = document.createElement("PRE"); 427 | h.innerHTML = a; 428 | e && D(h, e); 429 | E({ 430 | g: m, 431 | i: e, 432 | h: h 433 | }); 434 | return h.innerHTML 435 | }; 436 | window.prettyPrint = function(a) { 437 | function m() { 438 | for (var e = window.PR_SHOULD_USE_CONTINUATION ? l.now() + 250 : Infinity; p < h.length && l.now() < e; p++) { 439 | var n = h[p], 440 | k = n.className; 441 | if (k.indexOf("prettyprint") >= 0) { 442 | var k = k.match(g), 443 | f, b; 444 | if (b = !k) { 445 | b = n; 446 | for (var o = void 0, c = b.firstChild; c; c = c.nextSibling) var i = c.nodeType, 447 | o = i === 1 ? o ? b : c : i === 3 ? N.test(c.nodeValue) ? b : o : o; 448 | b = (f = o === b ? void 0 : o) && "CODE" === f.tagName 449 | } 450 | b && (k = f.className.match(g)); 451 | k && (k = k[1]); 452 | b = !1; 453 | for (o = n.parentNode; o; o = o.parentNode) if ((o.tagName === "pre" || o.tagName === "code" || o.tagName === "xmp") && o.className && o.className.indexOf("prettyprint") >= 0) { 454 | b = !0; 455 | break 456 | } 457 | b || ((b = (b = n.className.match(/\blinenums\b(?::(\d+))?/)) ? b[1] && b[1].length ? +b[1] : !0 : !1) && D(n, b), d = { 458 | g: k, 459 | h: n, 460 | i: b 461 | }, E(d)) 462 | } 463 | } 464 | p < h.length ? setTimeout(m, 250) : a && a() 465 | } 466 | for (var e = [document.getElementsByTagName("pre"), document.getElementsByTagName("code"), document.getElementsByTagName("xmp")], h = [], k = 0; k < e.length; ++k) for (var t = 0, s = e[k].length; t < s; ++t) h.push(e[k][t]); 467 | var e = q, 468 | l = Date; 469 | l.now || (l = { 470 | now: function() { 471 | return +new Date 472 | } 473 | }); 474 | var p = 0, 475 | d, g = /\blang(?:uage)?-([\w.]+)(?!\S)/; 476 | m() 477 | }; 478 | window.PR = { 479 | createSimpleLexer: x, 480 | registerLangHandler: k, 481 | sourceDecorator: u, 482 | PR_ATTRIB_NAME: "atn", 483 | PR_ATTRIB_VALUE: "atv", 484 | PR_COMMENT: "com", 485 | PR_DECLARATION: "dec", 486 | PR_KEYWORD: "kwd", 487 | PR_LITERAL: "lit", 488 | PR_NOCODE: "nocode", 489 | PR_PLAIN: "pln", 490 | PR_PUNCTUATION: "pun", 491 | PR_SOURCE: "src", 492 | PR_STRING: "str", 493 | PR_TAG: "tag", 494 | PR_TYPE: "typ" 495 | } 496 | })(); -------------------------------------------------------------------------------- /docs/html/MiddlewareManager.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | js-middleware Class: MiddlewareManager 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 64 | 65 | 66 |
67 |
68 | 69 | 70 |
71 | 72 |
73 | 74 | 75 |

Class: MiddlewareManager

76 |
77 | 78 |
79 | 80 |

81 | MiddlewareManager 82 |

83 | 84 |

Manage middlewares for an object. 85 | Middleware functions are functions that have access to the target function and it's arguments, 86 | and the target object and the next middleware function in the target function cycle. 87 | The next middleware function is commonly denoted by a variable named next.

88 |

Middleware functions can perform the following tasks:

89 |
    90 |
  • Execute any code.
  • 91 |
  • Make changes to the function's arguments.
  • 92 |
  • End the target function.
  • 93 |
  • Call the next middleware in the stack.
  • 94 |
95 |

If the current middleware function does not end the target function cycle, 96 | it must call next() to pass control to the next middleware function. Otherwise, 97 | the target function will be left hanging.

98 |

e.g.

99 |
 const walk = target => next => (...args) => {
 100 |     this.log(`walk function start.`);
 101 |     const result = next(...args);
 102 |     this.log(`walk function end.`);
 103 |     return result;
 104 |   }

Middleware object is an object that contains function's name as same as the target object's function name.

105 |

e.g.

106 |
 const Logger = {
 107 |      walk: target => next => (...args) => {
 108 |        console.log(`walk function start.`);
 109 |        const result = next(...args);
 110 |        console.log(`walk function end.`);
 111 |        return result;
 112 |      }
 113 |   }

Function's name start or end with "_" will not be able to apply middleware.

114 | 115 | 116 |
117 | 118 | 119 |
120 |
121 | 122 | 123 |
124 |
125 |

new MiddlewareManager()

126 | 127 | 128 |
129 |
130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 |
142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 |
178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 |
Example
194 | 195 |
## Basic
 196 | 
 197 | We define a Person class.
 198 | // the target object
 199 | class Person {
 200 |   // the target function
 201 |   walk(step) {
 202 |     this.step = step;
 203 |   }
 204 | 
 205 |   speak(word) {
 206 |     this.word = word;
 207 |   }
 208 | }
 209 | 
 210 | Then we define a middleware function to print log.
 211 | 
 212 | // middleware for walk function
 213 | const logger = target => next => (...args) => {
 214 |   console.log(`walk start, steps: ${args[0]}.`);
 215 |   const result = next(...args);
 216 |   console.log(`walk end.`);
 217 |   return result;
 218 | }
 219 | 
 220 | Now we apply the log function as a middleware to a Person instance.
 221 | 
 222 | // apply middleware to target object
 223 | const p = new Person();
 224 | const middlewareManager = new MiddlewareManager(p);
 225 | middlewareManager.use('walk', logger);
 226 | p.walk(3);
 227 | 
 228 | Whenever a Person instance call it's walk method, we'll see logs from the looger middleware.
 229 | 
 230 | ## Middleware object
 231 | We can also apply a middleware object to a target object.
 232 | Middleware object is an object that contains function's name as same as the target object's function name.
 233 | 
 234 | const PersonMiddleware = {
 235 |   walk: target => next => step => {
 236 |     console.log(`walk start, steps: step.`);
 237 |     const result = next(step);
 238 |     console.log(`walk end.`);
 239 |     return result;
 240 |   },
 241 |   speak: target => next => word => {
 242 |     word = 'this is a middleware trying to say: ' + word;
 243 |     return next(word);
 244 |   }
 245 | }
 246 | 
 247 | // apply middleware to target object
 248 | const p = new Person();
 249 | const middlewareManager = new MiddlewareManager(p);
 250 | middlewareManager.use(PersonMiddleware);
 251 | p.walk(3);
 252 | p.speak('hi');
 253 | 
 254 | ## middlewareMethods
 255 | In a class, function's name start or end with "_" will not be able to apply as middleware.
 256 | Or we can use `middlewareMethods` to define function names for middleware target within a class.
 257 | 
 258 | class PersonMiddleware {
 259 |   constructor() {
 260 |     // Or Define function names for middleware target.
 261 |     this.middlewareMethods = ['walk', 'speak'];
 262 |   }
 263 |   // Function's name start or end with "_" will not be able to apply as middleware.
 264 |   _getPrefix() {
 265 |     return 'Middleware log: ';
 266 |   }
 267 |   log(text) {
 268 |     console.log(this._getPrefix() + text);
 269 |   }
 270 |   walk(target) {
 271 |     return next => step => {
 272 |       this.log(`walk start, steps: step.`);
 273 |       const result = next(step);
 274 |       this.log(`walk end.`);
 275 |       return result;
 276 |     }
 277 |   }
 278 |   speak(target) {
 279 |     return next => word => {
 280 |       this.log('this is a middleware trying to say: ' + word);
 281 |       return next(word);
 282 |     }
 283 |   }
 284 | }
 285 | 
 286 | // apply middleware to target object
 287 | const p = new Person();
 288 | const middlewareManager = new MiddlewareManager(p);
 289 | middlewareManager.use(new PersonMiddleware())
 290 | p.walk(3);
 291 | p.speak('hi');
292 | 293 | 294 | 295 |
296 | 297 | 298 |
299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 |

Methods

314 | 315 |
316 | 317 |
318 |
319 |

use(methodName, middlewares)

320 | 321 | 322 |
323 |
324 | 325 | 326 |
327 |

Apply (register) middleware functions to the target function or apply (register) middleware objects. 328 | If the first argument is a middleware object, the rest arguments must be middleware objects.

329 |
330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 |
Parameters:
339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 380 | 381 | 382 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 415 | 416 | 417 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 |
NameTypeArgumentDescription
methodName 369 | 370 | 371 | string 372 | | 373 | 374 | object 375 | 376 | 377 | 378 | 379 | 383 | 384 | 385 | 386 | 387 | 388 |

String for target function name, object for a middleware object.

middlewares 404 | 405 | 406 | function 407 | | 408 | 409 | object 410 | 411 | 412 | 413 | 414 | 418 | 419 | 420 | 421 | 422 | 423 | <repeatable>
424 | 425 |

The middleware chain to be applied.

436 | 437 | 438 | 439 | 440 |
441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 |
477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 |
Returns:
491 | 492 | 493 |
494 |

this

495 |
496 | 497 | 498 | 499 |
500 |
501 | Type 502 |
503 |
504 | 505 | object 506 | 507 | 508 | 509 |
510 |
511 | 512 | 513 | 514 | 515 | 516 |
517 | 518 |
519 | 520 | 521 | 522 | 523 | 524 |
525 | 526 |
527 | 528 | 529 | 530 | 531 |

Class: MiddlewareManager

532 |
533 | 534 |
535 | 536 |

537 | MiddlewareManager 538 |

539 | 540 | 541 |
542 | 543 | 544 |
545 |
546 | 547 | 548 |
549 |
550 |

new MiddlewareManager(target, middlewareObjects)

551 | 552 | 553 |
554 |
555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 |
Parameters:
565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 603 | 604 | 605 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 635 | 636 | 637 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 |
NameTypeArgumentDescription
target 595 | 596 | 597 | object 598 | 599 | 600 | 601 | 602 | 606 | 607 | 608 | 609 | 610 | 611 |

The target object.

middlewareObjects 627 | 628 | 629 | object 630 | 631 | 632 | 633 | 634 | 638 | 639 | 640 | 641 | 642 | 643 | <repeatable>
644 | 645 |

Middleware objects.

656 | 657 | 658 | 659 | 660 |
661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 |
697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 |
Returns:
711 | 712 | 713 |
714 |

this

715 |
716 | 717 | 718 | 719 |
720 |
721 | Type 722 |
723 |
724 | 725 | object 726 | 727 | 728 | 729 |
730 |
731 | 732 | 733 | 734 | 735 | 736 |
737 | 738 | 739 |
740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 |

Methods

755 | 756 |
757 | 758 |
759 |
760 |

use(methodName, middlewares)

761 | 762 | 763 |
764 |
765 | 766 | 767 |
768 |

Apply (register) middleware functions to the target function or apply (register) middleware objects. 769 | If the first argument is a middleware object, the rest arguments must be middleware objects.

770 |
771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 |
Parameters:
780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 821 | 822 | 823 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 856 | 857 | 858 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 |
NameTypeArgumentDescription
methodName 810 | 811 | 812 | string 813 | | 814 | 815 | object 816 | 817 | 818 | 819 | 820 | 824 | 825 | 826 | 827 | 828 | 829 |

String for target function name, object for a middleware object.

middlewares 845 | 846 | 847 | function 848 | | 849 | 850 | object 851 | 852 | 853 | 854 | 855 | 859 | 860 | 861 | 862 | 863 | 864 | <repeatable>
865 | 866 |

The middleware chain to be applied.

877 | 878 | 879 | 880 | 881 |
882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 |
918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 |
Returns:
932 | 933 | 934 |
935 |

this

936 |
937 | 938 | 939 | 940 |
941 |
942 | Type 943 |
944 |
945 | 946 | object 947 | 948 | 949 | 950 |
951 |
952 | 953 | 954 | 955 | 956 | 957 |
958 | 959 |
960 | 961 | 962 | 963 | 964 | 965 |
966 | 967 |
968 | 969 | 970 | 971 | 972 |
973 |
974 | 975 |
976 | 977 | 978 |
979 | 980 |
981 | 982 | 983 |
984 |
985 | 986 | 987 | 1001 | 1002 | 1003 |
1004 | 1005 | 1006 | 1007 | Documentation generated by JSDoc 3.4.3 1008 | 1009 | on 2017-06-21 1010 | 1011 | using the DocStrap template. 1012 | 1013 |
1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1097 | 1098 | 1099 | 1100 | -------------------------------------------------------------------------------- /dist/middleware.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jsMiddleware = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o f(g(h(...args))). 29 | */ 30 | function compose() { 31 | for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) { 32 | funcs[_key] = arguments[_key]; 33 | } 34 | 35 | if (funcs.length === 0) { 36 | return function (arg) { 37 | return arg; 38 | }; 39 | } 40 | 41 | funcs = funcs.filter(function (func) { 42 | return typeof func === 'function'; 43 | }); 44 | 45 | if (funcs.length === 1) { 46 | return funcs[0]; 47 | } 48 | 49 | var last = funcs[funcs.length - 1]; 50 | var rest = funcs.slice(0, -1); 51 | return function () { 52 | return rest.reduceRight(function (composed, f) { 53 | return f(composed); 54 | }, last.apply(undefined, arguments)); 55 | }; 56 | } 57 | 58 | /** 59 | * Manage middlewares for an object. 60 | * Middleware functions are functions that have access to the target function and it's arguments, 61 | * and the target object and the next middleware function in the target function cycle. 62 | * The next middleware function is commonly denoted by a variable named next. 63 | * 64 | * Middleware functions can perform the following tasks: 65 | * - Execute any code. 66 | * - Make changes to the function's arguments. 67 | * - End the target function. 68 | * - Call the next middleware in the stack. 69 | * 70 | * If the current middleware function does not end the target function cycle, 71 | * it must call next() to pass control to the next middleware function. Otherwise, 72 | * the target function will be left hanging. 73 | * 74 | * e.g. 75 | * ``` 76 | * const walk = target => next => (...args) => { 77 | * this.log(`walk function start.`); 78 | * const result = next(...args); 79 | * this.log(`walk function end.`); 80 | * return result; 81 | * } 82 | * ``` 83 | * 84 | * Middleware object is an object that contains function's name as same as the target object's function name. 85 | * 86 | * e.g. 87 | * ``` 88 | * const Logger = { 89 | * walk: target => next => (...args) => { 90 | * console.log(`walk function start.`); 91 | * const result = next(...args); 92 | * console.log(`walk function end.`); 93 | * return result; 94 | * } 95 | * } 96 | * ``` 97 | * 98 | * Function's name start or end with "_" will not be able to apply middleware. 99 | * 100 | * @example 101 | * 102 | * ## Basic 103 | * 104 | * We define a Person class. 105 | * // the target object 106 | * class Person { 107 | * // the target function 108 | * walk(step) { 109 | * this.step = step; 110 | * } 111 | * 112 | * speak(word) { 113 | * this.word = word; 114 | * } 115 | * } 116 | * 117 | * Then we define a middleware function to print log. 118 | * 119 | * // middleware for walk function 120 | * const logger = target => next => (...args) => { 121 | * console.log(`walk start, steps: ${args[0]}.`); 122 | * const result = next(...args); 123 | * console.log(`walk end.`); 124 | * return result; 125 | * } 126 | * 127 | * Now we apply the log function as a middleware to a Person instance. 128 | * 129 | * // apply middleware to target object 130 | * const p = new Person(); 131 | * const middlewareManager = new MiddlewareManager(p); 132 | * middlewareManager.use('walk', logger); 133 | * p.walk(3); 134 | * 135 | * Whenever a Person instance call it's walk method, we'll see logs from the looger middleware. 136 | * 137 | * ## Middleware object 138 | * We can also apply a middleware object to a target object. 139 | * Middleware object is an object that contains function's name as same as the target object's function name. 140 | * 141 | * const PersonMiddleware = { 142 | * walk: target => next => step => { 143 | * console.log(`walk start, steps: step.`); 144 | * const result = next(step); 145 | * console.log(`walk end.`); 146 | * return result; 147 | * }, 148 | * speak: target => next => word => { 149 | * word = 'this is a middleware trying to say: ' + word; 150 | * return next(word); 151 | * } 152 | * } 153 | * 154 | * // apply middleware to target object 155 | * const p = new Person(); 156 | * const middlewareManager = new MiddlewareManager(p); 157 | * middlewareManager.use(PersonMiddleware); 158 | * p.walk(3); 159 | * p.speak('hi'); 160 | * 161 | * ## middlewareMethods 162 | * In a class, function's name start or end with "_" will not be able to apply as middleware. 163 | * Or we can use `middlewareMethods` to define function names for middleware target within a class. 164 | * 165 | * class PersonMiddleware { 166 | * constructor() { 167 | * // Or Define function names for middleware target. 168 | * this.middlewareMethods = ['walk', 'speak']; 169 | * } 170 | * // Function's name start or end with "_" will not be able to apply as middleware. 171 | * _getPrefix() { 172 | * return 'Middleware log: '; 173 | * } 174 | * log(text) { 175 | * console.log(this._getPrefix() + text); 176 | * } 177 | * walk(target) { 178 | * return next => step => { 179 | * this.log(`walk start, steps: step.`); 180 | * const result = next(step); 181 | * this.log(`walk end.`); 182 | * return result; 183 | * } 184 | * } 185 | * speak(target) { 186 | * return next => word => { 187 | * this.log('this is a middleware trying to say: ' + word); 188 | * return next(word); 189 | * } 190 | * } 191 | * } 192 | * 193 | * // apply middleware to target object 194 | * const p = new Person(); 195 | * const middlewareManager = new MiddlewareManager(p); 196 | * middlewareManager.use(new PersonMiddleware()) 197 | * p.walk(3); 198 | * p.speak('hi'); 199 | * 200 | */ 201 | 202 | var MiddlewareManager = exports.MiddlewareManager = function () { 203 | /** 204 | * @param {object} target The target object. 205 | * @param {...object} middlewareObjects Middleware objects. 206 | * @return {object} this 207 | */ 208 | function MiddlewareManager(target) { 209 | var _instance; 210 | 211 | _classCallCheck(this, MiddlewareManager); 212 | 213 | var instance = middlewareManagerHash.find(function (key) { 214 | return key._target === target; 215 | }); 216 | // a target can only has one MiddlewareManager instance 217 | if (instance === undefined) { 218 | this._target = target; 219 | this._methods = {}; 220 | this._methodMiddlewares = {}; 221 | middlewareManagerHash.push(this); 222 | instance = this; 223 | } 224 | 225 | for (var _len2 = arguments.length, middlewareObjects = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 226 | middlewareObjects[_key2 - 1] = arguments[_key2]; 227 | } 228 | 229 | (_instance = instance).use.apply(_instance, middlewareObjects); 230 | 231 | return instance; 232 | } 233 | 234 | // Function's name start or end with "_" will not be able to apply middleware. 235 | 236 | 237 | _createClass(MiddlewareManager, [{ 238 | key: '_methodIsValid', 239 | value: function _methodIsValid(methodName) { 240 | return !/^_+|_+$|constructor/g.test(methodName); 241 | } 242 | 243 | // Apply middleware to method 244 | 245 | }, { 246 | key: '_applyToMethod', 247 | value: function _applyToMethod(methodName) { 248 | var _this = this; 249 | 250 | if (typeof methodName === 'string' && this._methodIsValid(methodName)) { 251 | var method = this._methods[methodName] || this._target[methodName]; 252 | if (typeof method === 'function') { 253 | this._methods[methodName] = method; 254 | if (this._methodMiddlewares[methodName] === undefined) { 255 | this._methodMiddlewares[methodName] = []; 256 | } 257 | 258 | for (var _len3 = arguments.length, middlewares = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { 259 | middlewares[_key3 - 1] = arguments[_key3]; 260 | } 261 | 262 | middlewares.forEach(function (middleware) { 263 | return typeof middleware === 'function' && _this._methodMiddlewares[methodName].push(middleware(_this._target)); 264 | }); 265 | this._target[methodName] = compose.apply(undefined, _toConsumableArray(this._methodMiddlewares[methodName]))(method.bind(this._target)); 266 | } 267 | } 268 | } 269 | 270 | /** 271 | * Apply (register) middleware functions to the target function or apply (register) middleware objects. 272 | * If the first argument is a middleware object, the rest arguments must be middleware objects. 273 | * 274 | * @param {string|object} methodName String for target function name, object for a middleware object. 275 | * @param {...function|...object} middlewares The middleware chain to be applied. 276 | * @return {object} this 277 | */ 278 | 279 | }, { 280 | key: 'use', 281 | value: function use(methodName) { 282 | var _this2 = this; 283 | 284 | for (var _len4 = arguments.length, middlewares = Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) { 285 | middlewares[_key4 - 1] = arguments[_key4]; 286 | } 287 | 288 | if ((typeof methodName === 'undefined' ? 'undefined' : _typeof(methodName)) === 'object') { 289 | Array.prototype.slice.call(arguments).forEach(function (arg) { 290 | // A middleware object can specify target functions within middlewareMethods (Array). 291 | // e.g. obj.middlewareMethods = ['method1', 'method2']; 292 | // only method1 and method2 will be the target function. 293 | (typeof arg === 'undefined' ? 'undefined' : _typeof(arg)) === 'object' && (arg.middlewareMethods || (Object.keys(arg).length ? Object.keys(arg) : Object.getOwnPropertyNames(Object.getPrototypeOf(arg)))).forEach(function (key) { 294 | typeof arg[key] === 'function' && _this2._methodIsValid(key) && _this2._applyToMethod(key, arg[key].bind(arg)); 295 | }); 296 | }); 297 | } else { 298 | this._applyToMethod.apply(this, [methodName].concat(middlewares)); 299 | } 300 | 301 | return this; 302 | } 303 | }]); 304 | 305 | return MiddlewareManager; 306 | }(); 307 | 308 | if (typeof window !== 'undefined') { 309 | window['MiddlewareManager'] = MiddlewareManager; 310 | } 311 | 312 | },{}]},{},[1])(1) 313 | }); 314 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJsaWIvTWlkZGxld2FyZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBOzs7Ozs7Ozs7O1FBYWdCLE8sR0FBQSxPOzs7Ozs7QUFaaEIsSUFBSSx3QkFBd0IsRUFBNUI7O0FBRUE7Ozs7Ozs7Ozs7QUFVTyxTQUFTLE9BQVQsR0FBMkI7QUFBQSxvQ0FBUCxLQUFPO0FBQVAsU0FBTztBQUFBOztBQUNoQyxNQUFJLE1BQU0sTUFBTixLQUFpQixDQUFyQixFQUF3QjtBQUN0QixXQUFPO0FBQUEsYUFBTyxHQUFQO0FBQUEsS0FBUDtBQUNEOztBQUVELFVBQVEsTUFBTSxNQUFOLENBQWE7QUFBQSxXQUFRLE9BQU8sSUFBUCxLQUFnQixVQUF4QjtBQUFBLEdBQWIsQ0FBUjs7QUFFQSxNQUFJLE1BQU0sTUFBTixLQUFpQixDQUFyQixFQUF3QjtBQUN0QixXQUFPLE1BQU0sQ0FBTixDQUFQO0FBQ0Q7O0FBRUQsTUFBTSxPQUFPLE1BQU0sTUFBTSxNQUFOLEdBQWUsQ0FBckIsQ0FBYjtBQUNBLE1BQU0sT0FBTyxNQUFNLEtBQU4sQ0FBWSxDQUFaLEVBQWUsQ0FBQyxDQUFoQixDQUFiO0FBQ0EsU0FBTztBQUFBLFdBQWEsS0FBSyxXQUFMLENBQWlCLFVBQUMsUUFBRCxFQUFXLENBQVg7QUFBQSxhQUFpQixFQUFFLFFBQUYsQ0FBakI7QUFBQSxLQUFqQixFQUErQyxnQ0FBL0MsQ0FBYjtBQUFBLEdBQVA7QUFDRDs7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0lBK0lhLGlCLFdBQUEsaUI7QUFDWDs7Ozs7QUFLQSw2QkFBWSxNQUFaLEVBQTBDO0FBQUE7O0FBQUE7O0FBQ3hDLFFBQUksV0FBVyxzQkFBc0IsSUFBdEIsQ0FBMkIsVUFBVSxHQUFWLEVBQWU7QUFDdkQsYUFBTyxJQUFJLE9BQUosS0FBZ0IsTUFBdkI7QUFDRCxLQUZjLENBQWY7QUFHQTtBQUNBLFFBQUksYUFBYSxTQUFqQixFQUE0QjtBQUMxQixXQUFLLE9BQUwsR0FBZSxNQUFmO0FBQ0EsV0FBSyxRQUFMLEdBQWdCLEVBQWhCO0FBQ0EsV0FBSyxrQkFBTCxHQUEwQixFQUExQjtBQUNBLDRCQUFzQixJQUF0QixDQUEyQixJQUEzQjtBQUNBLGlCQUFXLElBQVg7QUFDRDs7QUFYdUMsdUNBQW5CLGlCQUFtQjtBQUFuQix1QkFBbUI7QUFBQTs7QUFZeEMsMkJBQVMsR0FBVCxrQkFBZ0IsaUJBQWhCOztBQUVBLFdBQU8sUUFBUDtBQUNEOztBQUVEOzs7OzttQ0FDZSxVLEVBQVk7QUFDekIsYUFBTyxDQUFDLHVCQUF1QixJQUF2QixDQUE0QixVQUE1QixDQUFSO0FBQ0Q7O0FBRUQ7Ozs7bUNBQ2UsVSxFQUE0QjtBQUFBOztBQUN6QyxVQUFJLE9BQU8sVUFBUCxLQUFzQixRQUF0QixJQUFrQyxLQUFLLGNBQUwsQ0FBb0IsVUFBcEIsQ0FBdEMsRUFBdUU7QUFDckUsWUFBSSxTQUFTLEtBQUssUUFBTCxDQUFjLFVBQWQsS0FBNkIsS0FBSyxPQUFMLENBQWEsVUFBYixDQUExQztBQUNBLFlBQUksT0FBTyxNQUFQLEtBQWtCLFVBQXRCLEVBQWtDO0FBQ2hDLGVBQUssUUFBTCxDQUFjLFVBQWQsSUFBNEIsTUFBNUI7QUFDQSxjQUFJLEtBQUssa0JBQUwsQ0FBd0IsVUFBeEIsTUFBd0MsU0FBNUMsRUFBdUQ7QUFDckQsaUJBQUssa0JBQUwsQ0FBd0IsVUFBeEIsSUFBc0MsRUFBdEM7QUFDRDs7QUFKK0IsNkNBSFIsV0FHUTtBQUhSLHVCQUdRO0FBQUE7O0FBS2hDLHNCQUFZLE9BQVosQ0FBb0I7QUFBQSxtQkFDbEIsT0FBTyxVQUFQLEtBQXNCLFVBQXRCLElBQW9DLE1BQUssa0JBQUwsQ0FBd0IsVUFBeEIsRUFBb0MsSUFBcEMsQ0FBeUMsV0FBVyxNQUFLLE9BQWhCLENBQXpDLENBRGxCO0FBQUEsV0FBcEI7QUFHQSxlQUFLLE9BQUwsQ0FBYSxVQUFiLElBQTJCLDRDQUFXLEtBQUssa0JBQUwsQ0FBd0IsVUFBeEIsQ0FBWCxHQUFnRCxPQUFPLElBQVAsQ0FBWSxLQUFLLE9BQWpCLENBQWhELENBQTNCO0FBQ0Q7QUFDRjtBQUNGOztBQUVEOzs7Ozs7Ozs7Ozt3QkFRSSxVLEVBQTRCO0FBQUE7O0FBQUEseUNBQWIsV0FBYTtBQUFiLG1CQUFhO0FBQUE7O0FBQzlCLFVBQUksUUFBTyxVQUFQLHlDQUFPLFVBQVAsT0FBc0IsUUFBMUIsRUFBb0M7QUFDbEMsY0FBTSxTQUFOLENBQWdCLEtBQWhCLENBQXNCLElBQXRCLENBQTJCLFNBQTNCLEVBQXNDLE9BQXRDLENBQThDLGVBQU87QUFDbkQ7QUFDQTtBQUNBO0FBQ0Esa0JBQU8sR0FBUCx5Q0FBTyxHQUFQLE9BQWUsUUFBZixJQUNBLENBQUMsSUFBSSxpQkFBSixLQUNBLE9BQU8sSUFBUCxDQUFZLEdBQVosRUFBaUIsTUFBakIsR0FBMEIsT0FBTyxJQUFQLENBQVksR0FBWixDQUExQixHQUE2QyxPQUFPLG1CQUFQLENBQTJCLE9BQU8sY0FBUCxDQUFzQixHQUF0QixDQUEzQixDQUQ3QyxDQUFELEVBRUUsT0FGRixDQUVVLGVBQU87QUFDZixtQkFBTyxJQUFJLEdBQUosQ0FBUCxLQUFvQixVQUFwQixJQUFrQyxPQUFLLGNBQUwsQ0FBb0IsR0FBcEIsQ0FBbEMsSUFBOEQsT0FBSyxjQUFMLENBQW9CLEdBQXBCLEVBQXlCLElBQUksR0FBSixFQUFTLElBQVQsQ0FBYyxHQUFkLENBQXpCLENBQTlEO0FBQ0QsV0FKRCxDQURBO0FBTUQsU0FWRDtBQVdELE9BWkQsTUFZTztBQUNMLGFBQUssY0FBTCxjQUFvQixVQUFwQixTQUFtQyxXQUFuQztBQUNEOztBQUVELGFBQU8sSUFBUDtBQUNEOzs7Ozs7QUFHSCxJQUFJLE9BQU8sTUFBUCxLQUFrQixXQUF0QixFQUFtQztBQUNqQyxTQUFPLG1CQUFQLElBQThCLGlCQUE5QjtBQUNEIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIid1c2Ugc3RyaWN0JztcbmxldCBtaWRkbGV3YXJlTWFuYWdlckhhc2ggPSBbXTtcblxuLyoqXG4gKiBDb21wb3NlcyBzaW5nbGUtYXJndW1lbnQgZnVuY3Rpb25zIGZyb20gcmlnaHQgdG8gbGVmdC4gVGhlIHJpZ2h0bW9zdFxuICogZnVuY3Rpb24gY2FuIHRha2UgbXVsdGlwbGUgYXJndW1lbnRzIGFzIGl0IHByb3ZpZGVzIHRoZSBzaWduYXR1cmUgZm9yXG4gKiB0aGUgcmVzdWx0aW5nIGNvbXBvc2l0ZSBmdW5jdGlvbi5cbiAqXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBmdW5jcyBUaGUgZnVuY3Rpb25zIHRvIGNvbXBvc2UuXG4gKiBAcmV0dXJucyB7RnVuY3Rpb259IEEgZnVuY3Rpb24gb2J0YWluZWQgYnkgY29tcG9zaW5nIHRoZSBhcmd1bWVudCBmdW5jdGlvbnNcbiAqIGZyb20gcmlnaHQgdG8gbGVmdC4gRm9yIGV4YW1wbGUsIGNvbXBvc2UoZiwgZywgaCkgaXMgaWRlbnRpY2FsIHRvIGRvaW5nXG4gKiAoLi4uYXJncykgPT4gZihnKGgoLi4uYXJncykpKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXBvc2UoLi4uZnVuY3MpIHtcbiAgaWYgKGZ1bmNzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBhcmcgPT4gYXJnO1xuICB9XG5cbiAgZnVuY3MgPSBmdW5jcy5maWx0ZXIoZnVuYyA9PiB0eXBlb2YgZnVuYyA9PT0gJ2Z1bmN0aW9uJyk7XG5cbiAgaWYgKGZ1bmNzLmxlbmd0aCA9PT0gMSkge1xuICAgIHJldHVybiBmdW5jc1swXTtcbiAgfVxuXG4gIGNvbnN0IGxhc3QgPSBmdW5jc1tmdW5jcy5sZW5ndGggLSAxXTtcbiAgY29uc3QgcmVzdCA9IGZ1bmNzLnNsaWNlKDAsIC0xKTtcbiAgcmV0dXJuICguLi5hcmdzKSA9PiByZXN0LnJlZHVjZVJpZ2h0KChjb21wb3NlZCwgZikgPT4gZihjb21wb3NlZCksIGxhc3QoLi4uYXJncykpO1xufVxuXG4vKipcbiAqIE1hbmFnZSBtaWRkbGV3YXJlcyBmb3IgYW4gb2JqZWN0LlxuICogTWlkZGxld2FyZSBmdW5jdGlvbnMgYXJlIGZ1bmN0aW9ucyB0aGF0IGhhdmUgYWNjZXNzIHRvIHRoZSB0YXJnZXQgZnVuY3Rpb24gYW5kIGl0J3MgYXJndW1lbnRzLFxuICogYW5kIHRoZSB0YXJnZXQgb2JqZWN0IGFuZCB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uIGluIHRoZSB0YXJnZXQgZnVuY3Rpb24gY3ljbGUuXG4gKiBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uIGlzIGNvbW1vbmx5IGRlbm90ZWQgYnkgYSB2YXJpYWJsZSBuYW1lZCBuZXh0LlxuICpcbiAqIE1pZGRsZXdhcmUgZnVuY3Rpb25zIGNhbiBwZXJmb3JtIHRoZSBmb2xsb3dpbmcgdGFza3M6XG4gKiAgLSBFeGVjdXRlIGFueSBjb2RlLlxuICogIC0gTWFrZSBjaGFuZ2VzIHRvIHRoZSBmdW5jdGlvbidzIGFyZ3VtZW50cy5cbiAqICAtIEVuZCB0aGUgdGFyZ2V0IGZ1bmN0aW9uLlxuICogIC0gQ2FsbCB0aGUgbmV4dCBtaWRkbGV3YXJlIGluIHRoZSBzdGFjay5cbiAqXG4gKiBJZiB0aGUgY3VycmVudCBtaWRkbGV3YXJlIGZ1bmN0aW9uIGRvZXMgbm90IGVuZCB0aGUgdGFyZ2V0IGZ1bmN0aW9uIGN5Y2xlLFxuICogaXQgbXVzdCBjYWxsIG5leHQoKSB0byBwYXNzIGNvbnRyb2wgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi4gT3RoZXJ3aXNlLFxuICogdGhlIHRhcmdldCBmdW5jdGlvbiB3aWxsIGJlIGxlZnQgaGFuZ2luZy5cbiAqXG4gKiBlLmcuXG4gKiAgYGBgXG4gKiAgY29uc3Qgd2FsayA9IHRhcmdldCA9PiBuZXh0ID0+ICguLi5hcmdzKSA9PiB7XG4gKiAgICAgdGhpcy5sb2coYHdhbGsgZnVuY3Rpb24gc3RhcnQuYCk7XG4gKiAgICAgY29uc3QgcmVzdWx0ID0gbmV4dCguLi5hcmdzKTtcbiAqICAgICB0aGlzLmxvZyhgd2FsayBmdW5jdGlvbiBlbmQuYCk7XG4gKiAgICAgcmV0dXJuIHJlc3VsdDtcbiAqICAgfVxuICogIGBgYFxuICpcbiAqIE1pZGRsZXdhcmUgb2JqZWN0IGlzIGFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIGZ1bmN0aW9uJ3MgbmFtZSBhcyBzYW1lIGFzIHRoZSB0YXJnZXQgb2JqZWN0J3MgZnVuY3Rpb24gbmFtZS5cbiAqXG4gKiBlLmcuXG4gKiAgYGBgXG4gKiAgY29uc3QgTG9nZ2VyID0ge1xuICogICAgICB3YWxrOiB0YXJnZXQgPT4gbmV4dCA9PiAoLi4uYXJncykgPT4ge1xuICogICAgICAgIGNvbnNvbGUubG9nKGB3YWxrIGZ1bmN0aW9uIHN0YXJ0LmApO1xuICogICAgICAgIGNvbnN0IHJlc3VsdCA9IG5leHQoLi4uYXJncyk7XG4gKiAgICAgICAgY29uc29sZS5sb2coYHdhbGsgZnVuY3Rpb24gZW5kLmApO1xuICogICAgICAgIHJldHVybiByZXN1bHQ7XG4gKiAgICAgIH1cbiAqICAgfVxuICogIGBgYFxuICpcbiAqIEZ1bmN0aW9uJ3MgbmFtZSBzdGFydCBvciBlbmQgd2l0aCBcIl9cIiB3aWxsIG5vdCBiZSBhYmxlIHRvIGFwcGx5IG1pZGRsZXdhcmUuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiAjIyBCYXNpY1xuICpcbiAqIFdlIGRlZmluZSBhIFBlcnNvbiBjbGFzcy5cbiAqIC8vIHRoZSB0YXJnZXQgb2JqZWN0XG4gKiBjbGFzcyBQZXJzb24ge1xuICogICAvLyB0aGUgdGFyZ2V0IGZ1bmN0aW9uXG4gKiAgIHdhbGsoc3RlcCkge1xuICogICAgIHRoaXMuc3RlcCA9IHN0ZXA7XG4gKiAgIH1cbiAqXG4gKiAgIHNwZWFrKHdvcmQpIHtcbiAqICAgICB0aGlzLndvcmQgPSB3b3JkO1xuICogICB9XG4gKiB9XG4gKlxuICogVGhlbiB3ZSBkZWZpbmUgYSBtaWRkbGV3YXJlIGZ1bmN0aW9uIHRvIHByaW50IGxvZy5cbiAqXG4gKiAvLyBtaWRkbGV3YXJlIGZvciB3YWxrIGZ1bmN0aW9uXG4gKiBjb25zdCBsb2dnZXIgPSB0YXJnZXQgPT4gbmV4dCA9PiAoLi4uYXJncykgPT4ge1xuICogICBjb25zb2xlLmxvZyhgd2FsayBzdGFydCwgc3RlcHM6ICR7YXJnc1swXX0uYCk7XG4gKiAgIGNvbnN0IHJlc3VsdCA9IG5leHQoLi4uYXJncyk7XG4gKiAgIGNvbnNvbGUubG9nKGB3YWxrIGVuZC5gKTtcbiAqICAgcmV0dXJuIHJlc3VsdDtcbiAqIH1cbiAqXG4gKiBOb3cgd2UgYXBwbHkgdGhlIGxvZyBmdW5jdGlvbiBhcyBhIG1pZGRsZXdhcmUgdG8gYSBQZXJzb24gaW5zdGFuY2UuXG4gKlxuICogLy8gYXBwbHkgbWlkZGxld2FyZSB0byB0YXJnZXQgb2JqZWN0XG4gKiBjb25zdCBwID0gbmV3IFBlcnNvbigpO1xuICogY29uc3QgbWlkZGxld2FyZU1hbmFnZXIgPSBuZXcgTWlkZGxld2FyZU1hbmFnZXIocCk7XG4gKiBtaWRkbGV3YXJlTWFuYWdlci51c2UoJ3dhbGsnLCBsb2dnZXIpO1xuICogcC53YWxrKDMpO1xuICpcbiAqIFdoZW5ldmVyIGEgUGVyc29uIGluc3RhbmNlIGNhbGwgaXQncyB3YWxrIG1ldGhvZCwgd2UnbGwgc2VlIGxvZ3MgZnJvbSB0aGUgbG9vZ2VyIG1pZGRsZXdhcmUuXG4gKlxuICogIyMgTWlkZGxld2FyZSBvYmplY3RcbiAqIFdlIGNhbiBhbHNvIGFwcGx5IGEgbWlkZGxld2FyZSBvYmplY3QgdG8gYSB0YXJnZXQgb2JqZWN0LlxuICogTWlkZGxld2FyZSBvYmplY3QgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgZnVuY3Rpb24ncyBuYW1lIGFzIHNhbWUgYXMgdGhlIHRhcmdldCBvYmplY3QncyBmdW5jdGlvbiBuYW1lLlxuICpcbiAqIGNvbnN0IFBlcnNvbk1pZGRsZXdhcmUgPSB7XG4gKiAgIHdhbGs6IHRhcmdldCA9PiBuZXh0ID0+IHN0ZXAgPT4ge1xuICogICAgIGNvbnNvbGUubG9nKGB3YWxrIHN0YXJ0LCBzdGVwczogc3RlcC5gKTtcbiAqICAgICBjb25zdCByZXN1bHQgPSBuZXh0KHN0ZXApO1xuICogICAgIGNvbnNvbGUubG9nKGB3YWxrIGVuZC5gKTtcbiAqICAgICByZXR1cm4gcmVzdWx0O1xuICogICB9LFxuICogICBzcGVhazogdGFyZ2V0ID0+IG5leHQgPT4gd29yZCA9PiB7XG4gKiAgICAgd29yZCA9ICd0aGlzIGlzIGEgbWlkZGxld2FyZSB0cnlpbmcgdG8gc2F5OiAnICsgd29yZDtcbiAqICAgICByZXR1cm4gbmV4dCh3b3JkKTtcbiAqICAgfVxuICogfVxuICpcbiAqIC8vIGFwcGx5IG1pZGRsZXdhcmUgdG8gdGFyZ2V0IG9iamVjdFxuICogY29uc3QgcCA9IG5ldyBQZXJzb24oKTtcbiAqIGNvbnN0IG1pZGRsZXdhcmVNYW5hZ2VyID0gbmV3IE1pZGRsZXdhcmVNYW5hZ2VyKHApO1xuICogbWlkZGxld2FyZU1hbmFnZXIudXNlKFBlcnNvbk1pZGRsZXdhcmUpO1xuICogcC53YWxrKDMpO1xuICogcC5zcGVhaygnaGknKTtcbiAqXG4gKiAjIyBtaWRkbGV3YXJlTWV0aG9kc1xuICogSW4gYSBjbGFzcywgZnVuY3Rpb24ncyBuYW1lIHN0YXJ0IG9yIGVuZCB3aXRoIFwiX1wiIHdpbGwgbm90IGJlIGFibGUgdG8gYXBwbHkgYXMgbWlkZGxld2FyZS5cbiAqIE9yIHdlIGNhbiB1c2UgYG1pZGRsZXdhcmVNZXRob2RzYCB0byBkZWZpbmUgZnVuY3Rpb24gbmFtZXMgZm9yIG1pZGRsZXdhcmUgdGFyZ2V0IHdpdGhpbiBhIGNsYXNzLlxuICpcbiAqIGNsYXNzIFBlcnNvbk1pZGRsZXdhcmUge1xuICogICBjb25zdHJ1Y3RvcigpIHtcbiAqICAgICAvLyBPciBEZWZpbmUgZnVuY3Rpb24gbmFtZXMgZm9yIG1pZGRsZXdhcmUgdGFyZ2V0LlxuICogICAgIHRoaXMubWlkZGxld2FyZU1ldGhvZHMgPSBbJ3dhbGsnLCAnc3BlYWsnXTtcbiAqICAgfVxuICogICAvLyBGdW5jdGlvbidzIG5hbWUgc3RhcnQgb3IgZW5kIHdpdGggXCJfXCIgd2lsbCBub3QgYmUgYWJsZSB0byBhcHBseSBhcyBtaWRkbGV3YXJlLlxuICogICBfZ2V0UHJlZml4KCkge1xuICogICAgIHJldHVybiAnTWlkZGxld2FyZSBsb2c6ICc7XG4gKiAgIH1cbiAqICAgbG9nKHRleHQpIHtcbiAqICAgICBjb25zb2xlLmxvZyh0aGlzLl9nZXRQcmVmaXgoKSArIHRleHQpO1xuICogICB9XG4gKiAgIHdhbGsodGFyZ2V0KSB7XG4gKiAgICAgcmV0dXJuIG5leHQgPT4gc3RlcCA9PiB7XG4gKiAgICAgICB0aGlzLmxvZyhgd2FsayBzdGFydCwgc3RlcHM6IHN0ZXAuYCk7XG4gKiAgICAgICBjb25zdCByZXN1bHQgPSBuZXh0KHN0ZXApO1xuICogICAgICAgdGhpcy5sb2coYHdhbGsgZW5kLmApO1xuICogICAgICAgcmV0dXJuIHJlc3VsdDtcbiAqICAgICB9XG4gKiAgIH1cbiAqICAgc3BlYWsodGFyZ2V0KSB7XG4gKiAgICAgcmV0dXJuIG5leHQgPT4gd29yZCA9PiB7XG4gKiAgICAgICB0aGlzLmxvZygndGhpcyBpcyBhIG1pZGRsZXdhcmUgdHJ5aW5nIHRvIHNheTogJyArIHdvcmQpO1xuICogICAgICAgcmV0dXJuIG5leHQod29yZCk7XG4gKiAgICAgfVxuICogICB9XG4gKiB9XG4gKlxuICogLy8gYXBwbHkgbWlkZGxld2FyZSB0byB0YXJnZXQgb2JqZWN0XG4gKiBjb25zdCBwID0gbmV3IFBlcnNvbigpO1xuICogY29uc3QgbWlkZGxld2FyZU1hbmFnZXIgPSBuZXcgTWlkZGxld2FyZU1hbmFnZXIocCk7XG4gKiBtaWRkbGV3YXJlTWFuYWdlci51c2UobmV3IFBlcnNvbk1pZGRsZXdhcmUoKSlcbiAqIHAud2FsaygzKTtcbiAqIHAuc3BlYWsoJ2hpJyk7XG4gKlxuICovXG5leHBvcnQgY2xhc3MgTWlkZGxld2FyZU1hbmFnZXIge1xuICAvKipcbiAgICogQHBhcmFtIHtvYmplY3R9IHRhcmdldCBUaGUgdGFyZ2V0IG9iamVjdC5cbiAgICogQHBhcmFtIHsuLi5vYmplY3R9IG1pZGRsZXdhcmVPYmplY3RzIE1pZGRsZXdhcmUgb2JqZWN0cy5cbiAgICogQHJldHVybiB7b2JqZWN0fSB0aGlzXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih0YXJnZXQsIC4uLm1pZGRsZXdhcmVPYmplY3RzKSB7XG4gICAgbGV0IGluc3RhbmNlID0gbWlkZGxld2FyZU1hbmFnZXJIYXNoLmZpbmQoZnVuY3Rpb24gKGtleSkge1xuICAgICAgcmV0dXJuIGtleS5fdGFyZ2V0ID09PSB0YXJnZXQ7XG4gICAgfSk7XG4gICAgLy8gYSB0YXJnZXQgY2FuIG9ubHkgaGFzIG9uZSBNaWRkbGV3YXJlTWFuYWdlciBpbnN0YW5jZVxuICAgIGlmIChpbnN0YW5jZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLl90YXJnZXQgPSB0YXJnZXQ7XG4gICAgICB0aGlzLl9tZXRob2RzID0ge307XG4gICAgICB0aGlzLl9tZXRob2RNaWRkbGV3YXJlcyA9IHt9O1xuICAgICAgbWlkZGxld2FyZU1hbmFnZXJIYXNoLnB1c2godGhpcyk7XG4gICAgICBpbnN0YW5jZSA9IHRoaXM7XG4gICAgfVxuICAgIGluc3RhbmNlLnVzZSguLi5taWRkbGV3YXJlT2JqZWN0cyk7XG5cbiAgICByZXR1cm4gaW5zdGFuY2U7XG4gIH1cblxuICAvLyBGdW5jdGlvbidzIG5hbWUgc3RhcnQgb3IgZW5kIHdpdGggXCJfXCIgd2lsbCBub3QgYmUgYWJsZSB0byBhcHBseSBtaWRkbGV3YXJlLlxuICBfbWV0aG9kSXNWYWxpZChtZXRob2ROYW1lKSB7XG4gICAgcmV0dXJuICEvXl8rfF8rJHxjb25zdHJ1Y3Rvci9nLnRlc3QobWV0aG9kTmFtZSk7XG4gIH1cblxuICAvLyBBcHBseSBtaWRkbGV3YXJlIHRvIG1ldGhvZFxuICBfYXBwbHlUb01ldGhvZChtZXRob2ROYW1lLCAuLi5taWRkbGV3YXJlcykge1xuICAgIGlmICh0eXBlb2YgbWV0aG9kTmFtZSA9PT0gJ3N0cmluZycgJiYgdGhpcy5fbWV0aG9kSXNWYWxpZChtZXRob2ROYW1lKSkge1xuICAgICAgbGV0IG1ldGhvZCA9IHRoaXMuX21ldGhvZHNbbWV0aG9kTmFtZV0gfHwgdGhpcy5fdGFyZ2V0W21ldGhvZE5hbWVdO1xuICAgICAgaWYgKHR5cGVvZiBtZXRob2QgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdGhpcy5fbWV0aG9kc1ttZXRob2ROYW1lXSA9IG1ldGhvZDtcbiAgICAgICAgaWYgKHRoaXMuX21ldGhvZE1pZGRsZXdhcmVzW21ldGhvZE5hbWVdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICB0aGlzLl9tZXRob2RNaWRkbGV3YXJlc1ttZXRob2ROYW1lXSA9IFtdO1xuICAgICAgICB9XG4gICAgICAgIG1pZGRsZXdhcmVzLmZvckVhY2gobWlkZGxld2FyZSA9PlxuICAgICAgICAgIHR5cGVvZiBtaWRkbGV3YXJlID09PSAnZnVuY3Rpb24nICYmIHRoaXMuX21ldGhvZE1pZGRsZXdhcmVzW21ldGhvZE5hbWVdLnB1c2gobWlkZGxld2FyZSh0aGlzLl90YXJnZXQpKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLl90YXJnZXRbbWV0aG9kTmFtZV0gPSBjb21wb3NlKC4uLnRoaXMuX21ldGhvZE1pZGRsZXdhcmVzW21ldGhvZE5hbWVdKShtZXRob2QuYmluZCh0aGlzLl90YXJnZXQpKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXBwbHkgKHJlZ2lzdGVyKSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byB0aGUgdGFyZ2V0IGZ1bmN0aW9uIG9yIGFwcGx5IChyZWdpc3RlcikgbWlkZGxld2FyZSBvYmplY3RzLlxuICAgKiBJZiB0aGUgZmlyc3QgYXJndW1lbnQgaXMgYSBtaWRkbGV3YXJlIG9iamVjdCwgdGhlIHJlc3QgYXJndW1lbnRzIG11c3QgYmUgbWlkZGxld2FyZSBvYmplY3RzLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IG1ldGhvZE5hbWUgU3RyaW5nIGZvciB0YXJnZXQgZnVuY3Rpb24gbmFtZSwgb2JqZWN0IGZvciBhIG1pZGRsZXdhcmUgb2JqZWN0LlxuICAgKiBAcGFyYW0gey4uLmZ1bmN0aW9ufC4uLm9iamVjdH0gbWlkZGxld2FyZXMgVGhlIG1pZGRsZXdhcmUgY2hhaW4gdG8gYmUgYXBwbGllZC5cbiAgICogQHJldHVybiB7b2JqZWN0fSB0aGlzXG4gICAqL1xuICB1c2UobWV0aG9kTmFtZSwgLi4ubWlkZGxld2FyZXMpIHtcbiAgICBpZiAodHlwZW9mIG1ldGhvZE5hbWUgPT09ICdvYmplY3QnKSB7XG4gICAgICBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpLmZvckVhY2goYXJnID0+IHtcbiAgICAgICAgLy8gQSBtaWRkbGV3YXJlIG9iamVjdCBjYW4gc3BlY2lmeSB0YXJnZXQgZnVuY3Rpb25zIHdpdGhpbiBtaWRkbGV3YXJlTWV0aG9kcyAoQXJyYXkpLlxuICAgICAgICAvLyBlLmcuIG9iai5taWRkbGV3YXJlTWV0aG9kcyA9IFsnbWV0aG9kMScsICdtZXRob2QyJ107XG4gICAgICAgIC8vIG9ubHkgbWV0aG9kMSBhbmQgbWV0aG9kMiB3aWxsIGJlIHRoZSB0YXJnZXQgZnVuY3Rpb24uXG4gICAgICAgIHR5cGVvZiBhcmcgPT09ICdvYmplY3QnICYmXG4gICAgICAgIChhcmcubWlkZGxld2FyZU1ldGhvZHMgfHxcbiAgICAgICAgKE9iamVjdC5rZXlzKGFyZykubGVuZ3RoID8gT2JqZWN0LmtleXMoYXJnKSA6IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKE9iamVjdC5nZXRQcm90b3R5cGVPZihhcmcpKSlcbiAgICAgICAgKS5mb3JFYWNoKGtleSA9PiB7XG4gICAgICAgICAgdHlwZW9mIGFyZ1trZXldID09PSAnZnVuY3Rpb24nICYmIHRoaXMuX21ldGhvZElzVmFsaWQoa2V5KSAmJiB0aGlzLl9hcHBseVRvTWV0aG9kKGtleSwgYXJnW2tleV0uYmluZChhcmcpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fYXBwbHlUb01ldGhvZChtZXRob2ROYW1lLCAuLi5taWRkbGV3YXJlcyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cblxuaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnKSB7XG4gIHdpbmRvd1snTWlkZGxld2FyZU1hbmFnZXInXSA9IE1pZGRsZXdhcmVNYW5hZ2VyO1xufVxuIl19 315 | --------------------------------------------------------------------------------