diff --git a/.gitignore b/.gitignore index d9b10266..c3129de4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules -Examples/bower_components +./Examples/bower_components .directory .codio .settings diff --git a/Examples/bower.json b/Examples/bower.json index 0a49b7c6..af2abeea 100644 --- a/Examples/bower.json +++ b/Examples/bower.json @@ -9,7 +9,15 @@ "license": "MIT", "ignore": [], "dependencies": { - "yjs": "../", - "y-webrtc": "~0.6.4" + "yjs": "~0.7.6", + "y-array": "~0.7.5", + "y-map": "~0.7.2", + "y-memory": "~0.7.0", + "y-richtext": "~0.7.5", + "y-webrtc": "~0.7.1", + "y-websockets-client": "~0.7.10", + "y-text": "~0.7.1", + "y-indexeddb": "~0.7.1", + "quill": "~0.20.1" } } diff --git a/Examples/bower_components/quill/.bower.json b/Examples/bower_components/quill/.bower.json new file mode 100644 index 00000000..2d9e222c --- /dev/null +++ b/Examples/bower_components/quill/.bower.json @@ -0,0 +1,35 @@ +{ + "name": "quill", + "version": "0.20.1", + "homepage": "http://quilljs.com", + "authors": [ + "Jason Chen " + ], + "contributors": [ + "Byron Milligan ", + "Keegan Poppen " + ], + "description": "Cross browser rich text editor", + "main": "dist/quill.js", + "license": "BSD", + "ignore": [ + "**/.*", + "config", + "examples", + "src", + "test", + "Gruntfile.coffee", + "index.js", + "package.json" + ], + "_release": "0.20.1", + "_resolution": { + "type": "version", + "tag": "v0.20.1", + "commit": "07b7f54dfe8997e1c8fe180be6f0817693215c48" + }, + "_source": "git://github.com/quilljs/quill.git", + "_target": "~0.20.1", + "_originalSource": "quill", + "_direct": true +} \ No newline at end of file diff --git a/Examples/bower_components/quill/LICENSE b/Examples/bower_components/quill/LICENSE new file mode 100644 index 00000000..707030ff --- /dev/null +++ b/Examples/bower_components/quill/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2014, Jason Chen +Copyright (c) 2013, salesforce.com +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Examples/bower_components/quill/README.md b/Examples/bower_components/quill/README.md new file mode 100644 index 00000000..69c91fea --- /dev/null +++ b/Examples/bower_components/quill/README.md @@ -0,0 +1,136 @@ +# [Quill Rich Text Editor](http://quilljs.com/) [![Build Status](https://travis-ci.org/quilljs/quill.svg?branch=master)](http://travis-ci.org/quilljs/quill) + +[![Webdriver Test Status](https://saucelabs.com/browser-matrix/quill-master.svg)](https://saucelabs.com/u/quill) + +Quill is a modern rich text editor built for compatibility and extensibility. It was created by [Jason Chen](https://twitter.com/jhchen) and [Byron Milligan](https://twitter.com/byronmilligan) and open sourced by [Salesforce.com](http://www.salesforce.com). + +To get started, check out the [Quill Github Page](http://quilljs.com/) or jump straight into the [demo](http://quilljs.com/examples/). + +## Quickstart + +Instantiate a new Quill object with a css selector for the div that should become the editor. + +```html + +
+ + +
+ + +
+
Hello World!
+
+ + + + + + +``` + + +## Downloading Quill + +There are a number of ways to download the latest or versioned copy of Quill. + +- npm: `npm install quill` +- bower: `bower install quill` +- tar: https://github.com/quilljs/quill/releases + +### CDN + +```html + + +``` + + +## Local Development + +Quill's source is in [Coffeescript](http://coffeescript.org/) and utilizes [Browserify](http://browserify.org/) to organize its files. + +### Installation + + npm install -g grunt-cli + npm install + +### Building + + grunt dist - compile and browserify + grunt server - starts a local server that will build and serve assets on the fly + +### Examples + +With the local server (`grunt server`) running you can try out some minimal examples on: + +- [localhost:9000/examples/index.html](http://localhost:9000/examples/index.html) +- [localhost:9000/examples/advanced.html](http://localhost:9000/examples/advanced.html) + +Quill [releases](https://github.com/quilljs/quill/releases) also contain these examples as built static files you can try without needing to run the local development server. + +### Testing + + grunt test:unit - runs javascript test suite with Chrome + grunt test:e2e - runs end to end tests with Webdriver + Chrome + grunt test:coverage - run tests measuring coverage with Chrome + +Tests are run by [Karma](http://karma-runner.github.io/) and [Protractor](https://github.com/angular/protractor) using [Jasmine](http://jasmine.github.io/). Check out `Gruntfile.coffee` and `config/grunt/` for more testing options. + + +## Contributing + +### Community + +Get help or stay up to date. + +- Follow [@quilljs](https://twitter.com/quilljs) on Twitter +- Ask questions on [Stack Overflow](http://stackoverflow.com/questions/tagged/quill) (tag with quill) +- If a private channel is required, you may also email support@quilljs.com + +### Bug Reports + +Search through [Github Issues](https://github.com/quilljs/quill/issues) to see if the bug has already been reported. If so, please comment with any additional information about the bug. + +For new issues, create a new issue and tag with the appropriate browser tag. Include as much detail as possible such as: + +- Detailed description of faulty behavior +- Affected platforms +- Steps for reproduction +- Failing test case + +The more details you provide, the more likely we or someone else will be able to find and fix the bug. + +### Feature Requests + +We welcome feature requests. Please make sure they are within scope of Quill's goals and submit them in [Github Issues](https://github.com/quilljs/quill/issues) tagged with the 'feature' tag. The more complete and compelling the request, the more likely it will be implemented. Garnering community support will help as well! + +### Pull Requests + +1. Please check to make sure your plans fall within Quill's scope (likely through Github Issues). +2. Fork Quill +3. Branch off of the 'develop' branch. +4. Implement your changes. +5. Submit a Pull Request. + +Pull requests will not be accepted without adhering to the following: + +1. Conform to existing [coding styles](docs/style-guide.md). +2. New functionality are accompanied by tests. +3. Serve a single atomic purpose (add one feature or fix one bug) +4. Introduce only changes that further the PR's singular purpose (ex. do not tweak an unrelated config along with adding your feature). + +**Important:** By issuing a Pull Request you agree to allow the project owners to license your work under the terms of the [License](https://github.com/quilljs/quill/blob/master/LICENSE). + + +## Thanks + +[Swift](https://github.com/theycallmeswift), for providing the npm package name. If you're looking for his blogging engine see [v0.1.5-1](https://www.npmjs.org/package/quill/0.1.5-1). + + +## License + +BSD 3-clause diff --git a/Examples/bower_components/quill/bower.json b/Examples/bower_components/quill/bower.json new file mode 100644 index 00000000..23fb2786 --- /dev/null +++ b/Examples/bower_components/quill/bower.json @@ -0,0 +1,23 @@ +{ + "name": "quill", + "version": "0.20.1", + "homepage": "http://quilljs.com", + "authors": ["Jason Chen "], + "contributors": [ + "Byron Milligan ", + "Keegan Poppen " + ], + "description": "Cross browser rich text editor", + "main": "dist/quill.js", + "license": "BSD", + "ignore": [ + "**/.*", + "config", + "examples", + "src", + "test", + "Gruntfile.coffee", + "index.js", + "package.json" + ] +} diff --git a/Examples/bower_components/quill/dist/quill.base.css b/Examples/bower_components/quill/dist/quill.base.css new file mode 100644 index 00000000..50db399f --- /dev/null +++ b/Examples/bower_components/quill/dist/quill.base.css @@ -0,0 +1,194 @@ +/*! Quill Editor v0.20.1 + * https://quilljs.com/ + * Copyright (c) 2014, Jason Chen + * Copyright (c) 2013, salesforce.com + */ +.ql-image-tooltip { + padding: 10px; + width: 300px; +} +.ql-image-tooltip:after { + clear: both; + content: ""; + display: table; +} +.ql-image-tooltip a { + border: 1px solid #000; + box-sizing: border-box; + display: inline-block; + float: left; + padding: 5px; + text-align: center; + width: 50%; +} +.ql-image-tooltip img { + bottom: 0; + left: 0; + margin: auto; + max-height: 100%; + max-width: 100%; + position: absolute; + right: 0; + top: 0; +} +.ql-image-tooltip .input { + box-sizing: border-box; + width: 100%; +} +.ql-image-tooltip .preview { + margin: 10px 0px; + position: relative; + border: 1px dashed #000; + height: 200px; +} +.ql-image-tooltip .preview span { + display: inline-block; + position: absolute; + text-align: center; + top: 40%; + width: 100%; +} +.ql-link-tooltip { + padding: 5px 10px; +} +.ql-link-tooltip input.input { + width: 170px; +} +.ql-link-tooltip input.input, +.ql-link-tooltip a.done { + display: none; +} +.ql-link-tooltip a.change { + margin-right: 4px; +} +.ql-link-tooltip.editing input.input, +.ql-link-tooltip.editing a.done { + display: inline-block; +} +.ql-link-tooltip.editing a.url, +.ql-link-tooltip.editing a.change, +.ql-link-tooltip.editing a.remove { + display: none; +} +.ql-multi-cursor { + position: absolute; + left: 0; + top: 0; + z-index: 1000; +} +.ql-multi-cursor .cursor { + margin-left: -1px; + position: absolute; +} +.ql-multi-cursor .cursor-flag { + bottom: 100%; + position: absolute; + white-space: nowrap; +} +.ql-multi-cursor .cursor-name { + display: inline-block; + color: #fff; + padding: 2px 8px; +} +.ql-multi-cursor .cursor-caret { + height: 100%; + position: absolute; + width: 2px; +} +.ql-multi-cursor .cursor.hidden .cursor-flag { + display: none; +} +.ql-multi-cursor .cursor.top .cursor-flag { + bottom: auto; + top: 100%; +} +.ql-multi-cursor .cursor.right .cursor-flag { + right: -2px; +} +.ql-paste-manager { + left: -100000px; + position: absolute; + top: 50%; +} +.ql-toolbar { + box-sizing: border-box; +} +.ql-tooltip { + background-color: #fff; + border: 1px solid #000; + box-sizing: border-box; + position: absolute; + top: 0px; + white-space: nowrap; + z-index: 2000; +} +.ql-tooltip a { + cursor: pointer; + text-decoration: none; +} +.ql-container { + box-sizing: border-box; + cursor: text; + font-family: Helvetica, 'Arial', sans-serif; + font-size: 13px; + height: 100%; + line-height: 1.42; + margin: 0px; + overflow-x: hidden; + overflow-y: auto; + padding: 12px 15px; + position: relative; +} +.ql-editor { + box-sizing: border-box; + min-height: 100%; + outline: none; + tab-size: 4; + white-space: pre-wrap; +} +.ql-editor div { + margin: 0; + padding: 0; +} +.ql-editor a { + text-decoration: underline; +} +.ql-editor b { + font-weight: bold; +} +.ql-editor i { + font-style: italic; +} +.ql-editor s { + text-decoration: line-through; +} +.ql-editor u { + text-decoration: underline; +} +.ql-editor a, +.ql-editor b, +.ql-editor i, +.ql-editor s, +.ql-editor u, +.ql-editor span { + background-color: inherit; +} +.ql-editor img { + max-width: 100%; +} +.ql-editor blockquote, +.ql-editor ol, +.ql-editor ul { + margin: 0 0 0 2em; + padding: 0; +} +.ql-editor ol { + list-style-type: decimal; +} +.ql-editor ul { + list-style-type: disc; +} +.ql-editor.ql-ie-9 br, +.ql-editor.ql-ie-10 br { + display: none; +} diff --git a/Examples/bower_components/quill/dist/quill.js b/Examples/bower_components/quill/dist/quill.js new file mode 100644 index 00000000..aad0a3b1 --- /dev/null +++ b/Examples/bower_components/quill/dist/quill.js @@ -0,0 +1,10749 @@ +/*! Quill Editor v0.20.1 + * https://quilljs.com/ + * Copyright (c) 2014, Jason Chen + * Copyright (c) 2013, salesforce.com + */ +(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.Quill = 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 + * Build: `lodash modern include="difference,intersection,last,all,each,find,invoke,map,reduce,partition,bind,defer,partial,clone,extend,defaults,omit,values,isElement,isEqual,isFunction,isNumber,isObject,isString,uniqueId" --development --output .build/lodash.js` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +;(function() { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '3.9.3'; + + /** Used to compose bitmasks for wrapper metadata. */ + var BIND_FLAG = 1, + BIND_KEY_FLAG = 2, + CURRY_BOUND_FLAG = 4, + CURRY_FLAG = 8, + CURRY_RIGHT_FLAG = 16, + PARTIAL_FLAG = 32, + PARTIAL_RIGHT_FLAG = 64, + ARY_FLAG = 128, + REARG_FLAG = 256; + + /** Used to detect when a function becomes hot. */ + var HOT_COUNT = 150, + HOT_SPAN = 16; + + /** Used as the `TypeError` message for "Functions" methods. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + weakMapTag = '[object WeakMap]'; + + var arrayBufferTag = '[object ArrayBuffer]', + 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]'; + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; + + /** + * Used to match `RegExp` [special characters](http://www.regular-expressions.info/characters.html#special). + * In addition to special characters the forward slash is escaped to allow for + * easier `eval` use and `Function` compilation. + */ + var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, + reHasRegExpChars = RegExp(reRegExpChars.source); + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect host constructors (Safari > 5). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^\d+$/; + + /** Used to identify `toStringTag` values of typed arrays. */ + 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[dateTag] = typedArrayTags[errorTag] = + typedArrayTags[funcTag] = typedArrayTags[mapTag] = + typedArrayTags[numberTag] = typedArrayTags[objectTag] = + typedArrayTags[regexpTag] = typedArrayTags[setTag] = + typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = + cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = + cloneableTags[dateTag] = cloneableTags[float32Tag] = + cloneableTags[float64Tag] = cloneableTags[int8Tag] = + cloneableTags[int16Tag] = cloneableTags[int32Tag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[stringTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[mapTag] = cloneableTags[setTag] = + cloneableTags[weakMapTag] = false; + + /** Used to determine if values are of the language type `Object`. */ + var objectTypes = { + 'function': true, + 'object': true + }; + + /** Detect free variable `exports`. */ + var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global; + + /** Detect free variable `self`. */ + var freeSelf = objectTypes[typeof self] && self && self.Object && self; + + /** Detect free variable `window`. */ + var freeWindow = objectTypes[typeof window] && window && window.Object && window; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; + + /** + * Used as a reference to the global object. + * + * The `this` value is used if it's the global object to avoid Greasemonkey's + * restricted `window` object, otherwise the `window` object is used. + */ + var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this; + + /*--------------------------------------------------------------------------*/ + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to search. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.indexOf` without support for binary searches. + * + * @private + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + if (value !== value) { + return indexOfNaN(array, fromIndex); + } + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.isFunction` without support for environments + * with incorrect `typeof` results. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + */ + function baseIsFunction(value) { + // Avoid a Chakra JIT bug in compatibility modes of IE 11. + // See https://github.com/jashkenas/underscore/issues/1621 for more details. + return typeof value == 'function' || false; + } + + /** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + if (typeof value == 'string') { + return value; + } + return value == null ? '' : (value + ''); + } + + /** + * Gets the index at which the first occurrence of `NaN` is found in `array`. + * + * @private + * @param {Array} array The array to search. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched `NaN`, else `-1`. + */ + function indexOfNaN(array, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 0 : -1); + + while ((fromRight ? index-- : ++index < length)) { + var other = array[index]; + if (other !== other) { + return index; + } + } + return -1; + } + + /** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ + function isObjectLike(value) { + return !!value && typeof value == 'object'; + } + + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + if (array[index] === placeholder) { + array[index] = PLACEHOLDER; + result[++resIndex] = index; + } + } + return result; + } + + /*--------------------------------------------------------------------------*/ + + /** Used for native method references. */ + var objectProto = Object.prototype; + + /** Used to detect DOM support. */ + var document = (document = root.window) ? document.document : null; + + /** Used to resolve the decompiled source of functions. */ + var fnToString = Function.prototype.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * of values. + */ + var objToString = objectProto.toString; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + escapeRegExp(fnToString.call(hasOwnProperty)) + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** Native method references. */ + var ArrayBuffer = getNative(root, 'ArrayBuffer'), + bufferSlice = getNative(ArrayBuffer && new ArrayBuffer(0), 'slice'), + floor = Math.floor, + getPrototypeOf = getNative(Object, 'getPrototypeOf'), + Set = getNative(root, 'Set'), + Uint8Array = getNative(root, 'Uint8Array'), + WeakMap = getNative(root, 'WeakMap'); + + /** Used to clone array buffers. */ + var Float64Array = (function() { + // Safari 5 errors when using an array buffer to initialize a typed array + // where the array buffer's `byteLength` is not a multiple of the typed + // array's `BYTES_PER_ELEMENT`. + try { + var func = getNative(root, 'Float64Array'), + result = new func(new ArrayBuffer(10), 0, 1) && func; + } catch(e) {} + return result || null; + }()); + + /* Native method references for those with the same name as other `lodash` methods. */ + var nativeCreate = getNative(Object, 'create'), + nativeIsArray = getNative(Array, 'isArray'), + nativeKeys = getNative(Object, 'keys'), + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = getNative(Date, 'now'); + + /** Used as references for `-Infinity` and `Infinity`. */ + var POSITIVE_INFINITY = Number.POSITIVE_INFINITY; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + + /** Used as the size, in bytes, of each `Float64Array` element. */ + var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0; + + /** + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) + * of an array-like value. + */ + var MAX_SAFE_INTEGER = 9007199254740991; + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap; + + /** Used to lookup unminified function names. */ + var realNames = {}; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable implicit chaining. + * Methods that operate on and return arrays, collections, and functions can + * be chained together. Methods that return a boolean or single value will + * automatically end the chain returning the unwrapped value. Explicit chaining + * may be enabled using `_.chain`. The execution of chained methods is lazy, + * that is, execution is deferred until `_#value` is implicitly or explicitly + * called. + * + * Lazy evaluation allows several methods to support shortcut fusion. Shortcut + * fusion is an optimization that merges iteratees to avoid creating intermediate + * arrays and reduce the number of iteratee executions. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers have `Array` and `String` methods. + * + * The wrapper `Array` methods are: + * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, + * `splice`, and `unshift` + * + * The wrapper `String` methods are: + * `replace` and `split` + * + * The wrapper methods that support shortcut fusion are: + * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, + * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, + * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`, + * and `where` + * + * The chainable wrapper methods are: + * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, + * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, + * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, + * `difference`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `fill`, + * `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, `forEach`, + * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`, + * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`, + * `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, + * `memoize`, `merge`, `method`, `methodOf`, `mixin`, `negate`, `omit`, `once`, + * `pairs`, `partial`, `partialRight`, `partition`, `pick`, `plant`, `pluck`, + * `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`, `rearg`, + * `reject`, `remove`, `rest`, `restParam`, `reverse`, `set`, `shuffle`, + * `slice`, `sort`, `sortBy`, `sortByAll`, `sortByOrder`, `splice`, `spread`, + * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`, + * `thru`, `times`, `toArray`, `toPlainObject`, `transform`, `union`, `uniq`, + * `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, `where`, `without`, + * `wrap`, `xor`, `zip`, `zipObject`, `zipWith` + * + * The wrapper methods that are **not** chainable by default are: + * `add`, `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`, + * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, + * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `get`, + * `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, `inRange`, `isArguments`, + * `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, + * `isFinite` `isFunction`, `isMatch`, `isNative`, `isNaN`, `isNull`, `isNumber`, + * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, + * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `lt`, `lte`, + * `max`, `min`, `noConflict`, `noop`, `now`, `pad`, `padLeft`, `padRight`, + * `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, + * `runInContext`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, + * `sortedLastIndex`, `startCase`, `startsWith`, `sum`, `template`, `trim`, + * `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, `value`, and `words` + * + * The wrapper method `sample` will return a wrapped value when `n` is provided, + * otherwise an unwrapped value is returned. + * + * @name _ + * @constructor + * @category Chain + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var wrapped = _([1, 2, 3]); + * + * // returns an unwrapped value + * wrapped.reduce(function(total, n) { + * return total + n; + * }); + * // => 6 + * + * // returns a wrapped value + * var squares = wrapped.map(function(n) { + * return n * n; + * }); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash() { + // No operation performed. + } + + /** + * The function whose prototype all chaining wrappers inherit from. + * + * @private + */ + function baseLodash() { + // No operation performed. + } + + /** + * An object environment feature flags. + * + * @static + * @memberOf _ + * @type Object + */ + var support = lodash.support = {}; + + (function(x) { + var Ctor = function() { this.x = x; }, + object = { '0': x, 'length': x }, + props = []; + + Ctor.prototype = { 'valueOf': x, 'y': x }; + for (var key in new Ctor) { props.push(key); } + + /** + * Detect if the DOM is supported. + * + * @memberOf _.support + * @type boolean + */ + try { + support.dom = document.createDocumentFragment().nodeType === 11; + } catch(e) { + support.dom = false; + } + }(1, 0)); + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.__wrapped__ = value; + this.__actions__ = null; + this.__dir__ = 1; + this.__dropCount__ = 0; + this.__filtered__ = false; + this.__iteratees__ = null; + this.__takeCount__ = POSITIVE_INFINITY; + this.__views__ = null; + } + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates a cache object to store unique values. + * + * @private + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var length = values ? values.length : 0; + + this.data = { 'hash': nativeCreate(null), 'set': new Set }; + while (length--) { + this.push(values[length]); + } + } + + /** + * Checks if `value` is in `cache` mimicking the return signature of + * `_.indexOf` by returning `0` if the value is found, else `-1`. + * + * @private + * @param {Object} cache The cache to search. + * @param {*} value The value to search for. + * @returns {number} Returns `0` if `value` is found, else `-1`. + */ + function cacheIndexOf(cache, value) { + var data = cache.data, + result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value]; + + return result ? 0 : -1; + } + + /** + * Adds `value` to the cache. + * + * @private + * @name push + * @memberOf SetCache + * @param {*} value The value to cache. + */ + function cachePush(value) { + var data = this.data; + if (typeof value == 'string' || isObject(value)) { + data.set.add(value); + } else { + data.hash[value] = true; + } + } + + /*------------------------------------------------------------------------*/ + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function arrayCopy(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * A specialized version of `_.forEach` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + + /** + * A specialized version of `_.map` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * A specialized version of `_.reduce` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the first element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initFromArray) { + var index = -1, + length = array.length; + + if (initFromArray && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Used by `_.defaults` to customize its `_.assign` use. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @returns {*} Returns the value to assign to the destination object. + */ + function assignDefaults(objectValue, sourceValue) { + return objectValue === undefined ? sourceValue : objectValue; + } + + /** + * A specialized version of `_.assign` for customizing assigned values without + * support for argument juggling, multiple sources, and `this` binding `customizer` + * functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + */ + function assignWith(object, source, customizer) { + var index = -1, + props = keys(source), + length = props.length; + + while (++index < length) { + var key = props[index], + value = object[key], + result = customizer(value, source[key], key, object, source); + + if ((result === result ? (result !== value) : (value === value)) || + (value === undefined && !(key in object))) { + object[key] = result; + } + } + return object; + } + + /** + * The base implementation of `_.assign` without support for argument juggling, + * multiple sources, and `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssign(object, source) { + return source == null + ? object + : baseCopy(source, keys(source), object); + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property names to copy. + * @param {Object} [object={}] The object to copy properties to. + * @returns {Object} Returns `object`. + */ + function baseCopy(source, props, object) { + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + object[key] = source[key]; + } + return object; + } + + /** + * The base implementation of `_.callback` which supports specifying the + * number of arguments to provide to `func`. + * + * @private + * @param {*} [func=_.identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ + function baseCallback(func, thisArg, argCount) { + var type = typeof func; + if (type == 'function') { + return thisArg === undefined + ? func + : bindCallback(func, thisArg, argCount); + } + if (func == null) { + return identity; + } + if (type == 'object') { + return baseMatches(func); + } + return thisArg === undefined + ? property(func) + : baseMatchesProperty(func, thisArg); + } + + /** + * The base implementation of `_.clone` without support for argument juggling + * and `this` binding `customizer` functions. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The object `value` belongs to. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates clones with source counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { + var result; + if (customizer) { + result = object ? customizer(value, key, object) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return arrayCopy(value, result); + } + } else { + var tag = objToString.call(value), + isFunc = tag == funcTag; + + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = initCloneObject(isFunc ? {} : value); + if (!isDeep) { + return baseAssign(result, value); + } + } else { + return cloneableTags[tag] + ? initCloneByTag(value, tag, isDeep) + : (object ? value : {}); + } + } + // Check for circular references and return corresponding clone. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == value) { + return stackB[length]; + } + } + // Add the source value to the stack of traversed objects and associate it with its clone. + stackA.push(value); + stackB.push(result); + + // Recursively populate clone (susceptible to call stack limits). + (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { + result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); + }); + return result; + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function object() {} + return function(prototype) { + if (isObject(prototype)) { + object.prototype = prototype; + var result = new object; + object.prototype = null; + } + return result || {}; + }; + }()); + + /** + * The base implementation of `_.delay` and `_.defer` which accepts an index + * of where to slice the arguments to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Object} args The arguments provide to `func`. + * @returns {number} Returns the timer id. + */ + function baseDelay(func, wait, args) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { func.apply(undefined, args); }, wait); + } + + /** + * The base implementation of `_.difference` which accepts a single array + * of values to exclude. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values) { + var length = array ? array.length : 0, + result = []; + + if (!length) { + return result; + } + var index = -1, + indexOf = getIndexOf(), + isCommon = indexOf == baseIndexOf, + cache = (isCommon && values.length >= 200) ? createCache(values) : null, + valuesLength = values.length; + + if (cache) { + indexOf = cacheIndexOf; + isCommon = false; + values = cache; + } + outer: + while (++index < length) { + var value = array[index]; + + if (isCommon && value === value) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === value) { + continue outer; + } + } + result.push(value); + } + else if (indexOf(values, value, 0) < 0) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.forEach` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object|string} Returns `collection`. + */ + var baseEach = createBaseEach(baseForOwn); + + /** + * The base implementation of `_.every` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } + + /** + * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, + * without support for callback shorthands and `this` binding, which iterates + * over `collection` using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} collection The collection to search. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @param {boolean} [retKey] Specify returning the key of the found element + * instead of the element itself. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFind(collection, predicate, eachFunc, retKey) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = retKey ? key : value; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with added support for restricting + * flattening and specifying the start index. + * + * @private + * @param {Array} array The array to flatten. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, isDeep, isStrict) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + if (isObjectLike(value) && isArrayLike(value) && + (isStrict || isArray(value) || isArguments(value))) { + if (isDeep) { + // Recursively flatten arrays (susceptible to call stack limits). + value = baseFlatten(value, isDeep, isStrict); + } + var valIndex = -1, + valLength = value.length; + + while (++valIndex < valLength) { + result[++resIndex] = value[valIndex]; + } + } else if (!isStrict) { + result[++resIndex] = value; + } + } + return result; + } + + /** + * The base implementation of `baseForIn` and `baseForOwn` which iterates + * over `object` properties returned by `keysFunc` invoking `iteratee` for + * each property. Iteratee functions may exit iteration early by explicitly + * returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * The base implementation of `_.forIn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForIn(object, iteratee) { + return baseFor(object, iteratee, keysIn); + } + + /** + * The base implementation of `_.forOwn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return baseFor(object, iteratee, keys); + } + + /** + * The base implementation of `get` without support for string paths + * and default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path of the property to get. + * @param {string} [pathKey] The key representation of path. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path, pathKey) { + if (object == null) { + return; + } + if (pathKey !== undefined && pathKey in toObject(object)) { + path = [pathKey]; + } + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[path[index++]]; + } + return (index && index == length) ? object : undefined; + } + + /** + * The base implementation of `_.isEqual` without support for `this` binding + * `customizer` functions. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); + } + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing objects. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA=[]] Tracks traversed `value` objects. + * @param {Array} [stackB=[]] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = arrayTag, + othTag = arrayTag; + + if (!objIsArr) { + objTag = objToString.call(object); + if (objTag == argsTag) { + objTag = objectTag; + } else if (objTag != objectTag) { + objIsArr = isTypedArray(object); + } + } + if (!othIsArr) { + othTag = objToString.call(other); + if (othTag == argsTag) { + othTag = objectTag; + } else if (othTag != objectTag) { + othIsArr = isTypedArray(other); + } + } + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && !(objIsArr || objIsObj)) { + return equalByTag(object, other, objTag); + } + if (!isLoose) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB); + } + } + if (!isSameTag) { + return false; + } + // Assume cyclic values are equal. + // For more information on detecting circular references see https://es5.github.io/#JO. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == object) { + return stackB[length] == other; + } + } + // Add `object` and `other` to the stack of traversed objects. + stackA.push(object); + stackB.push(other); + + var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB); + + stackA.pop(); + stackB.pop(); + + return result; + } + + /** + * The base implementation of `_.isMatch` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} matchData The propery names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparing objects. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = toObject(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var result = customizer ? customizer(objValue, srcValue, key) : undefined; + if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) { + return false; + } + } + } + return true; + } + + /** + * The base implementation of `_.map` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; + } + + /** + * The base implementation of `_.matches` which does not clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + var key = matchData[0][0], + value = matchData[0][1]; + + return function(object) { + if (object == null) { + return false; + } + return object[key] === value && (value !== undefined || (key in toObject(object))); + }; + } + return function(object) { + return baseIsMatch(object, matchData); + }; + } + + /** + * The base implementation of `_.matchesProperty` which does not clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to compare. + * @returns {Function} Returns the new function. + */ + function baseMatchesProperty(path, srcValue) { + var isArr = isArray(path), + isCommon = isKey(path) && isStrictComparable(srcValue), + pathKey = (path + ''); + + path = toPath(path); + return function(object) { + if (object == null) { + return false; + } + var key = pathKey; + object = toObject(object); + if ((isArr || !isCommon) && !(key in object)) { + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + if (object == null) { + return false; + } + key = last(path); + object = toObject(object); + } + return object[key] === srcValue + ? (srcValue !== undefined || (key in object)) + : baseIsEqual(srcValue, object[key], undefined, true); + }; + } + + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new function. + */ + function basePropertyDeep(path) { + var pathKey = (path + ''); + path = toPath(path); + return function(object) { + return baseGet(object, path, pathKey); + }; + } + + /** + * The base implementation of `_.reduce` and `_.reduceRight` without support + * for callback shorthands and `this` binding, which iterates over `collection` + * using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initFromCollection Specify using the first or last element + * of `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initFromCollection + ? (initFromCollection = false, value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; + } + + /** + * The base implementation of `setData` without support for hot loop detection. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap ? identity : function(func, data) { + metaMap.set(func, data); + return func; + }; + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + start = start == null ? 0 : (+start || 0); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (end === undefined || end > length) ? length : (+end || 0); + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + var index = -1, + length = props.length, + result = Array(length); + + while (++index < length) { + result[index] = object[props[index]]; + } + return result; + } + + /** + * Performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function binaryIndex(array, value, retHighest) { + var low = 0, + high = array ? array.length : low; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return binaryIndexBy(array, value, identity, retHighest); + } + + /** + * This function is like `binaryIndex` except that it invokes `iteratee` for + * `value` and each element of `array` to compute their sort ranking. The + * iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The function invoked per iteration. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function binaryIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array ? array.length : 0, + valIsNaN = value !== value, + valIsNull = value === null, + valIsUndef = value === undefined; + + while (low < high) { + var mid = floor((low + high) / 2), + computed = iteratee(array[mid]), + isDef = computed !== undefined, + isReflexive = computed === computed; + + if (valIsNaN) { + var setLow = isReflexive || retHighest; + } else if (valIsNull) { + setLow = isReflexive && isDef && (retHighest || computed != null); + } else if (valIsUndef) { + setLow = isReflexive && (retHighest || isDef); + } else if (computed == null) { + setLow = false; + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + + /** + * A specialized version of `baseCallback` which only supports `this` binding + * and specifying the number of arguments to provide to `func`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ + function bindCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + if (thisArg === undefined) { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + case 5: return function(value, other, key, object, source) { + return func.call(thisArg, value, other, key, object, source); + }; + } + return function() { + return func.apply(thisArg, arguments); + }; + } + + /** + * Creates a clone of the given array buffer. + * + * @private + * @param {ArrayBuffer} buffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function bufferClone(buffer) { + return bufferSlice.call(buffer, 0); + } + if (!bufferSlice) { + // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`. + bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) { + var byteLength = buffer.byteLength, + floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0, + offset = floatLength * FLOAT64_BYTES_PER_ELEMENT, + result = new ArrayBuffer(byteLength); + + if (floatLength) { + var view = new Float64Array(result, 0, floatLength); + view.set(new Float64Array(buffer, 0, floatLength)); + } + if (byteLength != offset) { + view = new Uint8Array(result, offset); + view.set(new Uint8Array(buffer, offset)); + } + return result; + }; + } + + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array|Object} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders) { + var holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), + leftIndex = -1, + leftLength = partials.length, + result = Array(argsLength + leftLength); + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + while (argsLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } + + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array|Object} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders) { + var holdersIndex = -1, + holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), + rightIndex = -1, + rightLength = partials.length, + result = Array(argsLength + rightLength); + + while (++argsIndex < argsLength) { + result[argsIndex] = args[argsIndex]; + } + var offset = argsIndex; + while (++rightIndex < rightLength) { + result[offset + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + result[offset + holders[holdersIndex]] = args[argsIndex++]; + } + return result; + } + + /** + * Creates a function that aggregates a collection, creating an accumulator + * object composed from the results of running each element in the collection + * through an iteratee. + * + * **Note:** This function is used to create `_.countBy`, `_.groupBy`, `_.indexBy`, + * and `_.partition`. + * + * @private + * @param {Function} setter The function to set keys and values of the accumulator object. + * @param {Function} [initializer] The function to initialize the accumulator object. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function(collection, iteratee, thisArg) { + var result = initializer ? initializer() : {}; + iteratee = getCallback(iteratee, thisArg, 3); + + if (isArray(collection)) { + var index = -1, + length = collection.length; + + while (++index < length) { + var value = collection[index]; + setter(result, value, iteratee(value, index, collection), collection); + } + } else { + baseEach(collection, function(value, key, collection) { + setter(result, value, iteratee(value, key, collection), collection); + }); + } + return result; + }; + } + + /** + * Creates a function that assigns properties of source object(s) to a given + * destination object. + * + * **Note:** This function is used to create `_.assign`, `_.defaults`, and `_.merge`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return restParam(function(object, sources) { + var index = -1, + length = object == null ? 0 : sources.length, + customizer = length > 2 ? sources[length - 2] : undefined, + guard = length > 2 ? sources[2] : undefined, + thisArg = length > 1 ? sources[length - 1] : undefined; + + if (typeof customizer == 'function') { + customizer = bindCallback(customizer, thisArg, 5); + length -= 2; + } else { + customizer = typeof thisArg == 'function' ? thisArg : undefined; + length -= (customizer ? 1 : 0); + } + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, customizer); + } + } + return object; + }); + } + + /** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + var length = collection ? getLength(collection) : 0; + if (!isLength(length)) { + return eachFunc(collection, iteratee); + } + var index = fromRight ? length : -1, + iterable = toObject(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; + } + + /** + * Creates a base function for `_.forIn` or `_.forInRight`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var iterable = toObject(object), + props = keysFunc(object), + length = props.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length)) { + var key = props[index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } + + /** + * Creates a function that wraps `func` and invokes it with the `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new bound function. + */ + function createBindWrapper(func, thisArg) { + var Ctor = createCtorWrapper(func); + + function wrapper() { + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(thisArg, arguments); + } + return wrapper; + } + + /** + * Creates a `Set` cache object to optimize linear searches of large arrays. + * + * @private + * @param {Array} [values] The values to cache. + * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. + */ + var createCache = !(nativeCreate && Set) ? constant(null) : function(values) { + return new SetCache(values); + }; + + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtorWrapper(Ctor) { + return function() { + // Use a `switch` statement to work with class constructors. + // See https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-function-objects-call-thisargument-argumentslist + // for more details. + var args = arguments; + switch (args.length) { + case 0: return new Ctor; + case 1: return new Ctor(args[0]); + case 2: return new Ctor(args[0], args[1]); + case 3: return new Ctor(args[0], args[1], args[2]); + case 4: return new Ctor(args[0], args[1], args[2], args[3]); + case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); + } + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, args); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } + + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new find function. + */ + function createFind(eachFunc, fromRight) { + return function(collection, predicate, thisArg) { + predicate = getCallback(predicate, thisArg, 3); + if (isArray(collection)) { + var index = baseFindIndex(collection, predicate, fromRight); + return index > -1 ? collection[index] : undefined; + } + return baseFind(collection, predicate, eachFunc); + }; + } + + /** + * Creates a function for `_.forEach` or `_.forEachRight`. + * + * @private + * @param {Function} arrayFunc The function to iterate over an array. + * @param {Function} eachFunc The function to iterate over a collection. + * @returns {Function} Returns the new each function. + */ + function createForEach(arrayFunc, eachFunc) { + return function(collection, iteratee, thisArg) { + return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) + ? arrayFunc(collection, iteratee) + : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); + }; + } + + /** + * Creates a `_.partial` or `_.partialRight` function. + * + * @private + * @param {boolean} flag The partial bit flag. + * @returns {Function} Returns the new partial function. + */ + function createPartial(flag) { + var partialFunc = restParam(function(func, partials) { + var holders = replaceHolders(partials, partialFunc.placeholder); + return createWrapper(func, flag, null, partials, holders); + }); + return partialFunc; + } + + /** + * Creates a function for `_.reduce` or `_.reduceRight`. + * + * @private + * @param {Function} arrayFunc The function to iterate over an array. + * @param {Function} eachFunc The function to iterate over a collection. + * @returns {Function} Returns the new each function. + */ + function createReduce(arrayFunc, eachFunc) { + return function(collection, iteratee, accumulator, thisArg) { + var initFromArray = arguments.length < 3; + return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) + ? arrayFunc(collection, iteratee, accumulator, initFromArray) + : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); + }; + } + + /** + * Creates a function that wraps `func` and invokes it with optional `this` + * binding of, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & ARY_FLAG, + isBind = bitmask & BIND_FLAG, + isBindKey = bitmask & BIND_KEY_FLAG, + isCurry = bitmask & CURRY_FLAG, + isCurryBound = bitmask & CURRY_BOUND_FLAG, + isCurryRight = bitmask & CURRY_RIGHT_FLAG, + Ctor = isBindKey ? null : createCtorWrapper(func); + + function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it to other functions. + var length = arguments.length, + index = length, + args = Array(length); + + while (index--) { + args[index] = arguments[index]; + } + if (partials) { + args = composeArgs(args, partials, holders); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight); + } + if (isCurry || isCurryRight) { + var placeholder = wrapper.placeholder, + argsHolders = replaceHolders(args, placeholder); + + length -= argsHolders.length; + if (length < arity) { + var newArgPos = argPos ? arrayCopy(argPos) : null, + newArity = nativeMax(arity - length, 0), + newsHolders = isCurry ? argsHolders : null, + newHoldersRight = isCurry ? null : argsHolders, + newPartials = isCurry ? args : null, + newPartialsRight = isCurry ? null : args; + + bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); + + if (!isCurryBound) { + bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); + } + var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity], + result = createHybridWrapper.apply(undefined, newData); + + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return result; + } + } + var thisBinding = isBind ? thisArg : this, + fn = isBindKey ? thisBinding[func] : func; + + if (argPos) { + args = reorder(args, argPos); + } + if (isAry && ary < args.length) { + args.length = ary; + } + if (this && this !== root && this instanceof wrapper) { + fn = Ctor || createCtorWrapper(func); + } + return fn.apply(thisBinding, args); + } + return wrapper; + } + + /** + * Creates a function that wraps `func` and invokes it with the optional `this` + * binding of `thisArg` and the `partials` prepended to those provided to + * the wrapper. + * + * @private + * @param {Function} func The function to partially apply arguments to. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to the new function. + * @returns {Function} Returns the new bound function. + */ + function createPartialWrapper(func, bitmask, thisArg, partials) { + var isBind = bitmask & BIND_FLAG, + Ctor = createCtorWrapper(func); + + function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it `func`. + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(argsLength + leftLength); + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(isBind ? thisArg : this, args); + } + return wrapper; + } + + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. + * The bitmask may be composed of the following flags: + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & BIND_KEY_FLAG; + if (!isBindKey && typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); + partials = holders = null; + } + length -= (holders ? holders.length : 0); + if (bitmask & PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = null; + } + var data = isBindKey ? null : getData(func), + newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity]; + + if (data) { + mergeData(newData, data); + bitmask = newData[1]; + arity = newData[9]; + } + newData[9] = arity == null + ? (isBindKey ? 0 : func.length) + : (nativeMax(arity - length, 0) || 0); + + if (bitmask == BIND_FLAG) { + var result = createBindWrapper(newData[0], newData[2]); + } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) { + result = createPartialWrapper.apply(undefined, newData); + } else { + result = createHybridWrapper.apply(undefined, newData); + } + var setter = data ? baseSetData : setData; + return setter(result, newData); + } + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing arrays. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { + var index = -1, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isLoose && othLength > arrLength)) { + return false; + } + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index], + result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined; + + if (result !== undefined) { + if (result) { + continue; + } + return false; + } + // Recursively compare arrays (susceptible to call stack limits). + if (isLoose) { + if (!arraySome(other, function(othValue) { + return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); + })) { + return false; + } + } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) { + return false; + } + } + return true; + } + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} value The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag) { + switch (tag) { + case boolTag: + case dateTag: + // Coerce dates and booleans to numbers, dates to milliseconds and booleans + // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. + return +object == +other; + + case errorTag: + return object.name == other.name && object.message == other.message; + + case numberTag: + // Treat `NaN` vs. `NaN` as equal. + return (object != +object) + ? other != +other + : object == +other; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings primitives and string + // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. + return object == (other + ''); + } + return false; + } + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) { + var objProps = keys(object), + objLength = objProps.length, + othProps = keys(other), + othLength = othProps.length; + + if (objLength != othLength && !isLoose) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + var skipCtor = isLoose; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key], + result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined; + + // Recursively compare objects (susceptible to call stack limits). + if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) { + return false; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (!skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + return false; + } + } + return true; + } + + /** + * Gets the appropriate "callback" function. If the `_.callback` method is + * customized this function returns the custom method, otherwise it returns + * the `baseCallback` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. + * + * @private + * @returns {Function} Returns the chosen function or its result. + */ + function getCallback(func, thisArg, argCount) { + var result = lodash.callback || callback; + result = result === callback ? baseCallback : result; + return argCount ? result(func, thisArg, argCount) : result; + } + + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap ? noop : function(func) { + return metaMap.get(func); + }; + + /** + * Gets the name of `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {string} Returns the function name. + */ + function getFuncName(func) { + var result = func.name, + array = realNames[result], + length = array ? array.length : 0; + + while (length--) { + var data = array[length], + otherFunc = data.func; + if (otherFunc == null || otherFunc == func) { + return data.name; + } + } + return result; + } + + /** + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized this function returns the custom method, otherwise it returns + * the `baseIndexOf` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. + * + * @private + * @returns {Function|number} Returns the chosen function or its result. + */ + function getIndexOf(collection, target, fromIndex) { + var result = lodash.indexOf || indexOf; + result = result === indexOf ? baseIndexOf : result; + return collection ? result(collection, target, fromIndex) : result; + } + + /** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ + var getLength = baseProperty('length'); + + /** + * Gets the propery names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = pairs(object), + length = result.length; + + while (length--) { + result[length][2] = isStrictComparable(result[length][1]); + } + return result; + } + + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = object == null ? undefined : object[key]; + return isNative(value) ? value : undefined; + } + + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add array properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + var Ctor = object.constructor; + if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { + Ctor = Object; + } + return new Ctor; + } + + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return bufferClone(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + var buffer = object.buffer; + return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + var result = new Ctor(object.source, reFlags.exec(object)); + result.lastIndex = object.lastIndex; + } + return result; + } + + /** + * Invokes the method at `path` on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + */ + function invokePath(object, path, args) { + if (object != null && !isKey(path, object)) { + path = toPath(path); + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + path = last(path); + } + var func = object == null ? object : object[path]; + return func == null ? undefined : func.apply(object, args); + } + + /** + * Checks if `value` is array-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + */ + function isArrayLike(value) { + return value != null && isLength(getLength(value)); + } + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; + length = length == null ? MAX_SAFE_INTEGER : length; + return value > -1 && value % 1 == 0 && value < length; + } + + /** + * Checks if the provided arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object)) { + var other = object[index]; + return value === value ? (value === other) : (other !== other); + } + return false; + } + + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + var type = typeof value; + if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { + return true; + } + if (isArray(value)) { + return false; + } + var result = !reIsDeepProp.test(value); + return result || (object != null && value in toObject(object)); + } + + /** + * Checks if `func` has a lazy counterpart. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`. + */ + function isLaziable(func) { + var funcName = getFuncName(func); + if (!(funcName in LazyWrapper.prototype)) { + return false; + } + var other = lodash[funcName]; + if (func === other) { + return true; + } + var data = getData(other); + return !!data && func === data[0]; + } + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ + function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } + + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers required to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` + * augment function arguments, making the order in which they are executed important, + * preventing the merging of metadata. However, we make an exception for a safe + * common case where curried functions have `_.ary` and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask, + isCommon = newBitmask < ARY_FLAG; + + var isCombo = + (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) || + (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) || + (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = arrayCopy(value); + } + // Use source `ary` if it's smaller. + if (srcBitmask & ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } + + /** + * A specialized version of `_.pick` which picks `object` properties specified + * by `props`. + * + * @private + * @param {Object} object The source object. + * @param {string[]} props The property names to pick. + * @returns {Object} Returns the new object. + */ + function pickByArray(object, props) { + object = toObject(object); + + var index = -1, + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index]; + if (key in object) { + result[key] = object[key]; + } + } + return result; + } + + /** + * A specialized version of `_.pick` which picks `object` properties `predicate` + * returns truthy for. + * + * @private + * @param {Object} object The source object. + * @param {Function} predicate The function invoked per iteration. + * @returns {Object} Returns the new object. + */ + function pickByCallback(object, predicate) { + var result = {}; + baseForIn(object, function(value, key, object) { + if (predicate(value, key, object)) { + result[key] = value; + } + }); + return result; + } + + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = arrayCopy(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } + + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity function + * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = (function() { + var count = 0, + lastCalled = 0; + + return function(key, value) { + var stamp = now(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return key; + } + } else { + count = 0; + } + return baseSetData(key, value); + }; + }()); + + /** + * A fallback implementation of `_.isPlainObject` which checks if `value` + * is an object created by the `Object` constructor or has a `[[Prototype]]` + * of `null`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + */ + function shimIsPlainObject(value) { + var Ctor, + support = lodash.support; + + // Exit early for non `Object` objects. + if (!(isObjectLike(value) && objToString.call(value) == objectTag) || + (!hasOwnProperty.call(value, 'constructor') && + (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { + return false; + } + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + var result; + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + baseForIn(value, function(subValue, key) { + result = key; + }); + return result === undefined || hasOwnProperty.call(value, result); + } + + /** + * A fallback implementation of `Object.keys` which creates an array of the + * own enumerable property names of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function shimKeys(object) { + var props = keysIn(object), + propsLength = props.length, + length = propsLength && object.length; + + var allowIndexes = !!length && isLength(length) && + (isArray(object) || isArguments(object)); + + var index = -1, + result = []; + + while (++index < propsLength) { + var key = props[index]; + if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { + result.push(key); + } + } + return result; + } + + /** + * Converts `value` to an object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ + function toObject(value) { + return isObject(value) ? value : Object(value); + } + + /** + * Converts `value` to property path array if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array} Returns the property path array. + */ + function toPath(value) { + if (isArray(value)) { + return value; + } + var result = []; + baseToString(value).replace(rePropName, function(match, number, quote, string) { + result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of unique `array` values not included in the other + * provided arrays using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The arrays of values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.difference([1, 2, 3], [4, 2]); + * // => [1, 3] + */ + var difference = restParam(function(array, values) { + return isArrayLike(array) + ? baseDifference(array, baseFlatten(values, false, true)) + : []; + }); + + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it is used as the offset + * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` + * performs a faster binary search. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {boolean|number} [fromIndex=0] The index to search from or `true` + * to perform a binary search on a sorted array. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // using `fromIndex` + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + * + * // performing a binary search + * _.indexOf([1, 1, 2, 2], 2, true); + * // => 2 + */ + function indexOf(array, value, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + if (typeof fromIndex == 'number') { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; + } else if (fromIndex) { + var index = binaryIndex(array, value), + other = array[index]; + + if (value === value ? (value === other) : (other !== other)) { + return index; + } + return -1; + } + return baseIndexOf(array, value, fromIndex || 0); + } + + /** + * Creates an array of unique values that are included in all of the provided + * arrays using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of shared values. + * @example + * _.intersection([1, 2], [4, 2], [2, 1]); + * // => [2] + */ + var intersection = restParam(function(arrays) { + var othLength = arrays.length, + othIndex = othLength, + caches = Array(length), + indexOf = getIndexOf(), + isCommon = indexOf == baseIndexOf, + result = []; + + while (othIndex--) { + var value = arrays[othIndex] = isArrayLike(value = arrays[othIndex]) ? value : []; + caches[othIndex] = (isCommon && value.length >= 120) ? createCache(othIndex && value) : null; + } + var array = arrays[0], + index = -1, + length = array ? array.length : 0, + seen = caches[0]; + + outer: + while (++index < length) { + value = array[index]; + if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) { + var othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) { + continue outer; + } + } + if (seen) { + seen.push(value); + } + result.push(value); + } + } + return result; + }); + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array ? array.length : 0; + return length ? array[length - 1] : undefined; + } + + /*------------------------------------------------------------------------*/ + + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * The predicate is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias all + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // using the `_.matches` callback shorthand + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // using the `_.matchesProperty` callback shorthand + * _.every(users, 'active', false); + * // => true + * + * // using the `_.property` callback shorthand + * _.every(users, 'active'); + * // => false + */ + function every(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (thisArg && isIterateeCall(collection, predicate, thisArg)) { + predicate = null; + } + if (typeof predicate != 'function' || thisArg !== undefined) { + predicate = getCallback(predicate, thisArg, 3); + } + return func(collection, predicate); + } + + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias detect + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': true } + * ]; + * + * _.result(_.find(users, function(chr) { + * return chr.age < 40; + * }), 'user'); + * // => 'barney' + * + * // using the `_.matches` callback shorthand + * _.result(_.find(users, { 'age': 1, 'active': true }), 'user'); + * // => 'pebbles' + * + * // using the `_.matchesProperty` callback shorthand + * _.result(_.find(users, 'active', false), 'user'); + * // => 'fred' + * + * // using the `_.property` callback shorthand + * _.result(_.find(users, 'active'), 'user'); + * // => 'barney' + */ + var find = createFind(baseEach); + + /** + * Iterates over elements of `collection` invoking `iteratee` for each element. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). Iteratee functions may exit iteration early + * by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * + * @static + * @memberOf _ + * @alias each + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2]).forEach(function(n) { + * console.log(n); + * }).value(); + * // => logs each value from left to right and returns the array + * + * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { + * console.log(n, key); + * }); + * // => logs each value-key pair and returns the object (iteration order is not guaranteed) + */ + var forEach = createForEach(arrayEach, baseEach); + + /** + * Invokes the method at `path` of each element in `collection`, returning + * an array of the results of each invoked method. Any additional arguments + * are provided to each invoked method. If `methodName` is a function it is + * invoked for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array|Function|string} path The path of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invoke([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + var invoke = restParam(function(collection, path, args) { + var index = -1, + isFunc = typeof path == 'function', + isProp = isKey(path), + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value) { + var func = isFunc ? path : ((isProp && value != null) ? value[path] : null); + result[++index] = func ? func.apply(value, args) : invokePath(value, path, args); + }); + return result; + }); + + /** + * Creates an array of values by running each element in `collection` through + * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three + * arguments: (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, + * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, + * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, + * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, + * `sum`, `uniq`, and `words` + * + * @static + * @memberOf _ + * @alias collect + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new mapped array. + * @example + * + * function timesThree(n) { + * return n * 3; + * } + * + * _.map([1, 2], timesThree); + * // => [3, 6] + * + * _.map({ 'a': 1, 'b': 2 }, timesThree); + * // => [3, 6] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // using the `_.property` callback shorthand + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee, thisArg) { + var func = isArray(collection) ? arrayMap : baseMap; + iteratee = getCallback(iteratee, thisArg, 3); + return func(collection, iteratee); + } + + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, while the second of which + * contains elements `predicate` returns falsey for. The predicate is bound + * to `thisArg` and invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * _.partition([1, 2, 3], function(n) { + * return n % 2; + * }); + * // => [[1, 3], [2]] + * + * _.partition([1.2, 2.3, 3.4], function(n) { + * return this.floor(n) % 2; + * }, Math); + * // => [[1.2, 3.4], [2.3]] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * var mapper = function(array) { + * return _.pluck(array, 'user'); + * }; + * + * // using the `_.matches` callback shorthand + * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); + * // => [['pebbles'], ['barney', 'fred']] + * + * // using the `_.matchesProperty` callback shorthand + * _.map(_.partition(users, 'active', false), mapper); + * // => [['barney', 'pebbles'], ['fred']] + * + * // using the `_.property` callback shorthand + * _.map(_.partition(users, 'active'), mapper); + * // => [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); + }, function() { return [[], []]; }); + + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` through `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not provided the first element of `collection` is used as the initial + * value. The `iteratee` is bound to `thisArg` and invoked with four arguments: + * (accumulator, value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.reduce`, `_.reduceRight`, and `_.transform`. + * + * The guarded methods are: + * `assign`, `defaults`, `includes`, `merge`, `sortByAll`, and `sortByOrder` + * + * @static + * @memberOf _ + * @alias foldl, inject + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * _.reduce([1, 2], function(total, n) { + * return total + n; + * }); + * // => 3 + * + * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) { + * result[key] = n * 3; + * return result; + * }, {}); + * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed) + */ + var reduce = createReduce(arrayReduce, baseEach); + + /*------------------------------------------------------------------------*/ + + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Date + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => logs the number of milliseconds it took for the deferred function to be invoked + */ + var now = nativeNow || function() { + return new Date().getTime(); + }; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and prepends any additional `_.bind` arguments to those provided to the + * bound function. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind` this method does not set the "length" + * property of bound functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var greet = function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * }; + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // using placeholders + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + var bind = restParam(function(func, thisArg, partials) { + var bitmask = BIND_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, bind.placeholder); + bitmask |= PARTIAL_FLAG; + } + return createWrapper(func, bitmask, thisArg, partials, holders); + }); + + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { + * console.log(text); + * }, 'deferred'); + * // logs 'deferred' after one or more milliseconds + */ + var defer = restParam(function(func, args) { + return baseDelay(func, 1, args); + }); + + /** + * Creates a function that invokes `func` with `partial` arguments prepended + * to those provided to the new function. This method is like `_.bind` except + * it does **not** alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method does not set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var greet = function(greeting, name) { + * return greeting + ' ' + name; + * }; + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // using placeholders + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ + var partial = createPartial(PARTIAL_FLAG); + + /** + * Creates a function that invokes `func` with the `this` binding of the + * created function and arguments from `start` and beyond provided as an array. + * + * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters). + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.restParam(function(what, names) { + * return what + ' ' + _.initial(names).join(', ') + + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); + * }); + * + * say('hello', 'fred', 'barney', 'pebbles'); + * // => 'hello fred, barney, & pebbles' + */ + function restParam(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + rest = Array(length); + + while (++index < length) { + rest[index] = args[start + index]; + } + switch (start) { + case 0: return func.call(this, rest); + case 1: return func.call(this, args[0], rest); + case 2: return func.call(this, args[0], args[1], rest); + } + var otherArgs = Array(start + 1); + index = -1; + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = rest; + return func.apply(this, otherArgs); + }; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, + * otherwise they are assigned by reference. If `customizer` is provided it is + * invoked to produce the cloned values. If `customizer` returns `undefined` + * cloning is handled by the method instead. The `customizer` is bound to + * `thisArg` and invoked with two argument; (value [, index|key, object]). + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {*} Returns the cloned value. + * @example + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * var shallow = _.clone(users); + * shallow[0] === users[0]; + * // => true + * + * var deep = _.clone(users, true); + * deep[0] === users[0]; + * // => false + * + * // using a customizer callback + * var el = _.clone(document.body, function(value) { + * if (_.isElement(value)) { + * return value.cloneNode(false); + * } + * }); + * + * el === document.body + * // => false + * el.nodeName + * // => BODY + * el.childNodes.length; + * // => 0 + */ + function clone(value, isDeep, customizer, thisArg) { + if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { + isDeep = false; + } + else if (typeof isDeep == 'function') { + thisArg = customizer; + customizer = isDeep; + isDeep = false; + } + return typeof customizer == 'function' + ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 1)) + : baseClone(value, isDeep); + } + + /** + * Checks if `value` is classified as an `arguments` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + function isArguments(value) { + return isObjectLike(value) && isArrayLike(value) && objToString.call(value) == argsTag; + } + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(function() { return arguments; }()); + * // => false + */ + var isArray = nativeIsArray || function(value) { + return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; + }; + + /** + * Checks if `value` is a DOM element. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ + function isElement(value) { + return !!value && value.nodeType === 1 && isObjectLike(value) && + (objToString.call(value).indexOf('Element') > -1); + } + // Fallback for environments without DOM support. + if (!support.dom) { + isElement = function(value) { + return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value); + }; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. If `customizer` is provided it is invoked to compare values. + * If `customizer` returns `undefined` comparisons are handled by the method + * instead. The `customizer` is bound to `thisArg` and invoked with three + * arguments: (value, other [, index|key]). + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Objects are compared by + * their own, not inherited, enumerable properties. Functions and DOM nodes + * are **not** supported. Provide a customizer function to extend support + * for comparing other values. + * + * @static + * @memberOf _ + * @alias eq + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize value comparisons. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'user': 'fred' }; + * var other = { 'user': 'fred' }; + * + * object == other; + * // => false + * + * _.isEqual(object, other); + * // => true + * + * // using a customizer callback + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqual(array, other, function(value, other) { + * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) { + * return true; + * } + * }); + * // => true + */ + function isEqual(value, other, customizer, thisArg) { + customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; + var result = customizer ? customizer(value, other) : undefined; + return result === undefined ? baseIsEqual(value, other, customizer) : !!result; + } + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + var isFunction = !(baseIsFunction(/x/) || (Uint8Array && !baseIsFunction(Uint8Array))) ? baseIsFunction : function(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in older versions of Chrome and Safari which return 'function' for regexes + // and Safari 8 equivalents which return 'object' for typed array constructors. + return objToString.call(value) == funcTag; + }; + + /** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ + function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); + } + + /** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ + function isNative(value) { + if (value == null) { + return false; + } + if (objToString.call(value) == funcTag) { + return reIsNative.test(fnToString.call(value)); + } + return isObjectLike(value) && reIsHostCtor.test(value); + } + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified + * as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isNumber(8.4); + * // => true + * + * _.isNumber(NaN); + * // => true + * + * _.isNumber('8.4'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag); + } + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * **Note:** This method assumes objects created by the `Object` constructor + * have no inherited enumerable properties. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { + if (!(value && objToString.call(value) == objectTag)) { + return false; + } + var valueOf = getNative(value, 'valueOf'), + objProto = valueOf && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); + + return objProto + ? (value == objProto || getPrototypeOf(value) == objProto) + : shimIsPlainObject(value); + }; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); + } + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + function isTypedArray(value) { + return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; + } + + /*------------------------------------------------------------------------*/ + + /** + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources overwrite property assignments of previous sources. + * If `customizer` is provided it is invoked to produce the assigned values. + * The `customizer` is bound to `thisArg` and invoked with five arguments: + * (objectValue, sourceValue, key, object, source). + * + * **Note:** This method mutates `object` and is based on + * [`Object.assign`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign). + * + * @static + * @memberOf _ + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {Object} Returns `object`. + * @example + * + * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); + * // => { 'user': 'fred', 'age': 40 } + * + * // using a customizer callback + * var defaults = _.partialRight(_.assign, function(value, other) { + * return _.isUndefined(value) ? other : value; + * }); + * + * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ + var assign = createAssigner(function(object, source, customizer) { + return customizer + ? assignWith(object, source, customizer) + : baseAssign(object, source); + }); + + /** + * Assigns own enumerable properties of source object(s) to the destination + * object for all destination properties that resolve to `undefined`. Once a + * property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ + var defaults = restParam(function(args) { + var object = args[0]; + if (object == null) { + return object; + } + args.push(assignDefaults); + return assign.apply(undefined, args); + }); + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys) + * for more details. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + var keys = !nativeKeys ? shimKeys : function(object) { + var Ctor = object == null ? null : object.constructor; + if ((typeof Ctor == 'function' && Ctor.prototype === object) || + (typeof object != 'function' && isArrayLike(object))) { + return shimKeys(object); + } + return isObject(object) ? nativeKeys(object) : []; + }; + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + if (object == null) { + return []; + } + if (!isObject(object)) { + object = Object(object); + } + var length = object.length; + length = (length && isLength(length) && + (isArray(object) || isArguments(object)) && length) || 0; + + var Ctor = object.constructor, + index = -1, + isProto = typeof Ctor == 'function' && Ctor.prototype === object, + result = Array(length), + skipIndexes = length > 0; + + while (++index < length) { + result[index] = (index + ''); + } + for (var key in object) { + if (!(skipIndexes && isIndex(key, length)) && + !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable properties of `object` that are not omitted. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|...(string|string[])} [predicate] The function invoked per + * iteration or property names to omit, specified as individual property + * names or arrays of property names. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.omit(object, 'age'); + * // => { 'user': 'fred' } + * + * _.omit(object, _.isNumber); + * // => { 'user': 'fred' } + */ + var omit = restParam(function(object, props) { + if (object == null) { + return {}; + } + if (typeof props[0] != 'function') { + var props = arrayMap(baseFlatten(props), String); + return pickByArray(object, baseDifference(keysIn(object), props)); + } + var predicate = bindCallback(props[0], props[1], 3); + return pickByCallback(object, function(value, key, object) { + return !predicate(value, key, object); + }); + }); + + /** + * Creates a two dimensional array of the key-value pairs for `object`, + * e.g. `[[key1, value1], [key2, value2]]`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the new array of key-value pairs. + * @example + * + * _.pairs({ 'barney': 36, 'fred': 40 }); + * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) + */ + function pairs(object) { + object = toObject(object); + + var index = -1, + props = keys(object), + length = props.length, + result = Array(length); + + while (++index < length) { + var key = props[index]; + result[index] = [key, object[key]]; + } + return result; + } + + /** + * Creates an array of the own enumerable property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ + function values(object) { + return baseValues(object, keys(object)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", + * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' + */ + function escapeRegExp(string) { + string = baseToString(string); + return (string && reHasRegExpChars.test(string)) + ? string.replace(reRegExpChars, '\\$&') + : string; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and arguments of the created function. If `func` is a property name the + * created callback returns the property value for a given element. If `func` + * is an object the created callback returns `true` for elements that contain + * the equivalent object properties, otherwise it returns `false`. + * + * @static + * @memberOf _ + * @alias iteratee + * @category Utility + * @param {*} [func=_.identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of `func`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the callback. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // wrap to create custom callback shorthands + * _.callback = _.wrap(_.callback, function(callback, func, thisArg) { + * var match = /^(.+?)__([gl]t)(.+)$/.exec(func); + * if (!match) { + * return callback(func, thisArg); + * } + * return function(object) { + * return match[2] == 'gt' + * ? object[match[1]] > match[3] + * : object[match[1]] < match[3]; + * }; + * }); + * + * _.filter(users, 'age__gt36'); + * // => [{ 'user': 'fred', 'age': 40 }] + */ + function callback(func, thisArg, guard) { + if (guard && isIterateeCall(func, thisArg, guard)) { + thisArg = null; + } + return isObjectLike(func) + ? matches(func) + : baseCallback(func, thisArg); + } + + /** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @category Utility + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new function. + * @example + * + * var object = { 'user': 'fred' }; + * var getter = _.constant(object); + * + * getter() === object; + * // => true + */ + function constant(value) { + return function() { + return value; + }; + } + + /** + * This method returns the first argument provided to it. + * + * @static + * @memberOf _ + * @category Utility + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'user': 'fred' }; + * + * _.identity(object) === object; + * // => true + */ + function identity(value) { + return value; + } + + /** + * Creates a function that performs a deep comparison between a given object + * and `source`, returning `true` if the given object has equivalent property + * values, else `false`. + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Objects are compared by + * their own, not inherited, enumerable properties. For comparing a single + * own or inherited property value see `_.matchesProperty`. + * + * @static + * @memberOf _ + * @category Utility + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new function. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * _.filter(users, _.matches({ 'age': 40, 'active': false })); + * // => [{ 'user': 'fred', 'age': 40, 'active': false }] + */ + function matches(source) { + return baseMatches(baseClone(source, true)); + } + + /** + * A no-operation function that returns `undefined` regardless of the + * arguments it receives. + * + * @static + * @memberOf _ + * @category Utility + * @example + * + * var object = { 'user': 'fred' }; + * + * _.noop(object) === undefined; + * // => true + */ + function noop() { + // No operation performed. + } + + /** + * Creates a function that returns the property value at `path` on a + * given object. + * + * @static + * @memberOf _ + * @category Utility + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new function. + * @example + * + * var objects = [ + * { 'a': { 'b': { 'c': 2 } } }, + * { 'a': { 'b': { 'c': 1 } } } + * ]; + * + * _.map(objects, _.property('a.b.c')); + * // => [2, 1] + * + * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c'); + * // => [1, 2] + */ + function property(path) { + return isKey(path) ? baseProperty(path) : basePropertyDeep(path); + } + + /** + * Generates a unique ID. If `prefix` is provided the ID is appended to it. + * + * @static + * @memberOf _ + * @category Utility + * @param {string} [prefix] The value to prefix the ID with. + * @returns {string} Returns the unique ID. + * @example + * + * _.uniqueId('contact_'); + * // => 'contact_104' + * + * _.uniqueId(); + * // => '105' + */ + function uniqueId(prefix) { + var id = ++idCounter; + return baseToString(prefix) + id; + } + + /*------------------------------------------------------------------------*/ + + LazyWrapper.prototype = baseCreate(baseLodash.prototype); + LazyWrapper.prototype.constructor = LazyWrapper; + + // Add functions to the `Set` cache. + SetCache.prototype.push = cachePush; + + // Add functions that return wrapped values when chaining. + lodash.assign = assign; + lodash.bind = bind; + lodash.callback = callback; + lodash.constant = constant; + lodash.defaults = defaults; + lodash.defer = defer; + lodash.difference = difference; + lodash.forEach = forEach; + lodash.intersection = intersection; + lodash.invoke = invoke; + lodash.keys = keys; + lodash.keysIn = keysIn; + lodash.map = map; + lodash.matches = matches; + lodash.omit = omit; + lodash.pairs = pairs; + lodash.partial = partial; + lodash.partition = partition; + lodash.property = property; + lodash.restParam = restParam; + lodash.values = values; + + // Add aliases. + lodash.collect = map; + lodash.each = forEach; + lodash.extend = assign; + lodash.iteratee = callback; + + /*------------------------------------------------------------------------*/ + + // Add functions that return unwrapped values when chaining. + lodash.clone = clone; + lodash.escapeRegExp = escapeRegExp; + lodash.every = every; + lodash.find = find; + lodash.identity = identity; + lodash.indexOf = indexOf; + lodash.isArguments = isArguments; + lodash.isArray = isArray; + lodash.isElement = isElement; + lodash.isEqual = isEqual; + lodash.isFunction = isFunction; + lodash.isNative = isNative; + lodash.isNumber = isNumber; + lodash.isObject = isObject; + lodash.isPlainObject = isPlainObject; + lodash.isString = isString; + lodash.isTypedArray = isTypedArray; + lodash.last = last; + lodash.noop = noop; + lodash.now = now; + lodash.reduce = reduce; + lodash.uniqueId = uniqueId; + + // Add aliases. + lodash.all = every; + lodash.eq = isEqual; + lodash.detect = find; + lodash.foldl = reduce; + lodash.inject = reduce; + + /*------------------------------------------------------------------------*/ + + /** + * The semantic version number. + * + * @static + * @memberOf _ + * @type string + */ + lodash.VERSION = VERSION; + + // Assign default placeholders. + arrayEach(['bind', 'partial'], function(methodName) { + lodash[methodName].placeholder = lodash; + }); + + /*--------------------------------------------------------------------------*/ + + // Some AMD build optimizers like r.js check for condition patterns like the following: + if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { + // Expose lodash to the global object when an AMD loader is present to avoid + // errors in cases where lodash is loaded by a script tag and not intended + // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch for + // more details. + root._ = lodash; + + // Define as an anonymous module so, through path mapping, it can be + // referenced as the "underscore" module. + define(function() { + return lodash; + }); + } + // Check for `exports` after `define` in case a build optimizer adds an `exports` object. + else if (freeExports && freeModule) { + // Export for Node.js or RingoJS. + if (moduleExports) { + (freeModule.exports = lodash)._ = lodash; + } + // Export for Rhino with CommonJS support. + else { + freeExports._ = lodash; + } + } + else { + // Export for a browser or Rhino. + root._ = lodash; + } +}.call(this)); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],2:[function(_dereq_,module,exports){ +/*! + * EventEmitter2 + * https://github.com/hij1nx/EventEmitter2 + * + * Copyright (c) 2013 hij1nx + * Licensed under the MIT license. + */ +;!function(undefined) { + + var isArray = Array.isArray ? Array.isArray : function _isArray(obj) { + return Object.prototype.toString.call(obj) === "[object Array]"; + }; + var defaultMaxListeners = 10; + + function init() { + this._events = {}; + if (this._conf) { + configure.call(this, this._conf); + } + } + + function configure(conf) { + if (conf) { + + this._conf = conf; + + conf.delimiter && (this.delimiter = conf.delimiter); + conf.maxListeners && (this._events.maxListeners = conf.maxListeners); + conf.wildcard && (this.wildcard = conf.wildcard); + conf.newListener && (this.newListener = conf.newListener); + + if (this.wildcard) { + this.listenerTree = {}; + } + } + } + + function EventEmitter(conf) { + this._events = {}; + this.newListener = false; + configure.call(this, conf); + } + + // + // Attention, function return type now is array, always ! + // It has zero elements if no any matches found and one or more + // elements (leafs) if there are matches + // + function searchListenerTree(handlers, type, tree, i) { + if (!tree) { + return []; + } + var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached, + typeLength = type.length, currentType = type[i], nextType = type[i+1]; + if (i === typeLength && tree._listeners) { + // + // If at the end of the event(s) list and the tree has listeners + // invoke those listeners. + // + if (typeof tree._listeners === 'function') { + handlers && handlers.push(tree._listeners); + return [tree]; + } else { + for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) { + handlers && handlers.push(tree._listeners[leaf]); + } + return [tree]; + } + } + + if ((currentType === '*' || currentType === '**') || tree[currentType]) { + // + // If the event emitted is '*' at this part + // or there is a concrete match at this patch + // + if (currentType === '*') { + for (branch in tree) { + if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1)); + } + } + return listeners; + } else if(currentType === '**') { + endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*')); + if(endReached && tree._listeners) { + // The next element has a _listeners, add it to the handlers. + listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength)); + } + + for (branch in tree) { + if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { + if(branch === '*' || branch === '**') { + if(tree[branch]._listeners && !endReached) { + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength)); + } + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); + } else if(branch === nextType) { + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2)); + } else { + // No match on this one, shift into the tree but not in the type array. + listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); + } + } + } + return listeners; + } + + listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1)); + } + + xTree = tree['*']; + if (xTree) { + // + // If the listener tree will allow any match for this part, + // then recursively explore all branches of the tree + // + searchListenerTree(handlers, type, xTree, i+1); + } + + xxTree = tree['**']; + if(xxTree) { + if(i < typeLength) { + if(xxTree._listeners) { + // If we have a listener on a '**', it will catch all, so add its handler. + searchListenerTree(handlers, type, xxTree, typeLength); + } + + // Build arrays of matching next branches and others. + for(branch in xxTree) { + if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) { + if(branch === nextType) { + // We know the next element will match, so jump twice. + searchListenerTree(handlers, type, xxTree[branch], i+2); + } else if(branch === currentType) { + // Current node matches, move into the tree. + searchListenerTree(handlers, type, xxTree[branch], i+1); + } else { + isolatedBranch = {}; + isolatedBranch[branch] = xxTree[branch]; + searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1); + } + } + } + } else if(xxTree._listeners) { + // We have reached the end and still on a '**' + searchListenerTree(handlers, type, xxTree, typeLength); + } else if(xxTree['*'] && xxTree['*']._listeners) { + searchListenerTree(handlers, type, xxTree['*'], typeLength); + } + } + + return listeners; + } + + function growListenerTree(type, listener) { + + type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + + // + // Looks for two consecutive '**', if so, don't add the event at all. + // + for(var i = 0, len = type.length; i+1 < len; i++) { + if(type[i] === '**' && type[i+1] === '**') { + return; + } + } + + var tree = this.listenerTree; + var name = type.shift(); + + while (name) { + + if (!tree[name]) { + tree[name] = {}; + } + + tree = tree[name]; + + if (type.length === 0) { + + if (!tree._listeners) { + tree._listeners = listener; + } + else if(typeof tree._listeners === 'function') { + tree._listeners = [tree._listeners, listener]; + } + else if (isArray(tree._listeners)) { + + tree._listeners.push(listener); + + if (!tree._listeners.warned) { + + var m = defaultMaxListeners; + + if (typeof this._events.maxListeners !== 'undefined') { + m = this._events.maxListeners; + } + + if (m > 0 && tree._listeners.length > m) { + + tree._listeners.warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + tree._listeners.length); + console.trace(); + } + } + } + return true; + } + name = type.shift(); + } + return true; + } + + // By default EventEmitters will print a warning if more than + // 10 listeners are added to it. This is a useful default which + // helps finding memory leaks. + // + // Obviously not all Emitters should be limited to 10. This function allows + // that to be increased. Set to zero for unlimited. + + EventEmitter.prototype.delimiter = '.'; + + EventEmitter.prototype.setMaxListeners = function(n) { + this._events || init.call(this); + this._events.maxListeners = n; + if (!this._conf) this._conf = {}; + this._conf.maxListeners = n; + }; + + EventEmitter.prototype.event = ''; + + EventEmitter.prototype.once = function(event, fn) { + this.many(event, 1, fn); + return this; + }; + + EventEmitter.prototype.many = function(event, ttl, fn) { + var self = this; + + if (typeof fn !== 'function') { + throw new Error('many only accepts instances of Function'); + } + + function listener() { + if (--ttl === 0) { + self.off(event, listener); + } + fn.apply(this, arguments); + } + + listener._origin = fn; + + this.on(event, listener); + + return self; + }; + + EventEmitter.prototype.emit = function() { + + this._events || init.call(this); + + var type = arguments[0]; + + if (type === 'newListener' && !this.newListener) { + if (!this._events.newListener) { return false; } + } + + // Loop through the *_all* functions and invoke them. + if (this._all) { + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; + for (i = 0, l = this._all.length; i < l; i++) { + this.event = type; + this._all[i].apply(this, args); + } + } + + // If there is no 'error' event listener then throw. + if (type === 'error') { + + if (!this._all && + !this._events.error && + !(this.wildcard && this.listenerTree.error)) { + + if (arguments[1] instanceof Error) { + throw arguments[1]; // Unhandled 'error' event + } else { + throw new Error("Uncaught, unspecified 'error' event."); + } + return false; + } + } + + var handler; + + if(this.wildcard) { + handler = []; + var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + searchListenerTree.call(this, handler, ns, this.listenerTree, 0); + } + else { + handler = this._events[type]; + } + + if (typeof handler === 'function') { + this.event = type; + if (arguments.length === 1) { + handler.call(this); + } + else if (arguments.length > 1) + switch (arguments.length) { + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; + handler.apply(this, args); + } + return true; + } + else if (handler) { + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; + + var listeners = handler.slice(); + for (var i = 0, l = listeners.length; i < l; i++) { + this.event = type; + listeners[i].apply(this, args); + } + return (listeners.length > 0) || !!this._all; + } + else { + return !!this._all; + } + + }; + + EventEmitter.prototype.on = function(type, listener) { + + if (typeof type === 'function') { + this.onAny(type); + return this; + } + + if (typeof listener !== 'function') { + throw new Error('on only accepts instances of Function'); + } + this._events || init.call(this); + + // To avoid recursion in the case that type == "newListeners"! Before + // adding it to the listeners, first emit "newListeners". + this.emit('newListener', type, listener); + + if(this.wildcard) { + growListenerTree.call(this, type, listener); + return this; + } + + if (!this._events[type]) { + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + } + else if(typeof this._events[type] === 'function') { + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + } + else if (isArray(this._events[type])) { + // If we've already got an array, just append. + this._events[type].push(listener); + + // Check for listener leak + if (!this._events[type].warned) { + + var m = defaultMaxListeners; + + if (typeof this._events.maxListeners !== 'undefined') { + m = this._events.maxListeners; + } + + if (m > 0 && this._events[type].length > m) { + + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + console.trace(); + } + } + } + return this; + }; + + EventEmitter.prototype.onAny = function(fn) { + + if (typeof fn !== 'function') { + throw new Error('onAny only accepts instances of Function'); + } + + if(!this._all) { + this._all = []; + } + + // Add the function to the event listener collection. + this._all.push(fn); + return this; + }; + + EventEmitter.prototype.addListener = EventEmitter.prototype.on; + + EventEmitter.prototype.off = function(type, listener) { + if (typeof listener !== 'function') { + throw new Error('removeListener only takes instances of Function'); + } + + var handlers,leafs=[]; + + if(this.wildcard) { + var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); + } + else { + // does not use listeners(), so no side effect of creating _events[type] + if (!this._events[type]) return this; + handlers = this._events[type]; + leafs.push({_listeners:handlers}); + } + + for (var iLeaf=0; iLeaf 0) { + fns = this._all; + for(i = 0, l = fns.length; i < l; i++) { + if(fn === fns[i]) { + fns.splice(i, 1); + return this; + } + } + } else { + this._all = []; + } + return this; + }; + + EventEmitter.prototype.removeListener = EventEmitter.prototype.off; + + EventEmitter.prototype.removeAllListeners = function(type) { + if (arguments.length === 0) { + !this._events || init.call(this); + return this; + } + + if(this.wildcard) { + var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); + + for (var iLeaf=0; iLeaf 0) newOp.attributes = attributes; + return this.push(newOp); +}; + +Delta.prototype['delete'] = function (length) { + if (length <= 0) return this; + return this.push({ 'delete': length }); +}; + +Delta.prototype.retain = function (length, attributes) { + if (length <= 0) return this; + var newOp = { retain: length }; + if (is.object(attributes) && Object.keys(attributes).length > 0) newOp.attributes = attributes; + return this.push(newOp); +}; + +Delta.prototype.push = function (newOp) { + var index = this.ops.length; + var lastOp = this.ops[index - 1]; + newOp = op.clone(newOp); + if (is.object(lastOp)) { + if (is.number(newOp['delete']) && is.number(lastOp['delete'])) { + this.ops[index - 1] = { 'delete': lastOp['delete'] + newOp['delete'] }; + return this; + } + // Since it does not matter if we insert before or after deleting at the same index, + // always prefer to insert first + if (is.number(lastOp['delete']) && newOp.insert != null) { + index -= 1; + lastOp = this.ops[index - 1]; + if (!is.object(lastOp)) { + this.ops.unshift(newOp); + return this; + } + } + if (is.equal(newOp.attributes, lastOp.attributes)) { + if (is.string(newOp.insert) && is.string(lastOp.insert)) { + this.ops[index - 1] = { insert: lastOp.insert + newOp.insert }; + if (is.object(newOp.attributes)) this.ops[index - 1].attributes = newOp.attributes + return this; + } else if (is.number(newOp.retain) && is.number(lastOp.retain)) { + this.ops[index - 1] = { retain: lastOp.retain + newOp.retain }; + if (is.object(newOp.attributes)) this.ops[index - 1].attributes = newOp.attributes + return this; + } + } + } + if (index === this.ops.length) { + this.ops.push(newOp); + } else { + this.ops.splice(index, 0, newOp); + } + return this; +}; + +Delta.prototype.chop = function () { + var lastOp = this.ops[this.ops.length - 1]; + if (lastOp && lastOp.retain && !lastOp.attributes) { + this.ops.pop(); + } + return this; +}; + +Delta.prototype.length = function () { + return this.ops.reduce(function (length, elem) { + return length + op.length(elem); + }, 0); +}; + +Delta.prototype.slice = function (start, end) { + start = start || 0; + if (!is.number(end)) end = Infinity; + var delta = new Delta(); + var iter = op.iterator(this.ops); + var index = 0; + while (index < end && iter.hasNext()) { + var nextOp; + if (index < start) { + nextOp = iter.next(start - index); + } else { + nextOp = iter.next(end - index); + delta.push(nextOp); + } + index += op.length(nextOp); + } + return delta; +}; + + +Delta.prototype.compose = function (other) { + var thisIter = op.iterator(this.ops); + var otherIter = op.iterator(other.ops); + var delta = new Delta(); + while (thisIter.hasNext() || otherIter.hasNext()) { + if (otherIter.peekType() === 'insert') { + delta.push(otherIter.next()); + } else if (thisIter.peekType() === 'delete') { + delta.push(thisIter.next()); + } else { + var length = Math.min(thisIter.peekLength(), otherIter.peekLength()); + var thisOp = thisIter.next(length); + var otherOp = otherIter.next(length); + if (is.number(otherOp.retain)) { + var newOp = {}; + if (is.number(thisOp.retain)) { + newOp.retain = length; + } else { + newOp.insert = thisOp.insert; + } + // Preserve null when composing with a retain, otherwise remove it for inserts + var attributes = op.attributes.compose(thisOp.attributes, otherOp.attributes, is.number(thisOp.retain)); + if (attributes) newOp.attributes = attributes; + delta.push(newOp); + // Other op should be delete, we could be an insert or retain + // Insert + delete cancels out + } else if (is.number(otherOp['delete']) && is.number(thisOp.retain)) { + delta.push(otherOp); + } + } + } + return delta.chop(); +}; + +Delta.prototype.concat = function (other) { + var delta = this.slice(); + if (other.ops.length > 0) { + delta.push(other.ops[0]); + delta.ops = delta.ops.concat(other.ops.slice(1)); + } + return delta; +}; + +Delta.prototype.diff = function (other) { + var delta = new Delta(); + if (this.ops === other.ops) { + return delta; + } + var strings = [this.ops, other.ops].map(function (ops) { + return ops.map(function (op) { + if (op.insert != null) { + return is.string(op.insert) ? op.insert : NULL_CHARACTER; + } + var prep = (ops === other.ops) ? 'on' : 'with'; + throw new Error('diff() called ' + prep + ' non-document'); + }).join(''); + }); + var diffResult = diff(strings[0], strings[1]); + var thisIter = op.iterator(this.ops); + var otherIter = op.iterator(other.ops); + diffResult.forEach(function (component) { + var length = component[1].length; + while (length > 0) { + var opLength = 0; + switch (component[0]) { + case diff.INSERT: + opLength = Math.min(otherIter.peekLength(), length); + delta.push(otherIter.next(opLength)); + break; + case diff.DELETE: + opLength = Math.min(length, thisIter.peekLength()); + thisIter.next(opLength); + delta['delete'](opLength); + break; + case diff.EQUAL: + opLength = Math.min(thisIter.peekLength(), otherIter.peekLength(), length); + var thisOp = thisIter.next(opLength); + var otherOp = otherIter.next(opLength); + if (is.equal(thisOp.insert, otherOp.insert)) { + delta.retain(opLength, op.attributes.diff(thisOp.attributes, otherOp.attributes)); + } else { + delta.push(otherOp)['delete'](opLength); + } + break; + } + length -= opLength; + } + }); + return delta.chop(); +}; + +Delta.prototype.transform = function (other, priority) { + priority = !!priority; + if (is.number(other)) { + return this.transformPosition(other, priority); + } + var thisIter = op.iterator(this.ops); + var otherIter = op.iterator(other.ops); + var delta = new Delta(); + while (thisIter.hasNext() || otherIter.hasNext()) { + if (thisIter.peekType() === 'insert' && (priority || otherIter.peekType() !== 'insert')) { + delta.retain(op.length(thisIter.next())); + } else if (otherIter.peekType() === 'insert') { + delta.push(otherIter.next()); + } else { + var length = Math.min(thisIter.peekLength(), otherIter.peekLength()); + var thisOp = thisIter.next(length); + var otherOp = otherIter.next(length); + if (thisOp['delete']) { + // Our delete either makes their delete redundant or removes their retain + continue; + } else if (otherOp['delete']) { + delta.push(otherOp); + } else { + // We retain either their retain or insert + delta.retain(length, op.attributes.transform(thisOp.attributes, otherOp.attributes, priority)); + } + } + } + return delta.chop(); +}; + +Delta.prototype.transformPosition = function (index, priority) { + priority = !!priority; + var thisIter = op.iterator(this.ops); + var offset = 0; + while (thisIter.hasNext() && offset <= index) { + var length = thisIter.peekLength(); + var nextType = thisIter.peekType(); + thisIter.next(); + if (nextType === 'delete') { + index -= Math.min(length, index - offset); + continue; + } else if (nextType === 'insert' && (offset < index || !priority)) { + index += length; + } + offset += length; + } + return index; +}; + + +module.exports = Delta; + +},{"./is":4,"./op":5,"fast-diff":6}],4:[function(_dereq_,module,exports){ +module.exports = { + equal: function (a, b) { + if (a === b) return true; + if (a == null && b == null) return true; + if (a == null || b == null) return false; + if (!this.object(a) || !this.object(b)) return false; + if (Object.keys(a).length != Object.keys(b).length) return false; + for(var key in a) { + // Only compare one level deep + if (a[key] !== b[key]) return false; + } + return true; + }, + + array: function (value) { + return Array.isArray(value); + }, + + number: function (value) { + if (typeof value === 'number') return true; + if (typeof value === 'object' && Object.prototype.toString.call(value) === '[object Number]') return true; + return false; + }, + + object: function (value) { + if (!value) return false; + return (typeof value === 'function' || typeof value === 'object'); + }, + + string: function (value) { + if (typeof value === 'string') return true; + if (typeof value === 'object' && Object.prototype.toString.call(value) === '[object String]') return true; + return false; + } +}; + +},{}],5:[function(_dereq_,module,exports){ +var is = _dereq_('./is'); + + +var lib = { + attributes: { + clone: function (attributes, keepNull) { + if (!is.object(attributes)) return {}; + return Object.keys(attributes).reduce(function (memo, key) { + if (attributes[key] !== undefined && (attributes[key] !== null || keepNull)) { + memo[key] = attributes[key]; + } + return memo; + }, {}); + }, + + compose: function (a, b, keepNull) { + if (!is.object(a)) a = {}; + if (!is.object(b)) b = {}; + var attributes = this.clone(b, keepNull); + for (var key in a) { + if (a[key] !== undefined && b[key] === undefined) { + attributes[key] = a[key]; + } + } + return Object.keys(attributes).length > 0 ? attributes : undefined; + }, + + diff: function(a, b) { + if (!is.object(a)) a = {}; + if (!is.object(b)) b = {}; + var attributes = Object.keys(a).concat(Object.keys(b)).reduce(function (attributes, key) { + if (a[key] !== b[key]) { + attributes[key] = b[key] === undefined ? null : b[key]; + } + return attributes; + }, {}); + return Object.keys(attributes).length > 0 ? attributes : undefined; + }, + + transform: function (a, b, priority) { + if (!is.object(a)) return b; + if (!is.object(b)) return undefined; + if (!priority) return b; // b simply overwrites us without priority + var attributes = Object.keys(b).reduce(function (attributes, key) { + if (a[key] === undefined) attributes[key] = b[key]; // null is a valid value + return attributes; + }, {}); + return Object.keys(attributes).length > 0 ? attributes : undefined; + } + }, + + clone: function (op) { + var newOp = this.attributes.clone(op); + if (is.object(newOp.attributes)) { + newOp.attributes = this.attributes.clone(newOp.attributes, true); + } + return newOp; + }, + + iterator: function (ops) { + return new Iterator(ops); + }, + + length: function (op) { + if (is.number(op['delete'])) { + return op['delete']; + } else if (is.number(op.retain)) { + return op.retain; + } else { + return is.string(op.insert) ? op.insert.length : 1; + } + } +}; + + +function Iterator(ops) { + this.ops = ops; + this.index = 0; + this.offset = 0; +}; + +Iterator.prototype.hasNext = function () { + return this.peekLength() < Infinity; +}; + +Iterator.prototype.next = function (length) { + if (!length) length = Infinity; + var nextOp = this.ops[this.index]; + if (nextOp) { + var offset = this.offset; + var opLength = lib.length(nextOp) + if (length >= opLength - offset) { + length = opLength - offset; + this.index += 1; + this.offset = 0; + } else { + this.offset += length; + } + if (is.number(nextOp['delete'])) { + return { 'delete': length }; + } else { + var retOp = {}; + if (nextOp.attributes) { + retOp.attributes = nextOp.attributes; + } + if (is.number(nextOp.retain)) { + retOp.retain = length; + } else if (is.string(nextOp.insert)) { + retOp.insert = nextOp.insert.substr(offset, length); + } else { + // offset should === 0, length should === 1 + retOp.insert = nextOp.insert; + } + return retOp; + } + } else { + return { retain: Infinity }; + } +}; + +Iterator.prototype.peekLength = function () { + if (this.ops[this.index]) { + // Should never return 0 if our index is being managed correctly + return lib.length(this.ops[this.index]) - this.offset; + } else { + return Infinity; + } +}; + +Iterator.prototype.peekType = function () { + if (this.ops[this.index]) { + if (is.number(this.ops[this.index]['delete'])) { + return 'delete'; + } else if (is.number(this.ops[this.index].retain)) { + return 'retain'; + } else { + return 'insert'; + } + } + return 'retain'; +}; + + +module.exports = lib; + +},{"./is":4}],6:[function(_dereq_,module,exports){ +/** + * This library modifies the diff-patch-match library by Neil Fraser + * by removing the patch and match functionality and certain advanced + * options in the diff function. The original license is as follows: + * + * === + * + * Diff Match and Patch + * + * Copyright 2006 Google Inc. + * http://code.google.com/p/google-diff-match-patch/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * The data structure representing a diff is an array of tuples: + * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']] + * which means: delete 'Hello', add 'Goodbye' and keep ' world.' + */ +var DIFF_DELETE = -1; +var DIFF_INSERT = 1; +var DIFF_EQUAL = 0; + + +/** + * Find the differences between two texts. Simplifies the problem by stripping + * any common prefix or suffix off the texts before diffing. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @return {Array} Array of diff tuples. + */ +function diff_main(text1, text2) { + // Check for equality (speedup). + if (text1 == text2) { + if (text1) { + return [[DIFF_EQUAL, text1]]; + } + return []; + } + + // Trim off common prefix (speedup). + var commonlength = diff_commonPrefix(text1, text2); + var commonprefix = text1.substring(0, commonlength); + text1 = text1.substring(commonlength); + text2 = text2.substring(commonlength); + + // Trim off common suffix (speedup). + commonlength = diff_commonSuffix(text1, text2); + var commonsuffix = text1.substring(text1.length - commonlength); + text1 = text1.substring(0, text1.length - commonlength); + text2 = text2.substring(0, text2.length - commonlength); + + // Compute the diff on the middle block. + var diffs = diff_compute_(text1, text2); + + // Restore the prefix and suffix. + if (commonprefix) { + diffs.unshift([DIFF_EQUAL, commonprefix]); + } + if (commonsuffix) { + diffs.push([DIFF_EQUAL, commonsuffix]); + } + diff_cleanupMerge(diffs); + return diffs; +}; + + +/** + * Find the differences between two texts. Assumes that the texts do not + * have any common prefix or suffix. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @return {Array} Array of diff tuples. + */ +function diff_compute_(text1, text2) { + var diffs; + + if (!text1) { + // Just add some text (speedup). + return [[DIFF_INSERT, text2]]; + } + + if (!text2) { + // Just delete some text (speedup). + return [[DIFF_DELETE, text1]]; + } + + var longtext = text1.length > text2.length ? text1 : text2; + var shorttext = text1.length > text2.length ? text2 : text1; + var i = longtext.indexOf(shorttext); + if (i != -1) { + // Shorter text is inside the longer text (speedup). + diffs = [[DIFF_INSERT, longtext.substring(0, i)], + [DIFF_EQUAL, shorttext], + [DIFF_INSERT, longtext.substring(i + shorttext.length)]]; + // Swap insertions for deletions if diff is reversed. + if (text1.length > text2.length) { + diffs[0][0] = diffs[2][0] = DIFF_DELETE; + } + return diffs; + } + + if (shorttext.length == 1) { + // Single character string. + // After the previous speedup, the character can't be an equality. + return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]]; + } + + // Check to see if the problem can be split in two. + var hm = diff_halfMatch_(text1, text2); + if (hm) { + // A half-match was found, sort out the return data. + var text1_a = hm[0]; + var text1_b = hm[1]; + var text2_a = hm[2]; + var text2_b = hm[3]; + var mid_common = hm[4]; + // Send both pairs off for separate processing. + var diffs_a = diff_main(text1_a, text2_a); + var diffs_b = diff_main(text1_b, text2_b); + // Merge the results. + return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b); + } + + return diff_bisect_(text1, text2); +}; + + +/** + * Find the 'middle snake' of a diff, split the problem in two + * and return the recursively constructed diff. + * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @return {Array} Array of diff tuples. + * @private + */ +function diff_bisect_(text1, text2) { + // Cache the text lengths to prevent multiple calls. + var text1_length = text1.length; + var text2_length = text2.length; + var max_d = Math.ceil((text1_length + text2_length) / 2); + var v_offset = max_d; + var v_length = 2 * max_d; + var v1 = new Array(v_length); + var v2 = new Array(v_length); + // Setting all elements to -1 is faster in Chrome & Firefox than mixing + // integers and undefined. + for (var x = 0; x < v_length; x++) { + v1[x] = -1; + v2[x] = -1; + } + v1[v_offset + 1] = 0; + v2[v_offset + 1] = 0; + var delta = text1_length - text2_length; + // If the total number of characters is odd, then the front path will collide + // with the reverse path. + var front = (delta % 2 != 0); + // Offsets for start and end of k loop. + // Prevents mapping of space beyond the grid. + var k1start = 0; + var k1end = 0; + var k2start = 0; + var k2end = 0; + for (var d = 0; d < max_d; d++) { + // Walk the front path one step. + for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) { + var k1_offset = v_offset + k1; + var x1; + if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) { + x1 = v1[k1_offset + 1]; + } else { + x1 = v1[k1_offset - 1] + 1; + } + var y1 = x1 - k1; + while (x1 < text1_length && y1 < text2_length && + text1.charAt(x1) == text2.charAt(y1)) { + x1++; + y1++; + } + v1[k1_offset] = x1; + if (x1 > text1_length) { + // Ran off the right of the graph. + k1end += 2; + } else if (y1 > text2_length) { + // Ran off the bottom of the graph. + k1start += 2; + } else if (front) { + var k2_offset = v_offset + delta - k1; + if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) { + // Mirror x2 onto top-left coordinate system. + var x2 = text1_length - v2[k2_offset]; + if (x1 >= x2) { + // Overlap detected. + return diff_bisectSplit_(text1, text2, x1, y1); + } + } + } + } + + // Walk the reverse path one step. + for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) { + var k2_offset = v_offset + k2; + var x2; + if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) { + x2 = v2[k2_offset + 1]; + } else { + x2 = v2[k2_offset - 1] + 1; + } + var y2 = x2 - k2; + while (x2 < text1_length && y2 < text2_length && + text1.charAt(text1_length - x2 - 1) == + text2.charAt(text2_length - y2 - 1)) { + x2++; + y2++; + } + v2[k2_offset] = x2; + if (x2 > text1_length) { + // Ran off the left of the graph. + k2end += 2; + } else if (y2 > text2_length) { + // Ran off the top of the graph. + k2start += 2; + } else if (!front) { + var k1_offset = v_offset + delta - k2; + if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) { + var x1 = v1[k1_offset]; + var y1 = v_offset + x1 - k1_offset; + // Mirror x2 onto top-left coordinate system. + x2 = text1_length - x2; + if (x1 >= x2) { + // Overlap detected. + return diff_bisectSplit_(text1, text2, x1, y1); + } + } + } + } + } + // Diff took too long and hit the deadline or + // number of diffs equals number of characters, no commonality at all. + return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]]; +}; + + +/** + * Given the location of the 'middle snake', split the diff in two parts + * and recurse. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {number} x Index of split point in text1. + * @param {number} y Index of split point in text2. + * @return {Array} Array of diff tuples. + */ +function diff_bisectSplit_(text1, text2, x, y) { + var text1a = text1.substring(0, x); + var text2a = text2.substring(0, y); + var text1b = text1.substring(x); + var text2b = text2.substring(y); + + // Compute both diffs serially. + var diffs = diff_main(text1a, text2a); + var diffsb = diff_main(text1b, text2b); + + return diffs.concat(diffsb); +}; + + +/** + * Determine the common prefix of two strings. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {number} The number of characters common to the start of each + * string. + */ +function diff_commonPrefix(text1, text2) { + // Quick check for common null cases. + if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) { + return 0; + } + // Binary search. + // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + var pointermin = 0; + var pointermax = Math.min(text1.length, text2.length); + var pointermid = pointermax; + var pointerstart = 0; + while (pointermin < pointermid) { + if (text1.substring(pointerstart, pointermid) == + text2.substring(pointerstart, pointermid)) { + pointermin = pointermid; + pointerstart = pointermin; + } else { + pointermax = pointermid; + } + pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); + } + return pointermid; +}; + + +/** + * Determine the common suffix of two strings. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {number} The number of characters common to the end of each string. + */ +function diff_commonSuffix(text1, text2) { + // Quick check for common null cases. + if (!text1 || !text2 || + text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) { + return 0; + } + // Binary search. + // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + var pointermin = 0; + var pointermax = Math.min(text1.length, text2.length); + var pointermid = pointermax; + var pointerend = 0; + while (pointermin < pointermid) { + if (text1.substring(text1.length - pointermid, text1.length - pointerend) == + text2.substring(text2.length - pointermid, text2.length - pointerend)) { + pointermin = pointermid; + pointerend = pointermin; + } else { + pointermax = pointermid; + } + pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin); + } + return pointermid; +}; + + +/** + * Do the two texts share a substring which is at least half the length of the + * longer text? + * This speedup can produce non-minimal diffs. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {Array.} Five element Array, containing the prefix of + * text1, the suffix of text1, the prefix of text2, the suffix of + * text2 and the common middle. Or null if there was no match. + */ +function diff_halfMatch_(text1, text2) { + var longtext = text1.length > text2.length ? text1 : text2; + var shorttext = text1.length > text2.length ? text2 : text1; + if (longtext.length < 4 || shorttext.length * 2 < longtext.length) { + return null; // Pointless. + } + + /** + * Does a substring of shorttext exist within longtext such that the substring + * is at least half the length of longtext? + * Closure, but does not reference any external variables. + * @param {string} longtext Longer string. + * @param {string} shorttext Shorter string. + * @param {number} i Start index of quarter length substring within longtext. + * @return {Array.} Five element Array, containing the prefix of + * longtext, the suffix of longtext, the prefix of shorttext, the suffix + * of shorttext and the common middle. Or null if there was no match. + * @private + */ + function diff_halfMatchI_(longtext, shorttext, i) { + // Start with a 1/4 length substring at position i as a seed. + var seed = longtext.substring(i, i + Math.floor(longtext.length / 4)); + var j = -1; + var best_common = ''; + var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b; + while ((j = shorttext.indexOf(seed, j + 1)) != -1) { + var prefixLength = diff_commonPrefix(longtext.substring(i), + shorttext.substring(j)); + var suffixLength = diff_commonSuffix(longtext.substring(0, i), + shorttext.substring(0, j)); + if (best_common.length < suffixLength + prefixLength) { + best_common = shorttext.substring(j - suffixLength, j) + + shorttext.substring(j, j + prefixLength); + best_longtext_a = longtext.substring(0, i - suffixLength); + best_longtext_b = longtext.substring(i + prefixLength); + best_shorttext_a = shorttext.substring(0, j - suffixLength); + best_shorttext_b = shorttext.substring(j + prefixLength); + } + } + if (best_common.length * 2 >= longtext.length) { + return [best_longtext_a, best_longtext_b, + best_shorttext_a, best_shorttext_b, best_common]; + } else { + return null; + } + } + + // First check if the second quarter is the seed for a half-match. + var hm1 = diff_halfMatchI_(longtext, shorttext, + Math.ceil(longtext.length / 4)); + // Check again based on the third quarter. + var hm2 = diff_halfMatchI_(longtext, shorttext, + Math.ceil(longtext.length / 2)); + var hm; + if (!hm1 && !hm2) { + return null; + } else if (!hm2) { + hm = hm1; + } else if (!hm1) { + hm = hm2; + } else { + // Both matched. Select the longest. + hm = hm1[4].length > hm2[4].length ? hm1 : hm2; + } + + // A half-match was found, sort out the return data. + var text1_a, text1_b, text2_a, text2_b; + if (text1.length > text2.length) { + text1_a = hm[0]; + text1_b = hm[1]; + text2_a = hm[2]; + text2_b = hm[3]; + } else { + text2_a = hm[0]; + text2_b = hm[1]; + text1_a = hm[2]; + text1_b = hm[3]; + } + var mid_common = hm[4]; + return [text1_a, text1_b, text2_a, text2_b, mid_common]; +}; + + +/** + * Reorder and merge like edit sections. Merge equalities. + * Any edit section can move as long as it doesn't cross an equality. + * @param {Array} diffs Array of diff tuples. + */ +function diff_cleanupMerge(diffs) { + diffs.push([DIFF_EQUAL, '']); // Add a dummy entry at the end. + var pointer = 0; + var count_delete = 0; + var count_insert = 0; + var text_delete = ''; + var text_insert = ''; + var commonlength; + while (pointer < diffs.length) { + switch (diffs[pointer][0]) { + case DIFF_INSERT: + count_insert++; + text_insert += diffs[pointer][1]; + pointer++; + break; + case DIFF_DELETE: + count_delete++; + text_delete += diffs[pointer][1]; + pointer++; + break; + case DIFF_EQUAL: + // Upon reaching an equality, check for prior redundancies. + if (count_delete + count_insert > 1) { + if (count_delete !== 0 && count_insert !== 0) { + // Factor out any common prefixies. + commonlength = diff_commonPrefix(text_insert, text_delete); + if (commonlength !== 0) { + if ((pointer - count_delete - count_insert) > 0 && + diffs[pointer - count_delete - count_insert - 1][0] == + DIFF_EQUAL) { + diffs[pointer - count_delete - count_insert - 1][1] += + text_insert.substring(0, commonlength); + } else { + diffs.splice(0, 0, [DIFF_EQUAL, + text_insert.substring(0, commonlength)]); + pointer++; + } + text_insert = text_insert.substring(commonlength); + text_delete = text_delete.substring(commonlength); + } + // Factor out any common suffixies. + commonlength = diff_commonSuffix(text_insert, text_delete); + if (commonlength !== 0) { + diffs[pointer][1] = text_insert.substring(text_insert.length - + commonlength) + diffs[pointer][1]; + text_insert = text_insert.substring(0, text_insert.length - + commonlength); + text_delete = text_delete.substring(0, text_delete.length - + commonlength); + } + } + // Delete the offending records and add the merged ones. + if (count_delete === 0) { + diffs.splice(pointer - count_insert, + count_delete + count_insert, [DIFF_INSERT, text_insert]); + } else if (count_insert === 0) { + diffs.splice(pointer - count_delete, + count_delete + count_insert, [DIFF_DELETE, text_delete]); + } else { + diffs.splice(pointer - count_delete - count_insert, + count_delete + count_insert, [DIFF_DELETE, text_delete], + [DIFF_INSERT, text_insert]); + } + pointer = pointer - count_delete - count_insert + + (count_delete ? 1 : 0) + (count_insert ? 1 : 0) + 1; + } else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL) { + // Merge this equality with the previous one. + diffs[pointer - 1][1] += diffs[pointer][1]; + diffs.splice(pointer, 1); + } else { + pointer++; + } + count_insert = 0; + count_delete = 0; + text_delete = ''; + text_insert = ''; + break; + } + } + if (diffs[diffs.length - 1][1] === '') { + diffs.pop(); // Remove the dummy entry at the end. + } + + // Second pass: look for single edits surrounded on both sides by equalities + // which can be shifted sideways to eliminate an equality. + // e.g: ABAC -> ABAC + var changes = false; + pointer = 1; + // Intentionally ignore the first and last element (don't need checking). + while (pointer < diffs.length - 1) { + if (diffs[pointer - 1][0] == DIFF_EQUAL && + diffs[pointer + 1][0] == DIFF_EQUAL) { + // This is a single edit surrounded by equalities. + if (diffs[pointer][1].substring(diffs[pointer][1].length - + diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) { + // Shift the edit over the previous equality. + diffs[pointer][1] = diffs[pointer - 1][1] + + diffs[pointer][1].substring(0, diffs[pointer][1].length - + diffs[pointer - 1][1].length); + diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; + diffs.splice(pointer - 1, 1); + changes = true; + } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == + diffs[pointer + 1][1]) { + // Shift the edit over the next equality. + diffs[pointer - 1][1] += diffs[pointer + 1][1]; + diffs[pointer][1] = + diffs[pointer][1].substring(diffs[pointer + 1][1].length) + + diffs[pointer + 1][1]; + diffs.splice(pointer + 1, 1); + changes = true; + } + } + pointer++; + } + // If shifts were made, the diff needs reordering and another shift sweep. + if (changes) { + diff_cleanupMerge(diffs); + } +}; + + +var diff = diff_main; +diff.INSERT = DIFF_INSERT; +diff.DELETE = DIFF_DELETE; +diff.EQUAL = DIFF_EQUAL; + + +module.exports = diff; + +},{}],7:[function(_dereq_,module,exports){ +module.exports={"version":"0.20.1"} +},{}],8:[function(_dereq_,module,exports){ +var Delta, Document, Format, Line, LinkedList, Normalizer, _, dom; + +_ = _dereq_('lodash'); + +Delta = _dereq_('rich-text/lib/delta'); + +dom = _dereq_('../lib/dom'); + +Format = _dereq_('./format'); + +Line = _dereq_('./line'); + +LinkedList = _dereq_('../lib/linked-list'); + +Normalizer = _dereq_('./normalizer'); + +Document = (function() { + function Document(root, options) { + this.root = root; + if (options == null) { + options = {}; + } + this.normalizer = new Normalizer(); + this.formats = {}; + _.each(options.formats, _.bind(this.addFormat, this)); + this.setHTML(this.root.innerHTML); + } + + Document.prototype.addFormat = function(name, config) { + if (!_.isObject(config)) { + config = Format.FORMATS[name]; + } + if (this.formats[name] != null) { + console.warn('Overwriting format', name, this.formats[name]); + } + this.formats[name] = new Format(config); + return this.normalizer.addFormat(config); + }; + + Document.prototype.appendLine = function(lineNode) { + return this.insertLineBefore(lineNode, null); + }; + + Document.prototype.findLeafAt = function(index, inclusive) { + var line, offset, ref; + ref = this.findLineAt(index), line = ref[0], offset = ref[1]; + if (line != null) { + return line.findLeafAt(offset, inclusive); + } else { + return [void 0, offset]; + } + }; + + Document.prototype.findLine = function(node) { + var line; + while ((node != null) && (dom.BLOCK_TAGS[node.tagName] == null)) { + node = node.parentNode; + } + line = node != null ? dom(node).data(Line.DATA_KEY) : void 0; + if ((line != null ? line.node : void 0) === node) { + return line; + } else { + return void 0; + } + }; + + Document.prototype.findLineAt = function(index) { + var curLine, length; + if (!(this.lines.length > 0)) { + return [void 0, index]; + } + length = this.toDelta().length(); + if (index === length) { + return [this.lines.last, this.lines.last.length]; + } + if (index > length) { + return [void 0, index - length]; + } + curLine = this.lines.first; + while (curLine != null) { + if (index < curLine.length) { + return [curLine, index]; + } + index -= curLine.length; + curLine = curLine.next; + } + return [void 0, index]; + }; + + Document.prototype.getHTML = function() { + return this.root.innerHTML.replace(/\>\s+\ <'); + }; + + Document.prototype.insertLineBefore = function(newLineNode, refLine) { + var line; + line = new Line(this, newLineNode); + if (refLine != null) { + if (!dom(newLineNode.parentNode).isElement()) { + this.root.insertBefore(newLineNode, refLine.node); + } + this.lines.insertAfter(refLine.prev, line); + } else { + if (!dom(newLineNode.parentNode).isElement()) { + this.root.appendChild(newLineNode); + } + this.lines.append(line); + } + return line; + }; + + Document.prototype.mergeLines = function(line, lineToMerge) { + if (lineToMerge.length > 1) { + if (line.length === 1) { + dom(line.leaves.last.node).remove(); + } + _.each(dom(lineToMerge.node).childNodes(), function(child) { + if (child.tagName !== dom.DEFAULT_BREAK_TAG) { + return line.node.appendChild(child); + } + }); + } + this.removeLine(lineToMerge); + return line.rebuild(); + }; + + Document.prototype.optimizeLines = function() { + return _.each(this.lines.toArray(), function(line, i) { + line.optimize(); + return true; + }); + }; + + Document.prototype.rebuild = function() { + var lineNode, lines, results; + lines = this.lines.toArray(); + lineNode = this.root.firstChild; + if ((lineNode != null) && (dom.LIST_TAGS[lineNode.tagName] != null)) { + lineNode = lineNode.firstChild; + } + _.each(lines, (function(_this) { + return function(line, index) { + var newLine, ref; + while (line.node !== lineNode) { + if (line.node.parentNode === _this.root || ((ref = line.node.parentNode) != null ? ref.parentNode : void 0) === _this.root) { + lineNode = _this.normalizer.normalizeLine(lineNode); + newLine = _this.insertLineBefore(lineNode, line); + lineNode = dom(lineNode).nextLineNode(_this.root); + } else { + return _this.removeLine(line); + } + } + if (line.outerHTML !== lineNode.outerHTML) { + line.node = _this.normalizer.normalizeLine(line.node); + line.rebuild(); + } + return lineNode = dom(lineNode).nextLineNode(_this.root); + }; + })(this)); + results = []; + while (lineNode != null) { + lineNode = this.normalizer.normalizeLine(lineNode); + this.appendLine(lineNode); + results.push(lineNode = dom(lineNode).nextLineNode(this.root)); + } + return results; + }; + + Document.prototype.removeLine = function(line) { + if (line.node.parentNode != null) { + if (dom.LIST_TAGS[line.node.parentNode.tagName] && line.node.parentNode.childNodes.length === 1) { + dom(line.node.parentNode).remove(); + } else { + dom(line.node).remove(); + } + } + return this.lines.remove(line); + }; + + Document.prototype.setHTML = function(html) { + html = Normalizer.stripComments(html); + html = Normalizer.stripWhitespace(html); + this.root.innerHTML = html; + this.lines = new LinkedList(); + return this.rebuild(); + }; + + Document.prototype.splitLine = function(line, offset) { + var lineNode1, lineNode2, newLine, ref; + offset = Math.min(offset, line.length - 1); + ref = dom(line.node).split(offset, true), lineNode1 = ref[0], lineNode2 = ref[1]; + line.node = lineNode1; + line.rebuild(); + newLine = this.insertLineBefore(lineNode2, line.next); + newLine.formats = _.clone(line.formats); + newLine.resetContent(); + return newLine; + }; + + Document.prototype.toDelta = function() { + var delta, lines; + lines = this.lines.toArray(); + delta = new Delta(); + _.each(lines, function(line) { + return _.each(line.delta.ops, function(op) { + return delta.push(op); + }); + }); + return delta; + }; + + return Document; + +})(); + +module.exports = Document; + + +},{"../lib/dom":17,"../lib/linked-list":18,"./format":10,"./line":12,"./normalizer":13,"lodash":1,"rich-text/lib/delta":3}],9:[function(_dereq_,module,exports){ +var Delta, Document, Editor, Line, Selection, _, dom; + +_ = _dereq_('lodash'); + +Delta = _dereq_('rich-text/lib/delta'); + +dom = _dereq_('../lib/dom'); + +Document = _dereq_('./document'); + +Line = _dereq_('./line'); + +Selection = _dereq_('./selection'); + +Editor = (function() { + Editor.sources = { + API: 'api', + SILENT: 'silent', + USER: 'user' + }; + + function Editor(root, quill, options) { + this.root = root; + this.quill = quill; + this.options = options != null ? options : {}; + this.root.setAttribute('id', this.options.id); + this.doc = new Document(this.root, this.options); + this.delta = this.doc.toDelta(); + this.length = this.delta.length(); + this.selection = new Selection(this.doc, this.quill); + this.timer = setInterval(_.bind(this.checkUpdate, this), this.options.pollInterval); + this.savedRange = null; + this.quill.on("selection-change", (function(_this) { + return function(range) { + return _this.savedRange = range; + }; + })(this)); + if (!this.options.readOnly) { + this.enable(); + } + } + + Editor.prototype.destroy = function() { + return clearInterval(this.timer); + }; + + Editor.prototype.disable = function() { + return this.enable(false); + }; + + Editor.prototype.enable = function(enabled) { + if (enabled == null) { + enabled = true; + } + return this.root.setAttribute('contenteditable', enabled); + }; + + Editor.prototype.applyDelta = function(delta, source) { + var localDelta; + localDelta = this._update(); + if (localDelta) { + delta = localDelta.transform(delta, true); + localDelta = delta.transform(localDelta, false); + } + if (delta.ops.length > 0) { + delta = this._trackDelta((function(_this) { + return function() { + var index; + index = 0; + _.each(delta.ops, function(op) { + if (_.isString(op.insert)) { + _this._insertAt(index, op.insert, op.attributes); + return index += op.insert.length; + } else if (_.isNumber(op.insert)) { + _this._insertEmbed(index, op.attributes); + return index += 1; + } else if (_.isNumber(op["delete"])) { + return _this._deleteAt(index, op["delete"]); + } else if (_.isNumber(op.retain)) { + _.each(op.attributes, function(value, name) { + return _this._formatAt(index, op.retain, name, value); + }); + return index += op.retain; + } + }); + return _this.selection.shiftAfter(0, 0, _.bind(_this.doc.optimizeLines, _this.doc)); + }; + })(this)); + this.delta = this.doc.toDelta(); + this.length = this.delta.length(); + this.innerHTML = this.root.innerHTML; + if (delta && source !== Editor.sources.SILENT) { + this.quill.emit(this.quill.constructor.events.TEXT_CHANGE, delta, source); + } + } + if (localDelta && localDelta.ops.length > 0 && source !== Editor.sources.SILENT) { + return this.quill.emit(this.quill.constructor.events.TEXT_CHANGE, localDelta, Editor.sources.USER); + } + }; + + Editor.prototype.checkUpdate = function(source) { + var delta; + if (source == null) { + source = 'user'; + } + if (this.root.parentNode == null) { + return clearInterval(this.timer); + } + delta = this._update(); + if (delta) { + this.delta = this.delta.compose(delta); + this.length = this.delta.length(); + this.quill.emit(this.quill.constructor.events.TEXT_CHANGE, delta, source); + } + if (delta) { + source = Editor.sources.SILENT; + } + return this.selection.update(source); + }; + + Editor.prototype.focus = function() { + if (this.selection.range != null) { + return this.selection.setRange(this.selection.range); + } else { + return this.root.focus(); + } + }; + + Editor.prototype.getBounds = function(index) { + var bounds, containerBounds, leaf, offset, range, ref, side; + this.checkUpdate(); + ref = this.doc.findLeafAt(index, true), leaf = ref[0], offset = ref[1]; + if (leaf == null) { + return null; + } + containerBounds = this.root.parentNode.getBoundingClientRect(); + side = 'left'; + if (leaf.length === 0) { + bounds = leaf.node.parentNode.getBoundingClientRect(); + } else if (dom.VOID_TAGS[leaf.node.tagName]) { + bounds = leaf.node.getBoundingClientRect(); + if (offset === 1) { + side = 'right'; + } + } else { + range = document.createRange(); + if (offset < leaf.length) { + range.setStart(leaf.node, offset); + range.setEnd(leaf.node, offset + 1); + } else { + range.setStart(leaf.node, offset - 1); + range.setEnd(leaf.node, offset); + side = 'right'; + } + bounds = range.getBoundingClientRect(); + } + return { + height: bounds.height, + left: bounds[side] - containerBounds.left, + top: bounds.top - containerBounds.top + }; + }; + + Editor.prototype._deleteAt = function(index, length) { + if (length <= 0) { + return; + } + return this.selection.shiftAfter(index, -1 * length, (function(_this) { + return function() { + var curLine, deleteLength, firstLine, mergeFirstLine, nextLine, offset, ref; + ref = _this.doc.findLineAt(index), firstLine = ref[0], offset = ref[1]; + curLine = firstLine; + mergeFirstLine = firstLine.length - offset <= length && offset > 0; + while ((curLine != null) && length > 0) { + nextLine = curLine.next; + deleteLength = Math.min(curLine.length - offset, length); + if (offset === 0 && length >= curLine.length) { + _this.doc.removeLine(curLine); + } else { + curLine.deleteText(offset, deleteLength); + } + length -= deleteLength; + curLine = nextLine; + offset = 0; + } + if (mergeFirstLine && firstLine.next) { + return _this.doc.mergeLines(firstLine, firstLine.next); + } + }; + })(this)); + }; + + Editor.prototype._formatAt = function(index, length, name, value) { + return this.selection.shiftAfter(index, 0, (function(_this) { + return function() { + var formatLength, line, offset, ref, results; + ref = _this.doc.findLineAt(index), line = ref[0], offset = ref[1]; + results = []; + while ((line != null) && length > 0) { + formatLength = Math.min(length, line.length - offset - 1); + line.formatText(offset, formatLength, name, value); + length -= formatLength; + if (length > 0) { + line.format(name, value); + } + length -= 1; + offset = 0; + results.push(line = line.next); + } + return results; + }; + })(this)); + }; + + Editor.prototype._insertEmbed = function(index, attributes) { + return this.selection.shiftAfter(index, 1, (function(_this) { + return function() { + var line, offset, ref; + ref = _this.doc.findLineAt(index), line = ref[0], offset = ref[1]; + return line.insertEmbed(offset, attributes); + }; + })(this)); + }; + + Editor.prototype._insertAt = function(index, text, formatting) { + if (formatting == null) { + formatting = {}; + } + return this.selection.shiftAfter(index, text.length, (function(_this) { + return function() { + var line, lineTexts, offset, ref; + text = text.replace(/\r\n?/g, '\n'); + lineTexts = text.split('\n'); + ref = _this.doc.findLineAt(index), line = ref[0], offset = ref[1]; + return _.each(lineTexts, function(lineText, i) { + var nextLine; + if ((line == null) || line.length <= offset) { + if (i < lineTexts.length - 1 || lineText.length > 0) { + line = _this.doc.appendLine(document.createElement(dom.DEFAULT_BLOCK_TAG)); + offset = 0; + line.insertText(offset, lineText, formatting); + line.format(formatting); + nextLine = null; + } + } else { + line.insertText(offset, lineText, formatting); + if (i < lineTexts.length - 1) { + nextLine = _this.doc.splitLine(line, offset + lineText.length); + _.each(_.defaults({}, formatting, line.formats), function(value, format) { + return line.format(format, formatting[format]); + }); + offset = 0; + } + } + return line = nextLine; + }); + }; + })(this)); + }; + + Editor.prototype._trackDelta = function(fn) { + var ignored, newDelta, newIndex, newLeftDelta, newRightDelta, oldIndex, oldLeftDelta, oldRightDelta, ref, ref1; + oldIndex = (ref = this.savedRange) != null ? ref.start : void 0; + fn(); + newDelta = this.doc.toDelta(); + this.savedRange = this.selection.getRange(); + newIndex = (ref1 = this.savedRange) != null ? ref1.start : void 0; + try { + if ((oldIndex != null) && (newIndex != null) && oldIndex <= this.delta.length() && newIndex <= newDelta.length()) { + oldRightDelta = this.delta.slice(oldIndex); + newRightDelta = newDelta.slice(newIndex); + if (_.isEqual(oldRightDelta.ops, newRightDelta.ops)) { + oldLeftDelta = this.delta.slice(0, oldIndex); + newLeftDelta = newDelta.slice(0, newIndex); + return oldLeftDelta.diff(newLeftDelta); + } + } + } catch (_error) { + ignored = _error; + } + return this.delta.diff(newDelta); + }; + + Editor.prototype._update = function() { + var delta; + if (this.innerHTML === this.root.innerHTML) { + return false; + } + delta = this._trackDelta((function(_this) { + return function() { + _this.selection.preserve(_.bind(_this.doc.rebuild, _this.doc)); + return _this.selection.shiftAfter(0, 0, _.bind(_this.doc.optimizeLines, _this.doc)); + }; + })(this)); + this.innerHTML = this.root.innerHTML; + if (delta.ops.length > 0) { + return delta; + } else { + return false; + } + }; + + return Editor; + +})(); + +module.exports = Editor; + + +},{"../lib/dom":17,"./document":8,"./line":12,"./selection":14,"lodash":1,"rich-text/lib/delta":3}],10:[function(_dereq_,module,exports){ +var Format, _, dom; + +_ = _dereq_('lodash'); + +dom = _dereq_('../lib/dom'); + +Format = (function() { + Format.types = { + LINE: 'line', + EMBED: 'embed' + }; + + Format.FORMATS = { + bold: { + tag: 'B', + prepare: 'bold' + }, + italic: { + tag: 'I', + prepare: 'italic' + }, + underline: { + tag: 'U', + prepare: 'underline' + }, + strike: { + tag: 'S', + prepare: 'strikeThrough' + }, + color: { + style: 'color', + "default": 'rgb(0, 0, 0)', + prepare: 'foreColor' + }, + background: { + style: 'backgroundColor', + "default": 'rgb(255, 255, 255)', + prepare: 'backColor' + }, + font: { + style: 'fontFamily', + "default": "'Helvetica', 'Arial', sans-serif", + prepare: 'fontName' + }, + size: { + style: 'fontSize', + "default": '13px', + prepare: function(value) { + return document.execCommand('fontSize', false, dom.convertFontSize(value)); + } + }, + link: { + tag: 'A', + add: function(node, value) { + node.setAttribute('href', value); + return node; + }, + remove: function(node) { + node.removeAttribute('href'); + return node; + }, + value: function(node) { + return node.getAttribute('href'); + } + }, + image: { + type: Format.types.EMBED, + tag: 'IMG', + attribute: 'src' + }, + align: { + type: Format.types.LINE, + style: 'textAlign', + "default": 'left' + }, + bullet: { + type: Format.types.LINE, + exclude: 'list', + parentTag: 'UL', + tag: 'LI' + }, + list: { + type: Format.types.LINE, + exclude: 'bullet', + parentTag: 'OL', + tag: 'LI' + } + }; + + function Format(config) { + this.config = config; + } + + Format.prototype.add = function(node, value) { + var formatNode, inline, parentNode, ref, ref1; + if (!value) { + return this.remove(node); + } + if (this.value(node) === value) { + return node; + } + if (_.isString(this.config.parentTag)) { + parentNode = node.parentNode; + if (parentNode.tagName !== this.config.parentTag) { + parentNode = document.createElement(this.config.parentTag); + dom(node).wrap(parentNode); + } + if (node.parentNode.tagName === ((ref = node.parentNode.previousSibling) != null ? ref.tagName : void 0)) { + dom(node.parentNode.previousSibling).merge(node.parentNode); + } + if (node.parentNode.tagName === ((ref1 = node.parentNode.nextSibling) != null ? ref1.tagName : void 0)) { + dom(node.parentNode).merge(node.parentNode.nextSibling); + } + } + if (_.isString(this.config.tag) && node.tagName !== this.config.tag) { + formatNode = document.createElement(this.config.tag); + if (dom.VOID_TAGS[formatNode.tagName] != null) { + if (node.parentNode != null) { + dom(node).replace(formatNode); + } + node = formatNode; + } else if (this.isType(Format.types.LINE)) { + node = dom(node).switchTag(this.config.tag).get(); + } else { + dom(node).wrap(formatNode); + node = formatNode; + } + } + if (_.isString(this.config.style) || _.isString(this.config.attribute) || _.isString(this.config["class"])) { + if (_.isString(this.config["class"])) { + node = this.remove(node); + } + if (dom(node).isTextNode()) { + inline = document.createElement(dom.DEFAULT_INLINE_TAG); + dom(node).wrap(inline); + node = inline; + } + if (_.isString(this.config.style)) { + if (value !== this.config["default"]) { + node.style[this.config.style] = value; + } + } + if (_.isString(this.config.attribute)) { + node.setAttribute(this.config.attribute, value); + } + if (_.isString(this.config["class"])) { + dom(node).addClass(this.config["class"] + value); + } + } + if (_.isFunction(this.config.add)) { + node = this.config.add(node, value); + } + return node; + }; + + Format.prototype.isType = function(type) { + return type === this.config.type; + }; + + Format.prototype.match = function(node) { + var c, i, len, ref, ref1; + if (!dom(node).isElement()) { + return false; + } + if (_.isString(this.config.parentTag) && ((ref = node.parentNode) != null ? ref.tagName : void 0) !== this.config.parentTag) { + return false; + } + if (_.isString(this.config.tag) && node.tagName !== this.config.tag) { + return false; + } + if (_.isString(this.config.style) && (!node.style[this.config.style] || node.style[this.config.style] === this.config["default"])) { + return false; + } + if (_.isString(this.config.attribute) && !node.hasAttribute(this.config.attribute)) { + return false; + } + if (_.isString(this.config["class"])) { + ref1 = dom(node).classes(); + for (i = 0, len = ref1.length; i < len; i++) { + c = ref1[i]; + if (c.indexOf(this.config["class"]) === 0) { + return true; + } + } + return false; + } + return true; + }; + + Format.prototype.prepare = function(value) { + if (_.isString(this.config.prepare)) { + return document.execCommand(this.config.prepare, false, value); + } else if (_.isFunction(this.config.prepare)) { + return this.config.prepare(value); + } + }; + + Format.prototype.remove = function(node) { + var c, i, len, ref; + if (!this.match(node)) { + return node; + } + if (_.isString(this.config.style)) { + node.style[this.config.style] = ''; + if (!node.getAttribute('style')) { + node.removeAttribute('style'); + } + } + if (_.isString(this.config.attribute)) { + node.removeAttribute(this.config.attribute); + } + if (_.isString(this.config["class"])) { + ref = dom(node).classes(); + for (i = 0, len = ref.length; i < len; i++) { + c = ref[i]; + if (c.indexOf(this.config["class"]) === 0) { + dom(node).removeClass(c); + } + } + } + if (_.isString(this.config.tag)) { + if (this.isType(Format.types.LINE)) { + if (_.isString(this.config.parentTag)) { + if (node.previousSibling != null) { + dom(node).splitBefore(node.parentNode.parentNode); + } + if (node.nextSibling != null) { + dom(node.nextSibling).splitBefore(node.parentNode.parentNode); + } + } + node = dom(node).switchTag(dom.DEFAULT_BLOCK_TAG).get(); + } else if (this.isType(Format.types.EMBED)) { + dom(node).remove(); + return void 0; + } else { + node = dom(node).switchTag(dom.DEFAULT_INLINE_TAG).get(); + } + } + if (_.isString(this.config.parentTag)) { + dom(node.parentNode).unwrap(); + } + if (_.isFunction(this.config.remove)) { + node = this.config.remove(node); + } + if (node.tagName === dom.DEFAULT_INLINE_TAG && !node.hasAttributes()) { + node = dom(node).unwrap(); + } + return node; + }; + + Format.prototype.value = function(node) { + var c, i, len, ref; + if (!this.match(node)) { + return void 0; + } + if (this.config.value) { + return this.config.value(node); + } + if (_.isString(this.config.attribute)) { + return node.getAttribute(this.config.attribute) || void 0; + } else if (_.isString(this.config.style)) { + return node.style[this.config.style] || void 0; + } else if (_.isString(this.config["class"])) { + ref = dom(node).classes(); + for (i = 0, len = ref.length; i < len; i++) { + c = ref[i]; + if (c.indexOf(this.config["class"]) === 0) { + return c.slice(this.config["class"].length); + } + } + } else if (_.isString(this.config.tag)) { + return true; + } + return void 0; + }; + + return Format; + +})(); + +module.exports = Format; + + +},{"../lib/dom":17,"lodash":1}],11:[function(_dereq_,module,exports){ +var Format, Leaf, LinkedList, _, dom, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +_ = _dereq_('lodash'); + +dom = _dereq_('../lib/dom'); + +Format = _dereq_('./format'); + +LinkedList = _dereq_('../lib/linked-list'); + +Leaf = (function(superClass) { + extend(Leaf, superClass); + + Leaf.DATA_KEY = 'leaf'; + + Leaf.isLeafNode = function(node) { + return dom(node).isTextNode() || (node.firstChild == null); + }; + + function Leaf(node1, formats) { + this.node = node1; + this.formats = _.clone(formats); + this.text = dom(this.node).text(); + this.length = this.text.length; + dom(this.node).data(Leaf.DATA_KEY, this); + } + + Leaf.prototype.deleteText = function(offset, length) { + var textNode; + if (!(length > 0)) { + return; + } + this.text = this.text.slice(0, offset) + this.text.slice(offset + length); + this.length = this.text.length; + if (dom.EMBED_TAGS[this.node.tagName] != null) { + textNode = document.createTextNode(this.text); + dom(textNode).data(Leaf.DATA_KEY, this); + return this.node = dom(this.node).replace(textNode).get(); + } else { + return dom(this.node).text(this.text); + } + }; + + Leaf.prototype.insertText = function(offset, text) { + var textNode; + this.text = this.text.slice(0, offset) + text + this.text.slice(offset); + if (dom(this.node).isTextNode()) { + dom(this.node).text(this.text); + } else { + textNode = document.createTextNode(text); + dom(textNode).data(Leaf.DATA_KEY, this); + if (this.node.tagName === dom.DEFAULT_BREAK_TAG) { + this.node = dom(this.node).replace(textNode).get(); + } else { + this.node.appendChild(textNode); + this.node = textNode; + } + } + return this.length = this.text.length; + }; + + return Leaf; + +})(LinkedList.Node); + +module.exports = Leaf; + + +},{"../lib/dom":17,"../lib/linked-list":18,"./format":10,"lodash":1}],12:[function(_dereq_,module,exports){ +var Delta, Format, Leaf, Line, LinkedList, Normalizer, _, dom, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +_ = _dereq_('lodash'); + +Delta = _dereq_('rich-text/lib/delta'); + +dom = _dereq_('../lib/dom'); + +Format = _dereq_('./format'); + +Leaf = _dereq_('./leaf'); + +Line = _dereq_('./line'); + +LinkedList = _dereq_('../lib/linked-list'); + +Normalizer = _dereq_('./normalizer'); + +Line = (function(superClass) { + extend(Line, superClass); + + Line.DATA_KEY = 'line'; + + function Line(doc, node1) { + this.doc = doc; + this.node = node1; + this.formats = {}; + this.rebuild(); + Line.__super__.constructor.call(this, this.node); + } + + Line.prototype.buildLeaves = function(node, formats) { + return _.each(dom(node).childNodes(), (function(_this) { + return function(node) { + var nodeFormats; + node = _this.doc.normalizer.normalizeNode(node); + nodeFormats = _.clone(formats); + _.each(_this.doc.formats, function(format, name) { + if (!format.isType(Format.types.LINE) && format.match(node)) { + return nodeFormats[name] = format.value(node); + } + }); + if (Leaf.isLeafNode(node)) { + return _this.leaves.append(new Leaf(node, nodeFormats)); + } else { + return _this.buildLeaves(node, nodeFormats); + } + }; + })(this)); + }; + + Line.prototype.deleteText = function(offset, length) { + var deleteLength, leaf, ref; + if (!(length > 0)) { + return; + } + ref = this.findLeafAt(offset), leaf = ref[0], offset = ref[1]; + while ((leaf != null) && length > 0) { + deleteLength = Math.min(length, leaf.length - offset); + leaf.deleteText(offset, deleteLength); + length -= deleteLength; + leaf = leaf.next; + offset = 0; + } + return this.rebuild(); + }; + + Line.prototype.findLeaf = function(leafNode) { + if (leafNode != null) { + return dom(leafNode).data(Leaf.DATA_KEY); + } else { + return void 0; + } + }; + + Line.prototype.findLeafAt = function(offset, inclusive) { + var leaf; + if (inclusive == null) { + inclusive = false; + } + if (offset >= this.length - 1) { + return [this.leaves.last, this.leaves.last.length]; + } + leaf = this.leaves.first; + while (leaf != null) { + if (offset < leaf.length || (offset === leaf.length && inclusive)) { + return [leaf, offset]; + } + offset -= leaf.length; + leaf = leaf.next; + } + return [this.leaves.last, offset - this.leaves.last.length]; + }; + + Line.prototype.format = function(name, value) { + var formats; + if (_.isObject(name)) { + formats = name; + } else { + formats = {}; + formats[name] = value; + } + _.each(formats, (function(_this) { + return function(value, name) { + var excludeFormat, format; + format = _this.doc.formats[name]; + if (format == null) { + return; + } + if (format.isType(Format.types.LINE)) { + if (format.config.exclude && _this.formats[format.config.exclude]) { + excludeFormat = _this.doc.formats[format.config.exclude]; + if (excludeFormat != null) { + _this.node = excludeFormat.remove(_this.node); + delete _this.formats[format.config.exclude]; + } + } + _this.node = format.add(_this.node, value); + } + if (value) { + return _this.formats[name] = value; + } else { + return delete _this.formats[name]; + } + }; + })(this)); + return this.resetContent(); + }; + + Line.prototype.formatText = function(offset, length, name, value) { + var format, leaf, leafOffset, leftNode, nextLeaf, ref, ref1, ref2, rightNode, targetNode; + ref = this.findLeafAt(offset), leaf = ref[0], leafOffset = ref[1]; + format = this.doc.formats[name]; + if (!((format != null) && format.config.type !== Format.types.LINE)) { + return; + } + while ((leaf != null) && length > 0) { + nextLeaf = leaf.next; + if ((value && leaf.formats[name] !== value) || (!value && (leaf.formats[name] != null))) { + targetNode = leaf.node; + if (leaf.formats[name] != null) { + dom(targetNode).splitBefore(this.node); + while (!format.match(targetNode)) { + targetNode = targetNode.parentNode; + } + dom(targetNode).split(leaf.length); + } + if (leafOffset > 0) { + ref1 = dom(targetNode).split(leafOffset), leftNode = ref1[0], targetNode = ref1[1]; + } + if (leaf.length > leafOffset + length) { + ref2 = dom(targetNode).split(length), targetNode = ref2[0], rightNode = ref2[1]; + } + format.add(targetNode, value); + } + length -= leaf.length - leafOffset; + leafOffset = 0; + leaf = nextLeaf; + } + return this.rebuild(); + }; + + Line.prototype._insert = function(offset, node, formats) { + var leaf, leafOffset, nextNode, prevNode, ref, ref1; + ref = this.findLeafAt(offset), leaf = ref[0], leafOffset = ref[1]; + node = _.reduce(formats, (function(_this) { + return function(node, value, name) { + var format; + format = _this.doc.formats[name]; + if ((format != null) && !format.isType(Format.types.LINE)) { + node = format.add(node, value); + } + return node; + }; + })(this), node); + ref1 = dom(leaf.node).split(leafOffset), prevNode = ref1[0], nextNode = ref1[1]; + if (nextNode) { + nextNode = dom(nextNode).splitBefore(this.node).get(); + } + this.node.insertBefore(node, nextNode); + return this.rebuild(); + }; + + Line.prototype.insertEmbed = function(offset, attributes) { + var formatName, leaf, leafOffset, nextNode, node, prevNode, ref, ref1; + ref = this.findLeafAt(offset), leaf = ref[0], leafOffset = ref[1]; + ref1 = dom(leaf.node).split(leafOffset), prevNode = ref1[0], nextNode = ref1[1]; + formatName = _.find(Object.keys(attributes), (function(_this) { + return function(name) { + return _this.doc.formats[name].isType(Format.types.EMBED); + }; + })(this)); + node = this.doc.formats[formatName].add({}, attributes[formatName]); + attributes = _.clone(attributes); + delete attributes[formatName]; + return this._insert(offset, node, attributes); + }; + + Line.prototype.insertText = function(offset, text, formats) { + var leaf, leafOffset, ref; + if (formats == null) { + formats = {}; + } + if (!(text.length > 0)) { + return; + } + ref = this.findLeafAt(offset), leaf = ref[0], leafOffset = ref[1]; + if (_.isEqual(leaf.formats, formats)) { + leaf.insertText(leafOffset, text); + return this.resetContent(); + } else { + return this._insert(offset, document.createTextNode(text), formats); + } + }; + + Line.prototype.optimize = function() { + Normalizer.optimizeLine(this.node); + return this.rebuild(); + }; + + Line.prototype.rebuild = function(force) { + if (force == null) { + force = false; + } + if (!force && (this.outerHTML != null) && this.outerHTML === this.node.outerHTML) { + if (_.all(this.leaves.toArray(), (function(_this) { + return function(leaf) { + return dom(leaf.node).isAncestor(_this.node); + }; + })(this))) { + return false; + } + } + this.node = this.doc.normalizer.normalizeNode(this.node); + if (dom(this.node).length() === 0 && !this.node.querySelector(dom.DEFAULT_BREAK_TAG)) { + this.node.appendChild(document.createElement(dom.DEFAULT_BREAK_TAG)); + } + this.leaves = new LinkedList(); + this.formats = _.reduce(this.doc.formats, (function(_this) { + return function(formats, format, name) { + if (format.isType(Format.types.LINE)) { + if (format.match(_this.node)) { + formats[name] = format.value(_this.node); + } else { + delete formats[name]; + } + } + return formats; + }; + })(this), this.formats); + this.buildLeaves(this.node, {}); + this.resetContent(); + return true; + }; + + Line.prototype.resetContent = function() { + dom(this.node).data(Line.DATA_KEY, this); + this.outerHTML = this.node.outerHTML; + this.length = 1; + this.delta = new Delta(); + _.each(this.leaves.toArray(), (function(_this) { + return function(leaf) { + _this.length += leaf.length; + if (dom.EMBED_TAGS[leaf.node.tagName] != null) { + return _this.delta.insert(1, leaf.formats); + } else { + return _this.delta.insert(leaf.text, leaf.formats); + } + }; + })(this)); + return this.delta.insert('\n', this.formats); + }; + + return Line; + +})(LinkedList.Node); + +module.exports = Line; + + +},{"../lib/dom":17,"../lib/linked-list":18,"./format":10,"./leaf":11,"./line":12,"./normalizer":13,"lodash":1,"rich-text/lib/delta":3}],13:[function(_dereq_,module,exports){ +var Normalizer, _, camelize, dom; + +_ = _dereq_('lodash'); + +dom = _dereq_('../lib/dom'); + +camelize = function(str) { + str = str.replace(/(?:^|[-_])(\w)/g, function(i, c) { + if (c) { + return c.toUpperCase(); + } else { + return ''; + } + }); + return str.charAt(0).toLowerCase() + str.slice(1); +}; + +Normalizer = (function() { + Normalizer.ALIASES = { + 'STRONG': 'B', + 'EM': 'I', + 'DEL': 'S', + 'STRIKE': 'S' + }; + + Normalizer.ATTRIBUTES = { + 'color': 'color', + 'face': 'fontFamily', + 'size': 'fontSize' + }; + + function Normalizer() { + this.whitelist = { + styles: {}, + tags: {} + }; + this.whitelist.tags[dom.DEFAULT_BREAK_TAG] = true; + this.whitelist.tags[dom.DEFAULT_BLOCK_TAG] = true; + this.whitelist.tags[dom.DEFAULT_INLINE_TAG] = true; + } + + Normalizer.prototype.addFormat = function(config) { + if (config.tag != null) { + this.whitelist.tags[config.tag] = true; + } + if (config.parentTag != null) { + this.whitelist.tags[config.parentTag] = true; + } + if (config.style != null) { + return this.whitelist.styles[config.style] = true; + } + }; + + Normalizer.prototype.normalizeLine = function(lineNode) { + lineNode = Normalizer.wrapInline(lineNode); + lineNode = Normalizer.handleBreaks(lineNode); + if (lineNode.tagName === 'LI') { + Normalizer.flattenList(lineNode); + } + lineNode = Normalizer.pullBlocks(lineNode); + lineNode = this.normalizeNode(lineNode); + Normalizer.unwrapText(lineNode); + if ((lineNode != null) && (dom.LIST_TAGS[lineNode.tagName] != null)) { + lineNode = lineNode.firstChild; + } + return lineNode; + }; + + Normalizer.prototype.normalizeNode = function(node) { + if (dom(node).isTextNode()) { + return node; + } + _.each(Normalizer.ATTRIBUTES, function(style, attribute) { + var value; + if (node.hasAttribute(attribute)) { + value = node.getAttribute(attribute); + if (attribute === 'size') { + value = dom.convertFontSize(value); + } + node.style[style] = value; + return node.removeAttribute(attribute); + } + }); + if (node.style.fontWeight === 'bold' || node.style.fontWeight > 500) { + node.style.fontWeight = ''; + dom(node).wrap(document.createElement('b')); + node = node.parentNode; + } + this.whitelistStyles(node); + return this.whitelistTags(node); + }; + + Normalizer.prototype.whitelistStyles = function(node) { + var original, styles; + original = dom(node).styles(); + styles = _.omit(original, (function(_this) { + return function(value, key) { + return _this.whitelist.styles[camelize(key)] == null; + }; + })(this)); + if (Object.keys(styles).length < Object.keys(original).length) { + if (Object.keys(styles).length > 0) { + return dom(node).styles(styles, true); + } else { + return node.removeAttribute('style'); + } + } + }; + + Normalizer.prototype.whitelistTags = function(node) { + if (!dom(node).isElement()) { + return node; + } + if (Normalizer.ALIASES[node.tagName] != null) { + node = dom(node).switchTag(Normalizer.ALIASES[node.tagName]).get(); + } else if (this.whitelist.tags[node.tagName] == null) { + if (dom.BLOCK_TAGS[node.tagName] != null) { + node = dom(node).switchTag(dom.DEFAULT_BLOCK_TAG).get(); + } else if (!node.hasAttributes() && (node.firstChild != null)) { + node = dom(node).unwrap(); + } else { + node = dom(node).switchTag(dom.DEFAULT_INLINE_TAG).get(); + } + } + return node; + }; + + Normalizer.flattenList = function(listNode) { + var innerItems, innerLists, ref; + ref = listNode.nextSibling; + innerItems = _.map(listNode.querySelectorAll('li')); + innerItems.forEach(function(item) { + listNode.parentNode.insertBefore(item, ref); + return ref = item.nextSibling; + }); + innerLists = _.map(listNode.querySelectorAll(Object.keys(dom.LIST_TAGS).join(','))); + return innerLists.forEach(function(list) { + return dom(list).remove(); + }); + }; + + Normalizer.handleBreaks = function(lineNode) { + var breaks; + breaks = _.map(lineNode.querySelectorAll(dom.DEFAULT_BREAK_TAG)); + _.each(breaks, (function(_this) { + return function(br) { + if ((br.nextSibling != null) && (!dom.isIE(10) || (br.previousSibling != null))) { + return dom(br.nextSibling).splitBefore(lineNode.parentNode); + } + }; + })(this)); + return lineNode; + }; + + Normalizer.optimizeLine = function(lineNode) { + var lineNodeLength, node, nodes, results; + lineNode.normalize(); + lineNodeLength = dom(lineNode).length(); + nodes = dom(lineNode).descendants(); + results = []; + while (nodes.length > 0) { + node = nodes.pop(); + if ((node != null ? node.parentNode : void 0) == null) { + continue; + } + if (dom.EMBED_TAGS[node.tagName] != null) { + continue; + } + if (node.tagName === dom.DEFAULT_BREAK_TAG) { + if (lineNodeLength !== 0) { + results.push(dom(node).remove()); + } else { + results.push(void 0); + } + } else if (dom(node).length() === 0) { + nodes.push(node.nextSibling); + results.push(dom(node).unwrap()); + } else if ((node.previousSibling != null) && node.tagName === node.previousSibling.tagName) { + if (_.isEqual(dom(node).attributes(), dom(node.previousSibling).attributes())) { + nodes.push(node.firstChild); + results.push(dom(node.previousSibling).merge(node)); + } else { + results.push(void 0); + } + } else { + results.push(void 0); + } + } + return results; + }; + + Normalizer.pullBlocks = function(lineNode) { + var curNode; + curNode = lineNode.firstChild; + while (curNode != null) { + if ((dom.BLOCK_TAGS[curNode.tagName] != null) && curNode.tagName !== 'LI') { + dom(curNode).isolate(lineNode.parentNode); + if ((dom.LIST_TAGS[curNode.tagName] == null) || !curNode.firstChild) { + dom(curNode).unwrap(); + Normalizer.pullBlocks(lineNode); + } else { + dom(curNode.parentNode).unwrap(); + if (lineNode.parentNode == null) { + lineNode = curNode; + } + } + break; + } + curNode = curNode.nextSibling; + } + return lineNode; + }; + + Normalizer.stripComments = function(html) { + return html.replace(//g, ''); + }; + + Normalizer.stripWhitespace = function(html) { + html = html.trim(); + html = html.replace(/(\r?\n|\r)+/g, ' '); + html = html.replace(/\>\s+\<'); + return html; + }; + + Normalizer.wrapInline = function(lineNode) { + var blockNode, nextNode; + if (dom.BLOCK_TAGS[lineNode.tagName] != null) { + return lineNode; + } + blockNode = document.createElement(dom.DEFAULT_BLOCK_TAG); + lineNode.parentNode.insertBefore(blockNode, lineNode); + while ((lineNode != null) && (dom.BLOCK_TAGS[lineNode.tagName] == null)) { + nextNode = lineNode.nextSibling; + blockNode.appendChild(lineNode); + lineNode = nextNode; + } + return blockNode; + }; + + Normalizer.unwrapText = function(lineNode) { + var spans; + spans = _.map(lineNode.querySelectorAll(dom.DEFAULT_INLINE_TAG)); + return _.each(spans, function(span) { + if (!span.hasAttributes()) { + return dom(span).unwrap(); + } + }); + }; + + return Normalizer; + +})(); + +module.exports = Normalizer; + + +},{"../lib/dom":17,"lodash":1}],14:[function(_dereq_,module,exports){ +var Leaf, Normalizer, Range, Selection, _, dom; + +_ = _dereq_('lodash'); + +dom = _dereq_('../lib/dom'); + +Leaf = _dereq_('./leaf'); + +Normalizer = _dereq_('./normalizer'); + +Range = _dereq_('../lib/range'); + +Selection = (function() { + function Selection(doc, emitter) { + this.doc = doc; + this.emitter = emitter; + this.focus = false; + this.range = new Range(0, 0); + this.nullDelay = false; + this.update('silent'); + } + + Selection.prototype.checkFocus = function() { + return document.activeElement === this.doc.root; + }; + + Selection.prototype.getRange = function(ignoreFocus) { + var end, nativeRange, start; + if (ignoreFocus == null) { + ignoreFocus = false; + } + if (this.checkFocus()) { + nativeRange = this._getNativeRange(); + if (nativeRange == null) { + return null; + } + start = this._positionToIndex(nativeRange.startContainer, nativeRange.startOffset); + if (nativeRange.startContainer === nativeRange.endContainer && nativeRange.startOffset === nativeRange.endOffset) { + end = start; + } else { + end = this._positionToIndex(nativeRange.endContainer, nativeRange.endOffset); + } + return new Range(Math.min(start, end), Math.max(start, end)); + } else if (ignoreFocus) { + return this.range; + } else { + return null; + } + }; + + Selection.prototype.preserve = function(fn) { + var endNode, endOffset, nativeRange, ref, ref1, ref2, ref3, startNode, startOffset; + nativeRange = this._getNativeRange(); + if ((nativeRange != null) && this.checkFocus()) { + ref = this._encodePosition(nativeRange.startContainer, nativeRange.startOffset), startNode = ref[0], startOffset = ref[1]; + ref1 = this._encodePosition(nativeRange.endContainer, nativeRange.endOffset), endNode = ref1[0], endOffset = ref1[1]; + fn(); + ref2 = this._decodePosition(startNode, startOffset), startNode = ref2[0], startOffset = ref2[1]; + ref3 = this._decodePosition(endNode, endOffset), endNode = ref3[0], endOffset = ref3[1]; + return this._setNativeRange(startNode, startOffset, endNode, endOffset); + } else { + return fn(); + } + }; + + Selection.prototype.scrollIntoView = function() { + var containerBounds, containerHeight, editor, endBounds, line, offset, ref, ref1, startBounds; + if (!this.range) { + return; + } + editor = this.emitter.editor; + startBounds = editor.getBounds(this.range.start); + endBounds = this.range.isCollapsed() ? startBounds : editor.getBounds(this.range.end); + containerBounds = editor.root.parentNode.getBoundingClientRect(); + containerHeight = containerBounds.bottom - containerBounds.top; + if (containerHeight < endBounds.top + endBounds.height) { + ref = editor.doc.findLineAt(this.range.end), line = ref[0], offset = ref[1]; + return line.node.scrollIntoView(false); + } else if (startBounds.top < 0) { + ref1 = editor.doc.findLineAt(this.range.start), line = ref1[0], offset = ref1[1]; + return line.node.scrollIntoView(); + } + }; + + Selection.prototype.setRange = function(range, source) { + var endNode, endOffset, ref, ref1, ref2, startNode, startOffset; + if (range != null) { + ref = this._indexToPosition(range.start), startNode = ref[0], startOffset = ref[1]; + if (range.isCollapsed()) { + ref1 = [startNode, startOffset], endNode = ref1[0], endOffset = ref1[1]; + } else { + ref2 = this._indexToPosition(range.end), endNode = ref2[0], endOffset = ref2[1]; + } + this._setNativeRange(startNode, startOffset, endNode, endOffset); + } else { + this._setNativeRange(null); + } + return this.update(source); + }; + + Selection.prototype.shiftAfter = function(index, length, fn) { + var range; + range = this.getRange(); + fn(); + if (range != null) { + range.shift(index, length); + return this.setRange(range, 'silent'); + } + }; + + Selection.prototype.update = function(source) { + var emit, focus, range, toEmit; + focus = this.checkFocus(); + range = this.getRange(true); + emit = source !== 'silent' && (!Range.compare(range, this.range) || focus !== this.focus); + toEmit = focus ? range : null; + if (toEmit === null && source === 'user' && !this.nullDelay) { + return this.nullDelay = true; + } else { + this.nullDelay = false; + this.range = range; + this.focus = focus; + if (emit) { + return this.emitter.emit(this.emitter.constructor.events.SELECTION_CHANGE, toEmit, source); + } + } + }; + + Selection.prototype._decodePosition = function(node, offset) { + var childIndex; + if (dom(node).isElement()) { + childIndex = dom(node.parentNode).childNodes().indexOf(node); + offset += childIndex; + node = node.parentNode; + } + return [node, offset]; + }; + + Selection.prototype._encodePosition = function(node, offset) { + var text; + while (true) { + if (dom(node).isTextNode() || node.tagName === dom.DEFAULT_BREAK_TAG || (dom.EMBED_TAGS[node.tagName] != null)) { + return [node, offset]; + } else if (offset < node.childNodes.length) { + node = node.childNodes[offset]; + offset = 0; + } else if (node.childNodes.length === 0) { + if (this.doc.normalizer.whitelist.tags[node.tagName] == null) { + text = document.createTextNode(''); + node.appendChild(text); + node = text; + } + return [node, 0]; + } else { + node = node.lastChild; + if (dom(node).isElement()) { + if (node.tagName === dom.DEFAULT_BREAK_TAG || (dom.EMBED_TAGS[node.tagName] != null)) { + return [node, 1]; + } else { + offset = node.childNodes.length; + } + } else { + return [node, dom(node).length()]; + } + } + } + }; + + Selection.prototype._getNativeRange = function() { + var range, selection; + selection = document.getSelection(); + if ((selection != null ? selection.rangeCount : void 0) > 0) { + range = selection.getRangeAt(0); + if (dom(range.startContainer).isAncestor(this.doc.root, true)) { + if (range.startContainer === range.endContainer || dom(range.endContainer).isAncestor(this.doc.root, true)) { + return range; + } + } + } + return null; + }; + + Selection.prototype._indexToPosition = function(index) { + var leaf, offset, ref; + if (this.doc.lines.length === 0) { + return [this.doc.root, 0]; + } + ref = this.doc.findLeafAt(index, true), leaf = ref[0], offset = ref[1]; + return this._decodePosition(leaf.node, offset); + }; + + Selection.prototype._positionToIndex = function(node, offset) { + var leaf, leafNode, leafOffset, line, lineOffset, ref; + if (dom.isIE(10) && node.tagName === 'BR' && offset === 1) { + offset = 0; + } + ref = this._encodePosition(node, offset), leafNode = ref[0], offset = ref[1]; + line = this.doc.findLine(leafNode); + if (line == null) { + return 0; + } + leaf = line.findLeaf(leafNode); + lineOffset = 0; + while (line.prev != null) { + line = line.prev; + lineOffset += line.length; + } + if (leaf == null) { + return lineOffset; + } + leafOffset = 0; + while (leaf.prev != null) { + leaf = leaf.prev; + leafOffset += leaf.length; + } + return lineOffset + leafOffset + offset; + }; + + Selection.prototype._setNativeRange = function(startNode, startOffset, endNode, endOffset) { + var nativeRange, selection; + selection = document.getSelection(); + if (!selection) { + return; + } + if (startNode != null) { + if (!this.checkFocus()) { + this.doc.root.focus(); + } + nativeRange = this._getNativeRange(); + if ((nativeRange == null) || startNode !== nativeRange.startContainer || startOffset !== nativeRange.startOffset || endNode !== nativeRange.endContainer || endOffset !== nativeRange.endOffset) { + selection.removeAllRanges(); + nativeRange = document.createRange(); + nativeRange.setStart(startNode, startOffset); + nativeRange.setEnd(endNode, endOffset); + return selection.addRange(nativeRange); + } + } else { + selection.removeAllRanges(); + this.doc.root.blur(); + if (dom.isIE(11) && !dom.isIE(9)) { + return document.body.focus(); + } + } + }; + + return Selection; + +})(); + +module.exports = Selection; + + +},{"../lib/dom":17,"../lib/range":20,"./leaf":11,"./normalizer":13,"lodash":1}],15:[function(_dereq_,module,exports){ +_dereq_('./modules/authorship'); + +_dereq_('./modules/image-tooltip'); + +_dereq_('./modules/keyboard'); + +_dereq_('./modules/link-tooltip'); + +_dereq_('./modules/multi-cursor'); + +_dereq_('./modules/paste-manager'); + +_dereq_('./modules/toolbar'); + +_dereq_('./modules/tooltip'); + +_dereq_('./modules/undo-manager'); + +module.exports = _dereq_('./quill'); + + +},{"./modules/authorship":21,"./modules/image-tooltip":22,"./modules/keyboard":23,"./modules/link-tooltip":24,"./modules/multi-cursor":25,"./modules/paste-manager":26,"./modules/toolbar":27,"./modules/tooltip":28,"./modules/undo-manager":29,"./quill":30}],16:[function(_dereq_,module,exports){ +var ColorPicker, Picker, dom, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +dom = _dereq_('./dom'); + +Picker = _dereq_('./picker'); + +ColorPicker = (function(superClass) { + extend(ColorPicker, superClass); + + function ColorPicker() { + ColorPicker.__super__.constructor.apply(this, arguments); + dom(this.container).addClass('ql-color-picker'); + } + + ColorPicker.prototype.buildItem = function(picker, option, index) { + var item; + item = ColorPicker.__super__.buildItem.call(this, picker, option, index); + item.style.backgroundColor = option.value; + return item; + }; + + return ColorPicker; + +})(Picker); + +module.exports = ColorPicker; + + +},{"./dom":17,"./picker":19}],17:[function(_dereq_,module,exports){ +var SelectWrapper, Wrapper, _, dom, lastKeyEvent, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +_ = _dereq_('lodash'); + +lastKeyEvent = null; + +Wrapper = (function() { + function Wrapper(node1) { + this.node = node1; + this.trigger = bind(this.trigger, this); + } + + Wrapper.prototype.addClass = function(cssClass) { + if (this.hasClass(cssClass)) { + return; + } + if (this.node.classList != null) { + this.node.classList.add(cssClass); + } else if (this.node.className != null) { + this.node.className = (this.node.className + ' ' + cssClass).trim(); + } + return this; + }; + + Wrapper.prototype.attributes = function(attributes) { + var attr, i, j, len, ref, value; + if (attributes) { + _.each(attributes, (function(_this) { + return function(value, name) { + return _this.node.setAttribute(name, value); + }; + })(this)); + return this; + } else { + if (this.node.attributes == null) { + return {}; + } + attributes = {}; + ref = this.node.attributes; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + value = ref[i]; + attr = this.node.attributes[i]; + attributes[attr.name] = attr.value; + } + return attributes; + } + }; + + Wrapper.prototype.child = function(offset) { + var child, length; + child = this.node.firstChild; + length = dom(child).length(); + while (child != null) { + if (offset < length) { + break; + } + offset -= length; + child = child.nextSibling; + length = dom(child).length(); + } + if (child == null) { + child = this.node.lastChild; + offset = dom(child).length(); + } + return [child, offset]; + }; + + Wrapper.prototype.childNodes = function() { + return _.map(this.node.childNodes); + }; + + Wrapper.prototype.classes = function() { + return this.node.className.split(/\s+/); + }; + + Wrapper.prototype.data = function(key, value) { + var ref; + if (value != null) { + if (this.node['ql-data'] == null) { + this.node['ql-data'] = {}; + } + this.node['ql-data'][key] = value; + return this; + } else { + return (ref = this.node['ql-data']) != null ? ref[key] : void 0; + } + }; + + Wrapper.prototype.descendants = function() { + return _.map(this.node.getElementsByTagName('*')); + }; + + Wrapper.prototype.get = function() { + return this.node; + }; + + Wrapper.prototype.hasClass = function(cssClass) { + if (this.node.classList != null) { + return this.node.classList.contains(cssClass); + } else if (this.node.className != null) { + return this.classes().indexOf(cssClass) > -1; + } + return false; + }; + + Wrapper.prototype.isAncestor = function(ancestor, inclusive) { + var node; + if (inclusive == null) { + inclusive = false; + } + if (ancestor === this.node) { + return inclusive; + } + node = this.node; + while (node) { + if (node === ancestor) { + return true; + } + node = node.parentNode; + } + return false; + }; + + Wrapper.prototype.isElement = function() { + var ref; + return ((ref = this.node) != null ? ref.nodeType : void 0) === dom.ELEMENT_NODE; + }; + + Wrapper.prototype.isTextNode = function() { + var ref; + return ((ref = this.node) != null ? ref.nodeType : void 0) === dom.TEXT_NODE; + }; + + Wrapper.prototype.isolate = function(root) { + if (this.node.nextSibling != null) { + dom(this.node.nextSibling).splitBefore(root); + } + this.splitBefore(root); + return this; + }; + + Wrapper.prototype.length = function() { + var length; + if (this.node == null) { + return 0; + } + length = this.text().length; + if (this.isElement()) { + length += this.node.querySelectorAll(Object.keys(dom.EMBED_TAGS).join(',')).length; + } + return length; + }; + + Wrapper.prototype.merge = function(node) { + var $node; + $node = dom(node); + if (this.isElement()) { + $node.moveChildren(this.node); + this.normalize(); + } else { + this.text(this.text() + $node.text()); + } + $node.remove(); + return this; + }; + + Wrapper.prototype.moveChildren = function(newParent) { + _.each(this.childNodes(), function(child) { + return newParent.appendChild(child); + }); + return this; + }; + + Wrapper.prototype.nextLineNode = function(root) { + var nextNode; + nextNode = this.node.nextSibling; + if ((nextNode == null) && this.node.parentNode !== root) { + nextNode = this.node.parentNode.nextSibling; + } + if ((nextNode != null) && (dom.LIST_TAGS[nextNode.tagName] != null)) { + nextNode = nextNode.firstChild; + } + return nextNode; + }; + + Wrapper.prototype.normalize = function() { + var $node, curNode, followingNode, nextNode; + curNode = this.node.firstChild; + while (curNode != null) { + nextNode = curNode.nextSibling; + $node = dom(curNode); + if ((nextNode != null) && dom(nextNode).isTextNode()) { + if ($node.text().length === 0) { + $node.remove(); + } else if ($node.isTextNode()) { + followingNode = nextNode.nextSibling; + $node.merge(nextNode); + nextNode = followingNode; + } + } + curNode = nextNode; + } + return this; + }; + + Wrapper.prototype.on = function(eventName, listener) { + this.node.addEventListener(eventName, (function(_this) { + return function(event) { + var arg, propagate; + arg = lastKeyEvent && (eventName === 'keydown' || eventName === 'keyup') ? lastKeyEvent : event; + propagate = listener.call(_this.node, arg); + if (!propagate) { + event.preventDefault(); + event.stopPropagation(); + } + return propagate; + }; + })(this)); + return this; + }; + + Wrapper.prototype.remove = function() { + var ref; + if ((ref = this.node.parentNode) != null) { + ref.removeChild(this.node); + } + this.node = null; + return null; + }; + + Wrapper.prototype.removeClass = function(cssClass) { + var classArray; + if (!this.hasClass(cssClass)) { + return; + } + if (this.node.classList != null) { + this.node.classList.remove(cssClass); + } else if (this.node.className != null) { + classArray = this.classes(); + classArray.splice(classArray.indexOf(cssClass), 1); + this.node.className = classArray.join(' '); + } + if (!this.node.getAttribute('class')) { + this.node.removeAttribute('class'); + } + return this; + }; + + Wrapper.prototype.replace = function(newNode) { + this.node.parentNode.replaceChild(newNode, this.node); + this.node = newNode; + return this; + }; + + Wrapper.prototype.splitBefore = function(root, force) { + var nextNode, parentClone, parentNode, refNode; + if (force == null) { + force = false; + } + if (this.node === root || this.node.parentNode === root) { + return this; + } + if ((this.node.previousSibling != null) || force) { + parentNode = this.node.parentNode; + parentClone = parentNode.cloneNode(false); + parentNode.parentNode.insertBefore(parentClone, parentNode.nextSibling); + refNode = this.node; + while (refNode != null) { + nextNode = refNode.nextSibling; + parentClone.appendChild(refNode); + refNode = nextNode; + } + return dom(parentClone).splitBefore(root); + } else { + return dom(this.node.parentNode).splitBefore(root); + } + }; + + Wrapper.prototype.split = function(offset, force) { + var after, child, childLeft, childRight, left, nextRight, nodeLength, ref, ref1, right; + if (force == null) { + force = false; + } + nodeLength = this.length(); + offset = Math.max(0, offset); + offset = Math.min(offset, nodeLength); + if (!(force || offset !== 0)) { + return [this.node.previousSibling, this.node, false]; + } + if (!(force || offset !== nodeLength)) { + return [this.node, this.node.nextSibling, false]; + } + if (this.node.nodeType === dom.TEXT_NODE) { + after = this.node.splitText(offset); + return [this.node, after, true]; + } else { + left = this.node; + right = this.node.cloneNode(false); + this.node.parentNode.insertBefore(right, left.nextSibling); + ref = this.child(offset), child = ref[0], offset = ref[1]; + ref1 = dom(child).split(offset), childLeft = ref1[0], childRight = ref1[1]; + while (childRight !== null) { + nextRight = childRight.nextSibling; + right.appendChild(childRight); + childRight = nextRight; + } + return [left, right, true]; + } + }; + + Wrapper.prototype.styles = function(styles, overwrite) { + var obj, styleString; + if (overwrite == null) { + overwrite = false; + } + if (styles) { + if (!overwrite) { + styles = _.defaults(styles, this.styles()); + } + styleString = _.map(styles, function(style, name) { + return name + ": " + style; + }).join('; ') + ';'; + this.node.setAttribute('style', styleString); + return this; + } else { + styleString = this.node.getAttribute('style') || ''; + obj = _.reduce(styleString.split(';'), function(styles, str) { + var name, ref, value; + ref = str.split(':'), name = ref[0], value = ref[1]; + if (name && value) { + name = name.trim(); + value = value.trim(); + styles[name.toLowerCase()] = value; + } + return styles; + }, {}); + return obj; + } + }; + + Wrapper.prototype.switchTag = function(newTag) { + var attributes, newNode; + newTag = newTag.toUpperCase(); + if (this.node.tagName === newTag) { + return this; + } + newNode = document.createElement(newTag); + attributes = this.attributes(); + if (dom.VOID_TAGS[newTag] == null) { + this.moveChildren(newNode); + } + this.replace(newNode); + this.node = newNode; + return this.attributes(attributes); + }; + + Wrapper.prototype.text = function(text) { + if (text != null) { + switch (this.node.nodeType) { + case dom.ELEMENT_NODE: + this.node.textContent = text; + break; + case dom.TEXT_NODE: + this.node.data = text; + } + return this; + } else { + switch (this.node.nodeType) { + case dom.ELEMENT_NODE: + if (this.node.tagName === dom.DEFAULT_BREAK_TAG) { + return ""; + } + if (dom.EMBED_TAGS[this.node.tagName] != null) { + return dom.EMBED_TEXT; + } + if (this.node.textContent != null) { + return this.node.textContent; + } + return ""; + case dom.TEXT_NODE: + return this.node.data || ""; + default: + return ""; + } + } + }; + + Wrapper.prototype.textNodes = function() { + var textNode, textNodes, walker; + walker = document.createTreeWalker(this.node, NodeFilter.SHOW_TEXT, null, false); + textNodes = []; + while (textNode = walker.nextNode()) { + textNodes.push(textNode); + } + return textNodes; + }; + + Wrapper.prototype.toggleClass = function(className, state) { + if (state == null) { + state = !this.hasClass(className); + } + if (state) { + this.addClass(className); + } else { + this.removeClass(className); + } + return this; + }; + + Wrapper.prototype.trigger = function(eventName, options) { + var event, initFn, modifiers; + if (options == null) { + options = {}; + } + if (['keypress', 'keydown', 'keyup'].indexOf(eventName) < 0) { + event = document.createEvent('Event'); + event.initEvent(eventName, options.bubbles, options.cancelable); + } else { + event = document.createEvent('KeyboardEvent'); + lastKeyEvent = _.clone(options); + if (_.isNumber(options.key)) { + lastKeyEvent.which = options.key; + } else if (_.isString(options.key)) { + lastKeyEvent.which = options.key.toUpperCase().charCodeAt(0); + } else { + lastKeyEvent.which = 0; + } + if (dom.isIE(10)) { + modifiers = []; + if (options.altKey) { + modifiers.push('Alt'); + } + if (options.ctrlKey) { + modifiers.push('Control'); + } + if (options.metaKey) { + modifiers.push('Meta'); + } + if (options.shiftKey) { + modifiers.push('Shift'); + } + event.initKeyboardEvent(eventName, options.bubbles, options.cancelable, window, 0, 0, modifiers.join(' '), null, null); + } else { + initFn = _.isFunction(event.initKeyboardEvent) ? 'initKeyboardEvent' : 'initKeyEvent'; + event[initFn](eventName, options.bubbles, options.cancelable, window, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, 0); + } + } + this.node.dispatchEvent(event); + lastKeyEvent = null; + return this; + }; + + Wrapper.prototype.unwrap = function() { + var next, ret; + ret = this.node.firstChild; + next = this.node.nextSibling; + _.each(this.childNodes(), (function(_this) { + return function(child) { + return _this.node.parentNode.insertBefore(child, next); + }; + })(this)); + this.remove(); + return ret; + }; + + Wrapper.prototype.wrap = function(wrapper) { + var parent; + if (this.node.parentNode != null) { + this.node.parentNode.insertBefore(wrapper, this.node); + } + parent = wrapper; + while (parent.firstChild != null) { + parent = wrapper.firstChild; + } + parent.appendChild(this.node); + return this; + }; + + return Wrapper; + +})(); + +SelectWrapper = (function(superClass) { + extend(SelectWrapper, superClass); + + function SelectWrapper() { + return SelectWrapper.__super__.constructor.apply(this, arguments); + } + + SelectWrapper.prototype["default"] = function() { + return this.node.querySelector('option[selected]'); + }; + + SelectWrapper.prototype.option = function(option, trigger) { + var child, i, j, len, ref, value; + if (trigger == null) { + trigger = true; + } + value = _.isElement(option) ? option.value : option; + if (value) { + value = value.replace(/[^\w]+/g, ''); + ref = this.node.children; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + child = ref[i]; + if (child.value.replace(/[^\w]+/g, '') === value) { + this.node.selectedIndex = i; + break; + } + } + } else { + this.node.selectedIndex = -1; + } + if (trigger) { + this.trigger('change'); + } + return this; + }; + + SelectWrapper.prototype.reset = function(trigger) { + var option; + if (trigger == null) { + trigger = true; + } + option = this["default"](); + if (option != null) { + option.selected = true; + } else { + this.node.selectedIndex = 0; + } + if (trigger) { + this.trigger('change'); + } + return this; + }; + + SelectWrapper.prototype.value = function() { + if (this.node.selectedIndex > -1) { + return this.node.options[this.node.selectedIndex].value; + } else { + return ''; + } + }; + + return SelectWrapper; + +})(Wrapper); + +dom = function(node) { + if ((node != null ? node.tagName : void 0) === 'SELECT') { + return new SelectWrapper(node); + } else { + return new Wrapper(node); + } +}; + +dom = _.extend(dom, { + ELEMENT_NODE: 1, + NOBREAK_SPACE: " ", + TEXT_NODE: 3, + ZERO_WIDTH_NOBREAK_SPACE: "\uFEFF", + DEFAULT_BLOCK_TAG: 'DIV', + DEFAULT_BREAK_TAG: 'BR', + DEFAULT_INLINE_TAG: 'SPAN', + EMBED_TEXT: '!', + FONT_SIZES: { + '10px': 1, + '13px': 2, + '16px': 3, + '18px': 4, + '24px': 5, + '32px': 6, + '48px': 7 + }, + KEYS: { + BACKSPACE: 8, + TAB: 9, + ENTER: 13, + ESCAPE: 27, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + DELETE: 46 + }, + BLOCK_TAGS: { + 'ADDRESS': 'ADDRESS', + 'ARTICLE': 'ARTICLE', + 'ASIDE': 'ASIDE', + 'AUDIO': 'AUDIO', + 'BLOCKQUOTE': 'BLOCKQUOTE', + 'CANVAS': 'CANVAS', + 'DD': 'DD', + 'DIV': 'DIV', + 'DL': 'DL', + 'FIGCAPTION': 'FIGCAPTION', + 'FIGURE': 'FIGURE', + 'FOOTER': 'FOOTER', + 'FORM': 'FORM', + 'H1': 'H1', + 'H2': 'H2', + 'H3': 'H3', + 'H4': 'H4', + 'H5': 'H5', + 'H6': 'H6', + 'HEADER': 'HEADER', + 'HGROUP': 'HGROUP', + 'LI': 'LI', + 'OL': 'OL', + 'OUTPUT': 'OUTPUT', + 'P': 'P', + 'PRE': 'PRE', + 'SECTION': 'SECTION', + 'TABLE': 'TABLE', + 'TBODY': 'TBODY', + 'TD': 'TD', + 'TFOOT': 'TFOOT', + 'TH': 'TH', + 'THEAD': 'THEAD', + 'TR': 'TR', + 'UL': 'UL', + 'VIDEO': 'VIDEO' + }, + EMBED_TAGS: { + 'IMG': 'IMG' + }, + LINE_TAGS: { + 'DIV': 'DIV', + 'LI': 'LI' + }, + LIST_TAGS: { + 'OL': 'OL', + 'UL': 'UL' + }, + VOID_TAGS: { + 'AREA': 'AREA', + 'BASE': 'BASE', + 'BR': 'BR', + 'COL': 'COL', + 'COMMAND': 'COMMAND', + 'EMBED': 'EMBED', + 'HR': 'HR', + 'IMG': 'IMG', + 'INPUT': 'INPUT', + 'KEYGEN': 'KEYGEN', + 'LINK': 'LINK', + 'META': 'META', + 'PARAM': 'PARAM', + 'SOURCE': 'SOURCE', + 'TRACK': 'TRACK', + 'WBR': 'WBR' + }, + convertFontSize: function(size) { + var i, s, sources, targets; + if (_.isString(size) && size.indexOf('px') > -1) { + sources = Object.keys(dom.FONT_SIZES); + targets = _.values(dom.FONT_SIZES); + } else { + targets = Object.keys(dom.FONT_SIZES); + sources = _.values(dom.FONT_SIZES); + } + for (i in sources) { + s = sources[i]; + if (parseInt(size) <= parseInt(s)) { + return targets[i]; + } + } + return _.last(targets); + }, + isIE: function(maxVersion) { + var version; + version = document.documentMode; + return version && maxVersion >= version; + }, + isIOS: function() { + return /iPhone|iPad/i.test(navigator.userAgent); + }, + isMac: function() { + return /Mac/i.test(navigator.platform); + } +}); + +module.exports = dom; + + +},{"lodash":1}],18:[function(_dereq_,module,exports){ +var LinkedList, Node; + +Node = (function() { + function Node(data) { + this.data = data; + this.prev = this.next = null; + } + + return Node; + +})(); + +LinkedList = (function() { + LinkedList.Node = Node; + + function LinkedList() { + this.length = 0; + this.first = this.last = null; + } + + LinkedList.prototype.append = function(node) { + if (this.first != null) { + node.next = null; + this.last.next = node; + } else { + this.first = node; + } + node.prev = this.last; + this.last = node; + return this.length += 1; + }; + + LinkedList.prototype.insertAfter = function(refNode, newNode) { + newNode.prev = refNode; + if (refNode != null) { + newNode.next = refNode.next; + if (refNode.next != null) { + refNode.next.prev = newNode; + } + refNode.next = newNode; + if (refNode === this.last) { + this.last = newNode; + } + } else { + newNode.next = this.first; + this.first.prev = newNode; + this.first = newNode; + } + return this.length += 1; + }; + + LinkedList.prototype.remove = function(node) { + if (this.length > 1) { + if (node.prev != null) { + node.prev.next = node.next; + } + if (node.next != null) { + node.next.prev = node.prev; + } + if (node === this.first) { + this.first = node.next; + } + if (node === this.last) { + this.last = node.prev; + } + } else { + this.first = this.last = null; + } + node.prev = node.next = null; + return this.length -= 1; + }; + + LinkedList.prototype.toArray = function() { + var arr, cur; + arr = []; + cur = this.first; + while (cur != null) { + arr.push(cur); + cur = cur.next; + } + return arr; + }; + + return LinkedList; + +})(); + +module.exports = LinkedList; + + +},{}],19:[function(_dereq_,module,exports){ +var Picker, _, dom; + +_ = _dereq_('lodash'); + +dom = _dereq_('./dom'); + +Picker = (function() { + Picker.TEMPLATE = ''; + + function Picker(select) { + this.select = select; + this.container = document.createElement('span'); + this.buildPicker(); + dom(this.container).addClass('ql-picker'); + this.select.style.display = 'none'; + this.select.parentNode.insertBefore(this.container, this.select); + dom(document).on('click', (function(_this) { + return function() { + _this.close(); + return true; + }; + })(this)); + dom(this.label).on('click', (function(_this) { + return function() { + _.defer(function() { + return dom(_this.container).toggleClass('ql-expanded'); + }); + return false; + }; + })(this)); + dom(this.select).on('change', (function(_this) { + return function() { + var item, option; + if (_this.select.selectedIndex > -1) { + item = _this.container.querySelectorAll('.ql-picker-item')[_this.select.selectedIndex]; + option = _this.select.options[_this.select.selectedIndex]; + } + _this.selectItem(item, false); + return dom(_this.label).toggleClass('ql-active', option !== dom(_this.select)["default"]()); + }; + })(this)); + } + + Picker.prototype.buildItem = function(picker, option, index) { + var item; + item = document.createElement('span'); + item.setAttribute('data-value', option.getAttribute('value')); + dom(item).addClass('ql-picker-item').text(dom(option).text()).on('click', (function(_this) { + return function() { + _this.selectItem(item, true); + return _this.close(); + }; + })(this)); + if (this.select.selectedIndex === index) { + this.selectItem(item, false); + } + return item; + }; + + Picker.prototype.buildPicker = function() { + var picker; + _.each(dom(this.select).attributes(), (function(_this) { + return function(value, name) { + return _this.container.setAttribute(name, value); + }; + })(this)); + this.container.innerHTML = Picker.TEMPLATE; + this.label = this.container.querySelector('.ql-picker-label'); + picker = this.container.querySelector('.ql-picker-options'); + return _.each(this.select.options, (function(_this) { + return function(option, i) { + var item; + item = _this.buildItem(picker, option, i); + return picker.appendChild(item); + }; + })(this)); + }; + + Picker.prototype.close = function() { + return dom(this.container).removeClass('ql-expanded'); + }; + + Picker.prototype.selectItem = function(item, trigger) { + var selected, value; + selected = this.container.querySelector('.ql-selected'); + if (selected != null) { + dom(selected).removeClass('ql-selected'); + } + if (item != null) { + value = item.getAttribute('data-value'); + dom(item).addClass('ql-selected'); + dom(this.label).text(dom(item).text()); + dom(this.select).option(value, trigger); + return this.label.setAttribute('data-value', value); + } else { + this.label.innerHTML = ' '; + return this.label.removeAttribute('data-value'); + } + }; + + return Picker; + +})(); + +module.exports = Picker; + + +},{"./dom":17,"lodash":1}],20:[function(_dereq_,module,exports){ +var Range, _; + +_ = _dereq_('lodash'); + +Range = (function() { + Range.compare = function(r1, r2) { + if (r1 === r2) { + return true; + } + if (!((r1 != null) && (r2 != null))) { + return false; + } + return r1.equals(r2); + }; + + function Range(start, end) { + this.start = start; + this.end = end; + } + + Range.prototype.equals = function(range) { + if (range == null) { + return false; + } + return this.start === range.start && this.end === range.end; + }; + + Range.prototype.shift = function(index, length) { + var ref; + return ref = _.map([this.start, this.end], function(pos) { + if (index > pos) { + return pos; + } + if (length >= 0) { + return pos + length; + } else { + return Math.max(index, pos + length); + } + }), this.start = ref[0], this.end = ref[1], ref; + }; + + Range.prototype.isCollapsed = function() { + return this.start === this.end; + }; + + return Range; + +})(); + +module.exports = Range; + + +},{"lodash":1}],21:[function(_dereq_,module,exports){ +var Authorship, Delta, Quill, _, dom; + +Quill = _dereq_('../quill'); + +_ = Quill.require('lodash'); + +dom = Quill.require('dom'); + +Delta = Quill.require('delta'); + +Authorship = (function() { + Authorship.DEFAULTS = { + authorId: null, + color: 'transparent', + enabled: false + }; + + function Authorship(quill, options) { + this.quill = quill; + this.options = options; + if (this.options.button != null) { + this.attachButton(this.options.button); + } + if (this.options.enabled) { + this.enable(); + } + this.quill.addFormat('author', { + "class": 'author-' + }); + if (this.options.authorId == null) { + return; + } + this.quill.on(this.quill.constructor.events.PRE_EVENT, (function(_this) { + return function(eventName, delta, origin) { + var authorDelta, authorFormat; + if (eventName === _this.quill.constructor.events.TEXT_CHANGE && origin === 'user') { + authorDelta = new Delta(); + authorFormat = { + author: _this.options.authorId + }; + _.each(delta.ops, function(op) { + if (op["delete"] != null) { + return; + } + if ((op.insert != null) || ((op.retain != null) && (op.attributes != null))) { + op.attributes || (op.attributes = {}); + op.attributes.author = _this.options.authorId; + return authorDelta.retain(op.retain || op.insert.length || 1, authorFormat); + } else { + return authorDelta.retain(op.retain); + } + }); + return _this.quill.updateContents(authorDelta, Quill.sources.SILENT); + } + }; + })(this)); + this.addAuthor(this.options.authorId, this.options.color); + } + + Authorship.prototype.addAuthor = function(id, color) { + var styles; + styles = {}; + styles[".authorship .author-" + id] = { + "background-color": "" + color + }; + return this.quill.theme.addStyles(styles); + }; + + Authorship.prototype.attachButton = function(button) { + var $button; + $button = dom(button); + return $button.on('click', (function(_this) { + return function() { + $button.toggleClass('ql-on'); + return _this.enable($dom.hasClass('ql-on')); + }; + })(this)); + }; + + Authorship.prototype.enable = function(enabled) { + if (enabled == null) { + enabled = true; + } + return dom(this.quill.root).toggleClass('authorship', enabled); + }; + + Authorship.prototype.disable = function() { + return this.enable(false); + }; + + return Authorship; + +})(); + +Quill.registerModule('authorship', Authorship); + +module.exports = Authorship; + + +},{"../quill":30}],22:[function(_dereq_,module,exports){ +var Delta, ImageTooltip, Quill, Range, Tooltip, _, dom, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Quill = _dereq_('../quill'); + +Tooltip = _dereq_('./tooltip'); + +_ = Quill.require('lodash'); + +dom = Quill.require('dom'); + +Delta = Quill.require('delta'); + +Range = Quill.require('range'); + +ImageTooltip = (function(superClass) { + extend(ImageTooltip, superClass); + + ImageTooltip.DEFAULTS = { + template: '
Preview
Cancel Insert' + }; + + function ImageTooltip(quill, options) { + this.quill = quill; + this.options = options; + this.options = _.defaults(this.options, Tooltip.DEFAULTS); + ImageTooltip.__super__.constructor.call(this, this.quill, this.options); + this.preview = this.container.querySelector('.preview'); + this.textbox = this.container.querySelector('.input'); + dom(this.container).addClass('ql-image-tooltip'); + this.initListeners(); + } + + ImageTooltip.prototype.initListeners = function() { + dom(this.quill.root).on('focus', _.bind(this.hide, this)); + dom(this.container.querySelector('.insert')).on('click', _.bind(this.insertImage, this)); + dom(this.container.querySelector('.cancel')).on('click', _.bind(this.hide, this)); + dom(this.textbox).on('input', _.bind(this._preview, this)); + this.initTextbox(this.textbox, this.insertImage, this.hide); + return this.quill.onModuleLoad('toolbar', (function(_this) { + return function(toolbar) { + _this.toolbar = toolbar; + return toolbar.initFormat('image', _.bind(_this._onToolbar, _this)); + }; + })(this)); + }; + + ImageTooltip.prototype.insertImage = function() { + var index, url; + url = this._normalizeURL(this.textbox.value); + if (this.range == null) { + this.range = new Range(0, 0); + } + if (this.range) { + this.preview.innerHTML = 'Preview'; + this.textbox.value = ''; + index = this.range.end; + this.quill.insertEmbed(index, 'image', url, 'user'); + this.quill.setSelection(index + 1, index + 1); + } + return this.hide(); + }; + + ImageTooltip.prototype._onToolbar = function(range, value) { + if (value) { + if (!this.textbox.value) { + this.textbox.value = 'http://'; + } + this.show(); + this.textbox.focus(); + return _.defer((function(_this) { + return function() { + return _this.textbox.setSelectionRange(_this.textbox.value.length, _this.textbox.value.length); + }; + })(this)); + } else { + this.quill.deleteText(range, 'user'); + return this.toolbar.setActive('image', false); + } + }; + + ImageTooltip.prototype._preview = function() { + var img; + if (!this._matchImageURL(this.textbox.value)) { + return; + } + if (this.preview.firstChild.tagName === 'IMG') { + return this.preview.firstChild.setAttribute('src', this.textbox.value); + } else { + img = document.createElement('img'); + img.setAttribute('src', this.textbox.value); + return this.preview.replaceChild(img, this.preview.firstChild); + } + }; + + ImageTooltip.prototype._matchImageURL = function(url) { + return /^https?:\/\/.+\.(jpe?g|gif|png)$/.test(url); + }; + + ImageTooltip.prototype._normalizeURL = function(url) { + if (!/^https?:\/\//.test(url)) { + url = 'http://' + url; + } + return url; + }; + + return ImageTooltip; + +})(Tooltip); + +Quill.registerModule('image-tooltip', ImageTooltip); + +module.exports = ImageTooltip; + + +},{"../quill":30,"./tooltip":28}],23:[function(_dereq_,module,exports){ +var Delta, Keyboard, Quill, _, dom; + +Quill = _dereq_('../quill'); + +_ = Quill.require('lodash'); + +dom = Quill.require('dom'); + +Delta = Quill.require('delta'); + +Keyboard = (function() { + Keyboard.hotkeys = { + BOLD: { + key: 'B', + metaKey: true + }, + INDENT: { + key: dom.KEYS.TAB + }, + ITALIC: { + key: 'I', + metaKey: true + }, + OUTDENT: { + key: dom.KEYS.TAB, + shiftKey: true + }, + UNDERLINE: { + key: 'U', + metaKey: true + } + }; + + function Keyboard(quill, options) { + this.quill = quill; + this.hotkeys = {}; + this._initListeners(); + this._initHotkeys(); + this.quill.onModuleLoad('toolbar', (function(_this) { + return function(toolbar) { + return _this.toolbar = toolbar; + }; + })(this)); + } + + Keyboard.prototype.addHotkey = function(hotkeys, callback) { + if (!Array.isArray(hotkeys)) { + hotkeys = [hotkeys]; + } + return _.each(hotkeys, (function(_this) { + return function(hotkey) { + var base, which; + hotkey = _.isObject(hotkey) ? _.clone(hotkey) : { + key: hotkey + }; + hotkey.callback = callback; + which = _.isNumber(hotkey.key) ? hotkey.key : hotkey.key.toUpperCase().charCodeAt(0); + if ((base = _this.hotkeys)[which] == null) { + base[which] = []; + } + return _this.hotkeys[which].push(hotkey); + }; + })(this)); + }; + + Keyboard.prototype.removeHotkeys = function(hotkey, callback) { + var base, kept, ref, removed, which; + hotkey = _.isString(hotkey) ? hotkey.toUpperCase() : hotkey; + hotkey = Keyboard.hotkeys[hotkey] ? Keyboard.hotkeys[hotkey] : hotkey; + hotkey = _.isObject(hotkey) ? hotkey : { + key: hotkey + }; + which = _.isNumber(hotkey.key) ? hotkey.key : hotkey.key.charCodeAt(0); + if ((base = this.hotkeys)[which] == null) { + base[which] = []; + } + ref = _.partition(this.hotkeys[which], function(handler) { + return _.isEqual(hotkey, _.omit(handler, 'callback')) && (!callback || callback === handler.callback); + }), removed = ref[0], kept = ref[1]; + this.hotkeys[which] = kept; + return _.map(removed, 'callback'); + }; + + Keyboard.prototype.toggleFormat = function(range, format) { + var delta, value; + if (range.isCollapsed()) { + delta = this.quill.getContents(Math.max(0, range.start - 1), range.end); + } else { + delta = this.quill.getContents(range); + } + value = delta.ops.length === 0 || !_.all(delta.ops, function(op) { + var ref; + return (ref = op.attributes) != null ? ref[format] : void 0; + }); + if (range.isCollapsed()) { + this.quill.prepareFormat(format, value, Quill.sources.USER); + } else { + this.quill.formatText(range, format, value, Quill.sources.USER); + } + if (this.toolbar != null) { + return this.toolbar.setActive(format, value); + } + }; + + Keyboard.prototype._initEnter = function() { + var keys; + keys = [ + { + key: dom.KEYS.ENTER + }, { + key: dom.KEYS.ENTER, + shiftKey: true + } + ]; + return this.addHotkey(keys, (function(_this) { + return function(range, hotkey) { + var delta, leaf, line, offset, ref, ref1; + if (range == null) { + return true; + } + ref = _this.quill.editor.doc.findLineAt(range.start), line = ref[0], offset = ref[1]; + ref1 = line.findLeafAt(offset), leaf = ref1[0], offset = ref1[1]; + delta = new Delta().retain(range.start).insert('\n', line.formats)["delete"](range.end - range.start); + _this.quill.updateContents(delta, Quill.sources.USER); + _.each(leaf.formats, function(value, format) { + _this.quill.prepareFormat(format, value); + if (_this.toolbar != null) { + _this.toolbar.setActive(format, value); + } + }); + _this.quill.editor.selection.scrollIntoView(); + return false; + }; + })(this)); + }; + + Keyboard.prototype._initDeletes = function() { + return this.addHotkey([dom.KEYS.DELETE, dom.KEYS.BACKSPACE], (function(_this) { + return function(range, hotkey) { + var format, line, offset, ref; + if ((range != null) && _this.quill.getLength() > 0) { + if (range.start !== range.end) { + _this.quill.deleteText(range.start, range.end, Quill.sources.USER); + } else { + if (hotkey.key === dom.KEYS.BACKSPACE) { + ref = _this.quill.editor.doc.findLineAt(range.start), line = ref[0], offset = ref[1]; + if (offset === 0 && (line.formats.bullet || line.formats.list)) { + format = line.formats.bullet ? 'bullet' : 'list'; + _this.quill.formatLine(range.start, range.start, format, false, Quill.sources.USER); + } else if (range.start > 0) { + _this.quill.deleteText(range.start - 1, range.start, Quill.sources.USER); + } + } else if (range.start < _this.quill.getLength() - 1) { + _this.quill.deleteText(range.start, range.start + 1, Quill.sources.USER); + } + } + } + _this.quill.editor.selection.scrollIntoView(); + return false; + }; + })(this)); + }; + + Keyboard.prototype._initHotkeys = function() { + this.addHotkey(Keyboard.hotkeys.INDENT, (function(_this) { + return function(range) { + _this._onTab(range, false); + return false; + }; + })(this)); + this.addHotkey(Keyboard.hotkeys.OUTDENT, (function(_this) { + return function(range) { + return false; + }; + })(this)); + _.each(['bold', 'italic', 'underline'], (function(_this) { + return function(format) { + return _this.addHotkey(Keyboard.hotkeys[format.toUpperCase()], function(range) { + if (_this.quill.editor.doc.formats[format]) { + _this.toggleFormat(range, format); + } + return false; + }); + }; + })(this)); + this._initDeletes(); + return this._initEnter(); + }; + + Keyboard.prototype._initListeners = function() { + return dom(this.quill.root).on('keydown', (function(_this) { + return function(event) { + var prevent; + prevent = false; + _.each(_this.hotkeys[event.which], function(hotkey) { + var metaKey; + metaKey = dom.isMac() ? event.metaKey : event.metaKey || event.ctrlKey; + if (!!hotkey.metaKey !== !!metaKey) { + return; + } + if (!!hotkey.shiftKey !== !!event.shiftKey) { + return; + } + if (!!hotkey.altKey !== !!event.altKey) { + return; + } + prevent = hotkey.callback(_this.quill.getSelection(), hotkey, event) === false || prevent; + return true; + }); + return !prevent; + }; + })(this)); + }; + + Keyboard.prototype._onTab = function(range, shift) { + var delta; + if (shift == null) { + shift = false; + } + delta = new Delta().retain(range.start).insert("\t")["delete"](range.end - range.start).retain(this.quill.getLength() - range.end); + this.quill.updateContents(delta, Quill.sources.USER); + return this.quill.setSelection(range.start + 1, range.start + 1); + }; + + return Keyboard; + +})(); + +Quill.registerModule('keyboard', Keyboard); + +module.exports = Keyboard; + + +},{"../quill":30}],24:[function(_dereq_,module,exports){ +var LinkTooltip, Quill, Tooltip, _, dom, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Quill = _dereq_('../quill'); + +Tooltip = _dereq_('./tooltip'); + +_ = Quill.require('lodash'); + +dom = Quill.require('dom'); + +LinkTooltip = (function(superClass) { + extend(LinkTooltip, superClass); + + LinkTooltip.DEFAULTS = { + maxLength: 50, + template: 'Visit URL:   -  Change Remove Done' + }; + + LinkTooltip.hotkeys = { + LINK: { + key: 'K', + metaKey: true + } + }; + + function LinkTooltip(quill, options) { + this.quill = quill; + this.options = options; + this.options = _.defaults(this.options, Tooltip.DEFAULTS); + LinkTooltip.__super__.constructor.call(this, this.quill, this.options); + dom(this.container).addClass('ql-link-tooltip'); + this.textbox = this.container.querySelector('.input'); + this.link = this.container.querySelector('.url'); + this.initListeners(); + } + + LinkTooltip.prototype.initListeners = function() { + this.quill.on(this.quill.constructor.events.SELECTION_CHANGE, (function(_this) { + return function(range) { + var anchor; + if (!((range != null) && range.isCollapsed())) { + return; + } + anchor = _this._findAnchor(range); + if (anchor) { + _this.setMode(anchor.href, false); + return _this.show(anchor); + } else if (_this.container.style.left !== Tooltip.HIDE_MARGIN) { + _this.range = null; + return _this.hide(); + } + }; + })(this)); + dom(this.container.querySelector('.done')).on('click', _.bind(this.saveLink, this)); + dom(this.container.querySelector('.remove')).on('click', (function(_this) { + return function() { + return _this.removeLink(_this.range); + }; + })(this)); + dom(this.container.querySelector('.change')).on('click', (function(_this) { + return function() { + return _this.setMode(_this.link.href, true); + }; + })(this)); + this.initTextbox(this.textbox, this.saveLink, this.hide); + this.quill.onModuleLoad('toolbar', (function(_this) { + return function(toolbar) { + _this.toolbar = toolbar; + return toolbar.initFormat('link', _.bind(_this._onToolbar, _this)); + }; + })(this)); + return this.quill.onModuleLoad('keyboard', (function(_this) { + return function(keyboard) { + return keyboard.addHotkey(LinkTooltip.hotkeys.LINK, _.bind(_this._onKeyboard, _this)); + }; + })(this)); + }; + + LinkTooltip.prototype.saveLink = function() { + var anchor, end, url; + url = this._normalizeURL(this.textbox.value); + if (this.range != null) { + end = this.range.end; + if (this.range.isCollapsed()) { + anchor = this._findAnchor(this.range); + if (anchor != null) { + anchor.href = url; + } + } else { + this.quill.formatText(this.range, 'link', url, 'user'); + } + this.quill.setSelection(end, end); + } + return this.setMode(url, false); + }; + + LinkTooltip.prototype.removeLink = function(range) { + if (range.isCollapsed()) { + range = this._expandRange(range); + } + this.hide(); + this.quill.formatText(range, 'link', false, 'user'); + if (this.toolbar != null) { + return this.toolbar.setActive('link', false); + } + }; + + LinkTooltip.prototype.setMode = function(url, edit) { + var text; + if (edit == null) { + edit = false; + } + if (edit) { + this.textbox.value = url; + _.defer((function(_this) { + return function() { + _this.textbox.focus(); + return _this.textbox.setSelectionRange(0, url.length); + }; + })(this)); + } else { + this.link.href = url; + url = this.link.href; + text = url.length > this.options.maxLength ? url.slice(0, this.options.maxLength) + '...' : url; + dom(this.link).text(text); + } + return dom(this.container).toggleClass('editing', edit); + }; + + LinkTooltip.prototype._findAnchor = function(range) { + var leaf, node, offset, ref; + ref = this.quill.editor.doc.findLeafAt(range.start, true), leaf = ref[0], offset = ref[1]; + if (leaf != null) { + node = leaf.node; + } + while ((node != null) && node !== this.quill.root) { + if (node.tagName === 'A') { + return node; + } + node = node.parentNode; + } + return null; + }; + + LinkTooltip.prototype._expandRange = function(range) { + var end, leaf, offset, ref, start; + ref = this.quill.editor.doc.findLeafAt(range.start, true), leaf = ref[0], offset = ref[1]; + start = range.start - offset; + end = start + leaf.length; + return { + start: start, + end: end + }; + }; + + LinkTooltip.prototype._onToolbar = function(range, value) { + return this._toggle(range, value); + }; + + LinkTooltip.prototype._onKeyboard = function() { + var range; + range = this.quill.getSelection(); + return this._toggle(range, !this._findAnchor(range)); + }; + + LinkTooltip.prototype._toggle = function(range, value) { + var nativeRange; + if (!range) { + return; + } + if (!value) { + return this.removeLink(range); + } else if (!range.isCollapsed()) { + this.setMode(this._suggestURL(range), true); + nativeRange = this.quill.editor.selection._getNativeRange(); + return this.show(nativeRange); + } + }; + + LinkTooltip.prototype._normalizeURL = function(url) { + if (!/^(https?:\/\/|mailto:)/.test(url)) { + url = 'http://' + url; + } + return url; + }; + + LinkTooltip.prototype._suggestURL = function(range) { + var text; + text = this.quill.getText(range); + return this._normalizeURL(text); + }; + + return LinkTooltip; + +})(Tooltip); + +Quill.registerModule('link-tooltip', LinkTooltip); + +module.exports = LinkTooltip; + + +},{"../quill":30,"./tooltip":28}],25:[function(_dereq_,module,exports){ +var EventEmitter2, MultiCursor, Quill, _, dom, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Quill = _dereq_('../quill'); + +EventEmitter2 = _dereq_('eventemitter2').EventEmitter2; + +_ = Quill.require('lodash'); + +dom = Quill.require('dom'); + +MultiCursor = (function(superClass) { + extend(MultiCursor, superClass); + + MultiCursor.DEFAULTS = { + template: ' ', + timeout: 2500 + }; + + MultiCursor.events = { + CURSOR_ADDED: 'cursor-addded', + CURSOR_MOVED: 'cursor-moved', + CURSOR_REMOVED: 'cursor-removed' + }; + + function MultiCursor(quill, options) { + this.quill = quill; + this.options = options; + this.cursors = {}; + this.container = this.quill.addContainer('ql-multi-cursor', true); + this.quill.on(this.quill.constructor.events.TEXT_CHANGE, _.bind(this._applyDelta, this)); + } + + MultiCursor.prototype.clearCursors = function() { + _.each(Object.keys(this.cursors), _.bind(this.removeCursor, this)); + return this.cursors = {}; + }; + + MultiCursor.prototype.moveCursor = function(userId, index) { + var cursor; + cursor = this.cursors[userId]; + if (cursor == null) { + return; + } + cursor.index = index; + dom(cursor.elem).removeClass('hidden'); + clearTimeout(cursor.timer); + cursor.timer = setTimeout((function(_this) { + return function() { + dom(cursor.elem).addClass('hidden'); + return cursor.timer = null; + }; + })(this), this.options.timeout); + this._updateCursor(cursor); + return cursor; + }; + + MultiCursor.prototype.removeCursor = function(userId) { + var cursor; + cursor = this.cursors[userId]; + this.emit(MultiCursor.events.CURSOR_REMOVED, cursor); + if (cursor != null) { + cursor.elem.parentNode.removeChild(cursor.elem); + } + return delete this.cursors[userId]; + }; + + MultiCursor.prototype.setCursor = function(userId, index, name, color) { + var cursor; + if (this.cursors[userId] == null) { + this.cursors[userId] = cursor = { + userId: userId, + index: index, + color: color, + elem: this._buildCursor(name, color) + }; + this.emit(MultiCursor.events.CURSOR_ADDED, cursor); + } + _.defer((function(_this) { + return function() { + return _this.moveCursor(userId, index); + }; + })(this)); + return this.cursors[userId]; + }; + + MultiCursor.prototype.shiftCursors = function(index, length, authorId) { + if (authorId == null) { + authorId = null; + } + return _.each(this.cursors, (function(_this) { + return function(cursor, id) { + var shift; + if (!cursor) { + return; + } + shift = Math.max(length, index - cursor.index); + if (cursor.userId === authorId) { + return _this.moveCursor(authorId, cursor.index + shift); + } else if (cursor.index > index) { + return cursor.index += shift; + } + }; + })(this)); + }; + + MultiCursor.prototype.update = function() { + return _.each(this.cursors, (function(_this) { + return function(cursor, id) { + if (cursor == null) { + return; + } + _this._updateCursor(cursor); + return true; + }; + })(this)); + }; + + MultiCursor.prototype._applyDelta = function(delta) { + var index; + index = 0; + _.each(delta.ops, (function(_this) { + return function(op) { + var length, ref; + length = 0; + if (op.insert != null) { + length = op.insert.length || 1; + _this.shiftCursors(index, length, (ref = op.attributes) != null ? ref['author'] : void 0); + } else if (op["delete"] != null) { + _this.shiftCursors(index, -1 * op["delete"], null); + } else if (op.retain != null) { + _this.shiftCursors(index, 0, null); + length = op.retain; + } + return index += length; + }; + })(this)); + return this.update(); + }; + + MultiCursor.prototype._buildCursor = function(name, color) { + var cursor, cursorCaret, cursorFlag, cursorName; + cursor = document.createElement('span'); + dom(cursor).addClass('cursor'); + cursor.innerHTML = this.options.template; + cursorFlag = cursor.querySelector('.cursor-flag'); + cursorName = cursor.querySelector('.cursor-name'); + dom(cursorName).text(name); + cursorCaret = cursor.querySelector('.cursor-caret'); + cursorCaret.style.backgroundColor = cursorName.style.backgroundColor = color; + this.container.appendChild(cursor); + return cursor; + }; + + MultiCursor.prototype._updateCursor = function(cursor) { + var bounds, flag; + bounds = this.quill.getBounds(cursor.index); + if (bounds == null) { + return this.removeCursor(cursor.userId); + } + cursor.elem.style.top = (bounds.top + this.quill.container.scrollTop) + 'px'; + cursor.elem.style.left = bounds.left + 'px'; + cursor.elem.style.height = bounds.height + 'px'; + flag = cursor.elem.querySelector('.cursor-flag'); + dom(cursor.elem).toggleClass('top', parseInt(cursor.elem.style.top) <= flag.offsetHeight).toggleClass('left', parseInt(cursor.elem.style.left) <= flag.offsetWidth).toggleClass('right', this.quill.root.offsetWidth - parseInt(cursor.elem.style.left) <= flag.offsetWidth); + return this.emit(MultiCursor.events.CURSOR_MOVED, cursor); + }; + + return MultiCursor; + +})(EventEmitter2); + +Quill.registerModule('multi-cursor', MultiCursor); + +module.exports = MultiCursor; + + +},{"../quill":30,"eventemitter2":2}],26:[function(_dereq_,module,exports){ +var Delta, Document, PasteManager, Quill, _, dom, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + +Quill = _dereq_('../quill'); + +Document = _dereq_('../core/document'); + +_ = Quill.require('lodash'); + +dom = Quill.require('dom'); + +Delta = Quill.require('delta'); + +PasteManager = (function() { + PasteManager.DEFAULTS = { + onConvert: null + }; + + function PasteManager(quill, options) { + var base; + this.quill = quill; + this._onConvert = bind(this._onConvert, this); + this.container = this.quill.addContainer('ql-paste-manager'); + this.container.setAttribute('contenteditable', true); + this.container.setAttribute('tabindex', '-1'); + dom(this.quill.root).on('paste', _.bind(this._paste, this)); + this.options = _.defaults(options, PasteManager.DEFAULTS); + if ((base = this.options).onConvert == null) { + base.onConvert = this._onConvert; + } + } + + PasteManager.prototype._onConvert = function(container) { + var delta, doc, lengthAdded; + doc = new Document(container, this.quill.options); + delta = doc.toDelta(); + lengthAdded = delta.length(); + if (lengthAdded === 0) { + return delta; + } + return delta.compose(new Delta().retain(lengthAdded - 1)["delete"](1)); + }; + + PasteManager.prototype._paste = function() { + var oldDocLength, range; + oldDocLength = this.quill.getLength(); + range = this.quill.getSelection(); + if (range == null) { + return; + } + this.container.focus(); + return _.defer((function(_this) { + return function() { + var delta, lengthAdded; + delta = _this.options.onConvert(_this.container); + lengthAdded = delta.length(); + if (lengthAdded > 0) { + if (range.start > 0) { + delta.ops.unshift({ + retain: range.start + }); + } + delta["delete"](range.end - range.start); + _this.quill.updateContents(delta, 'user'); + } + _this.quill.setSelection(range.start + lengthAdded, range.start + lengthAdded); + _this.quill.editor.selection.scrollIntoView(); + return _this.container.innerHTML = ""; + }; + })(this)); + }; + + return PasteManager; + +})(); + +Quill.registerModule('paste-manager', PasteManager); + +module.exports = PasteManager; + + +},{"../core/document":8,"../quill":30}],27:[function(_dereq_,module,exports){ +var Quill, Toolbar, _, dom; + +Quill = _dereq_('../quill'); + +_ = Quill.require('lodash'); + +dom = Quill.require('dom'); + +Toolbar = (function() { + Toolbar.DEFAULTS = { + container: null + }; + + Toolbar.formats = { + LINE: { + 'align': 'align', + 'bullet': 'bullet', + 'list': 'list' + }, + SELECT: { + 'align': 'align', + 'background': 'background', + 'color': 'color', + 'font': 'font', + 'size': 'size' + }, + TOGGLE: { + 'bold': 'bold', + 'bullet': 'bullet', + 'image': 'image', + 'italic': 'italic', + 'link': 'link', + 'list': 'list', + 'strike': 'strike', + 'underline': 'underline' + }, + TOOLTIP: { + 'image': 'image', + 'link': 'link' + } + }; + + function Toolbar(quill, options) { + this.quill = quill; + this.options = options; + if (_.isString(this.options) || _.isElement(this.options)) { + this.options = { + container: this.options + }; + } + if (this.options.container == null) { + throw new Error('container required for toolbar', this.options); + } + this.container = _.isString(this.options.container) ? document.querySelector(this.options.container) : this.options.container; + this.inputs = {}; + this.preventUpdate = false; + this.triggering = false; + _.each(this.quill.options.formats, (function(_this) { + return function(name) { + if (Toolbar.formats.TOOLTIP[name] != null) { + return; + } + return _this.initFormat(name, _.bind(_this._applyFormat, _this, name)); + }; + })(this)); + this.quill.on(Quill.events.FORMAT_INIT, (function(_this) { + return function(name) { + if (Toolbar.formats.TOOLTIP[name] != null) { + return; + } + return _this.initFormat(name, _.bind(_this._applyFormat, _this, name)); + }; + })(this)); + this.quill.on(Quill.events.SELECTION_CHANGE, (function(_this) { + return function(range) { + if (range != null) { + return _this.updateActive(range); + } + }; + })(this)); + this.quill.on(Quill.events.TEXT_CHANGE, (function(_this) { + return function() { + return _this.updateActive(); + }; + })(this)); + this.quill.onModuleLoad('keyboard', (function(_this) { + return function(keyboard) { + return keyboard.addHotkey([dom.KEYS.BACKSPACE, dom.KEYS.DELETE], function() { + return _.defer(_.bind(_this.updateActive, _this)); + }); + }; + })(this)); + dom(this.container).addClass('ql-toolbar'); + if (dom.isIOS()) { + dom(this.container).addClass('ios'); + } + } + + Toolbar.prototype.initFormat = function(format, callback) { + var eventName, input, selector; + selector = ".ql-" + format; + if (Toolbar.formats.SELECT[format] != null) { + selector = "select" + selector; + eventName = 'change'; + } else { + eventName = 'click'; + } + input = this.container.querySelector(selector); + if (input == null) { + return; + } + this.inputs[format] = input; + return dom(input).on(eventName, (function(_this) { + return function() { + var range, value; + value = eventName === 'change' ? dom(input).value() : !dom(input).hasClass('ql-active'); + _this.preventUpdate = true; + _this.quill.focus(); + range = _this.quill.getSelection(); + if (range != null) { + callback(range, value); + } + if (dom.isIE(11)) { + _this.quill.editor.selection.scrollIntoView(); + } + _this.preventUpdate = false; + return false; + }; + })(this)); + }; + + Toolbar.prototype.setActive = function(format, value) { + var $input, input, ref, selectValue; + if (format === 'image') { + value = false; + } + input = this.inputs[format]; + if (input == null) { + return; + } + $input = dom(input); + if (input.tagName === 'SELECT') { + this.triggering = true; + selectValue = $input.value(input); + if (value == null) { + value = (ref = $input["default"]()) != null ? ref.value : void 0; + } + if (Array.isArray(value)) { + value = ''; + } + if (value !== selectValue) { + if (value != null) { + $input.option(value); + } else { + $input.reset(); + } + } + return this.triggering = false; + } else { + return $input.toggleClass('ql-active', value || false); + } + }; + + Toolbar.prototype.updateActive = function(range, formats) { + var activeFormats; + if (formats == null) { + formats = null; + } + range || (range = this.quill.getSelection()); + if (!((range != null) && !this.preventUpdate)) { + return; + } + activeFormats = this._getActive(range); + return _.each(this.inputs, (function(_this) { + return function(input, format) { + if (!Array.isArray(formats) || formats.indexOf(format) > -1) { + _this.setActive(format, activeFormats[format]); + } + return true; + }; + })(this)); + }; + + Toolbar.prototype._applyFormat = function(format, range, value) { + if (this.triggering) { + return; + } + if (range.isCollapsed()) { + this.quill.prepareFormat(format, value, 'user'); + } else if (Toolbar.formats.LINE[format] != null) { + this.quill.formatLine(range, format, value, 'user'); + } else { + this.quill.formatText(range, format, value, 'user'); + } + return _.defer((function(_this) { + return function() { + _this.updateActive(range, ['bullet', 'list']); + return _this.setActive(format, value); + }; + })(this)); + }; + + Toolbar.prototype._getActive = function(range) { + var leafFormats, lineFormats; + leafFormats = this._getLeafActive(range); + lineFormats = this._getLineActive(range); + return _.defaults({}, leafFormats, lineFormats); + }; + + Toolbar.prototype._getLeafActive = function(range) { + var contents, formatsArr, line, offset, ref; + if (range.isCollapsed()) { + ref = this.quill.editor.doc.findLineAt(range.start), line = ref[0], offset = ref[1]; + if (offset === 0) { + contents = this.quill.getContents(range.start, range.end + 1); + } else { + contents = this.quill.getContents(range.start - 1, range.end); + } + } else { + contents = this.quill.getContents(range); + } + formatsArr = _.map(contents.ops, 'attributes'); + return this._intersectFormats(formatsArr); + }; + + Toolbar.prototype._getLineActive = function(range) { + var firstLine, formatsArr, lastLine, offset, ref, ref1; + formatsArr = []; + ref = this.quill.editor.doc.findLineAt(range.start), firstLine = ref[0], offset = ref[1]; + ref1 = this.quill.editor.doc.findLineAt(range.end), lastLine = ref1[0], offset = ref1[1]; + if ((lastLine != null) && lastLine === firstLine) { + lastLine = lastLine.next; + } + while ((firstLine != null) && firstLine !== lastLine) { + formatsArr.push(_.clone(firstLine.formats)); + firstLine = firstLine.next; + } + return this._intersectFormats(formatsArr); + }; + + Toolbar.prototype._intersectFormats = function(formatsArr) { + return _.reduce(formatsArr.slice(1), function(activeFormats, formats) { + var activeKeys, added, formatKeys, intersection, missing; + if (formats == null) { + formats = {}; + } + activeKeys = Object.keys(activeFormats); + formatKeys = formats != null ? Object.keys(formats) : {}; + intersection = _.intersection(activeKeys, formatKeys); + missing = _.difference(activeKeys, formatKeys); + added = _.difference(formatKeys, activeKeys); + _.each(intersection, function(name) { + if (Toolbar.formats.SELECT[name] != null) { + if (Array.isArray(activeFormats[name])) { + if (activeFormats[name].indexOf(formats[name]) < 0) { + return activeFormats[name].push(formats[name]); + } + } else if (activeFormats[name] !== formats[name]) { + return activeFormats[name] = [activeFormats[name], formats[name]]; + } + } + }); + _.each(missing, function(name) { + if (Toolbar.formats.TOGGLE[name] != null) { + return delete activeFormats[name]; + } else if ((Toolbar.formats.SELECT[name] != null) && !Array.isArray(activeFormats[name])) { + return activeFormats[name] = [activeFormats[name]]; + } + }); + _.each(added, function(name) { + if (Toolbar.formats.SELECT[name] != null) { + return activeFormats[name] = [formats[name]]; + } + }); + return activeFormats; + }, formatsArr[0] || {}); + }; + + return Toolbar; + +})(); + +Quill.registerModule('toolbar', Toolbar); + +module.exports = Toolbar; + + +},{"../quill":30}],28:[function(_dereq_,module,exports){ +var Quill, Tooltip, _, dom; + +Quill = _dereq_('../quill'); + +_ = Quill.require('lodash'); + +dom = Quill.require('dom'); + +Tooltip = (function() { + Tooltip.DEFAULTS = { + offset: 10, + template: '' + }; + + Tooltip.HIDE_MARGIN = '-10000px'; + + function Tooltip(quill, options) { + this.quill = quill; + this.options = options; + this.container = this.quill.addContainer('ql-tooltip'); + this.container.innerHTML = this.options.template; + this.hide(); + this.quill.on(this.quill.constructor.events.TEXT_CHANGE, (function(_this) { + return function(delta, source) { + if (_this.container.style.left !== Tooltip.HIDE_MARGIN) { + _this.range = null; + return _this.hide(); + } + }; + })(this)); + } + + Tooltip.prototype.initTextbox = function(textbox, enterCallback, escapeCallback) { + return dom(textbox).on('keydown', (function(_this) { + return function(event) { + switch (event.which) { + case dom.KEYS.ENTER: + event.preventDefault(); + return enterCallback.call(_this); + case dom.KEYS.ESCAPE: + event.preventDefault(); + return escapeCallback.call(_this); + default: + return true; + } + }; + })(this)); + }; + + Tooltip.prototype.hide = function() { + this.container.style.left = Tooltip.HIDE_MARGIN; + if (this.range) { + this.quill.setSelection(this.range); + } + return this.range = null; + }; + + Tooltip.prototype.position = function(reference) { + var left, offsetBottom, offsetLeft, offsetTop, parentBounds, referenceBounds, top; + if (reference != null) { + referenceBounds = reference.getBoundingClientRect(); + parentBounds = this.quill.container.getBoundingClientRect(); + offsetLeft = referenceBounds.left - parentBounds.left; + offsetTop = referenceBounds.top - parentBounds.top; + offsetBottom = referenceBounds.bottom - parentBounds.bottom; + left = offsetLeft + referenceBounds.width / 2 - this.container.offsetWidth / 2; + top = offsetTop + referenceBounds.height + this.options.offset; + if (top + this.container.offsetHeight > this.quill.container.offsetHeight) { + top = offsetTop - this.container.offsetHeight - this.options.offset; + } + left = Math.max(0, Math.min(left, this.quill.container.offsetWidth - this.container.offsetWidth)); + top = Math.max(0, Math.min(top, this.quill.container.offsetHeight - this.container.offsetHeight)); + } else { + left = this.quill.container.offsetWidth / 2 - this.container.offsetWidth / 2; + top = this.quill.container.offsetHeight / 2 - this.container.offsetHeight / 2; + } + top += this.quill.container.scrollTop; + return [left, top]; + }; + + Tooltip.prototype.show = function(reference) { + var left, ref, top; + this.range = this.quill.getSelection(); + ref = this.position(reference), left = ref[0], top = ref[1]; + this.container.style.left = left + "px"; + this.container.style.top = top + "px"; + return this.container.focus(); + }; + + return Tooltip; + +})(); + +Quill.registerModule('tooltip', Tooltip); + +module.exports = Tooltip; + + +},{"../quill":30}],29:[function(_dereq_,module,exports){ +var Delta, Quill, UndoManager, _; + +Quill = _dereq_('../quill'); + +_ = Quill.require('lodash'); + +Delta = Quill.require('delta'); + +UndoManager = (function() { + UndoManager.DEFAULTS = { + delay: 1000, + maxStack: 100, + userOnly: false + }; + + UndoManager.hotkeys = { + UNDO: { + key: 'Z', + metaKey: true + }, + REDO: { + key: 'Z', + metaKey: true, + shiftKey: true + } + }; + + function UndoManager(quill, options) { + this.quill = quill; + this.options = options != null ? options : {}; + this.lastRecorded = 0; + this.ignoreChange = false; + this.clear(); + this.initListeners(); + } + + UndoManager.prototype.initListeners = function() { + this.quill.onModuleLoad('keyboard', (function(_this) { + return function(keyboard) { + var redoKey; + keyboard.addHotkey(UndoManager.hotkeys.UNDO, function() { + _this.quill.editor.checkUpdate(); + _this.undo(); + return false; + }); + redoKey = [UndoManager.hotkeys.REDO]; + if (navigator.platform.indexOf('Win') > -1) { + redoKey.push({ + key: 'Y', + metaKey: true + }); + } + return keyboard.addHotkey(redoKey, function() { + _this.quill.editor.checkUpdate(); + _this.redo(); + return false; + }); + }; + })(this)); + return this.quill.on(this.quill.constructor.events.TEXT_CHANGE, (function(_this) { + return function(delta, source) { + if (_this.ignoreChange) { + return; + } + if (!_this.options.userOnly || source === Quill.sources.USER) { + _this.record(delta, _this.oldDelta); + } else { + _this._transform(delta); + } + return _this.oldDelta = _this.quill.getContents(); + }; + })(this)); + }; + + UndoManager.prototype.clear = function() { + this.stack = { + undo: [], + redo: [] + }; + return this.oldDelta = this.quill.getContents(); + }; + + UndoManager.prototype.record = function(changeDelta, oldDelta) { + var change, ignored, timestamp, undoDelta; + if (!(changeDelta.ops.length > 0)) { + return; + } + this.stack.redo = []; + try { + undoDelta = this.quill.getContents().diff(this.oldDelta); + timestamp = new Date().getTime(); + if (this.lastRecorded + this.options.delay > timestamp && this.stack.undo.length > 0) { + change = this.stack.undo.pop(); + undoDelta = undoDelta.compose(change.undo); + changeDelta = change.redo.compose(changeDelta); + } else { + this.lastRecorded = timestamp; + } + this.stack.undo.push({ + redo: changeDelta, + undo: undoDelta + }); + if (this.stack.undo.length > this.options.maxStack) { + return this.stack.undo.unshift(); + } + } catch (_error) { + ignored = _error; + console.warn('Could not record change... clearing undo stack.'); + return this.clear(); + } + }; + + UndoManager.prototype.redo = function() { + return this._change('redo', 'undo'); + }; + + UndoManager.prototype.undo = function() { + return this._change('undo', 'redo'); + }; + + UndoManager.prototype._getLastChangeIndex = function(delta) { + var index, lastIndex; + lastIndex = 0; + index = 0; + _.each(delta.ops, function(op) { + if (op.insert != null) { + return lastIndex = Math.max(index + (op.insert.length || 1), lastIndex); + } else if (op["delete"] != null) { + return lastIndex = Math.max(index, lastIndex); + } else if (op.retain != null) { + if (op.attributes != null) { + lastIndex = Math.max(index + op.retain, lastIndex); + } + return index += op.retain; + } + }); + return lastIndex; + }; + + UndoManager.prototype._change = function(source, dest) { + var change, index; + if (this.stack[source].length > 0) { + change = this.stack[source].pop(); + this.lastRecorded = 0; + this.ignoreChange = true; + this.quill.updateContents(change[source], Quill.sources.USER); + this.ignoreChange = false; + index = this._getLastChangeIndex(change[source]); + this.quill.setSelection(index, index); + this.oldDelta = this.quill.getContents(); + return this.stack[dest].push(change); + } + }; + + UndoManager.prototype._transform = function(delta) { + var change, i, j, len, len1, ref, ref1, results; + this.oldDelta = delta.transform(this.oldDelta, true); + ref = this.stack.undo; + for (i = 0, len = ref.length; i < len; i++) { + change = ref[i]; + change.undo = delta.transform(change.undo, true); + change.redo = delta.transform(change.redo, true); + } + ref1 = this.stack.redo; + results = []; + for (j = 0, len1 = ref1.length; j < len1; j++) { + change = ref1[j]; + change.undo = delta.transform(change.undo, true); + results.push(change.redo = delta.transform(change.redo, true)); + } + return results; + }; + + return UndoManager; + +})(); + +Quill.registerModule('undo-manager', UndoManager); + +module.exports = UndoManager; + + +},{"../quill":30}],30:[function(_dereq_,module,exports){ +var Delta, Document, Editor, EventEmitter2, Format, Normalizer, Quill, Range, _, dom, pkg, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty, + slice = [].slice; + +_ = _dereq_('lodash'); + +pkg = _dereq_('../package.json'); + +Delta = _dereq_('rich-text/lib/delta'); + +EventEmitter2 = _dereq_('eventemitter2').EventEmitter2; + +dom = _dereq_('./lib/dom'); + +Document = _dereq_('./core/document'); + +Editor = _dereq_('./core/editor'); + +Format = _dereq_('./core/format'); + +Normalizer = _dereq_('./core/normalizer'); + +Range = _dereq_('./lib/range'); + +Quill = (function(superClass) { + extend(Quill, superClass); + + Quill.version = pkg.version; + + Quill.editors = []; + + Quill.modules = []; + + Quill.themes = []; + + Quill.DEFAULTS = { + formats: ['align', 'bold', 'italic', 'strike', 'underline', 'color', 'background', 'font', 'size', 'link', 'image', 'bullet', 'list'], + modules: { + 'keyboard': true, + 'paste-manager': true, + 'undo-manager': true + }, + pollInterval: 100, + readOnly: false, + styles: {}, + theme: 'base' + }; + + Quill.events = { + FORMAT_INIT: 'format-init', + MODULE_INIT: 'module-init', + POST_EVENT: 'post-event', + PRE_EVENT: 'pre-event', + SELECTION_CHANGE: 'selection-change', + TEXT_CHANGE: 'text-change' + }; + + Quill.sources = Editor.sources; + + Quill.registerModule = function(name, module) { + if (Quill.modules[name] != null) { + console.warn("Overwriting " + name + " module"); + } + return Quill.modules[name] = module; + }; + + Quill.registerTheme = function(name, theme) { + if (Quill.themes[name] != null) { + console.warn("Overwriting " + name + " theme"); + } + return Quill.themes[name] = theme; + }; + + Quill.require = function(name) { + switch (name) { + case 'lodash': + return _; + case 'delta': + return Delta; + case 'format': + return Format; + case 'normalizer': + return Normalizer; + case 'dom': + return dom; + case 'document': + return Document; + case 'range': + return Range; + default: + return null; + } + }; + + function Quill(container1, options) { + var html, moduleOptions, themeClass; + this.container = container1; + if (options == null) { + options = {}; + } + if (_.isString(this.container)) { + this.container = document.querySelector(this.container); + } + if (this.container == null) { + throw new Error('Invalid Quill container'); + } + moduleOptions = _.defaults(options.modules || {}, Quill.DEFAULTS.modules); + html = this.container.innerHTML; + this.container.innerHTML = ''; + this.options = _.defaults(options, Quill.DEFAULTS); + this.options.modules = moduleOptions; + this.options.id = this.id = "ql-editor-" + (Quill.editors.length + 1); + this.modules = {}; + this.root = this.addContainer('ql-editor'); + this.editor = new Editor(this.root, this, this.options); + Quill.editors.push(this); + this.setHTML(html, Quill.sources.SILENT); + themeClass = Quill.themes[this.options.theme]; + if (themeClass == null) { + throw new Error("Cannot load " + this.options.theme + " theme. Are you sure you registered it?"); + } + this.theme = new themeClass(this, this.options); + _.each(this.options.modules, (function(_this) { + return function(option, name) { + return _this.addModule(name, option); + }; + })(this)); + } + + Quill.prototype.destroy = function() { + var html; + html = this.getHTML(); + _.each(this.modules, function(module, name) { + if (_.isFunction(module.destroy)) { + return module.destroy(); + } + }); + this.editor.destroy(); + this.removeAllListeners(); + Quill.editors.splice(_.indexOf(Quill.editors, this), 1); + return this.container.innerHTML = html; + }; + + Quill.prototype.addContainer = function(className, before) { + var container, refNode; + if (before == null) { + before = false; + } + refNode = before ? this.root : null; + container = document.createElement('div'); + dom(container).addClass(className); + this.container.insertBefore(container, refNode); + return container; + }; + + Quill.prototype.addFormat = function(name, config) { + this.editor.doc.addFormat(name, config); + return this.emit(Quill.events.FORMAT_INIT, name); + }; + + Quill.prototype.addModule = function(name, options) { + var moduleClass; + moduleClass = Quill.modules[name]; + if (moduleClass == null) { + throw new Error("Cannot load " + name + " module. Are you sure you registered it?"); + } + if (options === true) { + options = {}; + } + options = _.defaults(options, this.theme.constructor.OPTIONS[name] || {}, moduleClass.DEFAULTS || {}); + this.modules[name] = new moduleClass(this, options); + this.emit(Quill.events.MODULE_INIT, name, this.modules[name]); + return this.modules[name]; + }; + + Quill.prototype.deleteText = function(start, end, source) { + var delta, formats, ref; + if (source == null) { + source = Quill.sources.API; + } + ref = this._buildParams(start, end, {}, source), start = ref[0], end = ref[1], formats = ref[2], source = ref[3]; + if (!(end > start)) { + return; + } + delta = new Delta().retain(start)["delete"](end - start); + return this.editor.applyDelta(delta, source); + }; + + Quill.prototype.emit = function() { + var args, eventName; + eventName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + Quill.__super__.emit.apply(this, [Quill.events.PRE_EVENT, eventName].concat(slice.call(args))); + Quill.__super__.emit.apply(this, [eventName].concat(slice.call(args))); + return Quill.__super__.emit.apply(this, [Quill.events.POST_EVENT, eventName].concat(slice.call(args))); + }; + + Quill.prototype.focus = function() { + return this.editor.focus(); + }; + + Quill.prototype.formatLine = function(start, end, name, value, source) { + var formats, line, offset, ref, ref1; + ref = this._buildParams(start, end, name, value, source), start = ref[0], end = ref[1], formats = ref[2], source = ref[3]; + ref1 = this.editor.doc.findLineAt(end), line = ref1[0], offset = ref1[1]; + if (line != null) { + end += line.length - offset; + } + return this.formatText(start, end, formats, source); + }; + + Quill.prototype.formatText = function(start, end, name, value, source) { + var delta, formats, ref; + ref = this._buildParams(start, end, name, value, source), start = ref[0], end = ref[1], formats = ref[2], source = ref[3]; + formats = _.reduce(formats, (function(_this) { + return function(formats, value, name) { + var format; + format = _this.editor.doc.formats[name]; + if (!(value && value !== format.config["default"])) { + formats[name] = null; + } + return formats; + }; + })(this), formats); + delta = new Delta().retain(start).retain(end - start, formats); + return this.editor.applyDelta(delta, source); + }; + + Quill.prototype.getBounds = function(index) { + return this.editor.getBounds(index); + }; + + Quill.prototype.getContents = function(start, end) { + if (start == null) { + start = 0; + } + if (end == null) { + end = null; + } + if (_.isObject(start)) { + end = start.end; + start = start.start; + } + return this.editor.delta.slice(start, end); + }; + + Quill.prototype.getHTML = function() { + return this.editor.doc.getHTML(); + }; + + Quill.prototype.getLength = function() { + return this.editor.length; + }; + + Quill.prototype.getModule = function(name) { + return this.modules[name]; + }; + + Quill.prototype.getSelection = function() { + this.editor.checkUpdate(); + return this.editor.selection.getRange(); + }; + + Quill.prototype.getText = function(start, end) { + if (start == null) { + start = 0; + } + if (end == null) { + end = null; + } + return _.map(this.getContents(start, end).ops, function(op) { + if (_.isString(op.insert)) { + return op.insert; + } else { + return ''; + } + }).join(''); + }; + + Quill.prototype.insertEmbed = function(index, type, url, source) { + var delta, end, formats, ref; + ref = this._buildParams(index, 0, type, url, source), index = ref[0], end = ref[1], formats = ref[2], source = ref[3]; + delta = new Delta().retain(index).insert(1, formats); + return this.editor.applyDelta(delta, source); + }; + + Quill.prototype.insertText = function(index, text, name, value, source) { + var delta, end, formats, ref; + ref = this._buildParams(index, 0, name, value, source), index = ref[0], end = ref[1], formats = ref[2], source = ref[3]; + if (!(text.length > 0)) { + return; + } + delta = new Delta().retain(index).insert(text, formats); + return this.editor.applyDelta(delta, source); + }; + + Quill.prototype.onModuleLoad = function(name, callback) { + if (this.modules[name]) { + return callback(this.modules[name]); + } + return this.on(Quill.events.MODULE_INIT, function(moduleName, module) { + if (moduleName === name) { + return callback(module); + } + }); + }; + + Quill.prototype.prepareFormat = function(name, value, source) { + var format, range; + if (source == null) { + source = Quill.sources.API; + } + format = this.editor.doc.formats[name]; + if (format == null) { + return; + } + range = this.getSelection(); + if (!(range != null ? range.isCollapsed() : void 0)) { + return; + } + if (format.isType(Format.types.LINE)) { + return this.formatLine(range, name, value, source); + } else { + return format.prepare(value); + } + }; + + Quill.prototype.setContents = function(delta, source) { + var lastOp; + if (source == null) { + source = Quill.sources.API; + } + if (Array.isArray(delta)) { + delta = new Delta(delta.slice()); + } else { + delta = new Delta(delta.ops.slice()); + } + lastOp = _.last(delta.slice(delta.length() - 1).ops); + delta["delete"](this.getLength() - 1); + if ((lastOp != null) && _.isString(lastOp.insert) && _.last(lastOp.insert) === '\n') { + delta["delete"](1); + } + return this.updateContents(delta, source); + }; + + Quill.prototype.setHTML = function(html, source) { + if (source == null) { + source = Quill.sources.API; + } + if (!html.trim()) { + html = "<" + dom.DEFAULT_BLOCK_TAG + "><" + dom.DEFAULT_BREAK_TAG + ">"; + } + this.editor.doc.setHTML(html); + return this.editor.checkUpdate(source); + }; + + Quill.prototype.setSelection = function(start, end, source) { + var range; + if (source == null) { + source = Quill.sources.API; + } + if (_.isNumber(start) && _.isNumber(end)) { + range = new Range(start, end); + } else { + range = start; + source = end || source; + } + return this.editor.selection.setRange(range, source); + }; + + Quill.prototype.setText = function(text, source) { + var delta; + if (source == null) { + source = Quill.sources.API; + } + delta = new Delta().insert(text); + return this.setContents(delta, source); + }; + + Quill.prototype.updateContents = function(delta, source) { + if (source == null) { + source = Quill.sources.API; + } + if (Array.isArray(delta)) { + delta = { + ops: delta + }; + } + return this.editor.applyDelta(delta, source); + }; + + Quill.prototype._buildParams = function() { + var formats, params; + params = 1 <= arguments.length ? slice.call(arguments, 0) : []; + if (_.isObject(params[0])) { + params.splice(0, 1, params[0].start, params[0].end); + } + if (_.isString(params[2])) { + formats = {}; + formats[params[2]] = params[3]; + params.splice(2, 2, formats); + } + if (params[3] == null) { + params[3] = Quill.sources.API; + } + return params; + }; + + return Quill; + +})(EventEmitter2); + +Quill.registerTheme('base', _dereq_('./themes/base')); + +Quill.registerTheme('snow', _dereq_('./themes/snow')); + +module.exports = Quill; + + +},{"../package.json":7,"./core/document":8,"./core/editor":9,"./core/format":10,"./core/normalizer":13,"./lib/dom":17,"./lib/range":20,"./themes/base":32,"./themes/snow":33,"eventemitter2":2,"lodash":1,"rich-text/lib/delta":3}],31:[function(_dereq_,module,exports){ +module.exports = ".ql-image-tooltip{padding:10px;width:300px}.ql-image-tooltip:after{clear:both;content:\"\";display:table}.ql-image-tooltip a{border:1px solid #000;box-sizing:border-box;display:inline-block;float:left;padding:5px;text-align:center;width:50%}.ql-image-tooltip img{bottom:0;left:0;margin:auto;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.ql-image-tooltip .input{box-sizing:border-box;width:100%}.ql-image-tooltip .preview{margin:10px 0;position:relative;border:1px dashed #000;height:200px}.ql-image-tooltip .preview span{display:inline-block;position:absolute;text-align:center;top:40%;width:100%}.ql-link-tooltip{padding:5px 10px}.ql-link-tooltip input.input{width:170px}.ql-link-tooltip a.done,.ql-link-tooltip input.input{display:none}.ql-link-tooltip a.change{margin-right:4px}.ql-link-tooltip.editing a.done,.ql-link-tooltip.editing input.input{display:inline-block}.ql-link-tooltip.editing a.change,.ql-link-tooltip.editing a.remove,.ql-link-tooltip.editing a.url{display:none}.ql-multi-cursor{position:absolute;left:0;top:0;z-index:1000}.ql-multi-cursor .cursor{margin-left:-1px;position:absolute}.ql-multi-cursor .cursor-flag{bottom:100%;position:absolute;white-space:nowrap}.ql-multi-cursor .cursor-name{display:inline-block;color:#fff;padding:2px 8px}.ql-multi-cursor .cursor-caret{height:100%;position:absolute;width:2px}.ql-multi-cursor .cursor.hidden .cursor-flag{display:none}.ql-multi-cursor .cursor.top .cursor-flag{bottom:auto;top:100%}.ql-multi-cursor .cursor.right .cursor-flag{right:-2px}.ql-paste-manager{left:-100000px;position:absolute;top:50%}.ql-toolbar{box-sizing:border-box}.ql-tooltip{background-color:#fff;border:1px solid #000;box-sizing:border-box;position:absolute;top:0;white-space:nowrap;z-index:2000}.ql-tooltip a{cursor:pointer;text-decoration:none}.ql-container{box-sizing:border-box;cursor:text;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;line-height:1.42;margin:0;overflow-x:hidden;overflow-y:auto;padding:12px 15px;position:relative}.ql-editor{box-sizing:border-box;min-height:100%;outline:0;tab-size:4;white-space:pre-wrap}.ql-editor div{margin:0;padding:0}.ql-editor a{text-decoration:underline}.ql-editor b{font-weight:700}.ql-editor i{font-style:italic}.ql-editor s{text-decoration:line-through}.ql-editor u{text-decoration:underline}.ql-editor a,.ql-editor b,.ql-editor i,.ql-editor s,.ql-editor span,.ql-editor u{background-color:inherit}.ql-editor img{max-width:100%}.ql-editor blockquote,.ql-editor ol,.ql-editor ul{margin:0 0 0 2em;padding:0}.ql-editor ol{list-style-type:decimal}.ql-editor ul{list-style-type:disc}.ql-editor.ql-ie-10 br,.ql-editor.ql-ie-9 br{display:none}"; +},{}],32:[function(_dereq_,module,exports){ +var BaseTheme, _, baseStyles, dom; + +_ = _dereq_('lodash'); + +dom = _dereq_('../../lib/dom'); + +baseStyles = _dereq_('./base.styl'); + +BaseTheme = (function() { + BaseTheme.OPTIONS = {}; + + BaseTheme.objToCss = function(obj) { + return _.map(obj, function(value, key) { + var innerStr; + innerStr = _.map(value, function(innerValue, innerKey) { + return innerKey + ": " + innerValue + ";"; + }).join(' '); + return key + " { " + innerStr + " }"; + }).join("\n"); + }; + + function BaseTheme(quill, options) { + var version; + this.quill = quill; + this.options = options; + dom(this.quill.container).addClass('ql-container'); + if (this.options.styles) { + this.addStyles(baseStyles + BaseTheme.objToCss(this.options.styles)); + } + if (dom.isIE(10)) { + version = dom.isIE(9) ? '9' : '10'; + dom(this.quill.root).addClass('ql-ie-' + version); + } + } + + BaseTheme.prototype.addStyles = function(css) { + var style; + if (_.isObject(css)) { + css = BaseTheme.objToCss(css); + } + style = document.createElement('style'); + style.type = 'text/css'; + style.appendChild(document.createTextNode(css)); + return document.head.appendChild(style); + }; + + return BaseTheme; + +})(); + +module.exports = BaseTheme; + + +},{"../../lib/dom":17,"./base.styl":31,"lodash":1}],33:[function(_dereq_,module,exports){ +var BaseTheme, ColorPicker, Picker, SnowTheme, _, dom, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +_ = _dereq_('lodash'); + +ColorPicker = _dereq_('../../lib/color-picker'); + +BaseTheme = _dereq_('../base'); + +dom = _dereq_('../../lib/dom'); + +Picker = _dereq_('../../lib/picker'); + +SnowTheme = (function(superClass) { + extend(SnowTheme, superClass); + + SnowTheme.COLORS = ["#000000", "#e60000", "#ff9900", "#ffff00", "#008A00", "#0066cc", "#9933ff", "#ffffff", "#facccc", "#ffebcc", "#ffffcc", "#cce8cc", "#cce0f5", "#ebd6ff", "#bbbbbb", "#f06666", "#ffc266", "#ffff66", "#66b966", "#66a3e0", "#c285ff", "#888888", "#a10000", "#b26b00", "#b2b200", "#006100", "#0047b2", "#6b24b2", "#444444", "#5c0000", "#663d00", "#666600", "#003700", "#002966", "#3d1466"]; + + SnowTheme.OPTIONS = { + 'multi-cursor': { + template: ' ' + } + }; + + function SnowTheme(quill, options) { + this.quill = quill; + this.options = options; + SnowTheme.__super__.constructor.apply(this, arguments); + dom(this.quill.container).addClass('ql-snow'); + this.pickers = []; + this.quill.on(this.quill.constructor.events.SELECTION_CHANGE, (function(_this) { + return function(range) { + if (range != null) { + return _.invoke(_this.pickers, 'close'); + } + }; + })(this)); + this.quill.onModuleLoad('multi-cursor', _.bind(this.extendMultiCursor, this)); + this.quill.onModuleLoad('toolbar', _.bind(this.extendToolbar, this)); + } + + SnowTheme.prototype.extendMultiCursor = function(module) { + return module.on(module.constructor.events.CURSOR_ADDED, function(cursor) { + var bottomTriangle, topTriangle; + bottomTriangle = cursor.elem.querySelector('.cursor-triangle.bottom'); + topTriangle = cursor.elem.querySelector('.cursor-triangle.top'); + return bottomTriangle.style.borderTopColor = topTriangle.style.borderBottomColor = cursor.color; + }); + }; + + SnowTheme.prototype.extendToolbar = function(module) { + dom(module.container).addClass('ql-snow'); + _.each(['color', 'background', 'font', 'size', 'align'], (function(_this) { + return function(format) { + var picker, select; + select = module.container.querySelector(".ql-" + format); + if (select == null) { + return; + } + switch (format) { + case 'font': + case 'size': + case 'align': + picker = new Picker(select); + break; + case 'color': + case 'background': + picker = new ColorPicker(select); + _.each(picker.container.querySelectorAll('.ql-picker-item'), function(item, i) { + if (i < 7) { + return dom(item).addClass('ql-primary-color'); + } + }); + } + if (picker != null) { + return _this.pickers.push(picker); + } + }; + })(this)); + return _.each(dom(module.container).textNodes(), function(node) { + if (dom(node).text().trim().length === 0) { + return dom(node).remove(); + } + }); + }; + + return SnowTheme; + +})(BaseTheme); + +module.exports = SnowTheme; + + +},{"../../lib/color-picker":16,"../../lib/dom":17,"../../lib/picker":19,"../base":32,"lodash":1}]},{},[15])(15) +}); \ No newline at end of file diff --git a/Examples/bower_components/quill/dist/quill.min.js b/Examples/bower_components/quill/dist/quill.min.js new file mode 100644 index 00000000..d9d9ebd8 --- /dev/null +++ b/Examples/bower_components/quill/dist/quill.min.js @@ -0,0 +1,9 @@ +/*! Quill Editor v0.20.1 + * https://quilljs.com/ + * Copyright (c) 2014, Jason Chen + * Copyright (c) 2013, salesforce.com + */ +!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Quill=a()}}(function(){var a;return function b(a,c,d){function e(g,h){if(!c[g]){if(!a[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};a[g][0].call(k.exports,function(b){var c=a[g][1][b];return e(c?c:b)},k,k.exports,b,a,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=200?Wc(b):null,j=b.length;i&&(g=p,h=!1,b=i);a:for(;++ed;)a=a[b[d++]];return d&&d==e?a:lb}}function L(a,b,c,d,e,f){return a===b?!0:null==a||null==b||!Xa(a)&&!j(b)?a!==a&&b!==b:M(a,b,L,c,d,e,f)}function M(a,b,c,d,e,f,g){var h=jd(a),i=jd(b),j=Bb,k=Bb;h||(j=tc.call(a),j==Ab?j=Ib:j!=Ib&&(h=_a(a))),i||(k=tc.call(b),k==Ab?k=Ib:k!=Ib&&(i=_a(b)));var l=j==Ib,m=k==Ib,n=j==k;if(n&&!h&&!l)return oa(a,b,j);if(!e){var o=l&&rc.call(a,"__wrapped__"),p=m&&rc.call(b,"__wrapped__");if(o||p)return c(o?a.value():a,p?b.value():b,d,e,f,g)}if(!n)return!1;f||(f=[]),g||(g=[]);for(var q=f.length;q--;)if(f[q]==a)return g[q]==b;f.push(a),g.push(b);var r=(h?na:pa)(a,b,c,d,e,f,g);return f.pop(),g.pop(),r}function N(a,b,c){var d=b.length,e=d,f=!c;if(null==a)return!e;for(a=Ma(a);d--;){var g=b[d];if(f&&g[2]?g[1]!==a[g[0]]:!(g[0]in a))return!1}for(;++db&&(b=-b>e?0:e+b),c=c===lb||c>e?e:+c||0,0>c&&(c+=e),e=b>c?0:c-b>>>0,b>>>=0;for(var f=Array(e);++d=e){for(;e>d;){var f=d+e>>>1,g=a[f];(c?b>=g:b>g)&&null!==g?d=f+1:e=f}return e}return X(a,b,gb,c)}function X(a,b,c,d){b=c(b);for(var e=0,f=a?a.length:0,g=b!==b,h=null===b,i=b===lb;f>e;){var j=xc((e+f)/2),k=c(a[j]),l=k!==lb,m=k===k;if(g)var n=m||d;else n=h?m&&l&&(d||null!=k):i?m&&(d||l):null==k?!1:d?b>=k:b>k;n?e=j+1:f=j}return Hc(f,Lc)}function Y(a,b,c){if("function"!=typeof a)return gb;if(b===lb)return a;switch(c){case 1:return function(c){return a.call(b,c)};case 3:return function(c,d,e){return a.call(b,c,d,e)};case 4:return function(c,d,e,f){return a.call(b,c,d,e,f)};case 5:return function(c,d,e,f,g){return a.call(b,c,d,e,f,g)}}return function(){return a.apply(b,arguments)}}function Z(a){return wc.call(a,0)}function $(a,b,c){for(var d=c.length,e=-1,f=Gc(a.length-d,0),g=-1,h=b.length,i=Array(f+h);++g2?c[e-2]:lb,g=e>2?c[2]:lb,h=e>1?c[e-1]:lb;for("function"==typeof f?(f=Y(f,h,5),e-=2):(f="function"==typeof h?h:lb,e-=f?1:0),g&&Ba(c[0],c[1],g)&&(f=3>e?lb:f,e=1);++d-1?c[g]:lb}return G(c,d,a)}}function ha(a,b){return function(c,d,e){return"function"==typeof d&&e===lb&&jd(c)?a(c,d):b(c,Y(d,e,3))}}function ia(a){var b=Sa(function(c,d){var e=k(d,b.placeholder);return ma(c,a,null,d,e)});return b}function ja(a,b){return function(c,d,e,f){var g=arguments.length<3;return"function"==typeof d&&f===lb&&jd(c)?a(c,d,e,g):T(c,qa(d,f,4),e,g,b)}}function ka(a,b,c,d,e,f,g,h,i,j){function l(){for(var u=arguments.length,v=u,w=Array(u);v--;)w[v]=arguments[v];if(d&&(w=$(w,d,e)),f&&(w=_(w,f,g)),p||s){var x=l.placeholder,y=k(w,x);if(u-=y.length,j>u){var z=h?r(h):null,A=Gc(j-u,0),B=p?y:null,C=p?null:y,D=p?w:null,E=p?null:w;b|=p?sb:tb,b&=~(p?tb:sb),q||(b&=~(nb|ob));var F=[a,b,c,D,B,E,C,z,i,A],G=ka.apply(lb,F);return Da(a)&&Zc(G,F),G.placeholder=x,G}}var H=n?c:this,I=o?H[a]:a;return h&&(w=Ja(w,h)),m&&ii))return!1;for(;++h-1&&a%1==0&&b>a}function Ba(a,b,c){if(!Xa(c))return!1;var d=typeof b;if("number"==d?za(c)&&Aa(b,c.length):"string"==d&&b in c){var e=c[b];return a===a?a===e:e!==e}return!1}function Ca(a,b){var c=typeof a;if("string"==c&&Yb.test(a)||"number"==c)return!0;if(jd(a))return!1;var d=!Xb.test(a);return d||null!=b&&a in Ma(b)}function Da(a){var b=ra(a);if(!(b in n.prototype))return!1;var c=l[b];if(a===c)return!0;var d=Xc(c);return!!d&&a===d[0]}function Ea(a){return"number"==typeof a&&a>-1&&a%1==0&&Oc>=a}function Fa(a){return a===a&&!Xa(a)}function Ga(a,b){var c=a[1],d=b[1],e=c|d,f=ub>e,g=d==ub&&c==qb||d==ub&&c==vb&&a[7].length<=b[8]||d==(ub|vb)&&c==qb;if(!f&&!g)return a;d&nb&&(a[2]=b[2],e|=c&nb?0:pb);var h=b[3];if(h){var i=a[3];a[3]=i?$(i,h,b[4]):r(h),a[4]=i?k(a[3],zb):r(b[4])}return h=b[5],h&&(i=a[5],a[5]=i?_(i,h,b[6]):r(h),a[6]=i?k(a[5],zb):r(b[6])),h=b[7],h&&(a[7]=r(h)),d&ub&&(a[8]=null==a[8]?b[8]:Hc(a[8],b[8])),null==a[9]&&(a[9]=b[9]),a[0]=b[0],a[1]=e,a}function Ha(a,b){a=Ma(a);for(var c=-1,d=b.length,e={};++cc?Gc(d+c,0):c;else if(c){var e=W(a,b),g=a[e];return(b===b?b===g:g!==g)?e:-1}return f(a,b,c||0)}function Pa(a){var b=a?a.length:0;return b?a[b-1]:lb}function Qa(a,b,c){var d=jd(a)?t:F;return c&&Ba(a,b,c)&&(b=null),("function"!=typeof b||c!==lb)&&(b=qa(b,c,3)),d(a,b)}function Ra(a,b,c){var d=jd(a)?u:O;return b=qa(b,c,3),d(a,b)}function Sa(a,b){if("function"!=typeof a)throw new TypeError(yb);return b=Gc(b===lb?a.length-1:+b||0,0),function(){for(var c=arguments,d=-1,e=Gc(c.length-b,0),f=Array(e);++d-1}function Wa(a,b,c,d){c="function"==typeof c?Y(c,d,3):lb;var e=c?c(a,b):lb;return e===lb?L(a,b,c):!!e}function Xa(a){var b=typeof a;return!!a&&("object"==b||"function"==b)}function Ya(a){return null==a?!1:tc.call(a)==Fb?uc.test(qc.call(a)):j(a)&&cc.test(a)}function Za(a){return"number"==typeof a||j(a)&&tc.call(a)==Hb}function $a(a){return"string"==typeof a||j(a)&&tc.call(a)==Lb}function _a(a){return j(a)&&Ea(a.length)&&!!ec[tc.call(a)]}function ab(a){if(null==a)return[];Xa(a)||(a=Object(a));var b=a.length;b=b&&Ea(b)&&(jd(a)||Ua(a))&&b||0;for(var c=a.constructor,d=-1,e="function"==typeof c&&c.prototype===a,f=Array(b),g=b>0;++d>>1,Nc=Cc?Cc.BYTES_PER_ELEMENT:0,Oc=9007199254740991,Pc=Bc&&new Bc,Qc={},Rc=l.support={};!function(a){var b=function(){this.x=a},c=[];b.prototype={valueOf:a,y:a};for(var d in new b)c.push(d);try{Rc.dom=11===pc.createDocumentFragment().nodeType}catch(e){Rc.dom=!1}}(1,0);var Sc=function(){function a(){}return function(b){if(Xa(b)){a.prototype=b;var c=new a;a.prototype=null}return c||{}}}(),Tc=ca(J),Uc=da(),Vc=Pc?function(a,b){return Pc.set(a,b),a}:gb;wc||(Z=vc&&Ac?function(a){var b=a.byteLength,c=Cc?xc(b/Nc):0,d=c*Nc,e=new vc(b);if(c){var f=new Cc(e,0,c);f.set(new Cc(a,0,c))}return b!=d&&(f=new Ac(e,d),f.set(new Ac(a,d))),e}:fb(null));var Wc=Dc&&zc?function(a){return new o(a)}:fb(null),Xc=Pc?function(a){return Pc.get(a)}:ib,Yc=R("length"),Zc=function(){var a=0,b=0;return function(c,d){var e=fd(),f=xb-(e-b);if(b=e,f>0){if(++a>=wb)return c}else a=0;return Vc(c,d)}}(),$c=Sa(function(a,b){return za(a)?E(a,H(b,!1,!0)):[]}),_c=Sa(function(a){for(var b=a.length,c=b,d=Array(l),e=sa(),g=e==f,h=[];c--;){var i=a[c]=za(i=a[c])?i:[];d[c]=g&&i.length>=120?Wc(c&&i):null}var j=a[0],k=-1,l=j?j.length:0,m=d[0];a:for(;++ke;e++)a&&a.push(c._listeners[e]);return[c]}if("*"===o||"**"===o||c[o]){if("*"===o){for(h in c)"_listeners"!==h&&c.hasOwnProperty(h)&&(m=m.concat(g(a,b,c[h],d+1)));return m}if("**"===o){l=d+1===n||d+2===n&&"*"===p,l&&c._listeners&&(m=m.concat(g(a,b,c,n)));for(h in c)"_listeners"!==h&&c.hasOwnProperty(h)&&("*"===h||"**"===h?(c[h]._listeners&&!l&&(m=m.concat(g(a,b,c[h],n))),m=m.concat(g(a,b,c[h],d))):m=h===p?m.concat(g(a,b,c[h],d+2)):m.concat(g(a,b,c[h],d)));return m}m=m.concat(g(a,b,c[o],d+1))}if(i=c["*"],i&&g(a,b,i,d+1),j=c["**"])if(n>d){j._listeners&&g(a,b,j,n);for(h in j)"_listeners"!==h&&j.hasOwnProperty(h)&&(h===p?g(a,b,j[h],d+2):h===o?g(a,b,j[h],d+1):(k={},k[h]=j[h],g(a,b,{"**":k},d+1)))}else j._listeners?g(a,b,j,n):j["*"]&&j["*"]._listeners&&g(a,b,j["*"],n);return m}function h(a,b){a="string"==typeof a?a.split(this.delimiter):a.slice();for(var c=0,d=a.length;d>c+1;c++)if("**"===a[c]&&"**"===a[c+1])return;for(var e=this.listenerTree,f=a.shift();f;){if(e[f]||(e[f]={}),e=e[f],0===a.length){if(e._listeners){if("function"==typeof e._listeners)e._listeners=[e._listeners,b];else if(i(e._listeners)&&(e._listeners.push(b),!e._listeners.warned)){var g=j;"undefined"!=typeof this._events.maxListeners&&(g=this._events.maxListeners),g>0&&e._listeners.length>g&&(e._listeners.warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",e._listeners.length),console.trace())}}else e._listeners=b;return!0}f=a.shift()}return!0}var i=Array.isArray?Array.isArray:function(a){return"[object Array]"===Object.prototype.toString.call(a)},j=10;f.prototype.delimiter=".",f.prototype.setMaxListeners=function(a){this._events||c.call(this),this._events.maxListeners=a,this._conf||(this._conf={}),this._conf.maxListeners=a},f.prototype.event="",f.prototype.once=function(a,b){return this.many(a,1,b),this},f.prototype.many=function(a,b,c){function d(){0===--b&&e.off(a,d),c.apply(this,arguments)}var e=this;if("function"!=typeof c)throw new Error("many only accepts instances of Function");return d._origin=c,this.on(a,d),e},f.prototype.emit=function(){this._events||c.call(this);var a=arguments[0];if("newListener"===a&&!this.newListener&&!this._events.newListener)return!1;if(this._all){for(var b=arguments.length,d=new Array(b-1),e=1;b>e;e++)d[e-1]=arguments[e];for(e=0,b=this._all.length;b>e;e++)this.event=a,this._all[e].apply(this,d)}if("error"===a&&!(this._all||this._events.error||this.wildcard&&this.listenerTree.error))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");var f;if(this.wildcard){f=[];var h="string"==typeof a?a.split(this.delimiter):a.slice();g.call(this,f,h,this.listenerTree,0)}else f=this._events[a];if("function"==typeof f){if(this.event=a,1===arguments.length)f.call(this);else if(arguments.length>1)switch(arguments.length){case 2:f.call(this,arguments[1]);break;case 3:f.call(this,arguments[1],arguments[2]);break;default:for(var b=arguments.length,d=new Array(b-1),e=1;b>e;e++)d[e-1]=arguments[e];f.apply(this,d)}return!0}if(f){for(var b=arguments.length,d=new Array(b-1),e=1;b>e;e++)d[e-1]=arguments[e];for(var i=f.slice(),e=0,b=i.length;b>e;e++)this.event=a,i[e].apply(this,d);return i.length>0||!!this._all}return!!this._all},f.prototype.on=function(a,b){if("function"==typeof a)return this.onAny(a),this;if("function"!=typeof b)throw new Error("on only accepts instances of Function");if(this._events||c.call(this),this.emit("newListener",a,b),this.wildcard)return h.call(this,a,b),this;if(this._events[a]){if("function"==typeof this._events[a])this._events[a]=[this._events[a],b];else if(i(this._events[a])&&(this._events[a].push(b),!this._events[a].warned)){var d=j;"undefined"!=typeof this._events.maxListeners&&(d=this._events.maxListeners),d>0&&this._events[a].length>d&&(this._events[a].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[a].length),console.trace())}}else this._events[a]=b;return this},f.prototype.onAny=function(a){if("function"!=typeof a)throw new Error("onAny only accepts instances of Function");return this._all||(this._all=[]),this._all.push(a),this},f.prototype.addListener=f.prototype.on,f.prototype.off=function(a,b){if("function"!=typeof b)throw new Error("removeListener only takes instances of Function");var c,d=[];if(this.wildcard){var e="string"==typeof a?a.split(this.delimiter):a.slice();d=g.call(this,null,e,this.listenerTree,0)}else{if(!this._events[a])return this;c=this._events[a],d.push({_listeners:c})}for(var f=0;fk;k++)if(c[k]===b||c[k].listener&&c[k].listener===b||c[k]._origin&&c[k]._origin===b){j=k;break}if(0>j)continue;return this.wildcard?h._listeners.splice(j,1):this._events[a].splice(j,1),0===c.length&&(this.wildcard?delete h._listeners:delete this._events[a]),this}(c===b||c.listener&&c.listener===b||c._origin&&c._origin===b)&&(this.wildcard?delete h._listeners:delete this._events[a])}return this},f.prototype.offAny=function(a){var b,c=0,d=0;if(a&&this._all&&this._all.length>0){for(b=this._all,c=0,d=b.length;d>c;c++)if(a===b[c])return b.splice(c,1),this}else this._all=[];return this},f.prototype.removeListener=f.prototype.off,f.prototype.removeAllListeners=function(a){if(0===arguments.length)return!this._events||c.call(this),this;if(this.wildcard)for(var b="string"==typeof a?a.split(this.delimiter):a.slice(),d=g.call(this,null,b,this.listenerTree,0),e=0;e0&&(c.attributes=b),this.push(c))},h.prototype["delete"]=function(a){return 0>=a?this:this.push({"delete":a})},h.prototype.retain=function(a,b){if(0>=a)return this;var c={retain:a};return e.object(b)&&Object.keys(b).length>0&&(c.attributes=b),this.push(c)},h.prototype.push=function(a){var b=this.ops.length,c=this.ops[b-1];if(a=f.clone(a),e.object(c)){if(e.number(a["delete"])&&e.number(c["delete"]))return this.ops[b-1]={"delete":c["delete"]+a["delete"]},this;if(e.number(c["delete"])&&null!=a.insert&&(b-=1,c=this.ops[b-1],!e.object(c)))return this.ops.unshift(a),this;if(e.equal(a.attributes,c.attributes)){if(e.string(a.insert)&&e.string(c.insert))return this.ops[b-1]={insert:c.insert+a.insert},e.object(a.attributes)&&(this.ops[b-1].attributes=a.attributes),this;if(e.number(a.retain)&&e.number(c.retain))return this.ops[b-1]={retain:c.retain+a.retain},e.object(a.attributes)&&(this.ops[b-1].attributes=a.attributes),this}}return b===this.ops.length?this.ops.push(a):this.ops.splice(b,0,a),this},h.prototype.chop=function(){var a=this.ops[this.ops.length-1];return a&&a.retain&&!a.attributes&&this.ops.pop(),this},h.prototype.length=function(){return this.ops.reduce(function(a,b){return a+f.length(b)},0)},h.prototype.slice=function(a,b){a=a||0,e.number(b)||(b=1/0);for(var c=new h,d=f.iterator(this.ops),g=0;b>g&&d.hasNext();){var i;a>g?i=d.next(a-g):(i=d.next(b-g),c.push(i)),g+=f.length(i)}return c},h.prototype.compose=function(a){for(var b=f.iterator(this.ops),c=f.iterator(a.ops),d=new h;b.hasNext()||c.hasNext();)if("insert"===c.peekType())d.push(c.next());else if("delete"===b.peekType())d.push(b.next());else{var g=Math.min(b.peekLength(),c.peekLength()),i=b.next(g),j=c.next(g);if(e.number(j.retain)){var k={};e.number(i.retain)?k.retain=g:k.insert=i.insert;var l=f.attributes.compose(i.attributes,j.attributes,e.number(i.retain));l&&(k.attributes=l),d.push(k)}else e.number(j["delete"])&&e.number(i.retain)&&d.push(j)}return d.chop()},h.prototype.concat=function(a){var b=this.slice();return a.ops.length>0&&(b.push(a.ops[0]),b.ops=b.ops.concat(a.ops.slice(1))),b},h.prototype.diff=function(a){var b=new h;if(this.ops===a.ops)return b;var c=[this.ops,a.ops].map(function(b){return b.map(function(c){if(null!=c.insert)return e.string(c.insert)?c.insert:g;var d=b===a.ops?"on":"with";throw new Error("diff() called "+d+" non-document")}).join("")}),i=d(c[0],c[1]),j=f.iterator(this.ops),k=f.iterator(a.ops);return i.forEach(function(a){for(var c=a[1].length;c>0;){var g=0;switch(a[0]){case d.INSERT:g=Math.min(k.peekLength(),c),b.push(k.next(g));break;case d.DELETE:g=Math.min(c,j.peekLength()),j.next(g),b["delete"](g);break;case d.EQUAL:g=Math.min(j.peekLength(),k.peekLength(),c);var h=j.next(g),i=k.next(g);e.equal(h.insert,i.insert)?b.retain(g,f.attributes.diff(h.attributes,i.attributes)):b.push(i)["delete"](g); +}c-=g}}),b.chop()},h.prototype.transform=function(a,b){if(b=!!b,e.number(a))return this.transformPosition(a,b);for(var c=f.iterator(this.ops),d=f.iterator(a.ops),g=new h;c.hasNext()||d.hasNext();)if("insert"!==c.peekType()||!b&&"insert"===d.peekType())if("insert"===d.peekType())g.push(d.next());else{var i=Math.min(c.peekLength(),d.peekLength()),j=c.next(i),k=d.next(i);if(j["delete"])continue;k["delete"]?g.push(k):g.retain(i,f.attributes.transform(j.attributes,k.attributes,b))}else g.retain(f.length(c.next()));return g.chop()},h.prototype.transformPosition=function(a,b){b=!!b;for(var c=f.iterator(this.ops),d=0;c.hasNext()&&a>=d;){var e=c.peekLength(),g=c.peekType();c.next(),"delete"!==g?("insert"===g&&(a>d||!b)&&(a+=e),d+=e):a-=Math.min(e,a-d)}return a},b.exports=h},{"./is":4,"./op":5,"fast-diff":6}],4:[function(a,b,c){b.exports={equal:function(a,b){if(a===b)return!0;if(null==a&&null==b)return!0;if(null==a||null==b)return!1;if(!this.object(a)||!this.object(b))return!1;if(Object.keys(a).length!=Object.keys(b).length)return!1;for(var c in a)if(a[c]!==b[c])return!1;return!0},array:function(a){return Array.isArray(a)},number:function(a){return"number"==typeof a?!0:"object"==typeof a&&"[object Number]"===Object.prototype.toString.call(a)?!0:!1},object:function(a){return a?"function"==typeof a||"object"==typeof a:!1},string:function(a){return"string"==typeof a?!0:"object"==typeof a&&"[object String]"===Object.prototype.toString.call(a)?!0:!1}}},{}],5:[function(a,b,c){function d(a){this.ops=a,this.index=0,this.offset=0}var e=a("./is"),f={attributes:{clone:function(a,b){return e.object(a)?Object.keys(a).reduce(function(c,d){return void 0===a[d]||null===a[d]&&!b||(c[d]=a[d]),c},{}):{}},compose:function(a,b,c){e.object(a)||(a={}),e.object(b)||(b={});var d=this.clone(b,c);for(var f in a)void 0!==a[f]&&void 0===b[f]&&(d[f]=a[f]);return Object.keys(d).length>0?d:void 0},diff:function(a,b){e.object(a)||(a={}),e.object(b)||(b={});var c=Object.keys(a).concat(Object.keys(b)).reduce(function(c,d){return a[d]!==b[d]&&(c[d]=void 0===b[d]?null:b[d]),c},{});return Object.keys(c).length>0?c:void 0},transform:function(a,b,c){if(!e.object(a))return b;if(!e.object(b))return void 0;if(!c)return b;var d=Object.keys(b).reduce(function(c,d){return void 0===a[d]&&(c[d]=b[d]),c},{});return Object.keys(d).length>0?d:void 0}},clone:function(a){var b=this.attributes.clone(a);return e.object(b.attributes)&&(b.attributes=this.attributes.clone(b.attributes,!0)),b},iterator:function(a){return new d(a)},length:function(a){return e.number(a["delete"])?a["delete"]:e.number(a.retain)?a.retain:e.string(a.insert)?a.insert.length:1}};d.prototype.hasNext=function(){return this.peekLength()<1/0},d.prototype.next=function(a){a||(a=1/0);var b=this.ops[this.index];if(b){var c=this.offset,d=f.length(b);if(a>=d-c?(a=d-c,this.index+=1,this.offset=0):this.offset+=a,e.number(b["delete"]))return{"delete":a};var g={};return b.attributes&&(g.attributes=b.attributes),e.number(b.retain)?g.retain=a:e.string(b.insert)?g.insert=b.insert.substr(c,a):g.insert=b.insert,g}return{retain:1/0}},d.prototype.peekLength=function(){return this.ops[this.index]?f.length(this.ops[this.index])-this.offset:1/0},d.prototype.peekType=function(){return this.ops[this.index]?e.number(this.ops[this.index]["delete"])?"delete":e.number(this.ops[this.index].retain)?"retain":"insert":"retain"},b.exports=f},{"./is":4}],6:[function(a,b,c){function d(a,b){if(a==b)return a?[[n,a]]:[];var c=h(a,b),d=a.substring(0,c);a=a.substring(c),b=b.substring(c),c=i(a,b);var f=a.substring(a.length-c);a=a.substring(0,a.length-c),b=b.substring(0,b.length-c);var g=e(a,b);return d&&g.unshift([n,d]),f&&g.push([n,f]),k(g),g}function e(a,b){var c;if(!a)return[[m,b]];if(!b)return[[l,a]];var e=a.length>b.length?a:b,g=a.length>b.length?b:a,h=e.indexOf(g);if(-1!=h)return c=[[m,e.substring(0,h)],[n,g],[m,e.substring(h+g.length)]],a.length>b.length&&(c[0][0]=c[2][0]=l),c;if(1==g.length)return[[l,a],[m,b]];var i=j(a,b);if(i){var k=i[0],o=i[1],p=i[2],q=i[3],r=i[4],s=d(k,p),t=d(o,q);return s.concat([[n,r]],t)}return f(a,b)}function f(a,b){for(var c=a.length,d=b.length,e=Math.ceil((c+d)/2),f=e,h=2*e,i=new Array(h),j=new Array(h),k=0;h>k;k++)i[k]=-1,j[k]=-1;i[f+1]=0,j[f+1]=0;for(var n=c-d,o=n%2!=0,p=0,q=0,r=0,s=0,t=0;e>t;t++){for(var u=-t+p;t-q>=u;u+=2){var v,w=f+u;v=u==-t||u!=t&&i[w-1]v&&d>x&&a.charAt(v)==b.charAt(x);)v++,x++;if(i[w]=v,v>c)q+=2;else if(x>d)p+=2;else if(o){var y=f+n-u;if(y>=0&&h>y&&-1!=j[y]){var z=c-j[y];if(v>=z)return g(a,b,v,x)}}}for(var A=-t+r;t-s>=A;A+=2){var z,y=f+A;z=A==-t||A!=t&&j[y-1]z&&d>B&&a.charAt(c-z-1)==b.charAt(d-B-1);)z++,B++;if(j[y]=z,z>c)s+=2;else if(B>d)r+=2;else if(!o){var w=f+n-A;if(w>=0&&h>w&&-1!=i[w]){var v=i[w],x=f+v-w;if(z=c-z,v>=z)return g(a,b,v,x)}}}}return[[l,a],[m,b]]}function g(a,b,c,e){var f=a.substring(0,c),g=b.substring(0,e),h=a.substring(c),i=b.substring(e),j=d(f,g),k=d(h,i);return j.concat(k)}function h(a,b){if(!a||!b||a.charAt(0)!=b.charAt(0))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;e>c;)a.substring(f,e)==b.substring(f,e)?(c=e,f=c):d=e,e=Math.floor((d-c)/2+c);return e}function i(a,b){if(!a||!b||a.charAt(a.length-1)!=b.charAt(b.length-1))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;e>c;)a.substring(a.length-e,a.length-f)==b.substring(b.length-e,b.length-f)?(c=e,f=c):d=e,e=Math.floor((d-c)/2+c);return e}function j(a,b){function c(a,b,c){for(var d,e,f,g,j=a.substring(c,c+Math.floor(a.length/4)),k=-1,l="";-1!=(k=b.indexOf(j,k+1));){var m=h(a.substring(c),b.substring(k)),n=i(a.substring(0,c),b.substring(0,k));l.length=a.length?[d,e,f,g,l]:null}var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(d.length<4||2*e.lengthj[4].length?g:j:g;var k,l,m,n;a.length>b.length?(k=f[0],l=f[1],m=f[2],n=f[3]):(m=f[0],n=f[1],k=f[2],l=f[3]);var o=f[4];return[k,l,m,n,o]}function k(a){a.push([n,""]);for(var b,c=0,d=0,e=0,f="",g="";c1?(0!==d&&0!==e&&(b=h(g,f),0!==b&&(c-d-e>0&&a[c-d-e-1][0]==n?a[c-d-e-1][1]+=g.substring(0,b):(a.splice(0,0,[n,g.substring(0,b)]),c++),g=g.substring(b),f=f.substring(b)),b=i(g,f),0!==b&&(a[c][1]=g.substring(g.length-b)+a[c][1],g=g.substring(0,g.length-b),f=f.substring(0,f.length-b))),0===d?a.splice(c-e,d+e,[m,g]):0===e?a.splice(c-d,d+e,[l,f]):a.splice(c-d-e,d+e,[l,f],[m,g]),c=c-d-e+(d?1:0)+(e?1:0)+1):0!==c&&a[c-1][0]==n?(a[c-1][1]+=a[c][1],a.splice(c,1)):c++,e=0,d=0,f="",g=""}""===a[a.length-1][1]&&a.pop();var j=!1;for(c=1;c0))return[void 0,a];if(c=this.toDelta().length(),a===c)return[this.lines.last,this.lines.last.length];if(a>c)return[void 0,a-c];for(b=this.lines.first;null!=b;){if(a\s+\ <")},a.prototype.insertLineBefore=function(a,b){var c;return c=new g(this,a),null!=b?(k(a.parentNode).isElement()||this.root.insertBefore(a,b.node),this.lines.insertAfter(b.prev,c)):(k(a.parentNode).isElement()||this.root.appendChild(a),this.lines.append(c)),c},a.prototype.mergeLines=function(a,b){return b.length>1&&(1===a.length&&k(a.leaves.last.node).remove(),j.each(k(b.node).childNodes(),function(b){return b.tagName!==k.DEFAULT_BREAK_TAG?a.node.appendChild(b):void 0})),this.removeLine(b),a.rebuild()},a.prototype.optimizeLines=function(){return j.each(this.lines.toArray(),function(a,b){return a.optimize(),!0})},a.prototype.rebuild=function(){var a,b,c;for(b=this.lines.toArray(),a=this.root.firstChild,null!=a&&null!=k.LIST_TAGS[a.tagName]&&(a=a.firstChild),j.each(b,function(b){return function(c,d){for(var e,f;c.node!==a;){if(c.node.parentNode!==b.root&&(null!=(f=c.node.parentNode)?f.parentNode:void 0)!==b.root)return b.removeLine(c);a=b.normalizer.normalizeLine(a),e=b.insertLineBefore(a,c),a=k(a).nextLineNode(b.root)}return c.outerHTML!==a.outerHTML&&(c.node=b.normalizer.normalizeLine(c.node),c.rebuild()),a=k(a).nextLineNode(b.root)}}(this)),c=[];null!=a;)a=this.normalizer.normalizeLine(a),this.appendLine(a),c.push(a=k(a).nextLineNode(this.root));return c},a.prototype.removeLine=function(a){return null!=a.node.parentNode&&(k.LIST_TAGS[a.node.parentNode.tagName]&&1===a.node.parentNode.childNodes.length?k(a.node.parentNode).remove():k(a.node).remove()),this.lines.remove(a)},a.prototype.setHTML=function(a){return a=i.stripComments(a),a=i.stripWhitespace(a),this.root.innerHTML=a,this.lines=new h,this.rebuild()},a.prototype.splitLine=function(a,b){var c,d,e,f;return b=Math.min(b,a.length-1),f=k(a.node).split(b,!0),c=f[0],d=f[1],a.node=c,a.rebuild(),e=this.insertLineBefore(d,a.next),e.formats=j.clone(a.formats),e.resetContent(),e},a.prototype.toDelta=function(){var a,b;return b=this.lines.toArray(),a=new d,j.each(b,function(b){return j.each(b.delta.ops,function(b){return a.push(b)})}),a},a}(),b.exports=e},{"../lib/dom":17,"../lib/linked-list":18,"./format":10,"./line":12,"./normalizer":13,lodash:1,"rich-text/lib/delta":3}],9:[function(a,b,c){var d,e,f,g,h,i,j;i=a("lodash"),d=a("rich-text/lib/delta"),j=a("../lib/dom"),e=a("./document"),g=a("./line"),h=a("./selection"),f=function(){function a(a,b,c){this.root=a,this.quill=b,this.options=null!=c?c:{},this.root.setAttribute("id",this.options.id),this.doc=new e(this.root,this.options),this.delta=this.doc.toDelta(),this.length=this.delta.length(),this.selection=new h(this.doc,this.quill),this.timer=setInterval(i.bind(this.checkUpdate,this),this.options.pollInterval),this.savedRange=null,this.quill.on("selection-change",function(a){return function(b){return a.savedRange=b}}(this)),this.options.readOnly||this.enable()}return a.sources={API:"api",SILENT:"silent",USER:"user"},a.prototype.destroy=function(){return clearInterval(this.timer)},a.prototype.disable=function(){return this.enable(!1)},a.prototype.enable=function(a){return null==a&&(a=!0),this.root.setAttribute("contenteditable",a)},a.prototype.applyDelta=function(b,c){var d;return d=this._update(),d&&(b=d.transform(b,!0),d=b.transform(d,!1)),b.ops.length>0&&(b=this._trackDelta(function(a){return function(){var c;return c=0,i.each(b.ops,function(b){return i.isString(b.insert)?(a._insertAt(c,b.insert,b.attributes),c+=b.insert.length):i.isNumber(b.insert)?(a._insertEmbed(c,b.attributes),c+=1):i.isNumber(b["delete"])?a._deleteAt(c,b["delete"]):i.isNumber(b.retain)?(i.each(b.attributes,function(d,e){return a._formatAt(c,b.retain,e,d)}),c+=b.retain):void 0}),a.selection.shiftAfter(0,0,i.bind(a.doc.optimizeLines,a.doc))}}(this)),this.delta=this.doc.toDelta(),this.length=this.delta.length(),this.innerHTML=this.root.innerHTML,b&&c!==a.sources.SILENT&&this.quill.emit(this.quill.constructor.events.TEXT_CHANGE,b,c)),d&&d.ops.length>0&&c!==a.sources.SILENT?this.quill.emit(this.quill.constructor.events.TEXT_CHANGE,d,a.sources.USER):void 0},a.prototype.checkUpdate=function(b){var c;return null==b&&(b="user"),null==this.root.parentNode?clearInterval(this.timer):(c=this._update(),c&&(this.delta=this.delta.compose(c),this.length=this.delta.length(),this.quill.emit(this.quill.constructor.events.TEXT_CHANGE,c,b)),c&&(b=a.sources.SILENT),this.selection.update(b))},a.prototype.focus=function(){return null!=this.selection.range?this.selection.setRange(this.selection.range):this.root.focus()},a.prototype.getBounds=function(a){var b,c,d,e,f,g,h;return this.checkUpdate(),g=this.doc.findLeafAt(a,!0),d=g[0],e=g[1],null==d?null:(c=this.root.parentNode.getBoundingClientRect(),h="left",0===d.length?b=d.node.parentNode.getBoundingClientRect():j.VOID_TAGS[d.node.tagName]?(b=d.node.getBoundingClientRect(),1===e&&(h="right")):(f=document.createRange(),e=b?void 0:this.selection.shiftAfter(a,-1*b,function(c){return function(){var d,e,f,g,h,i,j;for(j=c.doc.findLineAt(a),f=j[0],i=j[1],d=f,g=f.length-i<=b&&i>0;null!=d&&b>0;)h=d.next,e=Math.min(d.length-i,b),0===i&&b>=d.length?c.doc.removeLine(d):d.deleteText(i,e),b-=e,d=h,i=0;return g&&f.next?c.doc.mergeLines(f,f.next):void 0}}(this))},a.prototype._formatAt=function(a,b,c,d){return this.selection.shiftAfter(a,0,function(e){return function(){var f,g,h,i,j;for(i=e.doc.findLineAt(a),g=i[0],h=i[1],j=[];null!=g&&b>0;)f=Math.min(b,g.length-h-1),g.formatText(h,f,c,d),b-=f,b>0&&g.format(c,d),b-=1,h=0,j.push(g=g.next);return j}}(this))},a.prototype._insertEmbed=function(a,b){return this.selection.shiftAfter(a,1,function(c){return function(){var d,e,f;return f=c.doc.findLineAt(a),d=f[0],e=f[1],d.insertEmbed(e,b)}}(this))},a.prototype._insertAt=function(a,b,c){return null==c&&(c={}),this.selection.shiftAfter(a,b.length,function(d){return function(){var e,f,g,h;return b=b.replace(/\r\n?/g,"\n"),f=b.split("\n"),h=d.doc.findLineAt(a),e=h[0],g=h[1],i.each(f,function(a,b){var h;return null==e||e.length<=g?(b0)&&(e=d.doc.appendLine(document.createElement(j.DEFAULT_BLOCK_TAG)),g=0,e.insertText(g,a,c),e.format(c),h=null):(e.insertText(g,a,c),b0?a:!1)},a}(),b.exports=f},{"../lib/dom":17,"./document":8,"./line":12,"./selection":14,lodash:1,"rich-text/lib/delta":3}],10:[function(a,b,c){var d,e,f;e=a("lodash"),f=a("../lib/dom"),d=function(){function a(a){this.config=a}return a.types={LINE:"line",EMBED:"embed"},a.FORMATS={bold:{tag:"B",prepare:"bold"},italic:{tag:"I",prepare:"italic"},underline:{tag:"U",prepare:"underline"},strike:{tag:"S",prepare:"strikeThrough"},color:{style:"color","default":"rgb(0, 0, 0)",prepare:"foreColor"},background:{style:"backgroundColor","default":"rgb(255, 255, 255)",prepare:"backColor"},font:{style:"fontFamily","default":"'Helvetica', 'Arial', sans-serif",prepare:"fontName"},size:{style:"fontSize","default":"13px",prepare:function(a){return document.execCommand("fontSize",!1,f.convertFontSize(a))}},link:{tag:"A",add:function(a,b){return a.setAttribute("href",b),a},remove:function(a){return a.removeAttribute("href"),a},value:function(a){return a.getAttribute("href")}},image:{type:a.types.EMBED,tag:"IMG",attribute:"src"},align:{type:a.types.LINE,style:"textAlign","default":"left"},bullet:{type:a.types.LINE,exclude:"list",parentTag:"UL",tag:"LI"},list:{type:a.types.LINE,exclude:"bullet",parentTag:"OL",tag:"LI"}},a.prototype.add=function(b,c){var d,g,h,i,j;return c?this.value(b)===c?b:(e.isString(this.config.parentTag)&&(h=b.parentNode,h.tagName!==this.config.parentTag&&(h=document.createElement(this.config.parentTag),f(b).wrap(h)),b.parentNode.tagName===(null!=(i=b.parentNode.previousSibling)?i.tagName:void 0)&&f(b.parentNode.previousSibling).merge(b.parentNode),b.parentNode.tagName===(null!=(j=b.parentNode.nextSibling)?j.tagName:void 0)&&f(b.parentNode).merge(b.parentNode.nextSibling)),e.isString(this.config.tag)&&b.tagName!==this.config.tag&&(d=document.createElement(this.config.tag),null!=f.VOID_TAGS[d.tagName]?(null!=b.parentNode&&f(b).replace(d),b=d):this.isType(a.types.LINE)?b=f(b).switchTag(this.config.tag).get():(f(b).wrap(d),b=d)),(e.isString(this.config.style)||e.isString(this.config.attribute)||e.isString(this.config["class"]))&&(e.isString(this.config["class"])&&(b=this.remove(b)),f(b).isTextNode()&&(g=document.createElement(f.DEFAULT_INLINE_TAG),f(b).wrap(g),b=g),e.isString(this.config.style)&&c!==this.config["default"]&&(b.style[this.config.style]=c),e.isString(this.config.attribute)&&b.setAttribute(this.config.attribute,c),e.isString(this.config["class"])&&f(b).addClass(this.config["class"]+c)),e.isFunction(this.config.add)&&(b=this.config.add(b,c)),b):this.remove(b)},a.prototype.isType=function(a){return a===this.config.type},a.prototype.match=function(a){var b,c,d,g,h;if(!f(a).isElement())return!1;if(e.isString(this.config.parentTag)&&(null!=(g=a.parentNode)?g.tagName:void 0)!==this.config.parentTag)return!1;if(e.isString(this.config.tag)&&a.tagName!==this.config.tag)return!1;if(e.isString(this.config.style)&&(!a.style[this.config.style]||a.style[this.config.style]===this.config["default"]))return!1;if(e.isString(this.config.attribute)&&!a.hasAttribute(this.config.attribute))return!1;if(e.isString(this.config["class"])){for(h=f(a).classes(),c=0,d=h.length;d>c;c++)if(b=h[c],0===b.indexOf(this.config["class"]))return!0;return!1}return!0},a.prototype.prepare=function(a){return e.isString(this.config.prepare)?document.execCommand(this.config.prepare,!1,a):e.isFunction(this.config.prepare)?this.config.prepare(a):void 0},a.prototype.remove=function(b){var c,d,g,h;if(!this.match(b))return b;if(e.isString(this.config.style)&&(b.style[this.config.style]="",b.getAttribute("style")||b.removeAttribute("style")),e.isString(this.config.attribute)&&b.removeAttribute(this.config.attribute),e.isString(this.config["class"]))for(h=f(b).classes(),d=0,g=h.length;g>d;d++)c=h[d],0===c.indexOf(this.config["class"])&&f(b).removeClass(c);if(e.isString(this.config.tag))if(this.isType(a.types.LINE))e.isString(this.config.parentTag)&&(null!=b.previousSibling&&f(b).splitBefore(b.parentNode.parentNode),null!=b.nextSibling&&f(b.nextSibling).splitBefore(b.parentNode.parentNode)),b=f(b).switchTag(f.DEFAULT_BLOCK_TAG).get();else{if(this.isType(a.types.EMBED))return void f(b).remove();b=f(b).switchTag(f.DEFAULT_INLINE_TAG).get()}return e.isString(this.config.parentTag)&&f(b.parentNode).unwrap(),e.isFunction(this.config.remove)&&(b=this.config.remove(b)),b.tagName!==f.DEFAULT_INLINE_TAG||b.hasAttributes()||(b=f(b).unwrap()),b},a.prototype.value=function(a){var b,c,d,g;if(!this.match(a))return void 0;if(this.config.value)return this.config.value(a);if(e.isString(this.config.attribute))return a.getAttribute(this.config.attribute)||void 0;if(e.isString(this.config.style))return a.style[this.config.style]||void 0;if(e.isString(this.config["class"])){for(g=f(a).classes(),c=0,d=g.length;d>c;c++)if(b=g[c],0===b.indexOf(this.config["class"]))return b.slice(this.config["class"].length)}else if(e.isString(this.config.tag))return!0;return void 0},a}(),b.exports=d},{"../lib/dom":17,lodash:1}],11:[function(a,b,c){var d,e,f,g,h,i=function(a,b){function c(){this.constructor=a}for(var d in b)j.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},j={}.hasOwnProperty;g=a("lodash"),h=a("../lib/dom"),d=a("./format"),f=a("../lib/linked-list"),e=function(a){function b(a,c){this.node=a,this.formats=g.clone(c),this.text=h(this.node).text(),this.length=this.text.length,h(this.node).data(b.DATA_KEY,this)}return i(b,a),b.DATA_KEY="leaf",b.isLeafNode=function(a){return h(a).isTextNode()||null==a.firstChild},b.prototype.deleteText=function(a,c){var d;if(c>0)return this.text=this.text.slice(0,a)+this.text.slice(a+c),this.length=this.text.length,null!=h.EMBED_TAGS[this.node.tagName]?(d=document.createTextNode(this.text),h(d).data(b.DATA_KEY,this),this.node=h(this.node).replace(d).get()):h(this.node).text(this.text)},b.prototype.insertText=function(a,c){var d;return this.text=this.text.slice(0,a)+c+this.text.slice(a),h(this.node).isTextNode()?h(this.node).text(this.text):(d=document.createTextNode(c),h(d).data(b.DATA_KEY,this),this.node.tagName===h.DEFAULT_BREAK_TAG?this.node=h(this.node).replace(d).get():(this.node.appendChild(d),this.node=d)),this.length=this.text.length},b}(f.Node),b.exports=e},{"../lib/dom":17,"../lib/linked-list":18,"./format":10,lodash:1}],12:[function(a,b,c){var d,e,f,g,h,i,j,k,l=function(a,b){function c(){this.constructor=a}for(var d in b)m.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},m={}.hasOwnProperty;j=a("lodash"),d=a("rich-text/lib/delta"),k=a("../lib/dom"),e=a("./format"),f=a("./leaf"),g=a("./line"),h=a("../lib/linked-list"),i=a("./normalizer"),g=function(a){function b(a,c){this.doc=a,this.node=c,this.formats={},this.rebuild(),b.__super__.constructor.call(this,this.node)}return l(b,a),b.DATA_KEY="line",b.prototype.buildLeaves=function(a,b){return j.each(k(a).childNodes(),function(a){return function(c){var d;return c=a.doc.normalizer.normalizeNode(c),d=j.clone(b),j.each(a.doc.formats,function(a,b){return!a.isType(e.types.LINE)&&a.match(c)?d[b]=a.value(c):void 0}),f.isLeafNode(c)?a.leaves.append(new f(c,d)):a.buildLeaves(c,d)}}(this))},b.prototype.deleteText=function(a,b){var c,d,e;if(b>0){for(e=this.findLeafAt(a),d=e[0],a=e[1];null!=d&&b>0;)c=Math.min(b,d.length-a),d.deleteText(a,c),b-=c,d=d.next,a=0;return this.rebuild()}},b.prototype.findLeaf=function(a){return null!=a?k(a).data(f.DATA_KEY):void 0},b.prototype.findLeafAt=function(a,b){var c;if(null==b&&(b=!1),a>=this.length-1)return[this.leaves.last,this.leaves.last.length];for(c=this.leaves.first;null!=c;){if(a0;){if(j=g.next,d&&g.formats[c]!==d||!d&&null!=g.formats[c]){if(p=g.node,null!=g.formats[c]){for(k(p).splitBefore(this.node);!f.match(p);)p=p.parentNode;k(p).split(g.length)}h>0&&(m=k(p).split(h),i=m[0],p=m[1]),g.length>h+b&&(n=k(p).split(b),p=n[0],o=n[1]),f.add(p,d)}b-=g.length-h,h=0,g=j}return this.rebuild()}},b.prototype._insert=function(a,b,c){var d,f,g,h,i,l;return i=this.findLeafAt(a),d=i[0],f=i[1],b=j.reduce(c,function(a){return function(b,c,d){var f;return f=a.doc.formats[d],null==f||f.isType(e.types.LINE)||(b=f.add(b,c)),b}}(this),b),l=k(d.node).split(f),h=l[0],g=l[1],g&&(g=k(g).splitBefore(this.node).get()),this.node.insertBefore(b,g),this.rebuild()},b.prototype.insertEmbed=function(a,b){var c,d,f,g,h,i,l,m;return l=this.findLeafAt(a),d=l[0],f=l[1],m=k(d.node).split(f),i=m[0],g=m[1],c=j.find(Object.keys(b),function(a){return function(b){return a.doc.formats[b].isType(e.types.EMBED)}}(this)),h=this.doc.formats[c].add({},b[c]),b=j.clone(b),delete b[c],this._insert(a,h,b)},b.prototype.insertText=function(a,b,c){var d,e,f;return null==c&&(c={}),b.length>0?(f=this.findLeafAt(a),d=f[0],e=f[1],j.isEqual(d.formats,c)?(d.insertText(e,b),this.resetContent()):this._insert(a,document.createTextNode(b),c)):void 0},b.prototype.optimize=function(){return i.optimizeLine(this.node),this.rebuild()},b.prototype.rebuild=function(a){return null==a&&(a=!1),!a&&null!=this.outerHTML&&this.outerHTML===this.node.outerHTML&&j.all(this.leaves.toArray(),function(a){return function(b){return k(b.node).isAncestor(a.node)}}(this))?!1:(this.node=this.doc.normalizer.normalizeNode(this.node),0!==k(this.node).length()||this.node.querySelector(k.DEFAULT_BREAK_TAG)||this.node.appendChild(document.createElement(k.DEFAULT_BREAK_TAG)),this.leaves=new h,this.formats=j.reduce(this.doc.formats,function(a){return function(b,c,d){return c.isType(e.types.LINE)&&(c.match(a.node)?b[d]=c.value(a.node):delete b[d]),b}}(this),this.formats),this.buildLeaves(this.node,{}),this.resetContent(),!0)},b.prototype.resetContent=function(){return k(this.node).data(b.DATA_KEY,this),this.outerHTML=this.node.outerHTML,this.length=1,this.delta=new d,j.each(this.leaves.toArray(),function(a){return function(b){return a.length+=b.length,null!=k.EMBED_TAGS[b.node.tagName]?a.delta.insert(1,b.formats):a.delta.insert(b.text,b.formats)}}(this)),this.delta.insert("\n",this.formats)},b}(h.Node),b.exports=g},{"../lib/dom":17,"../lib/linked-list":18,"./format":10,"./leaf":11,"./line":12,"./normalizer":13,lodash:1,"rich-text/lib/delta":3}],13:[function(a,b,c){var d,e,f,g;e=a("lodash"),g=a("../lib/dom"),f=function(a){return a=a.replace(/(?:^|[-_])(\w)/g,function(a,b){return b?b.toUpperCase():""}),a.charAt(0).toLowerCase()+a.slice(1)},d=function(){function a(){this.whitelist={styles:{},tags:{}},this.whitelist.tags[g.DEFAULT_BREAK_TAG]=!0,this.whitelist.tags[g.DEFAULT_BLOCK_TAG]=!0,this.whitelist.tags[g.DEFAULT_INLINE_TAG]=!0}return a.ALIASES={STRONG:"B",EM:"I",DEL:"S",STRIKE:"S"},a.ATTRIBUTES={color:"color",face:"fontFamily",size:"fontSize"},a.prototype.addFormat=function(a){return null!=a.tag&&(this.whitelist.tags[a.tag]=!0),null!=a.parentTag&&(this.whitelist.tags[a.parentTag]=!0),null!=a.style?this.whitelist.styles[a.style]=!0:void 0},a.prototype.normalizeLine=function(b){return b=a.wrapInline(b),b=a.handleBreaks(b),"LI"===b.tagName&&a.flattenList(b),b=a.pullBlocks(b),b=this.normalizeNode(b),a.unwrapText(b),null!=b&&null!=g.LIST_TAGS[b.tagName]&&(b=b.firstChild),b},a.prototype.normalizeNode=function(b){return g(b).isTextNode()?b:(e.each(a.ATTRIBUTES,function(a,c){var d;return b.hasAttribute(c)?(d=b.getAttribute(c),"size"===c&&(d=g.convertFontSize(d)),b.style[a]=d,b.removeAttribute(c)):void 0}),("bold"===b.style.fontWeight||b.style.fontWeight>500)&&(b.style.fontWeight="",g(b).wrap(document.createElement("b")),b=b.parentNode),this.whitelistStyles(b),this.whitelistTags(b))},a.prototype.whitelistStyles=function(a){var b,c;return b=g(a).styles(),c=e.omit(b,function(a){return function(b,c){return null==a.whitelist.styles[f(c)]}}(this)),Object.keys(c).length0?g(a).styles(c,!0):a.removeAttribute("style"):void 0},a.prototype.whitelistTags=function(b){return g(b).isElement()?(null!=a.ALIASES[b.tagName]?b=g(b).switchTag(a.ALIASES[b.tagName]).get():null==this.whitelist.tags[b.tagName]&&(b=null!=g.BLOCK_TAGS[b.tagName]?g(b).switchTag(g.DEFAULT_BLOCK_TAG).get():b.hasAttributes()||null==b.firstChild?g(b).switchTag(g.DEFAULT_INLINE_TAG).get():g(b).unwrap()),b):b},a.flattenList=function(a){var b,c,d;return d=a.nextSibling,b=e.map(a.querySelectorAll("li")),b.forEach(function(b){return a.parentNode.insertBefore(b,d),d=b.nextSibling}),c=e.map(a.querySelectorAll(Object.keys(g.LIST_TAGS).join(","))),c.forEach(function(a){return g(a).remove()})},a.handleBreaks=function(a){var b;return b=e.map(a.querySelectorAll(g.DEFAULT_BREAK_TAG)),e.each(b,function(b){return function(b){return null==b.nextSibling||g.isIE(10)&&null==b.previousSibling?void 0:g(b.nextSibling).splitBefore(a.parentNode)}}(this)),a},a.optimizeLine=function(a){var b,c,d,f;for(a.normalize(),b=g(a).length(),d=g(a).descendants(),f=[];d.length>0;)c=d.pop(),null!=(null!=c?c.parentNode:void 0)&&null==g.EMBED_TAGS[c.tagName]&&(c.tagName===g.DEFAULT_BREAK_TAG?0!==b?f.push(g(c).remove()):f.push(void 0):0===g(c).length()?(d.push(c.nextSibling),f.push(g(c).unwrap())):null!=c.previousSibling&&c.tagName===c.previousSibling.tagName&&e.isEqual(g(c).attributes(),g(c.previousSibling).attributes())?(d.push(c.firstChild),f.push(g(c.previousSibling).merge(c))):f.push(void 0));return f},a.pullBlocks=function(b){var c;for(c=b.firstChild;null!=c;){if(null!=g.BLOCK_TAGS[c.tagName]&&"LI"!==c.tagName){g(c).isolate(b.parentNode),null!=g.LIST_TAGS[c.tagName]&&c.firstChild?(g(c.parentNode).unwrap(),null==b.parentNode&&(b=c)):(g(c).unwrap(),a.pullBlocks(b));break}c=c.nextSibling}return b},a.stripComments=function(a){return a.replace(//g,"")},a.stripWhitespace=function(a){return a=a.trim(),a=a.replace(/(\r?\n|\r)+/g," "),a=a.replace(/\>\s+\<")},a.wrapInline=function(a){var b,c;if(null!=g.BLOCK_TAGS[a.tagName])return a;for(b=document.createElement(g.DEFAULT_BLOCK_TAG),a.parentNode.insertBefore(b,a);null!=a&&null==g.BLOCK_TAGS[a.tagName];)c=a.nextSibling,b.appendChild(a),a=c;return b},a.unwrapText=function(a){var b;return b=e.map(a.querySelectorAll(g.DEFAULT_INLINE_TAG)),e.each(b,function(a){return a.hasAttributes()?void 0:g(a).unwrap()})},a}(),b.exports=d},{"../lib/dom":17,lodash:1}],14:[function(a,b,c){var d,e,f,g,h,i;h=a("lodash"),i=a("../lib/dom"),d=a("./leaf"),e=a("./normalizer"),f=a("../lib/range"),g=function(){function a(a,b){this.doc=a,this.emitter=b,this.focus=!1,this.range=new f(0,0),this.nullDelay=!1,this.update("silent")}return a.prototype.checkFocus=function(){return document.activeElement===this.doc.root},a.prototype.getRange=function(a){var b,c,d;return null==a&&(a=!1),this.checkFocus()?(c=this._getNativeRange(),null==c?null:(d=this._positionToIndex(c.startContainer,c.startOffset),b=c.startContainer===c.endContainer&&c.startOffset===c.endOffset?d:this._positionToIndex(c.endContainer,c.endOffset),new f(Math.min(d,b),Math.max(d,b)))):a?this.range:null},a.prototype.preserve=function(a){var b,c,d,e,f,g,h,i,j;return d=this._getNativeRange(),null!=d&&this.checkFocus()?(e=this._encodePosition(d.startContainer,d.startOffset),i=e[0],j=e[1],f=this._encodePosition(d.endContainer,d.endOffset),b=f[0],c=f[1],a(),g=this._decodePosition(i,j),i=g[0],j=g[1],h=this._decodePosition(b,c),b=h[0],c=h[1],this._setNativeRange(i,j,b,c)):a()},a.prototype.scrollIntoView=function(){var a,b,c,d,e,f,g,h,i;if(this.range)return c=this.emitter.editor,i=c.getBounds(this.range.start),d=this.range.isCollapsed()?i:c.getBounds(this.range.end),a=c.root.parentNode.getBoundingClientRect(),b=a.bottom-a.top, +b0&&(a=b.getRangeAt(0),i(a.startContainer).isAncestor(this.doc.root,!0)&&(a.startContainer===a.endContainer||i(a.endContainer).isAncestor(this.doc.root,!0)))?a:null},a.prototype._indexToPosition=function(a){var b,c,d;return 0===this.doc.lines.length?[this.doc.root,0]:(d=this.doc.findLeafAt(a,!0),b=d[0],c=d[1],this._decodePosition(b.node,c))},a.prototype._positionToIndex=function(a,b){var c,d,e,f,g,h;if(i.isIE(10)&&"BR"===a.tagName&&1===b&&(b=0),h=this._encodePosition(a,b),d=h[0],b=h[1],f=this.doc.findLine(d),null==f)return 0;for(c=f.findLeaf(d),g=0;null!=f.prev;)f=f.prev,g+=f.length;if(null==c)return g;for(e=0;null!=c.prev;)c=c.prev,e+=c.length;return g+e+b},a.prototype._setNativeRange=function(a,b,c,d){var e,f;if(f=document.getSelection())if(null!=a){if(this.checkFocus()||this.doc.root.focus(),e=this._getNativeRange(),null==e||a!==e.startContainer||b!==e.startOffset||c!==e.endContainer||d!==e.endOffset)return f.removeAllRanges(),e=document.createRange(),e.setStart(a,b),e.setEnd(c,d),f.addRange(e)}else if(f.removeAllRanges(),this.doc.root.blur(),i.isIE(11)&&!i.isIE(9))return document.body.focus()},a}(),b.exports=g},{"../lib/dom":17,"../lib/range":20,"./leaf":11,"./normalizer":13,lodash:1}],15:[function(a,b,c){a("./modules/authorship"),a("./modules/image-tooltip"),a("./modules/keyboard"),a("./modules/link-tooltip"),a("./modules/multi-cursor"),a("./modules/paste-manager"),a("./modules/toolbar"),a("./modules/tooltip"),a("./modules/undo-manager"),b.exports=a("./quill")},{"./modules/authorship":21,"./modules/image-tooltip":22,"./modules/keyboard":23,"./modules/link-tooltip":24,"./modules/multi-cursor":25,"./modules/paste-manager":26,"./modules/toolbar":27,"./modules/tooltip":28,"./modules/undo-manager":29,"./quill":30}],16:[function(a,b,c){var d,e,f,g=function(a,b){function c(){this.constructor=a}for(var d in b)h.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},h={}.hasOwnProperty;f=a("./dom"),e=a("./picker"),d=function(a){function b(){b.__super__.constructor.apply(this,arguments),f(this.container).addClass("ql-color-picker")}return g(b,a),b.prototype.buildItem=function(a,c,d){var e;return e=b.__super__.buildItem.call(this,a,c,d),e.style.backgroundColor=c.value,e},b}(e),b.exports=d},{"./dom":17,"./picker":19}],17:[function(a,b,c){var d,e,f,g,h,i=function(a,b){return function(){return a.apply(b,arguments)}},j=function(a,b){function c(){this.constructor=a}for(var d in b)k.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},k={}.hasOwnProperty;f=a("lodash"),h=null,e=function(){function a(a){this.node=a,this.trigger=i(this.trigger,this)}return a.prototype.addClass=function(a){return this.hasClass(a)?void 0:(null!=this.node.classList?this.node.classList.add(a):null!=this.node.className&&(this.node.className=(this.node.className+" "+a).trim()),this)},a.prototype.attributes=function(a){var b,c,d,e,g,h;if(a)return f.each(a,function(a){return function(b,c){return a.node.setAttribute(c,b)}}(this)),this;if(null==this.node.attributes)return{};for(a={},g=this.node.attributes,c=d=0,e=g.length;e>d;c=++d)h=g[c],b=this.node.attributes[c],a[b.name]=b.value;return a},a.prototype.child=function(a){var b,c;for(b=this.node.firstChild,c=g(b).length();null!=b&&!(c>a);)a-=c,b=b.nextSibling,c=g(b).length();return null==b&&(b=this.node.lastChild,a=g(b).length()),[b,a]},a.prototype.childNodes=function(){return f.map(this.node.childNodes)},a.prototype.classes=function(){return this.node.className.split(/\s+/)},a.prototype.data=function(a,b){var c;return null!=b?(null==this.node["ql-data"]&&(this.node["ql-data"]={}),this.node["ql-data"][a]=b,this):null!=(c=this.node["ql-data"])?c[a]:void 0},a.prototype.descendants=function(){return f.map(this.node.getElementsByTagName("*"))},a.prototype.get=function(){return this.node},a.prototype.hasClass=function(a){return null!=this.node.classList?this.node.classList.contains(a):null!=this.node.className?this.classes().indexOf(a)>-1:!1},a.prototype.isAncestor=function(a,b){var c;if(null==b&&(b=!1),a===this.node)return b;for(c=this.node;c;){if(c===a)return!0;c=c.parentNode}return!1},a.prototype.isElement=function(){var a;return(null!=(a=this.node)?a.nodeType:void 0)===g.ELEMENT_NODE},a.prototype.isTextNode=function(){var a;return(null!=(a=this.node)?a.nodeType:void 0)===g.TEXT_NODE},a.prototype.isolate=function(a){return null!=this.node.nextSibling&&g(this.node.nextSibling).splitBefore(a),this.splitBefore(a),this},a.prototype.length=function(){var a;return null==this.node?0:(a=this.text().length,this.isElement()&&(a+=this.node.querySelectorAll(Object.keys(g.EMBED_TAGS).join(",")).length),a)},a.prototype.merge=function(a){var b;return b=g(a),this.isElement()?(b.moveChildren(this.node),this.normalize()):this.text(this.text()+b.text()),b.remove(),this},a.prototype.moveChildren=function(a){return f.each(this.childNodes(),function(b){return a.appendChild(b)}),this},a.prototype.nextLineNode=function(a){var b;return b=this.node.nextSibling,null==b&&this.node.parentNode!==a&&(b=this.node.parentNode.nextSibling),null!=b&&null!=g.LIST_TAGS[b.tagName]&&(b=b.firstChild),b},a.prototype.normalize=function(){var a,b,c,d;for(b=this.node.firstChild;null!=b;)d=b.nextSibling,a=g(b),null!=d&&g(d).isTextNode()&&(0===a.text().length?a.remove():a.isTextNode()&&(c=d.nextSibling,a.merge(d),d=c)),b=d;return this},a.prototype.on=function(a,b){return this.node.addEventListener(a,function(c){return function(d){var e,f;return e=!h||"keydown"!==a&&"keyup"!==a?d:h,f=b.call(c.node,e),f||(d.preventDefault(),d.stopPropagation()),f}}(this)),this},a.prototype.remove=function(){var a;return null!=(a=this.node.parentNode)&&a.removeChild(this.node),this.node=null,null},a.prototype.removeClass=function(a){var b;if(this.hasClass(a))return null!=this.node.classList?this.node.classList.remove(a):null!=this.node.className&&(b=this.classes(),b.splice(b.indexOf(a),1),this.node.className=b.join(" ")),this.node.getAttribute("class")||this.node.removeAttribute("class"),this},a.prototype.replace=function(a){return this.node.parentNode.replaceChild(a,this.node),this.node=a,this},a.prototype.splitBefore=function(a,b){var c,d,e,f;if(null==b&&(b=!1),this.node===a||this.node.parentNode===a)return this;if(null!=this.node.previousSibling||b){for(e=this.node.parentNode,d=e.cloneNode(!1),e.parentNode.insertBefore(d,e.nextSibling),f=this.node;null!=f;)c=f.nextSibling,d.appendChild(f),f=c;return g(d).splitBefore(a)}return g(this.node.parentNode).splitBefore(a)},a.prototype.split=function(a,b){var c,d,e,f,h,i,j,k,l,m;if(null==b&&(b=!1),j=this.length(),a=Math.max(0,a),a=Math.min(a,j),!b&&0===a)return[this.node.previousSibling,this.node,!1];if(!b&&a===j)return[this.node,this.node.nextSibling,!1];if(this.node.nodeType===g.TEXT_NODE)return c=this.node.splitText(a),[this.node,c,!0];for(h=this.node,m=this.node.cloneNode(!1),this.node.parentNode.insertBefore(m,h.nextSibling),k=this.child(a),d=k[0],a=k[1],l=g(d).split(a),e=l[0],f=l[1];null!==f;)i=f.nextSibling,m.appendChild(f),f=i;return[h,m,!0]},a.prototype.styles=function(a,b){var c,d;return null==b&&(b=!1),a?(b||(a=f.defaults(a,this.styles())),d=f.map(a,function(a,b){return b+": "+a}).join("; ")+";",this.node.setAttribute("style",d),this):(d=this.node.getAttribute("style")||"",c=f.reduce(d.split(";"),function(a,b){var c,d,e;return d=b.split(":"),c=d[0],e=d[1],c&&e&&(c=c.trim(),e=e.trim(),a[c.toLowerCase()]=e),a},{}))},a.prototype.switchTag=function(a){var b,c;return a=a.toUpperCase(),this.node.tagName===a?this:(c=document.createElement(a),b=this.attributes(),null==g.VOID_TAGS[a]&&this.moveChildren(c),this.replace(c),this.node=c,this.attributes(b))},a.prototype.text=function(a){if(null!=a){switch(this.node.nodeType){case g.ELEMENT_NODE:this.node.textContent=a;break;case g.TEXT_NODE:this.node.data=a}return this}switch(this.node.nodeType){case g.ELEMENT_NODE:return this.node.tagName===g.DEFAULT_BREAK_TAG?"":null!=g.EMBED_TAGS[this.node.tagName]?g.EMBED_TEXT:null!=this.node.textContent?this.node.textContent:"";case g.TEXT_NODE:return this.node.data||"";default:return""}},a.prototype.textNodes=function(){var a,b,c;for(c=document.createTreeWalker(this.node,NodeFilter.SHOW_TEXT,null,!1),b=[];a=c.nextNode();)b.push(a);return b},a.prototype.toggleClass=function(a,b){return null==b&&(b=!this.hasClass(a)),b?this.addClass(a):this.removeClass(a),this},a.prototype.trigger=function(a,b){var c,d,e;return null==b&&(b={}),["keypress","keydown","keyup"].indexOf(a)<0?(c=document.createEvent("Event"),c.initEvent(a,b.bubbles,b.cancelable)):(c=document.createEvent("KeyboardEvent"),h=f.clone(b),f.isNumber(b.key)?h.which=b.key:f.isString(b.key)?h.which=b.key.toUpperCase().charCodeAt(0):h.which=0,g.isIE(10)?(e=[],b.altKey&&e.push("Alt"),b.ctrlKey&&e.push("Control"),b.metaKey&&e.push("Meta"),b.shiftKey&&e.push("Shift"),c.initKeyboardEvent(a,b.bubbles,b.cancelable,window,0,0,e.join(" "),null,null)):(d=f.isFunction(c.initKeyboardEvent)?"initKeyboardEvent":"initKeyEvent",c[d](a,b.bubbles,b.cancelable,window,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,0,0))),this.node.dispatchEvent(c),h=null,this},a.prototype.unwrap=function(){var a,b;return b=this.node.firstChild,a=this.node.nextSibling,f.each(this.childNodes(),function(b){return function(c){return b.node.parentNode.insertBefore(c,a)}}(this)),this.remove(),b},a.prototype.wrap=function(a){var b;for(null!=this.node.parentNode&&this.node.parentNode.insertBefore(a,this.node),b=a;null!=b.firstChild;)b=a.firstChild;return b.appendChild(this.node),this},a}(),d=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return j(b,a),b.prototype["default"]=function(){return this.node.querySelector("option[selected]")},b.prototype.option=function(a,b){var c,d,e,g,h,i;if(null==b&&(b=!0),i=f.isElement(a)?a.value:a){for(i=i.replace(/[^\w]+/g,""),h=this.node.children,d=e=0,g=h.length;g>e;d=++e)if(c=h[d],c.value.replace(/[^\w]+/g,"")===i){this.node.selectedIndex=d;break}}else this.node.selectedIndex=-1;return b&&this.trigger("change"),this},b.prototype.reset=function(a){var b;return null==a&&(a=!0),b=this["default"](),null!=b?b.selected=!0:this.node.selectedIndex=0,a&&this.trigger("change"),this},b.prototype.value=function(){return this.node.selectedIndex>-1?this.node.options[this.node.selectedIndex].value:""},b}(e),g=function(a){return"SELECT"===(null!=a?a.tagName:void 0)?new d(a):new e(a)},g=f.extend(g,{ELEMENT_NODE:1,NOBREAK_SPACE:" ",TEXT_NODE:3,ZERO_WIDTH_NOBREAK_SPACE:"\ufeff",DEFAULT_BLOCK_TAG:"DIV",DEFAULT_BREAK_TAG:"BR",DEFAULT_INLINE_TAG:"SPAN",EMBED_TEXT:"!",FONT_SIZES:{"10px":1,"13px":2,"16px":3,"18px":4,"24px":5,"32px":6,"48px":7},KEYS:{BACKSPACE:8,TAB:9,ENTER:13,ESCAPE:27,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46},BLOCK_TAGS:{ADDRESS:"ADDRESS",ARTICLE:"ARTICLE",ASIDE:"ASIDE",AUDIO:"AUDIO",BLOCKQUOTE:"BLOCKQUOTE",CANVAS:"CANVAS",DD:"DD",DIV:"DIV",DL:"DL",FIGCAPTION:"FIGCAPTION",FIGURE:"FIGURE",FOOTER:"FOOTER",FORM:"FORM",H1:"H1",H2:"H2",H3:"H3",H4:"H4",H5:"H5",H6:"H6",HEADER:"HEADER",HGROUP:"HGROUP",LI:"LI",OL:"OL",OUTPUT:"OUTPUT",P:"P",PRE:"PRE",SECTION:"SECTION",TABLE:"TABLE",TBODY:"TBODY",TD:"TD",TFOOT:"TFOOT",TH:"TH",THEAD:"THEAD",TR:"TR",UL:"UL",VIDEO:"VIDEO"},EMBED_TAGS:{IMG:"IMG"},LINE_TAGS:{DIV:"DIV",LI:"LI"},LIST_TAGS:{OL:"OL",UL:"UL"},VOID_TAGS:{AREA:"AREA",BASE:"BASE",BR:"BR",COL:"COL",COMMAND:"COMMAND",EMBED:"EMBED",HR:"HR",IMG:"IMG",INPUT:"INPUT",KEYGEN:"KEYGEN",LINK:"LINK",META:"META",PARAM:"PARAM",SOURCE:"SOURCE",TRACK:"TRACK",WBR:"WBR"},convertFontSize:function(a){var b,c,d,e;f.isString(a)&&a.indexOf("px")>-1?(d=Object.keys(g.FONT_SIZES),e=f.values(g.FONT_SIZES)):(e=Object.keys(g.FONT_SIZES),d=f.values(g.FONT_SIZES));for(b in d)if(c=d[b],parseInt(a)<=parseInt(c))return e[b];return f.last(e)},isIE:function(a){var b;return b=document.documentMode,b&&a>=b},isIOS:function(){return/iPhone|iPad/i.test(navigator.userAgent)},isMac:function(){return/Mac/i.test(navigator.platform)}}),b.exports=g},{lodash:1}],18:[function(a,b,c){var d,e;e=function(){function a(a){this.data=a,this.prev=this.next=null}return a}(),d=function(){function a(){this.length=0,this.first=this.last=null}return a.Node=e,a.prototype.append=function(a){return null!=this.first?(a.next=null,this.last.next=a):this.first=a,a.prev=this.last,this.last=a,this.length+=1},a.prototype.insertAfter=function(a,b){return b.prev=a,null!=a?(b.next=a.next,null!=a.next&&(a.next.prev=b),a.next=b,a===this.last&&(this.last=b)):(b.next=this.first,this.first.prev=b,this.first=b),this.length+=1},a.prototype.remove=function(a){return this.length>1?(null!=a.prev&&(a.prev.next=a.next),null!=a.next&&(a.next.prev=a.prev),a===this.first&&(this.first=a.next),a===this.last&&(this.last=a.prev)):this.first=this.last=null,a.prev=a.next=null,this.length-=1},a.prototype.toArray=function(){var a,b;for(a=[],b=this.first;null!=b;)a.push(b),b=b.next;return a},a}(),b.exports=d},{}],19:[function(a,b,c){var d,e,f;e=a("lodash"),f=a("./dom"),d=function(){function a(a){this.select=a,this.container=document.createElement("span"),this.buildPicker(),f(this.container).addClass("ql-picker"),this.select.style.display="none",this.select.parentNode.insertBefore(this.container,this.select),f(document).on("click",function(a){return function(){return a.close(),!0}}(this)),f(this.label).on("click",function(a){return function(){return e.defer(function(){return f(a.container).toggleClass("ql-expanded")}),!1}}(this)),f(this.select).on("change",function(a){return function(){var b,c;return a.select.selectedIndex>-1&&(b=a.container.querySelectorAll(".ql-picker-item")[a.select.selectedIndex],c=a.select.options[a.select.selectedIndex]),a.selectItem(b,!1),f(a.label).toggleClass("ql-active",c!==f(a.select)["default"]())}}(this))}return a.TEMPLATE='',a.prototype.buildItem=function(a,b,c){var d;return d=document.createElement("span"),d.setAttribute("data-value",b.getAttribute("value")),f(d).addClass("ql-picker-item").text(f(b).text()).on("click",function(a){return function(){return a.selectItem(d,!0),a.close()}}(this)),this.select.selectedIndex===c&&this.selectItem(d,!1),d},a.prototype.buildPicker=function(){var b;return e.each(f(this.select).attributes(),function(a){return function(b,c){return a.container.setAttribute(c,b)}}(this)),this.container.innerHTML=a.TEMPLATE,this.label=this.container.querySelector(".ql-picker-label"),b=this.container.querySelector(".ql-picker-options"),e.each(this.select.options,function(a){return function(c,d){var e;return e=a.buildItem(b,c,d),b.appendChild(e)}}(this))},a.prototype.close=function(){return f(this.container).removeClass("ql-expanded")},a.prototype.selectItem=function(a,b){var c,d;return c=this.container.querySelector(".ql-selected"),null!=c&&f(c).removeClass("ql-selected"),null!=a?(d=a.getAttribute("data-value"),f(a).addClass("ql-selected"),f(this.label).text(f(a).text()),f(this.select).option(d,b),this.label.setAttribute("data-value",d)):(this.label.innerHTML=" ",this.label.removeAttribute("data-value"))},a}(),b.exports=d},{"./dom":17,lodash:1}],20:[function(a,b,c){var d,e;e=a("lodash"),d=function(){function a(a,b){this.start=a,this.end=b}return a.compare=function(a,b){return a===b?!0:null==a||null==b?!1:a.equals(b)},a.prototype.equals=function(a){return null==a?!1:this.start===a.start&&this.end===a.end},a.prototype.shift=function(a,b){var c;return c=e.map([this.start,this.end],function(c){return a>c?c:b>=0?c+b:Math.max(a,c+b)}),this.start=c[0],this.end=c[1],c},a.prototype.isCollapsed=function(){return this.start===this.end},a}(),b.exports=d},{lodash:1}],21:[function(a,b,c){var d,e,f,g,h;f=a("../quill"),g=f.require("lodash"),h=f.require("dom"),e=f.require("delta"),d=function(){function a(a,b){this.quill=a,this.options=b,null!=this.options.button&&this.attachButton(this.options.button),this.options.enabled&&this.enable(),this.quill.addFormat("author",{"class":"author-"}),null!=this.options.authorId&&(this.quill.on(this.quill.constructor.events.PRE_EVENT,function(a){return function(b,c,d){var h,i;return b===a.quill.constructor.events.TEXT_CHANGE&&"user"===d?(h=new e,i={author:a.options.authorId},g.each(c.ops,function(b){return null==b["delete"]?null!=b.insert||null!=b.retain&&null!=b.attributes?(b.attributes||(b.attributes={}),b.attributes.author=a.options.authorId,h.retain(b.retain||b.insert.length||1,i)):h.retain(b.retain):void 0}),a.quill.updateContents(h,f.sources.SILENT)):void 0}}(this)),this.addAuthor(this.options.authorId,this.options.color))}return a.DEFAULTS={authorId:null,color:"transparent",enabled:!1},a.prototype.addAuthor=function(a,b){var c;return c={},c[".authorship .author-"+a]={"background-color":""+b},this.quill.theme.addStyles(c)},a.prototype.attachButton=function(a){var b;return b=h(a),b.on("click",function(a){return function(){return b.toggleClass("ql-on"),a.enable($dom.hasClass("ql-on"))}}(this))},a.prototype.enable=function(a){return null==a&&(a=!0),h(this.quill.root).toggleClass("authorship",a)},a.prototype.disable=function(){return this.enable(!1)},a}(),f.registerModule("authorship",d),b.exports=d},{"../quill":30}],22:[function(a,b,c){var d,e,f,g,h,i,j,k=function(a,b){function c(){this.constructor=a}for(var d in b)l.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},l={}.hasOwnProperty;f=a("../quill"),h=a("./tooltip"),i=f.require("lodash"),j=f.require("dom"),d=f.require("delta"),g=f.require("range"),e=function(a){function b(a,c){this.quill=a,this.options=c,this.options=i.defaults(this.options,h.DEFAULTS),b.__super__.constructor.call(this,this.quill,this.options),this.preview=this.container.querySelector(".preview"),this.textbox=this.container.querySelector(".input"),j(this.container).addClass("ql-image-tooltip"),this.initListeners()}return k(b,a),b.DEFAULTS={template:'
Preview
Cancel Insert'},b.prototype.initListeners=function(){return j(this.quill.root).on("focus",i.bind(this.hide,this)),j(this.container.querySelector(".insert")).on("click",i.bind(this.insertImage,this)),j(this.container.querySelector(".cancel")).on("click",i.bind(this.hide,this)),j(this.textbox).on("input",i.bind(this._preview,this)),this.initTextbox(this.textbox,this.insertImage,this.hide),this.quill.onModuleLoad("toolbar",function(a){return function(b){return a.toolbar=b,b.initFormat("image",i.bind(a._onToolbar,a))}}(this))},b.prototype.insertImage=function(){var a,b;return b=this._normalizeURL(this.textbox.value),null==this.range&&(this.range=new g(0,0)),this.range&&(this.preview.innerHTML="Preview",this.textbox.value="",a=this.range.end,this.quill.insertEmbed(a,"image",b,"user"),this.quill.setSelection(a+1,a+1)),this.hide()},b.prototype._onToolbar=function(a,b){return b?(this.textbox.value||(this.textbox.value="http://"),this.show(),this.textbox.focus(),i.defer(function(a){return function(){return a.textbox.setSelectionRange(a.textbox.value.length,a.textbox.value.length)}}(this))):(this.quill.deleteText(a,"user"),this.toolbar.setActive("image",!1))},b.prototype._preview=function(){var a;if(this._matchImageURL(this.textbox.value))return"IMG"===this.preview.firstChild.tagName?this.preview.firstChild.setAttribute("src",this.textbox.value):(a=document.createElement("img"),a.setAttribute("src",this.textbox.value),this.preview.replaceChild(a,this.preview.firstChild))},b.prototype._matchImageURL=function(a){return/^https?:\/\/.+\.(jpe?g|gif|png)$/.test(a)},b.prototype._normalizeURL=function(a){return/^https?:\/\//.test(a)||(a="http://"+a),a},b}(h),f.registerModule("image-tooltip",e),b.exports=e},{"../quill":30,"./tooltip":28}],23:[function(a,b,c){var d,e,f,g,h;f=a("../quill"),g=f.require("lodash"),h=f.require("dom"),d=f.require("delta"),e=function(){function a(a,b){this.quill=a,this.hotkeys={},this._initListeners(),this._initHotkeys(),this.quill.onModuleLoad("toolbar",function(a){return function(b){return a.toolbar=b}}(this))}return a.hotkeys={BOLD:{key:"B",metaKey:!0},INDENT:{key:h.KEYS.TAB},ITALIC:{key:"I",metaKey:!0},OUTDENT:{key:h.KEYS.TAB,shiftKey:!0},UNDERLINE:{key:"U",metaKey:!0}},a.prototype.addHotkey=function(a,b){return Array.isArray(a)||(a=[a]),g.each(a,function(a){return function(c){var d,e;return c=g.isObject(c)?g.clone(c):{key:c},c.callback=b,e=g.isNumber(c.key)?c.key:c.key.toUpperCase().charCodeAt(0),null==(d=a.hotkeys)[e]&&(d[e]=[]),a.hotkeys[e].push(c)}}(this))},a.prototype.removeHotkeys=function(b,c){var d,e,f,h,i;return b=g.isString(b)?b.toUpperCase():b,b=a.hotkeys[b]?a.hotkeys[b]:b,b=g.isObject(b)?b:{key:b},i=g.isNumber(b.key)?b.key:b.key.charCodeAt(0),null==(d=this.hotkeys)[i]&&(d[i]=[]),f=g.partition(this.hotkeys[i],function(a){return g.isEqual(b,g.omit(a,"callback"))&&(!c||c===a.callback)}),h=f[0],e=f[1],this.hotkeys[i]=e,g.map(h,"callback")},a.prototype.toggleFormat=function(a,b){var c,d;return c=a.isCollapsed()?this.quill.getContents(Math.max(0,a.start-1),a.end):this.quill.getContents(a),d=0===c.ops.length||!g.all(c.ops,function(a){var c;return null!=(c=a.attributes)?c[b]:void 0}),a.isCollapsed()?this.quill.prepareFormat(b,d,f.sources.USER):this.quill.formatText(a,b,d,f.sources.USER),null!=this.toolbar?this.toolbar.setActive(b,d):void 0},a.prototype._initEnter=function(){var a;return a=[{key:h.KEYS.ENTER},{key:h.KEYS.ENTER,shiftKey:!0}],this.addHotkey(a,function(a){return function(b,c){var e,h,i,j,k,l;return null==b?!0:(k=a.quill.editor.doc.findLineAt(b.start),i=k[0],j=k[1],l=i.findLeafAt(j),h=l[0],j=l[1],e=(new d).retain(b.start).insert("\n",i.formats)["delete"](b.end-b.start),a.quill.updateContents(e,f.sources.USER),g.each(h.formats,function(b,c){a.quill.prepareFormat(c,b),null!=a.toolbar&&a.toolbar.setActive(c,b)}),a.quill.editor.selection.scrollIntoView(),!1)}}(this))},a.prototype._initDeletes=function(){return this.addHotkey([h.KEYS.DELETE,h.KEYS.BACKSPACE],function(a){return function(b,c){var d,e,g,i;return null!=b&&a.quill.getLength()>0&&(b.start!==b.end?a.quill.deleteText(b.start,b.end,f.sources.USER):c.key===h.KEYS.BACKSPACE?(i=a.quill.editor.doc.findLineAt(b.start),e=i[0],g=i[1],0===g&&(e.formats.bullet||e.formats.list)?(d=e.formats.bullet?"bullet":"list",a.quill.formatLine(b.start,b.start,d,!1,f.sources.USER)):b.start>0&&a.quill.deleteText(b.start-1,b.start,f.sources.USER)):b.startVisit URL:   -  Change Remove Done'},b.hotkeys={LINK:{key:"K",metaKey:!0}},b.prototype.initListeners=function(){return this.quill.on(this.quill.constructor.events.SELECTION_CHANGE,function(a){return function(b){var c;if(null!=b&&b.isCollapsed())return c=a._findAnchor(b),c?(a.setMode(c.href,!1),a.show(c)):a.container.style.left!==f.HIDE_MARGIN?(a.range=null,a.hide()):void 0}}(this)),h(this.container.querySelector(".done")).on("click",g.bind(this.saveLink,this)),h(this.container.querySelector(".remove")).on("click",function(a){return function(){return a.removeLink(a.range)}}(this)),h(this.container.querySelector(".change")).on("click",function(a){return function(){return a.setMode(a.link.href,!0)}}(this)),this.initTextbox(this.textbox,this.saveLink,this.hide),this.quill.onModuleLoad("toolbar",function(a){return function(b){return a.toolbar=b,b.initFormat("link",g.bind(a._onToolbar,a))}}(this)),this.quill.onModuleLoad("keyboard",function(a){return function(c){return c.addHotkey(b.hotkeys.LINK,g.bind(a._onKeyboard,a))}}(this))},b.prototype.saveLink=function(){var a,b,c;return c=this._normalizeURL(this.textbox.value),null!=this.range&&(b=this.range.end,this.range.isCollapsed()?(a=this._findAnchor(this.range),null!=a&&(a.href=c)):this.quill.formatText(this.range,"link",c,"user"),this.quill.setSelection(b,b)),this.setMode(c,!1)},b.prototype.removeLink=function(a){return a.isCollapsed()&&(a=this._expandRange(a)),this.hide(),this.quill.formatText(a,"link",!1,"user"),null!=this.toolbar?this.toolbar.setActive("link",!1):void 0},b.prototype.setMode=function(a,b){var c;return null==b&&(b=!1),b?(this.textbox.value=a,g.defer(function(b){return function(){return b.textbox.focus(),b.textbox.setSelectionRange(0,a.length)}}(this))):(this.link.href=a,a=this.link.href,c=a.length>this.options.maxLength?a.slice(0,this.options.maxLength)+"...":a,h(this.link).text(c)),h(this.container).toggleClass("editing",b)},b.prototype._findAnchor=function(a){var b,c,d,e;for(e=this.quill.editor.doc.findLeafAt(a.start,!0),b=e[0],d=e[1],null!=b&&(c=b.node);null!=c&&c!==this.quill.root;){if("A"===c.tagName)return c;c=c.parentNode}return null},b.prototype._expandRange=function(a){var b,c,d,e,f;return e=this.quill.editor.doc.findLeafAt(a.start,!0),c=e[0],d=e[1],f=a.start-d,b=f+c.length,{start:f,end:b}},b.prototype._onToolbar=function(a,b){return this._toggle(a,b)},b.prototype._onKeyboard=function(){var a;return a=this.quill.getSelection(),this._toggle(a,!this._findAnchor(a))},b.prototype._toggle=function(a,b){var c;if(a)return b?a.isCollapsed()?void 0:(this.setMode(this._suggestURL(a),!0),c=this.quill.editor.selection._getNativeRange(),this.show(c)):this.removeLink(a)},b.prototype._normalizeURL=function(a){return/^(https?:\/\/|mailto:)/.test(a)||(a="http://"+a),a},b.prototype._suggestURL=function(a){var b;return b=this.quill.getText(a),this._normalizeURL(b)},b}(f),e.registerModule("link-tooltip",d),b.exports=d},{"../quill":30,"./tooltip":28}],25:[function(a,b,c){var d,e,f,g,h,i=function(a,b){function c(){this.constructor=a}for(var d in b)j.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},j={}.hasOwnProperty;f=a("../quill"),d=a("eventemitter2").EventEmitter2,g=f.require("lodash"),h=f.require("dom"),e=function(a){function b(a,b){this.quill=a,this.options=b,this.cursors={},this.container=this.quill.addContainer("ql-multi-cursor",!0),this.quill.on(this.quill.constructor.events.TEXT_CHANGE,g.bind(this._applyDelta,this))}return i(b,a),b.DEFAULTS={template:' ',timeout:2500},b.events={CURSOR_ADDED:"cursor-addded",CURSOR_MOVED:"cursor-moved",CURSOR_REMOVED:"cursor-removed"},b.prototype.clearCursors=function(){return g.each(Object.keys(this.cursors),g.bind(this.removeCursor,this)),this.cursors={}},b.prototype.moveCursor=function(a,b){var c;return c=this.cursors[a],null!=c?(c.index=b,h(c.elem).removeClass("hidden"),clearTimeout(c.timer),c.timer=setTimeout(function(a){return function(){return h(c.elem).addClass("hidden"),c.timer=null}}(this),this.options.timeout),this._updateCursor(c),c):void 0},b.prototype.removeCursor=function(a){var c;return c=this.cursors[a],this.emit(b.events.CURSOR_REMOVED,c),null!=c&&c.elem.parentNode.removeChild(c.elem),delete this.cursors[a]},b.prototype.setCursor=function(a,c,d,e){var f;return null==this.cursors[a]&&(this.cursors[a]=f={userId:a,index:c,color:e,elem:this._buildCursor(d,e)},this.emit(b.events.CURSOR_ADDED,f)),g.defer(function(b){return function(){return b.moveCursor(a,c)}}(this)),this.cursors[a]},b.prototype.shiftCursors=function(a,b,c){return null==c&&(c=null),g.each(this.cursors,function(d){return function(e,f){var g;if(e)return g=Math.max(b,a-e.index),e.userId===c?d.moveCursor(c,e.index+g):e.index>a?e.index+=g:void 0}}(this))},b.prototype.update=function(){return g.each(this.cursors,function(a){return function(b,c){return null!=b?(a._updateCursor(b),!0):void 0}}(this))},b.prototype._applyDelta=function(a){var b;return b=0,g.each(a.ops,function(a){return function(c){var d,e;return d=0,null!=c.insert?(d=c.insert.length||1,a.shiftCursors(b,d,null!=(e=c.attributes)?e.author:void 0)):null!=c["delete"]?a.shiftCursors(b,-1*c["delete"],null):null!=c.retain&&(a.shiftCursors(b,0,null),d=c.retain),b+=d}}(this)),this.update()},b.prototype._buildCursor=function(a,b){var c,d,e,f;return c=document.createElement("span"),h(c).addClass("cursor"),c.innerHTML=this.options.template,e=c.querySelector(".cursor-flag"),f=c.querySelector(".cursor-name"),h(f).text(a),d=c.querySelector(".cursor-caret"),d.style.backgroundColor=f.style.backgroundColor=b, +this.container.appendChild(c),c},b.prototype._updateCursor=function(a){var c,d;return c=this.quill.getBounds(a.index),null==c?this.removeCursor(a.userId):(a.elem.style.top=c.top+this.quill.container.scrollTop+"px",a.elem.style.left=c.left+"px",a.elem.style.height=c.height+"px",d=a.elem.querySelector(".cursor-flag"),h(a.elem).toggleClass("top",parseInt(a.elem.style.top)<=d.offsetHeight).toggleClass("left",parseInt(a.elem.style.left)<=d.offsetWidth).toggleClass("right",this.quill.root.offsetWidth-parseInt(a.elem.style.left)<=d.offsetWidth),this.emit(b.events.CURSOR_MOVED,a))},b}(d),f.registerModule("multi-cursor",e),b.exports=e},{"../quill":30,eventemitter2:2}],26:[function(a,b,c){var d,e,f,g,h,i,j=function(a,b){return function(){return a.apply(b,arguments)}};g=a("../quill"),e=a("../core/document"),h=g.require("lodash"),i=g.require("dom"),d=g.require("delta"),f=function(){function a(b,c){var d;this.quill=b,this._onConvert=j(this._onConvert,this),this.container=this.quill.addContainer("ql-paste-manager"),this.container.setAttribute("contenteditable",!0),this.container.setAttribute("tabindex","-1"),i(this.quill.root).on("paste",h.bind(this._paste,this)),this.options=h.defaults(c,a.DEFAULTS),null==(d=this.options).onConvert&&(d.onConvert=this._onConvert)}return a.DEFAULTS={onConvert:null},a.prototype._onConvert=function(a){var b,c,f;return c=new e(a,this.quill.options),b=c.toDelta(),f=b.length(),0===f?b:b.compose((new d).retain(f-1)["delete"](1))},a.prototype._paste=function(){var a,b;return a=this.quill.getLength(),b=this.quill.getSelection(),null!=b?(this.container.focus(),h.defer(function(a){return function(){var c,d;return c=a.options.onConvert(a.container),d=c.length(),d>0&&(b.start>0&&c.ops.unshift({retain:b.start}),c["delete"](b.end-b.start),a.quill.updateContents(c,"user")),a.quill.setSelection(b.start+d,b.start+d),a.quill.editor.selection.scrollIntoView(),a.container.innerHTML=""}}(this))):void 0},a}(),g.registerModule("paste-manager",f),b.exports=f},{"../core/document":8,"../quill":30}],27:[function(a,b,c){var d,e,f,g;d=a("../quill"),f=d.require("lodash"),g=d.require("dom"),e=function(){function a(b,c){if(this.quill=b,this.options=c,(f.isString(this.options)||f.isElement(this.options))&&(this.options={container:this.options}),null==this.options.container)throw new Error("container required for toolbar",this.options);this.container=f.isString(this.options.container)?document.querySelector(this.options.container):this.options.container,this.inputs={},this.preventUpdate=!1,this.triggering=!1,f.each(this.quill.options.formats,function(b){return function(c){return null==a.formats.TOOLTIP[c]?b.initFormat(c,f.bind(b._applyFormat,b,c)):void 0}}(this)),this.quill.on(d.events.FORMAT_INIT,function(b){return function(c){return null==a.formats.TOOLTIP[c]?b.initFormat(c,f.bind(b._applyFormat,b,c)):void 0}}(this)),this.quill.on(d.events.SELECTION_CHANGE,function(a){return function(b){return null!=b?a.updateActive(b):void 0}}(this)),this.quill.on(d.events.TEXT_CHANGE,function(a){return function(){return a.updateActive()}}(this)),this.quill.onModuleLoad("keyboard",function(a){return function(b){return b.addHotkey([g.KEYS.BACKSPACE,g.KEYS.DELETE],function(){return f.defer(f.bind(a.updateActive,a))})}}(this)),g(this.container).addClass("ql-toolbar"),g.isIOS()&&g(this.container).addClass("ios")}return a.DEFAULTS={container:null},a.formats={LINE:{align:"align",bullet:"bullet",list:"list"},SELECT:{align:"align",background:"background",color:"color",font:"font",size:"size"},TOGGLE:{bold:"bold",bullet:"bullet",image:"image",italic:"italic",link:"link",list:"list",strike:"strike",underline:"underline"},TOOLTIP:{image:"image",link:"link"}},a.prototype.initFormat=function(b,c){var d,e,f;return f=".ql-"+b,null!=a.formats.SELECT[b]?(f="select"+f,d="change"):d="click",e=this.container.querySelector(f),null!=e?(this.inputs[b]=e,g(e).on(d,function(a){return function(){var b,f;return f="change"===d?g(e).value():!g(e).hasClass("ql-active"),a.preventUpdate=!0,a.quill.focus(),b=a.quill.getSelection(),null!=b&&c(b,f),g.isIE(11)&&a.quill.editor.selection.scrollIntoView(),a.preventUpdate=!1,!1}}(this))):void 0},a.prototype.setActive=function(a,b){var c,d,e,f;return"image"===a&&(b=!1),d=this.inputs[a],null!=d?(c=g(d),"SELECT"===d.tagName?(this.triggering=!0,f=c.value(d),null==b&&(b=null!=(e=c["default"]())?e.value:void 0),Array.isArray(b)&&(b=""),b!==f&&(null!=b?c.option(b):c.reset()),this.triggering=!1):c.toggleClass("ql-active",b||!1)):void 0},a.prototype.updateActive=function(a,b){var c;return null==b&&(b=null),a||(a=this.quill.getSelection()),null==a||this.preventUpdate?void 0:(c=this._getActive(a),f.each(this.inputs,function(a){return function(d,e){return(!Array.isArray(b)||b.indexOf(e)>-1)&&a.setActive(e,c[e]),!0}}(this)))},a.prototype._applyFormat=function(b,c,d){return this.triggering?void 0:(c.isCollapsed()?this.quill.prepareFormat(b,d,"user"):null!=a.formats.LINE[b]?this.quill.formatLine(c,b,d,"user"):this.quill.formatText(c,b,d,"user"),f.defer(function(a){return function(){return a.updateActive(c,["bullet","list"]),a.setActive(b,d)}}(this)))},a.prototype._getActive=function(a){var b,c;return b=this._getLeafActive(a),c=this._getLineActive(a),f.defaults({},b,c)},a.prototype._getLeafActive=function(a){var b,c,d,e,g;return a.isCollapsed()?(g=this.quill.editor.doc.findLineAt(a.start),d=g[0],e=g[1],b=0===e?this.quill.getContents(a.start,a.end+1):this.quill.getContents(a.start-1,a.end)):b=this.quill.getContents(a),c=f.map(b.ops,"attributes"),this._intersectFormats(c)},a.prototype._getLineActive=function(a){var b,c,d,e,g,h;for(c=[],g=this.quill.editor.doc.findLineAt(a.start),b=g[0],e=g[1],h=this.quill.editor.doc.findLineAt(a.end),d=h[0],e=h[1],null!=d&&d===b&&(d=d.next);null!=b&&b!==d;)c.push(f.clone(b.formats)),b=b.next;return this._intersectFormats(c)},a.prototype._intersectFormats=function(b){return f.reduce(b.slice(1),function(b,c){var d,e,g,h,i;return null==c&&(c={}),d=Object.keys(b),g=null!=c?Object.keys(c):{},h=f.intersection(d,g),i=f.difference(d,g),e=f.difference(g,d),f.each(h,function(d){if(null!=a.formats.SELECT[d])if(Array.isArray(b[d])){if(b[d].indexOf(c[d])<0)return b[d].push(c[d])}else if(b[d]!==c[d])return b[d]=[b[d],c[d]]}),f.each(i,function(c){return null!=a.formats.TOGGLE[c]?delete b[c]:null==a.formats.SELECT[c]||Array.isArray(b[c])?void 0:b[c]=[b[c]]}),f.each(e,function(d){return null!=a.formats.SELECT[d]?b[d]=[c[d]]:void 0}),b},b[0]||{})},a}(),d.registerModule("toolbar",e),b.exports=e},{"../quill":30}],28:[function(a,b,c){var d,e,f,g;d=a("../quill"),f=d.require("lodash"),g=d.require("dom"),e=function(){function a(b,c){this.quill=b,this.options=c,this.container=this.quill.addContainer("ql-tooltip"),this.container.innerHTML=this.options.template,this.hide(),this.quill.on(this.quill.constructor.events.TEXT_CHANGE,function(b){return function(c,d){return b.container.style.left!==a.HIDE_MARGIN?(b.range=null,b.hide()):void 0}}(this))}return a.DEFAULTS={offset:10,template:""},a.HIDE_MARGIN="-10000px",a.prototype.initTextbox=function(a,b,c){return g(a).on("keydown",function(a){return function(d){switch(d.which){case g.KEYS.ENTER:return d.preventDefault(),b.call(a);case g.KEYS.ESCAPE:return d.preventDefault(),c.call(a);default:return!0}}}(this))},a.prototype.hide=function(){return this.container.style.left=a.HIDE_MARGIN,this.range&&this.quill.setSelection(this.range),this.range=null},a.prototype.position=function(a){var b,c,d,e,f,g,h;return null!=a?(g=a.getBoundingClientRect(),f=this.quill.container.getBoundingClientRect(),d=g.left-f.left,e=g.top-f.top,c=g.bottom-f.bottom,b=d+g.width/2-this.container.offsetWidth/2,h=e+g.height+this.options.offset,h+this.container.offsetHeight>this.quill.container.offsetHeight&&(h=e-this.container.offsetHeight-this.options.offset),b=Math.max(0,Math.min(b,this.quill.container.offsetWidth-this.container.offsetWidth)),h=Math.max(0,Math.min(h,this.quill.container.offsetHeight-this.container.offsetHeight))):(b=this.quill.container.offsetWidth/2-this.container.offsetWidth/2,h=this.quill.container.offsetHeight/2-this.container.offsetHeight/2),h+=this.quill.container.scrollTop,[b,h]},a.prototype.show=function(a){var b,c,d;return this.range=this.quill.getSelection(),c=this.position(a),b=c[0],d=c[1],this.container.style.left=b+"px",this.container.style.top=d+"px",this.container.focus()},a}(),d.registerModule("tooltip",e),b.exports=e},{"../quill":30}],29:[function(a,b,c){var d,e,f,g;e=a("../quill"),g=e.require("lodash"),d=e.require("delta"),f=function(){function a(a,b){this.quill=a,this.options=null!=b?b:{},this.lastRecorded=0,this.ignoreChange=!1,this.clear(),this.initListeners()}return a.DEFAULTS={delay:1e3,maxStack:100,userOnly:!1},a.hotkeys={UNDO:{key:"Z",metaKey:!0},REDO:{key:"Z",metaKey:!0,shiftKey:!0}},a.prototype.initListeners=function(){return this.quill.onModuleLoad("keyboard",function(b){return function(c){var d;return c.addHotkey(a.hotkeys.UNDO,function(){return b.quill.editor.checkUpdate(),b.undo(),!1}),d=[a.hotkeys.REDO],navigator.platform.indexOf("Win")>-1&&d.push({key:"Y",metaKey:!0}),c.addHotkey(d,function(){return b.quill.editor.checkUpdate(),b.redo(),!1})}}(this)),this.quill.on(this.quill.constructor.events.TEXT_CHANGE,function(a){return function(b,c){return a.ignoreChange?void 0:(a.options.userOnly&&c!==e.sources.USER?a._transform(b):a.record(b,a.oldDelta),a.oldDelta=a.quill.getContents())}}(this))},a.prototype.clear=function(){return this.stack={undo:[],redo:[]},this.oldDelta=this.quill.getContents()},a.prototype.record=function(a,b){var c,d,e,f;if(a.ops.length>0){this.stack.redo=[];try{if(f=this.quill.getContents().diff(this.oldDelta),e=(new Date).getTime(),this.lastRecorded+this.options.delay>e&&this.stack.undo.length>0?(c=this.stack.undo.pop(),f=f.compose(c.undo),a=c.redo.compose(a)):this.lastRecorded=e,this.stack.undo.push({redo:a,undo:f}),this.stack.undo.length>this.options.maxStack)return this.stack.undo.unshift()}catch(g){return d=g,console.warn("Could not record change... clearing undo stack."),this.clear()}}},a.prototype.redo=function(){return this._change("redo","undo")},a.prototype.undo=function(){return this._change("undo","redo")},a.prototype._getLastChangeIndex=function(a){var b,c;return c=0,b=0,g.each(a.ops,function(a){return null!=a.insert?c=Math.max(b+(a.insert.length||1),c):null!=a["delete"]?c=Math.max(b,c):null!=a.retain?(null!=a.attributes&&(c=Math.max(b+a.retain,c)),b+=a.retain):void 0}),c},a.prototype._change=function(a,b){var c,d;return this.stack[a].length>0?(c=this.stack[a].pop(),this.lastRecorded=0,this.ignoreChange=!0,this.quill.updateContents(c[a],e.sources.USER),this.ignoreChange=!1,d=this._getLastChangeIndex(c[a]),this.quill.setSelection(d,d),this.oldDelta=this.quill.getContents(),this.stack[b].push(c)):void 0},a.prototype._transform=function(a){var b,c,d,e,f,g,h,i;for(this.oldDelta=a.transform(this.oldDelta,!0),g=this.stack.undo,c=0,e=g.length;e>c;c++)b=g[c],b.undo=a.transform(b.undo,!0),b.redo=a.transform(b.redo,!0);for(h=this.stack.redo,i=[],d=0,f=h.length;f>d;d++)b=h[d],b.undo=a.transform(b.undo,!0),i.push(b.redo=a.transform(b.redo,!0));return i},a}(),e.registerModule("undo-manager",f),b.exports=f},{"../quill":30}],30:[function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o=function(a,b){function c(){this.constructor=a}for(var d in b)p.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},p={}.hasOwnProperty,q=[].slice;l=a("lodash"),n=a("../package.json"),d=a("rich-text/lib/delta"),g=a("eventemitter2").EventEmitter2,m=a("./lib/dom"),e=a("./core/document"),f=a("./core/editor"),h=a("./core/format"),i=a("./core/normalizer"),k=a("./lib/range"),j=function(a){function b(a,c){var d,e,g;if(this.container=a,null==c&&(c={}),l.isString(this.container)&&(this.container=document.querySelector(this.container)),null==this.container)throw new Error("Invalid Quill container");if(e=l.defaults(c.modules||{},b.DEFAULTS.modules),d=this.container.innerHTML,this.container.innerHTML="",this.options=l.defaults(c,b.DEFAULTS),this.options.modules=e,this.options.id=this.id="ql-editor-"+(b.editors.length+1),this.modules={},this.root=this.addContainer("ql-editor"),this.editor=new f(this.root,this,this.options),b.editors.push(this),this.setHTML(d,b.sources.SILENT),g=b.themes[this.options.theme],null==g)throw new Error("Cannot load "+this.options.theme+" theme. Are you sure you registered it?");this.theme=new g(this,this.options),l.each(this.options.modules,function(a){return function(b,c){return a.addModule(c,b)}}(this))}return o(b,a),b.version=n.version,b.editors=[],b.modules=[],b.themes=[],b.DEFAULTS={formats:["align","bold","italic","strike","underline","color","background","font","size","link","image","bullet","list"],modules:{keyboard:!0,"paste-manager":!0,"undo-manager":!0},pollInterval:100,readOnly:!1,styles:{},theme:"base"},b.events={FORMAT_INIT:"format-init",MODULE_INIT:"module-init",POST_EVENT:"post-event",PRE_EVENT:"pre-event",SELECTION_CHANGE:"selection-change",TEXT_CHANGE:"text-change"},b.sources=f.sources,b.registerModule=function(a,c){return null!=b.modules[a]&&console.warn("Overwriting "+a+" module"),b.modules[a]=c},b.registerTheme=function(a,c){return null!=b.themes[a]&&console.warn("Overwriting "+a+" theme"),b.themes[a]=c},b.require=function(a){switch(a){case"lodash":return l;case"delta":return d;case"format":return h;case"normalizer":return i;case"dom":return m;case"document":return e;case"range":return k;default:return null}},b.prototype.destroy=function(){var a;return a=this.getHTML(),l.each(this.modules,function(a,b){return l.isFunction(a.destroy)?a.destroy():void 0}),this.editor.destroy(),this.removeAllListeners(),b.editors.splice(l.indexOf(b.editors,this),1),this.container.innerHTML=a},b.prototype.addContainer=function(a,b){var c,d;return null==b&&(b=!1),d=b?this.root:null,c=document.createElement("div"),m(c).addClass(a),this.container.insertBefore(c,d),c},b.prototype.addFormat=function(a,c){return this.editor.doc.addFormat(a,c),this.emit(b.events.FORMAT_INIT,a)},b.prototype.addModule=function(a,c){var d;if(d=b.modules[a],null==d)throw new Error("Cannot load "+a+" module. Are you sure you registered it?");return c===!0&&(c={}),c=l.defaults(c,this.theme.constructor.OPTIONS[a]||{},d.DEFAULTS||{}),this.modules[a]=new d(this,c),this.emit(b.events.MODULE_INIT,a,this.modules[a]),this.modules[a]},b.prototype.deleteText=function(a,c,e){var f,g,h;return null==e&&(e=b.sources.API),h=this._buildParams(a,c,{},e),a=h[0],c=h[1],g=h[2],e=h[3],c>a?(f=(new d).retain(a)["delete"](c-a),this.editor.applyDelta(f,e)):void 0},b.prototype.emit=function(){var a,c;return c=arguments[0],a=2<=arguments.length?q.call(arguments,1):[],b.__super__.emit.apply(this,[b.events.PRE_EVENT,c].concat(q.call(a))),b.__super__.emit.apply(this,[c].concat(q.call(a))),b.__super__.emit.apply(this,[b.events.POST_EVENT,c].concat(q.call(a)))},b.prototype.focus=function(){return this.editor.focus()},b.prototype.formatLine=function(a,b,c,d,e){var f,g,h,i,j;return i=this._buildParams(a,b,c,d,e),a=i[0],b=i[1],f=i[2],e=i[3],j=this.editor.doc.findLineAt(b),g=j[0],h=j[1],null!=g&&(b+=g.length-h),this.formatText(a,b,f,e)},b.prototype.formatText=function(a,b,c,e,f){var g,h,i;return i=this._buildParams(a,b,c,e,f),a=i[0],b=i[1],h=i[2],f=i[3],h=l.reduce(h,function(a){return function(b,c,d){var e;return e=a.editor.doc.formats[d],c&&c!==e.config["default"]||(b[d]=null),b}}(this),h),g=(new d).retain(a).retain(b-a,h),this.editor.applyDelta(g,f)},b.prototype.getBounds=function(a){return this.editor.getBounds(a)},b.prototype.getContents=function(a,b){return null==a&&(a=0),null==b&&(b=null),l.isObject(a)&&(b=a.end,a=a.start),this.editor.delta.slice(a,b)},b.prototype.getHTML=function(){return this.editor.doc.getHTML()},b.prototype.getLength=function(){return this.editor.length},b.prototype.getModule=function(a){return this.modules[a]},b.prototype.getSelection=function(){return this.editor.checkUpdate(),this.editor.selection.getRange()},b.prototype.getText=function(a,b){return null==a&&(a=0),null==b&&(b=null),l.map(this.getContents(a,b).ops,function(a){return l.isString(a.insert)?a.insert:""}).join("")},b.prototype.insertEmbed=function(a,b,c,e){var f,g,h,i;return i=this._buildParams(a,0,b,c,e),a=i[0],g=i[1],h=i[2],e=i[3],f=(new d).retain(a).insert(1,h),this.editor.applyDelta(f,e)},b.prototype.insertText=function(a,b,c,e,f){var g,h,i,j;return j=this._buildParams(a,0,c,e,f),a=j[0],h=j[1],i=j[2],f=j[3],b.length>0?(g=(new d).retain(a).insert(b,i),this.editor.applyDelta(g,f)):void 0},b.prototype.onModuleLoad=function(a,c){return this.modules[a]?c(this.modules[a]):this.on(b.events.MODULE_INIT,function(b,d){return b===a?c(d):void 0})},b.prototype.prepareFormat=function(a,c,d){var e,f;return null==d&&(d=b.sources.API),e=this.editor.doc.formats[a],null!=e&&(f=this.getSelection(),null!=f?f.isCollapsed():void 0)?e.isType(h.types.LINE)?this.formatLine(f,a,c,d):e.prepare(c):void 0},b.prototype.setContents=function(a,c){var e;return null==c&&(c=b.sources.API),a=new d(Array.isArray(a)?a.slice():a.ops.slice()),e=l.last(a.slice(a.length()-1).ops),a["delete"](this.getLength()-1),null!=e&&l.isString(e.insert)&&"\n"===l.last(e.insert)&&a["delete"](1),this.updateContents(a,c)},b.prototype.setHTML=function(a,c){return null==c&&(c=b.sources.API),a.trim()||(a="<"+m.DEFAULT_BLOCK_TAG+"><"+m.DEFAULT_BREAK_TAG+">"),this.editor.doc.setHTML(a),this.editor.checkUpdate(c)},b.prototype.setSelection=function(a,c,d){var e;return null==d&&(d=b.sources.API),l.isNumber(a)&&l.isNumber(c)?e=new k(a,c):(e=a,d=c||d),this.editor.selection.setRange(e,d)},b.prototype.setText=function(a,c){var e;return null==c&&(c=b.sources.API),e=(new d).insert(a),this.setContents(e,c)},b.prototype.updateContents=function(a,c){return null==c&&(c=b.sources.API),Array.isArray(a)&&(a={ops:a}),this.editor.applyDelta(a,c)},b.prototype._buildParams=function(){var a,c;return c=1<=arguments.length?q.call(arguments,0):[],l.isObject(c[0])&&c.splice(0,1,c[0].start,c[0].end),l.isString(c[2])&&(a={},a[c[2]]=c[3],c.splice(2,2,a)),null==c[3]&&(c[3]=b.sources.API),c},b}(g),j.registerTheme("base",a("./themes/base")),j.registerTheme("snow",a("./themes/snow")),b.exports=j},{"../package.json":7,"./core/document":8,"./core/editor":9,"./core/format":10,"./core/normalizer":13,"./lib/dom":17,"./lib/range":20,"./themes/base":32,"./themes/snow":33,eventemitter2:2,lodash:1,"rich-text/lib/delta":3}],31:[function(a,b,c){b.exports='.ql-image-tooltip{padding:10px;width:300px}.ql-image-tooltip:after{clear:both;content:"";display:table}.ql-image-tooltip a{border:1px solid #000;box-sizing:border-box;display:inline-block;float:left;padding:5px;text-align:center;width:50%}.ql-image-tooltip img{bottom:0;left:0;margin:auto;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.ql-image-tooltip .input{box-sizing:border-box;width:100%}.ql-image-tooltip .preview{margin:10px 0;position:relative;border:1px dashed #000;height:200px}.ql-image-tooltip .preview span{display:inline-block;position:absolute;text-align:center;top:40%;width:100%}.ql-link-tooltip{padding:5px 10px}.ql-link-tooltip input.input{width:170px}.ql-link-tooltip a.done,.ql-link-tooltip input.input{display:none}.ql-link-tooltip a.change{margin-right:4px}.ql-link-tooltip.editing a.done,.ql-link-tooltip.editing input.input{display:inline-block}.ql-link-tooltip.editing a.change,.ql-link-tooltip.editing a.remove,.ql-link-tooltip.editing a.url{display:none}.ql-multi-cursor{position:absolute;left:0;top:0;z-index:1000}.ql-multi-cursor .cursor{margin-left:-1px;position:absolute}.ql-multi-cursor .cursor-flag{bottom:100%;position:absolute;white-space:nowrap}.ql-multi-cursor .cursor-name{display:inline-block;color:#fff;padding:2px 8px}.ql-multi-cursor .cursor-caret{height:100%;position:absolute;width:2px}.ql-multi-cursor .cursor.hidden .cursor-flag{display:none}.ql-multi-cursor .cursor.top .cursor-flag{bottom:auto;top:100%}.ql-multi-cursor .cursor.right .cursor-flag{right:-2px}.ql-paste-manager{left:-100000px;position:absolute;top:50%}.ql-toolbar{box-sizing:border-box}.ql-tooltip{background-color:#fff;border:1px solid #000;box-sizing:border-box;position:absolute;top:0;white-space:nowrap;z-index:2000}.ql-tooltip a{cursor:pointer;text-decoration:none}.ql-container{box-sizing:border-box;cursor:text;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;line-height:1.42;margin:0;overflow-x:hidden;overflow-y:auto;padding:12px 15px;position:relative}.ql-editor{box-sizing:border-box;min-height:100%;outline:0;tab-size:4;white-space:pre-wrap}.ql-editor div{margin:0;padding:0}.ql-editor a{text-decoration:underline}.ql-editor b{font-weight:700}.ql-editor i{font-style:italic}.ql-editor s{text-decoration:line-through}.ql-editor u{text-decoration:underline}.ql-editor a,.ql-editor b,.ql-editor i,.ql-editor s,.ql-editor span,.ql-editor u{background-color:inherit}.ql-editor img{max-width:100%}.ql-editor blockquote,.ql-editor ol,.ql-editor ul{margin:0 0 0 2em;padding:0}.ql-editor ol{list-style-type:decimal}.ql-editor ul{list-style-type:disc}.ql-editor.ql-ie-10 br,.ql-editor.ql-ie-9 br{display:none}'},{}],32:[function(a,b,c){var d,e,f,g;e=a("lodash"),g=a("../../lib/dom"),f=a("./base.styl"),d=function(){function a(b,c){var d;this.quill=b,this.options=c,g(this.quill.container).addClass("ql-container"),this.options.styles&&this.addStyles(f+a.objToCss(this.options.styles)),g.isIE(10)&&(d=g.isIE(9)?"9":"10",g(this.quill.root).addClass("ql-ie-"+d))}return a.OPTIONS={},a.objToCss=function(a){return e.map(a,function(a,b){var c;return c=e.map(a,function(a,b){return b+": "+a+";"}).join(" "),b+" { "+c+" }"}).join("\n")},a.prototype.addStyles=function(b){var c;return e.isObject(b)&&(b=a.objToCss(b)),c=document.createElement("style"),c.type="text/css",c.appendChild(document.createTextNode(b)),document.head.appendChild(c)},a}(),b.exports=d},{"../../lib/dom":17,"./base.styl":31,lodash:1}],33:[function(a,b,c){var d,e,f,g,h,i,j=function(a,b){function c(){this.constructor=a}for(var d in b)k.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},k={}.hasOwnProperty;h=a("lodash"),e=a("../../lib/color-picker"),d=a("../base"),i=a("../../lib/dom"),f=a("../../lib/picker"),g=function(a){function b(a,c){this.quill=a,this.options=c,b.__super__.constructor.apply(this,arguments),i(this.quill.container).addClass("ql-snow"),this.pickers=[],this.quill.on(this.quill.constructor.events.SELECTION_CHANGE,function(a){return function(b){return null!=b?h.invoke(a.pickers,"close"):void 0}}(this)),this.quill.onModuleLoad("multi-cursor",h.bind(this.extendMultiCursor,this)),this.quill.onModuleLoad("toolbar",h.bind(this.extendToolbar,this))}return j(b,a),b.COLORS=["#000000","#e60000","#ff9900","#ffff00","#008A00","#0066cc","#9933ff","#ffffff","#facccc","#ffebcc","#ffffcc","#cce8cc","#cce0f5","#ebd6ff","#bbbbbb","#f06666","#ffc266","#ffff66","#66b966","#66a3e0","#c285ff","#888888","#a10000","#b26b00","#b2b200","#006100","#0047b2","#6b24b2","#444444","#5c0000","#663d00","#666600","#003700","#002966","#3d1466"],b.OPTIONS={"multi-cursor":{template:' '}},b.prototype.extendMultiCursor=function(a){return a.on(a.constructor.events.CURSOR_ADDED,function(a){var b,c;return b=a.elem.querySelector(".cursor-triangle.bottom"),c=a.elem.querySelector(".cursor-triangle.top"),b.style.borderTopColor=c.style.borderBottomColor=a.color})},b.prototype.extendToolbar=function(a){return i(a.container).addClass("ql-snow"),h.each(["color","background","font","size","align"],function(b){return function(c){var d,g;if(g=a.container.querySelector(".ql-"+c),null!=g){switch(c){case"font":case"size":case"align":d=new f(g);break;case"color":case"background":d=new e(g),h.each(d.container.querySelectorAll(".ql-picker-item"),function(a,b){return 7>b?i(a).addClass("ql-primary-color"):void 0})}return null!=d?b.pickers.push(d):void 0}}}(this)),h.each(i(a.container).textNodes(),function(a){return 0===i(a).text().trim().length?i(a).remove():void 0})},b}(d),b.exports=g},{"../../lib/color-picker":16,"../../lib/dom":17,"../../lib/picker":19,"../base":32,lodash:1}]},{},[15])(15)}); \ No newline at end of file diff --git a/Examples/bower_components/quill/dist/quill.snow.css b/Examples/bower_components/quill/dist/quill.snow.css new file mode 100644 index 00000000..8f8e7da1 --- /dev/null +++ b/Examples/bower_components/quill/dist/quill.snow.css @@ -0,0 +1,917 @@ +/*! Quill Editor v0.20.1 + * https://quilljs.com/ + * Copyright (c) 2014, Jason Chen + * Copyright (c) 2013, salesforce.com + */ +.ql-image-tooltip { + padding: 10px; + width: 300px; +} +.ql-image-tooltip:after { + clear: both; + content: ""; + display: table; +} +.ql-image-tooltip a { + border: 1px solid #000; + box-sizing: border-box; + display: inline-block; + float: left; + padding: 5px; + text-align: center; + width: 50%; +} +.ql-image-tooltip img { + bottom: 0; + left: 0; + margin: auto; + max-height: 100%; + max-width: 100%; + position: absolute; + right: 0; + top: 0; +} +.ql-image-tooltip .input { + box-sizing: border-box; + width: 100%; +} +.ql-image-tooltip .preview { + margin: 10px 0px; + position: relative; + border: 1px dashed #000; + height: 200px; +} +.ql-image-tooltip .preview span { + display: inline-block; + position: absolute; + text-align: center; + top: 40%; + width: 100%; +} +.ql-link-tooltip { + padding: 5px 10px; +} +.ql-link-tooltip input.input { + width: 170px; +} +.ql-link-tooltip input.input, +.ql-link-tooltip a.done { + display: none; +} +.ql-link-tooltip a.change { + margin-right: 4px; +} +.ql-link-tooltip.editing input.input, +.ql-link-tooltip.editing a.done { + display: inline-block; +} +.ql-link-tooltip.editing a.url, +.ql-link-tooltip.editing a.change, +.ql-link-tooltip.editing a.remove { + display: none; +} +.ql-multi-cursor { + position: absolute; + left: 0; + top: 0; + z-index: 1000; +} +.ql-multi-cursor .cursor { + margin-left: -1px; + position: absolute; +} +.ql-multi-cursor .cursor-flag { + bottom: 100%; + position: absolute; + white-space: nowrap; +} +.ql-multi-cursor .cursor-name { + display: inline-block; + color: #fff; + padding: 2px 8px; +} +.ql-multi-cursor .cursor-caret { + height: 100%; + position: absolute; + width: 2px; +} +.ql-multi-cursor .cursor.hidden .cursor-flag { + display: none; +} +.ql-multi-cursor .cursor.top .cursor-flag { + bottom: auto; + top: 100%; +} +.ql-multi-cursor .cursor.right .cursor-flag { + right: -2px; +} +.ql-paste-manager { + left: -100000px; + position: absolute; + top: 50%; +} +.ql-toolbar { + box-sizing: border-box; +} +.ql-tooltip { + background-color: #fff; + border: 1px solid #000; + box-sizing: border-box; + position: absolute; + top: 0px; + white-space: nowrap; + z-index: 2000; +} +.ql-tooltip a { + cursor: pointer; + text-decoration: none; +} +.ql-container { + box-sizing: border-box; + cursor: text; + font-family: Helvetica, 'Arial', sans-serif; + font-size: 13px; + height: 100%; + line-height: 1.42; + margin: 0px; + overflow-x: hidden; + overflow-y: auto; + padding: 12px 15px; + position: relative; +} +.ql-editor { + box-sizing: border-box; + min-height: 100%; + outline: none; + tab-size: 4; + white-space: pre-wrap; +} +.ql-editor div { + margin: 0; + padding: 0; +} +.ql-editor a { + text-decoration: underline; +} +.ql-editor b { + font-weight: bold; +} +.ql-editor i { + font-style: italic; +} +.ql-editor s { + text-decoration: line-through; +} +.ql-editor u { + text-decoration: underline; +} +.ql-editor a, +.ql-editor b, +.ql-editor i, +.ql-editor s, +.ql-editor u, +.ql-editor span { + background-color: inherit; +} +.ql-editor img { + max-width: 100%; +} +.ql-editor blockquote, +.ql-editor ol, +.ql-editor ul { + margin: 0 0 0 2em; + padding: 0; +} +.ql-editor ol { + list-style-type: decimal; +} +.ql-editor ul { + list-style-type: disc; +} +.ql-editor.ql-ie-9 br, +.ql-editor.ql-ie-10 br { + display: none; +} +.ql-snow .ql-image-tooltip a { + border: 1px solid #06c; +} +.ql-snow .ql-image-tooltip a.insert { + background-color: #06c; + color: #fff; +} +.ql-snow .ql-image-tooltip .preview { + border-color: #ccc; + color: #ccc; +} +.ql-snow .ql-link-tooltip a, +.ql-snow .ql-link-tooltip span { + line-height: 25px; +} +.ql-snow .ql-multi-cursor .cursor-name { + border-radius: 4px; + font-size: 11px; + font-family: Arial; + margin-left: -50%; + padding: 4px 10px; +} +.ql-snow .ql-multi-cursor .cursor-triangle { + border-left: 4px solid transparent; + border-right: 4px solid transparent; + height: 0px; + margin-left: -3px; + width: 0px; +} +.ql-snow .ql-multi-cursor .cursor.left .cursor-name { + margin-left: -8px; +} +.ql-snow .ql-multi-cursor .cursor.right .cursor-flag { + right: auto; +} +.ql-snow .ql-multi-cursor .cursor.right .cursor-name { + margin-left: -100%; + margin-right: -8px; +} +.ql-snow .ql-multi-cursor .cursor-triangle.bottom { + border-top: 4px solid transparent; + display: block; + margin-bottom: -1px; +} +.ql-snow .ql-multi-cursor .cursor-triangle.top { + border-bottom: 4px solid transparent; + display: none; + margin-top: -1px; +} +.ql-snow .ql-multi-cursor .cursor.top .cursor-triangle.bottom { + display: none; +} +.ql-snow .ql-multi-cursor .cursor.top .cursor-triangle.top { + display: block; +} +.ql-snow.ql-toolbar { + box-sizing: border-box; + padding: 8px; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.ql-snow.ql-toolbar .ql-format-group { + display: inline-block; + margin-right: 15px; + vertical-align: middle; +} +.ql-snow.ql-toolbar .ql-format-separator { + box-sizing: border-box; + background-color: #ddd; + display: inline-block; + height: 14px; + margin-left: 4px; + margin-right: 4px; + vertical-align: middle; + width: 1px; +} +.ql-snow.ql-toolbar .ql-format-button { + box-sizing: border-box; + display: inline-block; + height: 24px; + line-height: 24px; + vertical-align: middle; + background-position: center center; + background-repeat: no-repeat; + background-size: 18px 18px; + box-sizing: border-box; + cursor: pointer; + text-align: center; + width: 24px; +} +.ql-snow.ql-toolbar .ql-picker { + box-sizing: border-box; + color: #444; + display: inline-block; + font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; + font-size: 14px; + font-weight: 500; + position: relative; +} +.ql-snow.ql-toolbar .ql-picker .ql-picker-label { + box-sizing: border-box; + display: inline-block; + height: 24px; + line-height: 24px; + vertical-align: middle; + background-color: #fff; + background-position: right center; + background-repeat: no-repeat; + background-size: 18px 18px; + border: 1px solid transparent; + cursor: pointer; + position: relative; + width: 100%; +} +.ql-snow.ql-toolbar .ql-picker .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label:hover { + color: #06c; +} +.ql-snow.ql-toolbar .ql-picker .ql-picker-options { + background-color: #fff; + border: 1px solid transparent; + box-sizing: border-box; + display: none; + padding: 4px 8px; + position: absolute; + width: 100%; +} +.ql-snow.ql-toolbar .ql-picker .ql-picker-options .ql-picker-item { + background-position: center center; + background-repeat: no-repeat; + background-size: 18px 18px; + box-sizing: border-box; + cursor: pointer; + display: block; + padding-bottom: 5px; + padding-top: 5px; +} +.ql-snow.ql-toolbar .ql-picker .ql-picker-options .ql-picker-item.ql-selected, +.ql-snow.ql-toolbar .ql-picker .ql-picker-options .ql-picker-item:hover { + color: #06c; +} +.ql-snow.ql-toolbar .ql-picker.ql-expanded .ql-picker-label { + border-color: #ccc; + color: #ccc; + z-index: 2; +} +.ql-snow.ql-toolbar .ql-picker.ql-expanded .ql-picker-options { + border-color: #ccc; + box-shadow: rgba(0,0,0,0.2) 0 2px 8px; + display: block; + margin-top: -1px; + z-index: 1; +} +.ql-snow.ql-toolbar .ql-picker.ql-color-picker .ql-picker-label { + background-position: center center; + width: 28px; +} +.ql-snow.ql-toolbar .ql-picker.ql-color-picker .ql-picker-options { + padding: 5px; + width: 152px; +} +.ql-snow.ql-toolbar .ql-picker.ql-color-picker .ql-picker-options .ql-picker-item { + border: 1px solid transparent; + float: left; + height: 16px; + margin: 2px; + padding: 0px; + width: 16px; +} +.ql-snow.ql-toolbar .ql-picker.ql-color-picker .ql-picker-options .ql-picker-item.ql-primary-color { + margin-bottom: 8px; +} +.ql-snow.ql-toolbar .ql-picker.ql-color-picker .ql-picker-options .ql-picker-item.ql-selected, +.ql-snow.ql-toolbar .ql-picker.ql-color-picker .ql-picker-options .ql-picker-item:hover { + border-color: #000; +} +.ql-snow.ql-toolbar .ql-picker.ql-font { + width: 105px; +} +.ql-snow.ql-toolbar .ql-picker.ql-size { + width: 80px; +} +.ql-snow.ql-toolbar .ql-picker.ql-font .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker.ql-size .ql-picker-label { + padding-left: 8px; + padding-right: 8px; +} +.ql-snow.ql-toolbar .ql-picker.ql-align .ql-picker-label { + background-position: center center; + width: 28px; +} +.ql-snow.ql-toolbar .ql-picker.ql-align .ql-picker-item { + box-sizing: border-box; + display: inline-block; + height: 24px; + line-height: 24px; + vertical-align: middle; + padding: 0px; + width: 28px; +} +.ql-snow.ql-toolbar .ql-picker.ql-align .ql-picker-options { + padding: 4px 0px; +} +.ql-snow.ql-toolbar .ql-picker .ql-picker-label { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAKlBMVEUAAABJSUlAQEBERERFRUVERERERERERERERERFRUVEREREREREREREREQJcW6NAAAADXRSTlMAFRzExcbLzM/Q0dLbKbcyLwAAADVJREFUCNdjYCAeMKYJQFnSdzdCWbl3r0NZvnev4tFre/cKlNV79yaUpXP3EJTFtEqBBHcAAHyoDQk0vM/lAAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-picker.ql-expanded .ql-picker-label { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAdElEQVR42mP4//8/VfBINGjVqlUMhw4dEj148OBpEAaxQWKkGgQz5BIQ/4fiSyAxkg2CuuQ/Gj5DjkFHsRh0jJwwwooHzCCQ145g8dpRcgw6j8WgCyQbtH//fhmgxttIhtwGiZETRjDDLoIwiA0UG820FGAA5b25+qRqGXcAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-picker.ql-active:not(.ql-expanded) .ql-picker-label, +.ql-snow.ql-toolbar:not(.ios) .ql-picker:not(.ql-expanded) .ql-picker-label:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAKlBMVEUAAAAAYc4AZMgAZcwAZs0AZs0AZs0AZ8wAZswAZs0AZswAZswAZswAZsx12LPhAAAADXRSTlMAFRzExcbLzM/Q0dLbKbcyLwAAADVJREFUCNdjYCAeMKYJQFnSdzdCWbl3r0NZvnev4tFre/cKlNV79yaUpXP3EJTFtEqBBHcAAHyoDQk0vM/lAAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-bold, +.ql-snow.ql-toolbar .ql-picker.ql-bold .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=bold], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=bold] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAYFBMVEUAAACAgIBAQEA5OTlAQEBERERAQEBERERERERERERDQ0NERERERERERERDQ0NERERERERFRUVERERERERFRUVERERERERERERERERERERERERERERERERERERERERERESN6WzHAAAAH3RSTlMAAggJDA8cQEtTWHF/i4yTpau+xMXX3O7v8/f6+/z+qN9w2AAAAFZJREFUeNqlzMcSgCAMRVEsYO+9vv//S9FhNIYld5HFmSTCqQ66dazkRzA1lPSQGRZGIsDMKMxRW7+2yCIcyf/QUyUGSnc+dkaqoFumM32pf2BqY+HUBfQaCPgVIBc1AAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-bold.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-bold .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=bold].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=bold].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-bold:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-bold .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=bold]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=bold]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAYFBMVEUAAAAAgP8AYL8AccYAatUAZswAZMgAZMsAZswAZcsAZcsAZssAZssAZ80AZswAZs0AZswAZ8wAZswAZcwAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsxCU9XcAAAAH3RSTlMAAggJDA8cQEtTWHF/i4yTpau+xMXX3O7v8/f6+/z+qN9w2AAAAFZJREFUeNqlzMcSgCAMRVEsYO+9vv//S9FhNIYld5HFmSTCqQ66dazkRzA1lPSQGRZGIsDMKMxRW7+2yCIcyf/QUyUGSnc+dkaqoFumM32pf2BqY+HUBfQaCPgVIBc1AAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-italic, +.ql-snow.ql-toolbar .ql-picker.ql-italic .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=italic], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=italic] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAi0lEQVR42mMYvoARl4SLi0sNkGoAYmY0qf+MjIztu3fvrkYWZGLADZhB8pS4CN1lQUBqLRDvAQJXHMqIstEISp8BEZQYZAIi/v//f5ZSg0xBBCMj4ymyDQKGjxKQEgLiV8DweUS2QUBXGEOZp0EEJV4zgdJnKDLo379/JsS6iJHSFA0DTDhT9CiAAQBbWyIY/pd4rQAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-italic.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-italic .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=italic].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=italic].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-italic:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-italic .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=italic]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=italic]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAk0lEQVR42u3SsQ3CMBBA0X/2BozACMQswg4EMQMUdOyQVdggdpagZAc4ihjJjYmU66K8xpZsfdnSsVxCzTFdEW6AB0oKcqdrLhQcNaK+PLc79QfapLTDgz8cU9Tv8ibZQqIBgI8OxhexH29KPz90jltgA7zownN+6C0Nowhg+JqEvCZbSDSHNDJBLBNdctWJXv18Ad5dJL0jVfDhAAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-underline, +.ql-snow.ql-toolbar .ql-picker.ql-underline .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=underline], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=underline] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAM1BMVEUAAABLS0tFRUVDQ0NERERDQ0NFRUVFRUVERERDQ0NERERFRUVERERERERERERERERERESvCHKbAAAAEHRSTlMAERpMbW6Bgry9xMXh5PP51ZZfkwAAAEdJREFUeNq9yEEKgDAMRNHERDWq6dz/tFLBQUC6KfRtPnzpsh/sC2AHrcRUo0iuDXONI7gMxVW9wIQWPFb5sMgMk5YTdMmvGw2DA8yS9di7AAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-underline.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-underline .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=underline].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=underline].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-underline:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-underline .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=underline]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=underline]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAM1BMVEUAAAAAadIAYs4AZc0AZcwAZswAZ84AZswAZs0AZ8wAZcwAZs0AZswAZswAZswAZswAZsycBlETAAAAEHRSTlMAERpMbW6Bgry9xMXh5PP51ZZfkwAAAEdJREFUeNq9yEEKgDAMRNHERDWq6dz/tFLBQUC6KfRtPnzpsh/sC2AHrcRUo0iuDXONI7gMxVW9wIQWPFb5sMgMk5YTdMmvGw2DA8yS9di7AAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-strike, +.ql-snow.ql-toolbar .ql-picker.ql-strike .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=strike], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=strike] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAn1BMVEUAAAAAAACAgIBAQEA7OztAQEBLS0tHR0dAQEBJSUlGRkZERERCQkJERERDQ0NERERERERDQ0NFRUVERERERERERERERERERERFRUVERERERERERERFRUVDQ0NFRUVERERFRUVFRUVERERFRUVFRUVFRUVERERFRUVFRUVERERERERERERERERERERERERERERERERERERERERERERERERfrjwTAAAANHRSTlMAAQIMDRAREhQVKCk6PEhLT1xkZWZ4e4CCg4SIiZucoaersLK2wcTFydLX2ODi5err8fX3BKZfrQAAAH5JREFUGBmlwOEWgTAYBuC3isgMxCYAmwRh++7/2qRzttP/HnQTZjdjilkALzhR4wBvQiaLk8WXOJwlHVHjYgxnSmbeR0swGEkpxWZ3vt7fL/w9P4/ist+KdZ7zYYiWiCnScFYiRq1HFo4mxaKIKdJw0ooaVQovkaW1pUzQyQ86Agx4yKmWPAAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-strike.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-strike .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=strike].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=strike].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-strike:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-strike .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=strike]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=strike]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAolBMVEUAAAAAAP8AgP8AatUAYsQAYM8AadIAY8YAZswAYc4AZswAZM0AZcoAZswAZ8oAZswAZMsAZ8oAZswAZcoAZ8sAZswAZssAZssAZs0AZswAZ8wAZs0AZ8wAZs0AZswAZ8wAZ8wAZs0AZ8wAZ8wAZs0AZs0AZs0AZcwAZs0AZcwAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsyiCU+yAAAANXRSTlMAAQIMDRAREhQVKCk6PEhLT1xkZWZ4e4CAgoOEiImbnKGnq7CytsHExcnS19jg4uXq6/H190B1i7AAAAB/SURBVBgZpcDhFoEwGAbgt4pIBmImAJsEYfvu/9ZU52yn/z3oxk/vWuczD453psYRzoR0GkaLHzFYSzqhwvgY1pT0vI8WbzASQvDt/nJ7fN6ovb7P/HrYrTdZxoY+WoJEkoK14iEqPTKwFMkkCBJJClZcUqOM4USiMKYQETr5A2SVDLpJv6ZtAAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-link, +.ql-snow.ql-toolbar .ql-picker.ql-link .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=link], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=link] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAllBMVEUAAAD///9VVVVJSUk5OTlAQEBHR0dFRUVCQkJHR0dBQUFCQkJGRkZDQ0NGRkZFRUVCQkJDQ0NERERDQ0NERERFRUVERERFRUVDQ0NERERFRUVERERERERFRUVERERERERERERERERFRUVERERFRUVFRUVERERERERERERERERERERERERERERERERERERERERERERERETx5KUoAAAAMXRSTlMAAAYHCQwZGiMkJzIzOUJOYGNlfoCJl5ibnaCxtLa8xsfIycrQ1OHi5uvs7e/19vn8NGTYeAAAAJdJREFUeNqN0McOgkAARdGnFJWiKGBhEEFpSn3//3OGjMmQ6MK7PMuLxVe/CXDTPl5DJmk3cOTTmZE7MDQES11RyhBY5vQU9aOB2z3gWVFMsXywYx3t9Q9tXsyDjlOVLQlOyanOL1ibkqB7l5odM01QSJqK6GdXmGwUHVhowImJIr2iMI9sLUWwa5LtFjPCSjSJBUl//HoDlmQPy0DFuCkAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-link.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-link .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=link].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=link].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-link:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-link .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=link]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=link]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAmVBMVEUAAAD///8AVdUAbdsAccYAatUAZswAYs4AZswAY80AacsAZswAZM0AZ8kAZM0AZcsAZcoAZMsAZcoAZcoAZssAZs0AZs0AZ8wAZs0AZswAZs0AZswAZs0AZswAZs0AZs0AZs0AZ8wAZswAZcwAZs0AZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsy/jsjWAAAAMnRSTlMAAAYHCQwZGiMkJzIzOUJOYGNlfoCAiZeYm52gsbS2vMbHyMnK0NTh4ubr7O3v9fb5/BM/koAAAACXSURBVHjajdDbEoFQAIXhpROqiAjaSdGJSq33fzjTbDO7GS78l9/lj9lXvwnw0le8gEzSuufAhzshr2doCpaGopQhoOX0Fb0GE9fbnidFMYV2Z8c62hgfWj6Z7zqOVY4kuCXHuqBgbUmC4Z9rdsx0QSFpLGKQXWCxUbRloQNHJoqMisI6sLUVwalJtitMCHPRJDYk/fHrDdIHECSPJag6AAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-image, +.ql-snow.ql-toolbar .ql-picker.ql-image .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=image], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=image] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAElBMVEUAAABERERERERFRUVEREREREQbmEZBAAAABXRSTlMAeMTFxj7M9NAAAABBSURBVAjXY2DAD1RDQSAYyAqFABALLANmMRnAWMwODIIMUFnGUAEIS1A0NADMYgTqhLBY4SyEKXCTTcGMEAJuAgBa9RKl6Fva+wAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-image.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-image .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=image].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=image].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-image:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-image .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=image]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=image]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAElBMVEUAAAAAZswAZcwAZs0AZs0AZszYB6XUAAAABXRSTlMAeMTFxj7M9NAAAABBSURBVAjXY2DAD1RDQSAYyAqFABALLANmMRnAWMwODIIMUFnGUAEIS1A0NADMYgTqhLBY4SyEKXCTTcGMEAJuAgBa9RKl6Fva+wAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-list, +.ql-snow.ql-toolbar .ql-picker.ql-list .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=list], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=list] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAS1BMVEUAAABCQkJFRUVGRkZFRUVCQkJFRUVDQ0NFRUVFRUVFRUVERERERERERERERERFRUVERERERERERERERERERERERERERERERERERET32eciAAAAGHRSTlMAMjRCQ0lOfYKQlJmaocTFxuHi5OXm9falfyKhAAAATElEQVR42mMgFnCKYIpJMDDwSUABP1yIHyYkABYRlBAmwngucV50IXZGIXTjmQTZ0I0XIcp4DjEedCFWFlF041mZRdCN5xDjZiAdAACXwgbrzvG+ZgAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-list.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-list .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=list].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=list].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-list:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-list .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=list]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=list]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAS1BMVEUAAAAAZswAZ8kAZM0AZ8oAZcsAZcsAZswAZswAZ80AZs0AZs0AZ80AZ8wAZcwAZs0AZs0AZswAZswAZswAZswAZswAZswAZswAZswCB3gJAAAAGHRSTlMAMjRCQ0lOfYKQlJmaocTFxuHi5OXm9falfyKhAAAATElEQVR42mMgFnCKYIpJMDDwSUABP1yIHyYkABYRlBAmwngucV50IXZGIXTjmQTZ0I0XIcp4DjEedCFWFlF041mZRdCN5xDjZiAdAACXwgbrzvG+ZgAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-bullet, +.ql-snow.ql-toolbar .ql-picker.ql-bullet .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=bullet], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=bullet] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAABERERFRUVERERERETRGyWnAAAABHRSTlMAxMXG4b8ciAAAABxJREFUCNdjYMAPhBhdgMAJyFJmArGcGRgGXAcA/t0ImAOSO9kAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-bullet.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-bullet .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=bullet].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=bullet].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-bullet:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-bullet .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=bullet]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=bullet]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAAAAZcwAZs0AZs0AZsyEYJIjAAAABHRSTlMAxMXG4b8ciAAAABxJREFUCNdjYMAPhBhdgMAJyFJmArGcGRgGXAcA/t0ImAOSO9kAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-authorship, +.ql-snow.ql-toolbar .ql-picker.ql-authorship .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=authorship], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=authorship] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAARVBMVEUAAABFRUVFRUUAAAAAAABERERDQ0NEREQAAABERERERERERERERERERERFRUVERERERERERERERERERERERERERERERERVeSBUAAAAFnRSTlMAMDtOT1JfYmassMfN09Ta6vD4+fz9w8DTTwAAAExJREFUGBmVwEkSgCAMBMBRQUEU4zb/f6oFF5KbNLp4EQ8rkxnWQ76whBRYkYwwxo08ZijDzWJBs7La0ZysLjSJVUKXKSgOhQuKw08fJOYE1SddZQoAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-authorship.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-authorship .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=authorship].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=authorship].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-authorship:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-authorship .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=authorship]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=authorship]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAARVBMVEUAAAAAZcoAaMsAZc4AZ8sAZ8oAZswAZcsAZ80AZs0AZ8wAZ8wAZswAZswAZswAZs0AZswAZswAZswAZswAZswAZswAZszAoUIuAAAAFnRSTlMAMDtOT1JfYmassMfN09Ta6vD4+fz9w8DTTwAAAExJREFUGBmVwEkSgCAMBMBRQUEU4zb/f6oFF5KbNLp4EQ8rkxnWQ76whBRYkYwwxo08ZijDzWJBs7La0ZysLjSJVUKXKSgOhQuKw08fJOYE1SddZQoAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-color, +.ql-snow.ql-toolbar .ql-picker.ql-color .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=color], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=color] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAgVBMVEUAAAAAAACAgIBAQEBVVVVDQ0NGRkZGRkZFRUVERERDQ0NDQ0NDQ0NCQkIAAABFRUUAAABDQ0NEREREREREREQAAABDQ0NDQ0NERERFRUVERERERERERERDQ0NERERERERFRUVFRUVERERERERERERERERERERERERERERERERERERLPkdWAAAAKnRSTlMAAQIEBhMWISUtLkVMTU5OT1BTVlpmeX6OkJmdvL3GztTj5/Hy8/b3/f5utmv0AAAAX0lEQVR42pXIRQ6AQABDUdzd3bX3PyCWwAwr+Is2ecyvuKriXmQD5otKoKBFQz+sKkU5khQZKdK8yMoyiQTFOIseEbqLWv6mAPW+bAPvJmN0j/N7nfmTFRI5Jzk0fWwD4sYJPnqIyzwAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-color.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-color .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=color].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=color].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-color:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-color .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=color]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=color]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAgVBMVEUAAAAAAP8AgP8AgL8AVdUAa8kAaNEAZMkAZ8gAZswAZM0AZMsAZc0AZ8oAZcsAZc4AZ8sAZswAZcsAZc0AZswAZ80AZcoAZcoAZs0AZ80AZs0AZs0AZs0AZ8wAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsy3JBcuAAAAKnRSTlMAAQIEBhMWISUtLkVMTU5OT1BTVlpmeX6OkJmdvL3GztTj5/Hy8/b3/f5utmv0AAAAX0lEQVR42pXIRQ6AQABDUdzd3bX3PyCWwAwr+Is2ecyvuKriXmQB5otKoKBFQz+sKkU5khQZKdK8yMoyiQTFOIseEbqLWv6mAPW+bAPvJmN0j/N7nfmTHRI5Jzk0fWwD4foJPqgJbeoAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-background, +.ql-snow.ql-toolbar .ql-picker.ql-background .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=background], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=background] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAnFBMVEUAAAAAAACAgIBAQEAAAABVVVUAAAAAAAAAAABDQ0MAAABGRkZGRkYAAABFRUVERERDQ0MAAAAAAAAAAAAAAABDQ0MAAABDQ0MAAABCQkJFRUVDQ0NERERERERERERDQ0NDQ0NERERFRUVERERERERERERDQ0NERERERERFRUVFRUVERERERERERERERERERERERERERERERERERETMTXVbAAAAM3RSTlMAAQIEBgYHCBMTFBYhIyUtLjE2N0JFS0xNTU5QU1ZaeX6OkJmdvL3GztTj5/Hy8/b3/f5Qd6EEAAAAf0lEQVR42o2PRw6DQBRDHVJISCUhvTd69/3vhgT6MLPDmoX15KfRR++c6mdKgVIOTRFoeJ6hE+tCnjXRgUv+oc02jJNyrYk/vj/8jhRxnheLVZHNupn1Yp3nVIgzjhoUDlvxQR/AIOBtKbNjerUB+x7vhZjARPkLyslbYIe+qQDqMQxGJwkBGwAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-background.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-background .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=background].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=background].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-background:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-background .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=background]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=background]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAllBMVEUAAAAAAP8AgP8AgL8AVdUAbbYAYL8Aa8kAZswAaNEAZMkAZswAZ8gAZswAZM0AaMsAaNAAZswAZM0AZMsAZswAZc0AZ8oAZ80AZcsAZswAZcsAZc0AZswAZcoAZcoAZs0AZ80AZs0AZs0AZs0AZ8wAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsy8dW5vAAAAMXRSTlMAAQIEBgcIExQWISMlLS4xNjdCRUtMTU1OUFNWWnl+jpCZnby9xs7U4+fx8vP29/3+dqGBzgAAAH5JREFUeNqNj0cOg0AUQx1CgFQS0nujd9//ckigDzM7rFlYT34afYzOuX2WFCjl0BWBRhAYOnEu5EkTPfjkH9pswzSr15r44/vDr6mI87JarKrCHmbOi22ethDPTDoUT3vxwRDAJOJtKbNjfnUB957uhVjATPkLyslbYIexaQB/ngudkm14XQAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-left, +.ql-snow.ql-toolbar .ql-picker.ql-left .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=left], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=left] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAABERERFRUVERERERETRGyWnAAAABHRSTlMAxMXG4b8ciAAAAClJREFUCNdjYMAPRFxcnCAsFRcXZwYiAFCHC0STCpjlTJwOJwaYDoIaAKIACBBRNsu4AAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-left.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-left .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=left].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=left].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-left:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-left .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=left]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=left]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAAAAZcwAZs0AZs0AZsyEYJIjAAAABHRSTlMAxMXG4b8ciAAAAClJREFUCNdjYMAPRFxcnCAsFRcXZwYiAFCHC0STCpjlTJwOJwaYDoIaAKIACBBRNsu4AAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-right, +.ql-snow.ql-toolbar .ql-picker.ql-right .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=right], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=right] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAABERERFRUVERERERETRGyWnAAAABHRSTlMAxMXG4b8ciAAAAChJREFUCNdjYCAIRFxcnCAsFRcXZ2KUu0B0qIBZzgzEaXFigGkhpAMAmbwIEMJ9k/cAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-right.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-right .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=right].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=right].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-right:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-right .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=right]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=right]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAAAAZcwAZs0AZs0AZsyEYJIjAAAABHRSTlMAxMXG4b8ciAAAAChJREFUCNdjYCAIRFxcnCAsFRcXZ2KUu0B0qIBZzgzEaXFigGkhpAMAmbwIEMJ9k/cAAAAASUVORK5CYII="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-center, +.ql-snow.ql-toolbar .ql-picker.ql-center .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=center], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=center] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAABERERFRUVERERERETRGyWnAAAABHRSTlMAxMXG4b8ciAAAAC1JREFUCNdjYCAAGF1cXBTALCYgy4CBIBBxAQEnIEsFzHJmIMYKiCVMYBYhSwCyqQhMfft6AQAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-center.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-center .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=center].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=center].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-center:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-center .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=center]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=center]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAAAAZcwAZs0AZs0AZsyEYJIjAAAABHRSTlMAxMXG4b8ciAAAAC1JREFUCNdjYCAAGF1cXBTALCYgy4CBIBBxAQEnIEsFzHJmIMYKiCVMYBYhSwCyqQhMfft6AQAAAABJRU5ErkJggg=="); +} +.ql-snow.ql-toolbar .ql-format-button.ql-justify, +.ql-snow.ql-toolbar .ql-picker.ql-justify .ql-picker-label, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=justify], +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=justify] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAD1BMVEUAAABERERFRUVERERERETRGyWnAAAABHRSTlMAxMXG4b8ciAAAABpJREFUCNdjYMAPRFxAwAnIUgGznBkYBlwHAJGzCjB/C3owAAAAAElFTkSuQmCC"); +} +.ql-snow.ql-toolbar .ql-format-button.ql-justify.ql-active, +.ql-snow.ql-toolbar .ql-picker.ql-justify .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=justify].ql-active, +.ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=justify].ql-selected, +.ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-justify:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-justify .ql-picker-label:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=justify]:hover, +.ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=justify]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAALklEQVR42mMYvoARzko9cwTIsyZR+zGGWcZgPUwIMUZGShwyGtijgT0a2EMMAADESwwWta/i5QAAAABJRU5ErkJggg=="); +} +@media (-webkit-min-device-pixel-ratio: 2) { + .ql-snow.ql-toolbar .ql-picker .ql-picker-label { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAIVBMVEUAAABCQkJDQ0NDQ0NERERERERERERERERERERERERERERehmmoAAAACnRSTlMATVRbaeXo6fz+NPhZJgAAAF9JREFUKM9jYBjkQC0JXYS5a4UBmpDFqlXN6IpWrUJTprEKCJpQhLJAQsswhZaiCImDhAJp5kMxkPGJZLjLEiQ0GUWIZdaqVSsdUM33XLVqCpqVLLPQFTEwmAcP9qQAAFUgKabkwE6gAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-picker.ql-expanded .ql-picker-label { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAJFBMVEWqqqr////AwMDAwMDAwMDBwcHBwcHBwcHBwcHBwcHBwcHBwcEexLCPAAAAC3RSTlMAAE1UW2nl6On8/tZA57EAAABxSURBVHjazc4hFkBAGMTxL3AAp+AGniYiyaLnBETHoKkknbc7l7OrzW7zhP3HX5mRxCskEsknEaZoU6VDNbAyRRugSqICpoVotnT7dBFllnpefPuHUpjGD78aSztRfAK65cUOOIQpPnXrkFSDEFFB0APtK1HCkKpz1wAAAABJRU5ErkJggg=="); + } + .ql-snow.ql-toolbar .ql-picker.ql-active:not(.ql-expanded) .ql-picker-label, + .ql-snow.ql-toolbar:not(.ios) .ql-picker:not(.ql-expanded) .ql-picker-label:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAIVBMVEUAAAAAZ8oAZMsAZc0AZswAZswAZswAZswAZswAZswAZswhMkyGAAAACnRSTlMATVRbaeXo6fz+NPhZJgAAAF9JREFUKM9jYBjkQC0JXYS5a4UBmpDFqlXN6IpWrUJTprEKCJpQhLJAQsswhZaiCImDhAJp5kMxkPGJZLjLEiQ0GUWIZdaqVSsdUM33XLVqCpqVLLPQFTEwmAcP9qQAAFUgKabkwE6gAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-bold, + .ql-snow.ql-toolbar .ql-picker.ql-bold .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=bold], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=bold] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAxlBMVEUAAABVVVUzMzNVVVVJSUlGRkZAQEBJSUlAQEBAQEBAQEBHR0dCQkJGRkZAQEBGRkZCQkJERERDQ0NDQ0NGRkZERERDQ0NFRUVCQkJFRUVERERDQ0NDQ0NFRUVDQ0NERERERERERERERERERERERERERERERERERERFRUVDQ0NERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERfjmwgAAAAQXRSTlMAAwUGBwsMDhAUGBkbHSAhIykuOUJERUpNUVZYXGRne3yAi4+SmqWmq67R1tfY2dve5ujp7/Dy8/T19vf4+fv8/mUg1b0AAACrSURBVDjL5dPFDgJBEEXRxt3d3d11gPv/P8WCEAgZuno/b1WLk1TqJaWUI1Jc8852Mqz5bdHHALDK2CF+ckgYIHp/0GtypxpHYKlFSqkycJeQD7hIKADMJFQHulrkSrYs2MflCnZZgzKvo7RJmZeSAWIf1V3nihSGAG19BUq1gKmEQsBZQkHAklATmOuQN5zvP4COQQWnmIxuFfERWOTsXmrztWg8qHqUU/IEzOhNFx6Ncl4AAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-bold.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-bold .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=bold].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=bold].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-bold:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-bold .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=bold]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=bold]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAxlBMVEUAAAAAVaoAZswAVdUAbdsAXdEAatUAbcgAYM8AZswAasoAZswAaNAAasoAaMcAZMkAZswAZM0AZM0AZ8kAZM0AZcsAZMsAZMsAZ8oAZc0AZc0AZcsAZ8oAZswAZssAZssAZcwAZssAZ80AZs0AZ8wAZ80AZswAZ8wAZ8wAZ8wAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsyeO+aMAAAAQXRSTlMAAwUGBwsMDhAUGBkbHSAhIykuOUJERUpNUVZYXGRne3yAi4+SmqWmq67R1tfY2dve5ujp7/Dy8/T19vf4+fv8/mUg1b0AAACrSURBVDjL5dPFDgJBEEXRxt3d3d11gPv/P8WCEAgZuno/b1WLk1TqJaWUI1Jc8852Mqz5bdHHALDK2CF+ckgYIHp/0GtypxpHYKlFSqkycJeQD7hIKADMJFQHulrkSrYs2MflCnZZgzKvo7RJmZeSAWIf1V3nihSGAG19BUq1gKmEQsBZQkHAklATmOuQN5zvP4COQQWnmIxuFfERWOTsXmrztWg8qHqUU/IEzOhNFx6Ncl4AAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-italic, + .ql-snow.ql-toolbar .ql-picker.ql-italic .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=italic], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=italic] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAjVBMVEUAAAAAAACAgIBAQEBVVVVAQEBAQEBCQkJCQkJFRUVDQ0NBQUFDQ0NDQ0NDQ0NFRUVERERERERERERDQ0NERERDQ0NERERERERERERFRUVFRUVERERFRUVERERERERDQ0NERERERERERERDQ0NFRUVEREREREREREREREREREREREREREREREREREREREQUqV1+AAAALnRSTlMAAQIEBggMGyMlKisuUFhZXmJmb3R9hIiKjZGTlKWprrG0uL3BxObt8PL19/j9SqrrawAAAIJJREFUOMvl0jUOQgEQRVHc3d1dzv6XRwch+WRq4NYnmVdMKvU35RZXz+7LQiJqe6uXiDrvqJuI8vM7ALd14fOwIabR+i1agUmfUA1QGedMgJrYRZPGGEVoh0ZgMmeUAlTBMbrWwiZCEwwitEc9MNkLigGq4RBda2MVoRn6X/jfv9YDjuYgGnCpSqcAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-italic.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-italic .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=italic].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=italic].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-italic:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-italic .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=italic]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=italic]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAjVBMVEUAAAAAAP8AgP8AgL8AVdUAYL8AatUAaNAAZswAZ8gAZ8gAZcoAZM0AZswAZcsAZMsAZMsAZcsAZ8sAZcoAZcoAZswAZs0AZ8wAZs0AZ8wAZswAZs0AZs0AZswAZ8wAZ8wAZs0AZswAZ8wAZ8wAZs0AZcwAZswAZswAZswAZswAZswAZswAZswAZswAZsyyI9XbAAAALnRSTlMAAQIEBggMGyMlKisuUFhZXmJmb3R9hIiKjZGTlKWprrG0uL3BxObt8PL19/j9SqrrawAAAIJJREFUOMvl0jUOQgEQRVHc3d1dzv6XRwch+WRq4NYnmVdMKvU35RZXz+7LQiJqe6uXiDrvqJuI8vM7ALd14fOwIabR+i1agUmfUA1QGedMgJrYRZPGGEVoh0ZgMmeUAlTBMbrWwiZCEwwitEc9MNkLigGq4RBda2MVoRn6X/jfv9YDjuYgGnCpSqcAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-underline, + .ql-snow.ql-toolbar .ql-picker.ql-underline .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=underline], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=underline] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAWlBMVEUAAAAAAAAzMzNAQEBGRkZERERERERCQkJERERDQ0NFRUVERERERERFRUVERERERERERERFRUVERERERERERERDQ0NFRUVERERERERERERERERERERERERERET15sOLAAAAHXRSTlMAAQUMLC04TU9UVYePkJKkxMXG2Nrf4+jz9/n6/qlZ0HQAAACUSURBVHja7Y3BDsIgEAW3UCmCFatQxLL//5uuiQ0py1EPxs5tHhMW/oMhxoF5TUSMzGuQqH2PfiO60yiLStIHi260qqKKNLDI0XouOpI6Fh1f/x9W6xOpYZHwNM/9u5lJvACGzvSQRiWlOiUkNDSwuMFCi87mkmTbQRvt18aXWwxhXFiW4IyAr3LBJtMmmtrRFT7ME0B0HEswIOSJAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-underline.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-underline .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=underline].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=underline].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-underline:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-underline .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=underline]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=underline]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAWlBMVEUAAAAAAP8AZswAatUAaMsAZswAZM0AZ8oAZMsAZMsAZswAZswAZs0AZ80AZ8wAZ8wAZcwAZs0AZs0AZswAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZszogqY1AAAAHXRSTlMAAQUMLC04TU9UVYePkJKkxMXG2Nrf4+jz9/n6/qlZ0HQAAACUSURBVHja7Y3BDsIgEAW3UCmCFatQxLL//5uuiQ0py1EPxs5tHhMW/oMhxoF5TUSMzGuQqH2PfiO60yiLStIHi260qqKKNLDI0XouOpI6Fh1f/x9W6xOpYZHwNM/9u5lJvACGzvSQRiWlOiUkNDSwuMFCi87mkmTbQRvt18aXWwxhXFiW4IyAr3LBJtMmmtrRFT7ME0B0HEswIOSJAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-strike, + .ql-snow.ql-toolbar .ql-picker.ql-strike .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=strike], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=strike] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAABLFBMVEUAAACAgIBVVVVAQEAzMzNVVVVAQEA5OTlNTU1JSUlERERHR0dDQ0NGRkZDQ0NAQEBCQkJAQEBGRkZAQEBGRkZERERBQUFERERGRkZCQkJGRkZERERFRUVERERDQ0NFRUVERERDQ0NFRUVCQkJDQ0NFRUVCQkJDQ0NERERDQ0NERERERERDQ0NFRUVERERERERERERERERFRUVERERDQ0NFRUVERERERERFRUVERERERERDQ0NDQ0NFRUVERERERERFRUVERERERERFRUVERERERERDQ0NERERFRUVERERERERERERFRUVERERERERERERERERFRUVERERERERERERFRUVERERERERERERERERERERERERERERERERERERERERERERERERERERERET5TTiyAAAAY3RSTlMAAgMEBQYICQoODxITFhcYGxwdICEtLzEzNjc4P0BFRkdISk1YWWBjaWtsdHZ3f4CHiImKjJGSk5SVl5ufo6Smp625uru8vb/BwsPExcbMzs/Q0dPi4+Tl6+zv8PL19vf4+/z2SQ4sAAABE0lEQVQ4y2NgGDmAV8c5PCkxxFGDE6cSDuOEZCiI0WXGroY/OBkJeHJhU8Pkm4wCXBixKFIHyUTqibJzS5lEgNhqWBT5AMWD+CFsHg8gxxuLoniguCyMIwLkxGFRBPKZDKEw8gMqCuAloEgb7HADMTZ8ijisjHTUlCSFOdgFxeVUNPXM7Z38QmJ9EApQxFFCyxeuxhtFPC7U39nBQl9LVV5CiAMpiFDEOYQlldR0jGwM8DmOVVDRLBpkpDIBr/KBXOBKKNSEgYpiMUQjgaLChBQ5A0W94AHO6wXkumEoUgY5NcpUUYCFRUDBNAqHw22T0YAdNp9bo6qxZMLqI4VAhJIgBZwelzZ0D4uLC3M3lB5B5QgAFQdgZ6NzzvYAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-strike.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-strike .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=strike].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=strike].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-strike:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-strike .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=strike]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=strike]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAABLFBMVEUAAAAAgP8AVaoAgL8AZswAVdUAYL8AccYAZswAbcgAZswAY8YAa8kAaNEAZMgAasoAaNAAZMgAasoAaMcAZMkAZswAZ8kAaMsAZM0AaMsAZswAZM0AZcoAZMsAZMsAZswAZc0AZ8oAZMsAZ8oAZcsAZMsAZcoAZMsAZswAZssAZssAZcoAZssAZcwAZssAZs0AZswAZ8wAZs0AZs0AZswAZswAZ8wAZs0AZs0AZ80AZ8wAZswAZ8wAZs0AZ8wAZ8wAZs0AZs0AZswAZ8wAZs0AZs0AZ8wAZcwAZs0AZ8wAZswAZcwAZs0AZs0AZ8wAZswAZswAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswL5dPDAAAAY3RSTlMAAgMEBQYICQoODxITFhcYGxwdICEtLzEzNjc4P0BFRkdISk1YWWBjaWtsdHZ3f4CHiImKjJGSk5SVl5ufo6Smp625uru8vb/BwsPExcbMzs/Q0dPi4+Tl6+zv8PL19vf4+/z2SQ4sAAABE0lEQVQ4y2NgGDmAV8c5PCkxxFGDE6cSDuOEZCiI0WXGroY/OBkJeHJhU8Pkm4wCXBixKFIHyUTqibJzS5lEgNhqWBT5AMWD+CFsHg8gxxuLoniguCyMIwLkxGFRBPKZDKEw8gMqCuAloEgb7HADMTZ8ijisjHTUlCSFOdgFxeVUNPXM7Z38QmJ9EApQxFFCyxeuxhtFPC7U39nBQl9LVV5CiAMpiFDEOYQlldR0jGwM8DmOVVDRLBpkpDIBr/KBXOBKKNSEgYpiMUQjgaLChBQ5A0W94AHO6wXkumEoUgY5NcpUUYCFRUDBNAqHw22T0YAdNp9bo6qxZMLqI4VAhJIgBZwelzZ0D4uLC3M3lB5B5QgAFQdgZ6NzzvYAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-link, + .ql-snow.ql-toolbar .ql-picker.ql-link .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=link], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=link] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAABDlBMVEUAAAD///8AAACAgIBVVVVAQEAzMzNVVVVAQEBNTU1HR0dAQEBJSUlGRkZDQ0NAQEBERERHR0dGRkZDQ0NBQUFGRkZERERCQkJGRkZFRUVCQkJFRUVERERDQ0NDQ0NCQkJFRUVDQ0NERERDQ0NFRUVDQ0NFRUVFRUVFRUVFRUVERERDQ0NFRUVERERFRUVERERERERDQ0NFRUVFRUVERERERERERERERERFRUVERERERERERERFRUVDQ0NERERERERFRUVERERERERERERERERERERERERERERERERERERERERFRUVERERERERERERERERERERERERERERERERERERERERERERERERERERERESFPz0UAAAAWXRSTlMAAAECAwQFBggKEhQVFhccHiQoKissLTIzNDpGR0hMTU5QUlRVW12BgoaHjI2PmJmam5ygpKWosbKztLW6vcDD0NLT2Nna3N7g4eLj5Ofo6err7u/w8vn7/A90CXkAAAFqSURBVDjLzdTHUgJREIXho8yo6JgFc0LFjAkVMZAFJYrCzP/+L+JCtJipS5U7Patbt79Vd1dr6BfRHyBJUiie6dSSiwrEh2aeAPAO7cEoUqWXdHgQirQAOh7A46gZzVQBzsfmSgAnRhR6AjiS5OQAd9aE4t9GmqoCCRPKAGe9zzhQDxlQBzpjknab9c2RD2DBgGrgzUlqQnfrHlg3oGug6Eh1oFsAEtvLVhAteUBuSjseP2lfzQf6dARQjY/s9SncY9uH7DQA7+ky/XkI+8YSfvRVC6k3AO4s34BHT90+1N2yYq8A+/5V0Wyi0ac2NJkD3KgfSaGF9QRQ9oCC5JSAiyCStA2k9jzISooCFQNaBlpWrJBdkTThQsOA7DYQ+3pbKeDWgHQFvDiSNJwEWDWheRfIOZKVBLiRCekYoBiZSAHkx83IfgDABXielhkpfAcAkJ/WICTrwAXgZlyDkRS9rDRu1wJL98/u0yeVYHcP1mwWWgAAAABJRU5ErkJggg=="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-link.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-link .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=link].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=link].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-link:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-link .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=link]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=link]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAABDlBMVEUAAAD///8AAP8AgP8AVaoAgL8AZswAVdUAYL8AZswAY8YAZswAYc4AaNEAZMgAZMgAZswAY80AZswAZ8gAZcoAaMsAZswAZswAZM0AZ8kAZcoAZswAZc0AZ8oAZc0AZ8oAZcsAZswAZ8oAZMsAZswAZc0AZcsAZ84AZswAZ84AZswAZswAZ8wAZs0AZs0AZs0AZ80AZswAZ8wAZswAZ8wAZswAZs0AZs0AZs0AZ8wAZswAZ8wAZ8wAZ8wAZs0AZswAZs0AZswAZswAZswAZswAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsxCnEEHAAAAWXRSTlMAAAECAwQFBggKEhQVFhccHiQoKissLTIzNDpGR0hMTU5QUlRVW12BgoaHjI2PmJmam5ygpKWosbKztLW6vcDD0NLT2Nna3N7g4eLj5Ofo6err7u/w8vn7/A90CXkAAAFqSURBVDjLzdTHUgJREIXho8yo6JgFc0LFjAkVMZAFJYrCzP/+L+JCtJipS5U7Patbt79Vd1dr6BfRHyBJUiie6dSSiwrEh2aeAPAO7cEoUqWXdHgQirQAOh7A46gZzVQBzsfmSgAnRhR6AjiS5OQAd9aE4t9GmqoCCRPKAGe9zzhQDxlQBzpjknab9c2RD2DBgGrgzUlqQnfrHlg3oGug6Eh1oFsAEtvLVhAteUBuSjseP2lfzQf6dARQjY/s9SncY9uH7DQA7+ky/XkI+8YSfvRVC6k3AO4s34BHT90+1N2yYq8A+/5V0Wyi0ac2NJkD3KgfSaGF9QRQ9oCC5JSAiyCStA2k9jzISooCFQNaBlpWrJBdkTThQsOA7DYQ+3pbKeDWgHQFvDiSNJwEWDWheRfIOZKVBLiRCekYoBiZSAHkx83IfgDABXielhkpfAcAkJ/WICTrwAXgZlyDkRS9rDRu1wJL98/u0yeVYHcP1mwWWgAAAABJRU5ErkJggg=="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-image, + .ql-snow.ql-toolbar .ql-picker.ql-image .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=image], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=image] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAFVBMVEUAAABCQkJEREREREREREREREREREQL6X1nAAAABnRSTlMATXjl6OmAFiJpAAAAZklEQVR42sXQsQ3AIAxEUeQZoKdyzwg0DALo9h8hiCYXo4R0/MbSK1ycO5EHlScVpj4Jj97p/vtJPi9U+kptXIlMIY2r1b4XIBpSoDJJFIyYtKohAWBIV8Ke9kv8X7WwtEmBKbkDXfWkWdehkaSCAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-image.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-image .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=image].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=image].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-image:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-image .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=image]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=image]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAFVBMVEUAAAAAZ8oAZswAZswAZswAZswAZsx4QzxlAAAABnRSTlMATXjl6OmAFiJpAAAAZklEQVR42sXQsQ3AIAxEUeQZoKdyzwg0DALo9h8hiCYXo4R0/MbSK1ycO5EHlScVpj4Jj97p/vtJPi9U+kptXIlMIY2r1b4XIBpSoDJJFIyYtKohAWBIV8Ke9kv8X7WwtEmBKbkDXfWkWdehkaSCAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-list, + .ql-snow.ql-toolbar .ql-picker.ql-list .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=list], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=list] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAw1BMVEUAAAAAAABVVVVAQEBERERAQEBJSUlGRkZHR0dFRUVCQkJERERAQEBGRkZDQ0NFRUVDQ0NCQkJGRkZDQ0NCQkJERERDQ0NFRUVERERFRUVERERDQ0NERERERERDQ0NFRUVERERERERERERERERERERERERERERFRUVERERERERERERFRUVERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERESFbZw4AAAAQHRSTlMAAQYIDxAVFhkaGx4gKCo0NTY3OU10fYKIiYqMj56fo6SmqKmvtLe6vr/ExcbLz9fh4uXm5+jp7O/w8vP3+vv9Z7IwDAAAAK1JREFUOMvV0scOglAQQFGwYO+oiIq9YldEFPX+/1e5cGEii2FFdNY3b/JORlF+dAqNrS1GQyDEW+9Id/gaRw9EgQacMNEhuO4caD7rlgDS/2yAVWTiia53HWeEaMLzwUKIdvt08n4TxLMptc1UEo/38YqCuGZzKknimxDi6jpa8Vjn6I4kcQNgLkSmVSvjizeeb9ITbzxXxxLETatSxRfEWwAzicC4uANN+at5AdptTQ0Ubk4LAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-list.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-list .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=list].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=list].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-list:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-list .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=list]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=list]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAw1BMVEUAAAAAAP8AVdUAYL8AZswAYM8AYc4AaNEAZswAYs4AaNAAZswAaMcAZswAZ8gAZ8kAZcoAaMsAZswAZ8kAZ8oAZcoAZswAZswAZ8wAZs0AZs0AZswAZs0AZs0AZ8wAZs0AZ8wAZ8wAZs0AZ8wAZswAZswAZs0AZ8wAZswAZcwAZcwAZs0AZs0AZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZszno9YmAAAAQHRSTlMAAQYIDxAVFhkaGx4gKCo0NTY3OU10fYKIiYqMj56fo6SmqKmvtLe6vr/ExcbLz9fh4uXm5+jp7O/w8vP3+vv9Z7IwDAAAAK1JREFUOMvV0scOglAQQFGwYO+oiIq9YldEFPX+/1e5cGEii2FFdNY3b/JORlF+dAqNrS1GQyDEW+9Id/gaRw9EgQacMNEhuO4caD7rlgDS/2yAVWTiia53HWeEaMLzwUKIdvt08n4TxLMptc1UEo/38YqCuGZzKknimxDi6jpa8Vjn6I4kcQNgLkSmVSvjizeeb9ITbzxXxxLETatSxRfEWwAzicC4uANN+at5AdptTQ0Ubk4LAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-bullet, + .ql-snow.ql-toolbar .ql-picker.ql-bullet .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=bullet], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=bullet] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAABCQkJEREREREREREREREQc4xmxAAAABXRSTlMATeXo6UtNtyIAAAAzSURBVCjPY2AYACBsyCAcCgOGYCHTYAZTuFAwRCgISSgILCSiyCACF1JkGBgw6voBcj0AFsUtDasGrUcAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-bullet.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-bullet .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=bullet].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=bullet].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-bullet:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-bullet .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=bullet]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=bullet]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAAAAZ8oAZswAZswAZswAZsxixJGvAAAABXRSTlMATeXo6UtNtyIAAAAzSURBVCjPY2AYACBsyCAcCgOGYCHTYAZTuFAwRCgISSgILCSiyCACF1JkGBgw6voBcj0AFsUtDasGrUcAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-authorship, + .ql-snow.ql-toolbar .ql-picker.ql-authorship .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=authorship], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=authorship] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAllBMVEUAAACAgIBAQEBCQkIAAABCQkJAQEBGRkZERERERERCQkJGRkZDQ0NDQ0NDQ0MAAAAAAAAAAABDQ0NFRUVERERFRUVERERFRUVERERFRUVERERERERERERERERERERERERERERFRUVEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQe3JVeAAAAMXRSTlMAAhgbHx8gIS0xMjM5VFdcXWZyd3yChImPkKy4yMrO0tPj5ebq7e7v8PLz9/j6/P3+mEwo9QAAAJxJREFUGBnVwNcOgjAYBeCj4l7FjeAGUZzn/V9O0kikSftf44c/0A+Tc9iFqHll7tKEJKAWQLKjtockpZZC8qL2hiSjlkESUYsgmVNbQtKhNoCgNrwz95w14NTe8Os2gUP9wJ8p7NYsebRg06NhAZsVDRFstjQksMlogs2Rhhg2o5glpxGqz1O+g/JQUL6TQkH5TmMUPOU7jD1U1AdG8S1kERvjygAAAABJRU5ErkJggg=="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-authorship.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-authorship .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=authorship].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=authorship].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-authorship:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-authorship .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=authorship]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=authorship]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAllBMVEUAAAAAgP8AasoAaNAAY84AaMcAZMkAZswAaMsAZswAZM0AZ8kAZMsAZ8oAZ8oAZcsAZc4AZ80AZcwAZcwAZcwAZswAZs0AZs0AZs0AZ80AZs0AZ8wAZswAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsyCDIYeAAAAMXRSTlMAAhgbHyAhLTEyMzlUV1xdXWZyd3yChImPkKy4yMrO0tPj5ebq7e7v8PLz9/j6/P3+PxHOPAAAAJxJREFUGBnVwNcOgjAYBeCj1j0q7oEbRHGe9385SSORJu1/jR/+QGcdn9ctiNSVmYuCZEljCcmOxh6ShEYCyYvGG5KURgpJSCOEZEpjDkmTRheCSu/OzHNSg1djw6/bCB7VA3/GcFux4FGHS5uWGVwWtIRw2dISwyWlDS5HWiK49CMWnPooP6UDD62Q04GXRk4HXgPk1DDwGCiU1AcZWy1RmD8CRQAAAABJRU5ErkJggg=="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-color, + .ql-snow.ql-toolbar .ql-picker.ql-color .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=color], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=color] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAz1BMVEUAAAAAAACAgIBVVVVAQEBVVVU5OTk7OztLS0tHR0dGRkZCQkIAAABERERDQ0NDQ0NDQ0NDQ0NGRkZERERERERCQkJFRUVERERFRUVEREQAAAAAAABDQ0NFRUVEREQAAABERERFRUVERERDQ0NDQ0NERERERERERERERERERERERERERERERERERERFRUVFRUVERERERERERERERERERERDQ0NERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERbYaT1AAAARHRSTlMAAQIDBAYJDRESFhsfIiYqNUFCREtNVVZZWlxdY2RlZm1zdXZ9hI6Tl6Sws7nExcnS09XY2d/g5ejp6+zt8PP09/n9/idH/qoAAADKSURBVBgZ1cDXUsJAAIXhg2KMGruxsGoUe8cWoij1f/9nYiZDGJjsLrfwaRHEWRZrhuAXWoH8zgBO5VVpADTktU9uVz5P5B7lsdUn19+U2x3w+gbcyilsA0cnwP+qXOpAWl1pAhdyqKZAXboGvpZkdwi0Q2m9CxzI7oUJz7LaYdJgWzYPTLmXxUaPKZ01ld0A7xXllr+BK5VlwLlGLoFPlWXQCjQSduBDZfFPM9bY8V+6p7kXmcTBRCqYxMmoYBKnmgqRSRxqkebUEKsKOlxMa6IbAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-color.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-color .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=color].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=color].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-color:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-color .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=color]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=color]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAA0lBMVEUAAAAAAP8AgP8AVaoAgL8AVdUAccYAYsQAadIAY8YAaNEAaNAAY84AacsAZckAZ8gAZcoAZswAZM0AZcsAZswAZ8oAZswAZc0AZMsAZswAZ8oAZcsAZc4AZMsAZswAZcoAZ80AZcwAZswAZssAZssAZswAZs0AZs0AZs0AZ8wAZ8wAZ8wAZ8wAZswAZcwAZs0AZcwAZswAZswAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswVaivDAAAARXRSTlMAAQIDBAYJDRESFhsfIiYqNUFCREtNVVZZWlxdXWNkZWZtc3V2fYSOk5eksLO5xMXJ0tPV2Nnf4OXo6evs7fDz9Pf5/f6Y2SWXAAAAy0lEQVQYGdXA11LCQACF4YNijBq7sbCWKPaOLURREPjf/5WYyRAGJrvLLXyaB3GWxZoi+IFWIL9TgBN5VRoADXntktuWzyO5B3ls9Mj11uV2C7y8AjdyCtvAwRHwtyyXOpBWl5rAuRyqKVCXroDPBdntA+1QWv0H9mT3zJgnWW0xrr8pm3sm3MlircuEzorKroG3inKLX8ClyjLgTEMXwIfKMmgFGgo78K6y+LsZa+TwN93RzItM4mAiFUziZFQwiVNNheg4cahFmlEDFzs7cwmPHM8AAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-background, + .ql-snow.ql-toolbar .ql-picker.ql-background .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=background], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=background] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAA4VBMVEUAAAAAAACAgIBVVVVAQEBVVVU5OTk7OztLS0tHR0dGRkZCQkJERERDQ0NDQ0NDQ0NDQ0NERERCQkJEREQAAAADAwMGBgZDQ0NEREQODg5ERERDQ0NFRUVERERERERERERDQ0MiIiJDQ0MmJiZEREQrKytEREREREQyMjIyMjJEREREREREREQ4ODhERERERERFRUVFRUVERERERERERERERERAQEBERERERERBQUFERERERERERERBQUFERERERERERERBQUFERERERERERERDQ0NERERERERDQ0NERERERESZD8GyAAAASnRSTlMAAQIDBAYJDRESFhsiJio1QURJS01QU1RWWVpjZGVtdXZ4fYCEiI6TnZ6ksLO3ucTFydLT193g4OLl5ebn6enq6+7w8vP39/n+/rihcb4AAADbSURBVHjazZPFDsMwEERdZkpTZmbmpszd//+grhpFSaS1e+khc1jbmrG1z7KZdSXLgvo79M9ziKCkKJIeoUPJA8AxKT6H5QGVE3dlmwJqKqaLwVdRIV1fDfVEdKGXGnoFBXQtDIwnWJp8uswd/XQWy8XD7aqD9srp2uJQ5NElVuiWGKvisLFz6Bpo3ryM+R84iXO6GoFBQ5ouAka9wyRdF0waUHSBpzl09xF0dTRmNnXu2OOiTNDtAKCg7W3jYk7QnQGObu0KvVeAJUFXU9aS/h5Sp0VFtui/s6w+XSJAbiVJ3G0AAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-background.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-background .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=background].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=background].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-background:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-background .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=background]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=background]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAA5FBMVEUAAAAAAP8AgP8AVaoAgL8AZswAVdUAYL8AccYAYsQAadIAY8YAaNEAasoAZswAYsQAaNAAacsAZckAadEAZ8gAZcoAZswAZswAZMkAZM0AZcsAZ8sAZswAaM0AZ8oAZ80AZswAZc0AZMsAZswAZMsAZswAZcoAZcwAZswAZssAZssAZswAZs0AZs0AZs0AZ8wAZ8wAZ8wAZ8wAZswAZcwAZs0AZcwAZswAZswAZs0AZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZswAZsxJPDLdAAAAS3RSTlMAAQIDBAUGCAkNERIWGBkaGyImJyo1N0FCQkRFS0xNTVVWWVpjZGVtc3V2fYSOk5eksLO5xMXJ0tPV2Nnf4OXo6evs7fDz9Pf5/f60OfwzAAABG0lEQVR42s2T6VKDQBCEGyUJoqgSjcYg8dZ43/EieCUa5/3fx661qMAu7O98P4bZnq5lZlkwvXS7k1hf1BTdZFEsFpvUMU15IU7TuKiYJu9d5MODZZ8WcCBk39ZVAKcvpG+ZrgNsimIdTtV0TeBGFNewdBWORTFesUx3QcP9A8N59XT+kPWdPYavOQQVXfVYTtz6gI8jvfUsdRNWe8ApHy8z5ftgm8WhDyx8M4nKumoBd5LjVkkaAdYkz+8qpQLqtK+kwKU5XRPLP1JgNF8y3RkLjw4Us69cnMDb0qdLqR9myjEXz2brNPG2NSKQqOGPRJ5gEr8NYoT/9yHE7mfShoarovYptDw7kiWLyZTbNZBa9saK33tDWZlPK39U3ELkzhssBgAAAABJRU5ErkJggg=="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-left, + .ql-snow.ql-toolbar .ql-picker.ql-left .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=left], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=left] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAABCQkJEREREREREREREREQc4xmxAAAABXRSTlMATeXo6UtNtyIAAABCSURBVCjPY2AYACAcCgaGSEKmEKFgTKEgJCERiJAiw0ACqOuR/WCKLBSMKRSE7PqB9YMwuttRnBqMKRSEGvYD6HYAD8opyeJDvUUAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-left.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-left .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=left].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=left].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-left:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-left .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=left]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=left]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAAAAZ8oAZswAZswAZswAZsxixJGvAAAABXRSTlMATeXo6UtNtyIAAABCSURBVCjPY2AYACAcCgaGSEKmEKFgTKEgJCERiJAiw0ACqOuR/WCKLBSMKRSE7PqB9YMwuttRnBqMKRSEGvYD6HYAD8opyeJDvUUAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-right, + .ql-snow.ql-toolbar .ql-picker.ql-right .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=right], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=right] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAABCQkJEREREREREREREREQc4xmxAAAABXRSTlMATeXo6UtNtyIAAABCSURBVCjPY2AYMCAcCgaGSEKmEKFgTKEgJCERiJDiwLob2fWmyELBmEJByO4eWNejuN8QNZCRw94U3fUo7h8Q1wMAuRspyVIXC2UAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-right.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-right .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=right].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=right].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-right:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-right .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=right]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=right]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAAAAZ8oAZswAZswAZswAZsxixJGvAAAABXRSTlMATeXo6UtNtyIAAABCSURBVCjPY2AYMCAcCgaGSEKmEKFgTKEgJCERiJDiwLob2fWmyELBmEJByO4eWNejuN8QNZCRw94U3fUo7h8Q1wMAuRspyVIXC2UAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-center, + .ql-snow.ql-toolbar .ql-picker.ql-center .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=center], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=center] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAABCQkJEREREREREREREREQc4xmxAAAABXRSTlMATeXo6UtNtyIAAABCSURBVCjPY2AYGCAcCgaGSEKmEKFgTKEgJCERiJAiw4ABqNORPWCKLBSMKRSE7PQB9oAwuuNR3BqMKRSEGvID53gA5GspyQ9EElMAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-center.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-center .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=center].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=center].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-center:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-center .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=center]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=center]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAAAAZ8oAZswAZswAZswAZsxixJGvAAAABXRSTlMATeXo6UtNtyIAAABCSURBVCjPY2AYGCAcCgaGSEKmEKFgTKEgJCERiJAiw4ABqNORPWCKLBSMKRSE7PQB9oAwuuNR3BqMKRSEGvID53gA5GspyQ9EElMAAAAASUVORK5CYII="); + } + .ql-snow.ql-toolbar .ql-format-button.ql-justify, + .ql-snow.ql-toolbar .ql-picker.ql-justify .ql-picker-label, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=justify], + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=justify] { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAABCQkJEREREREREREREREQc4xmxAAAABXRSTlMATeXo6UtNtyIAAAAoSURBVCjPY2AYACAcigQMwUKmyELBmEJBYCERZCFFhoEBo64fINcDAAcQNGkJNhVcAAAAAElFTkSuQmCC"); + } + .ql-snow.ql-toolbar .ql-format-button.ql-justify.ql-active, + .ql-snow.ql-toolbar .ql-picker.ql-justify .ql-picker-label.ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-label[data-value=justify].ql-active, + .ql-snow.ql-toolbar .ql-picker .ql-picker-item[data-value=justify].ql-selected, + .ql-snow.ql-toolbar:not(.ios) .ql-format-button.ql-justify:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker.ql-justify .ql-picker-label:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-label[data-value=justify]:hover, + .ql-snow.ql-toolbar:not(.ios) .ql-picker .ql-picker-item[data-value=justify]:hover { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAElBMVEUAAAAAZ8oAZswAZswAZswAZsxixJGvAAAABXRSTlMATeXo6UtNtyIAAAAoSURBVCjPY2AYACAcigQMwUKmyELBmEJBYCERZCFFhoEBo64fINcDAAcQNGkJNhVcAAAAAElFTkSuQmCC"); + } +} +.ql-snow .ql-tooltip { + border: 1px solid #ccc; + box-shadow: 0px 0px 5px #ddd; + color: #222; +} +.ql-snow .ql-tooltip a { + color: #06c; +} +.ql-snow .ql-tooltip .input { + border: 1px solid #ccc; + margin: 0px; + padding: 5px; +} +.ql-snow a { + color: #06c; +} diff --git a/Examples/bower_components/quill/docs/style-guide.md b/Examples/bower_components/quill/docs/style-guide.md new file mode 100644 index 00000000..25a3c0a2 --- /dev/null +++ b/Examples/bower_components/quill/docs/style-guide.md @@ -0,0 +1,50 @@ +# Style Guide + +Code style is very subjective but consistency is very important for a healthy codebase. Quill strives to follow good programming practices and the language specific guidelines so those will not be reproduced here. However some less obvious guidelines are listed below. + +If there is ever uncertainty, please look at other parts of the codebase and mimic that style. + + +### General + +- Use two spaces for tabs +- No trailing whitespace on any lines + + +### Operators + +- Always use parenthesis for function calls +- Use brackets for one line object definitions + +```coffeescript +console.log('Yes') # Yes +console.log 'No' # No + +config = { attack: 10, defense: 10 } # Yes +config = attack: 10, defense: 10 # No + +# Okay +config = + attack: 10 + defense: 10 +``` + + +### Classes + +- Use an explicit `this` when referencing methods +- Use `@` when referencing instance variables + +```coffeescript +class Tower + @constructor: (strength, toughness) -> + @strength = strength # Yes + this.toughness = toughness # No + + this.attack() # Yes + @defend() # No + + attack: -> + + defend: -> +``` diff --git a/Examples/bower_components/y-array/.bower.json b/Examples/bower_components/y-array/.bower.json new file mode 100644 index 00000000..0174538c --- /dev/null +++ b/Examples/bower_components/y-array/.bower.json @@ -0,0 +1,15 @@ +{ + "name": "y-array", + "homepage": "https://github.com/y-js/y-array", + "version": "0.7.5", + "_release": "0.7.5", + "_resolution": { + "type": "version", + "tag": "v0.7.5", + "commit": "616d21127c3aece7c1c3619b9f7ffe2f20f03f23" + }, + "_source": "git://github.com/y-js/y-array.git", + "_target": "~0.7.5", + "_originalSource": "y-array", + "_direct": true +} \ No newline at end of file diff --git a/Examples/bower_components/y-array/.bowerrc b/Examples/bower_components/y-array/.bowerrc new file mode 100644 index 00000000..7bbfd373 --- /dev/null +++ b/Examples/bower_components/y-array/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "../" +} diff --git a/Examples/bower_components/y-array/.gitignore b/Examples/bower_components/y-array/.gitignore new file mode 100644 index 00000000..18092522 --- /dev/null +++ b/Examples/bower_components/y-array/.gitignore @@ -0,0 +1,6 @@ +/node_modules/ +bower_components +.directory +.c9 +.codio +.settings \ No newline at end of file diff --git a/Examples/bower_components/y-array/.travis.yml b/Examples/bower_components/y-array/.travis.yml new file mode 100644 index 00000000..e830c82b --- /dev/null +++ b/Examples/bower_components/y-array/.travis.yml @@ -0,0 +1,11 @@ +language: node_js +before_install: + - "npm install -g bower coffee-script" + - "bower install" +node_js: + - "0.12" + - "0.11" + - "0.10" +branches: + only: + - master \ No newline at end of file diff --git a/Examples/bower_components/y-array/README.md b/Examples/bower_components/y-array/README.md new file mode 100644 index 00000000..5a51c237 --- /dev/null +++ b/Examples/bower_components/y-array/README.md @@ -0,0 +1,92 @@ + +# List Type for [Yjs](https://github.com/y-js/yjs) + +Manage list-like data with this shareable list type. You can insert and delete arbitrary objects (also custom types for Yjs) in the list type. + +## Use it! +Retrieve this with bower or npm. + +##### Bower +``` +bower install y-list --save +``` + +and include the js library. + +``` + +``` + +##### NPM +``` +npm install y-list --save +``` +and put it on the `Y` object. + +``` +Y.List = require("y-list"); +``` + + +### List Object + +##### Reference +* Create +``` +var ylist = new Y.List() +``` +* .insert(position, content) + * Insert content at a position +* .insertContents(position, contents) + * Insert a set of content at a position. This expects that contents is an array of content. +* .push(content) + * Insert content at the end of the list +* .delete(position, length) + * Delete content. The *length* parameter is optional and defaults to 1 +* .val() + * Retrieve all content as an Array Object +* .val(position) + * Retrieve content from a position +* .ref(position) + * Retrieve a reference to the element on a *position*. + * You can call `ref.getNext()` and `ref.getPrev()` to get the next/previous reference + * You can call `ref.getNext(i)` and `ref.getPrev(i)` to get the i-th next/previous reference + * You can call `ref.val()` to get the element, to which the reference points (`y.ref(1).val() === y.val(1)`) +* .observe(f) + * The observer is called whenever something on this list changed. (throws insert, and delete events) +* .unobserve(f) + * Delete an observer + + +# A note on intention preservation +If two users insert something at the same position concurrently, the content that was inserted by the user with the higher user-id will be to the right of the other content. In the OT world we often speak of *intention preservation*, which is very loosely defined in most cases. This type has the following notion of intention preservation: When a user inserts content *c* after a set of content *C_left*, and before a set of content *C_right*, then *C_left* will be always to the left of c, and *C_right* will be always to the right of *c*. This property will also hold when content is deleted or when a deletion is undone. + +# A note on time complexities +* .insert(position, content) + * O(position) +* .insertContents(position, contents) + * O(position + |contents|) +* .push(content) + * O(1) +* .delete(position, length) + * O(position) +* .val() + * O(|ylist|) +* .val(position) + * O(position|) +* Apply a delete operation from another user + * O(1) +* Apply an insert operation from another user + * Yjs does not transform against operations that do not conflict with each other. + * An operation conflicts with another operation if it intends to be inserted at the same position. + * Overall worst case complexety: O(|conflicts|!) + + +# Issues +* Support moving of objects +* Create a polymer element + +## License +Yjs is licensed under the [MIT License](./LICENSE.txt). + + \ No newline at end of file diff --git a/Examples/bower_components/y-array/y-array.es6 b/Examples/bower_components/y-array/y-array.es6 new file mode 100644 index 00000000..27b2cc33 --- /dev/null +++ b/Examples/bower_components/y-array/y-array.es6 @@ -0,0 +1,197 @@ +(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 { + var userEvents = [] + for (var i in ops) { + var op = ops[i] + if (op.struct === 'Insert') { + let pos + // we check op.left only!, + // because op.right might not be defined when this is called + if (op.left === null) { + pos = 0 + } else { + var sid = JSON.stringify(op.left) + pos = this.idArray.indexOf(sid) + 1 + if (pos <= 0) { + throw new Error('Unexpected operation!') + } + } + this.idArray.splice(pos, 0, JSON.stringify(op.id)) + this.valArray.splice(pos, 0, op.content) + userEvents.push({ + type: 'insert', + object: this, + index: pos, + value: op.content, + length: 1 + }) + } else if (op.struct === 'Delete') { + let pos = this.idArray.indexOf(JSON.stringify(op.target)) + if (pos >= 0) { + var val = this.valArray[pos] + this.idArray.splice(pos, 1) + this.valArray.splice(pos, 1) + userEvents.push({ + type: 'delete', + object: this, + index: pos, + value: val, + length: 1 + }) + } + } else { + throw new Error('Unexpected struct!') + } + } + this.eventHandler.callEventListeners(userEvents) + }) + } + get length () { + return this.idArray.length + } + get (pos) { + if (pos == null || typeof pos !== 'number') { + throw new Error('pos must be a number!') + } + return this.valArray[pos] + } + toArray () { + return this.valArray.slice() + } + push (contents) { + this.insert(this.idArray.length, contents) + } + insert (pos, contents) { + if (typeof pos !== 'number') { + throw new Error('pos must be a number!') + } + if (!(contents instanceof Array)) { + throw new Error('contents must be an Array of objects!') + } + if (contents.length === 0) { + return + } + if (pos > this.idArray.length || pos < 0) { + throw new Error('This position exceeds the range of the array!') + } + var mostLeft = pos === 0 ? null : JSON.parse(this.idArray[pos - 1]) + + var ops = [] + var prevId = mostLeft + for (var i = 0; i < contents.length; i++) { + var op = { + left: prevId, + origin: prevId, + // right: mostRight, + // NOTE: I intentionally do not define right here, because it could be deleted + // at the time of creating this operation, and is therefore not defined in idArray + parent: this._model, + content: contents[i], + struct: 'Insert', + id: this.os.getNextOpId() + } + ops.push(op) + prevId = op.id + } + var eventHandler = this.eventHandler + eventHandler.awaitAndPrematurelyCall(ops) + this.os.requestTransaction(function *() { + // now we can set the right reference. + var mostRight + if (mostLeft != null) { + mostRight = (yield* this.getOperation(mostLeft)).right + } else { + mostRight = (yield* this.getOperation(ops[0].parent)).start + } + for (var j in ops) { + ops[j].right = mostRight + } + yield* this.applyCreatedOperations(ops) + eventHandler.awaitedInserts(ops.length) + }) + } + delete (pos, length) { + if (length == null) { length = 1 } + if (typeof length !== 'number') { + throw new Error('pos must be a number!') + } + if (typeof pos !== 'number') { + throw new Error('pos must be a number!') + } + if (pos + length > this.idArray.length || pos < 0 || length < 0) { + throw new Error('The deletion range exceeds the range of the array!') + } + if (length === 0) { + return + } + var eventHandler = this.eventHandler + var newLeft = pos > 0 ? JSON.parse(this.idArray[pos - 1]) : null + var dels = [] + for (var i = 0; i < length; i++) { + dels.push({ + target: JSON.parse(this.idArray[pos + i]), + struct: 'Delete' + }) + } + eventHandler.awaitAndPrematurelyCall(dels) + this.os.requestTransaction(function *() { + yield* this.applyCreatedOperations(dels) + eventHandler.awaitedDeletes(dels.length, newLeft) + }) + } + observe (f) { + this.eventHandler.addEventListener(f) + } + * _changed (transaction, op) { + if (!op.deleted) { + if (op.struct === 'Insert') { + var l = op.left + var left + while (l != null) { + left = yield* transaction.getOperation(l) + if (!left.deleted) { + break + } + l = left.left + } + op.left = l + } + this.eventHandler.receivedOp(op) + } + } + } + + Y.extend('Array', new Y.utils.CustomType({ + name: 'Array', // TODO: copy the name when extending the object.. (see one line above) + class: YArray, + struct: 'List', + initType: function * YArrayInitializer (os, model) { + var valArray = [] + var idArray = yield* Y.Struct.List.map.call(this, model, function (c) { + valArray.push(c.content) + return JSON.stringify(c.id) + }) + return new YArray(os, model.id, idArray, valArray) + } + })) +} + +module.exports = extend +if (typeof Y !== 'undefined') { + extend(Y) +} + +},{}]},{},[1]) + diff --git a/Examples/bower_components/y-array/y-array.es6.map b/Examples/bower_components/y-array/y-array.es6.map new file mode 100644 index 00000000..940ed968 --- /dev/null +++ b/Examples/bower_components/y-array/y-array.es6.map @@ -0,0 +1 @@ +{"version":3,"sources":["../yjs/node_modules/browser-pack/_prelude.js","src/Array.js"],"names":[],"mappings":"AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"y-array.es6","sourceRoot":"/source/","sourcesContent":["(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 {\r\n var userEvents = []\r\n for (var i in ops) {\r\n var op = ops[i]\r\n if (op.struct === 'Insert') {\r\n let pos\r\n // we check op.left only!,\r\n // because op.right might not be defined when this is called\r\n if (op.left === null) {\r\n pos = 0\r\n } else {\r\n var sid = JSON.stringify(op.left)\r\n pos = this.idArray.indexOf(sid) + 1\r\n if (pos <= 0) {\r\n throw new Error('Unexpected operation!')\r\n }\r\n }\r\n this.idArray.splice(pos, 0, JSON.stringify(op.id))\r\n this.valArray.splice(pos, 0, op.content)\r\n userEvents.push({\r\n type: 'insert',\r\n object: this,\r\n index: pos,\r\n value: op.content,\r\n length: 1\r\n })\r\n } else if (op.struct === 'Delete') {\r\n let pos = this.idArray.indexOf(JSON.stringify(op.target))\r\n if (pos >= 0) {\r\n var val = this.valArray[pos]\r\n this.idArray.splice(pos, 1)\r\n this.valArray.splice(pos, 1)\r\n userEvents.push({\r\n type: 'delete',\r\n object: this,\r\n index: pos,\r\n value: val,\r\n length: 1\r\n })\r\n }\r\n } else {\r\n throw new Error('Unexpected struct!')\r\n }\r\n }\r\n this.eventHandler.callEventListeners(userEvents)\r\n })\r\n }\r\n get length () {\r\n return this.idArray.length\r\n }\r\n get (pos) {\r\n if (pos == null || typeof pos !== 'number') {\r\n throw new Error('pos must be a number!')\r\n }\r\n return this.valArray[pos]\r\n }\r\n toArray () {\r\n return this.valArray.slice()\r\n }\r\n push (contents) {\r\n this.insert(this.idArray.length, contents)\r\n }\r\n insert (pos, contents) {\r\n if (typeof pos !== 'number') {\r\n throw new Error('pos must be a number!')\r\n }\r\n if (!(contents instanceof Array)) {\r\n throw new Error('contents must be an Array of objects!')\r\n }\r\n if (contents.length === 0) {\r\n return\r\n }\r\n if (pos > this.idArray.length || pos < 0) {\r\n throw new Error('This position exceeds the range of the array!')\r\n }\r\n var mostLeft = pos === 0 ? null : JSON.parse(this.idArray[pos - 1])\r\n\r\n var ops = []\r\n var prevId = mostLeft\r\n for (var i = 0; i < contents.length; i++) {\r\n var op = {\r\n left: prevId,\r\n origin: prevId,\r\n // right: mostRight,\r\n // NOTE: I intentionally do not define right here, because it could be deleted\r\n // at the time of creating this operation, and is therefore not defined in idArray\r\n parent: this._model,\r\n content: contents[i],\r\n struct: 'Insert',\r\n id: this.os.getNextOpId()\r\n }\r\n ops.push(op)\r\n prevId = op.id\r\n }\r\n var eventHandler = this.eventHandler\r\n eventHandler.awaitAndPrematurelyCall(ops)\r\n this.os.requestTransaction(function *() {\r\n // now we can set the right reference.\r\n var mostRight\r\n if (mostLeft != null) {\r\n mostRight = (yield* this.getOperation(mostLeft)).right\r\n } else {\r\n mostRight = (yield* this.getOperation(ops[0].parent)).start\r\n }\r\n for (var j in ops) {\r\n ops[j].right = mostRight\r\n }\r\n yield* this.applyCreatedOperations(ops)\r\n eventHandler.awaitedInserts(ops.length)\r\n })\r\n }\r\n delete (pos, length) {\r\n if (length == null) { length = 1 }\r\n if (typeof length !== 'number') {\r\n throw new Error('pos must be a number!')\r\n }\r\n if (typeof pos !== 'number') {\r\n throw new Error('pos must be a number!')\r\n }\r\n if (pos + length > this.idArray.length || pos < 0 || length < 0) {\r\n throw new Error('The deletion range exceeds the range of the array!')\r\n }\r\n if (length === 0) {\r\n return\r\n }\r\n var eventHandler = this.eventHandler\r\n var newLeft = pos > 0 ? JSON.parse(this.idArray[pos - 1]) : null\r\n var dels = []\r\n for (var i = 0; i < length; i++) {\r\n dels.push({\r\n target: JSON.parse(this.idArray[pos + i]),\r\n struct: 'Delete'\r\n })\r\n }\r\n eventHandler.awaitAndPrematurelyCall(dels)\r\n this.os.requestTransaction(function *() {\r\n yield* this.applyCreatedOperations(dels)\r\n eventHandler.awaitedDeletes(dels.length, newLeft)\r\n })\r\n }\r\n observe (f) {\r\n this.eventHandler.addEventListener(f)\r\n }\r\n * _changed (transaction, op) {\r\n if (!op.deleted) {\r\n if (op.struct === 'Insert') {\r\n var l = op.left\r\n var left\r\n while (l != null) {\r\n left = yield* transaction.getOperation(l)\r\n if (!left.deleted) {\r\n break\r\n }\r\n l = left.left\r\n }\r\n op.left = l\r\n }\r\n this.eventHandler.receivedOp(op)\r\n }\r\n }\r\n }\r\n\r\n Y.extend('Array', new Y.utils.CustomType({\r\n name: 'Array', // TODO: copy the name when extending the object.. (see one line above)\r\n class: YArray,\r\n struct: 'List',\r\n initType: function * YArrayInitializer (os, model) {\r\n var valArray = []\r\n var idArray = yield* Y.Struct.List.map.call(this, model, function (c) {\r\n valArray.push(c.content)\r\n return JSON.stringify(c.id)\r\n })\r\n return new YArray(os, model.id, idArray, valArray)\r\n }\r\n }))\r\n}\r\n\r\nmodule.exports = extend\r\nif (typeof Y !== 'undefined') {\r\n extend(Y)\r\n}\r\n"]} \ No newline at end of file diff --git a/Examples/bower_components/y-array/y-array.js b/Examples/bower_components/y-array/y-array.js new file mode 100644 index 00000000..5df139ed --- /dev/null +++ b/Examples/bower_components/y-array/y-array.js @@ -0,0 +1,2 @@ +!function e(r,t,n){function a(s,o){if(!t[s]){if(!r[s]){var u="function"==typeof require&&require;if(!o&&u)return u(s,!0);if(i)return i(s,!0);var l=new Error("Cannot find module '"+s+"'");throw l.code="MODULE_NOT_FOUND",l}var c=t[s]={exports:{}};r[s][0].call(c.exports,function(e){var t=r[s][1][e];return a(t?t:e)},c,c.exports,e,r,t,n)}return t[s].exports}for(var i="function"==typeof require&&require,s=0;s=a)throw new Error("Unexpected operation!")}o.idArray.splice(a,0,JSON.stringify(n.id)),o.valArray.splice(a,0,n.content),r.push({type:"insert",object:o,index:a,value:n.content,length:1})}else{if("Delete"!==n.struct)throw new Error("Unexpected struct!");var a=o.idArray.indexOf(JSON.stringify(n.target));if(a>=0){var s=o.valArray[a];o.idArray.splice(a,1),o.valArray.splice(a,1),r.push({type:"delete",object:o,index:a,value:s,length:1})}}}o.eventHandler.callEventListeners(r)})}return i(r,[{key:"get",value:function(e){if(null==e||"number"!=typeof e)throw new Error("pos must be a number!");return this.valArray[e]}},{key:"toArray",value:function(){return this.valArray.slice()}},{key:"push",value:function(e){this.insert(this.idArray.length,e)}},{key:"insert",value:function(e,r){if("number"!=typeof e)throw new Error("pos must be a number!");if(!(r instanceof Array))throw new Error("contents must be an Array of objects!");if(0!==r.length){if(e>this.idArray.length||0>e)throw new Error("This position exceeds the range of the array!");for(var t=0===e?null:JSON.parse(this.idArray[e-1]),n=[],a=t,i=0;ithis.idArray.length||0>e||0>r)throw new Error("The deletion range exceeds the range of the array!");if(0!==r){for(var t=this.eventHandler,n=e>0?JSON.parse(this.idArray[e-1]):null,a=[],i=0;r>i;i++)a.push({target:JSON.parse(this.idArray[e+i]),struct:"Delete"});t.awaitAndPrematurelyCall(a),this.os.requestTransaction(regeneratorRuntime.mark(function s(){return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.delegateYield(this.applyCreatedOperations(a),"t0",1);case 1:t.awaitedDeletes(a.length,n);case 2:case"end":return e.stop()}},s,this)}))}}},{key:"observe",value:function(e){this.eventHandler.addEventListener(e)}},{key:"_changed",value:regeneratorRuntime.mark(function t(e,r){var n,a;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:if(r.deleted){t.next=13;break}if("Insert"!==r.struct){t.next=12;break}n=r.left;case 3:if(null==n){t.next=11;break}return t.delegateYield(e.getOperation(n),"t0",5);case 5:if(a=t.t0,a.deleted){t.next=8;break}return t.abrupt("break",11);case 8:n=a.left,t.next=3;break;case 11:r.left=n;case 12:this.eventHandler.receivedOp(r);case 13:case"end":return t.stop()}},t,this)})},{key:"length",get:function(){return this.idArray.length}}]),r}();e.extend("Array",new e.utils.CustomType({name:"Array","class":r,struct:"List",initType:regeneratorRuntime.mark(function t(n,a){var i,s;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return i=[],t.delegateYield(e.Struct.List.map.call(this,a,function(e){return i.push(e.content),JSON.stringify(e.id)}),"t0",2);case 2:return s=t.t0,t.abrupt("return",new r(n,a.id,s,i));case 4:case"end":return t.stop()}},t,this)})}))}var i=function(){function e(e,r){for(var t=0;t {\r\n var userEvents = []\r\n for (var i in ops) {\r\n var op = ops[i]\r\n if (op.struct === 'Insert') {\r\n let pos\r\n // we check op.left only!,\r\n // because op.right might not be defined when this is called\r\n if (op.left === null) {\r\n pos = 0\r\n } else {\r\n var sid = JSON.stringify(op.left)\r\n pos = this.idArray.indexOf(sid) + 1\r\n if (pos <= 0) {\r\n throw new Error('Unexpected operation!')\r\n }\r\n }\r\n this.idArray.splice(pos, 0, JSON.stringify(op.id))\r\n this.valArray.splice(pos, 0, op.content)\r\n userEvents.push({\r\n type: 'insert',\r\n object: this,\r\n index: pos,\r\n value: op.content,\r\n length: 1\r\n })\r\n } else if (op.struct === 'Delete') {\r\n let pos = this.idArray.indexOf(JSON.stringify(op.target))\r\n if (pos >= 0) {\r\n var val = this.valArray[pos]\r\n this.idArray.splice(pos, 1)\r\n this.valArray.splice(pos, 1)\r\n userEvents.push({\r\n type: 'delete',\r\n object: this,\r\n index: pos,\r\n value: val,\r\n length: 1\r\n })\r\n }\r\n } else {\r\n throw new Error('Unexpected struct!')\r\n }\r\n }\r\n this.eventHandler.callEventListeners(userEvents)\r\n })\r\n }\r\n get length () {\r\n return this.idArray.length\r\n }\r\n get (pos) {\r\n if (pos == null || typeof pos !== 'number') {\r\n throw new Error('pos must be a number!')\r\n }\r\n return this.valArray[pos]\r\n }\r\n toArray () {\r\n return this.valArray.slice()\r\n }\r\n push (contents) {\r\n this.insert(this.idArray.length, contents)\r\n }\r\n insert (pos, contents) {\r\n if (typeof pos !== 'number') {\r\n throw new Error('pos must be a number!')\r\n }\r\n if (!(contents instanceof Array)) {\r\n throw new Error('contents must be an Array of objects!')\r\n }\r\n if (contents.length === 0) {\r\n return\r\n }\r\n if (pos > this.idArray.length || pos < 0) {\r\n throw new Error('This position exceeds the range of the array!')\r\n }\r\n var mostLeft = pos === 0 ? null : JSON.parse(this.idArray[pos - 1])\r\n\r\n var ops = []\r\n var prevId = mostLeft\r\n for (var i = 0; i < contents.length; i++) {\r\n var op = {\r\n left: prevId,\r\n origin: prevId,\r\n // right: mostRight,\r\n // NOTE: I intentionally do not define right here, because it could be deleted\r\n // at the time of creating this operation, and is therefore not defined in idArray\r\n parent: this._model,\r\n content: contents[i],\r\n struct: 'Insert',\r\n id: this.os.getNextOpId()\r\n }\r\n ops.push(op)\r\n prevId = op.id\r\n }\r\n var eventHandler = this.eventHandler\r\n eventHandler.awaitAndPrematurelyCall(ops)\r\n this.os.requestTransaction(function *() {\r\n // now we can set the right reference.\r\n var mostRight\r\n if (mostLeft != null) {\r\n mostRight = (yield* this.getOperation(mostLeft)).right\r\n } else {\r\n mostRight = (yield* this.getOperation(ops[0].parent)).start\r\n }\r\n for (var j in ops) {\r\n ops[j].right = mostRight\r\n }\r\n yield* this.applyCreatedOperations(ops)\r\n eventHandler.awaitedInserts(ops.length)\r\n })\r\n }\r\n delete (pos, length) {\r\n if (length == null) { length = 1 }\r\n if (typeof length !== 'number') {\r\n throw new Error('pos must be a number!')\r\n }\r\n if (typeof pos !== 'number') {\r\n throw new Error('pos must be a number!')\r\n }\r\n if (pos + length > this.idArray.length || pos < 0 || length < 0) {\r\n throw new Error('The deletion range exceeds the range of the array!')\r\n }\r\n if (length === 0) {\r\n return\r\n }\r\n var eventHandler = this.eventHandler\r\n var newLeft = pos > 0 ? JSON.parse(this.idArray[pos - 1]) : null\r\n var dels = []\r\n for (var i = 0; i < length; i++) {\r\n dels.push({\r\n target: JSON.parse(this.idArray[pos + i]),\r\n struct: 'Delete'\r\n })\r\n }\r\n eventHandler.awaitAndPrematurelyCall(dels)\r\n this.os.requestTransaction(function *() {\r\n yield* this.applyCreatedOperations(dels)\r\n eventHandler.awaitedDeletes(dels.length, newLeft)\r\n })\r\n }\r\n observe (f) {\r\n this.eventHandler.addEventListener(f)\r\n }\r\n * _changed (transaction, op) {\r\n if (!op.deleted) {\r\n if (op.struct === 'Insert') {\r\n var l = op.left\r\n var left\r\n while (l != null) {\r\n left = yield* transaction.getOperation(l)\r\n if (!left.deleted) {\r\n break\r\n }\r\n l = left.left\r\n }\r\n op.left = l\r\n }\r\n this.eventHandler.receivedOp(op)\r\n }\r\n }\r\n }\r\n\r\n Y.extend('Array', new Y.utils.CustomType({\r\n name: 'Array', // TODO: copy the name when extending the object.. (see one line above)\r\n class: YArray,\r\n struct: 'List',\r\n initType: function * YArrayInitializer (os, model) {\r\n var valArray = []\r\n var idArray = yield* Y.Struct.List.map.call(this, model, function (c) {\r\n valArray.push(c.content)\r\n return JSON.stringify(c.id)\r\n })\r\n return new YArray(os, model.id, idArray, valArray)\r\n }\r\n }))\r\n}\r\n\r\nmodule.exports = extend\r\nif (typeof Y !== 'undefined') {\r\n extend(Y)\r\n}\r\n","(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= 0) {\n var val = _this.valArray[pos];\n _this.idArray.splice(pos, 1);\n _this.valArray.splice(pos, 1);\n userEvents.push({\n type: 'delete',\n object: _this,\n index: pos,\n value: val,\n length: 1\n });\n }\n } else {\n throw new Error('Unexpected struct!');\n }\n }\n _this.eventHandler.callEventListeners(userEvents);\n });\n }\n\n _createClass(YArray, [{\n key: 'get',\n value: function get(pos) {\n if (pos == null || typeof pos !== 'number') {\n throw new Error('pos must be a number!');\n }\n return this.valArray[pos];\n }\n }, {\n key: 'toArray',\n value: function toArray() {\n return this.valArray.slice();\n }\n }, {\n key: 'push',\n value: function push(contents) {\n this.insert(this.idArray.length, contents);\n }\n }, {\n key: 'insert',\n value: function insert(pos, contents) {\n if (typeof pos !== 'number') {\n throw new Error('pos must be a number!');\n }\n if (!(contents instanceof Array)) {\n throw new Error('contents must be an Array of objects!');\n }\n if (contents.length === 0) {\n return;\n }\n if (pos > this.idArray.length || pos < 0) {\n throw new Error('This position exceeds the range of the array!');\n }\n var mostLeft = pos === 0 ? null : JSON.parse(this.idArray[pos - 1]);\n\n var ops = [];\n var prevId = mostLeft;\n for (var i = 0; i < contents.length; i++) {\n var op = {\n left: prevId,\n origin: prevId,\n // right: mostRight,\n // NOTE: I intentionally do not define right here, because it could be deleted\n // at the time of creating this operation, and is therefore not defined in idArray\n parent: this._model,\n content: contents[i],\n struct: 'Insert',\n id: this.os.getNextOpId()\n };\n ops.push(op);\n prevId = op.id;\n }\n var eventHandler = this.eventHandler;\n eventHandler.awaitAndPrematurelyCall(ops);\n this.os.requestTransaction(regeneratorRuntime.mark(function _callee() {\n var mostRight, j;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n if (!(mostLeft != null)) {\n _context.next = 5;\n break;\n }\n\n return _context.delegateYield(this.getOperation(mostLeft), 't0', 2);\n\n case 2:\n mostRight = _context.t0.right;\n _context.next = 7;\n break;\n\n case 5:\n return _context.delegateYield(this.getOperation(ops[0].parent), 't1', 6);\n\n case 6:\n mostRight = _context.t1.start;\n\n case 7:\n for (j in ops) {\n ops[j].right = mostRight;\n }\n return _context.delegateYield(this.applyCreatedOperations(ops), 't2', 9);\n\n case 9:\n eventHandler.awaitedInserts(ops.length);\n\n case 10:\n case 'end':\n return _context.stop();\n }\n }\n }, _callee, this);\n }));\n }\n }, {\n key: 'delete',\n value: function _delete(pos, length) {\n if (length == null) {\n length = 1;\n }\n if (typeof length !== 'number') {\n throw new Error('pos must be a number!');\n }\n if (typeof pos !== 'number') {\n throw new Error('pos must be a number!');\n }\n if (pos + length > this.idArray.length || pos < 0 || length < 0) {\n throw new Error('The deletion range exceeds the range of the array!');\n }\n if (length === 0) {\n return;\n }\n var eventHandler = this.eventHandler;\n var newLeft = pos > 0 ? JSON.parse(this.idArray[pos - 1]) : null;\n var dels = [];\n for (var i = 0; i < length; i++) {\n dels.push({\n target: JSON.parse(this.idArray[pos + i]),\n struct: 'Delete'\n });\n }\n eventHandler.awaitAndPrematurelyCall(dels);\n this.os.requestTransaction(regeneratorRuntime.mark(function _callee2() {\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n return _context2.delegateYield(this.applyCreatedOperations(dels), 't0', 1);\n\n case 1:\n eventHandler.awaitedDeletes(dels.length, newLeft);\n\n case 2:\n case 'end':\n return _context2.stop();\n }\n }\n }, _callee2, this);\n }));\n }\n }, {\n key: 'observe',\n value: function observe(f) {\n this.eventHandler.addEventListener(f);\n }\n }, {\n key: '_changed',\n value: regeneratorRuntime.mark(function _changed(transaction, op) {\n var l, left;\n return regeneratorRuntime.wrap(function _changed$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n if (op.deleted) {\n _context3.next = 13;\n break;\n }\n\n if (!(op.struct === 'Insert')) {\n _context3.next = 12;\n break;\n }\n\n l = op.left;\n\n case 3:\n if (!(l != null)) {\n _context3.next = 11;\n break;\n }\n\n return _context3.delegateYield(transaction.getOperation(l), 't0', 5);\n\n case 5:\n left = _context3.t0;\n\n if (left.deleted) {\n _context3.next = 8;\n break;\n }\n\n return _context3.abrupt('break', 11);\n\n case 8:\n l = left.left;\n _context3.next = 3;\n break;\n\n case 11:\n op.left = l;\n\n case 12:\n this.eventHandler.receivedOp(op);\n\n case 13:\n case 'end':\n return _context3.stop();\n }\n }\n }, _changed, this);\n })\n }, {\n key: 'length',\n get: function get() {\n return this.idArray.length;\n }\n }]);\n\n return YArray;\n }();\n\n Y.extend('Array', new Y.utils.CustomType({\n name: 'Array', // TODO: copy the name when extending the object.. (see one line above)\n class: YArray,\n struct: 'List',\n initType: regeneratorRuntime.mark(function YArrayInitializer(os, model) {\n var valArray, idArray;\n return regeneratorRuntime.wrap(function YArrayInitializer$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n valArray = [];\n return _context4.delegateYield(Y.Struct.List.map.call(this, model, function (c) {\n valArray.push(c.content);\n return JSON.stringify(c.id);\n }), 't0', 2);\n\n case 2:\n idArray = _context4.t0;\n return _context4.abrupt('return', new YArray(os, model.id, idArray, valArray));\n\n case 4:\n case 'end':\n return _context4.stop();\n }\n }\n }, YArrayInitializer, this);\n })\n }));\n}\n\nmodule.exports = extend;\nif (typeof Y !== 'undefined') {\n extend(Y);\n}\n\n},{}]},{},[1])\n\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/Examples/bower_components/y-indexeddb/.bower.json b/Examples/bower_components/y-indexeddb/.bower.json new file mode 100644 index 00000000..e8620006 --- /dev/null +++ b/Examples/bower_components/y-indexeddb/.bower.json @@ -0,0 +1,37 @@ +{ + "name": "y-indexeddb", + "main": "y-indexeddb.js", + "version": "0.7.1", + "homepage": "http://y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "IndexedDB database adapter for Yjs", + "moduleType": [ + "globals", + "node" + ], + "keywords": [ + "Yjs", + "connector", + "webrtc" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "_release": "0.7.1", + "_resolution": { + "type": "version", + "tag": "v0.7.1", + "commit": "f84233467fbf2f15a0bb74f34902d33f2790b9e3" + }, + "_source": "git://github.com/y-js/y-indexeddb.git", + "_target": "~0.7.1", + "_originalSource": "y-indexeddb", + "_direct": true +} \ No newline at end of file diff --git a/Examples/bower_components/y-indexeddb/LICENSE b/Examples/bower_components/y-indexeddb/LICENSE new file mode 100644 index 00000000..c8c5c6da --- /dev/null +++ b/Examples/bower_components/y-indexeddb/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2014 + - Kevin Jahns . + - Chair of Computer Science 5 (Databases & Information Systems), RWTH Aachen University, Germany + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Examples/bower_components/y-indexeddb/README.md b/Examples/bower_components/y-indexeddb/README.md new file mode 100644 index 00000000..6b987da5 --- /dev/null +++ b/Examples/bower_components/y-indexeddb/README.md @@ -0,0 +1 @@ +# IndexedDB database adapter for Yjs diff --git a/Examples/bower_components/y-indexeddb/bower.json b/Examples/bower_components/y-indexeddb/bower.json new file mode 100644 index 00000000..1c3366dc --- /dev/null +++ b/Examples/bower_components/y-indexeddb/bower.json @@ -0,0 +1,27 @@ +{ + "name": "y-indexeddb", + "main": "y-indexeddb.js", + "version": "0.7.1", + "homepage": "http://y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "IndexedDB database adapter for Yjs", + "moduleType": [ + "globals", + "node" + ], + "keywords": [ + "Yjs", + "connector", + "webrtc" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} diff --git a/Examples/bower_components/y-indexeddb/y-indexeddb.es6 b/Examples/bower_components/y-indexeddb/y-indexeddb.es6 new file mode 100644 index 00000000..612503b0 --- /dev/null +++ b/Examples/bower_components/y-indexeddb/y-indexeddb.es6 @@ -0,0 +1,189 @@ +(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" + ], + "description": "Map type for Yjs", + "main": [ + "./y-list.js", + "./build/node/y-list.js" + ], + "keywords": [ + "OT", + "collaboration", + "synchronization", + "ShareJS", + "Coweb", + "concurrency" + ], + "license": "MIT", + "ignore": [ + "node_modules", + "bower_components", + "test", + "extras", + "test" + ], + "_release": "0.7.2", + "_resolution": { + "type": "version", + "tag": "v0.7.2", + "commit": "1d85b5890ce8d76a37c5f8ad2587ca8ec7e82cbc" + }, + "_source": "git://github.com/y-js/y-map.git", + "_target": "~0.7.2", + "_originalSource": "y-map", + "_direct": true +} \ No newline at end of file diff --git a/Examples/bower_components/y-map/README.md b/Examples/bower_components/y-map/README.md new file mode 100644 index 00000000..e69de29b diff --git a/Examples/bower_components/y-map/bower.json b/Examples/bower_components/y-map/bower.json new file mode 100644 index 00000000..a6ca81b4 --- /dev/null +++ b/Examples/bower_components/y-map/bower.json @@ -0,0 +1,29 @@ +{ + "name": "y-map", + "version": "0.7.3", + "homepage": "http://y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "Map type for Yjs", + "main": [ + "./y-list.js", + "./build/node/y-list.js" + ], + "keywords": [ + "OT", + "collaboration", + "synchronization", + "ShareJS", + "Coweb", + "concurrency" + ], + "license": "MIT", + "ignore": [ + "node_modules", + "bower_components", + "test", + "extras", + "test" + ] +} diff --git a/Examples/bower_components/y-map/package.json b/Examples/bower_components/y-map/package.json new file mode 100644 index 00000000..12aa356a --- /dev/null +++ b/Examples/bower_components/y-map/package.json @@ -0,0 +1,56 @@ +{ + "name": "map", + "version": "0.7.3", + "description": "Map Type for Yjs", + "main": "./src/Map.js", + "scripts": { + "test": "node --harmony ./node_modules/.bin/gulp test", + "lint": "./node_modules/.bin/standard" + }, + "pre-commit": [ + "lint", + "test" + ], + "standard": { + "parser": "babel-eslint", + "ignore": [ + "build/**", + "dist/**", + "./y.js", + "./y.js.map" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/y-js/map" + }, + "keywords": [ + "Yjs", + "OT", + "List", + "Array", + "collaboration", + "synchronization", + "ShareJs", + "Coweb", + "concurrency" + ], + "author": "Kevin Jahns ", + "license": "MIT", + "bugs": { + "url": "https://github.com/y-js/yjs/issues" + }, + "homepage": "http://y-js.org", + "devDependencies": { + "babel-eslint": "^4.1.4", + "babel-plugin-transform-runtime": "^6.1.18", + "babel-preset-es2015": "^6.1.18", + "babelify": "^7.2.0", + "gulp": "^3.9.0", + "gulp-load-plugins": "^1.1.0", + "gulp-prompt": "^0.1.2", + "pre-commit": "^1.1.2", + "run-sequence": "^1.1.4", + "standard": "^5.3.1" + } +} diff --git a/Examples/bower_components/y-map/y-map.es6 b/Examples/bower_components/y-map/y-map.es6 new file mode 100644 index 00000000..2da80440 --- /dev/null +++ b/Examples/bower_components/y-map/y-map.es6 @@ -0,0 +1,315 @@ +(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 { + var userEvents = [] + for (var i in ops) { + var op = ops[i] + var oldValue + // key is the name to use to access (op)content + var key = op.struct === 'Delete' ? op.key : op.parentSub + + // compute oldValue + if (this.opContents[key] != null) { + let prevType = this.opContents[key] + oldValue = () => {// eslint-disable-line + return new Promise((resolve) => { + this.os.requestTransaction(function *() {// eslint-disable-line + var type = yield* this.getType(prevType) + resolve(type) + }) + }) + } + } else { + oldValue = this.contents[key] + } + // compute op event + if (op.struct === 'Insert') { + if (op.left === null) { + if (op.opContent != null) { + delete this.contents[key] + if (op.deleted) { + delete this.opContents[key] + } else { + this.opContents[key] = op.opContent + } + } else { + delete this.opContents[key] + if (op.deleted) { + delete this.contents[key] + } else { + this.contents[key] = op.content + } + } + this.map[key] = op.id + var insertEvent + if (oldValue === undefined) { + insertEvent = { + name: key, + object: this, + type: 'add' + } + } else { + insertEvent = { + name: key, + object: this, + oldValue: oldValue, + type: 'update' + } + } + userEvents.push(insertEvent) + } + } else if (op.struct === 'Delete') { + if (Y.utils.compareIds(this.map[key], op.target)) { + delete this.opContents[key] + delete this.contents[key] + var deleteEvent = { + name: key, + object: this, + oldValue: oldValue, + type: 'delete' + } + userEvents.push(deleteEvent) + } + } else { + throw new Error('Unexpected Operation!') + } + } + if (userEvents.length > 0) { + this.eventHandler.callEventListeners(userEvents) + } + }) + } + get (key) { + // return property. + // if property does not exist, return null + // if property is a type, return a promise + if (key == null) { + throw new Error('You must specify key!') + } + if (this.opContents[key] == null) { + return this.contents[key] + } else { + return new Promise((resolve) => { + var oid = this.opContents[key] + this.os.requestTransaction(function *() { + var type = yield* this.getType(oid) + resolve(type) + }) + }) + } + } + /* + If there is a primitive (not a custom type), then return it. + Returns all primitive values, if propertyName is specified! + Note: modifying the return value could result in inconsistencies! + -- so make sure to copy it first! + */ + getPrimitive (key) { + if (key == null) { + return Y.utils.copyObject(this.contents) + } else { + return this.contents[key] + } + } + delete (key) { + var right = this.map[key] + if (right != null) { + var del = { + target: right, + struct: 'Delete' + } + var eventHandler = this.eventHandler + var modDel = Y.utils.copyObject(del) + modDel.key = key + eventHandler.awaitAndPrematurelyCall([modDel]) + this.os.requestTransaction(function *() { + yield* this.applyCreatedOperations([del]) + eventHandler.awaitedDeletes(1) + }) + } + } + set (key, value) { + // set property. + // if property is a type, return a promise + // if not, apply immediately on this type an call event + + var right = this.map[key] || null + var insert /* :any */ = { + left: null, + right: right, + origin: null, + parent: this._model, + parentSub: key, + struct: 'Insert' + } + return new Promise((resolve) => { + if (value instanceof Y.utils.CustomType) { + // construct a new type + this.os.requestTransaction(function *() { + var type = yield* this.createType(value) + insert.opContent = type._model + insert.id = this.store.getNextOpId() + yield* this.applyCreatedOperations([insert]) + resolve(type) + }) + } else { + insert.content = value + insert.id = this.os.getNextOpId() + var eventHandler = this.eventHandler + eventHandler.awaitAndPrematurelyCall([insert]) + this.os.requestTransaction(function *() { + yield* this.applyCreatedOperations([insert]) + eventHandler.awaitedInserts(1) + }) + resolve(value) + } + }) + } + observe (f) { + this.eventHandler.addEventListener(f) + } + unobserve (f) { + this.eventHandler.removeEventListener(f) + } + /* + Observe a path. + + E.g. + ``` + o.set('textarea', Y.TextBind) + o.observePath(['textarea'], function(t){ + // is called whenever textarea is replaced + t.bind(textarea) + }) + + returns a Promise that contains a function that removes the observer from the path. + */ + observePath (path, f) { + var self = this + function observeProperty (events) { + // call f whenever path changes + for (var i = 0; i < events.length; i++) { + var event = events[i] + if (event.name === propertyName) { + // call this also for delete events! + var property = self.get(propertyName) + if (property instanceof Promise) { + property.then(f) + } else { + f(property) + } + } + } + } + + if (path.length < 1) { + throw new Error('Path must contain at least one element!') + } else if (path.length === 1) { + var propertyName = path[0] + var property = self.get(propertyName) + if (property instanceof Promise) { + property.then(f) + } else { + f(property) + } + this.observe(observeProperty) + return Promise.resolve(function () { + self.unobserve(f) + }) + } else { + var deleteChildObservers + var resetObserverPath = function () { + var promise = self.get(path[0]) + if (!promise instanceof Promise) { + // its either not defined or a primitive value + promise = self.set(path[0], Y.Map) + } + return promise.then(function (map) { + return map.observePath(path.slice(1), f) + }).then(function (_deleteChildObservers) { + // update deleteChildObservers + deleteChildObservers = _deleteChildObservers + return Promise.resolve() // Promise does not return anything + }) + } + var observer = function (events) { + for (var e in events) { + var event = events[e] + if (event.name === path[0]) { + if (deleteChildObservers != null) { + deleteChildObservers() + } + if (event.type === 'add' || event.type === 'update') { + resetObserverPath() + } + // TODO: what about the delete events? + } + } + } + self.observe(observer) + return resetObserverPath().then( + // this promise contains a function that deletes all the child observers + // and how to unobserve the observe from this object + new Promise.resolve(function () { // eslint-disable-line + if (deleteChildObservers != null) { + deleteChildObservers() + } + self.unobserve(observer) + }) + ) + } + } + * _changed (transaction, op) { + if (op.struct === 'Delete') { + var target = yield* transaction.getOperation(op.target) + op.key = target.parentSub + } + this.eventHandler.receivedOp(op) + } + } + Y.extend('Map', new Y.utils.CustomType({ + name: 'Map', + class: YMap, + struct: 'Map', + initType: function * YMapInitializer (os, model) { + var contents = {} + var opContents = {} + var map = model.map + for (var name in map) { + var op = yield* this.getOperation(map[name]) + if (op.opContent != null) { + opContents[name] = op.opContent + } else { + contents[name] = op.content + } + } + return new YMap(os, model, contents, opContents) + } + })) +} + +module.exports = extend +if (typeof Y !== 'undefined') { + extend(Y) +} + +},{}]},{},[1]) + diff --git a/Examples/bower_components/y-map/y-map.es6.map b/Examples/bower_components/y-map/y-map.es6.map new file mode 100644 index 00000000..e9ad8505 --- /dev/null +++ b/Examples/bower_components/y-map/y-map.es6.map @@ -0,0 +1 @@ +{"version":3,"sources":["../yjs/node_modules/browser-pack/_prelude.js","src/Map.js"],"names":[],"mappings":"AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"y-map.es6","sourceRoot":"/source/","sourcesContent":["(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 {\r\n var userEvents = []\r\n for (var i in ops) {\r\n var op = ops[i]\r\n var oldValue\r\n // key is the name to use to access (op)content\r\n var key = op.struct === 'Delete' ? op.key : op.parentSub\r\n\r\n // compute oldValue\r\n if (this.opContents[key] != null) {\r\n let prevType = this.opContents[key]\r\n oldValue = () => {// eslint-disable-line\r\n return new Promise((resolve) => {\r\n this.os.requestTransaction(function *() {// eslint-disable-line\r\n var type = yield* this.getType(prevType)\r\n resolve(type)\r\n })\r\n })\r\n }\r\n } else {\r\n oldValue = this.contents[key]\r\n }\r\n // compute op event\r\n if (op.struct === 'Insert') {\r\n if (op.left === null) {\r\n if (op.opContent != null) {\r\n delete this.contents[key]\r\n if (op.deleted) {\r\n delete this.opContents[key]\r\n } else {\r\n this.opContents[key] = op.opContent\r\n }\r\n } else {\r\n delete this.opContents[key]\r\n if (op.deleted) {\r\n delete this.contents[key]\r\n } else {\r\n this.contents[key] = op.content\r\n }\r\n }\r\n this.map[key] = op.id\r\n var insertEvent\r\n if (oldValue === undefined) {\r\n insertEvent = {\r\n name: key,\r\n object: this,\r\n type: 'add'\r\n }\r\n } else {\r\n insertEvent = {\r\n name: key,\r\n object: this,\r\n oldValue: oldValue,\r\n type: 'update'\r\n }\r\n }\r\n userEvents.push(insertEvent)\r\n }\r\n } else if (op.struct === 'Delete') {\r\n if (Y.utils.compareIds(this.map[key], op.target)) {\r\n delete this.opContents[key]\r\n delete this.contents[key]\r\n var deleteEvent = {\r\n name: key,\r\n object: this,\r\n oldValue: oldValue,\r\n type: 'delete'\r\n }\r\n userEvents.push(deleteEvent)\r\n }\r\n } else {\r\n throw new Error('Unexpected Operation!')\r\n }\r\n }\r\n if (userEvents.length > 0) {\r\n this.eventHandler.callEventListeners(userEvents)\r\n }\r\n })\r\n }\r\n get (key) {\r\n // return property.\r\n // if property does not exist, return null\r\n // if property is a type, return a promise\r\n if (key == null) {\r\n throw new Error('You must specify key!')\r\n }\r\n if (this.opContents[key] == null) {\r\n return this.contents[key]\r\n } else {\r\n return new Promise((resolve) => {\r\n var oid = this.opContents[key]\r\n this.os.requestTransaction(function *() {\r\n var type = yield* this.getType(oid)\r\n resolve(type)\r\n })\r\n })\r\n }\r\n }\r\n /*\r\n If there is a primitive (not a custom type), then return it.\r\n Returns all primitive values, if propertyName is specified!\r\n Note: modifying the return value could result in inconsistencies!\r\n -- so make sure to copy it first!\r\n */\r\n getPrimitive (key) {\r\n if (key == null) {\r\n return Y.utils.copyObject(this.contents)\r\n } else {\r\n return this.contents[key]\r\n }\r\n }\r\n delete (key) {\r\n var right = this.map[key]\r\n if (right != null) {\r\n var del = {\r\n target: right,\r\n struct: 'Delete'\r\n }\r\n var eventHandler = this.eventHandler\r\n var modDel = Y.utils.copyObject(del)\r\n modDel.key = key\r\n eventHandler.awaitAndPrematurelyCall([modDel])\r\n this.os.requestTransaction(function *() {\r\n yield* this.applyCreatedOperations([del])\r\n eventHandler.awaitedDeletes(1)\r\n })\r\n }\r\n }\r\n set (key, value) {\r\n // set property.\r\n // if property is a type, return a promise\r\n // if not, apply immediately on this type an call event\r\n\r\n var right = this.map[key] || null\r\n var insert /* :any */ = {\r\n left: null,\r\n right: right,\r\n origin: null,\r\n parent: this._model,\r\n parentSub: key,\r\n struct: 'Insert'\r\n }\r\n return new Promise((resolve) => {\r\n if (value instanceof Y.utils.CustomType) {\r\n // construct a new type\r\n this.os.requestTransaction(function *() {\r\n var type = yield* this.createType(value)\r\n insert.opContent = type._model\r\n insert.id = this.store.getNextOpId()\r\n yield* this.applyCreatedOperations([insert])\r\n resolve(type)\r\n })\r\n } else {\r\n insert.content = value\r\n insert.id = this.os.getNextOpId()\r\n var eventHandler = this.eventHandler\r\n eventHandler.awaitAndPrematurelyCall([insert])\r\n this.os.requestTransaction(function *() {\r\n yield* this.applyCreatedOperations([insert])\r\n eventHandler.awaitedInserts(1)\r\n })\r\n resolve(value)\r\n }\r\n })\r\n }\r\n observe (f) {\r\n this.eventHandler.addEventListener(f)\r\n }\r\n unobserve (f) {\r\n this.eventHandler.removeEventListener(f)\r\n }\r\n /*\r\n Observe a path.\r\n\r\n E.g.\r\n ```\r\n o.set('textarea', Y.TextBind)\r\n o.observePath(['textarea'], function(t){\r\n // is called whenever textarea is replaced\r\n t.bind(textarea)\r\n })\r\n\r\n returns a Promise that contains a function that removes the observer from the path.\r\n */\r\n observePath (path, f) {\r\n var self = this\r\n function observeProperty (events) {\r\n // call f whenever path changes\r\n for (var i = 0; i < events.length; i++) {\r\n var event = events[i]\r\n if (event.name === propertyName) {\r\n // call this also for delete events!\r\n var property = self.get(propertyName)\r\n if (property instanceof Promise) {\r\n property.then(f)\r\n } else {\r\n f(property)\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (path.length < 1) {\r\n throw new Error('Path must contain at least one element!')\r\n } else if (path.length === 1) {\r\n var propertyName = path[0]\r\n var property = self.get(propertyName)\r\n if (property instanceof Promise) {\r\n property.then(f)\r\n } else {\r\n f(property)\r\n }\r\n this.observe(observeProperty)\r\n return Promise.resolve(function () {\r\n self.unobserve(f)\r\n })\r\n } else {\r\n var deleteChildObservers\r\n var resetObserverPath = function () {\r\n var promise = self.get(path[0])\r\n if (!promise instanceof Promise) {\r\n // its either not defined or a primitive value\r\n promise = self.set(path[0], Y.Map)\r\n }\r\n return promise.then(function (map) {\r\n return map.observePath(path.slice(1), f)\r\n }).then(function (_deleteChildObservers) {\r\n // update deleteChildObservers\r\n deleteChildObservers = _deleteChildObservers\r\n return Promise.resolve() // Promise does not return anything\r\n })\r\n }\r\n var observer = function (events) {\r\n for (var e in events) {\r\n var event = events[e]\r\n if (event.name === path[0]) {\r\n if (deleteChildObservers != null) {\r\n deleteChildObservers()\r\n }\r\n if (event.type === 'add' || event.type === 'update') {\r\n resetObserverPath()\r\n }\r\n // TODO: what about the delete events?\r\n }\r\n }\r\n }\r\n self.observe(observer)\r\n return resetObserverPath().then(\r\n // this promise contains a function that deletes all the child observers\r\n // and how to unobserve the observe from this object\r\n new Promise.resolve(function () { // eslint-disable-line\r\n if (deleteChildObservers != null) {\r\n deleteChildObservers()\r\n }\r\n self.unobserve(observer)\r\n })\r\n )\r\n }\r\n }\r\n * _changed (transaction, op) {\r\n if (op.struct === 'Delete') {\r\n var target = yield* transaction.getOperation(op.target)\r\n op.key = target.parentSub\r\n }\r\n this.eventHandler.receivedOp(op)\r\n }\r\n }\r\n Y.extend('Map', new Y.utils.CustomType({\r\n name: 'Map',\r\n class: YMap,\r\n struct: 'Map',\r\n initType: function * YMapInitializer (os, model) {\r\n var contents = {}\r\n var opContents = {}\r\n var map = model.map\r\n for (var name in map) {\r\n var op = yield* this.getOperation(map[name])\r\n if (op.opContent != null) {\r\n opContents[name] = op.opContent\r\n } else {\r\n contents[name] = op.content\r\n }\r\n }\r\n return new YMap(os, model, contents, opContents)\r\n }\r\n }))\r\n}\r\n\r\nmodule.exports = extend\r\nif (typeof Y !== 'undefined') {\r\n extend(Y)\r\n}\r\n"]} \ No newline at end of file diff --git a/Examples/bower_components/y-map/y-map.js b/Examples/bower_components/y-map/y-map.js new file mode 100644 index 00000000..6ac82522 --- /dev/null +++ b/Examples/bower_components/y-map/y-map.js @@ -0,0 +1,2 @@ +!function e(t,n,r){function a(i,s){if(!n[i]){if(!t[i]){var u="function"==typeof require&&require;if(!s&&u)return u(i,!0);if(o)return o(i,!0);var c=new Error("Cannot find module '"+i+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[i]={exports:{}};t[i][0].call(l.exports,function(e){var n=t[i][1][e];return a(n?n:e)},l,l.exports,e,t,n,r)}return n[i].exports}for(var o="function"==typeof require&&require,i=0;i0&&s.eventHandler.callEventListeners(n)})}return o(t,[{key:"get",value:function(e){var t=this;if(null==e)throw new Error("You must specify key!");return null==this.opContents[e]?this.contents[e]:new Promise(function(n){var r=t.opContents[e];t.os.requestTransaction(regeneratorRuntime.mark(function a(){var e;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return t.delegateYield(this.getType(r),"t0",1);case 1:e=t.t0,n(e);case 3:case"end":return t.stop()}},a,this)}))})}},{key:"getPrimitive",value:function(t){return null==t?e.utils.copyObject(this.contents):this.contents[t]}},{key:"delete",value:function(t){var n=this.map[t];if(null!=n){var r={target:n,struct:"Delete"},a=this.eventHandler,o=e.utils.copyObject(r);o.key=t,a.awaitAndPrematurelyCall([o]),this.os.requestTransaction(regeneratorRuntime.mark(function i(){return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.delegateYield(this.applyCreatedOperations([r]),"t0",1);case 1:a.awaitedDeletes(1);case 2:case"end":return e.stop()}},i,this)}))}}},{key:"set",value:function(t,n){var r=this,a=this.map[t]||null,o={left:null,right:a,origin:null,parent:this._model,parentSub:t,struct:"Insert"};return new Promise(function(t){if(n instanceof e.utils.CustomType)r.os.requestTransaction(regeneratorRuntime.mark(function i(){var e;return regeneratorRuntime.wrap(function(r){for(;;)switch(r.prev=r.next){case 0:return r.delegateYield(this.createType(n),"t0",1);case 1:return e=r.t0,o.opContent=e._model,o.id=this.store.getNextOpId(),r.delegateYield(this.applyCreatedOperations([o]),"t1",5);case 5:t(e);case 6:case"end":return r.stop()}},i,this)}));else{o.content=n,o.id=r.os.getNextOpId();var a=r.eventHandler;a.awaitAndPrematurelyCall([o]),r.os.requestTransaction(regeneratorRuntime.mark(function s(){return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.delegateYield(this.applyCreatedOperations([o]),"t0",1);case 1:a.awaitedInserts(1);case 2:case"end":return e.stop()}},s,this)})),t(n)}})}},{key:"observe",value:function(e){this.eventHandler.addEventListener(e)}},{key:"unobserve",value:function(e){this.eventHandler.removeEventListener(e)}},{key:"observePath",value:function(t,n){function r(e){for(var t=0;t {\r\n var userEvents = []\r\n for (var i in ops) {\r\n var op = ops[i]\r\n var oldValue\r\n // key is the name to use to access (op)content\r\n var key = op.struct === 'Delete' ? op.key : op.parentSub\r\n\r\n // compute oldValue\r\n if (this.opContents[key] != null) {\r\n let prevType = this.opContents[key]\r\n oldValue = () => {// eslint-disable-line\r\n return new Promise((resolve) => {\r\n this.os.requestTransaction(function *() {// eslint-disable-line\r\n var type = yield* this.getType(prevType)\r\n resolve(type)\r\n })\r\n })\r\n }\r\n } else {\r\n oldValue = this.contents[key]\r\n }\r\n // compute op event\r\n if (op.struct === 'Insert') {\r\n if (op.left === null) {\r\n if (op.opContent != null) {\r\n delete this.contents[key]\r\n if (op.deleted) {\r\n delete this.opContents[key]\r\n } else {\r\n this.opContents[key] = op.opContent\r\n }\r\n } else {\r\n delete this.opContents[key]\r\n if (op.deleted) {\r\n delete this.contents[key]\r\n } else {\r\n this.contents[key] = op.content\r\n }\r\n }\r\n this.map[key] = op.id\r\n var insertEvent\r\n if (oldValue === undefined) {\r\n insertEvent = {\r\n name: key,\r\n object: this,\r\n type: 'add'\r\n }\r\n } else {\r\n insertEvent = {\r\n name: key,\r\n object: this,\r\n oldValue: oldValue,\r\n type: 'update'\r\n }\r\n }\r\n userEvents.push(insertEvent)\r\n }\r\n } else if (op.struct === 'Delete') {\r\n if (Y.utils.compareIds(this.map[key], op.target)) {\r\n delete this.opContents[key]\r\n delete this.contents[key]\r\n var deleteEvent = {\r\n name: key,\r\n object: this,\r\n oldValue: oldValue,\r\n type: 'delete'\r\n }\r\n userEvents.push(deleteEvent)\r\n }\r\n } else {\r\n throw new Error('Unexpected Operation!')\r\n }\r\n }\r\n if (userEvents.length > 0) {\r\n this.eventHandler.callEventListeners(userEvents)\r\n }\r\n })\r\n }\r\n get (key) {\r\n // return property.\r\n // if property does not exist, return null\r\n // if property is a type, return a promise\r\n if (key == null) {\r\n throw new Error('You must specify key!')\r\n }\r\n if (this.opContents[key] == null) {\r\n return this.contents[key]\r\n } else {\r\n return new Promise((resolve) => {\r\n var oid = this.opContents[key]\r\n this.os.requestTransaction(function *() {\r\n var type = yield* this.getType(oid)\r\n resolve(type)\r\n })\r\n })\r\n }\r\n }\r\n /*\r\n If there is a primitive (not a custom type), then return it.\r\n Returns all primitive values, if propertyName is specified!\r\n Note: modifying the return value could result in inconsistencies!\r\n -- so make sure to copy it first!\r\n */\r\n getPrimitive (key) {\r\n if (key == null) {\r\n return Y.utils.copyObject(this.contents)\r\n } else {\r\n return this.contents[key]\r\n }\r\n }\r\n delete (key) {\r\n var right = this.map[key]\r\n if (right != null) {\r\n var del = {\r\n target: right,\r\n struct: 'Delete'\r\n }\r\n var eventHandler = this.eventHandler\r\n var modDel = Y.utils.copyObject(del)\r\n modDel.key = key\r\n eventHandler.awaitAndPrematurelyCall([modDel])\r\n this.os.requestTransaction(function *() {\r\n yield* this.applyCreatedOperations([del])\r\n eventHandler.awaitedDeletes(1)\r\n })\r\n }\r\n }\r\n set (key, value) {\r\n // set property.\r\n // if property is a type, return a promise\r\n // if not, apply immediately on this type an call event\r\n\r\n var right = this.map[key] || null\r\n var insert /* :any */ = {\r\n left: null,\r\n right: right,\r\n origin: null,\r\n parent: this._model,\r\n parentSub: key,\r\n struct: 'Insert'\r\n }\r\n return new Promise((resolve) => {\r\n if (value instanceof Y.utils.CustomType) {\r\n // construct a new type\r\n this.os.requestTransaction(function *() {\r\n var type = yield* this.createType(value)\r\n insert.opContent = type._model\r\n insert.id = this.store.getNextOpId()\r\n yield* this.applyCreatedOperations([insert])\r\n resolve(type)\r\n })\r\n } else {\r\n insert.content = value\r\n insert.id = this.os.getNextOpId()\r\n var eventHandler = this.eventHandler\r\n eventHandler.awaitAndPrematurelyCall([insert])\r\n this.os.requestTransaction(function *() {\r\n yield* this.applyCreatedOperations([insert])\r\n eventHandler.awaitedInserts(1)\r\n })\r\n resolve(value)\r\n }\r\n })\r\n }\r\n observe (f) {\r\n this.eventHandler.addEventListener(f)\r\n }\r\n unobserve (f) {\r\n this.eventHandler.removeEventListener(f)\r\n }\r\n /*\r\n Observe a path.\r\n\r\n E.g.\r\n ```\r\n o.set('textarea', Y.TextBind)\r\n o.observePath(['textarea'], function(t){\r\n // is called whenever textarea is replaced\r\n t.bind(textarea)\r\n })\r\n\r\n returns a Promise that contains a function that removes the observer from the path.\r\n */\r\n observePath (path, f) {\r\n var self = this\r\n function observeProperty (events) {\r\n // call f whenever path changes\r\n for (var i = 0; i < events.length; i++) {\r\n var event = events[i]\r\n if (event.name === propertyName) {\r\n // call this also for delete events!\r\n var property = self.get(propertyName)\r\n if (property instanceof Promise) {\r\n property.then(f)\r\n } else {\r\n f(property)\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (path.length < 1) {\r\n throw new Error('Path must contain at least one element!')\r\n } else if (path.length === 1) {\r\n var propertyName = path[0]\r\n var property = self.get(propertyName)\r\n if (property instanceof Promise) {\r\n property.then(f)\r\n } else {\r\n f(property)\r\n }\r\n this.observe(observeProperty)\r\n return Promise.resolve(function () {\r\n self.unobserve(f)\r\n })\r\n } else {\r\n var deleteChildObservers\r\n var resetObserverPath = function () {\r\n var promise = self.get(path[0])\r\n if (!promise instanceof Promise) {\r\n // its either not defined or a primitive value\r\n promise = self.set(path[0], Y.Map)\r\n }\r\n return promise.then(function (map) {\r\n return map.observePath(path.slice(1), f)\r\n }).then(function (_deleteChildObservers) {\r\n // update deleteChildObservers\r\n deleteChildObservers = _deleteChildObservers\r\n return Promise.resolve() // Promise does not return anything\r\n })\r\n }\r\n var observer = function (events) {\r\n for (var e in events) {\r\n var event = events[e]\r\n if (event.name === path[0]) {\r\n if (deleteChildObservers != null) {\r\n deleteChildObservers()\r\n }\r\n if (event.type === 'add' || event.type === 'update') {\r\n resetObserverPath()\r\n }\r\n // TODO: what about the delete events?\r\n }\r\n }\r\n }\r\n self.observe(observer)\r\n return resetObserverPath().then(\r\n // this promise contains a function that deletes all the child observers\r\n // and how to unobserve the observe from this object\r\n new Promise.resolve(function () { // eslint-disable-line\r\n if (deleteChildObservers != null) {\r\n deleteChildObservers()\r\n }\r\n self.unobserve(observer)\r\n })\r\n )\r\n }\r\n }\r\n * _changed (transaction, op) {\r\n if (op.struct === 'Delete') {\r\n var target = yield* transaction.getOperation(op.target)\r\n op.key = target.parentSub\r\n }\r\n this.eventHandler.receivedOp(op)\r\n }\r\n }\r\n Y.extend('Map', new Y.utils.CustomType({\r\n name: 'Map',\r\n class: YMap,\r\n struct: 'Map',\r\n initType: function * YMapInitializer (os, model) {\r\n var contents = {}\r\n var opContents = {}\r\n var map = model.map\r\n for (var name in map) {\r\n var op = yield* this.getOperation(map[name])\r\n if (op.opContent != null) {\r\n opContents[name] = op.opContent\r\n } else {\r\n contents[name] = op.content\r\n }\r\n }\r\n return new YMap(os, model, contents, opContents)\r\n }\r\n }))\r\n}\r\n\r\nmodule.exports = extend\r\nif (typeof Y !== 'undefined') {\r\n extend(Y)\r\n}\r\n","(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 0) {\n _this.eventHandler.callEventListeners(userEvents);\n }\n });\n }\n\n _createClass(YMap, [{\n key: 'get',\n value: function get(key) {\n var _this2 = this;\n\n // return property.\n // if property does not exist, return null\n // if property is a type, return a promise\n if (key == null) {\n throw new Error('You must specify key!');\n }\n if (this.opContents[key] == null) {\n return this.contents[key];\n } else {\n return new Promise(function (resolve) {\n var oid = _this2.opContents[key];\n _this2.os.requestTransaction(regeneratorRuntime.mark(function _callee2() {\n var type;\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n return _context2.delegateYield(this.getType(oid), 't0', 1);\n\n case 1:\n type = _context2.t0;\n\n resolve(type);\n\n case 3:\n case 'end':\n return _context2.stop();\n }\n }\n }, _callee2, this);\n }));\n });\n }\n }\n /*\r\n If there is a primitive (not a custom type), then return it.\r\n Returns all primitive values, if propertyName is specified!\r\n Note: modifying the return value could result in inconsistencies!\r\n -- so make sure to copy it first!\r\n */\n\n }, {\n key: 'getPrimitive',\n value: function getPrimitive(key) {\n if (key == null) {\n return Y.utils.copyObject(this.contents);\n } else {\n return this.contents[key];\n }\n }\n }, {\n key: 'delete',\n value: function _delete(key) {\n var right = this.map[key];\n if (right != null) {\n var del = {\n target: right,\n struct: 'Delete'\n };\n var eventHandler = this.eventHandler;\n var modDel = Y.utils.copyObject(del);\n modDel.key = key;\n eventHandler.awaitAndPrematurelyCall([modDel]);\n this.os.requestTransaction(regeneratorRuntime.mark(function _callee3() {\n return regeneratorRuntime.wrap(function _callee3$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n return _context3.delegateYield(this.applyCreatedOperations([del]), 't0', 1);\n\n case 1:\n eventHandler.awaitedDeletes(1);\n\n case 2:\n case 'end':\n return _context3.stop();\n }\n }\n }, _callee3, this);\n }));\n }\n }\n }, {\n key: 'set',\n value: function set(key, value) {\n var _this3 = this;\n\n // set property.\n // if property is a type, return a promise\n // if not, apply immediately on this type an call event\n\n var right = this.map[key] || null;\n var insert /* :any */ = {\n left: null,\n right: right,\n origin: null,\n parent: this._model,\n parentSub: key,\n struct: 'Insert'\n };\n return new Promise(function (resolve) {\n if (value instanceof Y.utils.CustomType) {\n // construct a new type\n _this3.os.requestTransaction(regeneratorRuntime.mark(function _callee4() {\n var type;\n return regeneratorRuntime.wrap(function _callee4$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n return _context4.delegateYield(this.createType(value), 't0', 1);\n\n case 1:\n type = _context4.t0;\n\n insert.opContent = type._model;\n insert.id = this.store.getNextOpId();\n return _context4.delegateYield(this.applyCreatedOperations([insert]), 't1', 5);\n\n case 5:\n resolve(type);\n\n case 6:\n case 'end':\n return _context4.stop();\n }\n }\n }, _callee4, this);\n }));\n } else {\n insert.content = value;\n insert.id = _this3.os.getNextOpId();\n var eventHandler = _this3.eventHandler;\n eventHandler.awaitAndPrematurelyCall([insert]);\n _this3.os.requestTransaction(regeneratorRuntime.mark(function _callee5() {\n return regeneratorRuntime.wrap(function _callee5$(_context5) {\n while (1) {\n switch (_context5.prev = _context5.next) {\n case 0:\n return _context5.delegateYield(this.applyCreatedOperations([insert]), 't0', 1);\n\n case 1:\n eventHandler.awaitedInserts(1);\n\n case 2:\n case 'end':\n return _context5.stop();\n }\n }\n }, _callee5, this);\n }));\n resolve(value);\n }\n });\n }\n }, {\n key: 'observe',\n value: function observe(f) {\n this.eventHandler.addEventListener(f);\n }\n }, {\n key: 'unobserve',\n value: function unobserve(f) {\n this.eventHandler.removeEventListener(f);\n }\n /*\r\n Observe a path.\r\n E.g.\r\n ```\r\n o.set('textarea', Y.TextBind)\r\n o.observePath(['textarea'], function(t){\r\n // is called whenever textarea is replaced\r\n t.bind(textarea)\r\n })\r\n returns a Promise that contains a function that removes the observer from the path.\r\n */\n\n }, {\n key: 'observePath',\n value: function observePath(path, f) {\n var self = this;\n function observeProperty(events) {\n // call f whenever path changes\n for (var i = 0; i < events.length; i++) {\n var event = events[i];\n if (event.name === propertyName) {\n // call this also for delete events!\n var property = self.get(propertyName);\n if (property instanceof Promise) {\n property.then(f);\n } else {\n f(property);\n }\n }\n }\n }\n\n if (path.length < 1) {\n throw new Error('Path must contain at least one element!');\n } else if (path.length === 1) {\n var propertyName = path[0];\n var property = self.get(propertyName);\n if (property instanceof Promise) {\n property.then(f);\n } else {\n f(property);\n }\n this.observe(observeProperty);\n return Promise.resolve(function () {\n self.unobserve(f);\n });\n } else {\n var deleteChildObservers;\n var resetObserverPath = function resetObserverPath() {\n var promise = self.get(path[0]);\n if (!promise instanceof Promise) {\n // its either not defined or a primitive value\n promise = self.set(path[0], Y.Map);\n }\n return promise.then(function (map) {\n return map.observePath(path.slice(1), f);\n }).then(function (_deleteChildObservers) {\n // update deleteChildObservers\n deleteChildObservers = _deleteChildObservers;\n return Promise.resolve(); // Promise does not return anything\n });\n };\n var observer = function observer(events) {\n for (var e in events) {\n var event = events[e];\n if (event.name === path[0]) {\n if (deleteChildObservers != null) {\n deleteChildObservers();\n }\n if (event.type === 'add' || event.type === 'update') {\n resetObserverPath();\n }\n // TODO: what about the delete events?\n }\n }\n };\n self.observe(observer);\n return resetObserverPath().then(\n // this promise contains a function that deletes all the child observers\n // and how to unobserve the observe from this object\n new Promise.resolve(function () {\n // eslint-disable-line\n if (deleteChildObservers != null) {\n deleteChildObservers();\n }\n self.unobserve(observer);\n }));\n }\n }\n }, {\n key: '_changed',\n value: regeneratorRuntime.mark(function _changed(transaction, op) {\n var target;\n return regeneratorRuntime.wrap(function _changed$(_context6) {\n while (1) {\n switch (_context6.prev = _context6.next) {\n case 0:\n if (!(op.struct === 'Delete')) {\n _context6.next = 4;\n break;\n }\n\n return _context6.delegateYield(transaction.getOperation(op.target), 't0', 2);\n\n case 2:\n target = _context6.t0;\n\n op.key = target.parentSub;\n\n case 4:\n this.eventHandler.receivedOp(op);\n\n case 5:\n case 'end':\n return _context6.stop();\n }\n }\n }, _changed, this);\n })\n }]);\n\n return YMap;\n }();\n\n Y.extend('Map', new Y.utils.CustomType({\n name: 'Map',\n class: YMap,\n struct: 'Map',\n initType: regeneratorRuntime.mark(function YMapInitializer(os, model) {\n var contents, opContents, map, name, op;\n return regeneratorRuntime.wrap(function YMapInitializer$(_context7) {\n while (1) {\n switch (_context7.prev = _context7.next) {\n case 0:\n contents = {};\n opContents = {};\n map = model.map;\n _context7.t0 = regeneratorRuntime.keys(map);\n\n case 4:\n if ((_context7.t1 = _context7.t0()).done) {\n _context7.next = 11;\n break;\n }\n\n name = _context7.t1.value;\n return _context7.delegateYield(this.getOperation(map[name]), 't2', 7);\n\n case 7:\n op = _context7.t2;\n\n if (op.opContent != null) {\n opContents[name] = op.opContent;\n } else {\n contents[name] = op.content;\n }\n _context7.next = 4;\n break;\n\n case 11:\n return _context7.abrupt('return', new YMap(os, model, contents, opContents));\n\n case 12:\n case 'end':\n return _context7.stop();\n }\n }\n }, YMapInitializer, this);\n })\n }));\n}\n\nmodule.exports = extend;\nif (typeof Y !== 'undefined') {\n extend(Y);\n}\n\n},{}]},{},[1])\n\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/Examples/bower_components/y-memory/.bower.json b/Examples/bower_components/y-memory/.bower.json new file mode 100644 index 00000000..01c45c1d --- /dev/null +++ b/Examples/bower_components/y-memory/.bower.json @@ -0,0 +1,37 @@ +{ + "name": "y-memory", + "main": "y-memory.js", + "version": "0.7.0", + "homepage": "http://y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "In-Memory database adapter for Yjs", + "moduleType": [ + "globals", + "node" + ], + "keywords": [ + "Yjs", + "connector", + "webrtc" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "_release": "0.7.0", + "_resolution": { + "type": "version", + "tag": "v0.7.0", + "commit": "04c97da664d857328524e8a873e4f40cc066125d" + }, + "_source": "git://github.com/y-js/y-memory.git", + "_target": "~0.7.0", + "_originalSource": "y-memory", + "_direct": true +} \ No newline at end of file diff --git a/Examples/bower_components/y-memory/LICENSE b/Examples/bower_components/y-memory/LICENSE new file mode 100644 index 00000000..c8c5c6da --- /dev/null +++ b/Examples/bower_components/y-memory/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2014 + - Kevin Jahns . + - Chair of Computer Science 5 (Databases & Information Systems), RWTH Aachen University, Germany + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Examples/bower_components/y-memory/README.md b/Examples/bower_components/y-memory/README.md new file mode 100644 index 00000000..6b987da5 --- /dev/null +++ b/Examples/bower_components/y-memory/README.md @@ -0,0 +1 @@ +# IndexedDB database adapter for Yjs diff --git a/Examples/bower_components/y-memory/bower.json b/Examples/bower_components/y-memory/bower.json new file mode 100644 index 00000000..e65a094c --- /dev/null +++ b/Examples/bower_components/y-memory/bower.json @@ -0,0 +1,27 @@ +{ + "name": "y-memory", + "main": "y-memory.js", + "version": "0.7.1", + "homepage": "http://y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "In-Memory database adapter for Yjs", + "moduleType": [ + "globals", + "node" + ], + "keywords": [ + "Yjs", + "connector", + "webrtc" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} diff --git a/Examples/bower_components/y-memory/y-memory.es6 b/Examples/bower_components/y-memory/y-memory.es6 new file mode 100644 index 00000000..013bb6de --- /dev/null +++ b/Examples/bower_components/y-memory/y-memory.es6 @@ -0,0 +1,564 @@ +(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 0 || this.store.gc2.length > 0) { + console.warn('GC1|2 not empty!', this.store.gc1, this.store.gc2) + } + if (JSON.stringify(this.store.listenersById) !== '{}') { + console.warn('listenersById not empty!') + } + if (JSON.stringify(this.store.listenersByIdExecuteNow) !== '[]') { + console.warn('listenersByIdExecuteNow not empty!') + } + if (this.store.transactionInProgress) { + console.warn('Transaction still in progress!') + } + }, true) + } + transact (makeGen) { + var t = new Transaction(this) + while (makeGen !== null) { + var gen = makeGen.call(t) + var res = gen.next() + while (!res.done) { + res = gen.next(res.value) + } + makeGen = this.getNextRequest() + } + } + * destroy () { + super.destroy() + delete this.os + delete this.ss + delete this.ds + } + } + Y.extend('memory', Database) +} + +module.exports = extend +if (typeof Y !== 'undefined') { + extend(Y) +} + +},{"./RedBlackTree.js":2}],2:[function(require,module,exports){ +'use strict' + +/* + This file contains a not so fancy implemantion of a Red Black Tree. +*/ +module.exports = function (Y) { + class N { + // A created node is always red! + constructor (val) { + this.val = val + this.color = true + this._left = null + this._right = null + this._parent = null + if (val.id === null) { + throw new Error('You must define id!') + } + } + isRed () { return this.color } + isBlack () { return !this.color } + redden () { this.color = true; return this } + blacken () { this.color = false; return this } + get grandparent () { + return this.parent.parent + } + get parent () { + return this._parent + } + get sibling () { + return (this === this.parent.left) + ? this.parent.right : this.parent.left + } + get left () { + return this._left + } + get right () { + return this._right + } + set left (n) { + if (n !== null) { + n._parent = this + } + this._left = n + } + set right (n) { + if (n !== null) { + n._parent = this + } + this._right = n + } + rotateLeft (tree) { + var parent = this.parent + var newParent = this.right + var newRight = this.right.left + newParent.left = this + this.right = newRight + if (parent === null) { + tree.root = newParent + newParent._parent = null + } else if (parent.left === this) { + parent.left = newParent + } else if (parent.right === this) { + parent.right = newParent + } else { + throw new Error('The elements are wrongly connected!') + } + } + next () { + if (this.right !== null) { + // search the most left node in the right tree + var o = this.right + while (o.left !== null) { + o = o.left + } + return o + } else { + var p = this + while (p.parent !== null && p !== p.parent.left) { + p = p.parent + } + return p.parent + } + } + prev () { + if (this.left !== null) { + // search the most right node in the left tree + var o = this.left + while (o.right !== null) { + o = o.right + } + return o + } else { + var p = this + while (p.parent !== null && p !== p.parent.right) { + p = p.parent + } + return p.parent + } + } + rotateRight (tree) { + var parent = this.parent + var newParent = this.left + var newLeft = this.left.right + newParent.right = this + this.left = newLeft + if (parent === null) { + tree.root = newParent + newParent._parent = null + } else if (parent.left === this) { + parent.left = newParent + } else if (parent.right === this) { + parent.right = newParent + } else { + throw new Error('The elements are wrongly connected!') + } + } + getUncle () { + // we can assume that grandparent exists when this is called! + if (this.parent === this.parent.parent.left) { + return this.parent.parent.right + } else { + return this.parent.parent.left + } + } + } + + class RBTree { + constructor () { + this.root = null + this.length = 0 + } + * findNext (id) { + return yield* this.findWithLowerBound([id[0], id[1] + 1]) + } + * findPrev (id) { + return yield* this.findWithUpperBound([id[0], id[1] - 1]) + } + findNodeWithLowerBound (from) { + if (from === void 0) { + throw new Error('You must define from!') + } + var o = this.root + if (o === null) { + return null + } else { + while (true) { + if ((from === null || Y.utils.smaller(from, o.val.id)) && o.left !== null) { + // o is included in the bound + // try to find an element that is closer to the bound + o = o.left + } else if (from !== null && Y.utils.smaller(o.val.id, from)) { + // o is not within the bound, maybe one of the right elements is.. + if (o.right !== null) { + o = o.right + } else { + // there is no right element. Search for the next bigger element, + // this should be within the bounds + return o.next() + } + } else { + return o + } + } + } + } + findNodeWithUpperBound (to) { + if (to === void 0) { + throw new Error('You must define from!') + } + var o = this.root + if (o === null) { + return null + } else { + while (true) { + if ((to === null || Y.utils.smaller(o.val.id, to)) && o.right !== null) { + // o is included in the bound + // try to find an element that is closer to the bound + o = o.right + } else if (to !== null && Y.utils.smaller(to, o.val.id)) { + // o is not within the bound, maybe one of the left elements is.. + if (o.left !== null) { + o = o.left + } else { + // there is no left element. Search for the prev smaller element, + // this should be within the bounds + return o.prev() + } + } else { + return o + } + } + } + } + * findWithLowerBound (from) { + var n = this.findNodeWithLowerBound(from) + return n == null ? null : n.val + } + * findWithUpperBound (to) { + var n = this.findNodeWithUpperBound(to) + return n == null ? null : n.val + } + * iterate (t, from, to, f) { + var o = this.findNodeWithLowerBound(from) + while (o !== null && (to === null || Y.utils.smaller(o.val.id, to) || Y.utils.compareIds(o.val.id, to))) { + yield* f.call(t, o.val) + o = o.next() + } + return true + } + * logTable (from, to, filter) { + if (filter == null) { + filter = function () { + return true + } + } + if (from == null) { from = null } + if (to == null) { to = null } + var os = [] + yield* this.iterate(this, from, to, function * (o) { + if (filter(o)) { + var o_ = {} + for (var key in o) { + if (typeof o[key] === 'object') { + o_[key] = JSON.stringify(o[key]) + } else { + o_[key] = o[key] + } + } + os.push(o_) + } + }) + if (console.table != null) { + console.table(os) + } + } + * find (id) { + var n + return (n = this.findNode(id)) ? n.val : null + } + findNode (id) { + if (id == null || id.constructor !== Array) { + throw new Error('Expect id to be an array!') + } + var o = this.root + if (o === null) { + return false + } else { + while (true) { + if (o === null) { + return false + } + if (Y.utils.smaller(id, o.val.id)) { + o = o.left + } else if (Y.utils.smaller(o.val.id, id)) { + o = o.right + } else { + return o + } + } + } + } + * delete (id) { + if (id == null || id.constructor !== Array) { + throw new Error('id is expected to be an Array!') + } + var d = this.findNode(id) + if (d == null) { + throw new Error('Element does not exist!') + } + this.length-- + if (d.left !== null && d.right !== null) { + // switch d with the greates element in the left subtree. + // o should have at most one child. + var o = d.left + // find + while (o.right !== null) { + o = o.right + } + // switch + d.val = o.val + d = o + } + // d has at most one child + // let n be the node that replaces d + var isFakeChild + var child = d.left || d.right + if (child === null) { + isFakeChild = true + child = new N({id: 0}) + child.blacken() + d.right = child + } else { + isFakeChild = false + } + + if (d.parent === null) { + if (!isFakeChild) { + this.root = child + child.blacken() + child._parent = null + } else { + this.root = null + } + return + } else if (d.parent.left === d) { + d.parent.left = child + } else if (d.parent.right === d) { + d.parent.right = child + } else { + throw new Error('Impossible!') + } + if (d.isBlack()) { + if (child.isRed()) { + child.blacken() + } else { + this._fixDelete(child) + } + } + this.root.blacken() + if (isFakeChild) { + if (child.parent.left === child) { + child.parent.left = null + } else if (child.parent.right === child) { + child.parent.right = null + } else { + throw new Error('Impossible #3') + } + } + } + _fixDelete (n) { + function isBlack (node) { + return node !== null ? node.isBlack() : true + } + function isRed (node) { + return node !== null ? node.isRed() : false + } + if (n.parent === null) { + // this can only be called after the first iteration of fixDelete. + return + } + // d was already replaced by the child + // d is not the root + // d and child are black + var sibling = n.sibling + if (isRed(sibling)) { + // make sibling the grandfather + n.parent.redden() + sibling.blacken() + if (n === n.parent.left) { + n.parent.rotateLeft(this) + } else if (n === n.parent.right) { + n.parent.rotateRight(this) + } else { + throw new Error('Impossible #2') + } + sibling = n.sibling + } + // parent, sibling, and children of n are black + if (n.parent.isBlack() && + sibling.isBlack() && + isBlack(sibling.left) && + isBlack(sibling.right) + ) { + sibling.redden() + this._fixDelete(n.parent) + } else if (n.parent.isRed() && + sibling.isBlack() && + isBlack(sibling.left) && + isBlack(sibling.right) + ) { + sibling.redden() + n.parent.blacken() + } else { + if (n === n.parent.left && + sibling.isBlack() && + isRed(sibling.left) && + isBlack(sibling.right) + ) { + sibling.redden() + sibling.left.blacken() + sibling.rotateRight(this) + sibling = n.sibling + } else if (n === n.parent.right && + sibling.isBlack() && + isRed(sibling.right) && + isBlack(sibling.left) + ) { + sibling.redden() + sibling.right.blacken() + sibling.rotateLeft(this) + sibling = n.sibling + } + sibling.color = n.parent.color + n.parent.blacken() + if (n === n.parent.left) { + sibling.right.blacken() + n.parent.rotateLeft(this) + } else { + sibling.left.blacken() + n.parent.rotateRight(this) + } + } + } + * put (v) { + if (v == null || v.id == null || v.id.constructor !== Array) { + throw new Error('v is expected to have an id property which is an Array!') + } + var node = new N(v) + if (this.root !== null) { + var p = this.root // p abbrev. parent + while (true) { + if (Y.utils.smaller(node.val.id, p.val.id)) { + if (p.left === null) { + p.left = node + break + } else { + p = p.left + } + } else if (Y.utils.smaller(p.val.id, node.val.id)) { + if (p.right === null) { + p.right = node + break + } else { + p = p.right + } + } else { + p.val = node.val + return p + } + } + this._fixInsert(node) + } else { + this.root = node + } + this.length++ + this.root.blacken() + return node + } + _fixInsert (n) { + if (n.parent === null) { + n.blacken() + return + } else if (n.parent.isBlack()) { + return + } + var uncle = n.getUncle() + if (uncle !== null && uncle.isRed()) { + // Note: parent: red, uncle: red + n.parent.blacken() + uncle.blacken() + n.grandparent.redden() + this._fixInsert(n.grandparent) + } else { + // Note: parent: red, uncle: black or null + // Now we transform the tree in such a way that + // either of these holds: + // 1) grandparent.left.isRed + // and grandparent.left.left.isRed + // 2) grandparent.right.isRed + // and grandparent.right.right.isRed + if (n === n.parent.right && n.parent === n.grandparent.left) { + n.parent.rotateLeft(this) + // Since we rotated and want to use the previous + // cases, we need to set n in such a way that + // n.parent.isRed again + n = n.left + } else if (n === n.parent.left && n.parent === n.grandparent.right) { + n.parent.rotateRight(this) + // see above + n = n.right + } + // Case 1) or 2) hold from here on. + // Now traverse grandparent, make parent a black node + // on the highest level which holds two red nodes. + n.parent.blacken() + n.grandparent.redden() + if (n === n.parent.left) { + // Case 1 + n.grandparent.rotateRight(this) + } else { + // Case 2 + n.grandparent.rotateLeft(this) + } + } + } + } + + Y.utils.RBTree = RBTree +} + +},{}]},{},[1]) + diff --git a/Examples/bower_components/y-memory/y-memory.es6.map b/Examples/bower_components/y-memory/y-memory.es6.map new file mode 100644 index 00000000..1476380f --- /dev/null +++ b/Examples/bower_components/y-memory/y-memory.es6.map @@ -0,0 +1 @@ +{"version":3,"sources":["../yjs/node_modules/browser-pack/_prelude.js","src/Memory.js","src/RedBlackTree.js"],"names":[],"mappings":"AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"y-memory.es6","sourceRoot":"/source/","sourcesContent":["(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 0 || this.store.gc2.length > 0) {\r\n console.warn('GC1|2 not empty!', this.store.gc1, this.store.gc2)\r\n }\r\n if (JSON.stringify(this.store.listenersById) !== '{}') {\r\n console.warn('listenersById not empty!')\r\n }\r\n if (JSON.stringify(this.store.listenersByIdExecuteNow) !== '[]') {\r\n console.warn('listenersByIdExecuteNow not empty!')\r\n }\r\n if (this.store.transactionInProgress) {\r\n console.warn('Transaction still in progress!')\r\n }\r\n }, true)\r\n }\r\n transact (makeGen) {\r\n var t = new Transaction(this)\r\n while (makeGen !== null) {\r\n var gen = makeGen.call(t)\r\n var res = gen.next()\r\n while (!res.done) {\r\n res = gen.next(res.value)\r\n }\r\n makeGen = this.getNextRequest()\r\n }\r\n }\r\n * destroy () {\r\n super.destroy()\r\n delete this.os\r\n delete this.ss\r\n delete this.ds\r\n }\r\n }\r\n Y.extend('memory', Database)\r\n}\r\n\r\nmodule.exports = extend\r\nif (typeof Y !== 'undefined') {\r\n extend(Y)\r\n}\r\n","'use strict'\r\n\r\n/*\r\n This file contains a not so fancy implemantion of a Red Black Tree.\r\n*/\r\nmodule.exports = function (Y) {\r\n class N {\r\n // A created node is always red!\r\n constructor (val) {\r\n this.val = val\r\n this.color = true\r\n this._left = null\r\n this._right = null\r\n this._parent = null\r\n if (val.id === null) {\r\n throw new Error('You must define id!')\r\n }\r\n }\r\n isRed () { return this.color }\r\n isBlack () { return !this.color }\r\n redden () { this.color = true; return this }\r\n blacken () { this.color = false; return this }\r\n get grandparent () {\r\n return this.parent.parent\r\n }\r\n get parent () {\r\n return this._parent\r\n }\r\n get sibling () {\r\n return (this === this.parent.left)\r\n ? this.parent.right : this.parent.left\r\n }\r\n get left () {\r\n return this._left\r\n }\r\n get right () {\r\n return this._right\r\n }\r\n set left (n) {\r\n if (n !== null) {\r\n n._parent = this\r\n }\r\n this._left = n\r\n }\r\n set right (n) {\r\n if (n !== null) {\r\n n._parent = this\r\n }\r\n this._right = n\r\n }\r\n rotateLeft (tree) {\r\n var parent = this.parent\r\n var newParent = this.right\r\n var newRight = this.right.left\r\n newParent.left = this\r\n this.right = newRight\r\n if (parent === null) {\r\n tree.root = newParent\r\n newParent._parent = null\r\n } else if (parent.left === this) {\r\n parent.left = newParent\r\n } else if (parent.right === this) {\r\n parent.right = newParent\r\n } else {\r\n throw new Error('The elements are wrongly connected!')\r\n }\r\n }\r\n next () {\r\n if (this.right !== null) {\r\n // search the most left node in the right tree\r\n var o = this.right\r\n while (o.left !== null) {\r\n o = o.left\r\n }\r\n return o\r\n } else {\r\n var p = this\r\n while (p.parent !== null && p !== p.parent.left) {\r\n p = p.parent\r\n }\r\n return p.parent\r\n }\r\n }\r\n prev () {\r\n if (this.left !== null) {\r\n // search the most right node in the left tree\r\n var o = this.left\r\n while (o.right !== null) {\r\n o = o.right\r\n }\r\n return o\r\n } else {\r\n var p = this\r\n while (p.parent !== null && p !== p.parent.right) {\r\n p = p.parent\r\n }\r\n return p.parent\r\n }\r\n }\r\n rotateRight (tree) {\r\n var parent = this.parent\r\n var newParent = this.left\r\n var newLeft = this.left.right\r\n newParent.right = this\r\n this.left = newLeft\r\n if (parent === null) {\r\n tree.root = newParent\r\n newParent._parent = null\r\n } else if (parent.left === this) {\r\n parent.left = newParent\r\n } else if (parent.right === this) {\r\n parent.right = newParent\r\n } else {\r\n throw new Error('The elements are wrongly connected!')\r\n }\r\n }\r\n getUncle () {\r\n // we can assume that grandparent exists when this is called!\r\n if (this.parent === this.parent.parent.left) {\r\n return this.parent.parent.right\r\n } else {\r\n return this.parent.parent.left\r\n }\r\n }\r\n }\r\n\r\n class RBTree {\r\n constructor () {\r\n this.root = null\r\n this.length = 0\r\n }\r\n * findNext (id) {\r\n return yield* this.findWithLowerBound([id[0], id[1] + 1])\r\n }\r\n * findPrev (id) {\r\n return yield* this.findWithUpperBound([id[0], id[1] - 1])\r\n }\r\n findNodeWithLowerBound (from) {\r\n if (from === void 0) {\r\n throw new Error('You must define from!')\r\n }\r\n var o = this.root\r\n if (o === null) {\r\n return null\r\n } else {\r\n while (true) {\r\n if ((from === null || Y.utils.smaller(from, o.val.id)) && o.left !== null) {\r\n // o is included in the bound\r\n // try to find an element that is closer to the bound\r\n o = o.left\r\n } else if (from !== null && Y.utils.smaller(o.val.id, from)) {\r\n // o is not within the bound, maybe one of the right elements is..\r\n if (o.right !== null) {\r\n o = o.right\r\n } else {\r\n // there is no right element. Search for the next bigger element,\r\n // this should be within the bounds\r\n return o.next()\r\n }\r\n } else {\r\n return o\r\n }\r\n }\r\n }\r\n }\r\n findNodeWithUpperBound (to) {\r\n if (to === void 0) {\r\n throw new Error('You must define from!')\r\n }\r\n var o = this.root\r\n if (o === null) {\r\n return null\r\n } else {\r\n while (true) {\r\n if ((to === null || Y.utils.smaller(o.val.id, to)) && o.right !== null) {\r\n // o is included in the bound\r\n // try to find an element that is closer to the bound\r\n o = o.right\r\n } else if (to !== null && Y.utils.smaller(to, o.val.id)) {\r\n // o is not within the bound, maybe one of the left elements is..\r\n if (o.left !== null) {\r\n o = o.left\r\n } else {\r\n // there is no left element. Search for the prev smaller element,\r\n // this should be within the bounds\r\n return o.prev()\r\n }\r\n } else {\r\n return o\r\n }\r\n }\r\n }\r\n }\r\n * findWithLowerBound (from) {\r\n var n = this.findNodeWithLowerBound(from)\r\n return n == null ? null : n.val\r\n }\r\n * findWithUpperBound (to) {\r\n var n = this.findNodeWithUpperBound(to)\r\n return n == null ? null : n.val\r\n }\r\n * iterate (t, from, to, f) {\r\n var o = this.findNodeWithLowerBound(from)\r\n while (o !== null && (to === null || Y.utils.smaller(o.val.id, to) || Y.utils.compareIds(o.val.id, to))) {\r\n yield* f.call(t, o.val)\r\n o = o.next()\r\n }\r\n return true\r\n }\r\n * logTable (from, to, filter) {\r\n if (filter == null) {\r\n filter = function () {\r\n return true\r\n }\r\n }\r\n if (from == null) { from = null }\r\n if (to == null) { to = null }\r\n var os = []\r\n yield* this.iterate(this, from, to, function * (o) {\r\n if (filter(o)) {\r\n var o_ = {}\r\n for (var key in o) {\r\n if (typeof o[key] === 'object') {\r\n o_[key] = JSON.stringify(o[key])\r\n } else {\r\n o_[key] = o[key]\r\n }\r\n }\r\n os.push(o_)\r\n }\r\n })\r\n if (console.table != null) {\r\n console.table(os)\r\n }\r\n }\r\n * find (id) {\r\n var n\r\n return (n = this.findNode(id)) ? n.val : null\r\n }\r\n findNode (id) {\r\n if (id == null || id.constructor !== Array) {\r\n throw new Error('Expect id to be an array!')\r\n }\r\n var o = this.root\r\n if (o === null) {\r\n return false\r\n } else {\r\n while (true) {\r\n if (o === null) {\r\n return false\r\n }\r\n if (Y.utils.smaller(id, o.val.id)) {\r\n o = o.left\r\n } else if (Y.utils.smaller(o.val.id, id)) {\r\n o = o.right\r\n } else {\r\n return o\r\n }\r\n }\r\n }\r\n }\r\n * delete (id) {\r\n if (id == null || id.constructor !== Array) {\r\n throw new Error('id is expected to be an Array!')\r\n }\r\n var d = this.findNode(id)\r\n if (d == null) {\r\n throw new Error('Element does not exist!')\r\n }\r\n this.length--\r\n if (d.left !== null && d.right !== null) {\r\n // switch d with the greates element in the left subtree.\r\n // o should have at most one child.\r\n var o = d.left\r\n // find\r\n while (o.right !== null) {\r\n o = o.right\r\n }\r\n // switch\r\n d.val = o.val\r\n d = o\r\n }\r\n // d has at most one child\r\n // let n be the node that replaces d\r\n var isFakeChild\r\n var child = d.left || d.right\r\n if (child === null) {\r\n isFakeChild = true\r\n child = new N({id: 0})\r\n child.blacken()\r\n d.right = child\r\n } else {\r\n isFakeChild = false\r\n }\r\n\r\n if (d.parent === null) {\r\n if (!isFakeChild) {\r\n this.root = child\r\n child.blacken()\r\n child._parent = null\r\n } else {\r\n this.root = null\r\n }\r\n return\r\n } else if (d.parent.left === d) {\r\n d.parent.left = child\r\n } else if (d.parent.right === d) {\r\n d.parent.right = child\r\n } else {\r\n throw new Error('Impossible!')\r\n }\r\n if (d.isBlack()) {\r\n if (child.isRed()) {\r\n child.blacken()\r\n } else {\r\n this._fixDelete(child)\r\n }\r\n }\r\n this.root.blacken()\r\n if (isFakeChild) {\r\n if (child.parent.left === child) {\r\n child.parent.left = null\r\n } else if (child.parent.right === child) {\r\n child.parent.right = null\r\n } else {\r\n throw new Error('Impossible #3')\r\n }\r\n }\r\n }\r\n _fixDelete (n) {\r\n function isBlack (node) {\r\n return node !== null ? node.isBlack() : true\r\n }\r\n function isRed (node) {\r\n return node !== null ? node.isRed() : false\r\n }\r\n if (n.parent === null) {\r\n // this can only be called after the first iteration of fixDelete.\r\n return\r\n }\r\n // d was already replaced by the child\r\n // d is not the root\r\n // d and child are black\r\n var sibling = n.sibling\r\n if (isRed(sibling)) {\r\n // make sibling the grandfather\r\n n.parent.redden()\r\n sibling.blacken()\r\n if (n === n.parent.left) {\r\n n.parent.rotateLeft(this)\r\n } else if (n === n.parent.right) {\r\n n.parent.rotateRight(this)\r\n } else {\r\n throw new Error('Impossible #2')\r\n }\r\n sibling = n.sibling\r\n }\r\n // parent, sibling, and children of n are black\r\n if (n.parent.isBlack() &&\r\n sibling.isBlack() &&\r\n isBlack(sibling.left) &&\r\n isBlack(sibling.right)\r\n ) {\r\n sibling.redden()\r\n this._fixDelete(n.parent)\r\n } else if (n.parent.isRed() &&\r\n sibling.isBlack() &&\r\n isBlack(sibling.left) &&\r\n isBlack(sibling.right)\r\n ) {\r\n sibling.redden()\r\n n.parent.blacken()\r\n } else {\r\n if (n === n.parent.left &&\r\n sibling.isBlack() &&\r\n isRed(sibling.left) &&\r\n isBlack(sibling.right)\r\n ) {\r\n sibling.redden()\r\n sibling.left.blacken()\r\n sibling.rotateRight(this)\r\n sibling = n.sibling\r\n } else if (n === n.parent.right &&\r\n sibling.isBlack() &&\r\n isRed(sibling.right) &&\r\n isBlack(sibling.left)\r\n ) {\r\n sibling.redden()\r\n sibling.right.blacken()\r\n sibling.rotateLeft(this)\r\n sibling = n.sibling\r\n }\r\n sibling.color = n.parent.color\r\n n.parent.blacken()\r\n if (n === n.parent.left) {\r\n sibling.right.blacken()\r\n n.parent.rotateLeft(this)\r\n } else {\r\n sibling.left.blacken()\r\n n.parent.rotateRight(this)\r\n }\r\n }\r\n }\r\n * put (v) {\r\n if (v == null || v.id == null || v.id.constructor !== Array) {\r\n throw new Error('v is expected to have an id property which is an Array!')\r\n }\r\n var node = new N(v)\r\n if (this.root !== null) {\r\n var p = this.root // p abbrev. parent\r\n while (true) {\r\n if (Y.utils.smaller(node.val.id, p.val.id)) {\r\n if (p.left === null) {\r\n p.left = node\r\n break\r\n } else {\r\n p = p.left\r\n }\r\n } else if (Y.utils.smaller(p.val.id, node.val.id)) {\r\n if (p.right === null) {\r\n p.right = node\r\n break\r\n } else {\r\n p = p.right\r\n }\r\n } else {\r\n p.val = node.val\r\n return p\r\n }\r\n }\r\n this._fixInsert(node)\r\n } else {\r\n this.root = node\r\n }\r\n this.length++\r\n this.root.blacken()\r\n return node\r\n }\r\n _fixInsert (n) {\r\n if (n.parent === null) {\r\n n.blacken()\r\n return\r\n } else if (n.parent.isBlack()) {\r\n return\r\n }\r\n var uncle = n.getUncle()\r\n if (uncle !== null && uncle.isRed()) {\r\n // Note: parent: red, uncle: red\r\n n.parent.blacken()\r\n uncle.blacken()\r\n n.grandparent.redden()\r\n this._fixInsert(n.grandparent)\r\n } else {\r\n // Note: parent: red, uncle: black or null\r\n // Now we transform the tree in such a way that\r\n // either of these holds:\r\n // 1) grandparent.left.isRed\r\n // and grandparent.left.left.isRed\r\n // 2) grandparent.right.isRed\r\n // and grandparent.right.right.isRed\r\n if (n === n.parent.right && n.parent === n.grandparent.left) {\r\n n.parent.rotateLeft(this)\r\n // Since we rotated and want to use the previous\r\n // cases, we need to set n in such a way that\r\n // n.parent.isRed again\r\n n = n.left\r\n } else if (n === n.parent.left && n.parent === n.grandparent.right) {\r\n n.parent.rotateRight(this)\r\n // see above\r\n n = n.right\r\n }\r\n // Case 1) or 2) hold from here on.\r\n // Now traverse grandparent, make parent a black node\r\n // on the highest level which holds two red nodes.\r\n n.parent.blacken()\r\n n.grandparent.redden()\r\n if (n === n.parent.left) {\r\n // Case 1\r\n n.grandparent.rotateRight(this)\r\n } else {\r\n // Case 2\r\n n.grandparent.rotateLeft(this)\r\n }\r\n }\r\n }\r\n }\r\n\r\n Y.utils.RBTree = RBTree\r\n}\r\n"]} \ No newline at end of file diff --git a/Examples/bower_components/y-memory/y-memory.js b/Examples/bower_components/y-memory/y-memory.js new file mode 100644 index 00000000..bda905ef --- /dev/null +++ b/Examples/bower_components/y-memory/y-memory.js @@ -0,0 +1,2 @@ +!function e(t,r,n){function i(l,o){if(!r[l]){if(!t[l]){var s="function"==typeof require&&require;if(!o&&s)return s(l,!0);if(a)return a(l,!0);var u=new Error("Cannot find module '"+l+"'");throw u.code="MODULE_NOT_FOUND",u}var f=r[l]={exports:{}};t[l][0].call(f.exports,function(e){var r=t[l][1][e];return i(r?r:e)},f,f.exports,e,t,r,n)}return r[l].exports}for(var a="function"==typeof require&&require,l=0;l0||this.store.gc2.length>0)&&console.warn("GC1|2 not empty!",this.store.gc1,this.store.gc2),"{}"!==JSON.stringify(this.store.listenersById)&&console.warn("listenersById not empty!"),"[]"!==JSON.stringify(this.store.listenersByIdExecuteNow)&&console.warn("listenersByIdExecuteNow not empty!"),this.store.transactionInProgress&&console.warn("Transaction still in progress!");case 13:case"end":return e.stop()}},t,this)}),!0)}},{key:"transact",value:function(e){for(var t=new r(this);null!==e;){for(var n=e.call(t),i=n.next();!i.done;)i=n.next(i.value);e=this.getNextRequest()}}},{key:"destroy",value:regeneratorRuntime.mark(function u(){return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:s(Object.getPrototypeOf(l.prototype),"destroy",this).call(this),delete this.os,delete this.ss,delete this.ds;case 4:case"end":return e.stop()}},u,this)})}]),l}(t.AbstractDatabase);t.extend("memory",l)}var o=function(){function e(e,t){for(var r=0;r 0 || this.store.gc2.length > 0) {\r\n console.warn('GC1|2 not empty!', this.store.gc1, this.store.gc2)\r\n }\r\n if (JSON.stringify(this.store.listenersById) !== '{}') {\r\n console.warn('listenersById not empty!')\r\n }\r\n if (JSON.stringify(this.store.listenersByIdExecuteNow) !== '[]') {\r\n console.warn('listenersByIdExecuteNow not empty!')\r\n }\r\n if (this.store.transactionInProgress) {\r\n console.warn('Transaction still in progress!')\r\n }\r\n }, true)\r\n }\r\n transact (makeGen) {\r\n var t = new Transaction(this)\r\n while (makeGen !== null) {\r\n var gen = makeGen.call(t)\r\n var res = gen.next()\r\n while (!res.done) {\r\n res = gen.next(res.value)\r\n }\r\n makeGen = this.getNextRequest()\r\n }\r\n }\r\n * destroy () {\r\n super.destroy()\r\n delete this.os\r\n delete this.ss\r\n delete this.ds\r\n }\r\n }\r\n Y.extend('memory', Database)\r\n}\r\n\r\nmodule.exports = extend\r\nif (typeof Y !== 'undefined') {\r\n extend(Y)\r\n}\r\n","(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 0 || this.store.gc2.length > 0) {\n console.warn('GC1|2 not empty!', this.store.gc1, this.store.gc2);\n }\n if (JSON.stringify(this.store.listenersById) !== '{}') {\n console.warn('listenersById not empty!');\n }\n if (JSON.stringify(this.store.listenersByIdExecuteNow) !== '[]') {\n console.warn('listenersByIdExecuteNow not empty!');\n }\n if (this.store.transactionInProgress) {\n console.warn('Transaction still in progress!');\n }\n\n case 13:\n case 'end':\n return _context.stop();\n }\n }\n }, _callee, this);\n }), true);\n }\n }, {\n key: 'transact',\n value: function transact(makeGen) {\n var t = new Transaction(this);\n while (makeGen !== null) {\n var gen = makeGen.call(t);\n var res = gen.next();\n while (!res.done) {\n res = gen.next(res.value);\n }\n makeGen = this.getNextRequest();\n }\n }\n }, {\n key: 'destroy',\n value: regeneratorRuntime.mark(function destroy() {\n return regeneratorRuntime.wrap(function destroy$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n _get(Object.getPrototypeOf(Database.prototype), 'destroy', this).call(this);\n delete this.os;\n delete this.ss;\n delete this.ds;\n\n case 4:\n case 'end':\n return _context2.stop();\n }\n }\n }, destroy, this);\n })\n }]);\n\n return Database;\n }(Y.AbstractDatabase);\n\n Y.extend('memory', Database);\n}\n\nmodule.exports = extend;\nif (typeof Y !== 'undefined') {\n extend(Y);\n}\n\n},{\"./RedBlackTree.js\":2}],2:[function(require,module,exports){\n'use strict';\n\n/*\r\n This file contains a not so fancy implemantion of a Red Black Tree.\r\n*/\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol ? \"symbol\" : typeof obj; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nmodule.exports = function (Y) {\n var N = function () {\n // A created node is always red!\n\n function N(val) {\n _classCallCheck(this, N);\n\n this.val = val;\n this.color = true;\n this._left = null;\n this._right = null;\n this._parent = null;\n if (val.id === null) {\n throw new Error('You must define id!');\n }\n }\n\n _createClass(N, [{\n key: 'isRed',\n value: function isRed() {\n return this.color;\n }\n }, {\n key: 'isBlack',\n value: function isBlack() {\n return !this.color;\n }\n }, {\n key: 'redden',\n value: function redden() {\n this.color = true;return this;\n }\n }, {\n key: 'blacken',\n value: function blacken() {\n this.color = false;return this;\n }\n }, {\n key: 'rotateLeft',\n value: function rotateLeft(tree) {\n var parent = this.parent;\n var newParent = this.right;\n var newRight = this.right.left;\n newParent.left = this;\n this.right = newRight;\n if (parent === null) {\n tree.root = newParent;\n newParent._parent = null;\n } else if (parent.left === this) {\n parent.left = newParent;\n } else if (parent.right === this) {\n parent.right = newParent;\n } else {\n throw new Error('The elements are wrongly connected!');\n }\n }\n }, {\n key: 'next',\n value: function next() {\n if (this.right !== null) {\n // search the most left node in the right tree\n var o = this.right;\n while (o.left !== null) {\n o = o.left;\n }\n return o;\n } else {\n var p = this;\n while (p.parent !== null && p !== p.parent.left) {\n p = p.parent;\n }\n return p.parent;\n }\n }\n }, {\n key: 'prev',\n value: function prev() {\n if (this.left !== null) {\n // search the most right node in the left tree\n var o = this.left;\n while (o.right !== null) {\n o = o.right;\n }\n return o;\n } else {\n var p = this;\n while (p.parent !== null && p !== p.parent.right) {\n p = p.parent;\n }\n return p.parent;\n }\n }\n }, {\n key: 'rotateRight',\n value: function rotateRight(tree) {\n var parent = this.parent;\n var newParent = this.left;\n var newLeft = this.left.right;\n newParent.right = this;\n this.left = newLeft;\n if (parent === null) {\n tree.root = newParent;\n newParent._parent = null;\n } else if (parent.left === this) {\n parent.left = newParent;\n } else if (parent.right === this) {\n parent.right = newParent;\n } else {\n throw new Error('The elements are wrongly connected!');\n }\n }\n }, {\n key: 'getUncle',\n value: function getUncle() {\n // we can assume that grandparent exists when this is called!\n if (this.parent === this.parent.parent.left) {\n return this.parent.parent.right;\n } else {\n return this.parent.parent.left;\n }\n }\n }, {\n key: 'grandparent',\n get: function get() {\n return this.parent.parent;\n }\n }, {\n key: 'parent',\n get: function get() {\n return this._parent;\n }\n }, {\n key: 'sibling',\n get: function get() {\n return this === this.parent.left ? this.parent.right : this.parent.left;\n }\n }, {\n key: 'left',\n get: function get() {\n return this._left;\n },\n set: function set(n) {\n if (n !== null) {\n n._parent = this;\n }\n this._left = n;\n }\n }, {\n key: 'right',\n get: function get() {\n return this._right;\n },\n set: function set(n) {\n if (n !== null) {\n n._parent = this;\n }\n this._right = n;\n }\n }]);\n\n return N;\n }();\n\n var RBTree = function () {\n function RBTree() {\n _classCallCheck(this, RBTree);\n\n this.root = null;\n this.length = 0;\n }\n\n _createClass(RBTree, [{\n key: 'findNext',\n value: regeneratorRuntime.mark(function findNext(id) {\n return regeneratorRuntime.wrap(function findNext$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n return _context.delegateYield(this.findWithLowerBound([id[0], id[1] + 1]), 't0', 1);\n\n case 1:\n return _context.abrupt('return', _context.t0);\n\n case 2:\n case 'end':\n return _context.stop();\n }\n }\n }, findNext, this);\n })\n }, {\n key: 'findPrev',\n value: regeneratorRuntime.mark(function findPrev(id) {\n return regeneratorRuntime.wrap(function findPrev$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n return _context2.delegateYield(this.findWithUpperBound([id[0], id[1] - 1]), 't0', 1);\n\n case 1:\n return _context2.abrupt('return', _context2.t0);\n\n case 2:\n case 'end':\n return _context2.stop();\n }\n }\n }, findPrev, this);\n })\n }, {\n key: 'findNodeWithLowerBound',\n value: function findNodeWithLowerBound(from) {\n if (from === void 0) {\n throw new Error('You must define from!');\n }\n var o = this.root;\n if (o === null) {\n return null;\n } else {\n while (true) {\n if ((from === null || Y.utils.smaller(from, o.val.id)) && o.left !== null) {\n // o is included in the bound\n // try to find an element that is closer to the bound\n o = o.left;\n } else if (from !== null && Y.utils.smaller(o.val.id, from)) {\n // o is not within the bound, maybe one of the right elements is..\n if (o.right !== null) {\n o = o.right;\n } else {\n // there is no right element. Search for the next bigger element,\n // this should be within the bounds\n return o.next();\n }\n } else {\n return o;\n }\n }\n }\n }\n }, {\n key: 'findNodeWithUpperBound',\n value: function findNodeWithUpperBound(to) {\n if (to === void 0) {\n throw new Error('You must define from!');\n }\n var o = this.root;\n if (o === null) {\n return null;\n } else {\n while (true) {\n if ((to === null || Y.utils.smaller(o.val.id, to)) && o.right !== null) {\n // o is included in the bound\n // try to find an element that is closer to the bound\n o = o.right;\n } else if (to !== null && Y.utils.smaller(to, o.val.id)) {\n // o is not within the bound, maybe one of the left elements is..\n if (o.left !== null) {\n o = o.left;\n } else {\n // there is no left element. Search for the prev smaller element,\n // this should be within the bounds\n return o.prev();\n }\n } else {\n return o;\n }\n }\n }\n }\n }, {\n key: 'findWithLowerBound',\n value: regeneratorRuntime.mark(function findWithLowerBound(from) {\n var n;\n return regeneratorRuntime.wrap(function findWithLowerBound$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n n = this.findNodeWithLowerBound(from);\n return _context3.abrupt('return', n == null ? null : n.val);\n\n case 2:\n case 'end':\n return _context3.stop();\n }\n }\n }, findWithLowerBound, this);\n })\n }, {\n key: 'findWithUpperBound',\n value: regeneratorRuntime.mark(function findWithUpperBound(to) {\n var n;\n return regeneratorRuntime.wrap(function findWithUpperBound$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n n = this.findNodeWithUpperBound(to);\n return _context4.abrupt('return', n == null ? null : n.val);\n\n case 2:\n case 'end':\n return _context4.stop();\n }\n }\n }, findWithUpperBound, this);\n })\n }, {\n key: 'iterate',\n value: regeneratorRuntime.mark(function iterate(t, from, to, f) {\n var o;\n return regeneratorRuntime.wrap(function iterate$(_context5) {\n while (1) {\n switch (_context5.prev = _context5.next) {\n case 0:\n o = this.findNodeWithLowerBound(from);\n\n case 1:\n if (!(o !== null && (to === null || Y.utils.smaller(o.val.id, to) || Y.utils.compareIds(o.val.id, to)))) {\n _context5.next = 6;\n break;\n }\n\n return _context5.delegateYield(f.call(t, o.val), 't0', 3);\n\n case 3:\n o = o.next();\n _context5.next = 1;\n break;\n\n case 6:\n return _context5.abrupt('return', true);\n\n case 7:\n case 'end':\n return _context5.stop();\n }\n }\n }, iterate, this);\n })\n }, {\n key: 'logTable',\n value: regeneratorRuntime.mark(function logTable(from, to, filter) {\n var os;\n return regeneratorRuntime.wrap(function logTable$(_context7) {\n while (1) {\n switch (_context7.prev = _context7.next) {\n case 0:\n if (filter == null) {\n filter = function filter() {\n return true;\n };\n }\n if (from == null) {\n from = null;\n }\n if (to == null) {\n to = null;\n }\n os = [];\n return _context7.delegateYield(this.iterate(this, from, to, regeneratorRuntime.mark(function _callee(o) {\n var o_, key;\n return regeneratorRuntime.wrap(function _callee$(_context6) {\n while (1) {\n switch (_context6.prev = _context6.next) {\n case 0:\n if (filter(o)) {\n o_ = {};\n\n for (key in o) {\n if (_typeof(o[key]) === 'object') {\n o_[key] = JSON.stringify(o[key]);\n } else {\n o_[key] = o[key];\n }\n }\n os.push(o_);\n }\n\n case 1:\n case 'end':\n return _context6.stop();\n }\n }\n }, _callee, this);\n })), 't0', 5);\n\n case 5:\n if (console.table != null) {\n console.table(os);\n }\n\n case 6:\n case 'end':\n return _context7.stop();\n }\n }\n }, logTable, this);\n })\n }, {\n key: 'find',\n value: regeneratorRuntime.mark(function find(id) {\n var n;\n return regeneratorRuntime.wrap(function find$(_context8) {\n while (1) {\n switch (_context8.prev = _context8.next) {\n case 0:\n return _context8.abrupt('return', (n = this.findNode(id)) ? n.val : null);\n\n case 1:\n case 'end':\n return _context8.stop();\n }\n }\n }, find, this);\n })\n }, {\n key: 'findNode',\n value: function findNode(id) {\n if (id == null || id.constructor !== Array) {\n throw new Error('Expect id to be an array!');\n }\n var o = this.root;\n if (o === null) {\n return false;\n } else {\n while (true) {\n if (o === null) {\n return false;\n }\n if (Y.utils.smaller(id, o.val.id)) {\n o = o.left;\n } else if (Y.utils.smaller(o.val.id, id)) {\n o = o.right;\n } else {\n return o;\n }\n }\n }\n }\n }, {\n key: 'delete',\n value: regeneratorRuntime.mark(function _delete(id) {\n var d, o, isFakeChild, child;\n return regeneratorRuntime.wrap(function _delete$(_context9) {\n while (1) {\n switch (_context9.prev = _context9.next) {\n case 0:\n if (!(id == null || id.constructor !== Array)) {\n _context9.next = 2;\n break;\n }\n\n throw new Error('id is expected to be an Array!');\n\n case 2:\n d = this.findNode(id);\n\n if (!(d == null)) {\n _context9.next = 5;\n break;\n }\n\n throw new Error('Element does not exist!');\n\n case 5:\n this.length--;\n if (d.left !== null && d.right !== null) {\n // switch d with the greates element in the left subtree.\n // o should have at most one child.\n o = d.left;\n // find\n\n while (o.right !== null) {\n o = o.right;\n }\n // switch\n d.val = o.val;\n d = o;\n }\n // d has at most one child\n // let n be the node that replaces d\n child = d.left || d.right;\n\n if (child === null) {\n isFakeChild = true;\n child = new N({ id: 0 });\n child.blacken();\n d.right = child;\n } else {\n isFakeChild = false;\n }\n\n if (!(d.parent === null)) {\n _context9.next = 14;\n break;\n }\n\n if (!isFakeChild) {\n this.root = child;\n child.blacken();\n child._parent = null;\n } else {\n this.root = null;\n }\n return _context9.abrupt('return');\n\n case 14:\n if (!(d.parent.left === d)) {\n _context9.next = 18;\n break;\n }\n\n d.parent.left = child;\n _context9.next = 23;\n break;\n\n case 18:\n if (!(d.parent.right === d)) {\n _context9.next = 22;\n break;\n }\n\n d.parent.right = child;\n _context9.next = 23;\n break;\n\n case 22:\n throw new Error('Impossible!');\n\n case 23:\n if (d.isBlack()) {\n if (child.isRed()) {\n child.blacken();\n } else {\n this._fixDelete(child);\n }\n }\n this.root.blacken();\n\n if (!isFakeChild) {\n _context9.next = 35;\n break;\n }\n\n if (!(child.parent.left === child)) {\n _context9.next = 30;\n break;\n }\n\n child.parent.left = null;\n _context9.next = 35;\n break;\n\n case 30:\n if (!(child.parent.right === child)) {\n _context9.next = 34;\n break;\n }\n\n child.parent.right = null;\n _context9.next = 35;\n break;\n\n case 34:\n throw new Error('Impossible #3');\n\n case 35:\n case 'end':\n return _context9.stop();\n }\n }\n }, _delete, this);\n })\n }, {\n key: '_fixDelete',\n value: function _fixDelete(n) {\n function isBlack(node) {\n return node !== null ? node.isBlack() : true;\n }\n function isRed(node) {\n return node !== null ? node.isRed() : false;\n }\n if (n.parent === null) {\n // this can only be called after the first iteration of fixDelete.\n return;\n }\n // d was already replaced by the child\n // d is not the root\n // d and child are black\n var sibling = n.sibling;\n if (isRed(sibling)) {\n // make sibling the grandfather\n n.parent.redden();\n sibling.blacken();\n if (n === n.parent.left) {\n n.parent.rotateLeft(this);\n } else if (n === n.parent.right) {\n n.parent.rotateRight(this);\n } else {\n throw new Error('Impossible #2');\n }\n sibling = n.sibling;\n }\n // parent, sibling, and children of n are black\n if (n.parent.isBlack() && sibling.isBlack() && isBlack(sibling.left) && isBlack(sibling.right)) {\n sibling.redden();\n this._fixDelete(n.parent);\n } else if (n.parent.isRed() && sibling.isBlack() && isBlack(sibling.left) && isBlack(sibling.right)) {\n sibling.redden();\n n.parent.blacken();\n } else {\n if (n === n.parent.left && sibling.isBlack() && isRed(sibling.left) && isBlack(sibling.right)) {\n sibling.redden();\n sibling.left.blacken();\n sibling.rotateRight(this);\n sibling = n.sibling;\n } else if (n === n.parent.right && sibling.isBlack() && isRed(sibling.right) && isBlack(sibling.left)) {\n sibling.redden();\n sibling.right.blacken();\n sibling.rotateLeft(this);\n sibling = n.sibling;\n }\n sibling.color = n.parent.color;\n n.parent.blacken();\n if (n === n.parent.left) {\n sibling.right.blacken();\n n.parent.rotateLeft(this);\n } else {\n sibling.left.blacken();\n n.parent.rotateRight(this);\n }\n }\n }\n }, {\n key: 'put',\n value: regeneratorRuntime.mark(function put(v) {\n var node, p;\n return regeneratorRuntime.wrap(function put$(_context10) {\n while (1) {\n switch (_context10.prev = _context10.next) {\n case 0:\n if (!(v == null || v.id == null || v.id.constructor !== Array)) {\n _context10.next = 2;\n break;\n }\n\n throw new Error('v is expected to have an id property which is an Array!');\n\n case 2:\n node = new N(v);\n\n if (!(this.root !== null)) {\n _context10.next = 31;\n break;\n }\n\n p = this.root; // p abbrev. parent\n\n case 5:\n if (!true) {\n _context10.next = 28;\n break;\n }\n\n if (!Y.utils.smaller(node.val.id, p.val.id)) {\n _context10.next = 15;\n break;\n }\n\n if (!(p.left === null)) {\n _context10.next = 12;\n break;\n }\n\n p.left = node;\n return _context10.abrupt('break', 28);\n\n case 12:\n p = p.left;\n\n case 13:\n _context10.next = 26;\n break;\n\n case 15:\n if (!Y.utils.smaller(p.val.id, node.val.id)) {\n _context10.next = 24;\n break;\n }\n\n if (!(p.right === null)) {\n _context10.next = 21;\n break;\n }\n\n p.right = node;\n return _context10.abrupt('break', 28);\n\n case 21:\n p = p.right;\n\n case 22:\n _context10.next = 26;\n break;\n\n case 24:\n p.val = node.val;\n return _context10.abrupt('return', p);\n\n case 26:\n _context10.next = 5;\n break;\n\n case 28:\n this._fixInsert(node);\n _context10.next = 32;\n break;\n\n case 31:\n this.root = node;\n\n case 32:\n this.length++;\n this.root.blacken();\n return _context10.abrupt('return', node);\n\n case 35:\n case 'end':\n return _context10.stop();\n }\n }\n }, put, this);\n })\n }, {\n key: '_fixInsert',\n value: function _fixInsert(n) {\n if (n.parent === null) {\n n.blacken();\n return;\n } else if (n.parent.isBlack()) {\n return;\n }\n var uncle = n.getUncle();\n if (uncle !== null && uncle.isRed()) {\n // Note: parent: red, uncle: red\n n.parent.blacken();\n uncle.blacken();\n n.grandparent.redden();\n this._fixInsert(n.grandparent);\n } else {\n // Note: parent: red, uncle: black or null\n // Now we transform the tree in such a way that\n // either of these holds:\n // 1) grandparent.left.isRed\n // and grandparent.left.left.isRed\n // 2) grandparent.right.isRed\n // and grandparent.right.right.isRed\n if (n === n.parent.right && n.parent === n.grandparent.left) {\n n.parent.rotateLeft(this);\n // Since we rotated and want to use the previous\n // cases, we need to set n in such a way that\n // n.parent.isRed again\n n = n.left;\n } else if (n === n.parent.left && n.parent === n.grandparent.right) {\n n.parent.rotateRight(this);\n // see above\n n = n.right;\n }\n // Case 1) or 2) hold from here on.\n // Now traverse grandparent, make parent a black node\n // on the highest level which holds two red nodes.\n n.parent.blacken();\n n.grandparent.redden();\n if (n === n.parent.left) {\n // Case 1\n n.grandparent.rotateRight(this);\n } else {\n // Case 2\n n.grandparent.rotateLeft(this);\n }\n }\n }\n }]);\n\n return RBTree;\n }();\n\n Y.utils.RBTree = RBTree;\n};\n\n},{}]},{},[1])\n\n","'use strict'\r\n\r\n/*\r\n This file contains a not so fancy implemantion of a Red Black Tree.\r\n*/\r\nmodule.exports = function (Y) {\r\n class N {\r\n // A created node is always red!\r\n constructor (val) {\r\n this.val = val\r\n this.color = true\r\n this._left = null\r\n this._right = null\r\n this._parent = null\r\n if (val.id === null) {\r\n throw new Error('You must define id!')\r\n }\r\n }\r\n isRed () { return this.color }\r\n isBlack () { return !this.color }\r\n redden () { this.color = true; return this }\r\n blacken () { this.color = false; return this }\r\n get grandparent () {\r\n return this.parent.parent\r\n }\r\n get parent () {\r\n return this._parent\r\n }\r\n get sibling () {\r\n return (this === this.parent.left)\r\n ? this.parent.right : this.parent.left\r\n }\r\n get left () {\r\n return this._left\r\n }\r\n get right () {\r\n return this._right\r\n }\r\n set left (n) {\r\n if (n !== null) {\r\n n._parent = this\r\n }\r\n this._left = n\r\n }\r\n set right (n) {\r\n if (n !== null) {\r\n n._parent = this\r\n }\r\n this._right = n\r\n }\r\n rotateLeft (tree) {\r\n var parent = this.parent\r\n var newParent = this.right\r\n var newRight = this.right.left\r\n newParent.left = this\r\n this.right = newRight\r\n if (parent === null) {\r\n tree.root = newParent\r\n newParent._parent = null\r\n } else if (parent.left === this) {\r\n parent.left = newParent\r\n } else if (parent.right === this) {\r\n parent.right = newParent\r\n } else {\r\n throw new Error('The elements are wrongly connected!')\r\n }\r\n }\r\n next () {\r\n if (this.right !== null) {\r\n // search the most left node in the right tree\r\n var o = this.right\r\n while (o.left !== null) {\r\n o = o.left\r\n }\r\n return o\r\n } else {\r\n var p = this\r\n while (p.parent !== null && p !== p.parent.left) {\r\n p = p.parent\r\n }\r\n return p.parent\r\n }\r\n }\r\n prev () {\r\n if (this.left !== null) {\r\n // search the most right node in the left tree\r\n var o = this.left\r\n while (o.right !== null) {\r\n o = o.right\r\n }\r\n return o\r\n } else {\r\n var p = this\r\n while (p.parent !== null && p !== p.parent.right) {\r\n p = p.parent\r\n }\r\n return p.parent\r\n }\r\n }\r\n rotateRight (tree) {\r\n var parent = this.parent\r\n var newParent = this.left\r\n var newLeft = this.left.right\r\n newParent.right = this\r\n this.left = newLeft\r\n if (parent === null) {\r\n tree.root = newParent\r\n newParent._parent = null\r\n } else if (parent.left === this) {\r\n parent.left = newParent\r\n } else if (parent.right === this) {\r\n parent.right = newParent\r\n } else {\r\n throw new Error('The elements are wrongly connected!')\r\n }\r\n }\r\n getUncle () {\r\n // we can assume that grandparent exists when this is called!\r\n if (this.parent === this.parent.parent.left) {\r\n return this.parent.parent.right\r\n } else {\r\n return this.parent.parent.left\r\n }\r\n }\r\n }\r\n\r\n class RBTree {\r\n constructor () {\r\n this.root = null\r\n this.length = 0\r\n }\r\n * findNext (id) {\r\n return yield* this.findWithLowerBound([id[0], id[1] + 1])\r\n }\r\n * findPrev (id) {\r\n return yield* this.findWithUpperBound([id[0], id[1] - 1])\r\n }\r\n findNodeWithLowerBound (from) {\r\n if (from === void 0) {\r\n throw new Error('You must define from!')\r\n }\r\n var o = this.root\r\n if (o === null) {\r\n return null\r\n } else {\r\n while (true) {\r\n if ((from === null || Y.utils.smaller(from, o.val.id)) && o.left !== null) {\r\n // o is included in the bound\r\n // try to find an element that is closer to the bound\r\n o = o.left\r\n } else if (from !== null && Y.utils.smaller(o.val.id, from)) {\r\n // o is not within the bound, maybe one of the right elements is..\r\n if (o.right !== null) {\r\n o = o.right\r\n } else {\r\n // there is no right element. Search for the next bigger element,\r\n // this should be within the bounds\r\n return o.next()\r\n }\r\n } else {\r\n return o\r\n }\r\n }\r\n }\r\n }\r\n findNodeWithUpperBound (to) {\r\n if (to === void 0) {\r\n throw new Error('You must define from!')\r\n }\r\n var o = this.root\r\n if (o === null) {\r\n return null\r\n } else {\r\n while (true) {\r\n if ((to === null || Y.utils.smaller(o.val.id, to)) && o.right !== null) {\r\n // o is included in the bound\r\n // try to find an element that is closer to the bound\r\n o = o.right\r\n } else if (to !== null && Y.utils.smaller(to, o.val.id)) {\r\n // o is not within the bound, maybe one of the left elements is..\r\n if (o.left !== null) {\r\n o = o.left\r\n } else {\r\n // there is no left element. Search for the prev smaller element,\r\n // this should be within the bounds\r\n return o.prev()\r\n }\r\n } else {\r\n return o\r\n }\r\n }\r\n }\r\n }\r\n * findWithLowerBound (from) {\r\n var n = this.findNodeWithLowerBound(from)\r\n return n == null ? null : n.val\r\n }\r\n * findWithUpperBound (to) {\r\n var n = this.findNodeWithUpperBound(to)\r\n return n == null ? null : n.val\r\n }\r\n * iterate (t, from, to, f) {\r\n var o = this.findNodeWithLowerBound(from)\r\n while (o !== null && (to === null || Y.utils.smaller(o.val.id, to) || Y.utils.compareIds(o.val.id, to))) {\r\n yield* f.call(t, o.val)\r\n o = o.next()\r\n }\r\n return true\r\n }\r\n * logTable (from, to, filter) {\r\n if (filter == null) {\r\n filter = function () {\r\n return true\r\n }\r\n }\r\n if (from == null) { from = null }\r\n if (to == null) { to = null }\r\n var os = []\r\n yield* this.iterate(this, from, to, function * (o) {\r\n if (filter(o)) {\r\n var o_ = {}\r\n for (var key in o) {\r\n if (typeof o[key] === 'object') {\r\n o_[key] = JSON.stringify(o[key])\r\n } else {\r\n o_[key] = o[key]\r\n }\r\n }\r\n os.push(o_)\r\n }\r\n })\r\n if (console.table != null) {\r\n console.table(os)\r\n }\r\n }\r\n * find (id) {\r\n var n\r\n return (n = this.findNode(id)) ? n.val : null\r\n }\r\n findNode (id) {\r\n if (id == null || id.constructor !== Array) {\r\n throw new Error('Expect id to be an array!')\r\n }\r\n var o = this.root\r\n if (o === null) {\r\n return false\r\n } else {\r\n while (true) {\r\n if (o === null) {\r\n return false\r\n }\r\n if (Y.utils.smaller(id, o.val.id)) {\r\n o = o.left\r\n } else if (Y.utils.smaller(o.val.id, id)) {\r\n o = o.right\r\n } else {\r\n return o\r\n }\r\n }\r\n }\r\n }\r\n * delete (id) {\r\n if (id == null || id.constructor !== Array) {\r\n throw new Error('id is expected to be an Array!')\r\n }\r\n var d = this.findNode(id)\r\n if (d == null) {\r\n throw new Error('Element does not exist!')\r\n }\r\n this.length--\r\n if (d.left !== null && d.right !== null) {\r\n // switch d with the greates element in the left subtree.\r\n // o should have at most one child.\r\n var o = d.left\r\n // find\r\n while (o.right !== null) {\r\n o = o.right\r\n }\r\n // switch\r\n d.val = o.val\r\n d = o\r\n }\r\n // d has at most one child\r\n // let n be the node that replaces d\r\n var isFakeChild\r\n var child = d.left || d.right\r\n if (child === null) {\r\n isFakeChild = true\r\n child = new N({id: 0})\r\n child.blacken()\r\n d.right = child\r\n } else {\r\n isFakeChild = false\r\n }\r\n\r\n if (d.parent === null) {\r\n if (!isFakeChild) {\r\n this.root = child\r\n child.blacken()\r\n child._parent = null\r\n } else {\r\n this.root = null\r\n }\r\n return\r\n } else if (d.parent.left === d) {\r\n d.parent.left = child\r\n } else if (d.parent.right === d) {\r\n d.parent.right = child\r\n } else {\r\n throw new Error('Impossible!')\r\n }\r\n if (d.isBlack()) {\r\n if (child.isRed()) {\r\n child.blacken()\r\n } else {\r\n this._fixDelete(child)\r\n }\r\n }\r\n this.root.blacken()\r\n if (isFakeChild) {\r\n if (child.parent.left === child) {\r\n child.parent.left = null\r\n } else if (child.parent.right === child) {\r\n child.parent.right = null\r\n } else {\r\n throw new Error('Impossible #3')\r\n }\r\n }\r\n }\r\n _fixDelete (n) {\r\n function isBlack (node) {\r\n return node !== null ? node.isBlack() : true\r\n }\r\n function isRed (node) {\r\n return node !== null ? node.isRed() : false\r\n }\r\n if (n.parent === null) {\r\n // this can only be called after the first iteration of fixDelete.\r\n return\r\n }\r\n // d was already replaced by the child\r\n // d is not the root\r\n // d and child are black\r\n var sibling = n.sibling\r\n if (isRed(sibling)) {\r\n // make sibling the grandfather\r\n n.parent.redden()\r\n sibling.blacken()\r\n if (n === n.parent.left) {\r\n n.parent.rotateLeft(this)\r\n } else if (n === n.parent.right) {\r\n n.parent.rotateRight(this)\r\n } else {\r\n throw new Error('Impossible #2')\r\n }\r\n sibling = n.sibling\r\n }\r\n // parent, sibling, and children of n are black\r\n if (n.parent.isBlack() &&\r\n sibling.isBlack() &&\r\n isBlack(sibling.left) &&\r\n isBlack(sibling.right)\r\n ) {\r\n sibling.redden()\r\n this._fixDelete(n.parent)\r\n } else if (n.parent.isRed() &&\r\n sibling.isBlack() &&\r\n isBlack(sibling.left) &&\r\n isBlack(sibling.right)\r\n ) {\r\n sibling.redden()\r\n n.parent.blacken()\r\n } else {\r\n if (n === n.parent.left &&\r\n sibling.isBlack() &&\r\n isRed(sibling.left) &&\r\n isBlack(sibling.right)\r\n ) {\r\n sibling.redden()\r\n sibling.left.blacken()\r\n sibling.rotateRight(this)\r\n sibling = n.sibling\r\n } else if (n === n.parent.right &&\r\n sibling.isBlack() &&\r\n isRed(sibling.right) &&\r\n isBlack(sibling.left)\r\n ) {\r\n sibling.redden()\r\n sibling.right.blacken()\r\n sibling.rotateLeft(this)\r\n sibling = n.sibling\r\n }\r\n sibling.color = n.parent.color\r\n n.parent.blacken()\r\n if (n === n.parent.left) {\r\n sibling.right.blacken()\r\n n.parent.rotateLeft(this)\r\n } else {\r\n sibling.left.blacken()\r\n n.parent.rotateRight(this)\r\n }\r\n }\r\n }\r\n * put (v) {\r\n if (v == null || v.id == null || v.id.constructor !== Array) {\r\n throw new Error('v is expected to have an id property which is an Array!')\r\n }\r\n var node = new N(v)\r\n if (this.root !== null) {\r\n var p = this.root // p abbrev. parent\r\n while (true) {\r\n if (Y.utils.smaller(node.val.id, p.val.id)) {\r\n if (p.left === null) {\r\n p.left = node\r\n break\r\n } else {\r\n p = p.left\r\n }\r\n } else if (Y.utils.smaller(p.val.id, node.val.id)) {\r\n if (p.right === null) {\r\n p.right = node\r\n break\r\n } else {\r\n p = p.right\r\n }\r\n } else {\r\n p.val = node.val\r\n return p\r\n }\r\n }\r\n this._fixInsert(node)\r\n } else {\r\n this.root = node\r\n }\r\n this.length++\r\n this.root.blacken()\r\n return node\r\n }\r\n _fixInsert (n) {\r\n if (n.parent === null) {\r\n n.blacken()\r\n return\r\n } else if (n.parent.isBlack()) {\r\n return\r\n }\r\n var uncle = n.getUncle()\r\n if (uncle !== null && uncle.isRed()) {\r\n // Note: parent: red, uncle: red\r\n n.parent.blacken()\r\n uncle.blacken()\r\n n.grandparent.redden()\r\n this._fixInsert(n.grandparent)\r\n } else {\r\n // Note: parent: red, uncle: black or null\r\n // Now we transform the tree in such a way that\r\n // either of these holds:\r\n // 1) grandparent.left.isRed\r\n // and grandparent.left.left.isRed\r\n // 2) grandparent.right.isRed\r\n // and grandparent.right.right.isRed\r\n if (n === n.parent.right && n.parent === n.grandparent.left) {\r\n n.parent.rotateLeft(this)\r\n // Since we rotated and want to use the previous\r\n // cases, we need to set n in such a way that\r\n // n.parent.isRed again\r\n n = n.left\r\n } else if (n === n.parent.left && n.parent === n.grandparent.right) {\r\n n.parent.rotateRight(this)\r\n // see above\r\n n = n.right\r\n }\r\n // Case 1) or 2) hold from here on.\r\n // Now traverse grandparent, make parent a black node\r\n // on the highest level which holds two red nodes.\r\n n.parent.blacken()\r\n n.grandparent.redden()\r\n if (n === n.parent.left) {\r\n // Case 1\r\n n.grandparent.rotateRight(this)\r\n } else {\r\n // Case 2\r\n n.grandparent.rotateLeft(this)\r\n }\r\n }\r\n }\r\n }\r\n\r\n Y.utils.RBTree = RBTree\r\n}\r\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/Examples/bower_components/y-richtext/.bower.json b/Examples/bower_components/y-richtext/.bower.json new file mode 100644 index 00000000..f03b8788 --- /dev/null +++ b/Examples/bower_components/y-richtext/.bower.json @@ -0,0 +1,36 @@ +{ + "name": "y-richtext", + "version": "0.7.5", + "authors": [ + "corentin.cadiou@linagora.com", + "kevin.jahns@rwth-aachen.de" + ], + "description": "Rich Text type for Yjs", + "keywords": [ + "webrtc", + "text", + "edition", + "collaborative", + "rich text" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": {}, + "homepage": "https://github.com/y-js/y-richtext", + "_release": "0.7.5", + "_resolution": { + "type": "version", + "tag": "v0.7.5", + "commit": "5a6056fa835fab93e6add70537dde4cb67e8428c" + }, + "_source": "git://github.com/y-js/y-richtext.git", + "_target": "~0.7.5", + "_originalSource": "y-richtext", + "_direct": true +} \ No newline at end of file diff --git a/Examples/bower_components/y-richtext/LICENSE.txt b/Examples/bower_components/y-richtext/LICENSE.txt new file mode 100644 index 00000000..76c752bb --- /dev/null +++ b/Examples/bower_components/y-richtext/LICENSE.txt @@ -0,0 +1,25 @@ +The MIT License (MIT) + +Copyright (c) 2015 + - Corentin Cadiou + - Kevin Jahns + - Linagora + - Veeting.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Examples/bower_components/y-richtext/Readme.md b/Examples/bower_components/y-richtext/Readme.md new file mode 100644 index 00000000..27ebe711 --- /dev/null +++ b/Examples/bower_components/y-richtext/Readme.md @@ -0,0 +1,59 @@ + +# Rich Text type for [Yjs](https://github.com/y-js/richtext) + +This type strongly resembles the [rich text](https://github.com/ottypes/rich-text) format for operational transformation. Under the hood, however, several mechanisms ensure that the intentions of your changes are preserved. Furthermore, you can transform the actions on the document in the rich text format back and forth, and, therefore, you can bind this type to any rich text editor that supports the widely used rich text format. + + +## Use it! +Retrieve this with bower or npm. + +##### Bower +``` +bower install y-richtext --save +``` + +and include the js library. + +``` + +``` + +##### NPM +``` +npm install y-richtext --save +``` +and put it on the `Y` object. + +``` +Y.RichText = require("y-richtext"); +``` + + +### RichText Object + +##### Reference +* Create +``` +var yrichtext = new Y.RichText() +``` +* Create +``` +var yrichtext = new Y.RichText(ot_delta) +``` +* .bind(editor) + * Bind this type to an rich text editor. (Currently, only QuillJs is supported) + + +# A note on intention preservation +This type has several mechanisms to ensure that the intention of your actions are preserved. For example: +* If two users fix a word concurrently, only one change will prevail. A classical example is that two users want to correct the word "missplled". If two users correct it at the same time (or they merge after they corrected it offline), the result in operation transformation algorithms would be "misspeelled". This type will ensure that the result is "misspelled" +* When a user inserts content *c* after a set of content *C_left*, and before a set of content *C_right*, then *C_left* will be always to the left of c, and *C_right* will be always to the right of *c*. This property will also hold when content is deleted or when a deletion is undone. + +## Contribution +We thank [Veeting](https://www.veeting.com/) and [Linagora](https://www.linagora.com/) who sponsored this work, and agreed to publish it as Open Source. + +## License +Yjs and the RichText type are licensed under the [MIT License](./LICENSE.txt). + +- Corentin Cadiou +- Kevin Jahns diff --git a/Examples/bower_components/y-richtext/bower.json b/Examples/bower_components/y-richtext/bower.json new file mode 100644 index 00000000..4d498fa1 --- /dev/null +++ b/Examples/bower_components/y-richtext/bower.json @@ -0,0 +1,25 @@ +{ + "name": "y-richtext", + "version": "0.7.6", + "authors": [ + "corentin.cadiou@linagora.com", + "kevin.jahns@rwth-aachen.de" + ], + "description": "Rich Text type for Yjs", + "keywords": [ + "webrtc", + "text", + "edition", + "collaborative", + "rich text" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": {} +} diff --git a/Examples/bower_components/y-richtext/y-richtext.es6 b/Examples/bower_components/y-richtext/y-richtext.es6 new file mode 100644 index 00000000..3d69e1c6 --- /dev/null +++ b/Examples/bower_components/y-richtext/y-richtext.es6 @@ -0,0 +1,503 @@ +(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 0) { + op.insert = op.insert.join('') + ops.push(op) + createNewOp() + } + if (v[1] === null) { + delete op.attributes[v[0]] + } else { + op.attributes[v[0]] = v[1] + } + } else { + op.insert.push(v) + } + } + if (op.insert.length > 0) { + op.insert = op.insert.join('') + ops.push(op) + } + return ops + } + insert (pos, content) { + var curPos = 0 + var selection = {} + for (var i = 0; i < this.valArray.length; i++) { + if (curPos === pos) { + break + } + var v = this.valArray[i] + if (typeof v === 'string') { + curPos++ + } else if (v.constructor === Array) { + if (v[1] === null) { + delete selection[v[0]] + } else { + selection[v[0]] = v[1] + } + } + } + super.insert(i, content.split('')) + return selection + } + delete (pos, length) { + /* + let x = to be deleted string + let s = some string + let * = some selection + E.g. + sss*s***x*xxxxx***xx*x**ss*s + |---delete-range--| + delStart delEnd + + We'll check the following + * is it possible to delete some of the selections? + 1. a dominating selection to the right could be the same as the selection (curSel) to delStart + 2. a selections could be overwritten by another selection to the right + */ + var curPos = 0 + var curSel = {} + var endPos = pos + length + if (length <= 0) return + var delStart // relative to valArray + var delEnd // .. + var v, i // helper variable for elements of valArray + + for (delStart = 0, v = this.valArray[delStart]; curPos < pos && delStart < this.valArray.length; v = this.valArray[++delStart]) { + if (typeof v === 'string') { + curPos++ + } else if (v.constructor === Array) { + curSel[v[0]] = v[1] + } + } + for (delEnd = delStart, v = this.valArray[delEnd]; curPos < endPos && delEnd < this.valArray.length; v = this.valArray[++delEnd]) { + if (typeof v === 'string') { + curPos++ + } + } + if (delEnd === this.valArray.length) { + // yay, you can delete everything without checking + for (i = delEnd - 1, v = this.valArray[i]; i >= delStart; v = this.valArray[--i]) { + super.delete(i, 1) + } + } else { + if (typeof v === 'string') { + delEnd-- + } + var rightSel = {} + for (i = delEnd, v = this.valArray[i]; i >= delStart; v = this.valArray[--i]) { + if (v.constructor === Array) { + if (rightSel[v[0]] === undefined) { + if (v[1] === curSel[v[0]]) { + // case 1. + super.delete(i, 1) + } + rightSel[v[0]] = v[1] + } else { + // case 2. + super.delete(i, 1) + } + } else if (typeof v === 'string') { + // always delete the strings + super.delete(i, 1) + } + } + } + } + /* + 1. get selection attributes from position $from + (name it antiAttrs, and we'll use it to make sure that selection ends in antiAttrs) + 2. Insert selection $attr, if necessary + 3. Between from and to, we'll delete all selections that do not match $attr. + Furthermore, we'll update antiAttrs, if necessary + 4. In the end well insert a selection that makes sure that selection($to) ends in antiAttrs + */ + select (from, to, attrName, attrValue) { + if (from == null || to == null || attrName == null || attrValue === undefined) { + throw new Error('You must define four parameters') + } else { + var step2i + var step2sel + var antiAttrs = [attrName, null] + var curPos = 0 + var i = 0 + // 1. compute antiAttrs + for (; i < this.valArray.length; i++) { + let v = this.valArray[i] + if (curPos === from) { + break + } + if (v.constructor === Array) { + if (v[0] === attrName) { + antiAttrs[1] = v[1] + } + } else if (typeof v === 'string') { + curPos++ + } + } + // 2. Insert attr + if (antiAttrs[1] !== attrValue) { + // we'll execute this later + step2i = i + step2sel = [attrName, attrValue] + } + + // 3. update antiAttrs, modify selection + var deletes = [] + for (; i < this.valArray.length; i++) { + let v = this.valArray[i] + if (curPos === to) { + break + } + if (v.constructor === Array) { + if (v[0] === attrName) { + antiAttrs[1] = v[1] + deletes.push(i) + } + } else if (typeof v === 'string') { + curPos++ + } + } + // actually delete the found selections + // also.. we have to delete from right to left (so that the positions dont change) + for (var j = deletes.length - 1; j >= 0; j--) { + var del = deletes[j] + super.delete(del, 1) + // update i, rel. to + if (del < i) { + i-- + } + if (del < step2i) { + step2i-- + } + } + // 4. Update selection to match antiAttrs + // never insert, if not necessary + // 1. when it is the last position ~ i < valArray.length) + // 2. when a similar attrName already exists between i and the next character + if (antiAttrs[1] !== attrValue && i < this.valArray.length) { // check 1. + var performStep4 = true + var v + for (j = i, v = this.valArray[j]; j < this.valArray.length && v.constructor === Array; v = this.valArray[++j]) { + if (v[0] === attrName) { + performStep4 = false // check 2. + if (v[1] === attrValue) { + super.delete(j, 1) + } + break + } + } + if (performStep4) { + var sel = [attrName, antiAttrs[1]] + super.insert(i, [sel]) + } + } + if (step2i != null) { + super.insert(step2i, [step2sel]) + // if there are some selections to the left of step2sel, delete them if possible + // * have same attribute name + // * no insert between step2sel and selection + for (j = step2i - 1, v = this.valArray[j]; j >= 0 && v.constructor === Array; v = this.valArray[--j]) { + if (v[0] === attrName) { + super.delete(j, 1) + } + } + } + } + } + bind (quill) { + this.instances.push(quill) + var self = this + + // this function makes sure that either the + // quill event is executed, or the yjs observer is executed + var token = true + function mutualExcluse (f) { + if (token) { + token = false + try { + f() + } catch (e) { + token = true + throw new Error(e) + } + token = true + } + } + + quill.setContents(this.toOTOps()) + + quill.on('text-change', function (delta) { + mutualExcluse(function () { + var pos = 0 + var name // helper variable + for (var i = 0; i < delta.ops.length; i++) { + var op = delta.ops[i] + if (op.insert != null) { + var attrs = self.insert(pos, op.insert) + // create new selection + for (name in op.attributes) { + if (op.attributes[name] !== attrs[name]) { + self.select(pos, pos + op.insert.length, name, op.attributes[name]) + } + } + // not-existence of an attribute in op.attributes denotes + // that we have to unselect (set to null) + for (name in attrs) { + if (op.attributes == null || attrs[name] !== op.attributes[name]) { + self.select(pos, pos + op.insert.length, name, null) + } + } + pos += op.insert.length + } + if (op.delete != null) { + self.delete(pos, op.delete) + } + if (op.retain != null) { + var afterRetain = pos + op.retain + if (afterRetain > self.length) { + var diff = afterRetain - self.length + var enters = '' + while (diff !== 0) { + diff-- + enters += '\n' + } + for (name in op.attributes) { + quill.formatText(self.length, self.length + op.retain, name, null) + // quill.deleteText(self.length, self.length + op.retain) + } + quill.insertText(self.length, enters, op.attributes) + self.insert(self.length, enters) + } + for (name in op.attributes) { + self.select(pos, pos + op.retain, name, op.attributes[name]) + } + pos = afterRetain + } + } + }) + }) + this.observe(function (events) { + mutualExcluse(function () { + var v // helper variable + var curSel // helper variable (current selection) + for (var i = 0; i < events.length; i++) { + var event = events[i] + if (event.type === 'insert') { + if (typeof event.value === 'string') { + var position = 0 + var insertSel = {} + for (var l = event.index - 1; l >= 0; l--) { + v = self.valArray[l] + if (typeof v === 'string') { + position++ + } else if (v.constructor === Array && typeof insertSel[v[0]] === 'undefined') { + insertSel[v[0]] = v[1] + } + } + quill.insertText(position, event.value, insertSel) + } else if (event.value.constructor === Array) { + // a new selection is created + // find left selection that matches newSel[0] + curSel = null + var newSel = event.value + // denotes the start position of the selection + // (without the selection objects) + var selectionStart = 0 + for (var j = event.index - 1; j >= 0; j--) { + v = self.valArray[j] + if (v.constructor === Array) { + // check if v matches newSel + if (newSel[0] === v[0]) { + // found a selection + // update curSel and go to next step + curSel = v[1] + break + } + } else if (typeof v === 'string') { + selectionStart++ + } + } + // make sure to decrement j, so we correctly compute selectionStart + for (; j >= 0; j--) { + v = self.valArray[j] + if (typeof v === 'string') { + selectionStart++ + } + } + // either a selection was found {then curSel was updated}, or not (then curSel = null) + if (newSel[1] === curSel) { + // both are the same. not necessary to do anything + return + } + // now find out the range over which newSel has to be created + var selectionEnd = selectionStart + for (var k = event.index + 1; k < self.valArray.length; k++) { + v = self.valArray[k] + if (v.constructor === Array) { + if (v[0] === newSel[0]) { + // found another selection with same attr name + break + } + } else if (typeof v === 'string') { + selectionEnd++ + } + } + // create a selection from selectionStart to selectionEnd + if (selectionStart !== selectionEnd) { + quill.formatText(selectionStart, selectionEnd, newSel[0], newSel[1]) + } + } + } else if (event.type === 'delete') { + if (typeof event.value === 'string') { // TODO: see button. add || `event.length > 1` + // only if these conditions are true, we have to actually check if we have to delete sth. + // Then we have to check if between pos and pos + event.length are selections: + // delete till pos + (event.length - number of selections) + var pos = 0 + for (var u = 0; u < event.index; u++) { + v = self.valArray[u] + if (typeof v === 'string') { + pos++ + } + } + var delLength = event.length + /* TODO!! + they do not exist anymore.. so i can't query. you have to query over event.value(s) - but that not yet implemented + for (; i < event.index + event.length; i++) { + if (self.valArray[i].constructor === Array) { + delLength-- + } + }*/ + quill.deleteText(pos, pos + delLength) + } else if (event.value.constructor === Array) { + curSel = null + var from = 0 + var x + for (x = event.index - 1; x >= 0; x--) { + v = self.valArray[x] + if (v.constructor === Array) { + if (v[0] === event.value[0]) { + curSel = v[1] + break + } + } else if (typeof v === 'string') { + from++ + } + } + for (; x >= 0; v = self.valArray[--x]) { + if (typeof v === 'string') { + from++ + } + } + var to = from + for (x = event.index; x < self.valArray.length; x++) { + v = self.valArray[x] + if (v.constructor === Array) { + if (v[0] === event.value[0]) { + break + } + } else if (typeof v === 'string') { + to++ + } + } + if (curSel !== event.value[1] && from !== to) { + quill.formatText(from, to, event.value[0], curSel) + } + } + } + } + quill.editor.checkUpdate() + }) + }) + } + * _changed () { + this.instances.forEach(function (quill) { + quill.editor.checkUpdate() + }) + yield* Y.Array.class.prototype._changed.apply(this, arguments) + } + } + Y.extend('Richtext', new Y.utils.CustomType({ + name: 'Richtext', + class: YRichtext, + struct: 'List', + initType: function * YTextInitializer (os, model) { + var valArray = [] + var idArray = yield* Y.Struct.List.map.call(this, model, function (c) { + valArray.push(c.content) + return JSON.stringify(c.id) + }) + return new YRichtext(os, model.id, idArray, valArray) + } + })) + }) +} + +module.exports = extend +if (typeof Y !== 'undefined') { + extend(Y) +} + +},{}]},{},[1]) + diff --git a/Examples/bower_components/y-richtext/y-richtext.js b/Examples/bower_components/y-richtext/y-richtext.js new file mode 100644 index 00000000..96415b12 --- /dev/null +++ b/Examples/bower_components/y-richtext/y-richtext.js @@ -0,0 +1,2 @@ +!function t(r,e,n){function i(o,s){if(!e[o]){if(!r[o]){var l="function"==typeof require&&require;if(!s&&l)return l(o,!0);if(a)return a(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var f=e[o]={exports:{}};r[o][0].call(f.exports,function(t){var e=r[o][1][t];return i(e?e:t)},f,f.exports,t,r,e,n)}return e[o].exports}for(var a="function"==typeof require&&require,o=0;o0&&(e.insert=e.insert.join(""),r.push(e),t()),null===i[1]?delete e.attributes[i[0]]:e.attributes[i[0]]=i[1]):e.insert.push(i)}return e.insert.length>0&&(e.insert=e.insert.join(""),r.push(e)),r}},{key:"insert",value:function(t,r){for(var n=0,i={},a=0;a=r)){var o,s,u,f;for(o=0,u=this.valArray[o];t>n&&on&&s=o;u=this.valArray[--f])l(Object.getPrototypeOf(e.prototype),"delete",this).call(this,f,1);else{"string"==typeof u&&s--;var c={};for(f=s,u=this.valArray[f];f>=o;u=this.valArray[--f])u.constructor===Array?void 0===c[u[0]]?(u[1]===i[u[0]]&&l(Object.getPrototypeOf(e.prototype),"delete",this).call(this,f,1),c[u[0]]=u[1]):l(Object.getPrototypeOf(e.prototype),"delete",this).call(this,f,1):"string"==typeof u&&l(Object.getPrototypeOf(e.prototype),"delete",this).call(this,f,1)}}}},{key:"select",value:function(t,r,n,i){if(null==t||null==r||null==n||void 0===i)throw new Error("You must define four parameters");for(var a,o,s=[n,null],u=0,f=0;f=0;v--){var p=y[v];l(Object.getPrototypeOf(e.prototype),"delete",this).call(this,p,1),f>p&&f--,a>p&&a--}if(s[1]!==i&&f=0&&g.constructor===Array;g=this.valArray[--v])g[0]===n&&l(Object.getPrototypeOf(e.prototype),"delete",this).call(this,v,1)}},{key:"bind",value:function(t){function r(t){if(n){n=!1;try{t()}catch(r){throw n=!0,new Error(r)}n=!0}}this.instances.push(t);var e=this,n=!0;t.setContents(this.toOTOps()),t.on("text-change",function(n){r(function(){for(var r,i=0,a=0;ae.length){for(var u=l-e.length,f="";0!==u;)u--,f+="\n";for(r in o.attributes)t.formatText(e.length,e.length+o.retain,r,null);t.insertText(e.length,f,o.attributes),e.insert(e.length,f)}for(r in o.attributes)e.select(i,i+o.retain,r,o.attributes[r]);i=l}}})}),this.observe(function(n){r(function(){for(var r,i,a=0;a=0;u--)r=e.valArray[u],"string"==typeof r?s++:r.constructor===Array&&"undefined"==typeof l[r[0]]&&(l[r[0]]=r[1]);t.insertText(s,o.value,l)}else if(o.value.constructor===Array){i=null;for(var f=o.value,c=0,y=o.index-1;y>=0;y--)if(r=e.valArray[y],r.constructor===Array){if(f[0]===r[0]){i=r[1];break}}else"string"==typeof r&&c++;for(;y>=0;y--)r=e.valArray[y],"string"==typeof r&&c++;if(f[1]===i)return;for(var h=c,v=o.index+1;v=0;b--)if(r=e.valArray[b],r.constructor===Array){if(r[0]===o.value[0]){i=r[1];break}}else"string"==typeof r&&A++;for(;b>=0;r=e.valArray[--b])"string"==typeof r&&A++;var O=A;for(b=o.index;b" + ], + "description": "Text type for Yjs", + "main": "./src/Text.js", + "keywords": [ + "OT", + "collaboration", + "synchronization", + "ShareJS", + "Coweb", + "concurrency" + ], + "license": "MIT", + "ignore": [ + "node_modules", + "bower_components", + "test", + "extras", + "test" + ], + "devDependencies": {}, + "_release": "0.7.1", + "_resolution": { + "type": "version", + "tag": "v0.7.1", + "commit": "bdb6553994226703504875431c56436704b3af57" + }, + "_source": "git://github.com/y-js/y-text.git", + "_target": "~0.7.1", + "_originalSource": "y-text", + "_direct": true +} \ No newline at end of file diff --git a/Examples/bower_components/y-text/.bowerrc b/Examples/bower_components/y-text/.bowerrc new file mode 100644 index 00000000..7bbfd373 --- /dev/null +++ b/Examples/bower_components/y-text/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "../" +} diff --git a/Examples/bower_components/y-text/.gitignore b/Examples/bower_components/y-text/.gitignore new file mode 100644 index 00000000..18092522 --- /dev/null +++ b/Examples/bower_components/y-text/.gitignore @@ -0,0 +1,6 @@ +/node_modules/ +bower_components +.directory +.c9 +.codio +.settings \ No newline at end of file diff --git a/Examples/bower_components/y-text/.travis.yml b/Examples/bower_components/y-text/.travis.yml new file mode 100644 index 00000000..e830c82b --- /dev/null +++ b/Examples/bower_components/y-text/.travis.yml @@ -0,0 +1,11 @@ +language: node_js +before_install: + - "npm install -g bower coffee-script" + - "bower install" +node_js: + - "0.12" + - "0.11" + - "0.10" +branches: + only: + - master \ No newline at end of file diff --git a/Examples/bower_components/y-text/bower.json b/Examples/bower_components/y-text/bower.json new file mode 100644 index 00000000..544b8133 --- /dev/null +++ b/Examples/bower_components/y-text/bower.json @@ -0,0 +1,27 @@ +{ + "name": "y-text", + "version": "0.7.2", + "homepage": "http://y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "Text type for Yjs", + "main": "./src/Text.js", + "keywords": [ + "OT", + "collaboration", + "synchronization", + "ShareJS", + "Coweb", + "concurrency" + ], + "license": "MIT", + "ignore": [ + "node_modules", + "bower_components", + "test", + "extras", + "test" + ], + "devDependencies": {} +} diff --git a/Examples/bower_components/y-text/y-text.es6 b/Examples/bower_components/y-text/y-text.es6 new file mode 100644 index 00000000..e5a39bc6 --- /dev/null +++ b/Examples/bower_components/y-text/y-text.es6 @@ -0,0 +1,291 @@ +(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 textnode.length) { + range.right = textnode.length + } + range.left = Math.min(range.left, range.right) + var r = document.createRange(); // eslint-disable-line + r.setStart(textnode, range.left) + r.setEnd(textnode, range.right) + var s = window.getSelection(); // eslint-disable-line + s.removeAllRanges() + s.addRange(r) + } + } + writeContent = function (content) { + var contentArray = content.replace(new RegExp('\n', 'g'), ' ').split(' ');// eslint-disable-line + textfield.innerText = '' + for (var i in contentArray) { + var c = contentArray[i] + textfield.innerText += c + if (i !== contentArray.length - 1) { + textfield.innerHTML += ' ' + } + } + } + } + writeContent(this.toString()) + + this.observe(function (events) { + for (var e in events) { + var event = events[e] + if (!creatorToken) { + var oPos, fix + if (event.type === 'insert') { + oPos = event.index + fix = function (cursor) {// eslint-disable-line + if (cursor <= oPos) { + return cursor + } else { + cursor += 1 + return cursor + } + } + var r = createRange(fix) + writeRange(r) + } else if (event.type === 'delete') { + oPos = event.index + fix = function (cursor) {// eslint-disable-line + if (cursor < oPos) { + return cursor + } else { + cursor -= 1 + return cursor + } + } + r = createRange(fix) + writeRange(r) + } + } + } + }) + // consume all text-insert changes. + textfield.onkeypress = function (event) { + if (word.is_deleted) { + // if word is deleted, do not do anything ever again + textfield.onkeypress = null + return true + } + creatorToken = true + var char + if (event.keyCode === 13) { + char = '\n' + } else if (event.key != null) { + if (event.charCode === 32) { + char = ' ' + } else { + char = event.key + } + } else { + char = window.String.fromCharCode(event.keyCode); // eslint-disable-line + } + if (char.length > 1) { + return true + } else if (char.length > 0) { + var r = createRange() + var pos = Math.min(r.left, r.right, word.length) + var diff = Math.abs(r.right - r.left) + word.delete(pos, diff) + word.insert(pos, char) + r.left = pos + char.length + r.right = r.left + writeRange(r) + } + event.preventDefault() + creatorToken = false + return false + } + textfield.onpaste = function (event) { + if (word.is_deleted) { + // if word is deleted, do not do anything ever again + textfield.onpaste = null + return true + } + event.preventDefault() + } + textfield.oncut = function (event) { + if (word.is_deleted) { + // if word is deleted, do not do anything ever again + textfield.oncut = null + return true + } + event.preventDefault() + } + // + // consume deletes. Note that + // chrome: won't consume deletions on keypress event. + // keyCode is deprecated. BUT: I don't see another way. + // since event.key is not implemented in the current version of chrome. + // Every browser supports keyCode. Let's stick with it for now.. + // + textfield.onkeydown = function (event) { + creatorToken = true + if (word.is_deleted) { + // if word is deleted, do not do anything ever again + textfield.onkeydown = null + return true + } + var r = createRange() + var pos = Math.min(r.left, r.right, word.toString().length) + var diff = Math.abs(r.left - r.right) + if (event.keyCode != null && event.keyCode === 8) { // Backspace + if (diff > 0) { + word.delete(pos, diff) + r.left = pos + r.right = pos + writeRange(r) + } else { + if (event.ctrlKey != null && event.ctrlKey) { + var val = word.toString() + var newPos = pos + var delLength = 0 + if (pos > 0) { + newPos-- + delLength++ + } + while (newPos > 0 && val[newPos] !== ' ' && val[newPos] !== '\n') { + newPos-- + delLength++ + } + word.delete(newPos, pos - newPos) + r.left = newPos + r.right = newPos + writeRange(r) + } else { + if (pos > 0) { + word.delete(pos - 1, 1) + r.left = pos - 1 + r.right = pos - 1 + writeRange(r) + } + } + } + event.preventDefault() + creatorToken = false + return false + } else if (event.keyCode != null && event.keyCode === 46) { // Delete + if (diff > 0) { + word.delete(pos, diff) + r.left = pos + r.right = pos + writeRange(r) + } else { + word.delete(pos, 1) + r.left = pos + r.right = pos + writeRange(r) + } + event.preventDefault() + creatorToken = false + return false + } else { + creatorToken = false + return true + } + } + } + } + Y.extend('Text', new Y.utils.CustomType({ + name: 'Text', + class: YText, + struct: 'List', + initType: function * YTextInitializer (os, model) { + var valArray = [] + var idArray = yield* Y.Struct.List.map.call(this, model, function (c) { + valArray.push(c.content) + return JSON.stringify(c.id) + }) + return new YText(os, model.id, idArray, valArray) + } + })) + }) +} + +module.exports = extend +if (typeof Y !== 'undefined') { + extend(Y) +} + +},{}]},{},[1]) + diff --git a/Examples/bower_components/y-text/y-text.es6.map b/Examples/bower_components/y-text/y-text.es6.map new file mode 100644 index 00000000..c9b6d6d2 --- /dev/null +++ b/Examples/bower_components/y-text/y-text.es6.map @@ -0,0 +1 @@ +{"version":3,"sources":["../yjs/node_modules/browser-pack/_prelude.js","src/Text.js"],"names":[],"mappings":"AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"y-text.es6","sourceRoot":"/source/","sourcesContent":["(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 textnode.length) {\r\n range.right = textnode.length\r\n }\r\n range.left = Math.min(range.left, range.right)\r\n var r = document.createRange(); // eslint-disable-line\r\n r.setStart(textnode, range.left)\r\n r.setEnd(textnode, range.right)\r\n var s = window.getSelection(); // eslint-disable-line\r\n s.removeAllRanges()\r\n s.addRange(r)\r\n }\r\n }\r\n writeContent = function (content) {\r\n var contentArray = content.replace(new RegExp('\\n', 'g'), ' ').split(' ');// eslint-disable-line\r\n textfield.innerText = ''\r\n for (var i in contentArray) {\r\n var c = contentArray[i]\r\n textfield.innerText += c\r\n if (i !== contentArray.length - 1) {\r\n textfield.innerHTML += ' '\r\n }\r\n }\r\n }\r\n }\r\n writeContent(this.toString())\r\n\r\n this.observe(function (events) {\r\n for (var e in events) {\r\n var event = events[e]\r\n if (!creatorToken) {\r\n var oPos, fix\r\n if (event.type === 'insert') {\r\n oPos = event.index\r\n fix = function (cursor) {// eslint-disable-line\r\n if (cursor <= oPos) {\r\n return cursor\r\n } else {\r\n cursor += 1\r\n return cursor\r\n }\r\n }\r\n var r = createRange(fix)\r\n writeRange(r)\r\n } else if (event.type === 'delete') {\r\n oPos = event.index\r\n fix = function (cursor) {// eslint-disable-line\r\n if (cursor < oPos) {\r\n return cursor\r\n } else {\r\n cursor -= 1\r\n return cursor\r\n }\r\n }\r\n r = createRange(fix)\r\n writeRange(r)\r\n }\r\n }\r\n }\r\n })\r\n // consume all text-insert changes.\r\n textfield.onkeypress = function (event) {\r\n if (word.is_deleted) {\r\n // if word is deleted, do not do anything ever again\r\n textfield.onkeypress = null\r\n return true\r\n }\r\n creatorToken = true\r\n var char\r\n if (event.keyCode === 13) {\r\n char = '\\n'\r\n } else if (event.key != null) {\r\n if (event.charCode === 32) {\r\n char = ' '\r\n } else {\r\n char = event.key\r\n }\r\n } else {\r\n char = window.String.fromCharCode(event.keyCode); // eslint-disable-line\r\n }\r\n if (char.length > 1) {\r\n return true\r\n } else if (char.length > 0) {\r\n var r = createRange()\r\n var pos = Math.min(r.left, r.right, word.length)\r\n var diff = Math.abs(r.right - r.left)\r\n word.delete(pos, diff)\r\n word.insert(pos, char)\r\n r.left = pos + char.length\r\n r.right = r.left\r\n writeRange(r)\r\n }\r\n event.preventDefault()\r\n creatorToken = false\r\n return false\r\n }\r\n textfield.onpaste = function (event) {\r\n if (word.is_deleted) {\r\n // if word is deleted, do not do anything ever again\r\n textfield.onpaste = null\r\n return true\r\n }\r\n event.preventDefault()\r\n }\r\n textfield.oncut = function (event) {\r\n if (word.is_deleted) {\r\n // if word is deleted, do not do anything ever again\r\n textfield.oncut = null\r\n return true\r\n }\r\n event.preventDefault()\r\n }\r\n //\r\n // consume deletes. Note that\r\n // chrome: won't consume deletions on keypress event.\r\n // keyCode is deprecated. BUT: I don't see another way.\r\n // since event.key is not implemented in the current version of chrome.\r\n // Every browser supports keyCode. Let's stick with it for now..\r\n //\r\n textfield.onkeydown = function (event) {\r\n creatorToken = true\r\n if (word.is_deleted) {\r\n // if word is deleted, do not do anything ever again\r\n textfield.onkeydown = null\r\n return true\r\n }\r\n var r = createRange()\r\n var pos = Math.min(r.left, r.right, word.toString().length)\r\n var diff = Math.abs(r.left - r.right)\r\n if (event.keyCode != null && event.keyCode === 8) { // Backspace\r\n if (diff > 0) {\r\n word.delete(pos, diff)\r\n r.left = pos\r\n r.right = pos\r\n writeRange(r)\r\n } else {\r\n if (event.ctrlKey != null && event.ctrlKey) {\r\n var val = word.toString()\r\n var newPos = pos\r\n var delLength = 0\r\n if (pos > 0) {\r\n newPos--\r\n delLength++\r\n }\r\n while (newPos > 0 && val[newPos] !== ' ' && val[newPos] !== '\\n') {\r\n newPos--\r\n delLength++\r\n }\r\n word.delete(newPos, pos - newPos)\r\n r.left = newPos\r\n r.right = newPos\r\n writeRange(r)\r\n } else {\r\n if (pos > 0) {\r\n word.delete(pos - 1, 1)\r\n r.left = pos - 1\r\n r.right = pos - 1\r\n writeRange(r)\r\n }\r\n }\r\n }\r\n event.preventDefault()\r\n creatorToken = false\r\n return false\r\n } else if (event.keyCode != null && event.keyCode === 46) { // Delete\r\n if (diff > 0) {\r\n word.delete(pos, diff)\r\n r.left = pos\r\n r.right = pos\r\n writeRange(r)\r\n } else {\r\n word.delete(pos, 1)\r\n r.left = pos\r\n r.right = pos\r\n writeRange(r)\r\n }\r\n event.preventDefault()\r\n creatorToken = false\r\n return false\r\n } else {\r\n creatorToken = false\r\n return true\r\n }\r\n }\r\n }\r\n }\r\n Y.extend('Text', new Y.utils.CustomType({\r\n name: 'Text',\r\n class: YText,\r\n struct: 'List',\r\n initType: function * YTextInitializer (os, model) {\r\n var valArray = []\r\n var idArray = yield* Y.Struct.List.map.call(this, model, function (c) {\r\n valArray.push(c.content)\r\n return JSON.stringify(c.id)\r\n })\r\n return new YText(os, model.id, idArray, valArray)\r\n }\r\n }))\r\n })\r\n}\r\n\r\nmodule.exports = extend\r\nif (typeof Y !== 'undefined') {\r\n extend(Y)\r\n}\r\n"]} \ No newline at end of file diff --git a/Examples/bower_components/y-text/y-text.js b/Examples/bower_components/y-text/y-text.js new file mode 100644 index 00000000..d2d952c6 --- /dev/null +++ b/Examples/bower_components/y-text/y-text.js @@ -0,0 +1,2 @@ +!function e(t,n,r){function i(l,u){if(!n[l]){if(!t[l]){var f="function"==typeof require&&require;if(!u&&f)return f(l,!0);if(o)return o(l,!0);var a=new Error("Cannot find module '"+l+"'");throw a.code="MODULE_NOT_FOUND",a}var s=n[l]={exports:{}};t[l][0].call(s.exports,function(e){var n=t[l][1][e];return i(n?n:e)},s,s.exports,e,t,n,r)}return n[l].exports}for(var o="function"==typeof require&&require,l=0;ln.length&&(t.right=n.length),t.left=Math.min(t.left,t.right);var r=document.createRange();r.setStart(n,t.left),r.setEnd(n,t.right);var o=window.getSelection();o.removeAllRanges(),o.addRange(r)}},u=function(t){var n=t.replace(new RegExp("\n","g")," ").split(" ");e.innerText="";for(var r in n){var i=n[r];e.innerText+=i,r!==n.length-1&&(e.innerHTML+=" ")}}),u(this.toString()),this.observe(function(e){for(var t in e){var n=e[t];if(!r){var i,u;if("insert"===n.type){i=n.index,u=function(e){return i>=e?e:e+=1};var f=o(u);l(f)}else"delete"===n.type&&(i=n.index,u=function(e){return i>e?e:e-=1},f=o(u),l(f))}}}),e.onkeypress=function(t){if(i.is_deleted)return e.onkeypress=null,!0;r=!0;var n;if(n=13===t.keyCode?"\n":null!=t.key?32===t.charCode?" ":t.key:window.String.fromCharCode(t.keyCode),n.length>1)return!0;if(n.length>0){var u=o(),f=Math.min(u.left,u.right,i.length),a=Math.abs(u.right-u.left);i["delete"](f,a),i.insert(f,n),u.left=f+n.length,u.right=u.left,l(u)}return t.preventDefault(),r=!1,!1},e.onpaste=function(t){return i.is_deleted?(e.onpaste=null,!0):void t.preventDefault()},e.oncut=function(t){return i.is_deleted?(e.oncut=null,!0):void t.preventDefault()},e.onkeydown=function(t){if(r=!0,i.is_deleted)return e.onkeydown=null,!0;var n=o(),u=Math.min(n.left,n.right,i.toString().length),f=Math.abs(n.left-n.right);if(null!=t.keyCode&&8===t.keyCode){if(f>0)i["delete"](u,f),n.left=u,n.right=u,l(n);else if(null!=t.ctrlKey&&t.ctrlKey){var a=i.toString(),s=u,c=0;for(u>0&&(s--,c++);s>0&&" "!==a[s]&&"\n"!==a[s];)s--,c++;i["delete"](s,u-s),n.left=s,n.right=s,l(n)}else u>0&&(i["delete"](u-1,1),n.left=u-1,n.right=u-1,l(n));return t.preventDefault(),r=!1,!1}return null!=t.keyCode&&46===t.keyCode?(f>0?(i["delete"](u,f),n.left=u,n.right=u,l(n)):(i["delete"](u,1),n.left=u,n.right=u,l(n)),t.preventDefault(),r=!1,!1):(r=!1,!0)}}}]),t}(e.Array["class"]);e.extend("Text",new e.utils.CustomType({name:"Text","class":t,struct:"List",initType:regeneratorRuntime.mark(function n(r,i){var o,l;return regeneratorRuntime.wrap(function(n){for(;;)switch(n.prev=n.next){case 0:return o=[],n.delegateYield(e.Struct.List.map.call(this,i,function(e){return o.push(e.content),JSON.stringify(e.id)}),"t0",2);case 2:return l=n.t0,n.abrupt("return",new t(r,i.id,l,o));case 4:case"end":return n.stop()}},n,this)})}))})}var u=function(){function e(e,t){for(var n=0;n textnode.length) {\r\n range.right = textnode.length\r\n }\r\n range.left = Math.min(range.left, range.right)\r\n var r = document.createRange(); // eslint-disable-line\r\n r.setStart(textnode, range.left)\r\n r.setEnd(textnode, range.right)\r\n var s = window.getSelection(); // eslint-disable-line\r\n s.removeAllRanges()\r\n s.addRange(r)\r\n }\r\n }\r\n writeContent = function (content) {\r\n var contentArray = content.replace(new RegExp('\\n', 'g'), ' ').split(' ');// eslint-disable-line\r\n textfield.innerText = ''\r\n for (var i in contentArray) {\r\n var c = contentArray[i]\r\n textfield.innerText += c\r\n if (i !== contentArray.length - 1) {\r\n textfield.innerHTML += ' '\r\n }\r\n }\r\n }\r\n }\r\n writeContent(this.toString())\r\n\r\n this.observe(function (events) {\r\n for (var e in events) {\r\n var event = events[e]\r\n if (!creatorToken) {\r\n var oPos, fix\r\n if (event.type === 'insert') {\r\n oPos = event.index\r\n fix = function (cursor) {// eslint-disable-line\r\n if (cursor <= oPos) {\r\n return cursor\r\n } else {\r\n cursor += 1\r\n return cursor\r\n }\r\n }\r\n var r = createRange(fix)\r\n writeRange(r)\r\n } else if (event.type === 'delete') {\r\n oPos = event.index\r\n fix = function (cursor) {// eslint-disable-line\r\n if (cursor < oPos) {\r\n return cursor\r\n } else {\r\n cursor -= 1\r\n return cursor\r\n }\r\n }\r\n r = createRange(fix)\r\n writeRange(r)\r\n }\r\n }\r\n }\r\n })\r\n // consume all text-insert changes.\r\n textfield.onkeypress = function (event) {\r\n if (word.is_deleted) {\r\n // if word is deleted, do not do anything ever again\r\n textfield.onkeypress = null\r\n return true\r\n }\r\n creatorToken = true\r\n var char\r\n if (event.keyCode === 13) {\r\n char = '\\n'\r\n } else if (event.key != null) {\r\n if (event.charCode === 32) {\r\n char = ' '\r\n } else {\r\n char = event.key\r\n }\r\n } else {\r\n char = window.String.fromCharCode(event.keyCode); // eslint-disable-line\r\n }\r\n if (char.length > 1) {\r\n return true\r\n } else if (char.length > 0) {\r\n var r = createRange()\r\n var pos = Math.min(r.left, r.right, word.length)\r\n var diff = Math.abs(r.right - r.left)\r\n word.delete(pos, diff)\r\n word.insert(pos, char)\r\n r.left = pos + char.length\r\n r.right = r.left\r\n writeRange(r)\r\n }\r\n event.preventDefault()\r\n creatorToken = false\r\n return false\r\n }\r\n textfield.onpaste = function (event) {\r\n if (word.is_deleted) {\r\n // if word is deleted, do not do anything ever again\r\n textfield.onpaste = null\r\n return true\r\n }\r\n event.preventDefault()\r\n }\r\n textfield.oncut = function (event) {\r\n if (word.is_deleted) {\r\n // if word is deleted, do not do anything ever again\r\n textfield.oncut = null\r\n return true\r\n }\r\n event.preventDefault()\r\n }\r\n //\r\n // consume deletes. Note that\r\n // chrome: won't consume deletions on keypress event.\r\n // keyCode is deprecated. BUT: I don't see another way.\r\n // since event.key is not implemented in the current version of chrome.\r\n // Every browser supports keyCode. Let's stick with it for now..\r\n //\r\n textfield.onkeydown = function (event) {\r\n creatorToken = true\r\n if (word.is_deleted) {\r\n // if word is deleted, do not do anything ever again\r\n textfield.onkeydown = null\r\n return true\r\n }\r\n var r = createRange()\r\n var pos = Math.min(r.left, r.right, word.toString().length)\r\n var diff = Math.abs(r.left - r.right)\r\n if (event.keyCode != null && event.keyCode === 8) { // Backspace\r\n if (diff > 0) {\r\n word.delete(pos, diff)\r\n r.left = pos\r\n r.right = pos\r\n writeRange(r)\r\n } else {\r\n if (event.ctrlKey != null && event.ctrlKey) {\r\n var val = word.toString()\r\n var newPos = pos\r\n var delLength = 0\r\n if (pos > 0) {\r\n newPos--\r\n delLength++\r\n }\r\n while (newPos > 0 && val[newPos] !== ' ' && val[newPos] !== '\\n') {\r\n newPos--\r\n delLength++\r\n }\r\n word.delete(newPos, pos - newPos)\r\n r.left = newPos\r\n r.right = newPos\r\n writeRange(r)\r\n } else {\r\n if (pos > 0) {\r\n word.delete(pos - 1, 1)\r\n r.left = pos - 1\r\n r.right = pos - 1\r\n writeRange(r)\r\n }\r\n }\r\n }\r\n event.preventDefault()\r\n creatorToken = false\r\n return false\r\n } else if (event.keyCode != null && event.keyCode === 46) { // Delete\r\n if (diff > 0) {\r\n word.delete(pos, diff)\r\n r.left = pos\r\n r.right = pos\r\n writeRange(r)\r\n } else {\r\n word.delete(pos, 1)\r\n r.left = pos\r\n r.right = pos\r\n writeRange(r)\r\n }\r\n event.preventDefault()\r\n creatorToken = false\r\n return false\r\n } else {\r\n creatorToken = false\r\n return true\r\n }\r\n }\r\n }\r\n }\r\n Y.extend('Text', new Y.utils.CustomType({\r\n name: 'Text',\r\n class: YText,\r\n struct: 'List',\r\n initType: function * YTextInitializer (os, model) {\r\n var valArray = []\r\n var idArray = yield* Y.Struct.List.map.call(this, model, function (c) {\r\n valArray.push(c.content)\r\n return JSON.stringify(c.id)\r\n })\r\n return new YText(os, model.id, idArray, valArray)\r\n }\r\n }))\r\n })\r\n}\r\n\r\nmodule.exports = extend\r\nif (typeof Y !== 'undefined') {\r\n extend(Y)\r\n}\r\n","(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 textnode.length) {\n range.right = textnode.length;\n }\n range.left = Math.min(range.left, range.right);\n var r = document.createRange(); // eslint-disable-line\n r.setStart(textnode, range.left);\n r.setEnd(textnode, range.right);\n var s = window.getSelection(); // eslint-disable-line\n s.removeAllRanges();\n s.addRange(r);\n }\n };\n writeContent = function writeContent(content) {\n var contentArray = content.replace(new RegExp('\\n', 'g'), ' ').split(' '); // eslint-disable-line\n textfield.innerText = '';\n for (var i in contentArray) {\n var c = contentArray[i];\n textfield.innerText += c;\n if (i !== contentArray.length - 1) {\n textfield.innerHTML += ' ';\n }\n }\n };\n }\n writeContent(this.toString());\n\n this.observe(function (events) {\n for (var e in events) {\n var event = events[e];\n if (!creatorToken) {\n var oPos, fix;\n if (event.type === 'insert') {\n oPos = event.index;\n fix = function fix(cursor) {\n // eslint-disable-line\n if (cursor <= oPos) {\n return cursor;\n } else {\n cursor += 1;\n return cursor;\n }\n };\n var r = createRange(fix);\n writeRange(r);\n } else if (event.type === 'delete') {\n oPos = event.index;\n fix = function fix(cursor) {\n // eslint-disable-line\n if (cursor < oPos) {\n return cursor;\n } else {\n cursor -= 1;\n return cursor;\n }\n };\n r = createRange(fix);\n writeRange(r);\n }\n }\n }\n });\n // consume all text-insert changes.\n textfield.onkeypress = function (event) {\n if (word.is_deleted) {\n // if word is deleted, do not do anything ever again\n textfield.onkeypress = null;\n return true;\n }\n creatorToken = true;\n var char;\n if (event.keyCode === 13) {\n char = '\\n';\n } else if (event.key != null) {\n if (event.charCode === 32) {\n char = ' ';\n } else {\n char = event.key;\n }\n } else {\n char = window.String.fromCharCode(event.keyCode); // eslint-disable-line\n }\n if (char.length > 1) {\n return true;\n } else if (char.length > 0) {\n var r = createRange();\n var pos = Math.min(r.left, r.right, word.length);\n var diff = Math.abs(r.right - r.left);\n word.delete(pos, diff);\n word.insert(pos, char);\n r.left = pos + char.length;\n r.right = r.left;\n writeRange(r);\n }\n event.preventDefault();\n creatorToken = false;\n return false;\n };\n textfield.onpaste = function (event) {\n if (word.is_deleted) {\n // if word is deleted, do not do anything ever again\n textfield.onpaste = null;\n return true;\n }\n event.preventDefault();\n };\n textfield.oncut = function (event) {\n if (word.is_deleted) {\n // if word is deleted, do not do anything ever again\n textfield.oncut = null;\n return true;\n }\n event.preventDefault();\n };\n //\n // consume deletes. Note that\n // chrome: won't consume deletions on keypress event.\n // keyCode is deprecated. BUT: I don't see another way.\n // since event.key is not implemented in the current version of chrome.\n // Every browser supports keyCode. Let's stick with it for now..\n //\n textfield.onkeydown = function (event) {\n creatorToken = true;\n if (word.is_deleted) {\n // if word is deleted, do not do anything ever again\n textfield.onkeydown = null;\n return true;\n }\n var r = createRange();\n var pos = Math.min(r.left, r.right, word.toString().length);\n var diff = Math.abs(r.left - r.right);\n if (event.keyCode != null && event.keyCode === 8) {\n // Backspace\n if (diff > 0) {\n word.delete(pos, diff);\n r.left = pos;\n r.right = pos;\n writeRange(r);\n } else {\n if (event.ctrlKey != null && event.ctrlKey) {\n var val = word.toString();\n var newPos = pos;\n var delLength = 0;\n if (pos > 0) {\n newPos--;\n delLength++;\n }\n while (newPos > 0 && val[newPos] !== ' ' && val[newPos] !== '\\n') {\n newPos--;\n delLength++;\n }\n word.delete(newPos, pos - newPos);\n r.left = newPos;\n r.right = newPos;\n writeRange(r);\n } else {\n if (pos > 0) {\n word.delete(pos - 1, 1);\n r.left = pos - 1;\n r.right = pos - 1;\n writeRange(r);\n }\n }\n }\n event.preventDefault();\n creatorToken = false;\n return false;\n } else if (event.keyCode != null && event.keyCode === 46) {\n // Delete\n if (diff > 0) {\n word.delete(pos, diff);\n r.left = pos;\n r.right = pos;\n writeRange(r);\n } else {\n word.delete(pos, 1);\n r.left = pos;\n r.right = pos;\n writeRange(r);\n }\n event.preventDefault();\n creatorToken = false;\n return false;\n } else {\n creatorToken = false;\n return true;\n }\n };\n }\n }]);\n\n return YText;\n }(Y.Array['class']);\n\n Y.extend('Text', new Y.utils.CustomType({\n name: 'Text',\n class: YText,\n struct: 'List',\n initType: regeneratorRuntime.mark(function YTextInitializer(os, model) {\n var valArray, idArray;\n return regeneratorRuntime.wrap(function YTextInitializer$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n valArray = [];\n return _context.delegateYield(Y.Struct.List.map.call(this, model, function (c) {\n valArray.push(c.content);\n return JSON.stringify(c.id);\n }), 't0', 2);\n\n case 2:\n idArray = _context.t0;\n return _context.abrupt('return', new YText(os, model.id, idArray, valArray));\n\n case 4:\n case 'end':\n return _context.stop();\n }\n }\n }, YTextInitializer, this);\n })\n }));\n });\n}\n\nmodule.exports = extend;\nif (typeof Y !== 'undefined') {\n extend(Y);\n}\n\n},{}]},{},[1])\n\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/Examples/bower_components/y-webrtc/.bower.json b/Examples/bower_components/y-webrtc/.bower.json new file mode 100644 index 00000000..ac7154cc --- /dev/null +++ b/Examples/bower_components/y-webrtc/.bower.json @@ -0,0 +1,37 @@ +{ + "name": "y-webrtc", + "main": "y-webrtc.js", + "version": "0.7.1", + "homepage": "http://y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "WebRTC connector for Yjs", + "moduleType": [ + "globals", + "node" + ], + "keywords": [ + "Yjs", + "connector", + "webrtc" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "_release": "0.7.1", + "_resolution": { + "type": "version", + "tag": "v0.7.1", + "commit": "8620167b9feceaf4940b6fd0a7be60243e362420" + }, + "_source": "git://github.com/y-js/y-webrtc.git", + "_target": "~0.7.1", + "_originalSource": "y-webrtc", + "_direct": true +} \ No newline at end of file diff --git a/Examples/bower_components/y-webrtc/README.md b/Examples/bower_components/y-webrtc/README.md new file mode 100644 index 00000000..88096ffb --- /dev/null +++ b/Examples/bower_components/y-webrtc/README.md @@ -0,0 +1,70 @@ +# WebRTC Connector for [Yjs](https://github.com/y-js/yjs) + + +It propagates document updates directly to all users via WebRTC. While WebRTC is not the most reliable connector, messages are propagated with almost no delay. + +* Very fast message propagation (not noticeable) +* Very easy to use +* Very little server load (you still have to set up a [signaling server](http://www.html5rocks.com/en/tutorials/webrtc/infrastructure/)) +* Not suited for a large amount of collaborators +* WebRTC is not supported in all browsers, and some have troubles communicating with each other + +We provide you with a free signaling server (it is used by default), but in production you should set up your own signaling server. You could use the [signalmaster](https://github.com/andyet/signalmaster) from &yet, which is very easy to set up. + +## Use it! +Retrieve this with bower or npm, and use it as a js library or as a custom polymer element. + +##### NPM +``` +npm install y-webrtc --save +``` +and put it on the `Y` object. + +``` +Y.WebRTC = require("y-webrtc"); +``` + +##### Bower +``` +bower install y-webrtc --save +``` + +##### Polymer +On the website you find a bunch of examples on how you can use Yjs as polymer element. +``` + + +``` + +### Create the connection object +This connector uses [SimpleWebRTC](https://simplewebrtc.com/) as an underlaying WebRTC framework, which supports the concept of rooms. + +``` +var options = {}; +var conn = new Y.WebRTC("my_room_name", options); // will connect to the default signaling server +``` + +On the options object you can put the following properties: +* url (optional) + * Set the url of your signaling server. E.g. url = "https://yatta.ninja:8888" (which is the default endpoint) +* debug (optional) + * Whether to enable debugging mode (defaults to false) + +# Start Hacking +This connector is also a nice starting point to build your own connector. The only 75 SLOCs of code are pretty well documented and understandable. If you have any troubles, don't hesitate to ask me for help! + +### Directory Structure +* lib/ + * Source files +* build/browser + * Unminified, but [browserified](http://browserify.org/) source files +* build/node + * npm modules + + +## License +Yjs is licensed under the [MIT License](./LICENSE.txt). + + + + diff --git a/Examples/bower_components/y-webrtc/bower.json b/Examples/bower_components/y-webrtc/bower.json new file mode 100644 index 00000000..c89be21c --- /dev/null +++ b/Examples/bower_components/y-webrtc/bower.json @@ -0,0 +1,27 @@ +{ + "name": "y-webrtc", + "main": "y-webrtc.js", + "version": "0.7.2", + "homepage": "http://y-js.org", + "authors": [ + "Kevin Jahns " + ], + "description": "WebRTC connector for Yjs", + "moduleType": [ + "globals", + "node" + ], + "keywords": [ + "Yjs", + "connector", + "webrtc" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} diff --git a/Examples/bower_components/y-webrtc/y-webrtc.es6 b/Examples/bower_components/y-webrtc/y-webrtc.es6 new file mode 100644 index 00000000..57c22e6f --- /dev/null +++ b/Examples/bower_components/y-webrtc/y-webrtc.es6 @@ -0,0 +1,11656 @@ +(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 offset + e.target.result.byteLength) { + window.setTimeout(sliceFile, self.config.pacing, offset + self.config.chunksize); + } else { + self.emit('progress', file.size, file.size, null); + self.emit('sentFile'); + } + }; + })(file); + var slice = file.slice(offset, offset + self.config.chunksize); + reader.readAsArrayBuffer(slice); + }; + window.setTimeout(sliceFile, 0, 0); +}; + +function Receiver() { + WildEmitter.call(this); + + this.receiveBuffer = []; + this.received = 0; + this.metadata = {}; + this.channel = null; +} +util.inherits(Receiver, WildEmitter); + +Receiver.prototype.receive = function (metadata, channel) { + var self = this; + + if (metadata) { + this.metadata = metadata; + } + this.channel = channel; + // chrome only supports arraybuffers and those make it easier to calc the hash + channel.binaryType = 'arraybuffer'; + this.channel.onmessage = function (event) { + var len = event.data.byteLength; + self.received += len; + self.receiveBuffer.push(event.data); + + self.emit('progress', self.received, self.metadata.size, event.data); + if (self.received === self.metadata.size) { + self.emit('receivedFile', new window.Blob(self.receiveBuffer), self.metadata); + self.receiveBuffer = []; // discard receivebuffer + } else if (self.received > self.metadata.size) { + // FIXME + console.error('received more than expected, discarding...'); + self.receiveBuffer = []; // just discard... + + } + }; +}; + +module.exports = {}; +module.exports.support = typeof window !== 'undefined' && window && window.File && window.FileReader && window.Blob; +module.exports.Sender = Sender; +module.exports.Receiver = Receiver; + +},{"util":45,"wildemitter":40}],3:[function(require,module,exports){ +// getScreenMedia helper by @HenrikJoreteg +var getUserMedia = require('getusermedia'); + +// cache for constraints and callback +var cache = {}; + +module.exports = function (constraints, cb) { + var hasConstraints = arguments.length === 2; + var callback = hasConstraints ? cb : constraints; + var error; + + if (typeof window === 'undefined' || window.location.protocol === 'http:') { + error = new Error('NavigatorUserMediaError'); + error.name = 'HTTPS_REQUIRED'; + return callback(error); + } + + if (window.navigator.userAgent.match('Chrome')) { + var chromever = parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10); + var maxver = 33; + var isCef = !window.chrome.webstore; + // "known" crash in chrome 34 and 35 on linux + if (window.navigator.userAgent.match('Linux')) maxver = 35; + + // check that the extension is installed by looking for a + // sessionStorage variable that contains the extension id + // this has to be set after installation unless the contest + // script does that + if (sessionStorage.getScreenMediaJSExtensionId) { + chrome.runtime.sendMessage(sessionStorage.getScreenMediaJSExtensionId, + {type:'getScreen', id: 1}, null, + function (data) { + if (!data || data.sourceId === '') { // user canceled + var error = new Error('NavigatorUserMediaError'); + error.name = 'PERMISSION_DENIED'; + callback(error); + } else { + constraints = (hasConstraints && constraints) || {audio: false, video: { + mandatory: { + chromeMediaSource: 'desktop', + maxWidth: window.screen.width, + maxHeight: window.screen.height, + maxFrameRate: 3 + }, + optional: [ + {googLeakyBucket: true}, + {googTemporalLayeredScreencast: true} + ] + }}; + constraints.video.mandatory.chromeMediaSourceId = data.sourceId; + getUserMedia(constraints, callback); + } + } + ); + } else if (window.cefGetScreenMedia) { + //window.cefGetScreenMedia is experimental - may be removed without notice + window.cefGetScreenMedia(function(sourceId) { + if (!sourceId) { + var error = new Error('cefGetScreenMediaError'); + error.name = 'CEF_GETSCREENMEDIA_CANCELED'; + callback(error); + } else { + constraints = (hasConstraints && constraints) || {audio: false, video: { + mandatory: { + chromeMediaSource: 'desktop', + maxWidth: window.screen.width, + maxHeight: window.screen.height, + maxFrameRate: 3 + }, + optional: [ + {googLeakyBucket: true}, + {googTemporalLayeredScreencast: true} + ] + }}; + constraints.video.mandatory.chromeMediaSourceId = sourceId; + getUserMedia(constraints, callback); + } + }); + } else if (isCef || (chromever >= 26 && chromever <= maxver)) { + // chrome 26 - chrome 33 way to do it -- requires bad chrome://flags + // note: this is basically in maintenance mode and will go away soon + constraints = (hasConstraints && constraints) || { + video: { + mandatory: { + googLeakyBucket: true, + maxWidth: window.screen.width, + maxHeight: window.screen.height, + maxFrameRate: 3, + chromeMediaSource: 'screen' + } + } + }; + getUserMedia(constraints, callback); + } else { + // chrome 34+ way requiring an extension + var pending = window.setTimeout(function () { + error = new Error('NavigatorUserMediaError'); + error.name = 'EXTENSION_UNAVAILABLE'; + return callback(error); + }, 1000); + cache[pending] = [callback, hasConstraints ? constraints : null]; + window.postMessage({ type: 'getScreen', id: pending }, '*'); + } + } else if (window.navigator.userAgent.match('Firefox')) { + var ffver = parseInt(window.navigator.userAgent.match(/Firefox\/(.*)/)[1], 10); + if (ffver >= 33) { + constraints = (hasConstraints && constraints) || { + video: { + mozMediaSource: 'window', + mediaSource: 'window' + } + } + getUserMedia(constraints, function (err, stream) { + callback(err, stream); + // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1045810 + if (!err) { + var lastTime = stream.currentTime; + var polly = window.setInterval(function () { + if (!stream) window.clearInterval(polly); + if (stream.currentTime == lastTime) { + window.clearInterval(polly); + if (stream.onended) { + stream.onended(); + } + } + lastTime = stream.currentTime; + }, 500); + } + }); + } else { + error = new Error('NavigatorUserMediaError'); + error.name = 'EXTENSION_UNAVAILABLE'; // does not make much sense but... + } + } +}; + +window.addEventListener('message', function (event) { + if (event.origin != window.location.origin) { + return; + } + if (event.data.type == 'gotScreen' && cache[event.data.id]) { + var data = cache[event.data.id]; + var constraints = data[1]; + var callback = data[0]; + delete cache[event.data.id]; + + if (event.data.sourceId === '') { // user canceled + var error = new Error('NavigatorUserMediaError'); + error.name = 'PERMISSION_DENIED'; + callback(error); + } else { + constraints = constraints || {audio: false, video: { + mandatory: { + chromeMediaSource: 'desktop', + maxWidth: window.screen.width, + maxHeight: window.screen.height, + maxFrameRate: 3 + }, + optional: [ + {googLeakyBucket: true}, + {googTemporalLayeredScreencast: true} + ] + }}; + constraints.video.mandatory.chromeMediaSourceId = event.data.sourceId; + getUserMedia(constraints, callback); + } + } else if (event.data.type == 'getScreenPending') { + window.clearTimeout(event.data.id); + } +}); + +},{"getusermedia":4}],4:[function(require,module,exports){ +// getUserMedia helper by @HenrikJoreteg +var adapter = require('webrtc-adapter-test'); + +module.exports = function (constraints, cb) { + var options, error; + var haveOpts = arguments.length === 2; + var defaultOpts = {video: true, audio: true}; + + var denied = 'PermissionDeniedError'; + var altDenied = 'PERMISSION_DENIED'; + var notSatisfied = 'ConstraintNotSatisfiedError'; + + // make constraints optional + if (!haveOpts) { + cb = constraints; + constraints = defaultOpts; + } + + // treat lack of browser support like an error + if (!navigator.getUserMedia) { + // throw proper error per spec + error = new Error('MediaStreamError'); + error.name = 'NotSupportedError'; + + // keep all callbacks async + return window.setTimeout(function () { + cb(error); + }, 0); + } + + // normalize error handling when no media types are requested + if (!constraints.audio && !constraints.video) { + error = new Error('MediaStreamError'); + error.name = 'NoMediaRequestedError'; + + // keep all callbacks async + return window.setTimeout(function () { + cb(error); + }, 0); + } + + // testing support + if (localStorage && localStorage.useFirefoxFakeDevice === "true") { + constraints.fake = true; + } + + navigator.getUserMedia(constraints, function (stream) { + cb(null, stream); + }, function (err) { + var error; + // coerce into an error object since FF gives us a string + // there are only two valid names according to the spec + // we coerce all non-denied to "constraint not satisfied". + if (typeof err === 'string') { + error = new Error('MediaStreamError'); + if (err === denied || err === altDenied) { + error.name = denied; + } else { + error.name = notSatisfied; + } + } else { + // if we get an error object make sure '.name' property is set + // according to spec: http://dev.w3.org/2011/webrtc/editor/getusermedia.html#navigatorusermediaerror-and-navigatorusermediaerrorcallback + error = err; + if (!error.name) { + // this is likely chrome which + // sets a property called "ERROR_DENIED" on the error object + // if so we make sure to set a name + if (error[denied]) { + err.name = denied; + } else { + err.name = notSatisfied; + } + } + } + + cb(error); + }); +}; + +},{"webrtc-adapter-test":38}],5:[function(require,module,exports){ +var WildEmitter = require('wildemitter'); + +function getMaxVolume (analyser, fftBins) { + var maxVolume = -Infinity; + analyser.getFloatFrequencyData(fftBins); + + for(var i=4, ii=fftBins.length; i < ii; i++) { + if (fftBins[i] > maxVolume && fftBins[i] < 0) { + maxVolume = fftBins[i]; + } + }; + + return maxVolume; +} + + +var audioContextType = window.AudioContext || window.webkitAudioContext; +// use a single audio context due to hardware limits +var audioContext = null; +module.exports = function(stream, options) { + var harker = new WildEmitter(); + + + // make it not break in non-supported browsers + if (!audioContextType) return harker; + + //Config + var options = options || {}, + smoothing = (options.smoothing || 0.1), + interval = (options.interval || 50), + threshold = options.threshold, + play = options.play, + history = options.history || 10, + running = true; + + //Setup Audio Context + if (!audioContext) { + audioContext = new audioContextType(); + } + var sourceNode, fftBins, analyser; + + analyser = audioContext.createAnalyser(); + analyser.fftSize = 512; + analyser.smoothingTimeConstant = smoothing; + fftBins = new Float32Array(analyser.fftSize); + + if (stream.jquery) stream = stream[0]; + if (stream instanceof HTMLAudioElement || stream instanceof HTMLVideoElement) { + //Audio Tag + sourceNode = audioContext.createMediaElementSource(stream); + if (typeof play === 'undefined') play = true; + threshold = threshold || -50; + } else { + //WebRTC Stream + sourceNode = audioContext.createMediaStreamSource(stream); + threshold = threshold || -50; + } + + sourceNode.connect(analyser); + if (play) analyser.connect(audioContext.destination); + + harker.speaking = false; + + harker.setThreshold = function(t) { + threshold = t; + }; + + harker.setInterval = function(i) { + interval = i; + }; + + harker.stop = function() { + running = false; + harker.emit('volume_change', -100, threshold); + if (harker.speaking) { + harker.speaking = false; + harker.emit('stopped_speaking'); + } + }; + harker.speakingHistory = []; + for (var i = 0; i < history; i++) { + harker.speakingHistory.push(0); + } + + // Poll the analyser node to determine if speaking + // and emit events if changed + var looper = function() { + setTimeout(function() { + + //check if stop has been called + if(!running) { + return; + } + + var currentVolume = getMaxVolume(analyser, fftBins); + + harker.emit('volume_change', currentVolume, threshold); + + var history = 0; + if (currentVolume > threshold && !harker.speaking) { + // trigger quickly, short history + for (var i = harker.speakingHistory.length - 3; i < harker.speakingHistory.length; i++) { + history += harker.speakingHistory[i]; + } + if (history >= 2) { + harker.speaking = true; + harker.emit('speaking'); + } + } else if (currentVolume < threshold && harker.speaking) { + for (var i = 0; i < harker.speakingHistory.length; i++) { + history += harker.speakingHistory[i]; + } + if (history == 0) { + harker.speaking = false; + harker.emit('stopped_speaking'); + } + } + harker.speakingHistory.shift(); + harker.speakingHistory.push(0 + (currentVolume > threshold)); + + looper(); + }, interval); + }; + looper(); + + + return harker; +} + +},{"wildemitter":40}],6:[function(require,module,exports){ +var util = require('util'); +var hark = require('hark'); +var webrtc = require('webrtcsupport'); +var getUserMedia = require('getusermedia'); +var getScreenMedia = require('getscreenmedia'); +var WildEmitter = require('wildemitter'); +var GainController = require('mediastream-gain'); +var mockconsole = require('mockconsole'); + + +function LocalMedia(opts) { + WildEmitter.call(this); + + var config = this.config = { + autoAdjustMic: false, + detectSpeakingEvents: true, + audioFallback: false, + media: { + audio: true, + video: true + }, + logger: mockconsole + }; + + var item; + for (item in opts) { + this.config[item] = opts[item]; + } + + this.logger = config.logger; + this._log = this.logger.log.bind(this.logger, 'LocalMedia:'); + this._logerror = this.logger.error.bind(this.logger, 'LocalMedia:'); + + this.screenSharingSupport = webrtc.screenSharing; + + this.localStreams = []; + this.localScreens = []; + + if (!webrtc.support) { + this._logerror('Your browser does not support local media capture.'); + } +} + +util.inherits(LocalMedia, WildEmitter); + + +LocalMedia.prototype.start = function (mediaConstraints, cb) { + var self = this; + var constraints = mediaConstraints || this.config.media; + + getUserMedia(constraints, function (err, stream) { + + if (!err) { + if (constraints.audio && self.config.detectSpeakingEvents) { + self.setupAudioMonitor(stream, self.config.harkOptions); + } + self.localStreams.push(stream); + + if (self.config.autoAdjustMic) { + self.gainController = new GainController(stream); + // start out somewhat muted if we can track audio + self.setMicIfEnabled(0.5); + } + + // TODO: might need to migrate to the video tracks onended + // FIXME: firefox does not seem to trigger this... + stream.onended = function () { + /* + var idx = self.localStreams.indexOf(stream); + if (idx > -1) { + self.localScreens.splice(idx, 1); + } + self.emit('localStreamStopped', stream); + */ + }; + + self.emit('localStream', stream); + } else { + // Fallback for users without a camera + if (self.config.audioFallback && err.name === 'DevicesNotFoundError' && constraints.video !== false) { + constraints.video = false; + self.start(constraints, cb); + return; + } + } + if (cb) { + return cb(err, stream); + } + }); +}; + +LocalMedia.prototype.stop = function (stream) { + var self = this; + // FIXME: duplicates cleanup code until fixed in FF + if (stream) { + stream.getTracks().forEach(function (track) { track.stop(); }); + var idx = self.localStreams.indexOf(stream); + if (idx > -1) { + self.emit('localStreamStopped', stream); + self.localStreams = self.localStreams.splice(idx, 1); + } else { + idx = self.localScreens.indexOf(stream); + if (idx > -1) { + self.emit('localScreenStopped', stream); + self.localScreens = self.localScreens.splice(idx, 1); + } + } + } else { + this.stopStreams(); + this.stopScreenShare(); + } +}; + +LocalMedia.prototype.stopStreams = function () { + var self = this; + if (this.audioMonitor) { + this.audioMonitor.stop(); + delete this.audioMonitor; + } + this.localStreams.forEach(function (stream) { + stream.getTracks().forEach(function (track) { track.stop(); }); + self.emit('localStreamStopped', stream); + }); + this.localStreams = []; +}; + +LocalMedia.prototype.startScreenShare = function (cb) { + var self = this; + getScreenMedia(function (err, stream) { + if (!err) { + self.localScreens.push(stream); + + // TODO: might need to migrate to the video tracks onended + // Firefox does not support .onended but it does not support + // screensharing either + stream.onended = function () { + var idx = self.localScreens.indexOf(stream); + if (idx > -1) { + self.localScreens.splice(idx, 1); + } + self.emit('localScreenStopped', stream); + }; + self.emit('localScreen', stream); + } + + // enable the callback + if (cb) { + return cb(err, stream); + } + }); +}; + +LocalMedia.prototype.stopScreenShare = function (stream) { + var self = this; + if (stream) { + stream.getTracks().forEach(function (track) { track.stop(); }); + this.emit('localScreenStopped', stream); + } else { + this.localScreens.forEach(function (stream) { + stream.getTracks().forEach(function (track) { track.stop(); }); + self.emit('localScreenStopped', stream); + }); + this.localScreens = []; + } +}; + +// Audio controls +LocalMedia.prototype.mute = function () { + this._audioEnabled(false); + this.hardMuted = true; + this.emit('audioOff'); +}; + +LocalMedia.prototype.unmute = function () { + this._audioEnabled(true); + this.hardMuted = false; + this.emit('audioOn'); +}; + +LocalMedia.prototype.setupAudioMonitor = function (stream, harkOptions) { + this._log('Setup audio'); + var audio = this.audioMonitor = hark(stream, harkOptions); + var self = this; + var timeout; + + audio.on('speaking', function () { + self.emit('speaking'); + if (self.hardMuted) { + return; + } + self.setMicIfEnabled(1); + }); + + audio.on('stopped_speaking', function () { + if (timeout) { + clearTimeout(timeout); + } + + timeout = setTimeout(function () { + self.emit('stoppedSpeaking'); + if (self.hardMuted) { + return; + } + self.setMicIfEnabled(0.5); + }, 1000); + }); + audio.on('volume_change', function (volume, treshold) { + self.emit('volumeChange', volume, treshold); + }); +}; + +// We do this as a seperate method in order to +// still leave the "setMicVolume" as a working +// method. +LocalMedia.prototype.setMicIfEnabled = function (volume) { + if (!this.config.autoAdjustMic) { + return; + } + this.gainController.setGain(volume); +}; + +// Video controls +LocalMedia.prototype.pauseVideo = function () { + this._videoEnabled(false); + this.emit('videoOff'); +}; +LocalMedia.prototype.resumeVideo = function () { + this._videoEnabled(true); + this.emit('videoOn'); +}; + +// Combined controls +LocalMedia.prototype.pause = function () { + this.mute(); + this.pauseVideo(); +}; +LocalMedia.prototype.resume = function () { + this.unmute(); + this.resumeVideo(); +}; + +// Internal methods for enabling/disabling audio/video +LocalMedia.prototype._audioEnabled = function (bool) { + // work around for chrome 27 bug where disabling tracks + // doesn't seem to work (works in canary, remove when working) + this.setMicIfEnabled(bool ? 1 : 0); + this.localStreams.forEach(function (stream) { + stream.getAudioTracks().forEach(function (track) { + track.enabled = !!bool; + }); + }); +}; +LocalMedia.prototype._videoEnabled = function (bool) { + this.localStreams.forEach(function (stream) { + stream.getVideoTracks().forEach(function (track) { + track.enabled = !!bool; + }); + }); +}; + +// check if all audio streams are enabled +LocalMedia.prototype.isAudioEnabled = function () { + var enabled = true; + this.localStreams.forEach(function (stream) { + stream.getAudioTracks().forEach(function (track) { + enabled = enabled && track.enabled; + }); + }); + return enabled; +}; + +// check if all video streams are enabled +LocalMedia.prototype.isVideoEnabled = function () { + var enabled = true; + this.localStreams.forEach(function (stream) { + stream.getVideoTracks().forEach(function (track) { + enabled = enabled && track.enabled; + }); + }); + return enabled; +}; + +// Backwards Compat +LocalMedia.prototype.startLocalMedia = LocalMedia.prototype.start; +LocalMedia.prototype.stopLocalMedia = LocalMedia.prototype.stop; + +// fallback for old .localStream behaviour +Object.defineProperty(LocalMedia.prototype, 'localStream', { + get: function () { + return this.localStreams.length > 0 ? this.localStreams[0] : null; + } +}); +// fallback for old .localScreen behaviour +Object.defineProperty(LocalMedia.prototype, 'localScreen', { + get: function () { + return this.localScreens.length > 0 ? this.localScreens[0] : null; + } +}); + +module.exports = LocalMedia; + +},{"getscreenmedia":3,"getusermedia":4,"hark":5,"mediastream-gain":24,"mockconsole":25,"util":45,"webrtcsupport":39,"wildemitter":40}],7:[function(require,module,exports){ +/** + * lodash 3.0.0 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.7.0 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * A specialized version of `_.forEach` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ +function arrayEach(array, iteratee) { + var index = -1, + length = array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; +} + +module.exports = arrayEach; + +},{}],8:[function(require,module,exports){ +/** + * lodash 3.0.0 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.7.0 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * A specialized version of `_.map` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ +function arrayMap(array, iteratee) { + var index = -1, + length = array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; +} + +module.exports = arrayMap; + +},{}],9:[function(require,module,exports){ +/** + * lodash 3.3.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseIsEqual = require('lodash._baseisequal'), + bindCallback = require('lodash._bindcallback'), + isArray = require('lodash.isarray'), + pairs = require('lodash.pairs'); + +/** Used to match property names within property paths. */ +var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; + +/** Used to match backslashes in property paths. */ +var reEscapeChar = /\\(\\)?/g; + +/** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + return value == null ? '' : (value + ''); +} + +/** + * The base implementation of `_.callback` which supports specifying the + * number of arguments to provide to `func`. + * + * @private + * @param {*} [func=_.identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ +function baseCallback(func, thisArg, argCount) { + var type = typeof func; + if (type == 'function') { + return thisArg === undefined + ? func + : bindCallback(func, thisArg, argCount); + } + if (func == null) { + return identity; + } + if (type == 'object') { + return baseMatches(func); + } + return thisArg === undefined + ? property(func) + : baseMatchesProperty(func, thisArg); +} + +/** + * The base implementation of `get` without support for string paths + * and default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path of the property to get. + * @param {string} [pathKey] The key representation of path. + * @returns {*} Returns the resolved value. + */ +function baseGet(object, path, pathKey) { + if (object == null) { + return; + } + if (pathKey !== undefined && pathKey in toObject(object)) { + path = [pathKey]; + } + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[path[index++]]; + } + return (index && index == length) ? object : undefined; +} + +/** + * The base implementation of `_.isMatch` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} matchData The propery names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparing objects. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ +function baseIsMatch(object, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = toObject(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var result = customizer ? customizer(objValue, srcValue, key) : undefined; + if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) { + return false; + } + } + } + return true; +} + +/** + * The base implementation of `_.matches` which does not clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new function. + */ +function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + var key = matchData[0][0], + value = matchData[0][1]; + + return function(object) { + if (object == null) { + return false; + } + return object[key] === value && (value !== undefined || (key in toObject(object))); + }; + } + return function(object) { + return baseIsMatch(object, matchData); + }; +} + +/** + * The base implementation of `_.matchesProperty` which does not clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to compare. + * @returns {Function} Returns the new function. + */ +function baseMatchesProperty(path, srcValue) { + var isArr = isArray(path), + isCommon = isKey(path) && isStrictComparable(srcValue), + pathKey = (path + ''); + + path = toPath(path); + return function(object) { + if (object == null) { + return false; + } + var key = pathKey; + object = toObject(object); + if ((isArr || !isCommon) && !(key in object)) { + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + if (object == null) { + return false; + } + key = last(path); + object = toObject(object); + } + return object[key] === srcValue + ? (srcValue !== undefined || (key in object)) + : baseIsEqual(srcValue, object[key], undefined, true); + }; +} + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +/** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new function. + */ +function basePropertyDeep(path) { + var pathKey = (path + ''); + path = toPath(path); + return function(object) { + return baseGet(object, path, pathKey); + }; +} + +/** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ +function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + start = start == null ? 0 : (+start || 0); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (end === undefined || end > length) ? length : (+end || 0); + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; +} + +/** + * Gets the propery names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ +function getMatchData(object) { + var result = pairs(object), + length = result.length; + + while (length--) { + result[length][2] = isStrictComparable(result[length][1]); + } + return result; +} + +/** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ +function isKey(value, object) { + var type = typeof value; + if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { + return true; + } + if (isArray(value)) { + return false; + } + var result = !reIsDeepProp.test(value); + return result || (object != null && value in toObject(object)); +} + +/** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ +function isStrictComparable(value) { + return value === value && !isObject(value); +} + +/** + * Converts `value` to an object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ +function toObject(value) { + return isObject(value) ? value : Object(value); +} + +/** + * Converts `value` to property path array if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array} Returns the property path array. + */ +function toPath(value) { + if (isArray(value)) { + return value; + } + var result = []; + baseToString(value).replace(rePropName, function(match, number, quote, string) { + result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; +} + +/** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ +function last(array) { + var length = array ? array.length : 0; + return length ? array[length - 1] : undefined; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * This method returns the first argument provided to it. + * + * @static + * @memberOf _ + * @category Utility + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'user': 'fred' }; + * + * _.identity(object) === object; + * // => true + */ +function identity(value) { + return value; +} + +/** + * Creates a function that returns the property value at `path` on a + * given object. + * + * @static + * @memberOf _ + * @category Utility + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new function. + * @example + * + * var objects = [ + * { 'a': { 'b': { 'c': 2 } } }, + * { 'a': { 'b': { 'c': 1 } } } + * ]; + * + * _.map(objects, _.property('a.b.c')); + * // => [2, 1] + * + * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c'); + * // => [1, 2] + */ +function property(path) { + return isKey(path) ? baseProperty(path) : basePropertyDeep(path); +} + +module.exports = baseCallback; + +},{"lodash._baseisequal":12,"lodash._bindcallback":13,"lodash.isarray":18,"lodash.pairs":22}],10:[function(require,module,exports){ +/** + * lodash 3.0.4 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var keys = require('lodash.keys'); + +/** + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * The base implementation of `_.forEach` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object|string} Returns `collection`. + */ +var baseEach = createBaseEach(baseForOwn); + +/** + * The base implementation of `baseForIn` and `baseForOwn` which iterates + * over `object` properties returned by `keysFunc` invoking `iteratee` for + * each property. Iteratee functions may exit iteration early by explicitly + * returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ +var baseFor = createBaseFor(); + +/** + * The base implementation of `_.forOwn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ +function baseForOwn(object, iteratee) { + return baseFor(object, iteratee, keys); +} + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +/** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ +function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + var length = collection ? getLength(collection) : 0; + if (!isLength(length)) { + return eachFunc(collection, iteratee); + } + var index = fromRight ? length : -1, + iterable = toObject(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; +} + +/** + * Creates a base function for `_.forIn` or `_.forInRight`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ +function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var iterable = toObject(object), + props = keysFunc(object), + length = props.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length)) { + var key = props[index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; +} + +/** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ +var getLength = baseProperty('length'); + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Converts `value` to an object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ +function toObject(value) { + return isObject(value) ? value : Object(value); +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +module.exports = baseEach; + +},{"lodash.keys":20}],11:[function(require,module,exports){ +/** + * lodash 3.7.2 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * The base implementation of `get` without support for string paths + * and default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path of the property to get. + * @param {string} [pathKey] The key representation of path. + * @returns {*} Returns the resolved value. + */ +function baseGet(object, path, pathKey) { + if (object == null) { + return; + } + if (pathKey !== undefined && pathKey in toObject(object)) { + path = [pathKey]; + } + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[path[index++]]; + } + return (index && index == length) ? object : undefined; +} + +/** + * Converts `value` to an object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ +function toObject(value) { + return isObject(value) ? value : Object(value); +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +module.exports = baseGet; + +},{}],12:[function(require,module,exports){ +/** + * lodash 3.0.7 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isArray = require('lodash.isarray'), + isTypedArray = require('lodash.istypedarray'), + keys = require('lodash.keys'); + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + stringTag = '[object String]'; + +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; + +/** + * A specialized version of `_.some` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ +function arraySome(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; +} + +/** + * The base implementation of `_.isEqual` without support for `this` binding + * `customizer` functions. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ +function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); +} + +/** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing objects. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA=[]] Tracks traversed `value` objects. + * @param {Array} [stackB=[]] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = arrayTag, + othTag = arrayTag; + + if (!objIsArr) { + objTag = objToString.call(object); + if (objTag == argsTag) { + objTag = objectTag; + } else if (objTag != objectTag) { + objIsArr = isTypedArray(object); + } + } + if (!othIsArr) { + othTag = objToString.call(other); + if (othTag == argsTag) { + othTag = objectTag; + } else if (othTag != objectTag) { + othIsArr = isTypedArray(other); + } + } + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && !(objIsArr || objIsObj)) { + return equalByTag(object, other, objTag); + } + if (!isLoose) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB); + } + } + if (!isSameTag) { + return false; + } + // Assume cyclic values are equal. + // For more information on detecting circular references see https://es5.github.io/#JO. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == object) { + return stackB[length] == other; + } + } + // Add `object` and `other` to the stack of traversed objects. + stackA.push(object); + stackB.push(other); + + var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB); + + stackA.pop(); + stackB.pop(); + + return result; +} + +/** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing arrays. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ +function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { + var index = -1, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isLoose && othLength > arrLength)) { + return false; + } + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index], + result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined; + + if (result !== undefined) { + if (result) { + continue; + } + return false; + } + // Recursively compare arrays (susceptible to call stack limits). + if (isLoose) { + if (!arraySome(other, function(othValue) { + return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); + })) { + return false; + } + } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) { + return false; + } + } + return true; +} + +/** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} value The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalByTag(object, other, tag) { + switch (tag) { + case boolTag: + case dateTag: + // Coerce dates and booleans to numbers, dates to milliseconds and booleans + // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. + return +object == +other; + + case errorTag: + return object.name == other.name && object.message == other.message; + + case numberTag: + // Treat `NaN` vs. `NaN` as equal. + return (object != +object) + ? other != +other + : object == +other; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings primitives and string + // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. + return object == (other + ''); + } + return false; +} + +/** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) { + var objProps = keys(object), + objLength = objProps.length, + othProps = keys(other), + othLength = othProps.length; + + if (objLength != othLength && !isLoose) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + var skipCtor = isLoose; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key], + result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined; + + // Recursively compare objects (susceptible to call stack limits). + if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) { + return false; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (!skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + return false; + } + } + return true; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +module.exports = baseIsEqual; + +},{"lodash.isarray":18,"lodash.istypedarray":19,"lodash.keys":20}],13:[function(require,module,exports){ +/** + * lodash 3.0.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * A specialized version of `baseCallback` which only supports `this` binding + * and specifying the number of arguments to provide to `func`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ +function bindCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + if (thisArg === undefined) { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + case 5: return function(value, other, key, object, source) { + return func.call(thisArg, value, other, key, object, source); + }; + } + return function() { + return func.apply(thisArg, arguments); + }; +} + +/** + * This method returns the first argument provided to it. + * + * @static + * @memberOf _ + * @category Utility + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'user': 'fred' }; + * + * _.identity(object) === object; + * // => true + */ +function identity(value) { + return value; +} + +module.exports = bindCallback; + +},{}],14:[function(require,module,exports){ +/** + * lodash 3.9.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** `Object#toString` result references. */ +var funcTag = '[object Function]'; + +/** Used to detect host constructors (Safari > 5). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = object == null ? undefined : object[key]; + return isNative(value) ? value : undefined; +} + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in older versions of Chrome and Safari which return 'function' for regexes + // and Safari 8 equivalents which return 'object' for typed array constructors. + return isObject(value) && objToString.call(value) == funcTag; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ +function isNative(value) { + if (value == null) { + return false; + } + if (isFunction(value)) { + return reIsNative.test(fnToString.call(value)); + } + return isObjectLike(value) && reIsHostCtor.test(value); +} + +module.exports = getNative; + +},{}],15:[function(require,module,exports){ +/** + * lodash 3.8.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isArray = require('lodash.isarray'); + +/** Used to match property names within property paths. */ +var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; + +/** Used to match backslashes in property paths. */ +var reEscapeChar = /\\(\\)?/g; + +/** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + return value == null ? '' : (value + ''); +} + +/** + * Converts `value` to property path array if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array} Returns the property path array. + */ +function toPath(value) { + if (isArray(value)) { + return value; + } + var result = []; + baseToString(value).replace(rePropName, function(match, number, quote, string) { + result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; +} + +module.exports = toPath; + +},{"lodash.isarray":18}],16:[function(require,module,exports){ +/** + * lodash 3.0.3 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var arrayEach = require('lodash._arrayeach'), + baseEach = require('lodash._baseeach'), + bindCallback = require('lodash._bindcallback'), + isArray = require('lodash.isarray'); + +/** + * Creates a function for `_.forEach` or `_.forEachRight`. + * + * @private + * @param {Function} arrayFunc The function to iterate over an array. + * @param {Function} eachFunc The function to iterate over a collection. + * @returns {Function} Returns the new each function. + */ +function createForEach(arrayFunc, eachFunc) { + return function(collection, iteratee, thisArg) { + return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) + ? arrayFunc(collection, iteratee) + : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); + }; +} + +/** + * Iterates over elements of `collection` invoking `iteratee` for each element. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). Iteratee functions may exit iteration early + * by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * + * @static + * @memberOf _ + * @alias each + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2]).forEach(function(n) { + * console.log(n); + * }).value(); + * // => logs each value from left to right and returns the array + * + * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { + * console.log(n, key); + * }); + * // => logs each value-key pair and returns the object (iteration order is not guaranteed) + */ +var forEach = createForEach(arrayEach, baseEach); + +module.exports = forEach; + +},{"lodash._arrayeach":7,"lodash._baseeach":10,"lodash._bindcallback":13,"lodash.isarray":18}],17:[function(require,module,exports){ +/** + * lodash 3.0.4 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** Native method references. */ +var propertyIsEnumerable = objectProto.propertyIsEnumerable; + +/** + * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +/** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ +var getLength = baseProperty('length'); + +/** + * Checks if `value` is array-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + */ +function isArrayLike(value) { + return value != null && isLength(getLength(value)); +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Checks if `value` is classified as an `arguments` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +function isArguments(value) { + return isObjectLike(value) && isArrayLike(value) && + hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); +} + +module.exports = isArguments; + +},{}],18:[function(require,module,exports){ +/** + * lodash 3.0.4 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** `Object#toString` result references. */ +var arrayTag = '[object Array]', + funcTag = '[object Function]'; + +/** Used to detect host constructors (Safari > 5). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsArray = getNative(Array, 'isArray'); + +/** + * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = object == null ? undefined : object[key]; + return isNative(value) ? value : undefined; +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(function() { return arguments; }()); + * // => false + */ +var isArray = nativeIsArray || function(value) { + return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; +}; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in older versions of Chrome and Safari which return 'function' for regexes + // and Safari 8 equivalents which return 'object' for typed array constructors. + return isObject(value) && objToString.call(value) == funcTag; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ +function isNative(value) { + if (value == null) { + return false; + } + if (isFunction(value)) { + return reIsNative.test(fnToString.call(value)); + } + return isObjectLike(value) && reIsHostCtor.test(value); +} + +module.exports = isArray; + +},{}],19:[function(require,module,exports){ +/** + * lodash 3.0.2 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + 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]'; + +/** Used to identify `toStringTag` values of typed arrays. */ +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[dateTag] = typedArrayTags[errorTag] = +typedArrayTags[funcTag] = typedArrayTags[mapTag] = +typedArrayTags[numberTag] = typedArrayTags[objectTag] = +typedArrayTags[regexpTag] = typedArrayTags[setTag] = +typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; + +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { + return !!value && typeof value == 'object'; +} + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; + +/** + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ +function isTypedArray(value) { + return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; +} + +module.exports = isTypedArray; + +},{}],20:[function(require,module,exports){ +/** + * lodash 3.1.2 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var getNative = require('lodash._getnative'), + isArguments = require('lodash.isarguments'), + isArray = require('lodash.isarray'); + +/** Used to detect unsigned integer values. */ +var reIsUint = /^\d+$/; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeKeys = getNative(Object, 'keys'); + +/** + * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +/** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ +var getLength = baseProperty('length'); + +/** + * Checks if `value` is array-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + */ +function isArrayLike(value) { + return value != null && isLength(getLength(value)); +} + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; + length = length == null ? MAX_SAFE_INTEGER : length; + return value > -1 && value % 1 == 0 && value < length; +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * A fallback implementation of `Object.keys` which creates an array of the + * own enumerable property names of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function shimKeys(object) { + var props = keysIn(object), + propsLength = props.length, + length = propsLength && object.length; + + var allowIndexes = !!length && isLength(length) && + (isArray(object) || isArguments(object)); + + var index = -1, + result = []; + + while (++index < propsLength) { + var key = props[index]; + if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { + result.push(key); + } + } + return result; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) + * for more details. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +var keys = !nativeKeys ? shimKeys : function(object) { + var Ctor = object == null ? undefined : object.constructor; + if ((typeof Ctor == 'function' && Ctor.prototype === object) || + (typeof object != 'function' && isArrayLike(object))) { + return shimKeys(object); + } + return isObject(object) ? nativeKeys(object) : []; +}; + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { + if (object == null) { + return []; + } + if (!isObject(object)) { + object = Object(object); + } + var length = object.length; + length = (length && isLength(length) && + (isArray(object) || isArguments(object)) && length) || 0; + + var Ctor = object.constructor, + index = -1, + isProto = typeof Ctor == 'function' && Ctor.prototype === object, + result = Array(length), + skipIndexes = length > 0; + + while (++index < length) { + result[index] = (index + ''); + } + for (var key in object) { + if (!(skipIndexes && isIndex(key, length)) && + !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; +} + +module.exports = keys; + +},{"lodash._getnative":14,"lodash.isarguments":17,"lodash.isarray":18}],21:[function(require,module,exports){ +/** + * lodash 3.1.4 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var arrayMap = require('lodash._arraymap'), + baseCallback = require('lodash._basecallback'), + baseEach = require('lodash._baseeach'), + isArray = require('lodash.isarray'); + +/** + * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * The base implementation of `_.map` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ +function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; +} + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +/** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ +var getLength = baseProperty('length'); + +/** + * Checks if `value` is array-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + */ +function isArrayLike(value) { + return value != null && isLength(getLength(value)); +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Creates an array of values by running each element in `collection` through + * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three + * arguments: (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, + * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, + * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, + * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, + * `sum`, `uniq`, and `words` + * + * @static + * @memberOf _ + * @alias collect + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new mapped array. + * @example + * + * function timesThree(n) { + * return n * 3; + * } + * + * _.map([1, 2], timesThree); + * // => [3, 6] + * + * _.map({ 'a': 1, 'b': 2 }, timesThree); + * // => [3, 6] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // using the `_.property` callback shorthand + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ +function map(collection, iteratee, thisArg) { + var func = isArray(collection) ? arrayMap : baseMap; + iteratee = baseCallback(iteratee, thisArg, 3); + return func(collection, iteratee); +} + +module.exports = map; + +},{"lodash._arraymap":8,"lodash._basecallback":9,"lodash._baseeach":10,"lodash.isarray":18}],22:[function(require,module,exports){ +/** + * lodash 3.0.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var keys = require('lodash.keys'); + +/** + * Converts `value` to an object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ +function toObject(value) { + return isObject(value) ? value : Object(value); +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * Creates a two dimensional array of the key-value pairs for `object`, + * e.g. `[[key1, value1], [key2, value2]]`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the new array of key-value pairs. + * @example + * + * _.pairs({ 'barney': 36, 'fred': 40 }); + * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) + */ +function pairs(object) { + object = toObject(object); + + var index = -1, + props = keys(object), + length = props.length, + result = Array(length); + + while (++index < length) { + var key = props[index]; + result[index] = [key, object[key]]; + } + return result; +} + +module.exports = pairs; + +},{"lodash.keys":20}],23:[function(require,module,exports){ +/** + * lodash 3.1.2 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseGet = require('lodash._baseget'), + toPath = require('lodash._topath'), + isArray = require('lodash.isarray'), + map = require('lodash.map'); + +/** Used to match property names within property paths. */ +var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +/** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new function. + */ +function basePropertyDeep(path) { + var pathKey = (path + ''); + path = toPath(path); + return function(object) { + return baseGet(object, path, pathKey); + }; +} + +/** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ +function isKey(value, object) { + var type = typeof value; + if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { + return true; + } + if (isArray(value)) { + return false; + } + var result = !reIsDeepProp.test(value); + return result || (object != null && value in toObject(object)); +} + +/** + * Converts `value` to an object if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ +function toObject(value) { + return isObject(value) ? value : Object(value); +} + +/** + * Gets the property value of `path` from all elements in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array|string} path The path of the property to pluck. + * @returns {Array} Returns the property values. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.pluck(users, 'user'); + * // => ['barney', 'fred'] + * + * var userIndex = _.indexBy(users, 'user'); + * _.pluck(userIndex, 'age'); + * // => [36, 40] (iteration order is not guaranteed) + */ +function pluck(collection, path) { + return map(collection, property(path)); +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); +} + +/** + * Creates a function which returns the property value at `path` on a + * given object. + * + * @static + * @memberOf _ + * @category Utility + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new function. + * @example + * + * var objects = [ + * { 'a': { 'b': { 'c': 2 } } }, + * { 'a': { 'b': { 'c': 1 } } } + * ]; + * + * _.map(objects, _.property('a.b.c')); + * // => [2, 1] + * + * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c'); + * // => [1, 2] + */ +function property(path) { + return isKey(path) ? baseProperty(path) : basePropertyDeep(path); +} + +module.exports = pluck; + +},{"lodash._baseget":11,"lodash._topath":15,"lodash.isarray":18,"lodash.map":21}],24:[function(require,module,exports){ +var support = require('webrtcsupport'); + + +function GainController(stream) { + this.support = support.webAudio && support.mediaStream; + + // set our starting value + this.gain = 1; + + if (this.support) { + var context = this.context = new support.AudioContext(); + this.microphone = context.createMediaStreamSource(stream); + this.gainFilter = context.createGain(); + this.destination = context.createMediaStreamDestination(); + this.outputStream = this.destination.stream; + this.microphone.connect(this.gainFilter); + this.gainFilter.connect(this.destination); + stream.addTrack(this.outputStream.getAudioTracks()[0]); + stream.removeTrack(stream.getAudioTracks()[0]); + } + this.stream = stream; +} + +// setting +GainController.prototype.setGain = function (val) { + // check for support + if (!this.support) return; + this.gainFilter.gain.value = val; + this.gain = val; +}; + +GainController.prototype.getGain = function () { + return this.gain; +}; + +GainController.prototype.off = function () { + return this.setGain(0); +}; + +GainController.prototype.on = function () { + this.setGain(1); +}; + + +module.exports = GainController; + +},{"webrtcsupport":39}],25:[function(require,module,exports){ +var methods = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","); +var l = methods.length; +var fn = function () {}; +var mockconsole = {}; + +while (l--) { + mockconsole[methods[l]] = fn; +} + +module.exports = mockconsole; + +},{}],26:[function(require,module,exports){ +var util = require('util'); +var each = require('lodash.foreach'); +var pluck = require('lodash.pluck'); +var SJJ = require('sdp-jingle-json'); +var WildEmitter = require('wildemitter'); +var peerconn = require('traceablepeerconnection'); +var adapter = require('webrtc-adapter-test'); + +function PeerConnection(config, constraints) { + var self = this; + var item; + WildEmitter.call(this); + + config = config || {}; + config.iceServers = config.iceServers || []; + + // make sure this only gets enabled in Google Chrome + // EXPERIMENTAL FLAG, might get removed without notice + this.enableChromeNativeSimulcast = false; + if (constraints && constraints.optional && + adapter.webrtcDetectedBrowser === 'chrome' && + navigator.appVersion.match(/Chromium\//) === null) { + constraints.optional.forEach(function (constraint) { + if (constraint.enableChromeNativeSimulcast) { + self.enableChromeNativeSimulcast = true; + } + }); + } + + // EXPERIMENTAL FLAG, might get removed without notice + this.enableMultiStreamHacks = false; + if (constraints && constraints.optional && + adapter.webrtcDetectedBrowser === 'chrome') { + constraints.optional.forEach(function (constraint) { + if (constraint.enableMultiStreamHacks) { + self.enableMultiStreamHacks = true; + } + }); + } + // EXPERIMENTAL FLAG, might get removed without notice + this.restrictBandwidth = 0; + if (constraints && constraints.optional) { + constraints.optional.forEach(function (constraint) { + if (constraint.andyetRestrictBandwidth) { + self.restrictBandwidth = constraint.andyetRestrictBandwidth; + } + }); + } + + // EXPERIMENTAL FLAG, might get removed without notice + // bundle up ice candidates, only works for jingle mode + // number > 0 is the delay to wait for additional candidates + // ~20ms seems good + this.batchIceCandidates = 0; + if (constraints && constraints.optional) { + constraints.optional.forEach(function (constraint) { + if (constraint.andyetBatchIce) { + self.batchIceCandidates = constraint.andyetBatchIce; + } + }); + } + this.batchedIceCandidates = []; + + // EXPERIMENTAL FLAG, might get removed without notice + // this attemps to strip out candidates with an already known foundation + // and type -- i.e. those which are gathered via the same TURN server + // but different transports (TURN udp, tcp and tls respectively) + if (constraints && constraints.optional && adapter.webrtcDetectedBrowser === 'chrome') { + constraints.optional.forEach(function (constraint) { + if (constraint.andyetFasterICE) { + self.eliminateDuplicateCandidates = constraint.andyetFasterICE; + } + }); + } + // EXPERIMENTAL FLAG, might get removed without notice + // when using a server such as the jitsi videobridge we don't need to signal + // our candidates + if (constraints && constraints.optional) { + constraints.optional.forEach(function (constraint) { + if (constraint.andyetDontSignalCandidates) { + self.dontSignalCandidates = constraint.andyetDontSignalCandidates; + } + }); + } + + + // EXPERIMENTAL FLAG, might get removed without notice + this.assumeSetLocalSuccess = false; + if (constraints && constraints.optional) { + constraints.optional.forEach(function (constraint) { + if (constraint.andyetAssumeSetLocalSuccess) { + self.assumeSetLocalSuccess = constraint.andyetAssumeSetLocalSuccess; + } + }); + } + + // EXPERIMENTAL FLAG, might get removed without notice + // working around https://bugzilla.mozilla.org/show_bug.cgi?id=1087551 + // pass in a timeout for this + if (adapter.webrtcDetectedBrowser === 'firefox') { + if (constraints && constraints.optional) { + this.wtFirefox = 0; + constraints.optional.forEach(function (constraint) { + if (constraint.andyetFirefoxMakesMeSad) { + self.wtFirefox = constraint.andyetFirefoxMakesMeSad; + if (self.wtFirefox > 0) { + self.firefoxcandidatebuffer = []; + } + } + }); + } + } + + + this.pc = new peerconn(config, constraints); + + this.getLocalStreams = this.pc.getLocalStreams.bind(this.pc); + this.getRemoteStreams = this.pc.getRemoteStreams.bind(this.pc); + this.addStream = this.pc.addStream.bind(this.pc); + this.removeStream = this.pc.removeStream.bind(this.pc); + + // proxy events + this.pc.on('*', function () { + self.emit.apply(self, arguments); + }); + + // proxy some events directly + this.pc.onremovestream = this.emit.bind(this, 'removeStream'); + this.pc.onaddstream = this.emit.bind(this, 'addStream'); + this.pc.onnegotiationneeded = this.emit.bind(this, 'negotiationNeeded'); + this.pc.oniceconnectionstatechange = this.emit.bind(this, 'iceConnectionStateChange'); + this.pc.onsignalingstatechange = this.emit.bind(this, 'signalingStateChange'); + + // handle ice candidate and data channel events + this.pc.onicecandidate = this._onIce.bind(this); + this.pc.ondatachannel = this._onDataChannel.bind(this); + + this.localDescription = { + contents: [] + }; + this.remoteDescription = { + contents: [] + }; + + this.config = { + debug: false, + ice: {}, + sid: '', + isInitiator: true, + sdpSessionID: Date.now(), + useJingle: false + }; + + // apply our config + for (item in config) { + this.config[item] = config[item]; + } + + if (this.config.debug) { + this.on('*', function () { + var logger = config.logger || console; + logger.log('PeerConnection event:', arguments); + }); + } + this.hadLocalStunCandidate = false; + this.hadRemoteStunCandidate = false; + this.hadLocalRelayCandidate = false; + this.hadRemoteRelayCandidate = false; + + this.hadLocalIPv6Candidate = false; + this.hadRemoteIPv6Candidate = false; + + // keeping references for all our data channels + // so they dont get garbage collected + // can be removed once the following bugs have been fixed + // https://crbug.com/405545 + // https://bugzilla.mozilla.org/show_bug.cgi?id=964092 + // to be filed for opera + this._remoteDataChannels = []; + this._localDataChannels = []; + + this._candidateBuffer = []; +} + +util.inherits(PeerConnection, WildEmitter); + +Object.defineProperty(PeerConnection.prototype, 'signalingState', { + get: function () { + return this.pc.signalingState; + } +}); +Object.defineProperty(PeerConnection.prototype, 'iceConnectionState', { + get: function () { + return this.pc.iceConnectionState; + } +}); + +PeerConnection.prototype._role = function () { + return this.isInitiator ? 'initiator' : 'responder'; +}; + +// Add a stream to the peer connection object +PeerConnection.prototype.addStream = function (stream) { + this.localStream = stream; + this.pc.addStream(stream); +}; + +// helper function to check if a remote candidate is a stun/relay +// candidate or an ipv6 candidate +PeerConnection.prototype._checkLocalCandidate = function (candidate) { + var cand = SJJ.toCandidateJSON(candidate); + if (cand.type == 'srflx') { + this.hadLocalStunCandidate = true; + } else if (cand.type == 'relay') { + this.hadLocalRelayCandidate = true; + } + if (cand.ip.indexOf(':') != -1) { + this.hadLocalIPv6Candidate = true; + } +}; + +// helper function to check if a remote candidate is a stun/relay +// candidate or an ipv6 candidate +PeerConnection.prototype._checkRemoteCandidate = function (candidate) { + var cand = SJJ.toCandidateJSON(candidate); + if (cand.type == 'srflx') { + this.hadRemoteStunCandidate = true; + } else if (cand.type == 'relay') { + this.hadRemoteRelayCandidate = true; + } + if (cand.ip.indexOf(':') != -1) { + this.hadRemoteIPv6Candidate = true; + } +}; + + +// Init and add ice candidate object with correct constructor +PeerConnection.prototype.processIce = function (update, cb) { + cb = cb || function () {}; + var self = this; + + // ignore any added ice candidates to avoid errors. why does the + // spec not do this? + if (this.pc.signalingState === 'closed') return cb(); + + if (update.contents || (update.jingle && update.jingle.contents)) { + var contentNames = pluck(this.remoteDescription.contents, 'name'); + var contents = update.contents || update.jingle.contents; + + contents.forEach(function (content) { + var transport = content.transport || {}; + var candidates = transport.candidates || []; + var mline = contentNames.indexOf(content.name); + var mid = content.name; + + candidates.forEach( + function (candidate) { + var iceCandidate = SJJ.toCandidateSDP(candidate) + '\r\n'; + self.pc.addIceCandidate( + new RTCIceCandidate({ + candidate: iceCandidate, + sdpMLineIndex: mline, + sdpMid: mid + }), function () { + // well, this success callback is pretty meaningless + }, + function (err) { + self.emit('error', err); + } + ); + self._checkRemoteCandidate(iceCandidate); + }); + }); + } else { + // working around https://code.google.com/p/webrtc/issues/detail?id=3669 + if (update.candidate && update.candidate.candidate.indexOf('a=') !== 0) { + update.candidate.candidate = 'a=' + update.candidate.candidate; + } + + if (this.wtFirefox && this.firefoxcandidatebuffer !== null) { + // we cant add this yet due to https://bugzilla.mozilla.org/show_bug.cgi?id=1087551 + if (this.pc.localDescription && this.pc.localDescription.type === 'offer') { + this.firefoxcandidatebuffer.push(update.candidate); + return cb(); + } + } + + self.pc.addIceCandidate( + new RTCIceCandidate(update.candidate), + function () { }, + function (err) { + self.emit('error', err); + } + ); + self._checkRemoteCandidate(update.candidate.candidate); + } + cb(); +}; + +// Generate and emit an offer with the given constraints +PeerConnection.prototype.offer = function (constraints, cb) { + var self = this; + var hasConstraints = arguments.length === 2; + var mediaConstraints = hasConstraints && constraints ? constraints : { + mandatory: { + OfferToReceiveAudio: true, + OfferToReceiveVideo: true + } + }; + cb = hasConstraints ? cb : constraints; + cb = cb || function () {}; + + if (this.pc.signalingState === 'closed') return cb('Already closed'); + + // Actually generate the offer + this.pc.createOffer( + function (offer) { + // does not work for jingle, but jingle.js doesn't need + // this hack... + var expandedOffer = { + type: 'offer', + sdp: offer.sdp + }; + if (self.assumeSetLocalSuccess) { + self.emit('offer', expandedOffer); + cb(null, expandedOffer); + } + self._candidateBuffer = []; + self.pc.setLocalDescription(offer, + function () { + var jingle; + if (self.config.useJingle) { + jingle = SJJ.toSessionJSON(offer.sdp, { + role: self._role(), + direction: 'outgoing' + }); + jingle.sid = self.config.sid; + self.localDescription = jingle; + + // Save ICE credentials + each(jingle.contents, function (content) { + var transport = content.transport || {}; + if (transport.ufrag) { + self.config.ice[content.name] = { + ufrag: transport.ufrag, + pwd: transport.pwd + }; + } + }); + + expandedOffer.jingle = jingle; + } + expandedOffer.sdp.split('\r\n').forEach(function (line) { + if (line.indexOf('a=candidate:') === 0) { + self._checkLocalCandidate(line); + } + }); + + if (!self.assumeSetLocalSuccess) { + self.emit('offer', expandedOffer); + cb(null, expandedOffer); + } + }, + function (err) { + self.emit('error', err); + cb(err); + } + ); + }, + function (err) { + self.emit('error', err); + cb(err); + }, + mediaConstraints + ); +}; + + +// Process an incoming offer so that ICE may proceed before deciding +// to answer the request. +PeerConnection.prototype.handleOffer = function (offer, cb) { + cb = cb || function () {}; + var self = this; + offer.type = 'offer'; + if (offer.jingle) { + if (this.enableChromeNativeSimulcast) { + offer.jingle.contents.forEach(function (content) { + if (content.name === 'video') { + content.description.googConferenceFlag = true; + } + }); + } + if (this.enableMultiStreamHacks) { + // add a mixed video stream as first stream + offer.jingle.contents.forEach(function (content) { + if (content.name === 'video') { + var sources = content.description.sources || []; + if (sources.length === 0 || sources[0].ssrc !== "3735928559") { + sources.unshift({ + ssrc: "3735928559", // 0xdeadbeef + parameters: [ + { + key: "cname", + value: "deadbeef" + }, + { + key: "msid", + value: "mixyourfecintothis please" + } + ] + }); + content.description.sources = sources; + } + } + }); + } + if (self.restrictBandwidth > 0) { + if (offer.jingle.contents.length >= 2 && offer.jingle.contents[1].name === 'video') { + var content = offer.jingle.contents[1]; + var hasBw = content.description && content.description.bandwidth; + if (!hasBw) { + offer.jingle.contents[1].description.bandwidth = { type: 'AS', bandwidth: self.restrictBandwidth.toString() }; + offer.sdp = SJJ.toSessionSDP(offer.jingle, { + sid: self.config.sdpSessionID, + role: self._role(), + direction: 'outgoing' + }); + } + } + } + offer.sdp = SJJ.toSessionSDP(offer.jingle, { + sid: self.config.sdpSessionID, + role: self._role(), + direction: 'incoming' + }); + self.remoteDescription = offer.jingle; + } + offer.sdp.split('\r\n').forEach(function (line) { + if (line.indexOf('a=candidate:') === 0) { + self._checkRemoteCandidate(line); + } + }); + self.pc.setRemoteDescription(new RTCSessionDescription(offer), + function () { + cb(); + }, + cb + ); +}; + +// Answer an offer with audio only +PeerConnection.prototype.answerAudioOnly = function (cb) { + var mediaConstraints = { + mandatory: { + OfferToReceiveAudio: true, + OfferToReceiveVideo: false + } + }; + this._answer(mediaConstraints, cb); +}; + +// Answer an offer without offering to recieve +PeerConnection.prototype.answerBroadcastOnly = function (cb) { + var mediaConstraints = { + mandatory: { + OfferToReceiveAudio: false, + OfferToReceiveVideo: false + } + }; + this._answer(mediaConstraints, cb); +}; + +// Answer an offer with given constraints default is audio/video +PeerConnection.prototype.answer = function (constraints, cb) { + var hasConstraints = arguments.length === 2; + var callback = hasConstraints ? cb : constraints; + var mediaConstraints = hasConstraints && constraints ? constraints : { + mandatory: { + OfferToReceiveAudio: true, + OfferToReceiveVideo: true + } + }; + + this._answer(mediaConstraints, callback); +}; + +// Process an answer +PeerConnection.prototype.handleAnswer = function (answer, cb) { + cb = cb || function () {}; + var self = this; + if (answer.jingle) { + answer.sdp = SJJ.toSessionSDP(answer.jingle, { + sid: self.config.sdpSessionID, + role: self._role(), + direction: 'incoming' + }); + self.remoteDescription = answer.jingle; + } + answer.sdp.split('\r\n').forEach(function (line) { + if (line.indexOf('a=candidate:') === 0) { + self._checkRemoteCandidate(line); + } + }); + self.pc.setRemoteDescription( + new RTCSessionDescription(answer), + function () { + if (self.wtFirefox) { + window.setTimeout(function () { + self.firefoxcandidatebuffer.forEach(function (candidate) { + // add candidates later + self.pc.addIceCandidate( + new RTCIceCandidate(candidate), + function () { }, + function (err) { + self.emit('error', err); + } + ); + self._checkRemoteCandidate(candidate.candidate); + }); + self.firefoxcandidatebuffer = null; + }, self.wtFirefox); + } + cb(null); + }, + cb + ); +}; + +// Close the peer connection +PeerConnection.prototype.close = function () { + this.pc.close(); + + this._localDataChannels = []; + this._remoteDataChannels = []; + + this.emit('close'); +}; + +// Internal code sharing for various types of answer methods +PeerConnection.prototype._answer = function (constraints, cb) { + cb = cb || function () {}; + var self = this; + if (!this.pc.remoteDescription) { + // the old API is used, call handleOffer + throw new Error('remoteDescription not set'); + } + + if (this.pc.signalingState === 'closed') return cb('Already closed'); + + self.pc.createAnswer( + function (answer) { + var sim = []; + if (self.enableChromeNativeSimulcast) { + // native simulcast part 1: add another SSRC + answer.jingle = SJJ.toSessionJSON(answer.sdp, { + role: self._role(), + direction: 'outgoing' + }); + if (answer.jingle.contents.length >= 2 && answer.jingle.contents[1].name === 'video') { + var groups = answer.jingle.contents[1].description.sourceGroups || []; + var hasSim = false; + groups.forEach(function (group) { + if (group.semantics == 'SIM') hasSim = true; + }); + if (!hasSim && + answer.jingle.contents[1].description.sources.length) { + var newssrc = JSON.parse(JSON.stringify(answer.jingle.contents[1].description.sources[0])); + newssrc.ssrc = '' + Math.floor(Math.random() * 0xffffffff); // FIXME: look for conflicts + answer.jingle.contents[1].description.sources.push(newssrc); + + sim.push(answer.jingle.contents[1].description.sources[0].ssrc); + sim.push(newssrc.ssrc); + groups.push({ + semantics: 'SIM', + sources: sim + }); + + // also create an RTX one for the SIM one + var rtxssrc = JSON.parse(JSON.stringify(newssrc)); + rtxssrc.ssrc = '' + Math.floor(Math.random() * 0xffffffff); // FIXME: look for conflicts + answer.jingle.contents[1].description.sources.push(rtxssrc); + groups.push({ + semantics: 'FID', + sources: [newssrc.ssrc, rtxssrc.ssrc] + }); + + answer.jingle.contents[1].description.sourceGroups = groups; + answer.sdp = SJJ.toSessionSDP(answer.jingle, { + sid: self.config.sdpSessionID, + role: self._role(), + direction: 'outgoing' + }); + } + } + } + var expandedAnswer = { + type: 'answer', + sdp: answer.sdp + }; + if (self.assumeSetLocalSuccess) { + // not safe to do when doing simulcast mangling + self.emit('answer', expandedAnswer); + cb(null, expandedAnswer); + } + self._candidateBuffer = []; + self.pc.setLocalDescription(answer, + function () { + if (self.config.useJingle) { + var jingle = SJJ.toSessionJSON(answer.sdp, { + role: self._role(), + direction: 'outgoing' + }); + jingle.sid = self.config.sid; + self.localDescription = jingle; + expandedAnswer.jingle = jingle; + } + if (self.enableChromeNativeSimulcast) { + // native simulcast part 2: + // signal multiple tracks to the receiver + // for anything in the SIM group + if (!expandedAnswer.jingle) { + expandedAnswer.jingle = SJJ.toSessionJSON(answer.sdp, { + role: self._role(), + direction: 'outgoing' + }); + } + expandedAnswer.jingle.contents[1].description.sources.forEach(function (source, idx) { + // the floor idx/2 is a hack that relies on a particular order + // of groups, alternating between sim and rtx + source.parameters = source.parameters.map(function (parameter) { + if (parameter.key === 'msid') { + parameter.value += '-' + Math.floor(idx / 2); + } + return parameter; + }); + }); + expandedAnswer.sdp = SJJ.toSessionSDP(expandedAnswer.jingle, { + sid: self.sdpSessionID, + role: self._role(), + direction: 'outgoing' + }); + } + expandedAnswer.sdp.split('\r\n').forEach(function (line) { + if (line.indexOf('a=candidate:') === 0) { + self._checkLocalCandidate(line); + } + }); + if (!self.assumeSetLocalSuccess) { + self.emit('answer', expandedAnswer); + cb(null, expandedAnswer); + } + }, + function (err) { + self.emit('error', err); + cb(err); + } + ); + }, + function (err) { + self.emit('error', err); + cb(err); + }, + constraints + ); +}; + +// Internal method for emitting ice candidates on our peer object +PeerConnection.prototype._onIce = function (event) { + var self = this; + if (event.candidate) { + if (this.dontSignalCandidates) return; + var ice = event.candidate; + + var expandedCandidate = { + candidate: { + candidate: ice.candidate, + sdpMid: ice.sdpMid, + sdpMLineIndex: ice.sdpMLineIndex + } + }; + this._checkLocalCandidate(ice.candidate); + + var cand = SJJ.toCandidateJSON(ice.candidate); + + var already; + var idx; + if (this.eliminateDuplicateCandidates && cand.type === 'relay') { + // drop candidates with same foundation, component + // take local type pref into account so we don't ignore udp + // ones when we know about a TCP one. unlikely but... + already = this._candidateBuffer.filter( + function (c) { + return c.type === 'relay'; + }).map(function (c) { + return c.foundation + ':' + c.component; + } + ); + idx = already.indexOf(cand.foundation + ':' + cand.component); + // remember: local type pref of udp is 0, tcp 1, tls 2 + if (idx > -1 && ((cand.priority >> 24) >= (already[idx].priority >> 24))) { + // drop it, same foundation with higher (worse) type pref + return; + } + } + if (this.config.bundlePolicy === 'max-bundle') { + // drop candidates which are duplicate for audio/video/data + // duplicate means same host/port but different sdpMid + already = this._candidateBuffer.filter( + function (c) { + return cand.type === c.type; + }).map(function (cand) { + return cand.address + ':' + cand.port; + } + ); + idx = already.indexOf(cand.address + ':' + cand.port); + if (idx > -1) return; + } + // also drop rtcp candidates since we know the peer supports RTCP-MUX + // this is a workaround until browsers implement this natively + if (this.config.rtcpMuxPolicy === 'require' && cand.component === '2') { + return; + } + this._candidateBuffer.push(cand); + + if (self.config.useJingle) { + if (!ice.sdpMid) { // firefox doesn't set this + if (self.pc.remoteDescription && self.pc.remoteDescription.type === 'offer') { + // preserve name from remote + ice.sdpMid = self.remoteDescription.contents[ice.sdpMLineIndex].name; + } else { + ice.sdpMid = self.localDescription.contents[ice.sdpMLineIndex].name; + } + } + if (!self.config.ice[ice.sdpMid]) { + var jingle = SJJ.toSessionJSON(self.pc.localDescription.sdp, { + role: self._role(), + direction: 'outgoing' + }); + each(jingle.contents, function (content) { + var transport = content.transport || {}; + if (transport.ufrag) { + self.config.ice[content.name] = { + ufrag: transport.ufrag, + pwd: transport.pwd + }; + } + }); + } + expandedCandidate.jingle = { + contents: [{ + name: ice.sdpMid, + creator: self._role(), + transport: { + transType: 'iceUdp', + ufrag: self.config.ice[ice.sdpMid].ufrag, + pwd: self.config.ice[ice.sdpMid].pwd, + candidates: [ + cand + ] + } + }] + }; + if (self.batchIceCandidates > 0) { + if (self.batchedIceCandidates.length === 0) { + window.setTimeout(function () { + var contents = {}; + self.batchedIceCandidates.forEach(function (content) { + content = content.contents[0]; + if (!contents[content.name]) contents[content.name] = content; + contents[content.name].transport.candidates.push(content.transport.candidates[0]); + }); + var newCand = { + jingle: { + contents: [] + } + }; + Object.keys(contents).forEach(function (name) { + newCand.jingle.contents.push(contents[name]); + }); + self.batchedIceCandidates = []; + self.emit('ice', newCand); + }, self.batchIceCandidates); + } + self.batchedIceCandidates.push(expandedCandidate.jingle); + return; + } + + } + this.emit('ice', expandedCandidate); + } else { + this.emit('endOfCandidates'); + } +}; + +// Internal method for processing a new data channel being added by the +// other peer. +PeerConnection.prototype._onDataChannel = function (event) { + // make sure we keep a reference so this doesn't get garbage collected + var channel = event.channel; + this._remoteDataChannels.push(channel); + + this.emit('addChannel', channel); +}; + +// Create a data channel spec reference: +// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannelInit +PeerConnection.prototype.createDataChannel = function (name, opts) { + var channel = this.pc.createDataChannel(name, opts); + + // make sure we keep a reference so this doesn't get garbage collected + this._localDataChannels.push(channel); + + return channel; +}; + +// a wrapper around getStats which hides the differences (where possible) +// TODO: remove in favor of adapter.js shim +PeerConnection.prototype.getStats = function (cb) { + if (adapter.webrtcDetectedBrowser === 'firefox') { + this.pc.getStats( + function (res) { + var items = []; + for (var result in res) { + if (typeof res[result] === 'object') { + items.push(res[result]); + } + } + cb(null, items); + }, + cb + ); + } else { + this.pc.getStats(function (res) { + var items = []; + res.result().forEach(function (result) { + var item = {}; + result.names().forEach(function (name) { + item[name] = result.stat(name); + }); + item.id = result.id; + item.type = result.type; + item.timestamp = result.timestamp; + items.push(item); + }); + cb(null, items); + }); + } +}; + +module.exports = PeerConnection; + +},{"lodash.foreach":16,"lodash.pluck":23,"sdp-jingle-json":27,"traceablepeerconnection":37,"util":45,"webrtc-adapter-test":38,"wildemitter":40}],27:[function(require,module,exports){ +var toSDP = require('./lib/tosdp'); +var toJSON = require('./lib/tojson'); + + +// Converstion from JSON to SDP + +exports.toIncomingSDPOffer = function (session) { + return toSDP.toSessionSDP(session, { + role: 'responder', + direction: 'incoming' + }); +}; +exports.toOutgoingSDPOffer = function (session) { + return toSDP.toSessionSDP(session, { + role: 'initiator', + direction: 'outgoing' + }); +}; +exports.toIncomingSDPAnswer = function (session) { + return toSDP.toSessionSDP(session, { + role: 'initiator', + direction: 'incoming' + }); +}; +exports.toOutgoingSDPAnswer = function (session) { + return toSDP.toSessionSDP(session, { + role: 'responder', + direction: 'outgoing' + }); +}; +exports.toIncomingMediaSDPOffer = function (media) { + return toSDP.toMediaSDP(media, { + role: 'responder', + direction: 'incoming' + }); +}; +exports.toOutgoingMediaSDPOffer = function (media) { + return toSDP.toMediaSDP(media, { + role: 'initiator', + direction: 'outgoing' + }); +}; +exports.toIncomingMediaSDPAnswer = function (media) { + return toSDP.toMediaSDP(media, { + role: 'initiator', + direction: 'incoming' + }); +}; +exports.toOutgoingMediaSDPAnswer = function (media) { + return toSDP.toMediaSDP(media, { + role: 'responder', + direction: 'outgoing' + }); +}; +exports.toCandidateSDP = toSDP.toCandidateSDP; +exports.toMediaSDP = toSDP.toMediaSDP; +exports.toSessionSDP = toSDP.toSessionSDP; + + +// Conversion from SDP to JSON + +exports.toIncomingJSONOffer = function (sdp, creators) { + return toJSON.toSessionJSON(sdp, { + role: 'responder', + direction: 'incoming', + creators: creators + }); +}; +exports.toOutgoingJSONOffer = function (sdp, creators) { + return toJSON.toSessionJSON(sdp, { + role: 'initiator', + direction: 'outgoing', + creators: creators + }); +}; +exports.toIncomingJSONAnswer = function (sdp, creators) { + return toJSON.toSessionJSON(sdp, { + role: 'initiator', + direction: 'incoming', + creators: creators + }); +}; +exports.toOutgoingJSONAnswer = function (sdp, creators) { + return toJSON.toSessionJSON(sdp, { + role: 'responder', + direction: 'outgoing', + creators: creators + }); +}; +exports.toIncomingMediaJSONOffer = function (sdp, creator) { + return toJSON.toMediaJSON(sdp, { + role: 'responder', + direction: 'incoming', + creator: creator + }); +}; +exports.toOutgoingMediaJSONOffer = function (sdp, creator) { + return toJSON.toMediaJSON(sdp, { + role: 'initiator', + direction: 'outgoing', + creator: creator + }); +}; +exports.toIncomingMediaJSONAnswer = function (sdp, creator) { + return toJSON.toMediaJSON(sdp, { + role: 'initiator', + direction: 'incoming', + creator: creator + }); +}; +exports.toOutgoingMediaJSONAnswer = function (sdp, creator) { + return toJSON.toMediaJSON(sdp, { + role: 'responder', + direction: 'outgoing', + creator: creator + }); +}; +exports.toCandidateJSON = toJSON.toCandidateJSON; +exports.toMediaJSON = toJSON.toMediaJSON; +exports.toSessionJSON = toJSON.toSessionJSON; + +},{"./lib/tojson":30,"./lib/tosdp":31}],28:[function(require,module,exports){ +exports.lines = function (sdp) { + return sdp.split('\r\n').filter(function (line) { + return line.length > 0; + }); +}; + +exports.findLine = function (prefix, mediaLines, sessionLines) { + var prefixLength = prefix.length; + for (var i = 0; i < mediaLines.length; i++) { + if (mediaLines[i].substr(0, prefixLength) === prefix) { + return mediaLines[i]; + } + } + // Continue searching in parent session section + if (!sessionLines) { + return false; + } + + for (var j = 0; j < sessionLines.length; j++) { + if (sessionLines[j].substr(0, prefixLength) === prefix) { + return sessionLines[j]; + } + } + + return false; +}; + +exports.findLines = function (prefix, mediaLines, sessionLines) { + var results = []; + var prefixLength = prefix.length; + for (var i = 0; i < mediaLines.length; i++) { + if (mediaLines[i].substr(0, prefixLength) === prefix) { + results.push(mediaLines[i]); + } + } + if (results.length || !sessionLines) { + return results; + } + for (var j = 0; j < sessionLines.length; j++) { + if (sessionLines[j].substr(0, prefixLength) === prefix) { + results.push(sessionLines[j]); + } + } + return results; +}; + +exports.mline = function (line) { + var parts = line.substr(2).split(' '); + var parsed = { + media: parts[0], + port: parts[1], + proto: parts[2], + formats: [] + }; + for (var i = 3; i < parts.length; i++) { + if (parts[i]) { + parsed.formats.push(parts[i]); + } + } + return parsed; +}; + +exports.rtpmap = function (line) { + var parts = line.substr(9).split(' '); + var parsed = { + id: parts.shift() + }; + + parts = parts[0].split('/'); + + parsed.name = parts[0]; + parsed.clockrate = parts[1]; + parsed.channels = parts.length == 3 ? parts[2] : '1'; + return parsed; +}; + +exports.sctpmap = function (line) { + // based on -05 draft + var parts = line.substr(10).split(' '); + var parsed = { + number: parts.shift(), + protocol: parts.shift(), + streams: parts.shift() + }; + return parsed; +}; + + +exports.fmtp = function (line) { + var kv, key, value; + var parts = line.substr(line.indexOf(' ') + 1).split(';'); + var parsed = []; + for (var i = 0; i < parts.length; i++) { + kv = parts[i].split('='); + key = kv[0].trim(); + value = kv[1]; + if (key && value) { + parsed.push({key: key, value: value}); + } else if (key) { + parsed.push({key: '', value: key}); + } + } + return parsed; +}; + +exports.crypto = function (line) { + var parts = line.substr(9).split(' '); + var parsed = { + tag: parts[0], + cipherSuite: parts[1], + keyParams: parts[2], + sessionParams: parts.slice(3).join(' ') + }; + return parsed; +}; + +exports.fingerprint = function (line) { + var parts = line.substr(14).split(' '); + return { + hash: parts[0], + value: parts[1] + }; +}; + +exports.extmap = function (line) { + var parts = line.substr(9).split(' '); + var parsed = {}; + + var idpart = parts.shift(); + var sp = idpart.indexOf('/'); + if (sp >= 0) { + parsed.id = idpart.substr(0, sp); + parsed.senders = idpart.substr(sp + 1); + } else { + parsed.id = idpart; + parsed.senders = 'sendrecv'; + } + + parsed.uri = parts.shift() || ''; + + return parsed; +}; + +exports.rtcpfb = function (line) { + var parts = line.substr(10).split(' '); + var parsed = {}; + parsed.id = parts.shift(); + parsed.type = parts.shift(); + if (parsed.type === 'trr-int') { + parsed.value = parts.shift(); + } else { + parsed.subtype = parts.shift() || ''; + } + parsed.parameters = parts; + return parsed; +}; + +exports.candidate = function (line) { + var parts; + if (line.indexOf('a=candidate:') === 0) { + parts = line.substring(12).split(' '); + } else { // no a=candidate + parts = line.substring(10).split(' '); + } + + var candidate = { + foundation: parts[0], + component: parts[1], + protocol: parts[2].toLowerCase(), + priority: parts[3], + ip: parts[4], + port: parts[5], + // skip parts[6] == 'typ' + type: parts[7], + generation: '0' + }; + + for (var i = 8; i < parts.length; i += 2) { + if (parts[i] === 'raddr') { + candidate.relAddr = parts[i + 1]; + } else if (parts[i] === 'rport') { + candidate.relPort = parts[i + 1]; + } else if (parts[i] === 'generation') { + candidate.generation = parts[i + 1]; + } else if (parts[i] === 'tcptype') { + candidate.tcpType = parts[i + 1]; + } + } + + candidate.network = '1'; + + return candidate; +}; + +exports.sourceGroups = function (lines) { + var parsed = []; + for (var i = 0; i < lines.length; i++) { + var parts = lines[i].substr(13).split(' '); + parsed.push({ + semantics: parts.shift(), + sources: parts + }); + } + return parsed; +}; + +exports.sources = function (lines) { + // http://tools.ietf.org/html/rfc5576 + var parsed = []; + var sources = {}; + for (var i = 0; i < lines.length; i++) { + var parts = lines[i].substr(7).split(' '); + var ssrc = parts.shift(); + + if (!sources[ssrc]) { + var source = { + ssrc: ssrc, + parameters: [] + }; + parsed.push(source); + + // Keep an index + sources[ssrc] = source; + } + + parts = parts.join(' ').split(':'); + var attribute = parts.shift(); + var value = parts.join(':') || null; + + sources[ssrc].parameters.push({ + key: attribute, + value: value + }); + } + + return parsed; +}; + +exports.groups = function (lines) { + // http://tools.ietf.org/html/rfc5888 + var parsed = []; + var parts; + for (var i = 0; i < lines.length; i++) { + parts = lines[i].substr(8).split(' '); + parsed.push({ + semantics: parts.shift(), + contents: parts + }); + } + return parsed; +}; + +exports.bandwidth = function (line) { + var parts = line.substr(2).split(':'); + var parsed = {}; + parsed.type = parts.shift(); + parsed.bandwidth = parts.shift(); + return parsed; +}; + +exports.msid = function (line) { + var data = line.substr(7); + var parts = data.split(' '); + return { + msid: data, + mslabel: parts[0], + label: parts[1] + }; +}; + +},{}],29:[function(require,module,exports){ +module.exports = { + initiator: { + incoming: { + initiator: 'recvonly', + responder: 'sendonly', + both: 'sendrecv', + none: 'inactive', + recvonly: 'initiator', + sendonly: 'responder', + sendrecv: 'both', + inactive: 'none' + }, + outgoing: { + initiator: 'sendonly', + responder: 'recvonly', + both: 'sendrecv', + none: 'inactive', + recvonly: 'responder', + sendonly: 'initiator', + sendrecv: 'both', + inactive: 'none' + } + }, + responder: { + incoming: { + initiator: 'sendonly', + responder: 'recvonly', + both: 'sendrecv', + none: 'inactive', + recvonly: 'responder', + sendonly: 'initiator', + sendrecv: 'both', + inactive: 'none' + }, + outgoing: { + initiator: 'recvonly', + responder: 'sendonly', + both: 'sendrecv', + none: 'inactive', + recvonly: 'initiator', + sendonly: 'responder', + sendrecv: 'both', + inactive: 'none' + } + } +}; + +},{}],30:[function(require,module,exports){ +var SENDERS = require('./senders'); +var parsers = require('./parsers'); +var idCounter = Math.random(); + + +exports._setIdCounter = function (counter) { + idCounter = counter; +}; + +exports.toSessionJSON = function (sdp, opts) { + var i; + var creators = opts.creators || []; + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; + + + // Divide the SDP into session and media sections. + var media = sdp.split('\r\nm='); + for (i = 1; i < media.length; i++) { + media[i] = 'm=' + media[i]; + if (i !== media.length - 1) { + media[i] += '\r\n'; + } + } + var session = media.shift() + '\r\n'; + var sessionLines = parsers.lines(session); + var parsed = {}; + + var contents = []; + for (i = 0; i < media.length; i++) { + contents.push(exports.toMediaJSON(media[i], session, { + role: role, + direction: direction, + creator: creators[i] || 'initiator' + })); + } + parsed.contents = contents; + + var groupLines = parsers.findLines('a=group:', sessionLines); + if (groupLines.length) { + parsed.groups = parsers.groups(groupLines); + } + + return parsed; +}; + +exports.toMediaJSON = function (media, session, opts) { + var creator = opts.creator || 'initiator'; + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; + + var lines = parsers.lines(media); + var sessionLines = parsers.lines(session); + var mline = parsers.mline(lines[0]); + + var content = { + creator: creator, + name: mline.media, + description: { + descType: 'rtp', + media: mline.media, + payloads: [], + encryption: [], + feedback: [], + headerExtensions: [] + }, + transport: { + transType: 'iceUdp', + candidates: [], + fingerprints: [] + } + }; + if (mline.media == 'application') { + // FIXME: the description is most likely to be independent + // of the SDP and should be processed by other parts of the library + content.description = { + descType: 'datachannel' + }; + content.transport.sctp = []; + } + var desc = content.description; + var trans = content.transport; + + // If we have a mid, use that for the content name instead. + var mid = parsers.findLine('a=mid:', lines); + if (mid) { + content.name = mid.substr(6); + } + + if (parsers.findLine('a=sendrecv', lines, sessionLines)) { + content.senders = 'both'; + } else if (parsers.findLine('a=sendonly', lines, sessionLines)) { + content.senders = SENDERS[role][direction].sendonly; + } else if (parsers.findLine('a=recvonly', lines, sessionLines)) { + content.senders = SENDERS[role][direction].recvonly; + } else if (parsers.findLine('a=inactive', lines, sessionLines)) { + content.senders = 'none'; + } + + if (desc.descType == 'rtp') { + var bandwidth = parsers.findLine('b=', lines); + if (bandwidth) { + desc.bandwidth = parsers.bandwidth(bandwidth); + } + + var ssrc = parsers.findLine('a=ssrc:', lines); + if (ssrc) { + desc.ssrc = ssrc.substr(7).split(' ')[0]; + } + + var rtpmapLines = parsers.findLines('a=rtpmap:', lines); + rtpmapLines.forEach(function (line) { + var payload = parsers.rtpmap(line); + payload.parameters = []; + payload.feedback = []; + + var fmtpLines = parsers.findLines('a=fmtp:' + payload.id, lines); + // There should only be one fmtp line per payload + fmtpLines.forEach(function (line) { + payload.parameters = parsers.fmtp(line); + }); + + var fbLines = parsers.findLines('a=rtcp-fb:' + payload.id, lines); + fbLines.forEach(function (line) { + payload.feedback.push(parsers.rtcpfb(line)); + }); + + desc.payloads.push(payload); + }); + + var cryptoLines = parsers.findLines('a=crypto:', lines, sessionLines); + cryptoLines.forEach(function (line) { + desc.encryption.push(parsers.crypto(line)); + }); + + if (parsers.findLine('a=rtcp-mux', lines)) { + desc.mux = true; + } + + var fbLines = parsers.findLines('a=rtcp-fb:*', lines); + fbLines.forEach(function (line) { + desc.feedback.push(parsers.rtcpfb(line)); + }); + + var extLines = parsers.findLines('a=extmap:', lines); + extLines.forEach(function (line) { + var ext = parsers.extmap(line); + + ext.senders = SENDERS[role][direction][ext.senders]; + + desc.headerExtensions.push(ext); + }); + + var ssrcGroupLines = parsers.findLines('a=ssrc-group:', lines); + desc.sourceGroups = parsers.sourceGroups(ssrcGroupLines || []); + + var ssrcLines = parsers.findLines('a=ssrc:', lines); + var sources = desc.sources = parsers.sources(ssrcLines || []); + + var msidLine = parsers.findLine('a=msid:', lines); + if (msidLine) { + var msid = parsers.msid(msidLine); + ['msid', 'mslabel', 'label'].forEach(function (key) { + for (var i = 0; i < sources.length; i++) { + var found = false; + for (var j = 0; j < sources[i].parameters.length; j++) { + if (sources[i].parameters[j].key === key) { + found = true; + } + } + if (!found) { + sources[i].parameters.push({ key: key, value: msid[key] }); + } + } + }); + } + + if (parsers.findLine('a=x-google-flag:conference', lines, sessionLines)) { + desc.googConferenceFlag = true; + } + } + + // transport specific attributes + var fingerprintLines = parsers.findLines('a=fingerprint:', lines, sessionLines); + var setup = parsers.findLine('a=setup:', lines, sessionLines); + fingerprintLines.forEach(function (line) { + var fp = parsers.fingerprint(line); + if (setup) { + fp.setup = setup.substr(8); + } + trans.fingerprints.push(fp); + }); + + var ufragLine = parsers.findLine('a=ice-ufrag:', lines, sessionLines); + var pwdLine = parsers.findLine('a=ice-pwd:', lines, sessionLines); + if (ufragLine && pwdLine) { + trans.ufrag = ufragLine.substr(12); + trans.pwd = pwdLine.substr(10); + trans.candidates = []; + + var candidateLines = parsers.findLines('a=candidate:', lines, sessionLines); + candidateLines.forEach(function (line) { + trans.candidates.push(exports.toCandidateJSON(line)); + }); + } + + if (desc.descType == 'datachannel') { + var sctpmapLines = parsers.findLines('a=sctpmap:', lines); + sctpmapLines.forEach(function (line) { + var sctp = parsers.sctpmap(line); + trans.sctp.push(sctp); + }); + } + + return content; +}; + +exports.toCandidateJSON = function (line) { + var candidate = parsers.candidate(line.split('\r\n')[0]); + candidate.id = (idCounter++).toString(36).substr(0, 12); + return candidate; +}; + +},{"./parsers":28,"./senders":29}],31:[function(require,module,exports){ +var SENDERS = require('./senders'); + + +exports.toSessionSDP = function (session, opts) { + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; + var sid = opts.sid || session.sid || Date.now(); + var time = opts.time || Date.now(); + + var sdp = [ + 'v=0', + 'o=- ' + sid + ' ' + time + ' IN IP4 0.0.0.0', + 's=-', + 't=0 0', + 'a=msid-semantic: WMS *' + ]; + + var groups = session.groups || []; + groups.forEach(function (group) { + sdp.push('a=group:' + group.semantics + ' ' + group.contents.join(' ')); + }); + + var contents = session.contents || []; + contents.forEach(function (content) { + sdp.push(exports.toMediaSDP(content, opts)); + }); + + return sdp.join('\r\n') + '\r\n'; +}; + +exports.toMediaSDP = function (content, opts) { + var sdp = []; + + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; + + var desc = content.description; + var transport = content.transport; + var payloads = desc.payloads || []; + var fingerprints = (transport && transport.fingerprints) || []; + + var mline = []; + if (desc.descType == 'datachannel') { + mline.push('application'); + mline.push('1'); + mline.push('DTLS/SCTP'); + if (transport.sctp) { + transport.sctp.forEach(function (map) { + mline.push(map.number); + }); + } + } else { + mline.push(desc.media); + mline.push('1'); + if ((desc.encryption && desc.encryption.length > 0) || (fingerprints.length > 0)) { + mline.push('RTP/SAVPF'); + } else { + mline.push('RTP/AVPF'); + } + payloads.forEach(function (payload) { + mline.push(payload.id); + }); + } + + + sdp.push('m=' + mline.join(' ')); + + sdp.push('c=IN IP4 0.0.0.0'); + if (desc.bandwidth && desc.bandwidth.type && desc.bandwidth.bandwidth) { + sdp.push('b=' + desc.bandwidth.type + ':' + desc.bandwidth.bandwidth); + } + if (desc.descType == 'rtp') { + sdp.push('a=rtcp:1 IN IP4 0.0.0.0'); + } + + if (transport) { + if (transport.ufrag) { + sdp.push('a=ice-ufrag:' + transport.ufrag); + } + if (transport.pwd) { + sdp.push('a=ice-pwd:' + transport.pwd); + } + + var pushedSetup = false; + fingerprints.forEach(function (fingerprint) { + sdp.push('a=fingerprint:' + fingerprint.hash + ' ' + fingerprint.value); + if (fingerprint.setup && !pushedSetup) { + sdp.push('a=setup:' + fingerprint.setup); + } + }); + + if (transport.sctp) { + transport.sctp.forEach(function (map) { + sdp.push('a=sctpmap:' + map.number + ' ' + map.protocol + ' ' + map.streams); + }); + } + } + + if (desc.descType == 'rtp') { + sdp.push('a=' + (SENDERS[role][direction][content.senders] || 'sendrecv')); + } + sdp.push('a=mid:' + content.name); + + if (desc.sources && desc.sources.length) { + (desc.sources[0].parameters || []).forEach(function (param) { + if (param.key === 'msid') { + sdp.push('a=msid:' + param.value); + } + }); + } + + if (desc.mux) { + sdp.push('a=rtcp-mux'); + } + + var encryption = desc.encryption || []; + encryption.forEach(function (crypto) { + sdp.push('a=crypto:' + crypto.tag + ' ' + crypto.cipherSuite + ' ' + crypto.keyParams + (crypto.sessionParams ? ' ' + crypto.sessionParams : '')); + }); + if (desc.googConferenceFlag) { + sdp.push('a=x-google-flag:conference'); + } + + payloads.forEach(function (payload) { + var rtpmap = 'a=rtpmap:' + payload.id + ' ' + payload.name + '/' + payload.clockrate; + if (payload.channels && payload.channels != '1') { + rtpmap += '/' + payload.channels; + } + sdp.push(rtpmap); + + if (payload.parameters && payload.parameters.length) { + var fmtp = ['a=fmtp:' + payload.id]; + var parameters = []; + payload.parameters.forEach(function (param) { + parameters.push((param.key ? param.key + '=' : '') + param.value); + }); + fmtp.push(parameters.join(';')); + sdp.push(fmtp.join(' ')); + } + + if (payload.feedback) { + payload.feedback.forEach(function (fb) { + if (fb.type === 'trr-int') { + sdp.push('a=rtcp-fb:' + payload.id + ' trr-int ' + (fb.value ? fb.value : '0')); + } else { + sdp.push('a=rtcp-fb:' + payload.id + ' ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); + } + }); + } + }); + + if (desc.feedback) { + desc.feedback.forEach(function (fb) { + if (fb.type === 'trr-int') { + sdp.push('a=rtcp-fb:* trr-int ' + (fb.value ? fb.value : '0')); + } else { + sdp.push('a=rtcp-fb:* ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); + } + }); + } + + var hdrExts = desc.headerExtensions || []; + hdrExts.forEach(function (hdr) { + sdp.push('a=extmap:' + hdr.id + (hdr.senders ? '/' + SENDERS[role][direction][hdr.senders] : '') + ' ' + hdr.uri); + }); + + var ssrcGroups = desc.sourceGroups || []; + ssrcGroups.forEach(function (ssrcGroup) { + sdp.push('a=ssrc-group:' + ssrcGroup.semantics + ' ' + ssrcGroup.sources.join(' ')); + }); + + var ssrcs = desc.sources || []; + ssrcs.forEach(function (ssrc) { + for (var i = 0; i < ssrc.parameters.length; i++) { + var param = ssrc.parameters[i]; + sdp.push('a=ssrc:' + (ssrc.ssrc || desc.ssrc) + ' ' + param.key + (param.value ? (':' + param.value) : '')); + } + }); + + var candidates = transport.candidates || []; + candidates.forEach(function (candidate) { + sdp.push(exports.toCandidateSDP(candidate)); + }); + + return sdp.join('\r\n'); +}; + +exports.toCandidateSDP = function (candidate) { + var sdp = []; + + sdp.push(candidate.foundation); + sdp.push(candidate.component); + sdp.push(candidate.protocol.toUpperCase()); + sdp.push(candidate.priority); + sdp.push(candidate.ip); + sdp.push(candidate.port); + + var type = candidate.type; + sdp.push('typ'); + sdp.push(type); + if (type === 'srflx' || type === 'prflx' || type === 'relay') { + if (candidate.relAddr && candidate.relPort) { + sdp.push('raddr'); + sdp.push(candidate.relAddr); + sdp.push('rport'); + sdp.push(candidate.relPort); + } + } + if (candidate.tcpType && candidate.protocol.toUpperCase() == 'TCP') { + sdp.push('tcptype'); + sdp.push(candidate.tcpType); + } + + sdp.push('generation'); + sdp.push(candidate.generation || '0'); + + // FIXME: apparently this is wrong per spec + // but then, we need this when actually putting this into + // SDP so it's going to stay. + // decision needs to be revisited when browsers dont + // accept this any longer + return 'a=candidate:' + sdp.join(' '); +}; + +},{"./senders":29}],32:[function(require,module,exports){ +var util = require('util'); +var webrtc = require('webrtcsupport'); +var PeerConnection = require('rtcpeerconnection'); +var WildEmitter = require('wildemitter'); +var FileTransfer = require('filetransfer'); + +// the inband-v1 protocol is sending metadata inband in a serialized JSON object +// followed by the actual data. Receiver closes the datachannel upon completion +var INBAND_FILETRANSFER_V1 = 'https://simplewebrtc.com/protocol/filetransfer#inband-v1'; + +function Peer(options) { + var self = this; + + // call emitter constructor + WildEmitter.call(this); + + this.id = options.id; + this.parent = options.parent; + this.type = options.type || 'video'; + this.oneway = options.oneway || false; + this.sharemyscreen = options.sharemyscreen || false; + this.browserPrefix = options.prefix; + this.stream = options.stream; + this.enableDataChannels = options.enableDataChannels === undefined ? this.parent.config.enableDataChannels : options.enableDataChannels; + this.receiveMedia = options.receiveMedia || this.parent.config.receiveMedia; + this.channels = {}; + this.sid = options.sid || Date.now().toString(); + // Create an RTCPeerConnection via the polyfill + this.pc = new PeerConnection(this.parent.config.peerConnectionConfig, this.parent.config.peerConnectionConstraints); + this.pc.on('ice', this.onIceCandidate.bind(this)); + this.pc.on('offer', function (offer) { + if (self.parent.config.nick) offer.nick = self.parent.config.nick; + self.send('offer', offer); + }); + this.pc.on('answer', function (answer) { + if (self.parent.config.nick) answer.nick = self.parent.config.nick; + self.send('answer', answer); + }); + this.pc.on('addStream', this.handleRemoteStreamAdded.bind(this)); + this.pc.on('addChannel', this.handleDataChannelAdded.bind(this)); + this.pc.on('removeStream', this.handleStreamRemoved.bind(this)); + // Just fire negotiation needed events for now + // When browser re-negotiation handling seems to work + // we can use this as the trigger for starting the offer/answer process + // automatically. We'll just leave it be for now while this stabalizes. + this.pc.on('negotiationNeeded', this.emit.bind(this, 'negotiationNeeded')); + this.pc.on('iceConnectionStateChange', this.emit.bind(this, 'iceConnectionStateChange')); + this.pc.on('iceConnectionStateChange', function () { + switch (self.pc.iceConnectionState) { + case 'failed': + // currently, in chrome only the initiator goes to failed + // so we need to signal this to the peer + if (self.pc.pc.peerconnection.localDescription.type === 'offer') { + self.parent.emit('iceFailed', self); + self.send('connectivityError'); + } + break; + } + }); + this.pc.on('signalingStateChange', this.emit.bind(this, 'signalingStateChange')); + this.logger = this.parent.logger; + + // handle screensharing/broadcast mode + if (options.type === 'screen') { + if (this.parent.localScreen && this.sharemyscreen) { + this.logger.log('adding local screen stream to peer connection'); + this.pc.addStream(this.parent.localScreen); + this.broadcaster = options.broadcaster; + } + } else { + this.parent.localStreams.forEach(function (stream) { + self.pc.addStream(stream); + }); + } + + this.on('channelOpen', function (channel) { + if (channel.protocol === INBAND_FILETRANSFER_V1) { + channel.onmessage = function (event) { + var metadata = JSON.parse(event.data); + var receiver = new FileTransfer.Receiver(); + receiver.receive(metadata, channel); + self.emit('fileTransfer', metadata, receiver); + receiver.on('receivedFile', function (file, metadata) { + receiver.channel.close(); + }); + }; + } + }); + + // proxy events to parent + this.on('*', function () { + self.parent.emit.apply(self.parent, arguments); + }); +} + +util.inherits(Peer, WildEmitter); + +Peer.prototype.handleMessage = function (message) { + var self = this; + + this.logger.log('getting', message.type, message); + + if (message.prefix) this.browserPrefix = message.prefix; + + if (message.type === 'offer') { + if (!this.nick) this.nick = message.payload.nick; + delete message.payload.nick; + // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1064247 + message.payload.sdp = message.payload.sdp.replace('a=fmtp:0 profile-level-id=0x42e00c;packetization-mode=1\r\n', ''); + this.pc.handleOffer(message.payload, function (err) { + if (err) { + return; + } + // auto-accept + self.pc.answer(self.receiveMedia, function (err, sessionDescription) { + //self.send('answer', sessionDescription); + }); + }); + } else if (message.type === 'answer') { + if (!this.nick) this.nick = message.payload.nick; + delete message.payload.nick; + this.pc.handleAnswer(message.payload); + } else if (message.type === 'candidate') { + this.pc.processIce(message.payload); + } else if (message.type === 'connectivityError') { + this.parent.emit('connectivityError', self); + } else if (message.type === 'mute') { + this.parent.emit('mute', {id: message.from, name: message.payload.name}); + } else if (message.type === 'unmute') { + this.parent.emit('unmute', {id: message.from, name: message.payload.name}); + } +}; + +// send via signalling channel +Peer.prototype.send = function (messageType, payload) { + var message = { + to: this.id, + sid: this.sid, + broadcaster: this.broadcaster, + roomType: this.type, + type: messageType, + payload: payload, + prefix: webrtc.prefix + }; + this.logger.log('sending', messageType, message); + this.parent.emit('message', message); +}; + +// send via data channel +// returns true when message was sent and false if channel is not open +Peer.prototype.sendDirectly = function (channel, messageType, payload) { + var message = { + type: messageType, + payload: payload + }; + this.logger.log('sending via datachannel', channel, messageType, message); + var dc = this.getDataChannel(channel); + if (dc.readyState != 'open') return false; + dc.send(JSON.stringify(message)); + return true; +}; + +// Internal method registering handlers for a data channel and emitting events on the peer +Peer.prototype._observeDataChannel = function (channel) { + var self = this; + channel.onclose = this.emit.bind(this, 'channelClose', channel); + channel.onerror = this.emit.bind(this, 'channelError', channel); + channel.onmessage = function (event) { + self.emit('channelMessage', self, channel.label, JSON.parse(event.data), channel, event); + }; + channel.onopen = this.emit.bind(this, 'channelOpen', channel); +}; + +// Fetch or create a data channel by the given name +Peer.prototype.getDataChannel = function (name, opts) { + if (!webrtc.supportDataChannel) return this.emit('error', new Error('createDataChannel not supported')); + var channel = this.channels[name]; + opts || (opts = {}); + if (channel) return channel; + // if we don't have one by this label, create it + channel = this.channels[name] = this.pc.createDataChannel(name, opts); + this._observeDataChannel(channel); + return channel; +}; + +Peer.prototype.onIceCandidate = function (candidate) { + if (this.closed) return; + if (candidate) { + var pcConfig = this.parent.config.peerConnectionConfig; + if (webrtc.prefix === 'moz' && pcConfig && pcConfig.iceTransports && + candidate.candidate && candidate.candidate.candidate && + candidate.candidate.candidate.indexOf(pcConfig.iceTransports) < 0) { + this.logger.log('Ignoring ice candidate not matching pcConfig iceTransports type: ', pcConfig.iceTransports); + } else { + this.send('candidate', candidate); + } + } else { + this.logger.log("End of candidates."); + } +}; + +Peer.prototype.start = function () { + var self = this; + + // well, the webrtc api requires that we either + // a) create a datachannel a priori + // b) do a renegotiation later to add the SCTP m-line + // Let's do (a) first... + if (this.enableDataChannels) { + this.getDataChannel('simplewebrtc'); + } + + this.pc.offer(this.receiveMedia, function (err, sessionDescription) { + //self.send('offer', sessionDescription); + }); +}; + +Peer.prototype.icerestart = function () { + var constraints = this.receiveMedia; + constraints.mandatory.IceRestart = true; + this.pc.offer(constraints, function (err, success) { }); +}; + +Peer.prototype.end = function () { + if (this.closed) return; + this.pc.close(); + this.handleStreamRemoved(); +}; + +Peer.prototype.handleRemoteStreamAdded = function (event) { + var self = this; + if (this.stream) { + this.logger.warn('Already have a remote stream'); + } else { + this.stream = event.stream; + // FIXME: addEventListener('ended', ...) would be nicer + // but does not work in firefox + this.stream.onended = function () { + self.end(); + }; + this.parent.emit('peerStreamAdded', this); + } +}; + +Peer.prototype.handleStreamRemoved = function () { + this.parent.peers.splice(this.parent.peers.indexOf(this), 1); + this.closed = true; + this.parent.emit('peerStreamRemoved', this); +}; + +Peer.prototype.handleDataChannelAdded = function (channel) { + this.channels[channel.label] = channel; + this._observeDataChannel(channel); +}; + +Peer.prototype.sendFile = function (file) { + var sender = new FileTransfer.Sender(); + var dc = this.getDataChannel('filetransfer' + (new Date()).getTime(), { + protocol: INBAND_FILETRANSFER_V1 + }); + // override onopen + dc.onopen = function () { + dc.send(JSON.stringify({ + size: file.size, + name: file.name + })); + sender.send(file, dc); + }; + // override onclose + dc.onclose = function () { + console.log('sender received transfer'); + sender.emit('complete'); + }; + return sender; +}; + +module.exports = Peer; + +},{"filetransfer":2,"rtcpeerconnection":26,"util":45,"webrtcsupport":39,"wildemitter":40}],33:[function(require,module,exports){ +var WebRTC = require('./webrtc'); +var WildEmitter = require('wildemitter'); +var webrtcSupport = require('webrtcsupport'); +var attachMediaStream = require('attachmediastream'); +var mockconsole = require('mockconsole'); +var SocketIoConnection = require('./socketioconnection'); + +function SimpleWebRTC(opts) { + var self = this; + var options = opts || {}; + var config = this.config = { + url: 'https://signaling.simplewebrtc.com:443/', + socketio: {/* 'force new connection':true*/}, + connection: null, + debug: false, + localVideoEl: '', + remoteVideosEl: '', + enableDataChannels: true, + autoRequestMedia: false, + autoRemoveVideos: true, + adjustPeerVolume: true, + peerVolumeWhenSpeaking: 0.25, + media: { + video: true, + audio: true + }, + receiveMedia: { // FIXME: remove old chrome <= 37 constraints format + mandatory: { + OfferToReceiveAudio: true, + OfferToReceiveVideo: true + } + }, + localVideo: { + autoplay: true, + mirror: true, + muted: true + } + }; + var item, connection; + + // We also allow a 'logger' option. It can be any object that implements + // log, warn, and error methods. + // We log nothing by default, following "the rule of silence": + // http://www.linfo.org/rule_of_silence.html + this.logger = function () { + // we assume that if you're in debug mode and you didn't + // pass in a logger, you actually want to log as much as + // possible. + if (opts.debug) { + return opts.logger || console; + } else { + // or we'll use your logger which should have its own logic + // for output. Or we'll return the no-op. + return opts.logger || mockconsole; + } + }(); + + // set our config from options + for (item in options) { + this.config[item] = options[item]; + } + + // attach detected support for convenience + this.capabilities = webrtcSupport; + + // call WildEmitter constructor + WildEmitter.call(this); + + // create default SocketIoConnection if it's not passed in + if (this.config.connection === null) { + connection = this.connection = new SocketIoConnection(this.config); + } else { + connection = this.connection = this.config.connection; + } + + connection.on('connect', function () { + self.emit('connectionReady', connection.getSessionid()); + self.sessionReady = true; + self.testReadiness(); + }); + + connection.on('message', function (message) { + var peers = self.webrtc.getPeers(message.from, message.roomType); + var peer; + + if (message.type === 'offer') { + if (peers.length) { + peers.forEach(function (p) { + if (p.sid == message.sid) peer = p; + }); + //if (!peer) peer = peers[0]; // fallback for old protocol versions + } + if (!peer) { + peer = self.webrtc.createPeer({ + id: message.from, + sid: message.sid, + type: message.roomType, + enableDataChannels: self.config.enableDataChannels && message.roomType !== 'screen', + sharemyscreen: message.roomType === 'screen' && !message.broadcaster, + broadcaster: message.roomType === 'screen' && !message.broadcaster ? self.connection.getSessionid() : null + }); + self.emit('createdPeer', peer); + } + peer.handleMessage(message); + } else if (peers.length) { + peers.forEach(function (peer) { + if (message.sid) { + if (peer.sid === message.sid) { + peer.handleMessage(message); + } + } else { + peer.handleMessage(message); + } + }); + } + }); + + connection.on('remove', function (room) { + if (room.id !== self.connection.getSessionid()) { + self.webrtc.removePeers(room.id, room.type); + } + }); + + // instantiate our main WebRTC helper + // using same logger from logic here + opts.logger = this.logger; + opts.debug = false; + this.webrtc = new WebRTC(opts); + + // attach a few methods from underlying lib to simple. + ['mute', 'unmute', 'pauseVideo', 'resumeVideo', 'pause', 'resume', 'sendToAll', 'sendDirectlyToAll', 'getPeers'].forEach(function (method) { + self[method] = self.webrtc[method].bind(self.webrtc); + }); + + // proxy events from WebRTC + this.webrtc.on('*', function () { + self.emit.apply(self, arguments); + }); + + // log all events in debug mode + if (config.debug) { + this.on('*', this.logger.log.bind(this.logger, 'SimpleWebRTC event:')); + } + + // check for readiness + this.webrtc.on('localStream', function () { + self.testReadiness(); + }); + + this.webrtc.on('message', function (payload) { + self.connection.emit('message', payload); + }); + + this.webrtc.on('peerStreamAdded', this.handlePeerStreamAdded.bind(this)); + this.webrtc.on('peerStreamRemoved', this.handlePeerStreamRemoved.bind(this)); + + // echo cancellation attempts + if (this.config.adjustPeerVolume) { + this.webrtc.on('speaking', this.setVolumeForAll.bind(this, this.config.peerVolumeWhenSpeaking)); + this.webrtc.on('stoppedSpeaking', this.setVolumeForAll.bind(this, 1)); + } + + connection.on('stunservers', function (args) { + // resets/overrides the config + self.webrtc.config.peerConnectionConfig.iceServers = args; + self.emit('stunservers', args); + }); + connection.on('turnservers', function (args) { + // appends to the config + self.webrtc.config.peerConnectionConfig.iceServers = self.webrtc.config.peerConnectionConfig.iceServers.concat(args); + self.emit('turnservers', args); + }); + + this.webrtc.on('iceFailed', function (peer) { + // local ice failure + }); + this.webrtc.on('connectivityError', function (peer) { + // remote ice failure + }); + + + // sending mute/unmute to all peers + this.webrtc.on('audioOn', function () { + self.webrtc.sendToAll('unmute', {name: 'audio'}); + }); + this.webrtc.on('audioOff', function () { + self.webrtc.sendToAll('mute', {name: 'audio'}); + }); + this.webrtc.on('videoOn', function () { + self.webrtc.sendToAll('unmute', {name: 'video'}); + }); + this.webrtc.on('videoOff', function () { + self.webrtc.sendToAll('mute', {name: 'video'}); + }); + + // screensharing events + this.webrtc.on('localScreen', function (stream) { + var item, + el = document.createElement('video'), + container = self.getRemoteVideoContainer(); + + el.oncontextmenu = function () { return false; }; + el.id = 'localScreen'; + attachMediaStream(stream, el); + if (container) { + container.appendChild(el); + } + + self.emit('localScreenAdded', el); + self.connection.emit('shareScreen'); + + self.webrtc.peers.forEach(function (existingPeer) { + var peer; + if (existingPeer.type === 'video') { + peer = self.webrtc.createPeer({ + id: existingPeer.id, + type: 'screen', + sharemyscreen: true, + enableDataChannels: false, + receiveMedia: { + mandatory: { + OfferToReceiveAudio: false, + OfferToReceiveVideo: false + } + }, + broadcaster: self.connection.getSessionid(), + }); + self.emit('createdPeer', peer); + peer.start(); + } + }); + }); + this.webrtc.on('localScreenStopped', function (stream) { + self.stopScreenShare(); + /* + self.connection.emit('unshareScreen'); + self.webrtc.peers.forEach(function (peer) { + if (peer.sharemyscreen) { + peer.end(); + } + }); + */ + }); + + this.webrtc.on('channelMessage', function (peer, label, data) { + if (data.type == 'volume') { + self.emit('remoteVolumeChange', peer, data.volume); + } + }); + + if (this.config.autoRequestMedia) this.startLocalVideo(); +} + + +SimpleWebRTC.prototype = Object.create(WildEmitter.prototype, { + constructor: { + value: SimpleWebRTC + } +}); + +SimpleWebRTC.prototype.leaveRoom = function () { + if (this.roomName) { + this.connection.emit('leave'); + this.webrtc.peers.forEach(function (peer) { + peer.end(); + }); + if (this.getLocalScreen()) { + this.stopScreenShare(); + } + this.emit('leftRoom', this.roomName); + this.roomName = undefined; + } +}; + +SimpleWebRTC.prototype.disconnect = function () { + this.connection.disconnect(); + delete this.connection; +}; + +SimpleWebRTC.prototype.handlePeerStreamAdded = function (peer) { + var self = this; + var container = this.getRemoteVideoContainer(); + var video = attachMediaStream(peer.stream); + + // store video element as part of peer for easy removal + peer.videoEl = video; + video.id = this.getDomId(peer); + + if (container) container.appendChild(video); + + this.emit('videoAdded', video, peer); + + // send our mute status to new peer if we're muted + // currently called with a small delay because it arrives before + // the video element is created otherwise (which happens after + // the async setRemoteDescription-createAnswer) + window.setTimeout(function () { + if (!self.webrtc.isAudioEnabled()) { + peer.send('mute', {name: 'audio'}); + } + if (!self.webrtc.isVideoEnabled()) { + peer.send('mute', {name: 'video'}); + } + }, 250); +}; + +SimpleWebRTC.prototype.handlePeerStreamRemoved = function (peer) { + var container = this.getRemoteVideoContainer(); + var videoEl = peer.videoEl; + if (this.config.autoRemoveVideos && container && videoEl) { + container.removeChild(videoEl); + } + if (videoEl) this.emit('videoRemoved', videoEl, peer); +}; + +SimpleWebRTC.prototype.getDomId = function (peer) { + return [peer.id, peer.type, peer.broadcaster ? 'broadcasting' : 'incoming'].join('_'); +}; + +// set volume on video tag for all peers takse a value between 0 and 1 +SimpleWebRTC.prototype.setVolumeForAll = function (volume) { + this.webrtc.peers.forEach(function (peer) { + if (peer.videoEl) peer.videoEl.volume = volume; + }); +}; + +SimpleWebRTC.prototype.joinRoom = function (name, cb) { + var self = this; + this.roomName = name; + this.connection.emit('join', name, function (err, roomDescription) { + if (err) { + self.emit('error', err); + } else { + var id, + client, + type, + peer; + for (id in roomDescription.clients) { + client = roomDescription.clients[id]; + for (type in client) { + if (client[type]) { + peer = self.webrtc.createPeer({ + id: id, + type: type, + enableDataChannels: self.config.enableDataChannels && type !== 'screen', + receiveMedia: { + mandatory: { + OfferToReceiveAudio: type !== 'screen' && self.config.receiveMedia.mandatory.OfferToReceiveAudio, + OfferToReceiveVideo: self.config.receiveMedia.mandatory.OfferToReceiveVideo + } + } + }); + self.emit('createdPeer', peer); + peer.start(); + } + } + } + } + + if (cb) cb(err, roomDescription); + self.emit('joinedRoom', name); + }); +}; + +SimpleWebRTC.prototype.getEl = function (idOrEl) { + if (typeof idOrEl === 'string') { + return document.getElementById(idOrEl); + } else { + return idOrEl; + } +}; + +SimpleWebRTC.prototype.startLocalVideo = function () { + var self = this; + this.webrtc.startLocalMedia(this.config.media, function (err, stream) { + if (err) { + self.emit('localMediaError', err); + } else { + attachMediaStream(stream, self.getLocalVideoContainer(), self.config.localVideo); + } + }); +}; + +SimpleWebRTC.prototype.stopLocalVideo = function () { + this.webrtc.stopLocalMedia(); +}; + +// this accepts either element ID or element +// and either the video tag itself or a container +// that will be used to put the video tag into. +SimpleWebRTC.prototype.getLocalVideoContainer = function () { + var el = this.getEl(this.config.localVideoEl); + if (el && el.tagName === 'VIDEO') { + el.oncontextmenu = function () { return false; }; + return el; + } else if (el) { + var video = document.createElement('video'); + video.oncontextmenu = function () { return false; }; + el.appendChild(video); + return video; + } else { + return; + } +}; + +SimpleWebRTC.prototype.getRemoteVideoContainer = function () { + return this.getEl(this.config.remoteVideosEl); +}; + +SimpleWebRTC.prototype.shareScreen = function (cb) { + this.webrtc.startScreenShare(cb); +}; + +SimpleWebRTC.prototype.getLocalScreen = function () { + return this.webrtc.localScreen; +}; + +SimpleWebRTC.prototype.stopScreenShare = function () { + this.connection.emit('unshareScreen'); + var videoEl = document.getElementById('localScreen'); + var container = this.getRemoteVideoContainer(); + var stream = this.getLocalScreen(); + + if (this.config.autoRemoveVideos && container && videoEl) { + container.removeChild(videoEl); + } + + // a hack to emit the event the removes the video + // element that we want + if (videoEl) this.emit('videoRemoved', videoEl); + if (stream) stream.stop(); + this.webrtc.peers.forEach(function (peer) { + if (peer.broadcaster) { + peer.end(); + } + }); + //delete this.webrtc.localScreen; +}; + +SimpleWebRTC.prototype.testReadiness = function () { + var self = this; + if (this.webrtc.localStream && this.sessionReady) { + self.emit('readyToCall', self.connection.getSessionid()); + } +}; + +SimpleWebRTC.prototype.createRoom = function (name, cb) { + if (arguments.length === 2) { + this.connection.emit('create', name, cb); + } else { + this.connection.emit('create', name); + } +}; + +SimpleWebRTC.prototype.sendFile = function () { + if (!webrtcSupport.dataChannel) { + return this.emit('error', new Error('DataChannelNotSupported')); + } + +}; + +module.exports = SimpleWebRTC; + +},{"./socketioconnection":34,"./webrtc":35,"attachmediastream":1,"mockconsole":25,"webrtcsupport":39,"wildemitter":40}],34:[function(require,module,exports){ +var io = require('socket.io-client'); + +function SocketIoConnection(config) { + this.connection = io.connect(config.url, config.socketio); +} + +SocketIoConnection.prototype.on = function (ev, fn) { + this.connection.on(ev, fn); +}; + +SocketIoConnection.prototype.emit = function () { + this.connection.emit.apply(this.connection, arguments); +}; + +SocketIoConnection.prototype.getSessionid = function () { + return this.connection.socket.sessionid; +}; + +SocketIoConnection.prototype.disconnect = function () { + return this.connection.disconnect(); +}; + +module.exports = SocketIoConnection; + +},{"socket.io-client":36}],35:[function(require,module,exports){ +var util = require('util'); +var webrtc = require('webrtcsupport'); +var WildEmitter = require('wildemitter'); +var mockconsole = require('mockconsole'); +var localMedia = require('localmedia'); +var Peer = require('./peer'); + + +function WebRTC(opts) { + var self = this; + var options = opts || {}; + var config = this.config = { + debug: false, + // makes the entire PC config overridable + peerConnectionConfig: { + iceServers: [{"url": "stun:stun.l.google.com:19302"}] + }, + peerConnectionConstraints: { + optional: [ + {DtlsSrtpKeyAgreement: true} + ] + }, + receiveMedia: { + mandatory: { + OfferToReceiveAudio: true, + OfferToReceiveVideo: true + } + }, + enableDataChannels: true + }; + var item; + + // expose screensharing check + this.screenSharingSupport = webrtc.screenSharing; + + // We also allow a 'logger' option. It can be any object that implements + // log, warn, and error methods. + // We log nothing by default, following "the rule of silence": + // http://www.linfo.org/rule_of_silence.html + this.logger = function () { + // we assume that if you're in debug mode and you didn't + // pass in a logger, you actually want to log as much as + // possible. + if (opts.debug) { + return opts.logger || console; + } else { + // or we'll use your logger which should have its own logic + // for output. Or we'll return the no-op. + return opts.logger || mockconsole; + } + }(); + + // set options + for (item in options) { + this.config[item] = options[item]; + } + + // check for support + if (!webrtc.support) { + this.logger.error('Your browser doesn\'t seem to support WebRTC'); + } + + // where we'll store our peer connections + this.peers = []; + + // call localMedia constructor + localMedia.call(this, this.config); + + this.on('speaking', function () { + if (!self.hardMuted) { + // FIXME: should use sendDirectlyToAll, but currently has different semantics wrt payload + self.peers.forEach(function (peer) { + if (peer.enableDataChannels) { + var dc = peer.getDataChannel('hark'); + if (dc.readyState != 'open') return; + dc.send(JSON.stringify({type: 'speaking'})); + } + }); + } + }); + this.on('stoppedSpeaking', function () { + if (!self.hardMuted) { + // FIXME: should use sendDirectlyToAll, but currently has different semantics wrt payload + self.peers.forEach(function (peer) { + if (peer.enableDataChannels) { + var dc = peer.getDataChannel('hark'); + if (dc.readyState != 'open') return; + dc.send(JSON.stringify({type: 'stoppedSpeaking'})); + } + }); + } + }); + this.on('volumeChange', function (volume, treshold) { + if (!self.hardMuted) { + // FIXME: should use sendDirectlyToAll, but currently has different semantics wrt payload + self.peers.forEach(function (peer) { + if (peer.enableDataChannels) { + var dc = peer.getDataChannel('hark'); + if (dc.readyState != 'open') return; + dc.send(JSON.stringify({type: 'volume', volume: volume })); + } + }); + } + }); + + // log events in debug mode + if (this.config.debug) { + this.on('*', function (event, val1, val2) { + var logger; + // if you didn't pass in a logger and you explicitly turning on debug + // we're just going to assume you're wanting log output with console + if (self.config.logger === mockconsole) { + logger = console; + } else { + logger = self.logger; + } + logger.log('event:', event, val1, val2); + }); + } +} + +util.inherits(WebRTC, localMedia); + +WebRTC.prototype.createPeer = function (opts) { + var peer; + opts.parent = this; + peer = new Peer(opts); + this.peers.push(peer); + return peer; +}; + +// removes peers +WebRTC.prototype.removePeers = function (id, type) { + this.getPeers(id, type).forEach(function (peer) { + peer.end(); + }); +}; + +// fetches all Peer objects by session id and/or type +WebRTC.prototype.getPeers = function (sessionId, type) { + return this.peers.filter(function (peer) { + return (!sessionId || peer.id === sessionId) && (!type || peer.type === type); + }); +}; + +// sends message to all +WebRTC.prototype.sendToAll = function (message, payload) { + this.peers.forEach(function (peer) { + peer.send(message, payload); + }); +}; + +// sends message to all using a datachannel +// only sends to anyone who has an open datachannel +WebRTC.prototype.sendDirectlyToAll = function (channel, message, payload) { + this.peers.forEach(function (peer) { + if (peer.enableDataChannels) { + peer.sendDirectly(channel, message, payload); + } + }); +}; + +module.exports = WebRTC; + +},{"./peer":32,"localmedia":6,"mockconsole":25,"util":45,"webrtcsupport":39,"wildemitter":40}],36:[function(require,module,exports){ +/*! Socket.IO.js build:0.9.16, development. Copyright(c) 2011 LearnBoost MIT Licensed */ + +var io = ('undefined' === typeof module ? {} : module.exports); +(function() { + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, global) { + + /** + * IO namespace. + * + * @namespace + */ + + var io = exports; + + /** + * Socket.IO version + * + * @api public + */ + + io.version = '0.9.16'; + + /** + * Protocol implemented. + * + * @api public + */ + + io.protocol = 1; + + /** + * Available transports, these will be populated with the available transports + * + * @api public + */ + + io.transports = []; + + /** + * Keep track of jsonp callbacks. + * + * @api private + */ + + io.j = []; + + /** + * Keep track of our io.Sockets + * + * @api private + */ + io.sockets = {}; + + + /** + * Manages connections to hosts. + * + * @param {String} uri + * @Param {Boolean} force creation of new socket (defaults to false) + * @api public + */ + + io.connect = function (host, details) { + var uri = io.util.parseUri(host) + , uuri + , socket; + + if (global && global.location) { + uri.protocol = uri.protocol || global.location.protocol.slice(0, -1); + uri.host = uri.host || (global.document + ? global.document.domain : global.location.hostname); + uri.port = uri.port || global.location.port; + } + + uuri = io.util.uniqueUri(uri); + + var options = { + host: uri.host + , secure: 'https' == uri.protocol + , port: uri.port || ('https' == uri.protocol ? 443 : 80) + , query: uri.query || '' + }; + + io.util.merge(options, details); + + if (options['force new connection'] || !io.sockets[uuri]) { + socket = new io.Socket(options); + } + + if (!options['force new connection'] && socket) { + io.sockets[uuri] = socket; + } + + socket = socket || io.sockets[uuri]; + + // if path is different from '' or / + return socket.of(uri.path.length > 1 ? uri.path : ''); + }; + +})('object' === typeof module ? module.exports : (this.io = {}), this); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, global) { + + /** + * Utilities namespace. + * + * @namespace + */ + + var util = exports.util = {}; + + /** + * Parses an URI + * + * @author Steven Levithan (MIT license) + * @api public + */ + + var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; + + var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', + 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', + 'anchor']; + + util.parseUri = function (str) { + var m = re.exec(str || '') + , uri = {} + , i = 14; + + while (i--) { + uri[parts[i]] = m[i] || ''; + } + + return uri; + }; + + /** + * Produces a unique url that identifies a Socket.IO connection. + * + * @param {Object} uri + * @api public + */ + + util.uniqueUri = function (uri) { + var protocol = uri.protocol + , host = uri.host + , port = uri.port; + + if ('document' in global) { + host = host || document.domain; + port = port || (protocol == 'https' + && document.location.protocol !== 'https:' ? 443 : document.location.port); + } else { + host = host || 'localhost'; + + if (!port && protocol == 'https') { + port = 443; + } + } + + return (protocol || 'http') + '://' + host + ':' + (port || 80); + }; + + /** + * Mergest 2 query strings in to once unique query string + * + * @param {String} base + * @param {String} addition + * @api public + */ + + util.query = function (base, addition) { + var query = util.chunkQuery(base || '') + , components = []; + + util.merge(query, util.chunkQuery(addition || '')); + for (var part in query) { + if (query.hasOwnProperty(part)) { + components.push(part + '=' + query[part]); + } + } + + return components.length ? '?' + components.join('&') : ''; + }; + + /** + * Transforms a querystring in to an object + * + * @param {String} qs + * @api public + */ + + util.chunkQuery = function (qs) { + var query = {} + , params = qs.split('&') + , i = 0 + , l = params.length + , kv; + + for (; i < l; ++i) { + kv = params[i].split('='); + if (kv[0]) { + query[kv[0]] = kv[1]; + } + } + + return query; + }; + + /** + * Executes the given function when the page is loaded. + * + * io.util.load(function () { console.log('page loaded'); }); + * + * @param {Function} fn + * @api public + */ + + var pageLoaded = false; + + util.load = function (fn) { + if ('document' in global && document.readyState === 'complete' || pageLoaded) { + return fn(); + } + + util.on(global, 'load', fn, false); + }; + + /** + * Adds an event. + * + * @api private + */ + + util.on = function (element, event, fn, capture) { + if (element.attachEvent) { + element.attachEvent('on' + event, fn); + } else if (element.addEventListener) { + element.addEventListener(event, fn, capture); + } + }; + + /** + * Generates the correct `XMLHttpRequest` for regular and cross domain requests. + * + * @param {Boolean} [xdomain] Create a request that can be used cross domain. + * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest. + * @api private + */ + + util.request = function (xdomain) { + + if (xdomain && 'undefined' != typeof XDomainRequest && !util.ua.hasCORS) { + return new XDomainRequest(); + } + + if ('undefined' != typeof XMLHttpRequest && (!xdomain || util.ua.hasCORS)) { + return new XMLHttpRequest(); + } + + if (!xdomain) { + try { + return new window[(['Active'].concat('Object').join('X'))]('Microsoft.XMLHTTP'); + } catch(e) { } + } + + return null; + }; + + /** + * XHR based transport constructor. + * + * @constructor + * @api public + */ + + /** + * Change the internal pageLoaded value. + */ + + if ('undefined' != typeof window) { + util.load(function () { + pageLoaded = true; + }); + } + + /** + * Defers a function to ensure a spinner is not displayed by the browser + * + * @param {Function} fn + * @api public + */ + + util.defer = function (fn) { + if (!util.ua.webkit || 'undefined' != typeof importScripts) { + return fn(); + } + + util.load(function () { + setTimeout(fn, 100); + }); + }; + + /** + * Merges two objects. + * + * @api public + */ + + util.merge = function merge (target, additional, deep, lastseen) { + var seen = lastseen || [] + , depth = typeof deep == 'undefined' ? 2 : deep + , prop; + + for (prop in additional) { + if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) { + if (typeof target[prop] !== 'object' || !depth) { + target[prop] = additional[prop]; + seen.push(additional[prop]); + } else { + util.merge(target[prop], additional[prop], depth - 1, seen); + } + } + } + + return target; + }; + + /** + * Merges prototypes from objects + * + * @api public + */ + + util.mixin = function (ctor, ctor2) { + util.merge(ctor.prototype, ctor2.prototype); + }; + + /** + * Shortcut for prototypical and static inheritance. + * + * @api private + */ + + util.inherit = function (ctor, ctor2) { + function f() {}; + f.prototype = ctor2.prototype; + ctor.prototype = new f; + }; + + /** + * Checks if the given object is an Array. + * + * io.util.isArray([]); // true + * io.util.isArray({}); // false + * + * @param Object obj + * @api public + */ + + util.isArray = Array.isArray || function (obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; + + /** + * Intersects values of two arrays into a third + * + * @api public + */ + + util.intersect = function (arr, arr2) { + var ret = [] + , longest = arr.length > arr2.length ? arr : arr2 + , shortest = arr.length > arr2.length ? arr2 : arr; + + for (var i = 0, l = shortest.length; i < l; i++) { + if (~util.indexOf(longest, shortest[i])) + ret.push(shortest[i]); + } + + return ret; + }; + + /** + * Array indexOf compatibility. + * + * @see bit.ly/a5Dxa2 + * @api public + */ + + util.indexOf = function (arr, o, i) { + + for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0; + i < j && arr[i] !== o; i++) {} + + return j <= i ? -1 : i; + }; + + /** + * Converts enumerables to array. + * + * @api public + */ + + util.toArray = function (enu) { + var arr = []; + + for (var i = 0, l = enu.length; i < l; i++) + arr.push(enu[i]); + + return arr; + }; + + /** + * UA / engines detection namespace. + * + * @namespace + */ + + util.ua = {}; + + /** + * Whether the UA supports CORS for XHR. + * + * @api public + */ + + util.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () { + try { + var a = new XMLHttpRequest(); + } catch (e) { + return false; + } + + return a.withCredentials != undefined; + })(); + + /** + * Detect webkit. + * + * @api public + */ + + util.ua.webkit = 'undefined' != typeof navigator + && /webkit/i.test(navigator.userAgent); + + /** + * Detect iPad/iPhone/iPod. + * + * @api public + */ + + util.ua.iDevice = 'undefined' != typeof navigator + && /iPad|iPhone|iPod/i.test(navigator.userAgent); + +})('undefined' != typeof io ? io : module.exports, this); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.EventEmitter = EventEmitter; + + /** + * Event emitter constructor. + * + * @api public. + */ + + function EventEmitter () {}; + + /** + * Adds a listener + * + * @api public + */ + + EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (io.util.isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; + }; + + EventEmitter.prototype.addListener = EventEmitter.prototype.on; + + /** + * Adds a volatile listener. + * + * @api public + */ + + EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; + }; + + /** + * Removes a listener. + * + * @api public + */ + + EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (io.util.isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; + }; + + /** + * Removes all listeners for an event. + * + * @api public + */ + + EventEmitter.prototype.removeAllListeners = function (name) { + if (name === undefined) { + this.$events = {}; + return this; + } + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; + }; + + /** + * Gets all listeners for a certain event. + * + * @api publci + */ + + EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!io.util.isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; + }; + + /** + * Emits an event. + * + * @api public + */ + + EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = Array.prototype.slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (io.util.isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +/** + * Based on JSON2 (http://www.JSON.org/js.html). + */ + +(function (exports, nativeJSON) { + "use strict"; + + // use native JSON if it's available + if (nativeJSON && nativeJSON.parse){ + return exports.JSON = { + parse: nativeJSON.parse + , stringify: nativeJSON.stringify + }; + } + + var JSON = exports.JSON = {}; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + function date(d, key) { + return isFinite(d.valueOf()) ? + d.getUTCFullYear() + '-' + + f(d.getUTCMonth() + 1) + '-' + + f(d.getUTCDate()) + 'T' + + f(d.getUTCHours()) + ':' + + f(d.getUTCMinutes()) + ':' + + f(d.getUTCSeconds()) + 'Z' : null; + }; + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value instanceof Date) { + value = date(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : gap ? + '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : gap ? + '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : + '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + +// If the JSON object does not yet have a parse method, give it one. + + JSON.parse = function (text, reviver) { + // The parse method takes a text and an optional reviver function, and returns + // a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + + // The walk method is used to recursively walk the resulting structure so + // that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + + // Parsing happens in four stages. In the first stage, we replace certain + // Unicode characters with escape sequences. JavaScript handles many characters + // incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + + // In the second stage, we run the text against regular expressions that look + // for non-JSON patterns. We are especially concerned with '()' and 'new' + // because they can cause invocation, and '=' because it can cause mutation. + // But just to be safe, we want to reject all unexpected forms. + + // We split the second stage into 4 regexp operations in order to work around + // crippling inefficiencies in IE's and Safari's regexp engines. First we + // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we + // replace all simple value tokens with ']' characters. Third, we delete all + // open brackets that follow a colon or comma or that begin the text. Finally, + // we look to see that the remaining characters are only whitespace or ']' or + // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ + .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + + // In the third stage we use the eval function to compile the text into a + // JavaScript structure. The '{' operator is subject to a syntactic ambiguity + // in JavaScript: it can begin a block or an object literal. We wrap the text + // in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + + // In the optional fourth stage, we recursively walk the new structure, passing + // each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + + // If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , typeof JSON !== 'undefined' ? JSON : undefined +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Parser namespace. + * + * @namespace + */ + + var parser = exports.parser = {}; + + /** + * Packet types. + */ + + var packets = parser.packets = [ + 'disconnect' + , 'connect' + , 'heartbeat' + , 'message' + , 'json' + , 'event' + , 'ack' + , 'error' + , 'noop' + ]; + + /** + * Errors reasons. + */ + + var reasons = parser.reasons = [ + 'transport not supported' + , 'client not handshaken' + , 'unauthorized' + ]; + + /** + * Errors advice. + */ + + var advice = parser.advice = [ + 'reconnect' + ]; + + /** + * Shortcuts. + */ + + var JSON = io.JSON + , indexOf = io.util.indexOf; + + /** + * Encodes a packet. + * + * @api private + */ + + parser.encodePacket = function (packet) { + var type = indexOf(packets, packet.type) + , id = packet.id || '' + , endpoint = packet.endpoint || '' + , ack = packet.ack + , data = null; + + switch (packet.type) { + case 'error': + var reason = packet.reason ? indexOf(reasons, packet.reason) : '' + , adv = packet.advice ? indexOf(advice, packet.advice) : ''; + + if (reason !== '' || adv !== '') + data = reason + (adv !== '' ? ('+' + adv) : ''); + + break; + + case 'message': + if (packet.data !== '') + data = packet.data; + break; + + case 'event': + var ev = { name: packet.name }; + + if (packet.args && packet.args.length) { + ev.args = packet.args; + } + + data = JSON.stringify(ev); + break; + + case 'json': + data = JSON.stringify(packet.data); + break; + + case 'connect': + if (packet.qs) + data = packet.qs; + break; + + case 'ack': + data = packet.ackId + + (packet.args && packet.args.length + ? '+' + JSON.stringify(packet.args) : ''); + break; + } + + // construct packet with required fragments + var encoded = [ + type + , id + (ack == 'data' ? '+' : '') + , endpoint + ]; + + // data fragment is optional + if (data !== null && data !== undefined) + encoded.push(data); + + return encoded.join(':'); + }; + + /** + * Encodes multiple messages (payload). + * + * @param {Array} messages + * @api private + */ + + parser.encodePayload = function (packets) { + var decoded = ''; + + if (packets.length == 1) + return packets[0]; + + for (var i = 0, l = packets.length; i < l; i++) { + var packet = packets[i]; + decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]; + } + + return decoded; + }; + + /** + * Decodes a packet + * + * @api private + */ + + var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/; + + parser.decodePacket = function (data) { + var pieces = data.match(regexp); + + if (!pieces) return {}; + + var id = pieces[2] || '' + , data = pieces[5] || '' + , packet = { + type: packets[pieces[1]] + , endpoint: pieces[4] || '' + }; + + // whether we need to acknowledge the packet + if (id) { + packet.id = id; + if (pieces[3]) + packet.ack = 'data'; + else + packet.ack = true; + } + + // handle different packet types + switch (packet.type) { + case 'error': + var pieces = data.split('+'); + packet.reason = reasons[pieces[0]] || ''; + packet.advice = advice[pieces[1]] || ''; + break; + + case 'message': + packet.data = data || ''; + break; + + case 'event': + try { + var opts = JSON.parse(data); + packet.name = opts.name; + packet.args = opts.args; + } catch (e) { } + + packet.args = packet.args || []; + break; + + case 'json': + try { + packet.data = JSON.parse(data); + } catch (e) { } + break; + + case 'connect': + packet.qs = data || ''; + break; + + case 'ack': + var pieces = data.match(/^([0-9]+)(\+)?(.*)/); + if (pieces) { + packet.ackId = pieces[1]; + packet.args = []; + + if (pieces[3]) { + try { + packet.args = pieces[3] ? JSON.parse(pieces[3]) : []; + } catch (e) { } + } + } + break; + + case 'disconnect': + case 'heartbeat': + break; + }; + + return packet; + }; + + /** + * Decodes data payload. Detects multiple messages + * + * @return {Array} messages + * @api public + */ + + parser.decodePayload = function (data) { + // IE doesn't like data[i] for unicode chars, charAt works fine + if (data.charAt(0) == '\ufffd') { + var ret = []; + + for (var i = 1, length = ''; i < data.length; i++) { + if (data.charAt(i) == '\ufffd') { + ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length))); + i += Number(length) + 1; + length = ''; + } else { + length += data.charAt(i); + } + } + + return ret; + } else { + return [parser.decodePacket(data)]; + } + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.Transport = Transport; + + /** + * This is the transport template for all supported transport methods. + * + * @constructor + * @api public + */ + + function Transport (socket, sessid) { + this.socket = socket; + this.sessid = sessid; + }; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(Transport, io.EventEmitter); + + + /** + * Indicates whether heartbeats is enabled for this transport + * + * @api private + */ + + Transport.prototype.heartbeats = function () { + return true; + }; + + /** + * Handles the response from the server. When a new response is received + * it will automatically update the timeout, decode the message and + * forwards the response to the onMessage function for further processing. + * + * @param {String} data Response from the server. + * @api private + */ + + Transport.prototype.onData = function (data) { + this.clearCloseTimeout(); + + // If the connection in currently open (or in a reopening state) reset the close + // timeout since we have just received data. This check is necessary so + // that we don't reset the timeout on an explicitly disconnected connection. + if (this.socket.connected || this.socket.connecting || this.socket.reconnecting) { + this.setCloseTimeout(); + } + + if (data !== '') { + // todo: we should only do decodePayload for xhr transports + var msgs = io.parser.decodePayload(data); + + if (msgs && msgs.length) { + for (var i = 0, l = msgs.length; i < l; i++) { + this.onPacket(msgs[i]); + } + } + } + + return this; + }; + + /** + * Handles packets. + * + * @api private + */ + + Transport.prototype.onPacket = function (packet) { + this.socket.setHeartbeatTimeout(); + + if (packet.type == 'heartbeat') { + return this.onHeartbeat(); + } + + if (packet.type == 'connect' && packet.endpoint == '') { + this.onConnect(); + } + + if (packet.type == 'error' && packet.advice == 'reconnect') { + this.isOpen = false; + } + + this.socket.onPacket(packet); + + return this; + }; + + /** + * Sets close timeout + * + * @api private + */ + + Transport.prototype.setCloseTimeout = function () { + if (!this.closeTimeout) { + var self = this; + + this.closeTimeout = setTimeout(function () { + self.onDisconnect(); + }, this.socket.closeTimeout); + } + }; + + /** + * Called when transport disconnects. + * + * @api private + */ + + Transport.prototype.onDisconnect = function () { + if (this.isOpen) this.close(); + this.clearTimeouts(); + this.socket.onDisconnect(); + return this; + }; + + /** + * Called when transport connects + * + * @api private + */ + + Transport.prototype.onConnect = function () { + this.socket.onConnect(); + return this; + }; + + /** + * Clears close timeout + * + * @api private + */ + + Transport.prototype.clearCloseTimeout = function () { + if (this.closeTimeout) { + clearTimeout(this.closeTimeout); + this.closeTimeout = null; + } + }; + + /** + * Clear timeouts + * + * @api private + */ + + Transport.prototype.clearTimeouts = function () { + this.clearCloseTimeout(); + + if (this.reopenTimeout) { + clearTimeout(this.reopenTimeout); + } + }; + + /** + * Sends a packet + * + * @param {Object} packet object. + * @api private + */ + + Transport.prototype.packet = function (packet) { + this.send(io.parser.encodePacket(packet)); + }; + + /** + * Send the received heartbeat message back to server. So the server + * knows we are still connected. + * + * @param {String} heartbeat Heartbeat response from the server. + * @api private + */ + + Transport.prototype.onHeartbeat = function (heartbeat) { + this.packet({ type: 'heartbeat' }); + }; + + /** + * Called when the transport opens. + * + * @api private + */ + + Transport.prototype.onOpen = function () { + this.isOpen = true; + this.clearCloseTimeout(); + this.socket.onOpen(); + }; + + /** + * Notifies the base when the connection with the Socket.IO server + * has been disconnected. + * + * @api private + */ + + Transport.prototype.onClose = function () { + var self = this; + + /* FIXME: reopen delay causing a infinit loop + this.reopenTimeout = setTimeout(function () { + self.open(); + }, this.socket.options['reopen delay']);*/ + + this.isOpen = false; + this.socket.onClose(); + this.onDisconnect(); + }; + + /** + * Generates a connection url based on the Socket.IO URL Protocol. + * See for more details. + * + * @returns {String} Connection url + * @api private + */ + + Transport.prototype.prepareUrl = function () { + var options = this.socket.options; + + return this.scheme() + '://' + + options.host + ':' + options.port + '/' + + options.resource + '/' + io.protocol + + '/' + this.name + '/' + this.sessid; + }; + + /** + * Checks if the transport is ready to start a connection. + * + * @param {Socket} socket The socket instance that needs a transport + * @param {Function} fn The callback + * @api private + */ + + Transport.prototype.ready = function (socket, fn) { + fn.call(this); + }; +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + */ + + exports.Socket = Socket; + + /** + * Create a new `Socket.IO client` which can establish a persistent + * connection with a Socket.IO enabled server. + * + * @api public + */ + + function Socket (options) { + this.options = { + port: 80 + , secure: false + , document: 'document' in global ? document : false + , resource: 'socket.io' + , transports: io.transports + , 'connect timeout': 10000 + , 'try multiple transports': true + , 'reconnect': true + , 'reconnection delay': 500 + , 'reconnection limit': Infinity + , 'reopen delay': 3000 + , 'max reconnection attempts': 10 + , 'sync disconnect on unload': false + , 'auto connect': true + , 'flash policy port': 10843 + , 'manualFlush': false + }; + + io.util.merge(this.options, options); + + this.connected = false; + this.open = false; + this.connecting = false; + this.reconnecting = false; + this.namespaces = {}; + this.buffer = []; + this.doBuffer = false; + + if (this.options['sync disconnect on unload'] && + (!this.isXDomain() || io.util.ua.hasCORS)) { + var self = this; + io.util.on(global, 'beforeunload', function () { + self.disconnectSync(); + }, false); + } + + if (this.options['auto connect']) { + this.connect(); + } +}; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(Socket, io.EventEmitter); + + /** + * Returns a namespace listener/emitter for this socket + * + * @api public + */ + + Socket.prototype.of = function (name) { + if (!this.namespaces[name]) { + this.namespaces[name] = new io.SocketNamespace(this, name); + + if (name !== '') { + this.namespaces[name].packet({ type: 'connect' }); + } + } + + return this.namespaces[name]; + }; + + /** + * Emits the given event to the Socket and all namespaces + * + * @api private + */ + + Socket.prototype.publish = function () { + this.emit.apply(this, arguments); + + var nsp; + + for (var i in this.namespaces) { + if (this.namespaces.hasOwnProperty(i)) { + nsp = this.of(i); + nsp.$emit.apply(nsp, arguments); + } + } + }; + + /** + * Performs the handshake + * + * @api private + */ + + function empty () { }; + + Socket.prototype.handshake = function (fn) { + var self = this + , options = this.options; + + function complete (data) { + if (data instanceof Error) { + self.connecting = false; + self.onError(data.message); + } else { + fn.apply(null, data.split(':')); + } + }; + + var url = [ + 'http' + (options.secure ? 's' : '') + ':/' + , options.host + ':' + options.port + , options.resource + , io.protocol + , io.util.query(this.options.query, 't=' + +new Date) + ].join('/'); + + if (this.isXDomain() && !io.util.ua.hasCORS) { + var insertAt = document.getElementsByTagName('script')[0] + , script = document.createElement('script'); + + script.src = url + '&jsonp=' + io.j.length; + insertAt.parentNode.insertBefore(script, insertAt); + + io.j.push(function (data) { + complete(data); + script.parentNode.removeChild(script); + }); + } else { + var xhr = io.util.request(); + + xhr.open('GET', url, true); + if (this.isXDomain()) { + xhr.withCredentials = true; + } + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty; + + if (xhr.status == 200) { + complete(xhr.responseText); + } else if (xhr.status == 403) { + self.onError(xhr.responseText); + } else { + self.connecting = false; + !self.reconnecting && self.onError(xhr.responseText); + } + } + }; + xhr.send(null); + } + }; + + /** + * Find an available transport based on the options supplied in the constructor. + * + * @api private + */ + + Socket.prototype.getTransport = function (override) { + var transports = override || this.transports, match; + + for (var i = 0, transport; transport = transports[i]; i++) { + if (io.Transport[transport] + && io.Transport[transport].check(this) + && (!this.isXDomain() || io.Transport[transport].xdomainCheck(this))) { + return new io.Transport[transport](this, this.sessionid); + } + } + + return null; + }; + + /** + * Connects to the server. + * + * @param {Function} [fn] Callback. + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.connect = function (fn) { + if (this.connecting) { + return this; + } + + var self = this; + self.connecting = true; + + this.handshake(function (sid, heartbeat, close, transports) { + self.sessionid = sid; + self.closeTimeout = close * 1000; + self.heartbeatTimeout = heartbeat * 1000; + if(!self.transports) + self.transports = self.origTransports = (transports ? io.util.intersect( + transports.split(',') + , self.options.transports + ) : self.options.transports); + + self.setHeartbeatTimeout(); + + function connect (transports){ + if (self.transport) self.transport.clearTimeouts(); + + self.transport = self.getTransport(transports); + if (!self.transport) return self.publish('connect_failed'); + + // once the transport is ready + self.transport.ready(self, function () { + self.connecting = true; + self.publish('connecting', self.transport.name); + self.transport.open(); + + if (self.options['connect timeout']) { + self.connectTimeoutTimer = setTimeout(function () { + if (!self.connected) { + self.connecting = false; + + if (self.options['try multiple transports']) { + var remaining = self.transports; + + while (remaining.length > 0 && remaining.splice(0,1)[0] != + self.transport.name) {} + + if (remaining.length){ + connect(remaining); + } else { + self.publish('connect_failed'); + } + } + } + }, self.options['connect timeout']); + } + }); + } + + connect(self.transports); + + self.once('connect', function (){ + clearTimeout(self.connectTimeoutTimer); + + fn && typeof fn == 'function' && fn(); + }); + }); + + return this; + }; + + /** + * Clears and sets a new heartbeat timeout using the value given by the + * server during the handshake. + * + * @api private + */ + + Socket.prototype.setHeartbeatTimeout = function () { + clearTimeout(this.heartbeatTimeoutTimer); + if(this.transport && !this.transport.heartbeats()) return; + + var self = this; + this.heartbeatTimeoutTimer = setTimeout(function () { + self.transport.onClose(); + }, this.heartbeatTimeout); + }; + + /** + * Sends a message. + * + * @param {Object} data packet. + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.packet = function (data) { + if (this.connected && !this.doBuffer) { + this.transport.packet(data); + } else { + this.buffer.push(data); + } + + return this; + }; + + /** + * Sets buffer state + * + * @api private + */ + + Socket.prototype.setBuffer = function (v) { + this.doBuffer = v; + + if (!v && this.connected && this.buffer.length) { + if (!this.options['manualFlush']) { + this.flushBuffer(); + } + } + }; + + /** + * Flushes the buffer data over the wire. + * To be invoked manually when 'manualFlush' is set to true. + * + * @api public + */ + + Socket.prototype.flushBuffer = function() { + this.transport.payload(this.buffer); + this.buffer = []; + }; + + + /** + * Disconnect the established connect. + * + * @returns {io.Socket} + * @api public + */ + + Socket.prototype.disconnect = function () { + if (this.connected || this.connecting) { + if (this.open) { + this.of('').packet({ type: 'disconnect' }); + } + + // handle disconnection immediately + this.onDisconnect('booted'); + } + + return this; + }; + + /** + * Disconnects the socket with a sync XHR. + * + * @api private + */ + + Socket.prototype.disconnectSync = function () { + // ensure disconnection + var xhr = io.util.request(); + var uri = [ + 'http' + (this.options.secure ? 's' : '') + ':/' + , this.options.host + ':' + this.options.port + , this.options.resource + , io.protocol + , '' + , this.sessionid + ].join('/') + '/?disconnect=1'; + + xhr.open('GET', uri, false); + xhr.send(null); + + // handle disconnection immediately + this.onDisconnect('booted'); + }; + + /** + * Check if we need to use cross domain enabled transports. Cross domain would + * be a different port or different domain name. + * + * @returns {Boolean} + * @api private + */ + + Socket.prototype.isXDomain = function () { + + var port = global.location.port || + ('https:' == global.location.protocol ? 443 : 80); + + return this.options.host !== global.location.hostname + || this.options.port != port; + }; + + /** + * Called upon handshake. + * + * @api private + */ + + Socket.prototype.onConnect = function () { + if (!this.connected) { + this.connected = true; + this.connecting = false; + if (!this.doBuffer) { + // make sure to flush the buffer + this.setBuffer(false); + } + this.emit('connect'); + } + }; + + /** + * Called when the transport opens + * + * @api private + */ + + Socket.prototype.onOpen = function () { + this.open = true; + }; + + /** + * Called when the transport closes. + * + * @api private + */ + + Socket.prototype.onClose = function () { + this.open = false; + clearTimeout(this.heartbeatTimeoutTimer); + }; + + /** + * Called when the transport first opens a connection + * + * @param text + */ + + Socket.prototype.onPacket = function (packet) { + this.of(packet.endpoint).onPacket(packet); + }; + + /** + * Handles an error. + * + * @api private + */ + + Socket.prototype.onError = function (err) { + if (err && err.advice) { + if (err.advice === 'reconnect' && (this.connected || this.connecting)) { + this.disconnect(); + if (this.options.reconnect) { + this.reconnect(); + } + } + } + + this.publish('error', err && err.reason ? err.reason : err); + }; + + /** + * Called when the transport disconnects. + * + * @api private + */ + + Socket.prototype.onDisconnect = function (reason) { + var wasConnected = this.connected + , wasConnecting = this.connecting; + + this.connected = false; + this.connecting = false; + this.open = false; + + if (wasConnected || wasConnecting) { + this.transport.close(); + this.transport.clearTimeouts(); + if (wasConnected) { + this.publish('disconnect', reason); + + if ('booted' != reason && this.options.reconnect && !this.reconnecting) { + this.reconnect(); + } + } + } + }; + + /** + * Called upon reconnection. + * + * @api private + */ + + Socket.prototype.reconnect = function () { + this.reconnecting = true; + this.reconnectionAttempts = 0; + this.reconnectionDelay = this.options['reconnection delay']; + + var self = this + , maxAttempts = this.options['max reconnection attempts'] + , tryMultiple = this.options['try multiple transports'] + , limit = this.options['reconnection limit']; + + function reset () { + if (self.connected) { + for (var i in self.namespaces) { + if (self.namespaces.hasOwnProperty(i) && '' !== i) { + self.namespaces[i].packet({ type: 'connect' }); + } + } + self.publish('reconnect', self.transport.name, self.reconnectionAttempts); + } + + clearTimeout(self.reconnectionTimer); + + self.removeListener('connect_failed', maybeReconnect); + self.removeListener('connect', maybeReconnect); + + self.reconnecting = false; + + delete self.reconnectionAttempts; + delete self.reconnectionDelay; + delete self.reconnectionTimer; + delete self.redoTransports; + + self.options['try multiple transports'] = tryMultiple; + }; + + function maybeReconnect () { + if (!self.reconnecting) { + return; + } + + if (self.connected) { + return reset(); + }; + + if (self.connecting && self.reconnecting) { + return self.reconnectionTimer = setTimeout(maybeReconnect, 1000); + } + + if (self.reconnectionAttempts++ >= maxAttempts) { + if (!self.redoTransports) { + self.on('connect_failed', maybeReconnect); + self.options['try multiple transports'] = true; + self.transports = self.origTransports; + self.transport = self.getTransport(); + self.redoTransports = true; + self.connect(); + } else { + self.publish('reconnect_failed'); + reset(); + } + } else { + if (self.reconnectionDelay < limit) { + self.reconnectionDelay *= 2; // exponential back off + } + + self.connect(); + self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts); + self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay); + } + }; + + this.options['try multiple transports'] = false; + this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay); + + this.on('connect', maybeReconnect); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.SocketNamespace = SocketNamespace; + + /** + * Socket namespace constructor. + * + * @constructor + * @api public + */ + + function SocketNamespace (socket, name) { + this.socket = socket; + this.name = name || ''; + this.flags = {}; + this.json = new Flag(this, 'json'); + this.ackPackets = 0; + this.acks = {}; + }; + + /** + * Apply EventEmitter mixin. + */ + + io.util.mixin(SocketNamespace, io.EventEmitter); + + /** + * Copies emit since we override it + * + * @api private + */ + + SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit; + + /** + * Creates a new namespace, by proxying the request to the socket. This + * allows us to use the synax as we do on the server. + * + * @api public + */ + + SocketNamespace.prototype.of = function () { + return this.socket.of.apply(this.socket, arguments); + }; + + /** + * Sends a packet. + * + * @api private + */ + + SocketNamespace.prototype.packet = function (packet) { + packet.endpoint = this.name; + this.socket.packet(packet); + this.flags = {}; + return this; + }; + + /** + * Sends a message + * + * @api public + */ + + SocketNamespace.prototype.send = function (data, fn) { + var packet = { + type: this.flags.json ? 'json' : 'message' + , data: data + }; + + if ('function' == typeof fn) { + packet.id = ++this.ackPackets; + packet.ack = true; + this.acks[packet.id] = fn; + } + + return this.packet(packet); + }; + + /** + * Emits an event + * + * @api public + */ + + SocketNamespace.prototype.emit = function (name) { + var args = Array.prototype.slice.call(arguments, 1) + , lastArg = args[args.length - 1] + , packet = { + type: 'event' + , name: name + }; + + if ('function' == typeof lastArg) { + packet.id = ++this.ackPackets; + packet.ack = 'data'; + this.acks[packet.id] = lastArg; + args = args.slice(0, args.length - 1); + } + + packet.args = args; + + return this.packet(packet); + }; + + /** + * Disconnects the namespace + * + * @api private + */ + + SocketNamespace.prototype.disconnect = function () { + if (this.name === '') { + this.socket.disconnect(); + } else { + this.packet({ type: 'disconnect' }); + this.$emit('disconnect'); + } + + return this; + }; + + /** + * Handles a packet + * + * @api private + */ + + SocketNamespace.prototype.onPacket = function (packet) { + var self = this; + + function ack () { + self.packet({ + type: 'ack' + , args: io.util.toArray(arguments) + , ackId: packet.id + }); + }; + + switch (packet.type) { + case 'connect': + this.$emit('connect'); + break; + + case 'disconnect': + if (this.name === '') { + this.socket.onDisconnect(packet.reason || 'booted'); + } else { + this.$emit('disconnect', packet.reason); + } + break; + + case 'message': + case 'json': + var params = ['message', packet.data]; + + if (packet.ack == 'data') { + params.push(ack); + } else if (packet.ack) { + this.packet({ type: 'ack', ackId: packet.id }); + } + + this.$emit.apply(this, params); + break; + + case 'event': + var params = [packet.name].concat(packet.args); + + if (packet.ack == 'data') + params.push(ack); + + this.$emit.apply(this, params); + break; + + case 'ack': + if (this.acks[packet.ackId]) { + this.acks[packet.ackId].apply(this, packet.args); + delete this.acks[packet.ackId]; + } + break; + + case 'error': + if (packet.advice){ + this.socket.onError(packet); + } else { + if (packet.reason == 'unauthorized') { + this.$emit('connect_failed', packet.reason); + } else { + this.$emit('error', packet.reason); + } + } + break; + } + }; + + /** + * Flag interface. + * + * @api private + */ + + function Flag (nsp, name) { + this.namespace = nsp; + this.name = name; + }; + + /** + * Send a message + * + * @api public + */ + + Flag.prototype.send = function () { + this.namespace.flags[this.name] = true; + this.namespace.send.apply(this.namespace, arguments); + }; + + /** + * Emit an event + * + * @api public + */ + + Flag.prototype.emit = function () { + this.namespace.flags[this.name] = true; + this.namespace.emit.apply(this.namespace, arguments); + }; + +})( + 'undefined' != typeof io ? io : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + */ + + exports.websocket = WS; + + /** + * The WebSocket transport uses the HTML5 WebSocket API to establish an + * persistent connection with the Socket.IO server. This transport will also + * be inherited by the FlashSocket fallback as it provides a API compatible + * polyfill for the WebSockets. + * + * @constructor + * @extends {io.Transport} + * @api public + */ + + function WS (socket) { + io.Transport.apply(this, arguments); + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(WS, io.Transport); + + /** + * Transport name + * + * @api public + */ + + WS.prototype.name = 'websocket'; + + /** + * Initializes a new `WebSocket` connection with the Socket.IO server. We attach + * all the appropriate listeners to handle the responses from the server. + * + * @returns {Transport} + * @api public + */ + + WS.prototype.open = function () { + var query = io.util.query(this.socket.options.query) + , self = this + , Socket + + + if (!Socket) { + Socket = global.MozWebSocket || global.WebSocket; + } + + this.websocket = new Socket(this.prepareUrl() + query); + + this.websocket.onopen = function () { + self.onOpen(); + self.socket.setBuffer(false); + }; + this.websocket.onmessage = function (ev) { + self.onData(ev.data); + }; + this.websocket.onclose = function () { + self.onClose(); + self.socket.setBuffer(true); + }; + this.websocket.onerror = function (e) { + self.onError(e); + }; + + return this; + }; + + /** + * Send a message to the Socket.IO server. The message will automatically be + * encoded in the correct message format. + * + * @returns {Transport} + * @api public + */ + + // Do to a bug in the current IDevices browser, we need to wrap the send in a + // setTimeout, when they resume from sleeping the browser will crash if + // we don't allow the browser time to detect the socket has been closed + if (io.util.ua.iDevice) { + WS.prototype.send = function (data) { + var self = this; + setTimeout(function() { + self.websocket.send(data); + },0); + return this; + }; + } else { + WS.prototype.send = function (data) { + this.websocket.send(data); + return this; + }; + } + + /** + * Payload + * + * @api private + */ + + WS.prototype.payload = function (arr) { + for (var i = 0, l = arr.length; i < l; i++) { + this.packet(arr[i]); + } + return this; + }; + + /** + * Disconnect the established `WebSocket` connection. + * + * @returns {Transport} + * @api public + */ + + WS.prototype.close = function () { + this.websocket.close(); + return this; + }; + + /** + * Handle the errors that `WebSocket` might be giving when we + * are attempting to connect or send messages. + * + * @param {Error} e The error. + * @api private + */ + + WS.prototype.onError = function (e) { + this.socket.onError(e); + }; + + /** + * Returns the appropriate scheme for the URI generation. + * + * @api private + */ + WS.prototype.scheme = function () { + return this.socket.options.secure ? 'wss' : 'ws'; + }; + + /** + * Checks if the browser has support for native `WebSockets` and that + * it's not the polyfill created for the FlashSocket transport. + * + * @return {Boolean} + * @api public + */ + + WS.check = function () { + return ('WebSocket' in global && !('__addTask' in WebSocket)) + || 'MozWebSocket' in global; + }; + + /** + * Check if the `WebSocket` transport support cross domain communications. + * + * @returns {Boolean} + * @api public + */ + + WS.xdomainCheck = function () { + return true; + }; + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('websocket'); + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.flashsocket = Flashsocket; + + /** + * The FlashSocket transport. This is a API wrapper for the HTML5 WebSocket + * specification. It uses a .swf file to communicate with the server. If you want + * to serve the .swf file from a other server than where the Socket.IO script is + * coming from you need to use the insecure version of the .swf. More information + * about this can be found on the github page. + * + * @constructor + * @extends {io.Transport.websocket} + * @api public + */ + + function Flashsocket () { + io.Transport.websocket.apply(this, arguments); + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(Flashsocket, io.Transport.websocket); + + /** + * Transport name + * + * @api public + */ + + Flashsocket.prototype.name = 'flashsocket'; + + /** + * Disconnect the established `FlashSocket` connection. This is done by adding a + * new task to the FlashSocket. The rest will be handled off by the `WebSocket` + * transport. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.open = function () { + var self = this + , args = arguments; + + WebSocket.__addTask(function () { + io.Transport.websocket.prototype.open.apply(self, args); + }); + return this; + }; + + /** + * Sends a message to the Socket.IO server. This is done by adding a new + * task to the FlashSocket. The rest will be handled off by the `WebSocket` + * transport. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.send = function () { + var self = this, args = arguments; + WebSocket.__addTask(function () { + io.Transport.websocket.prototype.send.apply(self, args); + }); + return this; + }; + + /** + * Disconnects the established `FlashSocket` connection. + * + * @returns {Transport} + * @api public + */ + + Flashsocket.prototype.close = function () { + WebSocket.__tasks.length = 0; + io.Transport.websocket.prototype.close.call(this); + return this; + }; + + /** + * The WebSocket fall back needs to append the flash container to the body + * element, so we need to make sure we have access to it. Or defer the call + * until we are sure there is a body element. + * + * @param {Socket} socket The socket instance that needs a transport + * @param {Function} fn The callback + * @api private + */ + + Flashsocket.prototype.ready = function (socket, fn) { + function init () { + var options = socket.options + , port = options['flash policy port'] + , path = [ + 'http' + (options.secure ? 's' : '') + ':/' + , options.host + ':' + options.port + , options.resource + , 'static/flashsocket' + , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf' + ]; + + // Only start downloading the swf file when the checked that this browser + // actually supports it + if (!Flashsocket.loaded) { + if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') { + // Set the correct file based on the XDomain settings + WEB_SOCKET_SWF_LOCATION = path.join('/'); + } + + if (port !== 843) { + WebSocket.loadFlashPolicyFile('xmlsocket://' + options.host + ':' + port); + } + + WebSocket.__initialize(); + Flashsocket.loaded = true; + } + + fn.call(self); + } + + var self = this; + if (document.body) return init(); + + io.util.load(init); + }; + + /** + * Check if the FlashSocket transport is supported as it requires that the Adobe + * Flash Player plug-in version `10.0.0` or greater is installed. And also check if + * the polyfill is correctly loaded. + * + * @returns {Boolean} + * @api public + */ + + Flashsocket.check = function () { + if ( + typeof WebSocket == 'undefined' + || !('__initialize' in WebSocket) || !swfobject + ) return false; + + return swfobject.getFlashPlayerVersion().major >= 10; + }; + + /** + * Check if the FlashSocket transport can be used as cross domain / cross origin + * transport. Because we can't see which type (secure or insecure) of .swf is used + * we will just return true. + * + * @returns {Boolean} + * @api public + */ + + Flashsocket.xdomainCheck = function () { + return true; + }; + + /** + * Disable AUTO_INITIALIZATION + */ + + if (typeof window != 'undefined') { + WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true; + } + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('flashsocket'); +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); +/* SWFObject v2.2 + is released under the MIT License +*/ +if ('undefined' != typeof window) { +var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O[(['Active'].concat('Object').join('X'))]!=D){try{var ad=new window[(['Active'].concat('Object').join('X'))](W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab +// License: New BSD License +// Reference: http://dev.w3.org/html5/websockets/ +// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol + +(function() { + + if ('undefined' == typeof window || window.WebSocket) return; + + var console = window.console; + if (!console || !console.log || !console.error) { + console = {log: function(){ }, error: function(){ }}; + } + + if (!swfobject.hasFlashPlayerVersion("10.0.0")) { + console.error("Flash Player >= 10.0.0 is required."); + return; + } + if (location.protocol == "file:") { + console.error( + "WARNING: web-socket-js doesn't work in file:///... URL " + + "unless you set Flash Security Settings properly. " + + "Open the page via Web server i.e. http://..."); + } + + /** + * This class represents a faux web socket. + * @param {string} url + * @param {array or string} protocols + * @param {string} proxyHost + * @param {int} proxyPort + * @param {string} headers + */ + WebSocket = function(url, protocols, proxyHost, proxyPort, headers) { + var self = this; + self.__id = WebSocket.__nextId++; + WebSocket.__instances[self.__id] = self; + self.readyState = WebSocket.CONNECTING; + self.bufferedAmount = 0; + self.__events = {}; + if (!protocols) { + protocols = []; + } else if (typeof protocols == "string") { + protocols = [protocols]; + } + // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc. + // Otherwise, when onopen fires immediately, onopen is called before it is set. + setTimeout(function() { + WebSocket.__addTask(function() { + WebSocket.__flash.create( + self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null); + }); + }, 0); + }; + + /** + * Send data to the web socket. + * @param {string} data The data to send to the socket. + * @return {boolean} True for success, false for failure. + */ + WebSocket.prototype.send = function(data) { + if (this.readyState == WebSocket.CONNECTING) { + throw "INVALID_STATE_ERR: Web Socket connection has not been established"; + } + // We use encodeURIComponent() here, because FABridge doesn't work if + // the argument includes some characters. We don't use escape() here + // because of this: + // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions + // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't + // preserve all Unicode characters either e.g. "\uffff" in Firefox. + // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require + // additional testing. + var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data)); + if (result < 0) { // success + return true; + } else { + this.bufferedAmount += result; + return false; + } + }; + + /** + * Close this web socket gracefully. + */ + WebSocket.prototype.close = function() { + if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) { + return; + } + this.readyState = WebSocket.CLOSING; + WebSocket.__flash.close(this.__id); + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {string} type + * @param {function} listener + * @param {boolean} useCapture + * @return void + */ + WebSocket.prototype.addEventListener = function(type, listener, useCapture) { + if (!(type in this.__events)) { + this.__events[type] = []; + } + this.__events[type].push(listener); + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {string} type + * @param {function} listener + * @param {boolean} useCapture + * @return void + */ + WebSocket.prototype.removeEventListener = function(type, listener, useCapture) { + if (!(type in this.__events)) return; + var events = this.__events[type]; + for (var i = events.length - 1; i >= 0; --i) { + if (events[i] === listener) { + events.splice(i, 1); + break; + } + } + }; + + /** + * Implementation of {@link DOM 2 EventTarget Interface} + * + * @param {Event} event + * @return void + */ + WebSocket.prototype.dispatchEvent = function(event) { + var events = this.__events[event.type] || []; + for (var i = 0; i < events.length; ++i) { + events[i](event); + } + var handler = this["on" + event.type]; + if (handler) handler(event); + }; + + /** + * Handles an event from Flash. + * @param {Object} flashEvent + */ + WebSocket.prototype.__handleEvent = function(flashEvent) { + if ("readyState" in flashEvent) { + this.readyState = flashEvent.readyState; + } + if ("protocol" in flashEvent) { + this.protocol = flashEvent.protocol; + } + + var jsEvent; + if (flashEvent.type == "open" || flashEvent.type == "error") { + jsEvent = this.__createSimpleEvent(flashEvent.type); + } else if (flashEvent.type == "close") { + // TODO implement jsEvent.wasClean + jsEvent = this.__createSimpleEvent("close"); + } else if (flashEvent.type == "message") { + var data = decodeURIComponent(flashEvent.message); + jsEvent = this.__createMessageEvent("message", data); + } else { + throw "unknown event type: " + flashEvent.type; + } + + this.dispatchEvent(jsEvent); + }; + + WebSocket.prototype.__createSimpleEvent = function(type) { + if (document.createEvent && window.Event) { + var event = document.createEvent("Event"); + event.initEvent(type, false, false); + return event; + } else { + return {type: type, bubbles: false, cancelable: false}; + } + }; + + WebSocket.prototype.__createMessageEvent = function(type, data) { + if (document.createEvent && window.MessageEvent && !window.opera) { + var event = document.createEvent("MessageEvent"); + event.initMessageEvent("message", false, false, data, null, null, window, null); + return event; + } else { + // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes. + return {type: type, data: data, bubbles: false, cancelable: false}; + } + }; + + /** + * Define the WebSocket readyState enumeration. + */ + WebSocket.CONNECTING = 0; + WebSocket.OPEN = 1; + WebSocket.CLOSING = 2; + WebSocket.CLOSED = 3; + + WebSocket.__flash = null; + WebSocket.__instances = {}; + WebSocket.__tasks = []; + WebSocket.__nextId = 0; + + /** + * Load a new flash security policy file. + * @param {string} url + */ + WebSocket.loadFlashPolicyFile = function(url){ + WebSocket.__addTask(function() { + WebSocket.__flash.loadManualPolicyFile(url); + }); + }; + + /** + * Loads WebSocketMain.swf and creates WebSocketMain object in Flash. + */ + WebSocket.__initialize = function() { + if (WebSocket.__flash) return; + + if (WebSocket.__swfLocation) { + // For backword compatibility. + window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation; + } + if (!window.WEB_SOCKET_SWF_LOCATION) { + console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf"); + return; + } + var container = document.createElement("div"); + container.id = "webSocketContainer"; + // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents + // Flash from loading at least in IE. So we move it out of the screen at (-100, -100). + // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash + // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is + // the best we can do as far as we know now. + container.style.position = "absolute"; + if (WebSocket.__isFlashLite()) { + container.style.left = "0px"; + container.style.top = "0px"; + } else { + container.style.left = "-100px"; + container.style.top = "-100px"; + } + var holder = document.createElement("div"); + holder.id = "webSocketFlash"; + container.appendChild(holder); + document.body.appendChild(container); + // See this article for hasPriority: + // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html + swfobject.embedSWF( + WEB_SOCKET_SWF_LOCATION, + "webSocketFlash", + "1" /* width */, + "1" /* height */, + "10.0.0" /* SWF version */, + null, + null, + {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"}, + null, + function(e) { + if (!e.success) { + console.error("[WebSocket] swfobject.embedSWF failed"); + } + }); + }; + + /** + * Called by Flash to notify JS that it's fully loaded and ready + * for communication. + */ + WebSocket.__onFlashInitialized = function() { + // We need to set a timeout here to avoid round-trip calls + // to flash during the initialization process. + setTimeout(function() { + WebSocket.__flash = document.getElementById("webSocketFlash"); + WebSocket.__flash.setCallerUrl(location.href); + WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG); + for (var i = 0; i < WebSocket.__tasks.length; ++i) { + WebSocket.__tasks[i](); + } + WebSocket.__tasks = []; + }, 0); + }; + + /** + * Called by Flash to notify WebSockets events are fired. + */ + WebSocket.__onFlashEvent = function() { + setTimeout(function() { + try { + // Gets events using receiveEvents() instead of getting it from event object + // of Flash event. This is to make sure to keep message order. + // It seems sometimes Flash events don't arrive in the same order as they are sent. + var events = WebSocket.__flash.receiveEvents(); + for (var i = 0; i < events.length; ++i) { + WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]); + } + } catch (e) { + console.error(e); + } + }, 0); + return true; + }; + + // Called by Flash. + WebSocket.__log = function(message) { + console.log(decodeURIComponent(message)); + }; + + // Called by Flash. + WebSocket.__error = function(message) { + console.error(decodeURIComponent(message)); + }; + + WebSocket.__addTask = function(task) { + if (WebSocket.__flash) { + task(); + } else { + WebSocket.__tasks.push(task); + } + }; + + /** + * Test if the browser is running flash lite. + * @return {boolean} True if flash lite is running, false otherwise. + */ + WebSocket.__isFlashLite = function() { + if (!window.navigator || !window.navigator.mimeTypes) { + return false; + } + var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"]; + if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) { + return false; + } + return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false; + }; + + if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) { + if (window.addEventListener) { + window.addEventListener("load", function(){ + WebSocket.__initialize(); + }, false); + } else { + window.attachEvent("onload", function(){ + WebSocket.__initialize(); + }); + } + } + +})(); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + * + * @api public + */ + + exports.XHR = XHR; + + /** + * XHR constructor + * + * @costructor + * @api public + */ + + function XHR (socket) { + if (!socket) return; + + io.Transport.apply(this, arguments); + this.sendBuffer = []; + }; + + /** + * Inherits from Transport. + */ + + io.util.inherit(XHR, io.Transport); + + /** + * Establish a connection + * + * @returns {Transport} + * @api public + */ + + XHR.prototype.open = function () { + this.socket.setBuffer(false); + this.onOpen(); + this.get(); + + // we need to make sure the request succeeds since we have no indication + // whether the request opened or not until it succeeded. + this.setCloseTimeout(); + + return this; + }; + + /** + * Check if we need to send data to the Socket.IO server, if we have data in our + * buffer we encode it and forward it to the `post` method. + * + * @api private + */ + + XHR.prototype.payload = function (payload) { + var msgs = []; + + for (var i = 0, l = payload.length; i < l; i++) { + msgs.push(io.parser.encodePacket(payload[i])); + } + + this.send(io.parser.encodePayload(msgs)); + }; + + /** + * Send data to the Socket.IO server. + * + * @param data The message + * @returns {Transport} + * @api public + */ + + XHR.prototype.send = function (data) { + this.post(data); + return this; + }; + + /** + * Posts a encoded message to the Socket.IO server. + * + * @param {String} data A encoded message. + * @api private + */ + + function empty () { }; + + XHR.prototype.post = function (data) { + var self = this; + this.socket.setBuffer(true); + + function stateChange () { + if (this.readyState == 4) { + this.onreadystatechange = empty; + self.posting = false; + + if (this.status == 200){ + self.socket.setBuffer(false); + } else { + self.onClose(); + } + } + } + + function onload () { + this.onload = empty; + self.socket.setBuffer(false); + }; + + this.sendXHR = this.request('POST'); + + if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) { + this.sendXHR.onload = this.sendXHR.onerror = onload; + } else { + this.sendXHR.onreadystatechange = stateChange; + } + + this.sendXHR.send(data); + }; + + /** + * Disconnects the established `XHR` connection. + * + * @returns {Transport} + * @api public + */ + + XHR.prototype.close = function () { + this.onClose(); + return this; + }; + + /** + * Generates a configured XHR request + * + * @param {String} url The url that needs to be requested. + * @param {String} method The method the request should use. + * @returns {XMLHttpRequest} + * @api private + */ + + XHR.prototype.request = function (method) { + var req = io.util.request(this.socket.isXDomain()) + , query = io.util.query(this.socket.options.query, 't=' + +new Date); + + req.open(method || 'GET', this.prepareUrl() + query, true); + + if (method == 'POST') { + try { + if (req.setRequestHeader) { + req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8'); + } else { + // XDomainRequest + req.contentType = 'text/plain'; + } + } catch (e) {} + } + + return req; + }; + + /** + * Returns the scheme to use for the transport URLs. + * + * @api private + */ + + XHR.prototype.scheme = function () { + return this.socket.options.secure ? 'https' : 'http'; + }; + + /** + * Check if the XHR transports are supported + * + * @param {Boolean} xdomain Check if we support cross domain requests. + * @returns {Boolean} + * @api public + */ + + XHR.check = function (socket, xdomain) { + try { + var request = io.util.request(xdomain), + usesXDomReq = (global.XDomainRequest && request instanceof XDomainRequest), + socketProtocol = (socket && socket.options && socket.options.secure ? 'https:' : 'http:'), + isXProtocol = (global.location && socketProtocol != global.location.protocol); + if (request && !(usesXDomReq && isXProtocol)) { + return true; + } + } catch(e) {} + + return false; + }; + + /** + * Check if the XHR transport supports cross domain requests. + * + * @returns {Boolean} + * @api public + */ + + XHR.xdomainCheck = function (socket) { + return XHR.check(socket, true); + }; + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io) { + + /** + * Expose constructor. + */ + + exports.htmlfile = HTMLFile; + + /** + * The HTMLFile transport creates a `forever iframe` based transport + * for Internet Explorer. Regular forever iframe implementations will + * continuously trigger the browsers buzy indicators. If the forever iframe + * is created inside a `htmlfile` these indicators will not be trigged. + * + * @constructor + * @extends {io.Transport.XHR} + * @api public + */ + + function HTMLFile (socket) { + io.Transport.XHR.apply(this, arguments); + }; + + /** + * Inherits from XHR transport. + */ + + io.util.inherit(HTMLFile, io.Transport.XHR); + + /** + * Transport name + * + * @api public + */ + + HTMLFile.prototype.name = 'htmlfile'; + + /** + * Creates a new Ac...eX `htmlfile` with a forever loading iframe + * that can be used to listen to messages. Inside the generated + * `htmlfile` a reference will be made to the HTMLFile transport. + * + * @api private + */ + + HTMLFile.prototype.get = function () { + this.doc = new window[(['Active'].concat('Object').join('X'))]('htmlfile'); + this.doc.open(); + this.doc.write(''); + this.doc.close(); + this.doc.parentWindow.s = this; + + var iframeC = this.doc.createElement('div'); + iframeC.className = 'socketio'; + + this.doc.body.appendChild(iframeC); + this.iframe = this.doc.createElement('iframe'); + + iframeC.appendChild(this.iframe); + + var self = this + , query = io.util.query(this.socket.options.query, 't='+ +new Date); + + this.iframe.src = this.prepareUrl() + query; + + io.util.on(window, 'unload', function () { + self.destroy(); + }); + }; + + /** + * The Socket.IO server will write script tags inside the forever + * iframe, this function will be used as callback for the incoming + * information. + * + * @param {String} data The message + * @param {document} doc Reference to the context + * @api private + */ + + HTMLFile.prototype._ = function (data, doc) { + // unescape all forward slashes. see GH-1251 + data = data.replace(/\\\//g, '/'); + this.onData(data); + try { + var script = doc.getElementsByTagName('script')[0]; + script.parentNode.removeChild(script); + } catch (e) { } + }; + + /** + * Destroy the established connection, iframe and `htmlfile`. + * And calls the `CollectGarbage` function of Internet Explorer + * to release the memory. + * + * @api private + */ + + HTMLFile.prototype.destroy = function () { + if (this.iframe){ + try { + this.iframe.src = 'about:blank'; + } catch(e){} + + this.doc = null; + this.iframe.parentNode.removeChild(this.iframe); + this.iframe = null; + + CollectGarbage(); + } + }; + + /** + * Disconnects the established connection. + * + * @returns {Transport} Chaining. + * @api public + */ + + HTMLFile.prototype.close = function () { + this.destroy(); + return io.Transport.XHR.prototype.close.call(this); + }; + + /** + * Checks if the browser supports this transport. The browser + * must have an `Ac...eXObject` implementation. + * + * @return {Boolean} + * @api public + */ + + HTMLFile.check = function (socket) { + if (typeof window != "undefined" && (['Active'].concat('Object').join('X')) in window){ + try { + var a = new window[(['Active'].concat('Object').join('X'))]('htmlfile'); + return a && io.Transport.XHR.check(socket); + } catch(e){} + } + return false; + }; + + /** + * Check if cross domain requests are supported. + * + * @returns {Boolean} + * @api public + */ + + HTMLFile.xdomainCheck = function () { + // we can probably do handling for sub-domains, we should + // test that it's cross domain but a subdomain here + return false; + }; + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('htmlfile'); + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + + /** + * Expose constructor. + */ + + exports['xhr-polling'] = XHRPolling; + + /** + * The XHR-polling transport uses long polling XHR requests to create a + * "persistent" connection with the server. + * + * @constructor + * @api public + */ + + function XHRPolling () { + io.Transport.XHR.apply(this, arguments); + }; + + /** + * Inherits from XHR transport. + */ + + io.util.inherit(XHRPolling, io.Transport.XHR); + + /** + * Merge the properties from XHR transport + */ + + io.util.merge(XHRPolling, io.Transport.XHR); + + /** + * Transport name + * + * @api public + */ + + XHRPolling.prototype.name = 'xhr-polling'; + + /** + * Indicates whether heartbeats is enabled for this transport + * + * @api private + */ + + XHRPolling.prototype.heartbeats = function () { + return false; + }; + + /** + * Establish a connection, for iPhone and Android this will be done once the page + * is loaded. + * + * @returns {Transport} Chaining. + * @api public + */ + + XHRPolling.prototype.open = function () { + var self = this; + + io.Transport.XHR.prototype.open.call(self); + return false; + }; + + /** + * Starts a XHR request to wait for incoming messages. + * + * @api private + */ + + function empty () {}; + + XHRPolling.prototype.get = function () { + if (!this.isOpen) return; + + var self = this; + + function stateChange () { + if (this.readyState == 4) { + this.onreadystatechange = empty; + + if (this.status == 200) { + self.onData(this.responseText); + self.get(); + } else { + self.onClose(); + } + } + }; + + function onload () { + this.onload = empty; + this.onerror = empty; + self.retryCounter = 1; + self.onData(this.responseText); + self.get(); + }; + + function onerror () { + self.retryCounter ++; + if(!self.retryCounter || self.retryCounter > 3) { + self.onClose(); + } else { + self.get(); + } + }; + + this.xhr = this.request(); + + if (global.XDomainRequest && this.xhr instanceof XDomainRequest) { + this.xhr.onload = onload; + this.xhr.onerror = onerror; + } else { + this.xhr.onreadystatechange = stateChange; + } + + this.xhr.send(null); + }; + + /** + * Handle the unclean close behavior. + * + * @api private + */ + + XHRPolling.prototype.onClose = function () { + io.Transport.XHR.prototype.onClose.call(this); + + if (this.xhr) { + this.xhr.onreadystatechange = this.xhr.onload = this.xhr.onerror = empty; + try { + this.xhr.abort(); + } catch(e){} + this.xhr = null; + } + }; + + /** + * Webkit based browsers show a infinit spinner when you start a XHR request + * before the browsers onload event is called so we need to defer opening of + * the transport until the onload event is called. Wrapping the cb in our + * defer method solve this. + * + * @param {Socket} socket The socket instance that needs a transport + * @param {Function} fn The callback + * @api private + */ + + XHRPolling.prototype.ready = function (socket, fn) { + var self = this; + + io.util.defer(function () { + fn.call(self); + }); + }; + + /** + * Add the transport to your public io.transports array. + * + * @api private + */ + + io.transports.push('xhr-polling'); + +})( + 'undefined' != typeof io ? io.Transport : module.exports + , 'undefined' != typeof io ? io : module.parent.exports + , this +); + +/** + * socket.io + * Copyright(c) 2011 LearnBoost + * MIT Licensed + */ + +(function (exports, io, global) { + /** + * There is a way to hide the loading indicator in Firefox. If you create and + * remove a iframe it will stop showing the current loading indicator. + * Unfortunately we can't feature detect that and UA sniffing is evil. + * + * @api private + */ + + var indicator = global.document && "MozAppearance" in + global.document.documentElement.style; + + /** + * Expose constructor. + */ + + exports['jsonp-polling'] = JSONPPolling; + + /** + * The JSONP transport creates an persistent connection by dynamically + * inserting a script tag in the page. This script tag will receive the + * information of the Socket.IO server. When new information is received + * it creates a new script tag for the new data stream. + * + * @constructor + * @extends {io.Transport.xhr-polling} + * @api public + */ + + function JSONPPolling (socket) { + io.Transport['xhr-polling'].apply(this, arguments); + + this.index = io.j.length; + + var self = this; + + io.j.push(function (msg) { + self._(msg); + }); + }; + + /** + * Inherits from XHR polling transport. + */ + + io.util.inherit(JSONPPolling, io.Transport['xhr-polling']); + + /** + * Transport name + * + * @api public + */ + + JSONPPolling.prototype.name = 'jsonp-polling'; + + /** + * Posts a encoded message to the Socket.IO server using an iframe. + * The iframe is used because script tags can create POST based requests. + * The iframe is positioned outside of the view so the user does not + * notice it's existence. + * + * @param {String} data A encoded message. + * @api private + */ + + JSONPPolling.prototype.post = function (data) { + var self = this + , query = io.util.query( + this.socket.options.query + , 't='+ (+new Date) + '&i=' + this.index + ); + + if (!this.form) { + var form = document.createElement('form') + , area = document.createElement('textarea') + , id = this.iframeId = 'socketio_iframe_' + this.index + , iframe; + + form.className = 'socketio'; + form.style.position = 'absolute'; + form.style.top = '0px'; + form.style.left = '0px'; + form.style.display = 'none'; + form.target = id; + form.method = 'POST'; + form.setAttribute('accept-charset', 'utf-8'); + area.name = 'd'; + form.appendChild(area); + document.body.appendChild(form); + + this.form = form; + this.area = area; + } + + this.form.action = this.prepareUrl() + query; + + function complete () { + initIframe(); + self.socket.setBuffer(false); + }; + + function initIframe () { + if (self.iframe) { + self.form.removeChild(self.iframe); + } + + try { + // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) + iframe = document.createElement('