├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .hound.yml ├── .npmignore ├── .travis.yml ├── README.md ├── dist ├── ko-component-tester.js └── ko-component-tester.min.js ├── karma.conf.js ├── karma.travis.js ├── package.json ├── src └── index.js ├── test ├── $context.spec.js ├── $data.spec.js ├── .eslintrc ├── getComponentParams.spec.js ├── renderComponent.spec.js ├── renderHtml.spec.js ├── sample.spec.js ├── waitForBinding.spec.js └── waitForProperty.spec.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "profiscience", 3 | "env": { 4 | "mocha": true 5 | }, 6 | "parserOptions": { 7 | "sourceType": "script" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | coverage/ 4 | 5 | node_modules/ 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | javascript: 2 | enabled: false 3 | ignore_file: .eslintignore 4 | eslint: 5 | enabled: true 6 | 7 | fail_on_violations: true 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | .git/ 4 | .gitignore 5 | 6 | .eslintrc 7 | 8 | src/ 9 | example/ 10 | coverage/ 11 | 12 | index.html 13 | README.md 14 | test.js 15 | karma.config.* 16 | webpack.config.* 17 | 18 | node_modules/ 19 | npm-debug.log 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - stable 5 | 6 | addons: 7 | firefox: "latest" 8 | 9 | before_script: 10 | - export DISPLAY=:99.0 11 | - sh -e /etc/init.d/xvfb start 12 | 13 | after_script: 14 | - ./node_modules/coveralls/bin/coveralls.js < coverage/lcov.txt 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ko-component-tester 2 | 3 | [](https://www.npmjs.com/package/ko-component-tester) 4 |  5 | [](https://travis-ci.org/Profiscience/ko-component-tester) 6 | [](https://coveralls.io/github/Profiscience/ko-component-tester?branch=master) 7 | [](https://david-dm.org/Profiscience/ko-component-tester) 8 | [](https://david-dm.org/Profiscience/ko-component-tester#info=peerDependencies&view=table) 9 | [](http://npm-stat.com/charts.html?package=ko-component-tester&author=&from=&to=) 10 | 11 | _TDD Helpers for Knockout components and bindings_ 12 | 13 | #### Sample tests for a Knockout binding 14 | 15 | ```javascript 16 | 'use strict' 17 | 18 | const { renderHtml } = require('ko-component-tester') 19 | const { expect } = require('chai') 20 | 21 | describe ('Hello World text-binding', () => { 22 | let $el 23 | beforeEach(() => { 24 | $el = renderHtml({ 25 | template: `
`, 26 | viewModel: { greeting: 'Hello World'} 27 | }) 28 | }) 29 | it('renders', () => { 30 | expect($el).to.exist 31 | }) 32 | it('renders correct text', () => { 33 | expect($el.html()).equals('Hello World') 34 | }) 35 | }) 36 | ``` 37 | 38 | #### Sample tests for a Knockout component 39 | 40 | ```javascript 41 | 'use strict' 42 | 43 | const { renderComponent } = require('ko-component-tester') 44 | const { expect } = require('chai') 45 | 46 | describe('Hello World Component' , () => { 47 | let $el 48 | beforeEach(() => { 49 | $el = renderComponent({ 50 | template: ``, 51 | viewModel: function() { this.greeting = 'Hello World' } 52 | }) 53 | }) 54 | afterEach(() => { 55 | $el.dispose() 56 | }) 57 | it('renders', () => { 58 | expect($el).to.exist 59 | }) 60 | it('renders correct content', () => { 61 | expect($el.html()).contains('Hello World') 62 | }) 63 | }) 64 | ``` 65 | 66 | #### Sample Login test 67 | 68 | ```javascript 69 | 'use strict' 70 | 71 | const ko = require('knockout') 72 | const { expect } = require('chai') 73 | const sinon = require('sinon') 74 | const { renderComponent } = require('../src') 75 | 76 | class LoginComponent { 77 | constructor() { 78 | this.username = ko.observable() 79 | this.password = ko.observable() 80 | } 81 | submit() {} 82 | } 83 | 84 | describe('sample login component' , () => { 85 | let $el 86 | 87 | before(() => { 88 | $el = renderComponent({ 89 | viewModel: LoginComponent, 90 | template: ` 91 | ` 96 | }) 97 | }) 98 | 99 | after(() => { 100 | $el.dispose() 101 | }) 102 | 103 | it('renders correctly', () => { 104 | expect($el).to.exist 105 | expect($el.find('form'), 'contains a form').to.exist 106 | expect($el.find('input[name="user"]', 'contains a username field')).to.exist 107 | expect($el.find('input[name="pass"]', 'contains a password field')).to.exist 108 | expect($el.find('input[type="submit"]', 'contains a submit button')).to.exist 109 | }) 110 | 111 | it('updates the viewmodel when a value is changed', () => { 112 | $el.find('input[name=user]').simulate('change', 'john') 113 | expect($el.$data().username()).equals('john') 114 | }) 115 | 116 | it('can submit the form', () => { 117 | const submitSpy = sinon.spy($el.$data().submit) 118 | $el.find('input[name=user]').simulate('change', 'john') 119 | $el.find('input[name=pass]').simulate('change', 'p455w0rd') 120 | $el.find('input[type="submit"]').simulate('click') 121 | 122 | expect(submitSpy).to.be.called 123 | }) 124 | }) 125 | 126 | ``` 127 | 128 | #### renderHtml(options) 129 | 130 | returns a jQuery element containing the rendered html output 131 | 132 | - `options.template` - a string of html to be rendered 133 | - `options.viewModel` - an object, function, or class 134 | 135 | Example with viewModel function: 136 | 137 | ```javascript 138 | const options = { 139 | template: ``, 140 | viewModel: function() { this.greeting = 'Hello Text Binding' } 141 | } 142 | const $el = renderHtml(options) 143 | ``` 144 | 145 | Example with viewModel class: 146 | 147 | ```javascript 148 | const options = { 149 | template: ``, 150 | viewModel: class ViewModel { 151 | constructor() { 152 | this.greeting = 'Hello Text Binding' 153 | } 154 | } 155 | } 156 | const $el = renderHtml(options) 157 | ``` 158 | 159 | Example with viewModel object: 160 | 161 | ```javascript 162 | const options = { 163 | template: ``, 164 | viewModel: { greeting: 'Hello Text Binding' } 165 | } 166 | const $el = renderHtml(options) 167 | ``` 168 | [See spec for more examples of renderHtml().](test/renderHtml.spec.js) 169 | 170 | 171 | #### renderComponent(component, params, bindingContext) 172 | 173 | returns a jQuery element containing the rendered html output 174 | 175 | - `component.template` - a string of html to be rendered 176 | - `component.viewModel` - a function, class, or instance 177 | - `params` - optional params to be passed into the viewModel's constructor 178 | - `bindingContext` - optional bindingContext to inject (useful for stubbing `$parent` or `$index`) 179 | 180 | Example with viewModel function: 181 | 182 | ```javascript 183 | const component = { 184 | template: ``, 185 | viewModel: function() { this.greeting = 'Hello Text Binding' } 186 | } 187 | const $el = renderComponent(component) 188 | // $el.dispose() 189 | ``` 190 | 191 | Example with viewModel class: 192 | 193 | ```javascript 194 | const component = { 195 | template: ``, 196 | viewModel: class ViewModel { 197 | constructor(params) { 198 | this.greeting = params.greeting 199 | } 200 | } 201 | } 202 | const params = { 203 | greeting: 'Hello Text Binding' 204 | } 205 | const $el = renderComponent(component, params) 206 | // $el.dispose() 207 | ``` 208 | 209 | Example with viewModel instance: 210 | 211 | ```javascript 212 | class ViewModel { 213 | constructor(params) { 214 | this.greeting = params.greeting 215 | } 216 | } 217 | const component = { 218 | template: ``, 219 | viewModel: { instance: new ViewModel(params) } 220 | } 221 | const $el = renderComponent(component) 222 | // $el.dispose() 223 | ``` 224 | 225 | [See spec for more examples of renderComponent().](test/renderComponent.spec.js) 226 | 227 | #### $el.getComponentParams() 228 | 229 | [see spec for examples](test/getComponentParams.spec.js) 230 | 231 | #### $el.waitForBinding() 232 | 233 | [see spec for examples](test/waitForBinding.spec.js) 234 | 235 | #### $el.waitForProperty() 236 | 237 | [see spec for examples](test/waitForProperty.spec.js) 238 | 239 | #### $el.simulate(event, value) 240 | 241 | - `event` - the event to simulate, eg `'click', or 'change'` 242 | - `value` - if provided this value will be assigned. It's handy for assigning a value to a textbox and triggering a `change` event like this. 243 | 244 | ```javascript 245 | // simulate changing the value of a textbox 246 | $input.simulate('change', 'new value') 247 | // simulate clicking a button 248 | $submit.simulate('click') 249 | ``` 250 | 251 | #### Attribution 252 | 253 | https://github.com/jeremija/kotest 254 | -------------------------------------------------------------------------------- /dist/ko-component-tester.min.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root,factory){if(typeof exports==="object"&&typeof module==="object")module.exports=factory(require("knockout"),require("jquery"));else if(typeof define==="function"&&define.amd)define(["knockout","jquery"],factory);else if(typeof exports==="object")exports["ko-component-tester"]=factory(require("knockout"),require("jquery"));else root["ko-component-tester"]=factory(root["ko"],root["jQuery"])})(this,function(__WEBPACK_EXTERNAL_MODULE_1__,__WEBPACK_EXTERNAL_MODULE_2__){return function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={exports:{},id:moduleId,loaded:false};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.loaded=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.p="";return __webpack_require__(0)}([function(module,exports,__webpack_require__){"use strict";function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function")}}function _toArray(arr){return Array.isArray(arr)?arr:Array.from(arr)}var ko=__webpack_require__(1);var $=__webpack_require__(2);var _=__webpack_require__(3);var simulateEvent=__webpack_require__(5);$.fn.simulate=function(eventName,value){if(value){this.val(value)}if(value)this.val(value);var target=this.get(0);simulateEvent.simulate(target,eventName,value);ko.tasks.runEarly()};$.fn.waitForBinding=function(bindingName){var _this=this,_arguments=arguments;if(!ko.bindingHandlers[bindingName])throw new Error("binding does not exist: "+bindingName);var binding=ko.bindingHandlers[bindingName].init?ko.bindingHandlers[bindingName].init.bind(ko.bindingHandlers[bindingName].init):function(){};return new Promise(function(resolve){var $el=_this;ko.bindingHandlers[bindingName].init=function(el){if($el.get(0)===el){binding.apply(undefined,_arguments);ko.tasks.schedule(function(){ko.bindingHandlers[bindingName].init=binding;resolve($el)})}else{binding.apply(undefined,_arguments)}}})};$.fn.waitForProperty=function(key,val){var timeout=arguments.length>2&&arguments[2]!==undefined?arguments[2]:2e3;var prop=access(key.split("."),this.$data());return new Promise(function(resolve,reject){if(matches(prop())){return resolve(prop())}var timeoutId=setTimeout(function(){killMe.dispose();reject("Timed out waiting for property "+key)},timeout);var killMe=prop.subscribe(function(v){if(!matches(v)){return}clearTimeout(timeoutId);killMe.dispose();ko.tasks.runEarly();resolve(v)})});function access(_ref,obj){var _ref2=_toArray(_ref),k=_ref2[0],ks=_ref2.slice(1);var p=obj[k];return ks.length>0?access(ks,p):p}function matches(v){return typeof v!=="undefined"&&(typeof val==="undefined"||(val instanceof RegExp?val.test(v):v===val))}};$.fn.$data=function(){return this.children().length>0?ko.dataFor(this.children().get(0)):ko.dataFor(ko.virtualElements.firstChild(this.get(0)))};$.fn.$context=function(){return this.children().length>0?ko.contextFor(this.children().get(0)):ko.contextFor(ko.virtualElements.firstChild(this.get(0)))};ko.components.loaders.unshift({loadComponent:function loadComponent(name,component,done){if(!component.viewModel){var ViewModel=function ViewModel(params){_classCallCheck(this,ViewModel);ko.utils.extend(this,params)};component.viewModel=ViewModel}done(null)},loadViewModel:function loadViewModel(name,config,done){if(typeof config==="function"){done(function(params){var viewModel=new config(params);viewModel._calledWith=params;return viewModel},done)}else if(config.createViewModel){done(function(params,componentInfo){var viewModel=config.createViewModel(params,componentInfo);viewModel._calledWith=params;return viewModel},done)}else{done(null)}}});$.fn.getComponentParams=function(){return ko.contextFor(ko.virtualElements.firstChild(this.get(0))).$component._calledWith};function renderComponent(component){var _params=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};var _bindingCtx=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};var _component=ko.observable("_SUT");var $el=$('');component.synchronous=true;if(ko.components.isRegistered("_SUT")){ko.components.unregister("_SUT")}ko.components.register("_SUT",component);ko.bindingHandlers._setContext={init:function init(el,valueAccessor,allBindings,viewModel,bindingContext){_.merge(bindingContext,_bindingCtx)}};$("body").html($el);ko.applyBindings(_.merge({_component:_component,_params:_params}),$el.get(0));ko.tasks.runEarly();ko.components.unregister("_SUT");ko.bindingHandlers._setContext=void 0;$el.dispose=function(){ko.components.register("_NULL",{template:""});_component("_NULL");ko.tasks.runEarly();ko.components.unregister("_NULL");$el.remove()};return $el}function renderHtml(_ref3){var template=_ref3.template,_ref3$viewModel=_ref3.viewModel,viewModel=_ref3$viewModel===undefined?{}:_ref3$viewModel;var $el=void 0;try{$el=$(template)}catch(e){$el=$("").text(template)}$("body").html($el);if(typeof viewModel==="function"){ko.applyBindings(new viewModel,$el.get(0))}else{ko.applyBindings(viewModel,$el.get(0))}ko.tasks.runEarly();return $el}module.exports={renderComponent:renderComponent,renderHtml:renderHtml}},function(module,exports){module.exports=__WEBPACK_EXTERNAL_MODULE_1__},function(module,exports){module.exports=__WEBPACK_EXTERNAL_MODULE_2__},function(module,exports,__webpack_require__){var __WEBPACK_AMD_DEFINE_RESULT__;(function(global,module){(function(){var undefined;var VERSION="4.17.4";var LARGE_ARRAY_SIZE=200;var CORE_ERROR_TEXT="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",FUNC_ERROR_TEXT="Expected a function";var HASH_UNDEFINED="__lodash_hash_undefined__";var MAX_MEMOIZE_SIZE=500;var PLACEHOLDER="__lodash_placeholder__";var CLONE_DEEP_FLAG=1,CLONE_FLAT_FLAG=2,CLONE_SYMBOLS_FLAG=4;var COMPARE_PARTIAL_FLAG=1,COMPARE_UNORDERED_FLAG=2;var WRAP_BIND_FLAG=1,WRAP_BIND_KEY_FLAG=2,WRAP_CURRY_BOUND_FLAG=4,WRAP_CURRY_FLAG=8,WRAP_CURRY_RIGHT_FLAG=16,WRAP_PARTIAL_FLAG=32,WRAP_PARTIAL_RIGHT_FLAG=64,WRAP_ARY_FLAG=128,WRAP_REARG_FLAG=256,WRAP_FLIP_FLAG=512;var DEFAULT_TRUNC_LENGTH=30,DEFAULT_TRUNC_OMISSION="...";var HOT_COUNT=800,HOT_SPAN=16;var LAZY_FILTER_FLAG=1,LAZY_MAP_FLAG=2,LAZY_WHILE_FLAG=3;var INFINITY=1/0,MAX_SAFE_INTEGER=9007199254740991,MAX_INTEGER=1.7976931348623157e308,NAN=0/0;var MAX_ARRAY_LENGTH=4294967295,MAX_ARRAY_INDEX=MAX_ARRAY_LENGTH-1,HALF_MAX_ARRAY_LENGTH=MAX_ARRAY_LENGTH>>>1;var wrapFlags=[["ary",WRAP_ARY_FLAG],["bind",WRAP_BIND_FLAG],["bindKey",WRAP_BIND_KEY_FLAG],["curry",WRAP_CURRY_FLAG],["curryRight",WRAP_CURRY_RIGHT_FLAG],["flip",WRAP_FLIP_FLAG],["partial",WRAP_PARTIAL_FLAG],["partialRight",WRAP_PARTIAL_RIGHT_FLAG],["rearg",WRAP_REARG_FLAG]];var argsTag="[object Arguments]",arrayTag="[object Array]",asyncTag="[object AsyncFunction]",boolTag="[object Boolean]",dateTag="[object Date]",domExcTag="[object DOMException]",errorTag="[object Error]",funcTag="[object Function]",genTag="[object GeneratorFunction]",mapTag="[object Map]",numberTag="[object Number]",nullTag="[object Null]",objectTag="[object Object]",promiseTag="[object Promise]",proxyTag="[object Proxy]",regexpTag="[object RegExp]",setTag="[object Set]",stringTag="[object String]",symbolTag="[object Symbol]",undefinedTag="[object Undefined]",weakMapTag="[object WeakMap]",weakSetTag="[object WeakSet]";var arrayBufferTag="[object ArrayBuffer]",dataViewTag="[object DataView]",float32Tag="[object Float32Array]",float64Tag="[object Float64Array]",int8Tag="[object Int8Array]",int16Tag="[object Int16Array]",int32Tag="[object Int32Array]",uint8Tag="[object Uint8Array]",uint8ClampedTag="[object Uint8ClampedArray]",uint16Tag="[object Uint16Array]",uint32Tag="[object Uint32Array]";var reEmptyStringLeading=/\b__p \+= '';/g,reEmptyStringMiddle=/\b(__p \+=) '' \+/g,reEmptyStringTrailing=/(__e\(.*?\)|\b__t\)) \+\n'';/g;var reEscapedHtml=/&(?:amp|lt|gt|quot|#39);/g,reUnescapedHtml=/[&<>"']/g,reHasEscapedHtml=RegExp(reEscapedHtml.source),reHasUnescapedHtml=RegExp(reUnescapedHtml.source);var reEscape=/<%-([\s\S]+?)%>/g,reEvaluate=/<%([\s\S]+?)%>/g,reInterpolate=/<%=([\s\S]+?)%>/g;var reIsDeepProp=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,reIsPlainProp=/^\w*$/,reLeadingDot=/^\./,rePropName=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;var reRegExpChar=/[\\^$.*+?()[\]{}|]/g,reHasRegExpChar=RegExp(reRegExpChar.source);var reTrim=/^\s+|\s+$/g,reTrimStart=/^\s+/,reTrimEnd=/\s+$/;var reWrapComment=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,reWrapDetails=/\{\n\/\* \[wrapped with (.+)\] \*/,reSplitDetails=/,? & /;var reAsciiWord=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;var reEscapeChar=/\\(\\)?/g;var reEsTemplate=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;var reFlags=/\w*$/;var reIsBadHex=/^[-+]0x[0-9a-f]+$/i;var reIsBinary=/^0b[01]+$/i;var reIsHostCtor=/^\[object .+?Constructor\]$/;var reIsOctal=/^0o[0-7]+$/i;var reIsUint=/^(?:0|[1-9]\d*)$/;var reLatin=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;var reNoMatch=/($^)/;var reUnescapedString=/['\n\r\u2028\u2029\\]/g;var rsAstralRange="\\ud800-\\udfff",rsComboMarksRange="\\u0300-\\u036f",reComboHalfMarksRange="\\ufe20-\\ufe2f",rsComboSymbolsRange="\\u20d0-\\u20ff",rsComboRange=rsComboMarksRange+reComboHalfMarksRange+rsComboSymbolsRange,rsDingbatRange="\\u2700-\\u27bf",rsLowerRange="a-z\\xdf-\\xf6\\xf8-\\xff",rsMathOpRange="\\xac\\xb1\\xd7\\xf7",rsNonCharRange="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",rsPunctuationRange="\\u2000-\\u206f",rsSpaceRange=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",rsUpperRange="A-Z\\xc0-\\xd6\\xd8-\\xde",rsVarRange="\\ufe0e\\ufe0f",rsBreakRange=rsMathOpRange+rsNonCharRange+rsPunctuationRange+rsSpaceRange;var rsApos="['’]",rsAstral="["+rsAstralRange+"]",rsBreak="["+rsBreakRange+"]",rsCombo="["+rsComboRange+"]",rsDigits="\\d+",rsDingbat="["+rsDingbatRange+"]",rsLower="["+rsLowerRange+"]",rsMisc="[^"+rsAstralRange+rsBreakRange+rsDigits+rsDingbatRange+rsLowerRange+rsUpperRange+"]",rsFitz="\\ud83c[\\udffb-\\udfff]",rsModifier="(?:"+rsCombo+"|"+rsFitz+")",rsNonAstral="[^"+rsAstralRange+"]",rsRegional="(?:\\ud83c[\\udde6-\\uddff]){2}",rsSurrPair="[\\ud800-\\udbff][\\udc00-\\udfff]",rsUpper="["+rsUpperRange+"]",rsZWJ="\\u200d";var rsMiscLower="(?:"+rsLower+"|"+rsMisc+")",rsMiscUpper="(?:"+rsUpper+"|"+rsMisc+")",rsOptContrLower="(?:"+rsApos+"(?:d|ll|m|re|s|t|ve))?",rsOptContrUpper="(?:"+rsApos+"(?:D|LL|M|RE|S|T|VE))?",reOptMod=rsModifier+"?",rsOptVar="["+rsVarRange+"]?",rsOptJoin="(?:"+rsZWJ+"(?:"+[rsNonAstral,rsRegional,rsSurrPair].join("|")+")"+rsOptVar+reOptMod+")*",rsOrdLower="\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)",rsOrdUpper="\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)",rsSeq=rsOptVar+reOptMod+rsOptJoin,rsEmoji="(?:"+[rsDingbat,rsRegional,rsSurrPair].join("|")+")"+rsSeq,rsSymbol="(?:"+[rsNonAstral+rsCombo+"?",rsCombo,rsRegional,rsSurrPair,rsAstral].join("|")+")";var reApos=RegExp(rsApos,"g");var reComboMark=RegExp(rsCombo,"g");var reUnicode=RegExp(rsFitz+"(?="+rsFitz+")|"+rsSymbol+rsSeq,"g");var reUnicodeWord=RegExp([rsUpper+"?"+rsLower+"+"+rsOptContrLower+"(?="+[rsBreak,rsUpper,"$"].join("|")+")",rsMiscUpper+"+"+rsOptContrUpper+"(?="+[rsBreak,rsUpper+rsMiscLower,"$"].join("|")+")",rsUpper+"?"+rsMiscLower+"+"+rsOptContrLower,rsUpper+"+"+rsOptContrUpper,rsOrdUpper,rsOrdLower,rsDigits,rsEmoji].join("|"),"g");var reHasUnicode=RegExp("["+rsZWJ+rsAstralRange+rsComboRange+rsVarRange+"]");var reHasUnicodeWord=/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;var contextProps=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"];var templateCounter=-1;var typedArrayTags={};typedArrayTags[float32Tag]=typedArrayTags[float64Tag]=typedArrayTags[int8Tag]=typedArrayTags[int16Tag]=typedArrayTags[int32Tag]=typedArrayTags[uint8Tag]=typedArrayTags[uint8ClampedTag]=typedArrayTags[uint16Tag]=typedArrayTags[uint32Tag]=true;typedArrayTags[argsTag]=typedArrayTags[arrayTag]=typedArrayTags[arrayBufferTag]=typedArrayTags[boolTag]=typedArrayTags[dataViewTag]=typedArrayTags[dateTag]=typedArrayTags[errorTag]=typedArrayTags[funcTag]=typedArrayTags[mapTag]=typedArrayTags[numberTag]=typedArrayTags[objectTag]=typedArrayTags[regexpTag]=typedArrayTags[setTag]=typedArrayTags[stringTag]=typedArrayTags[weakMapTag]=false;var cloneableTags={};cloneableTags[argsTag]=cloneableTags[arrayTag]=cloneableTags[arrayBufferTag]=cloneableTags[dataViewTag]=cloneableTags[boolTag]=cloneableTags[dateTag]=cloneableTags[float32Tag]=cloneableTags[float64Tag]=cloneableTags[int8Tag]=cloneableTags[int16Tag]=cloneableTags[int32Tag]=cloneableTags[mapTag]=cloneableTags[numberTag]=cloneableTags[objectTag]=cloneableTags[regexpTag]=cloneableTags[setTag]=cloneableTags[stringTag]=cloneableTags[symbolTag]=cloneableTags[uint8Tag]=cloneableTags[uint8ClampedTag]=cloneableTags[uint16Tag]=cloneableTags[uint32Tag]=true;cloneableTags[errorTag]=cloneableTags[funcTag]=cloneableTags[weakMapTag]=false;var deburredLetters={"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss","Ā":"A","Ă":"A","Ą":"A","ā":"a","ă":"a","ą":"a","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","ć":"c","ĉ":"c","ċ":"c","č":"c","Ď":"D","Đ":"D","ď":"d","đ":"d","Ē":"E","Ĕ":"E","Ė":"E","Ę":"E","Ě":"E","ē":"e","ĕ":"e","ė":"e","ę":"e","ě":"e","Ĝ":"G","Ğ":"G","Ġ":"G","Ģ":"G","ĝ":"g","ğ":"g","ġ":"g","ģ":"g","Ĥ":"H","Ħ":"H","ĥ":"h","ħ":"h","Ĩ":"I","Ī":"I","Ĭ":"I","Į":"I","İ":"I","ĩ":"i","ī":"i","ĭ":"i","į":"i","ı":"i","Ĵ":"J","ĵ":"j","Ķ":"K","ķ":"k","ĸ":"k","Ĺ":"L","Ļ":"L","Ľ":"L","Ŀ":"L","Ł":"L","ĺ":"l","ļ":"l","ľ":"l","ŀ":"l","ł":"l","Ń":"N","Ņ":"N","Ň":"N","Ŋ":"N","ń":"n","ņ":"n","ň":"n","ŋ":"n","Ō":"O","Ŏ":"O","Ő":"O","ō":"o","ŏ":"o","ő":"o","Ŕ":"R","Ŗ":"R","Ř":"R","ŕ":"r","ŗ":"r","ř":"r","Ś":"S","Ŝ":"S","Ş":"S","Š":"S","ś":"s","ŝ":"s","ş":"s","š":"s","Ţ":"T","Ť":"T","Ŧ":"T","ţ":"t","ť":"t","ŧ":"t","Ũ":"U","Ū":"U","Ŭ":"U","Ů":"U","Ű":"U","Ų":"U","ũ":"u","ū":"u","ŭ":"u","ů":"u","ű":"u","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","Ż":"Z","Ž":"Z","ź":"z","ż":"z","ž":"z","IJ":"IJ","ij":"ij","Œ":"Oe","œ":"oe","ʼn":"'n","ſ":"s"};var htmlEscapes={"&":"&","<":"<",">":">",'"':""","'":"'"};var htmlUnescapes={"&":"&","<":"<",">":">",""":'"',"'":"'"};var stringEscapes={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"};var freeParseFloat=parseFloat,freeParseInt=parseInt;var freeGlobal=typeof global=="object"&&global&&global.Object===Object&&global;var freeSelf=typeof self=="object"&&self&&self.Object===Object&&self;var root=freeGlobal||freeSelf||Function("return this")();var freeExports=typeof exports=="object"&&exports&&!exports.nodeType&&exports;var freeModule=freeExports&&typeof module=="object"&&module&&!module.nodeType&&module;var moduleExports=freeModule&&freeModule.exports===freeExports;var freeProcess=moduleExports&&freeGlobal.process;var nodeUtil=function(){try{return freeProcess&&freeProcess.binding&&freeProcess.binding("util")}catch(e){}}();var nodeIsArrayBuffer=nodeUtil&&nodeUtil.isArrayBuffer,nodeIsDate=nodeUtil&&nodeUtil.isDate,nodeIsMap=nodeUtil&&nodeUtil.isMap,nodeIsRegExp=nodeUtil&&nodeUtil.isRegExp,nodeIsSet=nodeUtil&&nodeUtil.isSet,nodeIsTypedArray=nodeUtil&&nodeUtil.isTypedArray;function addMapEntry(map,pair){map.set(pair[0],pair[1]);return map}function addSetEntry(set,value){set.add(value);return set}function apply(func,thisArg,args){switch(args.length){case 0:return func.call(thisArg);case 1:return func.call(thisArg,args[0]);case 2:return func.call(thisArg,args[0],args[1]);case 3:return func.call(thisArg,args[0],args[1],args[2])}return func.apply(thisArg,args)}function arrayAggregator(array,setter,iteratee,accumulator){var index=-1,length=array==null?0:array.length;while(++index