├── .gitignore
├── README.md
├── app.js
├── bower_components
└── gss
│ ├── .bower.json
│ ├── CHANGES.md
│ ├── LICENSE
│ ├── README.md
│ ├── bower.json
│ ├── dist
│ ├── gss.js
│ ├── gss.min.js
│ ├── gss
│ │ └── vendor
│ │ │ ├── MutationObserver.js
│ │ │ ├── observe.js
│ │ │ └── sidetable.js
│ ├── slightlyoff-cassowary.js
│ │ └── bin
│ │ │ └── c.js
│ ├── worker.js
│ └── worker.min.js
│ └── vendor
│ ├── MutationObserver.js
│ ├── gl-matrix-min.js
│ ├── gl-matrix.js
│ ├── observe.js
│ └── sidetable.js
├── index.html
├── index.js
├── package.json
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *~
3 | bundle.js
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-gss
2 | 
3 | constraint layout system for components using grid stylesheets
4 |
5 | ```js
6 | var VerticalCenter = React.createClass({
7 | render: function() {
8 | return this.transferPropsTo(
9 |
10 | {this.props.children}
11 |
12 | );
13 | }
14 | });
15 |
16 | var App = React.createClass({
17 | render: function() {
18 | // You can prefix the props on Box with >= or <= for more control
19 | return (
20 |
21 |
27 | Heading
28 |
29 |
34 | Left nav
35 |
36 |
42 | Content
43 |
44 |
45 | );
46 | }
47 | });
48 | ```
49 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var mq = require('react-responsive');
5 | var {AutoLayout, Box} = require('./index');
6 |
7 | var App = React.createClass({
8 | render: function() {
9 | return (
10 |
11 | This is the header
12 |
13 | This is the left nav
14 |
15 |
16 |
17 | Content here
18 |
19 |
20 |
21 | );
22 | }
23 | });
24 |
25 | GSS.once('afterLoaded', function() {
26 | React.renderComponent(, document.body);
27 | });
28 |
--------------------------------------------------------------------------------
/bower_components/gss/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gss",
3 | "homepage": "http://gridstylesheets.org/",
4 | "authors": [
5 | "Dan Tocchini "
6 | ],
7 | "description": "Grid Style Sheets Runtime",
8 | "main": [
9 | "dist/gss.js",
10 | "dist/gss.min.js",
11 | "dist/worker.js",
12 | "dist/worker.min.js"
13 | ],
14 | "keywords": [
15 | "gss"
16 | ],
17 | "license": "MIT",
18 | "ignore": [
19 | "/components",
20 | "/node_modules",
21 | "/bower_components",
22 | ".gitignore",
23 | "/src",
24 | "/lib",
25 | "/spec",
26 | "/demo",
27 | "/docs",
28 | "_layouts",
29 | "_includes",
30 | "_config.yml",
31 | "CNAME",
32 | "component.json",
33 | "package.json",
34 | "Gruntfile.coffee",
35 | "index.html",
36 | ".travis.yml"
37 | ],
38 | "version": "1.0.4-beta",
39 | "_release": "1.0.4-beta",
40 | "_resolution": {
41 | "type": "version",
42 | "tag": "1.0.4-beta",
43 | "commit": "4e1d9f5d824dd57800e1d2c1f87097c8417acf51"
44 | },
45 | "_source": "git://github.com/the-gss/engine.git",
46 | "_target": "~1.0.4-beta",
47 | "_originalSource": "gss",
48 | "_direct": true
49 | }
--------------------------------------------------------------------------------
/bower_components/gss/CHANGES.md:
--------------------------------------------------------------------------------
1 | GSS Engine ChangeLog
2 | ====================
3 |
4 | ## 1.0.3-beta (May 24th 2014)
5 |
6 | - Selectors other than id, class & tag can now be used in CCSS when surrounded by parans:
7 |
8 | ```css
9 | (.section > article:not(.featured))[font-size] == 100;
10 | ```
11 |
12 | - Support for plural selectors on either side of a constraint operator:
13 |
14 | ```css
15 | .article[font-size] == .header[font-size];
16 |
17 | @h |[.a][.b]| in(.cont) chain-width;
18 |
19 | .container {
20 | @h |[.itemA][.itemB]| in(::) chain-width;
21 | }
22 | ```
23 |
24 | - 2D sugar props: `size`, `position`, `center`, `intrinsic-size`, `top-left`, `top-right`, `bottom-left`, `bottom-right`
25 |
26 |
27 | ## 1.0.2-beta (April 14th 2014)
28 |
29 | - VGL: `@grid-template` empty zones can be defined with `.`
30 | - VGL: added `in()` to `@grid-template`
31 | - VGL: added `h/v/top/right/bottom/left-gap()` to `@grid-template`
32 |
33 | VGL is still undocumented & under heavy dev.
34 |
35 | ## 1.0.1-beta (April 7th 2014)
36 |
37 | - VFL: **Point** support
38 | - VFL: shorthands `@h` & `@v` for `@horizontal` & `@vertical`
39 | - VFL: `outer-gap()`
40 | - VFL: Default containing element selector to `::this`
41 |
42 | ### New VFL Sugar
43 |
44 | With the new VFL API sugar, the following:
45 |
46 | ```css
47 | #container {
48 | @h |-[#a]-[#b]-| gap(10) outer-gap(20);
49 | }
50 | ```
51 |
52 | is equivalent too:
53 |
54 | ```css
55 | @horizontal |-20-[#a]-10-[#b]-20-| in(#container);
56 | ```
57 |
58 | ### VFL Points
59 |
60 | Elements can be aligned relative to arbitrary positioned points using `< Number | Constraint Variable | Element Property >`
61 |
62 | To horizontally align two buttons, each 8px from the center of the window:
63 |
64 | ```css
65 | /* VFL */
66 | @h [#btn1]-<::window[center-x]>-[#btn2] gap(8);
67 |
68 | /* Equivalent CCSS */
69 | #btn1[right] + 8 == ::window[center-x];
70 | ::window[center-x] + 8 == #btn2[left];
71 | ```
72 |
73 | Alignments can be positioned within points:
74 |
75 | ```css
76 | /* VFL */
77 | @h <#wall[center-x]>-[#poster]-[#clock]-<::window[right])> gap(7);
78 |
79 | /* Equivalent CCSS */
80 | #wall[center-x] + 7 == #poster[left];
81 | #poster[right] + 7 == #clock[left];
82 | ::window[right] - 7 == #clock[right];
83 | ```
84 |
85 | Numbers, variables and arithmetic can be used:
86 |
87 | ```css
88 | /* VFL */
89 | @v <100>[#box]<[row2]>;
90 |
91 | /* Equivalent CCSS */
92 | 100 == #box[top];
93 | #box[bottom] == [row2];
94 | ```css
95 |
96 |
--------------------------------------------------------------------------------
/bower_components/gss/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2014 The Grid
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/bower_components/gss/README.md:
--------------------------------------------------------------------------------
1 | GSS engine [](https://travis-ci.org/the-gss/engine)
2 | ==========
3 |
4 | [](https://saucelabs.com/u/gss-engine)
5 |
6 | Compiles and runs Grid Style Sheet (GSS) rules. GSS is an implementation of Badros & Borning's [Constraint Cascading Style Sheets](http://www.cs.washington.edu/research/constraints/web/ccss-uwtr.pdf), enabling far better layout control through building relational rules between different elements.
7 |
8 | GSS supports the following syntaxes for defining layout rules:
9 |
10 | * [CCSS](https://github.com/the-gss/ccss-compiler#readme) - direct constraints related to position and size of DOM elements
11 | * [VFL](https://github.com/the-gss/vfl-compiler#readme) - horizontal and vertical spacing constraints based on [Apple's Visual Format Language](https://developer.apple.com/library/ios/documentation/userexperience/conceptual/AutolayoutPG/VisualFormatLanguage/VisualFormatLanguage.html)
12 |
13 | Additionally, support for [GTL](https://github.com/the-gss/gtl-compiler#readme), based on the [W3C Grid Template Language](http://dev.w3.org/csswg/css-template/) is planned.
14 |
15 | The main GSS repository provides a [Component](http://component.io/) library handling both the compilation and application of the layout constraints.
16 |
17 | Please refer to for documentation and usage instructions.
18 |
--------------------------------------------------------------------------------
/bower_components/gss/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gss",
3 | "homepage": "http://gridstylesheets.org/",
4 | "authors": [
5 | "Dan Tocchini "
6 | ],
7 | "description": "Grid Style Sheets Runtime",
8 | "main": ["dist/gss.js","dist/gss.min.js","dist/worker.js","dist/worker.min.js"],
9 | "keywords": [
10 | "gss"
11 | ],
12 | "license": "MIT",
13 | "ignore": [
14 | "/components",
15 | "/node_modules",
16 | "/bower_components",
17 | ".gitignore",
18 | "/src",
19 | "/lib",
20 | "/spec",
21 | "/demo",
22 | "/docs",
23 | "_layouts",
24 | "_includes",
25 | "_config.yml",
26 | "CNAME",
27 | "component.json",
28 | "package.json",
29 | "Gruntfile.coffee",
30 | "index.html",
31 | ".travis.yml"
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/bower_components/gss/dist/gss/vendor/MutationObserver.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 The Polymer Authors. All rights reserved.
3 | * Use of this source code is goverened by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | (function(scope) {
8 | 'use strict';
9 |
10 | var setEndOfMicrotask = scope.setEndOfMicrotask
11 | var wrapIfNeeded = scope.wrapIfNeeded
12 | var wrappers = scope.wrappers;
13 |
14 | var registrationsTable = new WeakMap();
15 | var globalMutationObservers = [];
16 | var isScheduled = false;
17 |
18 | function scheduleCallback(observer) {
19 | if (isScheduled)
20 | return;
21 | setEndOfMicrotask(notifyObservers);
22 | isScheduled = true;
23 | }
24 |
25 | // http://dom.spec.whatwg.org/#mutation-observers
26 | function notifyObservers() {
27 | isScheduled = false;
28 |
29 | do {
30 | var notifyList = globalMutationObservers.slice();
31 | var anyNonEmpty = false;
32 | for (var i = 0; i < notifyList.length; i++) {
33 | var mo = notifyList[i];
34 | var queue = mo.takeRecords();
35 | removeTransientObserversFor(mo);
36 | if (queue.length) {
37 | mo.callback_(queue, mo);
38 | anyNonEmpty = true;
39 | }
40 | }
41 | } while (anyNonEmpty);
42 | }
43 |
44 | /**
45 | * @param {string} type
46 | * @param {Node} target
47 | * @constructor
48 | */
49 | function MutationRecord(type, target) {
50 | this.type = type;
51 | this.target = target;
52 | this.addedNodes = new wrappers.NodeList();
53 | this.removedNodes = new wrappers.NodeList();
54 | this.previousSibling = null;
55 | this.nextSibling = null;
56 | this.attributeName = null;
57 | this.attributeNamespace = null;
58 | this.oldValue = null;
59 | }
60 |
61 | /**
62 | * Registers transient observers to ancestor and its ancesors for the node
63 | * which was removed.
64 | * @param {!Node} ancestor
65 | * @param {!Node} node
66 | */
67 | function registerTransientObservers(ancestor, node) {
68 | for (; ancestor; ancestor = ancestor.parentNode) {
69 | var registrations = registrationsTable.get(ancestor);
70 | if (!registrations)
71 | continue;
72 | for (var i = 0; i < registrations.length; i++) {
73 | var registration = registrations[i];
74 | if (registration.options.subtree)
75 | registration.addTransientObserver(node);
76 | }
77 | }
78 | }
79 |
80 | function removeTransientObserversFor(observer) {
81 | for (var i = 0; i < observer.nodes_.length; i++) {
82 | var node = observer.nodes_[i];
83 | var registrations = registrationsTable.get(node);
84 | if (!registrations)
85 | return;
86 | for (var j = 0; j < registrations.length; j++) {
87 | var registration = registrations[j];
88 | if (registration.observer === observer)
89 | registration.removeTransientObservers();
90 | }
91 | }
92 | }
93 |
94 | // http://dom.spec.whatwg.org/#queue-a-mutation-record
95 | function enqueueMutation(target, type, data) {
96 | // 1.
97 | var interestedObservers = Object.create(null);
98 | var associatedStrings = Object.create(null);
99 |
100 | // 2.
101 | for (var node = target; node; node = node.parentNode) {
102 | // 3.
103 | var registrations = registrationsTable.get(node);
104 | if (!registrations)
105 | continue;
106 | for (var j = 0; j < registrations.length; j++) {
107 | var registration = registrations[j];
108 | var options = registration.options;
109 | // 1.
110 | if (node !== target && !options.subtree)
111 | continue;
112 |
113 | // 2.
114 | if (type === 'attributes' && !options.attributes)
115 | continue;
116 |
117 | // 3. If type is "attributes", options's attributeFilter is present, and
118 | // either options's attributeFilter does not contain name or namespace
119 | // is non-null, continue.
120 | if (type === 'attributes' && options.attributeFilter &&
121 | (data.namespace !== null ||
122 | options.attributeFilter.indexOf(data.name) === -1)) {
123 | continue;
124 | }
125 |
126 | // 4.
127 | if (type === 'characterData' && !options.characterData)
128 | continue;
129 |
130 | // 5.
131 | if (type === 'childList' && !options.childList)
132 | continue;
133 |
134 | // 6.
135 | var observer = registration.observer;
136 | interestedObservers[observer.uid_] = observer;
137 |
138 | // 7. If either type is "attributes" and options's attributeOldValue is
139 | // true, or type is "characterData" and options's characterDataOldValue
140 | // is true, set the paired string of registered observer's observer in
141 | // interested observers to oldValue.
142 | if (type === 'attributes' && options.attributeOldValue ||
143 | type === 'characterData' && options.characterDataOldValue) {
144 | associatedStrings[observer.uid_] = data.oldValue;
145 | }
146 | }
147 | }
148 |
149 | var anyRecordsEnqueued = false;
150 |
151 | // 4.
152 | for (var uid in interestedObservers) {
153 | var observer = interestedObservers[uid];
154 | var record = new MutationRecord(type, target);
155 |
156 | // 2.
157 | if ('name' in data && 'namespace' in data) {
158 | record.attributeName = data.name;
159 | record.attributeNamespace = data.namespace;
160 | }
161 |
162 | // 3.
163 | if (data.addedNodes)
164 | record.addedNodes = data.addedNodes;
165 |
166 | // 4.
167 | if (data.removedNodes)
168 | record.removedNodes = data.removedNodes;
169 |
170 | // 5.
171 | if (data.previousSibling)
172 | record.previousSibling = data.previousSibling;
173 |
174 | // 6.
175 | if (data.nextSibling)
176 | record.nextSibling = data.nextSibling;
177 |
178 | // 7.
179 | if (associatedStrings[uid] !== undefined)
180 | record.oldValue = associatedStrings[uid];
181 |
182 | // 8.
183 | observer.records_.push(record);
184 |
185 | anyRecordsEnqueued = true;
186 | }
187 |
188 | if (anyRecordsEnqueued)
189 | scheduleCallback();
190 | }
191 |
192 | var slice = Array.prototype.slice;
193 |
194 | /**
195 | * @param {!Object} options
196 | * @constructor
197 | */
198 | function MutationObserverOptions(options) {
199 | this.childList = !!options.childList;
200 | this.subtree = !!options.subtree;
201 |
202 | // 1. If either options' attributeOldValue or attributeFilter is present
203 | // and options' attributes is omitted, set options' attributes to true.
204 | if (!('attributes' in options) &&
205 | ('attributeOldValue' in options || 'attributeFilter' in options)) {
206 | this.attributes = true;
207 | } else {
208 | this.attributes = !!options.attributes;
209 | }
210 |
211 | // 2. If options' characterDataOldValue is present and options'
212 | // characterData is omitted, set options' characterData to true.
213 | if ('characterDataOldValue' in options && !('characterData' in options))
214 | this.characterData = true;
215 | else
216 | this.characterData = !!options.characterData;
217 |
218 | // 3. & 4.
219 | if (!this.attributes &&
220 | (options.attributeOldValue || 'attributeFilter' in options) ||
221 | // 5.
222 | !this.characterData && options.characterDataOldValue) {
223 | throw new TypeError();
224 | }
225 |
226 | this.characterData = !!options.characterData;
227 | this.attributeOldValue = !!options.attributeOldValue;
228 | this.characterDataOldValue = !!options.characterDataOldValue;
229 | if ('attributeFilter' in options) {
230 | if (options.attributeFilter == null ||
231 | typeof options.attributeFilter !== 'object') {
232 | throw new TypeError();
233 | }
234 | this.attributeFilter = slice.call(options.attributeFilter);
235 | } else {
236 | this.attributeFilter = null;
237 | }
238 | }
239 |
240 | var uidCounter = 0;
241 |
242 | /**
243 | * The class that maps to the DOM MutationObserver interface.
244 | * @param {Function} callback.
245 | * @constructor
246 | */
247 | function MutationObserver(callback) {
248 | this.callback_ = callback;
249 | this.nodes_ = [];
250 | this.records_ = [];
251 | this.uid_ = ++uidCounter;
252 |
253 | // This will leak. There is no way to implement this without WeakRefs :'(
254 | globalMutationObservers.push(this);
255 | }
256 |
257 | MutationObserver.prototype = {
258 | // http://dom.spec.whatwg.org/#dom-mutationobserver-observe
259 | observe: function(target, options) {
260 | target = wrapIfNeeded(target);
261 |
262 | var newOptions = new MutationObserverOptions(options);
263 |
264 | // 6.
265 | var registration;
266 | var registrations = registrationsTable.get(target);
267 | if (!registrations)
268 | registrationsTable.set(target, registrations = []);
269 |
270 | for (var i = 0; i < registrations.length; i++) {
271 | if (registrations[i].observer === this) {
272 | registration = registrations[i];
273 | // 6.1.
274 | registration.removeTransientObservers();
275 | // 6.2.
276 | registration.options = newOptions;
277 | }
278 | }
279 |
280 | // 7.
281 | if (!registration) {
282 | registration = new Registration(this, target, newOptions);
283 | registrations.push(registration);
284 | this.nodes_.push(target);
285 | }
286 | },
287 |
288 | // http://dom.spec.whatwg.org/#dom-mutationobserver-disconnect
289 | disconnect: function() {
290 | this.nodes_.forEach(function(node) {
291 | var registrations = registrationsTable.get(node);
292 | for (var i = 0; i < registrations.length; i++) {
293 | var registration = registrations[i];
294 | if (registration.observer === this) {
295 | registrations.splice(i, 1);
296 | // Each node can only have one registered observer associated with
297 | // this observer.
298 | break;
299 | }
300 | }
301 | }, this);
302 | this.records_ = [];
303 | },
304 |
305 | takeRecords: function() {
306 | var copyOfRecords = this.records_;
307 | this.records_ = [];
308 | return copyOfRecords;
309 | }
310 | };
311 |
312 | /**
313 | * Class used to represent a registered observer.
314 | * @param {MutationObserver} observer
315 | * @param {Node} target
316 | * @param {MutationObserverOptions} options
317 | * @constructor
318 | */
319 | function Registration(observer, target, options) {
320 | this.observer = observer;
321 | this.target = target;
322 | this.options = options;
323 | this.transientObservedNodes = [];
324 | }
325 |
326 | Registration.prototype = {
327 | /**
328 | * Adds a transient observer on node. The transient observer gets removed
329 | * next time we deliver the change records.
330 | * @param {Node} node
331 | */
332 | addTransientObserver: function(node) {
333 | // Don't add transient observers on the target itself. We already have all
334 | // the required listeners set up on the target.
335 | if (node === this.target)
336 | return;
337 |
338 | this.transientObservedNodes.push(node);
339 | var registrations = registrationsTable.get(node);
340 | if (!registrations)
341 | registrationsTable.set(node, registrations = []);
342 |
343 | // We know that registrations does not contain this because we already
344 | // checked if node === this.target.
345 | registrations.push(this);
346 | },
347 |
348 | removeTransientObservers: function() {
349 | var transientObservedNodes = this.transientObservedNodes;
350 | this.transientObservedNodes = [];
351 |
352 | for (var i = 0; i < transientObservedNodes.length; i++) {
353 | var node = transientObservedNodes[i];
354 | var registrations = registrationsTable.get(node);
355 | for (var j = 0; j < registrations.length; j++) {
356 | if (registrations[j] === this) {
357 | registrations.splice(j, 1);
358 | // Each node can only have one registered observer associated with
359 | // this observer.
360 | break;
361 | }
362 | }
363 | }
364 | }
365 | };
366 |
367 | scope.enqueueMutation = enqueueMutation;
368 | scope.registerTransientObservers = registerTransientObservers;
369 | scope.wrappers.MutationObserver = MutationObserver;
370 | scope.wrappers.MutationRecord = MutationRecord;
371 |
372 | })(window.ShadowDOMPolyfill);
--------------------------------------------------------------------------------
/bower_components/gss/dist/gss/vendor/observe.js:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | (function(global) {
16 | 'use strict';
17 |
18 | function detectObjectObserve() {
19 | if (typeof Object.observe !== 'function' ||
20 | typeof Array.observe !== 'function') {
21 | return false;
22 | }
23 |
24 | var gotSplice = false;
25 | function callback(records) {
26 | if (records[0].type === 'splice' && records[1].type === 'splice')
27 | gotSplice = true;
28 | }
29 |
30 | var test = [0];
31 | Array.observe(test, callback);
32 | test[1] = 1;
33 | test.length = 0;
34 | Object.deliverChangeRecords(callback);
35 | return gotSplice;
36 | }
37 |
38 | var hasObserve = detectObjectObserve();
39 |
40 | function detectEval() {
41 | // don't test for eval if document has CSP securityPolicy object and we can see that
42 | // eval is not supported. This avoids an error message in console even when the exception
43 | // is caught
44 | if (global.document &&
45 | 'securityPolicy' in global.document &&
46 | !global.document.securityPolicy.allowsEval) {
47 | return false;
48 | }
49 |
50 | try {
51 | var f = new Function('', 'return true;');
52 | return f();
53 | } catch (ex) {
54 | return false;
55 | }
56 | }
57 |
58 | var hasEval = detectEval();
59 |
60 | function isIndex(s) {
61 | return +s === s >>> 0;
62 | }
63 |
64 | function toNumber(s) {
65 | return +s;
66 | }
67 |
68 | function isObject(obj) {
69 | return obj === Object(obj);
70 | }
71 |
72 | var numberIsNaN = global.Number.isNaN || function isNaN(value) {
73 | return typeof value === 'number' && global.isNaN(value);
74 | }
75 |
76 | function areSameValue(left, right) {
77 | if (left === right)
78 | return left !== 0 || 1 / left === 1 / right;
79 | if (numberIsNaN(left) && numberIsNaN(right))
80 | return true;
81 |
82 | return left !== left && right !== right;
83 | }
84 |
85 | var createObject = ('__proto__' in {}) ?
86 | function(obj) { return obj; } :
87 | function(obj) {
88 | var proto = obj.__proto__;
89 | if (!proto)
90 | return obj;
91 | var newObject = Object.create(proto);
92 | Object.getOwnPropertyNames(obj).forEach(function(name) {
93 | Object.defineProperty(newObject, name,
94 | Object.getOwnPropertyDescriptor(obj, name));
95 | });
96 | return newObject;
97 | };
98 |
99 | var identStart = '[\$_a-zA-Z]';
100 | var identPart = '[\$_a-zA-Z0-9]';
101 | var ident = identStart + '+' + identPart + '*';
102 | var elementIndex = '(?:[0-9]|[1-9]+[0-9]+)';
103 | var identOrElementIndex = '(?:' + ident + '|' + elementIndex + ')';
104 | var path = '(?:' + identOrElementIndex + ')(?:\\s*\\.\\s*' + identOrElementIndex + ')*';
105 | var pathRegExp = new RegExp('^' + path + '$');
106 |
107 | function isPathValid(s) {
108 | if (typeof s != 'string')
109 | return false;
110 | s = s.trim();
111 |
112 | if (s == '')
113 | return true;
114 |
115 | if (s[0] == '.')
116 | return false;
117 |
118 | return pathRegExp.test(s);
119 | }
120 |
121 | var constructorIsPrivate = {};
122 |
123 | function Path(s, privateToken) {
124 | if (privateToken !== constructorIsPrivate)
125 | throw Error('Use Path.get to retrieve path objects');
126 |
127 | if (s.trim() == '')
128 | return this;
129 |
130 | if (isIndex(s)) {
131 | this.push(s);
132 | return this;
133 | }
134 |
135 | s.split(/\s*\.\s*/).filter(function(part) {
136 | return part;
137 | }).forEach(function(part) {
138 | this.push(part);
139 | }, this);
140 |
141 | if (hasEval && !hasObserve && this.length) {
142 | this.getValueFrom = this.compiledGetValueFromFn();
143 | }
144 | }
145 |
146 | // TODO(rafaelw): Make simple LRU cache
147 | var pathCache = {};
148 |
149 | function getPath(pathString) {
150 | if (pathString instanceof Path)
151 | return pathString;
152 |
153 | if (pathString == null)
154 | pathString = '';
155 |
156 | if (typeof pathString !== 'string')
157 | pathString = String(pathString);
158 |
159 | var path = pathCache[pathString];
160 | if (path)
161 | return path;
162 | if (!isPathValid(pathString))
163 | return invalidPath;
164 | var path = new Path(pathString, constructorIsPrivate);
165 | pathCache[pathString] = path;
166 | return path;
167 | }
168 |
169 | Path.get = getPath;
170 |
171 | Path.prototype = createObject({
172 | __proto__: [],
173 | valid: true,
174 |
175 | toString: function() {
176 | return this.join('.');
177 | },
178 |
179 | getValueFrom: function(obj, observedSet) {
180 | for (var i = 0; i < this.length; i++) {
181 | if (obj == null)
182 | return;
183 | if (observedSet)
184 | observedSet.observe(obj);
185 | obj = obj[this[i]];
186 | }
187 | return obj;
188 | },
189 |
190 | compiledGetValueFromFn: function() {
191 | var accessors = this.map(function(ident) {
192 | return isIndex(ident) ? '["' + ident + '"]' : '.' + ident;
193 | });
194 |
195 | var str = '';
196 | var pathString = 'obj';
197 | str += 'if (obj != null';
198 | var i = 0;
199 | for (; i < (this.length - 1); i++) {
200 | var ident = this[i];
201 | pathString += accessors[i];
202 | str += ' &&\n ' + pathString + ' != null';
203 | }
204 | str += ')\n';
205 |
206 | pathString += accessors[i];
207 |
208 | str += ' return ' + pathString + ';\nelse\n return undefined;';
209 | return new Function('obj', str);
210 | },
211 |
212 | setValueFrom: function(obj, value) {
213 | if (!this.length)
214 | return false;
215 |
216 | for (var i = 0; i < this.length - 1; i++) {
217 | if (!isObject(obj))
218 | return false;
219 | obj = obj[this[i]];
220 | }
221 |
222 | if (!isObject(obj))
223 | return false;
224 |
225 | obj[this[i]] = value;
226 | return true;
227 | }
228 | });
229 |
230 | var invalidPath = new Path('', constructorIsPrivate);
231 | invalidPath.valid = false;
232 | invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
233 |
234 | var MAX_DIRTY_CHECK_CYCLES = 1000;
235 |
236 | function dirtyCheck(observer) {
237 | var cycles = 0;
238 | while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check()) {
239 | observer.report();
240 | cycles++;
241 | }
242 | if (global.testingExposeCycleCount)
243 | global.dirtyCheckCycleCount = cycles;
244 | }
245 |
246 | function objectIsEmpty(object) {
247 | for (var prop in object)
248 | return false;
249 | return true;
250 | }
251 |
252 | function diffIsEmpty(diff) {
253 | return objectIsEmpty(diff.added) &&
254 | objectIsEmpty(diff.removed) &&
255 | objectIsEmpty(diff.changed);
256 | }
257 |
258 | function diffObjectFromOldObject(object, oldObject) {
259 | var added = {};
260 | var removed = {};
261 | var changed = {};
262 | var oldObjectHas = {};
263 |
264 | for (var prop in oldObject) {
265 | var newValue = object[prop];
266 |
267 | if (newValue !== undefined && newValue === oldObject[prop])
268 | continue;
269 |
270 | if (!(prop in object)) {
271 | removed[prop] = undefined;
272 | continue;
273 | }
274 |
275 | if (newValue !== oldObject[prop])
276 | changed[prop] = newValue;
277 | }
278 |
279 | for (var prop in object) {
280 | if (prop in oldObject)
281 | continue;
282 |
283 | added[prop] = object[prop];
284 | }
285 |
286 | if (Array.isArray(object) && object.length !== oldObject.length)
287 | changed.length = object.length;
288 |
289 | return {
290 | added: added,
291 | removed: removed,
292 | changed: changed
293 | };
294 | }
295 |
296 | function copyObject(object, opt_copy) {
297 | var copy = opt_copy || (Array.isArray(object) ? [] : {});
298 | for (var prop in object) {
299 | copy[prop] = object[prop];
300 | };
301 | if (Array.isArray(object))
302 | copy.length = object.length;
303 | return copy;
304 | }
305 |
306 | function Observer(object, callback, target, token) {
307 | this.closed = false;
308 | this.object = object;
309 | this.callback = callback;
310 | // TODO(rafaelw): Hold this.target weakly when WeakRef is available.
311 | this.target = target;
312 | this.token = token;
313 | this.reporting = true;
314 | if (hasObserve) {
315 | var self = this;
316 | this.boundInternalCallback = function(records) {
317 | self.internalCallback(records);
318 | };
319 | }
320 |
321 | addToAll(this);
322 | }
323 |
324 | Observer.prototype = {
325 | internalCallback: function(records) {
326 | if (this.closed)
327 | return;
328 | if (this.reporting && this.check(records)) {
329 | this.report();
330 | if (this.testingResults)
331 | this.testingResults.anyChanged = true;
332 | }
333 | },
334 |
335 | close: function() {
336 | if (this.closed)
337 | return;
338 | if (this.object && typeof this.object.close === 'function')
339 | this.object.close();
340 |
341 | this.disconnect();
342 | this.object = undefined;
343 | this.closed = true;
344 | },
345 |
346 | deliver: function(testingResults) {
347 | if (this.closed)
348 | return;
349 | if (hasObserve) {
350 | this.testingResults = testingResults;
351 | Object.deliverChangeRecords(this.boundInternalCallback);
352 | this.testingResults = undefined;
353 | } else {
354 | dirtyCheck(this);
355 | }
356 | },
357 |
358 | report: function() {
359 | if (!this.reporting)
360 | return;
361 |
362 | this.sync(false);
363 | if (this.callback) {
364 | this.reportArgs.push(this.token);
365 | this.invokeCallback(this.reportArgs);
366 | }
367 | this.reportArgs = undefined;
368 | },
369 |
370 | invokeCallback: function(args) {
371 | try {
372 | this.callback.apply(this.target, args);
373 | } catch (ex) {
374 | Observer._errorThrownDuringCallback = true;
375 | console.error('Exception caught during observer callback: ' + (ex.stack || ex));
376 | }
377 | },
378 |
379 | reset: function() {
380 | if (this.closed)
381 | return;
382 |
383 | if (hasObserve) {
384 | this.reporting = false;
385 | Object.deliverChangeRecords(this.boundInternalCallback);
386 | this.reporting = true;
387 | }
388 |
389 | this.sync(true);
390 | }
391 | }
392 |
393 | var collectObservers = !hasObserve || global.forceCollectObservers;
394 | var allObservers;
395 | Observer._allObserversCount = 0;
396 |
397 | if (collectObservers) {
398 | allObservers = [];
399 | }
400 |
401 | function addToAll(observer) {
402 | if (!collectObservers)
403 | return;
404 |
405 | allObservers.push(observer);
406 | Observer._allObserversCount++;
407 | }
408 |
409 | var runningMicrotaskCheckpoint = false;
410 |
411 | var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'function';
412 |
413 | global.Platform = global.Platform || {};
414 |
415 | global.Platform.performMicrotaskCheckpoint = function() {
416 | if (runningMicrotaskCheckpoint)
417 | return;
418 |
419 | if (hasDebugForceFullDelivery) {
420 | Object.deliverAllChangeRecords();
421 | return;
422 | }
423 |
424 | if (!collectObservers)
425 | return;
426 |
427 | runningMicrotaskCheckpoint = true;
428 |
429 | var cycles = 0;
430 | var results = {};
431 |
432 | do {
433 | cycles++;
434 | var toCheck = allObservers;
435 | allObservers = [];
436 | results.anyChanged = false;
437 |
438 | for (var i = 0; i < toCheck.length; i++) {
439 | var observer = toCheck[i];
440 | if (observer.closed)
441 | continue;
442 |
443 | if (hasObserve) {
444 | observer.deliver(results);
445 | } else if (observer.check()) {
446 | results.anyChanged = true;
447 | observer.report();
448 | }
449 |
450 | allObservers.push(observer);
451 | }
452 | } while (cycles < MAX_DIRTY_CHECK_CYCLES && results.anyChanged);
453 |
454 | if (global.testingExposeCycleCount)
455 | global.dirtyCheckCycleCount = cycles;
456 |
457 | Observer._allObserversCount = allObservers.length;
458 | runningMicrotaskCheckpoint = false;
459 | };
460 |
461 | if (collectObservers) {
462 | global.Platform.clearObservers = function() {
463 | allObservers = [];
464 | };
465 | }
466 |
467 | function ObjectObserver(object, callback, target, token) {
468 | Observer.call(this, object, callback, target, token);
469 | this.connect();
470 | this.sync(true);
471 | }
472 |
473 | ObjectObserver.prototype = createObject({
474 | __proto__: Observer.prototype,
475 |
476 | connect: function() {
477 | if (hasObserve)
478 | Object.observe(this.object, this.boundInternalCallback);
479 | },
480 |
481 | sync: function(hard) {
482 | if (!hasObserve)
483 | this.oldObject = copyObject(this.object);
484 | },
485 |
486 | check: function(changeRecords) {
487 | var diff;
488 | var oldValues;
489 | if (hasObserve) {
490 | if (!changeRecords)
491 | return false;
492 |
493 | oldValues = {};
494 | diff = diffObjectFromChangeRecords(this.object, changeRecords,
495 | oldValues);
496 | } else {
497 | oldValues = this.oldObject;
498 | diff = diffObjectFromOldObject(this.object, this.oldObject);
499 | }
500 |
501 | if (diffIsEmpty(diff))
502 | return false;
503 |
504 | this.reportArgs =
505 | [diff.added || {}, diff.removed || {}, diff.changed || {}];
506 | this.reportArgs.push(function(property) {
507 | return oldValues[property];
508 | });
509 |
510 | return true;
511 | },
512 |
513 | disconnect: function() {
514 | if (!hasObserve)
515 | this.oldObject = undefined;
516 | else if (this.object)
517 | Object.unobserve(this.object, this.boundInternalCallback);
518 | }
519 | });
520 |
521 | function ArrayObserver(array, callback, target, token) {
522 | if (!Array.isArray(array))
523 | throw Error('Provided object is not an Array');
524 | ObjectObserver.call(this, array, callback, target, token);
525 | }
526 |
527 | ArrayObserver.prototype = createObject({
528 | __proto__: ObjectObserver.prototype,
529 |
530 | connect: function() {
531 | if (hasObserve)
532 | Array.observe(this.object, this.boundInternalCallback);
533 | },
534 |
535 | sync: function() {
536 | if (!hasObserve)
537 | this.oldObject = this.object.slice();
538 | },
539 |
540 | check: function(changeRecords) {
541 | var splices;
542 | if (hasObserve) {
543 | if (!changeRecords)
544 | return false;
545 | splices = projectArraySplices(this.object, changeRecords);
546 | } else {
547 | splices = calcSplices(this.object, 0, this.object.length,
548 | this.oldObject, 0, this.oldObject.length);
549 | }
550 |
551 | if (!splices || !splices.length)
552 | return false;
553 |
554 | this.reportArgs = [splices];
555 | return true;
556 | }
557 | });
558 |
559 | ArrayObserver.applySplices = function(previous, current, splices) {
560 | splices.forEach(function(splice) {
561 | var spliceArgs = [splice.index, splice.removed.length];
562 | var addIndex = splice.index;
563 | while (addIndex < splice.index + splice.addedCount) {
564 | spliceArgs.push(current[addIndex]);
565 | addIndex++;
566 | }
567 |
568 | Array.prototype.splice.apply(previous, spliceArgs);
569 | });
570 | };
571 |
572 | function ObservedSet(callback) {
573 | this.arr = [];
574 | this.callback = callback;
575 | this.isObserved = true;
576 | }
577 |
578 | var objProto = Object.getPrototypeOf({});
579 | var arrayProto = Object.getPrototypeOf([]);
580 | ObservedSet.prototype = {
581 | reset: function() {
582 | this.isObserved = !this.isObserved;
583 | },
584 |
585 | observe: function(obj) {
586 | if (!isObject(obj) || obj === objProto || obj === arrayProto)
587 | return;
588 | var i = this.arr.indexOf(obj);
589 | if (i >= 0 && this.arr[i+1] === this.isObserved)
590 | return;
591 |
592 | if (i < 0) {
593 | i = this.arr.length;
594 | this.arr[i] = obj;
595 | Object.observe(obj, this.callback);
596 | }
597 |
598 | this.arr[i+1] = this.isObserved;
599 | this.observe(Object.getPrototypeOf(obj));
600 | },
601 |
602 | cleanup: function() {
603 | var i = 0, j = 0;
604 | var isObserved = this.isObserved;
605 | while(j < this.arr.length) {
606 | var obj = this.arr[j];
607 | if (this.arr[j + 1] == isObserved) {
608 | if (i < j) {
609 | this.arr[i] = obj;
610 | this.arr[i + 1] = isObserved;
611 | }
612 | i += 2;
613 | } else {
614 | Object.unobserve(obj, this.callback);
615 | }
616 | j += 2;
617 | }
618 |
619 | this.arr.length = i;
620 | }
621 | };
622 |
623 | function PathObserver(object, path, callback, target, token, valueFn,
624 | setValueFn) {
625 | var path = path instanceof Path ? path : getPath(path);
626 | if (!path || !path.length || !isObject(object)) {
627 | this.value_ = path ? path.getValueFrom(object) : undefined;
628 | this.value = valueFn ? valueFn(this.value_) : this.value_;
629 | this.closed = true;
630 | return;
631 | }
632 |
633 | Observer.call(this, object, callback, target, token);
634 | this.valueFn = valueFn;
635 | this.setValueFn = setValueFn;
636 | this.path = path;
637 |
638 | this.connect();
639 | this.sync(true);
640 | }
641 |
642 | PathObserver.prototype = createObject({
643 | __proto__: Observer.prototype,
644 |
645 | connect: function() {
646 | if (hasObserve)
647 | this.observedSet = new ObservedSet(this.boundInternalCallback);
648 | },
649 |
650 | disconnect: function() {
651 | this.value = undefined;
652 | this.value_ = undefined;
653 | if (this.observedSet) {
654 | this.observedSet.reset();
655 | this.observedSet.cleanup();
656 | this.observedSet = undefined;
657 | }
658 | },
659 |
660 | check: function() {
661 | // Note: Extracting this to a member function for use here and below
662 | // regresses dirty-checking path perf by about 25% =-(.
663 | if (this.observedSet)
664 | this.observedSet.reset();
665 |
666 | this.value_ = this.path.getValueFrom(this.object, this.observedSet);
667 |
668 | if (this.observedSet)
669 | this.observedSet.cleanup();
670 |
671 | if (areSameValue(this.value_, this.oldValue_))
672 | return false;
673 |
674 | this.value = this.valueFn ? this.valueFn(this.value_) : this.value_;
675 | this.reportArgs = [this.value, this.oldValue];
676 | return true;
677 | },
678 |
679 | sync: function(hard) {
680 | if (hard) {
681 | if (this.observedSet)
682 | this.observedSet.reset();
683 |
684 | this.value_ = this.path.getValueFrom(this.object, this.observedSet);
685 | this.value = this.valueFn ? this.valueFn(this.value_) : this.value_;
686 |
687 | if (this.observedSet)
688 | this.observedSet.cleanup();
689 | }
690 |
691 | this.oldValue_ = this.value_;
692 | this.oldValue = this.value;
693 | },
694 |
695 | setValue: function(newValue) {
696 | if (!this.path)
697 | return;
698 | if (typeof this.setValueFn === 'function')
699 | newValue = this.setValueFn(newValue);
700 | this.path.setValueFrom(this.object, newValue);
701 | }
702 | });
703 |
704 | function CompoundPathObserver(callback, target, token, valueFn) {
705 | Observer.call(this, undefined, callback, target, token);
706 | this.valueFn = valueFn;
707 |
708 | this.observed = [];
709 | this.values = [];
710 | this.value = undefined;
711 | this.oldValue = undefined;
712 | this.oldValues = undefined;
713 | this.changeFlags = undefined;
714 | this.started = false;
715 | }
716 |
717 | CompoundPathObserver.prototype = createObject({
718 | __proto__: PathObserver.prototype,
719 |
720 | addPath: function(object, path) {
721 | if (this.started)
722 | throw Error('Cannot add more paths once started.');
723 |
724 | var path = path instanceof Path ? path : getPath(path);
725 | var value = path ? path.getValueFrom(object) : undefined;
726 |
727 | this.observed.push(object, path);
728 | this.values.push(value);
729 | },
730 |
731 | start: function() {
732 | this.connect();
733 | this.sync(true);
734 | },
735 |
736 | getValues: function() {
737 | if (this.observedSet)
738 | this.observedSet.reset();
739 |
740 | var anyChanged = false;
741 | for (var i = 0; i < this.observed.length; i = i+2) {
742 | var path = this.observed[i+1];
743 | if (!path)
744 | continue;
745 | var object = this.observed[i];
746 | var value = path.getValueFrom(object, this.observedSet);
747 | var oldValue = this.values[i/2];
748 | if (!areSameValue(value, oldValue)) {
749 | if (!anyChanged && !this.valueFn) {
750 | this.oldValues = this.oldValues || [];
751 | this.changeFlags = this.changeFlags || [];
752 | for (var j = 0; j < this.values.length; j++) {
753 | this.oldValues[j] = this.values[j];
754 | this.changeFlags[j] = false;
755 | }
756 | }
757 |
758 | if (!this.valueFn)
759 | this.changeFlags[i/2] = true;
760 |
761 | this.values[i/2] = value;
762 | anyChanged = true;
763 | }
764 | }
765 |
766 | if (this.observedSet)
767 | this.observedSet.cleanup();
768 |
769 | return anyChanged;
770 | },
771 |
772 | check: function() {
773 | if (!this.getValues())
774 | return;
775 |
776 | if (this.valueFn) {
777 | this.value = this.valueFn(this.values);
778 |
779 | if (areSameValue(this.value, this.oldValue))
780 | return false;
781 |
782 | this.reportArgs = [this.value, this.oldValue];
783 | } else {
784 | this.reportArgs = [this.values, this.oldValues, this.changeFlags];
785 | }
786 |
787 | return true;
788 | },
789 |
790 | sync: function(hard) {
791 | if (hard) {
792 | this.getValues();
793 | if (this.valueFn)
794 | this.value = this.valueFn(this.values);
795 | }
796 |
797 | if (this.valueFn)
798 | this.oldValue = this.value;
799 | },
800 |
801 | close: function() {
802 | if (this.observed) {
803 | for (var i = 0; i < this.observed.length; i = i + 2) {
804 | var object = this.observed[i];
805 | if (object && typeof object.close === 'function')
806 | object.close();
807 | }
808 | this.observed = undefined;
809 | this.values = undefined;
810 | }
811 |
812 | Observer.prototype.close.call(this);
813 | }
814 | });
815 |
816 | var knownRecordTypes = {
817 | 'new': true,
818 | 'updated': true,
819 | 'deleted': true
820 | };
821 |
822 | function notifyFunction(object, name) {
823 | if (typeof Object.observe !== 'function')
824 | return;
825 |
826 | var notifier = Object.getNotifier(object);
827 | return function(type, oldValue) {
828 | var changeRecord = {
829 | object: object,
830 | type: type,
831 | name: name
832 | };
833 | if (arguments.length === 2)
834 | changeRecord.oldValue = oldValue;
835 | notifier.notify(changeRecord);
836 | }
837 | }
838 |
839 | // TODO(rafaelw): It should be possible for the Object.observe case to have
840 | // every PathObserver used by defineProperty share a single Object.observe
841 | // callback, and thus get() can simply call observer.deliver() and any changes
842 | // to any dependent value will be observed.
843 | PathObserver.defineProperty = function(object, name, descriptor) {
844 | // TODO(rafaelw): Validate errors
845 | var obj = descriptor.object;
846 | var path = getPath(descriptor.path);
847 | var notify = notifyFunction(object, name);
848 |
849 | var observer = new PathObserver(obj, descriptor.path,
850 | function(newValue, oldValue) {
851 | if (notify)
852 | notify('updated', oldValue);
853 | }
854 | );
855 |
856 | Object.defineProperty(object, name, {
857 | get: function() {
858 | return path.getValueFrom(obj);
859 | },
860 | set: function(newValue) {
861 | path.setValueFrom(obj, newValue);
862 | },
863 | configurable: true
864 | });
865 |
866 | return {
867 | close: function() {
868 | var oldValue = path.getValueFrom(obj);
869 | if (notify)
870 | observer.deliver();
871 | observer.close();
872 | Object.defineProperty(object, name, {
873 | value: oldValue,
874 | writable: true,
875 | configurable: true
876 | });
877 | }
878 | };
879 | }
880 |
881 | function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
882 | var added = {};
883 | var removed = {};
884 |
885 | for (var i = 0; i < changeRecords.length; i++) {
886 | var record = changeRecords[i];
887 | if (!knownRecordTypes[record.type]) {
888 | console.error('Unknown changeRecord type: ' + record.type);
889 | console.error(record);
890 | continue;
891 | }
892 |
893 | if (!(record.name in oldValues))
894 | oldValues[record.name] = record.oldValue;
895 |
896 | if (record.type == 'updated')
897 | continue;
898 |
899 | if (record.type == 'new') {
900 | if (record.name in removed)
901 | delete removed[record.name];
902 | else
903 | added[record.name] = true;
904 |
905 | continue;
906 | }
907 |
908 | // type = 'deleted'
909 | if (record.name in added) {
910 | delete added[record.name];
911 | delete oldValues[record.name];
912 | } else {
913 | removed[record.name] = true;
914 | }
915 | }
916 |
917 | for (var prop in added)
918 | added[prop] = object[prop];
919 |
920 | for (var prop in removed)
921 | removed[prop] = undefined;
922 |
923 | var changed = {};
924 | for (var prop in oldValues) {
925 | if (prop in added || prop in removed)
926 | continue;
927 |
928 | var newValue = object[prop];
929 | if (oldValues[prop] !== newValue)
930 | changed[prop] = newValue;
931 | }
932 |
933 | return {
934 | added: added,
935 | removed: removed,
936 | changed: changed
937 | };
938 | }
939 |
940 | function newSplice(index, removed, addedCount) {
941 | return {
942 | index: index,
943 | removed: removed,
944 | addedCount: addedCount
945 | };
946 | }
947 |
948 | var EDIT_LEAVE = 0;
949 | var EDIT_UPDATE = 1;
950 | var EDIT_ADD = 2;
951 | var EDIT_DELETE = 3;
952 |
953 | function ArraySplice() {}
954 |
955 | ArraySplice.prototype = {
956 |
957 | // Note: This function is *based* on the computation of the Levenshtein
958 | // "edit" distance. The one change is that "updates" are treated as two
959 | // edits - not one. With Array splices, an update is really a delete
960 | // followed by an add. By retaining this, we optimize for "keeping" the
961 | // maximum array items in the original array. For example:
962 | //
963 | // 'xxxx123' -> '123yyyy'
964 | //
965 | // With 1-edit updates, the shortest path would be just to update all seven
966 | // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
967 | // leaves the substring '123' intact.
968 | calcEditDistances: function(current, currentStart, currentEnd,
969 | old, oldStart, oldEnd) {
970 | // "Deletion" columns
971 | var rowCount = oldEnd - oldStart + 1;
972 | var columnCount = currentEnd - currentStart + 1;
973 | var distances = new Array(rowCount);
974 |
975 | // "Addition" rows. Initialize null column.
976 | for (var i = 0; i < rowCount; i++) {
977 | distances[i] = new Array(columnCount);
978 | distances[i][0] = i;
979 | }
980 |
981 | // Initialize null row
982 | for (var j = 0; j < columnCount; j++)
983 | distances[0][j] = j;
984 |
985 | for (var i = 1; i < rowCount; i++) {
986 | for (var j = 1; j < columnCount; j++) {
987 | if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
988 | distances[i][j] = distances[i - 1][j - 1];
989 | else {
990 | var north = distances[i - 1][j] + 1;
991 | var west = distances[i][j - 1] + 1;
992 | distances[i][j] = north < west ? north : west;
993 | }
994 | }
995 | }
996 |
997 | return distances;
998 | },
999 |
1000 | // This starts at the final weight, and walks "backward" by finding
1001 | // the minimum previous weight recursively until the origin of the weight
1002 | // matrix.
1003 | spliceOperationsFromEditDistances: function(distances) {
1004 | var i = distances.length - 1;
1005 | var j = distances[0].length - 1;
1006 | var current = distances[i][j];
1007 | var edits = [];
1008 | while (i > 0 || j > 0) {
1009 | if (i == 0) {
1010 | edits.push(EDIT_ADD);
1011 | j--;
1012 | continue;
1013 | }
1014 | if (j == 0) {
1015 | edits.push(EDIT_DELETE);
1016 | i--;
1017 | continue;
1018 | }
1019 | var northWest = distances[i - 1][j - 1];
1020 | var west = distances[i - 1][j];
1021 | var north = distances[i][j - 1];
1022 |
1023 | var min;
1024 | if (west < north)
1025 | min = west < northWest ? west : northWest;
1026 | else
1027 | min = north < northWest ? north : northWest;
1028 |
1029 | if (min == northWest) {
1030 | if (northWest == current) {
1031 | edits.push(EDIT_LEAVE);
1032 | } else {
1033 | edits.push(EDIT_UPDATE);
1034 | current = northWest;
1035 | }
1036 | i--;
1037 | j--;
1038 | } else if (min == west) {
1039 | edits.push(EDIT_DELETE);
1040 | i--;
1041 | current = west;
1042 | } else {
1043 | edits.push(EDIT_ADD);
1044 | j--;
1045 | current = north;
1046 | }
1047 | }
1048 |
1049 | edits.reverse();
1050 | return edits;
1051 | },
1052 |
1053 | /**
1054 | * Splice Projection functions:
1055 | *
1056 | * A splice map is a representation of how a previous array of items
1057 | * was transformed into a new array of items. Conceptually it is a list of
1058 | * tuples of
1059 | *
1060 | *
1061 | *
1062 | * which are kept in ascending index order of. The tuple represents that at
1063 | * the |index|, |removed| sequence of items were removed, and counting forward
1064 | * from |index|, |addedCount| items were added.
1065 | */
1066 |
1067 | /**
1068 | * Lacking individual splice mutation information, the minimal set of
1069 | * splices can be synthesized given the previous state and final state of an
1070 | * array. The basic approach is to calculate the edit distance matrix and
1071 | * choose the shortest path through it.
1072 | *
1073 | * Complexity: O(l * p)
1074 | * l: The length of the current array
1075 | * p: The length of the old array
1076 | */
1077 | calcSplices: function(current, currentStart, currentEnd,
1078 | old, oldStart, oldEnd) {
1079 | var prefixCount = 0;
1080 | var suffixCount = 0;
1081 |
1082 | var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
1083 | if (currentStart == 0 && oldStart == 0)
1084 | prefixCount = this.sharedPrefix(current, old, minLength);
1085 |
1086 | if (currentEnd == current.length && oldEnd == old.length)
1087 | suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
1088 |
1089 | currentStart += prefixCount;
1090 | oldStart += prefixCount;
1091 | currentEnd -= suffixCount;
1092 | oldEnd -= suffixCount;
1093 |
1094 | if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
1095 | return [];
1096 |
1097 | if (currentStart == currentEnd) {
1098 | var splice = newSplice(currentStart, [], 0);
1099 | while (oldStart < oldEnd)
1100 | splice.removed.push(old[oldStart++]);
1101 |
1102 | return [ splice ];
1103 | } else if (oldStart == oldEnd)
1104 | return [ newSplice(currentStart, [], currentEnd - currentStart) ];
1105 |
1106 | var ops = this.spliceOperationsFromEditDistances(
1107 | this.calcEditDistances(current, currentStart, currentEnd,
1108 | old, oldStart, oldEnd));
1109 |
1110 | var splice = undefined;
1111 | var splices = [];
1112 | var index = currentStart;
1113 | var oldIndex = oldStart;
1114 | for (var i = 0; i < ops.length; i++) {
1115 | switch(ops[i]) {
1116 | case EDIT_LEAVE:
1117 | if (splice) {
1118 | splices.push(splice);
1119 | splice = undefined;
1120 | }
1121 |
1122 | index++;
1123 | oldIndex++;
1124 | break;
1125 | case EDIT_UPDATE:
1126 | if (!splice)
1127 | splice = newSplice(index, [], 0);
1128 |
1129 | splice.addedCount++;
1130 | index++;
1131 |
1132 | splice.removed.push(old[oldIndex]);
1133 | oldIndex++;
1134 | break;
1135 | case EDIT_ADD:
1136 | if (!splice)
1137 | splice = newSplice(index, [], 0);
1138 |
1139 | splice.addedCount++;
1140 | index++;
1141 | break;
1142 | case EDIT_DELETE:
1143 | if (!splice)
1144 | splice = newSplice(index, [], 0);
1145 |
1146 | splice.removed.push(old[oldIndex]);
1147 | oldIndex++;
1148 | break;
1149 | }
1150 | }
1151 |
1152 | if (splice) {
1153 | splices.push(splice);
1154 | }
1155 | return splices;
1156 | },
1157 |
1158 | sharedPrefix: function(current, old, searchLength) {
1159 | for (var i = 0; i < searchLength; i++)
1160 | if (!this.equals(current[i], old[i]))
1161 | return i;
1162 | return searchLength;
1163 | },
1164 |
1165 | sharedSuffix: function(current, old, searchLength) {
1166 | var index1 = current.length;
1167 | var index2 = old.length;
1168 | var count = 0;
1169 | while (count < searchLength && this.equals(current[--index1], old[--index2]))
1170 | count++;
1171 |
1172 | return count;
1173 | },
1174 |
1175 | calculateSplices: function(current, previous) {
1176 | return this.calcSplices(current, 0, current.length, previous, 0,
1177 | previous.length);
1178 | },
1179 |
1180 | equals: function(currentValue, previousValue) {
1181 | return currentValue === previousValue;
1182 | }
1183 | };
1184 |
1185 | var arraySplice = new ArraySplice();
1186 |
1187 | function calcSplices(current, currentStart, currentEnd,
1188 | old, oldStart, oldEnd) {
1189 | return arraySplice.calcSplices(current, currentStart, currentEnd,
1190 | old, oldStart, oldEnd);
1191 | }
1192 |
1193 | function intersect(start1, end1, start2, end2) {
1194 | // Disjoint
1195 | if (end1 < start2 || end2 < start1)
1196 | return -1;
1197 |
1198 | // Adjacent
1199 | if (end1 == start2 || end2 == start1)
1200 | return 0;
1201 |
1202 | // Non-zero intersect, span1 first
1203 | if (start1 < start2) {
1204 | if (end1 < end2)
1205 | return end1 - start2; // Overlap
1206 | else
1207 | return end2 - start2; // Contained
1208 | } else {
1209 | // Non-zero intersect, span2 first
1210 | if (end2 < end1)
1211 | return end2 - start1; // Overlap
1212 | else
1213 | return end1 - start1; // Contained
1214 | }
1215 | }
1216 |
1217 | function mergeSplice(splices, index, removed, addedCount) {
1218 |
1219 | var splice = newSplice(index, removed, addedCount);
1220 |
1221 | var inserted = false;
1222 | var insertionOffset = 0;
1223 |
1224 | for (var i = 0; i < splices.length; i++) {
1225 | var current = splices[i];
1226 | current.index += insertionOffset;
1227 |
1228 | if (inserted)
1229 | continue;
1230 |
1231 | var intersectCount = intersect(splice.index,
1232 | splice.index + splice.removed.length,
1233 | current.index,
1234 | current.index + current.addedCount);
1235 |
1236 | if (intersectCount >= 0) {
1237 | // Merge the two splices
1238 |
1239 | splices.splice(i, 1);
1240 | i--;
1241 |
1242 | insertionOffset -= current.addedCount - current.removed.length;
1243 |
1244 | splice.addedCount += current.addedCount - intersectCount;
1245 | var deleteCount = splice.removed.length +
1246 | current.removed.length - intersectCount;
1247 |
1248 | if (!splice.addedCount && !deleteCount) {
1249 | // merged splice is a noop. discard.
1250 | inserted = true;
1251 | } else {
1252 | var removed = current.removed;
1253 |
1254 | if (splice.index < current.index) {
1255 | // some prefix of splice.removed is prepended to current.removed.
1256 | var prepend = splice.removed.slice(0, current.index - splice.index);
1257 | Array.prototype.push.apply(prepend, removed);
1258 | removed = prepend;
1259 | }
1260 |
1261 | if (splice.index + splice.removed.length > current.index + current.addedCount) {
1262 | // some suffix of splice.removed is appended to current.removed.
1263 | var append = splice.removed.slice(current.index + current.addedCount - splice.index);
1264 | Array.prototype.push.apply(removed, append);
1265 | }
1266 |
1267 | splice.removed = removed;
1268 | if (current.index < splice.index) {
1269 | splice.index = current.index;
1270 | }
1271 | }
1272 | } else if (splice.index < current.index) {
1273 | // Insert splice here.
1274 |
1275 | inserted = true;
1276 |
1277 | splices.splice(i, 0, splice);
1278 | i++;
1279 |
1280 | var offset = splice.addedCount - splice.removed.length
1281 | current.index += offset;
1282 | insertionOffset += offset;
1283 | }
1284 | }
1285 |
1286 | if (!inserted)
1287 | splices.push(splice);
1288 | }
1289 |
1290 | function createInitialSplices(array, changeRecords) {
1291 | var splices = [];
1292 |
1293 | for (var i = 0; i < changeRecords.length; i++) {
1294 | var record = changeRecords[i];
1295 | switch(record.type) {
1296 | case 'splice':
1297 | mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
1298 | break;
1299 | case 'new':
1300 | case 'updated':
1301 | case 'deleted':
1302 | if (!isIndex(record.name))
1303 | continue;
1304 | var index = toNumber(record.name);
1305 | if (index < 0)
1306 | continue;
1307 | mergeSplice(splices, index, [record.oldValue], 1);
1308 | break;
1309 | default:
1310 | console.error('Unexpected record type: ' + JSON.stringify(record));
1311 | break;
1312 | }
1313 | }
1314 |
1315 | return splices;
1316 | }
1317 |
1318 | function projectArraySplices(array, changeRecords) {
1319 | var splices = [];
1320 |
1321 | createInitialSplices(array, changeRecords).forEach(function(splice) {
1322 | if (splice.addedCount == 1 && splice.removed.length == 1) {
1323 | if (splice.removed[0] !== array[splice.index])
1324 | splices.push(splice);
1325 |
1326 | return
1327 | };
1328 |
1329 | splices = splices.concat(calcSplices(array, splice.index, splice.index + splice.addedCount,
1330 | splice.removed, 0, splice.removed.length));
1331 | });
1332 |
1333 | return splices;
1334 | }
1335 |
1336 | global.Observer = Observer;
1337 | global.Observer.hasObjectObserve = hasObserve;
1338 | global.ArrayObserver = ArrayObserver;
1339 | global.ArrayObserver.calculateSplices = function(current, previous) {
1340 | return arraySplice.calculateSplices(current, previous);
1341 | };
1342 |
1343 | global.ArraySplice = ArraySplice;
1344 | global.ObjectObserver = ObjectObserver;
1345 | global.PathObserver = PathObserver;
1346 | global.CompoundPathObserver = CompoundPathObserver;
1347 | global.Path = Path;
1348 | })(typeof global !== 'undefined' && global ? global : this);
--------------------------------------------------------------------------------
/bower_components/gss/dist/gss/vendor/sidetable.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 The Polymer Authors. All rights reserved.
3 | * Use of this source code is goverened by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | // SideTable is a weak map where possible. If WeakMap is not available the
8 | // association is stored as an expando property.
9 | var SideTable;
10 | // TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox
11 | if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) {
12 | SideTable = WeakMap;
13 | } else {
14 | (function() {
15 | var defineProperty = Object.defineProperty;
16 | var hasOwnProperty = Object.hasOwnProperty;
17 | var counter = new Date().getTime() % 1e9;
18 |
19 | SideTable = function() {
20 | this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
21 | };
22 |
23 | SideTable.prototype = {
24 | set: function(key, value) {
25 | defineProperty(key, this.name, {value: value, writable: true});
26 | },
27 | get: function(key) {
28 | return hasOwnProperty.call(key, this.name) ? key[this.name] : undefined;
29 | },
30 | delete: function(key) {
31 | this.set(key, undefined);
32 | }
33 | }
34 | })();
35 | }
--------------------------------------------------------------------------------
/bower_components/gss/dist/slightlyoff-cassowary.js/bin/c.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Parts Copyright (C) 2011-2012, Alex Russell (slightlyoff@chromium.org)
3 | * Parts Copyright (C) Copyright (C) 1998-2000 Greg J. Badros
4 | *
5 | * Use of this source code is governed by http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * This is a compiled version of Cassowary/JS. For source versions or to
8 | * contribute, see the github project:
9 | *
10 | * https://github.com/slightlyoff/cassowary-js-refactor
11 | *
12 | */
13 |
14 | (function() {
15 | !function(a){"use strict";try{!function(){}.bind(a)}catch(b){Object.defineProperty(Function.prototype,"bind",{value:function(a){var b=this;return function(){return b.apply(a,arguments)}},enumerable:!1,configurable:!0,writable:!0})}var c="undefined"!=typeof a.HTMLElement,d=function(a){for(var b=null;a&&a!=Object.prototype;){if(a.tagName){b=a.tagName;break}a=a.prototype}return b||"div"},e=1e-8,f={},g=function(a,b){if(a&&b){if("function"==typeof a[b])return a[b];var c=a.prototype;if(c&&"function"==typeof c[b])return c[b];if(c!==Object.prototype&&c!==Function.prototype)return"function"==typeof a.__super__?g(a.__super__,b):void 0}},h=a.c=function(){return h._api?h._api.apply(this,arguments):void 0};h.debug=!1,h.trace=!1,h.verbose=!1,h.traceAdded=!1,h.GC=!1,h.GEQ=1,h.LEQ=2,h.inherit=function(b){var e=null,g=null;b["extends"]&&(g=b["extends"],delete b["extends"]),b.initialize&&(e=b.initialize,delete b.initialize);var i=e||function(){};Object.defineProperty(i,"__super__",{value:g?g:Object,enumerable:!1,configurable:!0,writable:!1}),b._t&&(f[b._t]=i);var j=i.prototype=Object.create(g?g.prototype:Object.prototype);if(h.extend(j,b),c&&g&&g.prototype instanceof a.HTMLElement){var k=i,l=d(j),m=function(a){return a.__proto__=j,k.apply(a,arguments),j.created&&a.created(),j.decorate&&a.decorate(),a};this.extend(j,{upgrade:m}),i=function(){return m(a.document.createElement(l))},i.prototype=j,this.extend(i,{ctor:k})}return i},h.own=function(b,c,d){return Object.getOwnPropertyNames(b).forEach(c,d||a),b},h.extend=function(a,b){return h.own(b,function(c){var d=Object.getOwnPropertyDescriptor(b,c);try{"function"==typeof d.get||"function"==typeof d.set?Object.defineProperty(a,c,d):"function"==typeof d.value||"_"===c.charAt(0)?(d.writable=!0,d.configurable=!0,d.enumerable=!1,Object.defineProperty(a,c,d)):a[c]=b[c]}catch(e){}}),a},h.traceprint=function(a){h.verbose&&console.log(a)},h.fnenterprint=function(a){console.log("* "+a)},h.fnexitprint=function(a){console.log("- "+a)},h.assert=function(a,b){if(!a)throw new h.InternalError("Assertion failed: "+b)};var i=function(a){return"number"==typeof a?h.Expression.fromConstant(a):a instanceof h.Variable?h.Expression.fromVariable(a):a};h.plus=function(a,b){return a=i(a),b=i(b),a.plus(b)},h.minus=function(a,b){return a=i(a),b=i(b),a.minus(b)},h.times=function(a,b){return a=i(a),b=i(b),a.times(b)},h.divide=function(a,b){return a=i(a),b=i(b),a.divide(b)},h.approx=function(a,b){return a===b?!0:(a=+a,b=+b,0==a?Math.abs(b)30||this._deleted>this._compactThreshold&&(this._compact(),this._deleted=0)},"delete":function(a){a=a.hashCode,this._store.hasOwnProperty(a)&&(this._deleted++,delete this._store[a],this.size>0&&this.size--)},each:function(a,b){if(this.size){this._perhapsCompact();var c=this._store,d=this._keyStrMap;for(var e in this._store)this._store.hasOwnProperty(e)&&a.call(b||null,d[e],c[e])}},escapingEach:function(a,b){if(this.size){this._perhapsCompact();for(var c=this,e=this._store,f=this._keyStrMap,g=d,h=Object.keys(e),i=0;i "+c+"\n"}),b}})}(this.c||module.parent.exports||{}),function(a){"use strict";a.HashSet=a.inherit({_t:"c.HashSet",initialize:function(){this.storage=[],this.size=0,this.hashCode=a._inc()},add:function(a){var b=this.storage;b.indexOf(a),-1==b.indexOf(a)&&(b[b.length]=a),this.size=this.storage.length},values:function(){return this.storage},has:function(a){var b=this.storage;return-1!=b.indexOf(a)},"delete":function(a){var b=this.storage.indexOf(a);return-1==b?null:(this.storage.splice(b,1)[0],this.size=this.storage.length,void 0)},clear:function(){this.storage.length=0},each:function(a,b){this.size&&this.storage.forEach(a,b)},escapingEach:function(a,b){this.size&&this.storage.forEach(a,b)},toString:function(){var a=this.size+" {",b=!0;return this.each(function(c){b?b=!1:a+=", ",a+=c}),a+="}\n"},toJSON:function(){var a=[];return this.each(function(b){a[a.length]=b.toJSON()}),{_t:"c.HashSet",data:a}},fromJSON:function(b){var c=new a.HashSet;return b.data&&(c.size=b.data.length,c.storage=b.data),c}})}(this.c||module.parent.exports||{}),function(a){"use strict";a.Error=a.inherit({initialize:function(a){a&&(this._description=a)},_name:"c.Error",_description:"An error has occured in Cassowary",set description(a){this._description=a},get description(){return"("+this._name+") "+this._description},get message(){return this.description},toString:function(){return this.description}});var b=function(b,c){return a.inherit({"extends":a.Error,initialize:function(){a.Error.apply(this,arguments)},_name:b||"",_description:c||""})};a.ConstraintNotFound=b("c.ConstraintNotFound","Tried to remove a constraint never added to the tableu"),a.InternalError=b("c.InternalError"),a.NonExpression=b("c.NonExpression","The resulting expression would be non"),a.NotEnoughStays=b("c.NotEnoughStays","There are not enough stays to give specific values to every variable"),a.RequiredFailure=b("c.RequiredFailure","A required constraint cannot be satisfied"),a.TooDifficult=b("c.TooDifficult","The constraints are too difficult to solve")}(this.c||module.parent.exports||{}),function(a){"use strict";var b=1e3;a.SymbolicWeight=a.inherit({_t:"c.SymbolicWeight",initialize:function(){this.value=0;for(var a=1,c=arguments.length-1;c>=0;--c)this.value+=arguments[c]*a,a*=b},toJSON:function(){return{_t:this._t,value:this.value}}})}(this.c||module.parent.exports||{}),function(a){a.Strength=a.inherit({initialize:function(b,c,d,e){this.name=b,this.symbolicWeight=c instanceof a.SymbolicWeight?c:new a.SymbolicWeight(c,d,e)},get required(){return this===a.Strength.required},toString:function(){return this.name+(this.isRequired?"":":"+this.symbolicWeight)}}),a.Strength.required=new a.Strength("",1e3,1e3,1e3),a.Strength.strong=new a.Strength("strong",1,0,0),a.Strength.medium=new a.Strength("medium",0,1,0),a.Strength.weak=new a.Strength("weak",0,0,1)}(this.c||("undefined"!=typeof module?module.parent.exports.c:{})),function(a){"use strict";a.AbstractVariable=a.inherit({isDummy:!1,isExternal:!1,isPivotable:!1,isRestricted:!1,_init:function(b,c){this.hashCode=a._inc(),this.name=(c||"")+this.hashCode,b&&("undefined"!=typeof b.name&&(this.name=b.name),"undefined"!=typeof b.value&&(this.value=b.value),"undefined"!=typeof b.prefix&&(this._prefix=b.prefix))},_prefix:"",name:"",value:0,valueOf:function(){return this.value},toJSON:function(){var a={};return this._t&&(a._t=this._t),this.name&&(a.name=this.name),"undefined"!=typeof this.value&&(a.value=this.value),this._prefix&&(a._prefix=this._prefix),this._t&&(a._t=this._t),a},fromJSON:function(b,c){var d=new c;return a.extend(d,b),d},toString:function(){return this._prefix+"["+this.name+":"+this.value+"]"}}),a.Variable=a.inherit({_t:"c.Variable","extends":a.AbstractVariable,initialize:function(b){this._init(b,"v");var c=a.Variable._map;c&&(c[this.name]=this)},isExternal:!0}),a.DummyVariable=a.inherit({_t:"c.DummyVariable","extends":a.AbstractVariable,initialize:function(a){this._init(a,"d")},isDummy:!0,isRestricted:!0,value:"dummy"}),a.ObjectiveVariable=a.inherit({_t:"c.ObjectiveVariable","extends":a.AbstractVariable,initialize:function(a){this._init(a,"o")},value:"obj"}),a.SlackVariable=a.inherit({_t:"c.SlackVariable","extends":a.AbstractVariable,initialize:function(a){this._init(a,"s")},isPivotable:!0,isRestricted:!0,value:"slack"})}(this.c||module.parent.exports||{}),function(a){"use strict";a.Point=a.inherit({initialize:function(b,c,d){if(b instanceof a.Variable)this._x=b;else{var e={value:b};d&&(e.name="x"+d),this._x=new a.Variable(e)}if(c instanceof a.Variable)this._y=c;else{var f={value:c};d&&(f.name="y"+d),this._y=new a.Variable(f)}},get x(){return this._x},set x(b){b instanceof a.Variable?this._x=b:this._x.value=b},get y(){return this._y},set y(b){b instanceof a.Variable?this._y=b:this._y.value=b},toString:function(){return"("+this.x+", "+this.y+")"}})}(this.c||module.parent.exports||{}),function(a){"use strict";var b=function(a,b){return"number"==typeof a?a:b};a.Expression=a.inherit({initialize:function(c,d,e){this.constant=b(e,0),this.terms=new a.HashTable,c instanceof a.AbstractVariable?(d=b(d,1),this.setVariable(c,d)):"number"==typeof c&&(isNaN(c)?console.trace():this.constant=c)},initializeFromHash:function(b,c){return a.verbose&&(console.log("*******************************"),console.log("clone c.initializeFromHash"),console.log("*******************************")),a.GC&&console.log("clone c.Expression"),this.constant=b,this.terms=c.clone(),this},multiplyMe:function(a){this.constant*=a;var b=this.terms;return b.each(function(c,d){b.set(c,d*a)}),this},clone:function(){a.verbose&&(console.log("*******************************"),console.log("clone c.Expression"),console.log("*******************************"));var b=a.Expression.empty();return b.initializeFromHash(this.constant,this.terms),b},times:function(b){if("number"==typeof b)return this.clone().multiplyMe(b);if(this.isConstant)return b.times(this.constant);if(b.isConstant)return this.times(b.constant);throw new a.NonExpression},plus:function(b){return b instanceof a.Expression?this.clone().addExpression(b,1):b instanceof a.Variable?this.clone().addVariable(b,1):void 0},minus:function(b){return b instanceof a.Expression?this.clone().addExpression(b,-1):b instanceof a.Variable?this.clone().addVariable(b,-1):void 0},divide:function(b){if("number"==typeof b){if(a.approx(b,0))throw new a.NonExpression;return this.times(1/b)}if(b instanceof a.Expression){if(!b.isConstant)throw new a.NonExpression;return this.times(1/b.constant)}},addExpression:function(c,d,e,f){return c instanceof a.AbstractVariable&&(c=a.Expression.fromVariable(c)),d=b(d,1),this.constant+=d*c.constant,c.terms.each(function(a,b){this.addVariable(a,b*d,e,f)},this),this},addVariable:function(b,c,d,e){null==c&&(c=1),a.trace&&console.log("c.Expression::addVariable():",b,c);var f=this.terms.get(b);if(f){var g=f+c;0==g||a.approx(g,0)?(e&&e.noteRemovedVariable(b,d),this.terms.delete(b)):this.setVariable(b,g)}else a.approx(c,0)||(this.setVariable(b,c),e&&e.noteAddedVariable(b,d));return this},setVariable:function(a,b){return this.terms.set(a,b),this},anyPivotableVariable:function(){if(this.isConstant)throw new a.InternalError("anyPivotableVariable called on a constant");var b=this.terms.escapingEach(function(a){return a.isPivotable?{retval:a}:void 0});return b&&void 0!==b.retval?b.retval:null},substituteOut:function(b,c,d,e){a.trace&&(a.fnenterprint("CLE:substituteOut: "+b+", "+c+", "+d+", ..."),a.traceprint("this = "+this)),this.setVariable.bind(this);var g=this.terms,h=g.get(b);g.delete(b),this.constant+=h*c.constant,c.terms.each(function(b,c){var f=g.get(b);if(f){var i=f+h*c;a.approx(i,0)?(e.noteRemovedVariable(b,d),g.delete(b)):g.set(b,i)}else g.set(b,h*c),e&&e.noteAddedVariable(b,d)}),a.trace&&a.traceprint("Now this is "+this)},changeSubject:function(a,b){this.setVariable(a,this.newSubject(b))},newSubject:function(b){a.trace&&a.fnenterprint("newSubject:"+b);var c=1/this.terms.get(b);return this.terms.delete(b),this.multiplyMe(-c),c},coefficientFor:function(a){return this.terms.get(a)||0},get isConstant(){return 0==this.terms.size},toString:function(){var b="",c=!1;if(!a.approx(this.constant,0)||this.isConstant){if(b+=this.constant,this.isConstant)return b;c=!0}return this.terms.each(function(a,d){c&&(b+=" + "),b+=d+"*"+a,c=!0}),b},equals:function(b){return b===this?!0:b instanceof a.Expression&&b.constant===this.constant&&b.terms.equals(this.terms)},Plus:function(a,b){return a.plus(b)},Minus:function(a,b){return a.minus(b)},Times:function(a,b){return a.times(b)},Divide:function(a,b){return a.divide(b)}}),a.Expression.empty=function(){return new a.Expression(void 0,1,0)},a.Expression.fromConstant=function(b){return new a.Expression(b)},a.Expression.fromValue=function(b){return b=+b,new a.Expression(void 0,b,0)},a.Expression.fromVariable=function(b){return new a.Expression(b,1,0)}}(this.c||module.parent.exports||{}),function(a){"use strict";a.AbstractConstraint=a.inherit({initialize:function(b,c){this.hashCode=a._inc(),this.strength=b||a.Strength.required,this.weight=c||1},isEditConstraint:!1,isInequality:!1,isStayConstraint:!1,get required(){return this.strength===a.Strength.required},toString:function(){return this.strength+" {"+this.weight+"} ("+this.expression+")"}});var b=a.AbstractConstraint.prototype.toString,c=function(b,c,d){a.AbstractConstraint.call(this,c||a.Strength.strong,d),this.variable=b,this.expression=new a.Expression(b,-1,b.value)};a.EditConstraint=a.inherit({"extends":a.AbstractConstraint,initialize:function(){c.apply(this,arguments)},isEditConstraint:!0,toString:function(){return"edit:"+b.call(this)}}),a.StayConstraint=a.inherit({"extends":a.AbstractConstraint,initialize:function(){c.apply(this,arguments)},isStayConstraint:!0,toString:function(){return"stay:"+b.call(this)}});var d=a.Constraint=a.inherit({"extends":a.AbstractConstraint,initialize:function(b,c,d){a.AbstractConstraint.call(this,c,d),this.expression=b}});a.Inequality=a.inherit({"extends":a.Constraint,_cloneOrNewCle:function(b){return b.clone?b.clone():new a.Expression(b)},initialize:function(b,c,e,f,g){var h=b instanceof a.Expression,i=e instanceof a.Expression,j=b instanceof a.AbstractVariable,k=e instanceof a.AbstractVariable,l="number"==typeof b,m="number"==typeof e;if((h||l)&&k){var n=b,o=c,p=e,q=f,r=g;if(d.call(this,this._cloneOrNewCle(n),q,r),o==a.LEQ)this.expression.multiplyMe(-1),this.expression.addVariable(p);else{if(o!=a.GEQ)throw new a.InternalError("Invalid operator in c.Inequality constructor");this.expression.addVariable(p,-1)}}else if(j&&(i||m)){var n=e,o=c,p=b,q=f,r=g;if(d.call(this,this._cloneOrNewCle(n),q,r),o==a.GEQ)this.expression.multiplyMe(-1),this.expression.addVariable(p);else{if(o!=a.LEQ)throw new a.InternalError("Invalid operator in c.Inequality constructor");this.expression.addVariable(p,-1)}}else{if(h&&m){var s=b,o=c,t=e,q=f,r=g;if(d.call(this,this._cloneOrNewCle(s),q,r),o==a.LEQ)this.expression.multiplyMe(-1),this.expression.addExpression(this._cloneOrNewCle(t));else{if(o!=a.GEQ)throw new a.InternalError("Invalid operator in c.Inequality constructor");this.expression.addExpression(this._cloneOrNewCle(t),-1)}return this}if(l&&i){var s=e,o=c,t=b,q=f,r=g;if(d.call(this,this._cloneOrNewCle(s),q,r),o==a.GEQ)this.expression.multiplyMe(-1),this.expression.addExpression(this._cloneOrNewCle(t));else{if(o!=a.LEQ)throw new a.InternalError("Invalid operator in c.Inequality constructor");this.expression.addExpression(this._cloneOrNewCle(t),-1)}return this}if(h&&i){var s=b,o=c,t=e,q=f,r=g;if(d.call(this,this._cloneOrNewCle(t),q,r),o==a.GEQ)this.expression.multiplyMe(-1),this.expression.addExpression(this._cloneOrNewCle(s));else{if(o!=a.LEQ)throw new a.InternalError("Invalid operator in c.Inequality constructor");this.expression.addExpression(this._cloneOrNewCle(s),-1)}}else{if(h)return d.call(this,b,c,e);if(c==a.GEQ)d.call(this,new a.Expression(e),f,g),this.expression.multiplyMe(-1),this.expression.addVariable(b);else{if(c!=a.LEQ)throw new a.InternalError("Invalid operator in c.Inequality constructor");d.call(this,new a.Expression(e),f,g),this.expression.addVariable(b,-1)}}}},isInequality:!0,toString:function(){return d.prototype.toString.call(this)+" >= 0) id: "+this.hashCode}}),a.Equation=a.inherit({"extends":a.Constraint,initialize:function(b,c,e,f){if(b instanceof a.Expression&&!c||c instanceof a.Strength)d.call(this,b,c,e);else if(b instanceof a.AbstractVariable&&c instanceof a.Expression){var g=b,h=c,i=e,j=f;d.call(this,h.clone(),i,j),this.expression.addVariable(g,-1)}else if(b instanceof a.AbstractVariable&&"number"==typeof c){var g=b,k=c,i=e,j=f;d.call(this,new a.Expression(k),i,j),this.expression.addVariable(g,-1)}else if(b instanceof a.Expression&&c instanceof a.AbstractVariable){var h=b,g=c,i=e,j=f;d.call(this,h.clone(),i,j),this.expression.addVariable(g,-1)}else{if(!(b instanceof a.Expression||b instanceof a.AbstractVariable||"number"==typeof b)||!(c instanceof a.Expression||c instanceof a.AbstractVariable||"number"==typeof c))throw"Bad initializer to c.Equation";b=b instanceof a.Expression?b.clone():new a.Expression(b),c=c instanceof a.Expression?c.clone():new a.Expression(c),d.call(this,b,e,f),this.expression.addExpression(c,-1)}a.assert(this.strength instanceof a.Strength,"_strength not set")},toString:function(){return d.prototype.toString.call(this)+" = 0)"}})}(this.c||module.parent.exports||{}),function(a){"use strict";a.EditInfo=a.inherit({initialize:function(a,b,c,d,e){this.constraint=a,this.editPlus=b,this.editMinus=c,this.prevEditConstant=d,this.index=e},toString:function(){return""}})}(this.c||module.parent.exports||{}),function(a){"use strict";a.Tableau=a.inherit({initialize:function(){this.columns=new a.HashTable,this.rows=new a.HashTable,this._infeasibleRows=new a.HashSet,this._externalRows=new a.HashSet,this._externalParametricVars=new a.HashSet},noteRemovedVariable:function(b,c){a.trace&&console.log("c.Tableau::noteRemovedVariable: ",b,c);var d=this.columns.get(b);c&&d&&d.delete(c)},noteAddedVariable:function(a,b){b&&this.insertColVar(a,b)},getInternalInfo:function(){var a="Tableau Information:\n";return a+="Rows: "+this.rows.size,a+=" (= "+(this.rows.size-1)+" constraints)",a+="\nColumns: "+this.columns.size,a+="\nInfeasible Rows: "+this._infeasibleRows.size,a+="\nExternal basic variables: "+this._externalRows.size,a+="\nExternal parametric variables: ",a+=this._externalParametricVars.size,a+="\n"},toString:function(){var a="Tableau:\n";return this.rows.each(function(b,c){a+=b,a+=" <==> ",a+=c,a+="\n"}),a+="\nColumns:\n",a+=this.columns,a+="\nInfeasible rows: ",a+=this._infeasibleRows,a+="External basic variables: ",a+=this._externalRows,a+="External parametric variables: ",a+=this._externalParametricVars},insertColVar:function(b,c){var d=this.columns.get(b);d||(d=new a.HashSet,this.columns.set(b,d)),d.add(c)},addRow:function(b,c){a.trace&&a.fnenterprint("addRow: "+b+", "+c),this.rows.set(b,c),c.terms.each(function(a){this.insertColVar(a,b),a.isExternal&&this._externalParametricVars.add(a)},this),b.isExternal&&this._externalRows.add(b),a.trace&&a.traceprint(this.toString())},removeColumn:function(b){a.trace&&a.fnenterprint("removeColumn:"+b);var c=this.columns.get(b);c?(this.columns.delete(b),c.each(function(a){var c=this.rows.get(a);c.terms.delete(b)},this)):a.trace&&console.log("Could not find var",b,"in columns"),b.isExternal&&(this._externalRows.delete(b),this._externalParametricVars.delete(b))},removeRow:function(b){a.trace&&a.fnenterprint("removeRow:"+b);var c=this.rows.get(b);return a.assert(null!=c),c.terms.each(function(c){var e=this.columns.get(c);null!=e&&(a.trace&&console.log("removing from varset:",b),e.delete(b))},this),this._infeasibleRows.delete(b),b.isExternal&&this._externalRows.delete(b),this.rows.delete(b),a.trace&&a.fnexitprint("returning "+c),c},substituteOut:function(b,c){a.trace&&a.fnenterprint("substituteOut:"+b+", "+c),a.trace&&a.traceprint(this.toString());var d=this.columns.get(b);d.each(function(a){var d=this.rows.get(a);d.substituteOut(b,c,a,this),a.isRestricted&&d.constant<0&&this._infeasibleRows.add(a)},this),b.isExternal&&(this._externalRows.add(b),this._externalParametricVars.delete(b)),this.columns.delete(b)},columnsHasKey:function(a){return!!this.columns.get(a)}})}(this.c||module.parent.exports||{}),function(a){var b=a.Tableau,c=b.prototype,d=1e-8,e=a.Strength.weak;a.SimplexSolver=a.inherit({"extends":a.Tableau,initialize:function(){a.Tableau.call(this),this._stayMinusErrorVars=[],this._stayPlusErrorVars=[],this._errorVars=new a.HashTable,this._markerVars=new a.HashTable,this._objective=new a.ObjectiveVariable({name:"Z"}),this._editVarMap=new a.HashTable,this._editVarList=[],this._slackCounter=0,this._artificialCounter=0,this._dummyCounter=0,this.autoSolve=!0,this._needsSolving=!1,this._optimizeCount=0,this.rows.set(this._objective,a.Expression.empty()),this._editVariableStack=[0],a.trace&&a.traceprint("objective expr == "+this.rows.get(this._objective))},add:function(){for(var a=0;a0,"_editVarMap.size > 0"),this._infeasibleRows.clear(),this._resetStayConstants(),this._editVariableStack[this._editVariableStack.length]=this._editVarMap.size,this},endEdit:function(){return a.assert(this._editVarMap.size>0,"_editVarMap.size > 0"),this.resolve(),this._editVariableStack.pop(),this.removeEditVarsTo(this._editVariableStack[this._editVariableStack.length-1]),this},removeAllEditVars:function(){return this.removeEditVarsTo(0)},removeEditVarsTo:function(b){try{for(var c=this._editVarList.length,d=b;c>d;d++)this._editVarList[d]&&this.removeConstraint(this._editVarMap.get(this._editVarList[d].v).constraint);return this._editVarList.length=b,a.assert(this._editVarMap.size==b,"_editVarMap.size == n"),this}catch(e){throw new a.InternalError("Constraint not found in removeEditVarsTo")}},addPointStays:function(b){return a.trace&&console.log("addPointStays",b),b.forEach(function(a,b){this.addStay(a.x,e,Math.pow(2,b)),this.addStay(a.y,e,Math.pow(2,b))},this),this},addStay:function(b,c,d){var f=new a.StayConstraint(b,c||e,d||1);return this.addConstraint(f)},removeConstraint:function(b){a.trace&&a.fnenterprint("removeConstraintInternal: "+b),a.trace&&a.traceprint(this.toString()),this._needsSolving=!0,this._resetStayConstants();var c=this.rows.get(this._objective),d=this._errorVars.get(b);a.trace&&a.traceprint("eVars == "+d),null!=d&&d.each(function(e){var f=this.rows.get(e);null==f?c.addVariable(e,-b.weight*b.strength.symbolicWeight.value,this._objective,this):c.addExpression(f,-b.weight*b.strength.symbolicWeight.value,this._objective,this),a.trace&&a.traceprint("now eVars == "+d)},this);var e=this._markerVars.get(b);if(this._markerVars.delete(b),null==e)throw new a.InternalError("Constraint not found in removeConstraintInternal");if(a.trace&&a.traceprint("Looking to remove var "+e),null==this.rows.get(e)){var f=this.columns.get(e);a.trace&&a.traceprint("Must pivot -- columns are "+f);var g=null,h=0;f.each(function(b){if(b.isRestricted){var c=this.rows.get(b),d=c.coefficientFor(e);if(a.trace&&a.traceprint("Marker "+e+"'s coefficient in "+c+" is "+d),0>d){var f=-c.constant/d;(null==g||h>f||a.approx(f,h)&&b.hashCoded)&&(h=d,g=a)}},this)),null==g&&(0==f.size?this.removeColumn(e):f.escapingEach(function(a){return a!=this._objective?(g=a,{brk:!0}):void 0},this)),null!=g&&this.pivot(e,g)}if(null!=this.rows.get(e)&&this.removeRow(e),null!=d&&d.each(function(a){a!=e&&this.removeColumn(a)},this),b.isStayConstraint){if(null!=d)for(var j=0;je&&this.suggestValue(a,b[e])},this),this.resolve()},resolvePair:function(a,b){this.suggestValue(this._editVarList[0].v,a),this.suggestValue(this._editVarList[1].v,b),this.resolve()},resolve:function(){a.trace&&a.fnenterprint("resolve()"),this.dualOptimize(),this._setExternalVariables(),this._infeasibleRows.clear(),this._resetStayConstants()},suggestValue:function(b,c){a.trace&&console.log("suggestValue("+b+", "+c+")");var d=this._editVarMap.get(b);if(!d)throw new a.Error("suggestValue for variable "+b+", but var is not an edit variable");var e=c-d.prevEditConstant;return d.prevEditConstant=c,this.deltaEditConstant(e,d.editPlus,d.editMinus),this},solve:function(){return this._needsSolving&&(this.optimize(this._objective),this._setExternalVariables()),this},setEditedValue:function(b,c){if(!this.columnsHasKey(b)&&null==this.rows.get(b))return b.value=c,this;if(!a.approx(c,b.value)){this.addEditVar(b),this.beginEdit();try{this.suggestValue(b,c)}catch(d){throw new a.InternalError("Error in setEditedValue")}this.endEdit()}return this},addVar:function(b){if(!this.columnsHasKey(b)&&null==this.rows.get(b)){try{this.addStay(b)}catch(c){throw new a.InternalError("Error in addVar -- required failure is impossible")}a.trace&&a.traceprint("added initial stay on "+b)}return this},getInternalInfo:function(){var a=c.getInternalInfo.call(this);return a+="\nSolver info:\n",a+="Stay Error Variables: ",a+=this._stayPlusErrorVars.length+this._stayMinusErrorVars.length,a+=" ("+this._stayPlusErrorVars.length+" +, ",a+=this._stayMinusErrorVars.length+" -)\n",a+="Edit Variables: "+this._editVarMap.size,a+="\n"},getDebugInfo:function(){return this.toString()+this.getInternalInfo()+"\n"},toString:function(){var a=c.getInternalInfo.call(this);return a+="\n_stayPlusErrorVars: ",a+="["+this._stayPlusErrorVars+"]",a+="\n_stayMinusErrorVars: ",a+="["+this._stayMinusErrorVars+"]",a+="\n",a+="_editVarMap:\n"+this._editVarMap,a+="\n"},addWithArtificialVariable:function(b){a.trace&&a.fnenterprint("addWithArtificialVariable: "+b);var c=new a.SlackVariable({value:++this._artificialCounter,prefix:"a"}),d=new a.ObjectiveVariable({name:"az"}),e=b.clone();a.trace&&a.traceprint("before addRows:\n"+this),this.addRow(d,e),this.addRow(c,b),a.trace&&a.traceprint("after addRows:\n"+this),this.optimize(d);var f=this.rows.get(d);if(a.trace&&a.traceprint("azTableauRow.constant == "+f.constant),!a.approx(f.constant,0))throw this.removeRow(d),this.removeColumn(c),new a.RequiredFailure;var g=this.rows.get(c);if(null!=g){if(g.isConstant)return this.removeRow(c),this.removeRow(d),void 0;var h=g.anyPivotableVariable();this.pivot(h,c)}a.assert(null==this.rows.get(c),"rowExpression(av) == null"),this.removeColumn(c),this.removeRow(d)},tryAddingDirectly:function(b){a.trace&&a.fnenterprint("tryAddingDirectly: "+b);var c=this.chooseSubject(b);return null==c?(a.trace&&a.fnexitprint("returning false"),!1):(b.newSubject(c),this.columnsHasKey(c)&&this.substituteOut(c,b),this.addRow(c,b),a.trace&&a.fnexitprint("returning true"),!0)},chooseSubject:function(b){a.trace&&a.fnenterprint("chooseSubject: "+b);var c=null,d=!1,e=!1,f=b.terms,g=f.escapingEach(function(a,b){if(d){if(!a.isRestricted&&!this.columnsHasKey(a))return{retval:a}}else if(a.isRestricted){if(!e&&!a.isDummy&&0>b){var f=this.columns.get(a);(null==f||1==f.size&&this.columnsHasKey(this._objective))&&(c=a,e=!0)}}else c=a,d=!0},this);if(g&&void 0!==g.retval)return g.retval;if(null!=c)return c;var h=0,g=f.escapingEach(function(a,b){return a.isDummy?(this.columnsHasKey(a)||(c=a,h=b),void 0):{retval:null}},this);if(g&&void 0!==g.retval)return g.retval;if(!a.approx(b.constant,0))throw new a.RequiredFailure;return h>0&&b.multiplyMe(-1),c},deltaEditConstant:function(b,c,d){a.trace&&a.fnenterprint("deltaEditConstant :"+b+", "+c+", "+d);var e=this.rows.get(c);if(null!=e)return e.constant+=b,e.constant<0&&this._infeasibleRows.add(c),void 0;var f=this.rows.get(d);if(null!=f)return f.constant+=-b,f.constant<0&&this._infeasibleRows.add(d),void 0;var g=this.columns.get(d);g||console.log("columnVars is null -- tableau is:\n"+this),g.each(function(a){var c=this.rows.get(a),e=c.coefficientFor(d);c.constant+=e*b,a.isRestricted&&c.constant<0&&this._infeasibleRows.add(a)},this)},dualOptimize:function(){a.trace&&a.fnenterprint("dualOptimize:");for(var b=this.rows.get(this._objective);this._infeasibleRows.size;){var c=this._infeasibleRows.values()[0];this._infeasibleRows.delete(c);var d=null,e=this.rows.get(c);if(e&&e.constant<0){var g,f=Number.MAX_VALUE,h=e.terms;if(h.each(function(c,e){if(e>0&&c.isPivotable){var h=b.coefficientFor(c);g=h/e,(f>g||a.approx(g,f)&&c.hashCodeb?(g=b,e=a,{brk:1}):void 0},this),g>=-d)return;a.trace&&console.log("entryVar:",e,"objectiveCoeff:",g);var i=Number.MAX_VALUE,j=this.columns.get(e),k=0;if(j.each(function(b){if(a.trace&&a.traceprint("Checking "+b),b.isPivotable){var c=this.rows.get(b),d=c.coefficientFor(e);a.trace&&a.traceprint("pivotable, coeff = "+d),0>d&&(k=-c.constant/d,(i>k||a.approx(k,i)&&b.hashCoded;d++){var e=this.rows.get(b[d]);null===e&&(e=this.rows.get(this._stayMinusErrorVars[d])),null!=e&&(e.constant=0)}},_setExternalVariables:function(){a.trace&&a.fnenterprint("_setExternalVariables:"),a.trace&&a.traceprint(this.toString());var b={};this._externalParametricVars.each(function(c){null!=this.rows.get(c)?a.trace&&console.log("Error: variable"+c+" in _externalParametricVars is basic"):(c.value=0,b[c.name]=0)},this),this._externalRows.each(function(a){var c=this.rows.get(a);a.value!=c.constant&&(a.value=c.constant,b[a.name]=c.constant)},this),this._changed=b,this._needsSolving=!1,this._informCallbacks(),this.onsolved()},onsolved:function(){},_informCallbacks:function(){if(this._callbacks){var a=this._changed;this._callbacks.forEach(function(b){b(a)})}},_addCallback:function(a){var b=this._callbacks||(this._callbacks=[]);b[b.length]=a},insertErrorVar:function(b,c){a.trace&&a.fnenterprint("insertErrorVar:"+b+", "+c);var d=this._errorVars.get(c);d||(d=new a.HashSet,this._errorVars.set(b,d)),d.add(c)}})}(this.c||module.parent.exports||{}),function(a){"use strict";a.Timer=a.inherit({initialize:function(){this.isRunning=!1,this._elapsedMs=0},start:function(){return this.isRunning=!0,this._startReading=new Date,this},stop:function(){return this.isRunning=!1,this._elapsedMs+=new Date-this._startReading,this},reset:function(){return this.isRunning=!1,this._elapsedMs=0,this},elapsedTime:function(){return this.isRunning?(this._elapsedMs+(new Date-this._startReading))/1e3:this._elapsedMs/1e3}})}(this.c||module.parent.exports||{}),this.c.parser=function(){function a(a){return'"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g,escape)+'"'}var b={parse:function(b,c){function k(a){g>e||(e>g&&(g=e,h=[]),h.push(a))}function l(){var a,b,c,d,f;if(d=e,f=e,a=z(),null!==a){for(b=[],c=m();null!==c;)b.push(c),c=m();null!==b?(c=z(),null!==c?a=[a,b,c]:(a=null,e=f)):(a=null,e=f)}else a=null,e=f;return null!==a&&(a=function(a,b){return b}(d,a[1])),null===a&&(e=d),a}function m(){var a,b,c,d;return c=e,d=e,a=P(),null!==a?(b=s(),null!==b?a=[a,b]:(a=null,e=d)):(a=null,e=d),null!==a&&(a=function(a,b){return b}(c,a[0])),null===a&&(e=c),a}function n(){var a;return b.length>e?(a=b.charAt(e),e++):(a=null,0===f&&k("any character")),a}function o(){var a;return/^[a-zA-Z]/.test(b.charAt(e))?(a=b.charAt(e),e++):(a=null,0===f&&k("[a-zA-Z]")),null===a&&(36===b.charCodeAt(e)?(a="$",e++):(a=null,0===f&&k('"$"')),null===a&&(95===b.charCodeAt(e)?(a="_",e++):(a=null,0===f&&k('"_"')))),a}function p(){var a;return f++,/^[\t\x0B\f \xA0\uFEFF]/.test(b.charAt(e))?(a=b.charAt(e),e++):(a=null,0===f&&k("[\\t\\x0B\\f \\xA0\\uFEFF]")),f--,0===f&&null===a&&k("whitespace"),a}function q(){var a;return/^[\n\r\u2028\u2029]/.test(b.charAt(e))?(a=b.charAt(e),e++):(a=null,0===f&&k("[\\n\\r\\u2028\\u2029]")),a}function r(){var a;return f++,10===b.charCodeAt(e)?(a="\n",e++):(a=null,0===f&&k('"\\n"')),null===a&&("\r\n"===b.substr(e,2)?(a="\r\n",e+=2):(a=null,0===f&&k('"\\r\\n"')),null===a&&(13===b.charCodeAt(e)?(a="\r",e++):(a=null,0===f&&k('"\\r"')),null===a&&(8232===b.charCodeAt(e)?(a="\u2028",e++):(a=null,0===f&&k('"\\u2028"')),null===a&&(8233===b.charCodeAt(e)?(a="\u2029",e++):(a=null,0===f&&k('"\\u2029"')))))),f--,0===f&&null===a&&k("end of line"),a}function s(){var a,c,d;return d=e,a=z(),null!==a?(59===b.charCodeAt(e)?(c=";",e++):(c=null,0===f&&k('";"')),null!==c?a=[a,c]:(a=null,e=d)):(a=null,e=d),null===a&&(d=e,a=y(),null!==a?(c=r(),null!==c?a=[a,c]:(a=null,e=d)):(a=null,e=d),null===a&&(d=e,a=z(),null!==a?(c=t(),null!==c?a=[a,c]:(a=null,e=d)):(a=null,e=d))),a}function t(){var a,c;return c=e,f++,b.length>e?(a=b.charAt(e),e++):(a=null,0===f&&k("any character")),f--,null===a?a="":(a=null,e=c),a}function u(){var a;return f++,a=v(),null===a&&(a=x()),f--,0===f&&null===a&&k("comment"),a}function v(){var a,c,d,g,h,i,j;if(h=e,"/*"===b.substr(e,2)?(a="/*",e+=2):(a=null,0===f&&k('"/*"')),null!==a){for(c=[],i=e,j=e,f++,"*/"===b.substr(e,2)?(d="*/",e+=2):(d=null,0===f&&k('"*/"')),f--,null===d?d="":(d=null,e=j),null!==d?(g=n(),null!==g?d=[d,g]:(d=null,e=i)):(d=null,e=i);null!==d;)c.push(d),i=e,j=e,f++,"*/"===b.substr(e,2)?(d="*/",e+=2):(d=null,0===f&&k('"*/"')),f--,null===d?d="":(d=null,e=j),null!==d?(g=n(),null!==g?d=[d,g]:(d=null,e=i)):(d=null,e=i);null!==c?("*/"===b.substr(e,2)?(d="*/",e+=2):(d=null,0===f&&k('"*/"')),null!==d?a=[a,c,d]:(a=null,e=h)):(a=null,e=h)}else a=null,e=h;return a}function w(){var a,c,d,g,h,i,j;if(h=e,"/*"===b.substr(e,2)?(a="/*",e+=2):(a=null,0===f&&k('"/*"')),null!==a){for(c=[],i=e,j=e,f++,"*/"===b.substr(e,2)?(d="*/",e+=2):(d=null,0===f&&k('"*/"')),null===d&&(d=q()),f--,null===d?d="":(d=null,e=j),null!==d?(g=n(),null!==g?d=[d,g]:(d=null,e=i)):(d=null,e=i);null!==d;)c.push(d),i=e,j=e,f++,"*/"===b.substr(e,2)?(d="*/",e+=2):(d=null,0===f&&k('"*/"')),null===d&&(d=q()),f--,null===d?d="":(d=null,e=j),null!==d?(g=n(),null!==g?d=[d,g]:(d=null,e=i)):(d=null,e=i);null!==c?("*/"===b.substr(e,2)?(d="*/",e+=2):(d=null,0===f&&k('"*/"')),null!==d?a=[a,c,d]:(a=null,e=h)):(a=null,e=h)}else a=null,e=h;return a}function x(){var a,c,d,g,h,i,j;if(h=e,"//"===b.substr(e,2)?(a="//",e+=2):(a=null,0===f&&k('"//"')),null!==a){for(c=[],i=e,j=e,f++,d=q(),f--,null===d?d="":(d=null,e=j),null!==d?(g=n(),null!==g?d=[d,g]:(d=null,e=i)):(d=null,e=i);null!==d;)c.push(d),i=e,j=e,f++,d=q(),f--,null===d?d="":(d=null,e=j),null!==d?(g=n(),null!==g?d=[d,g]:(d=null,e=i)):(d=null,e=i);null!==c?(d=q(),null===d&&(d=t()),null!==d?a=[a,c,d]:(a=null,e=h)):(a=null,e=h)}else a=null,e=h;return a}function y(){var a,b;for(a=[],b=p(),null===b&&(b=w(),null===b&&(b=x()));null!==b;)a.push(b),b=p(),null===b&&(b=w(),null===b&&(b=x()));return a}function z(){var a,b;for(a=[],b=p(),null===b&&(b=r(),null===b&&(b=u()));null!==b;)a.push(b),b=p(),null===b&&(b=r(),null===b&&(b=u()));return a}function A(){var a,b;return b=e,a=C(),null===a&&(a=B()),null!==a&&(a=function(a,b){return{type:"NumericLiteral",value:b}}(b,a)),null===a&&(e=b),a}function B(){var a,c,d;if(d=e,/^[0-9]/.test(b.charAt(e))?(c=b.charAt(e),e++):(c=null,0===f&&k("[0-9]")),null!==c)for(a=[];null!==c;)a.push(c),/^[0-9]/.test(b.charAt(e))?(c=b.charAt(e),e++):(c=null,0===f&&k("[0-9]"));else a=null;return null!==a&&(a=function(a,b){return parseInt(b.join(""))}(d,a)),null===a&&(e=d),a}function C(){var a,c,d,g,h;return g=e,h=e,a=B(),null!==a?(46===b.charCodeAt(e)?(c=".",e++):(c=null,0===f&&k('"."')),null!==c?(d=B(),null!==d?a=[a,c,d]:(a=null,e=h)):(a=null,e=h)):(a=null,e=h),null!==a&&(a=function(a,b){return parseFloat(b.join(""))}(g,a)),null===a&&(e=g),a}function D(){var a,c,d,g;if(g=e,/^[\-+]/.test(b.charAt(e))?(a=b.charAt(e),e++):(a=null,0===f&&k("[\\-+]")),a=null!==a?a:"",null!==a){if(/^[0-9]/.test(b.charAt(e))?(d=b.charAt(e),e++):(d=null,0===f&&k("[0-9]")),null!==d)for(c=[];null!==d;)c.push(d),/^[0-9]/.test(b.charAt(e))?(d=b.charAt(e),e++):(d=null,0===f&&k("[0-9]"));else c=null;null!==c?a=[a,c]:(a=null,e=g)}else a=null,e=g;return a}function E(){var a,b;return f++,b=e,a=F(),null!==a&&(a=function(a,b){return b}(b,a)),null===a&&(e=b),f--,0===f&&null===a&&k("identifier"),a}function F(){var a,b,c,d,g;if(f++,d=e,g=e,a=o(),null!==a){for(b=[],c=o();null!==c;)b.push(c),c=o();null!==b?a=[a,b]:(a=null,e=g)}else a=null,e=g;return null!==a&&(a=function(a,b,c){return b+c.join("")}(d,a[0],a[1])),null===a&&(e=d),f--,0===f&&null===a&&k("identifier"),a}function G(){var a,c,d,g,h,i,j;return i=e,a=E(),null!==a&&(a=function(a,b){return{type:"Variable",name:b}}(i,a)),null===a&&(e=i),null===a&&(a=A(),null===a&&(i=e,j=e,40===b.charCodeAt(e)?(a="(",e++):(a=null,0===f&&k('"("')),null!==a?(c=z(),null!==c?(d=P(),null!==d?(g=z(),null!==g?(41===b.charCodeAt(e)?(h=")",e++):(h=null,0===f&&k('")"')),null!==h?a=[a,c,d,g,h]:(a=null,e=j)):(a=null,e=j)):(a=null,e=j)):(a=null,e=j)):(a=null,e=j),null!==a&&(a=function(a,b){return b}(i,a[2])),null===a&&(e=i))),a}function H(){var a,b,c,d,f;return a=G(),null===a&&(d=e,f=e,a=I(),null!==a?(b=z(),null!==b?(c=H(),null!==c?a=[a,b,c]:(a=null,e=f)):(a=null,e=f)):(a=null,e=f),null!==a&&(a=function(a,b,c){return{type:"UnaryExpression",operator:b,expression:c}}(d,a[0],a[2])),null===a&&(e=d)),a}function I(){var a;return 43===b.charCodeAt(e)?(a="+",e++):(a=null,0===f&&k('"+"')),null===a&&(45===b.charCodeAt(e)?(a="-",e++):(a=null,0===f&&k('"-"')),null===a&&(33===b.charCodeAt(e)?(a="!",e++):(a=null,0===f&&k('"!"')))),a}function J(){var a,b,c,d,f,g,h,i,j;if(h=e,i=e,a=H(),null!==a){for(b=[],j=e,c=z(),null!==c?(d=K(),null!==d?(f=z(),null!==f?(g=H(),null!==g?c=[c,d,f,g]:(c=null,e=j)):(c=null,e=j)):(c=null,e=j)):(c=null,e=j);null!==c;)b.push(c),j=e,c=z(),null!==c?(d=K(),null!==d?(f=z(),null!==f?(g=H(),null!==g?c=[c,d,f,g]:(c=null,e=j)):(c=null,e=j)):(c=null,e=j)):(c=null,e=j);null!==b?a=[a,b]:(a=null,e=i)}else a=null,e=i;return null!==a&&(a=function(a,b,c){for(var d=b,e=0;e="===b.substr(e,2)?(a=">=",e+=2):(a=null,0===f&&k('">="')),null===a&&(60===b.charCodeAt(e)?(a="<",e++):(a=null,0===f&&k('"<"')),null===a&&(62===b.charCodeAt(e)?(a=">",e++):(a=null,0===f&&k('">"'))))),a}function P(){var a,c,d,g,h,i,j,l,m;if(j=e,l=e,a=N(),null!==a){for(c=[],m=e,d=z(),null!==d?("=="===b.substr(e,2)?(g="==",e+=2):(g=null,0===f&&k('"=="')),null!==g?(h=z(),null!==h?(i=N(),null!==i?d=[d,g,h,i]:(d=null,e=m)):(d=null,e=m)):(d=null,e=m)):(d=null,e=m);null!==d;)c.push(d),m=e,d=z(),null!==d?("=="===b.substr(e,2)?(g="==",e+=2):(g=null,0===f&&k('"=="')),null!==g?(h=z(),null!==h?(i=N(),null!==i?d=[d,g,h,i]:(d=null,e=m)):(d=null,e=m)):(d=null,e=m)):(d=null,e=m);null!==c?a=[a,c]:(a=null,e=l)}else a=null,e=l;return null!==a&&(a=function(a,b,c){for(var d=b,e=0;e0&&(i=1/Math.sqrt(i),e[0]=t[0]*i,e[1]=t[1]*i),e},o.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]},o.cross=function(e,t,n){var r=t[0]*n[1]-t[1]*n[0];return e[0]=e[1]=0,e[2]=r,e},o.lerp=function(e,t,n,r){var i=t[0],s=t[1];return e[0]=i+r*(n[0]-i),e[1]=s+r*(n[1]-s),e},o.random=function(e,t){t=t||1;var n=r()*2*Math.PI;return e[0]=Math.cos(n)*t,e[1]=Math.sin(n)*t,e},o.transformMat2=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[2]*i,e[1]=n[1]*r+n[3]*i,e},o.transformMat2d=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[2]*i+n[4],e[1]=n[1]*r+n[3]*i+n[5],e},o.transformMat3=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[3]*i+n[6],e[1]=n[1]*r+n[4]*i+n[7],e},o.transformMat4=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[4]*i+n[12],e[1]=n[1]*r+n[5]*i+n[13],e},o.forEach=function(){var e=o.create();return function(t,n,r,i,s,o){var u,a;n||(n=2),r||(r=0),i?a=Math.min(i*n+r,t.length):a=t.length;for(u=r;u0&&(s=1/Math.sqrt(s),e[0]=t[0]*s,e[1]=t[1]*s,e[2]=t[2]*s),e},u.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},u.cross=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=n[0],u=n[1],a=n[2];return e[0]=i*a-s*u,e[1]=s*o-r*a,e[2]=r*u-i*o,e},u.lerp=function(e,t,n,r){var i=t[0],s=t[1],o=t[2];return e[0]=i+r*(n[0]-i),e[1]=s+r*(n[1]-s),e[2]=o+r*(n[2]-o),e},u.random=function(e,t){t=t||1;var n=r()*2*Math.PI,i=r()*2-1,s=Math.sqrt(1-i*i)*t;return e[0]=Math.cos(n)*s,e[1]=Math.sin(n)*s,e[2]=i*t,e},u.transformMat4=function(e,t,n){var r=t[0],i=t[1],s=t[2];return e[0]=n[0]*r+n[4]*i+n[8]*s+n[12],e[1]=n[1]*r+n[5]*i+n[9]*s+n[13],e[2]=n[2]*r+n[6]*i+n[10]*s+n[14],e},u.transformMat3=function(e,t,n){var r=t[0],i=t[1],s=t[2];return e[0]=r*n[0]+i*n[3]+s*n[6],e[1]=r*n[1]+i*n[4]+s*n[7],e[2]=r*n[2]+i*n[5]+s*n[8],e},u.transformQuat=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=n[0],u=n[1],a=n[2],f=n[3],l=f*r+u*s-a*i,c=f*i+a*r-o*s,h=f*s+o*i-u*r,p=-o*r-u*i-a*s;return e[0]=l*f+p*-o+c*-a-h*-u,e[1]=c*f+p*-u+h*-o-l*-a,e[2]=h*f+p*-a+l*-u-c*-o,e},u.forEach=function(){var e=u.create();return function(t,n,r,i,s,o){var u,a;n||(n=3),r||(r=0),i?a=Math.min(i*n+r,t.length):a=t.length;for(u=r;u0&&(o=1/Math.sqrt(o),e[0]=t[0]*o,e[1]=t[1]*o,e[2]=t[2]*o,e[3]=t[3]*o),e},a.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]+e[3]*t[3]},a.lerp=function(e,t,n,r){var i=t[0],s=t[1],o=t[2],u=t[3];return e[0]=i+r*(n[0]-i),e[1]=s+r*(n[1]-s),e[2]=o+r*(n[2]-o),e[3]=u+r*(n[3]-u),e},a.random=function(e,t){return t=t||1,e[0]=r(),e[1]=r(),e[2]=r(),e[3]=r(),a.normalize(e,e),a.scale(e,e,t),e},a.transformMat4=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3];return e[0]=n[0]*r+n[4]*i+n[8]*s+n[12]*o,e[1]=n[1]*r+n[5]*i+n[9]*s+n[13]*o,e[2]=n[2]*r+n[6]*i+n[10]*s+n[14]*o,e[3]=n[3]*r+n[7]*i+n[11]*s+n[15]*o,e},a.transformQuat=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=n[0],u=n[1],a=n[2],f=n[3],l=f*r+u*s-a*i,c=f*i+a*r-o*s,h=f*s+o*i-u*r,p=-o*r-u*i-a*s;return e[0]=l*f+p*-o+c*-a-h*-u,e[1]=c*f+p*-u+h*-o-l*-a,e[2]=h*f+p*-a+l*-u-c*-o,e},a.forEach=function(){var e=a.create();return function(t,n,r,i,s,o){var u,a;n||(n=4),r||(r=0),i?a=Math.min(i*n+r,t.length):a=t.length;for(u=r;u.999999?(r[0]=0,r[1]=0,r[2]=0,r[3]=1,r):(u.cross(e,i,s),r[0]=e[0],r[1]=e[1],r[2]=e[2],r[3]=1+o,p.normalize(r,r))}}(),p.setAxes=function(){var e=c.create();return function(t,n,r,i){return e[0]=r[0],e[3]=r[1],e[6]=r[2],e[1]=i[0],e[4]=i[1],e[7]=i[2],e[2]=-n[0],e[5]=-n[1],e[8]=-n[2],p.normalize(t,p.fromMat3(t,e))}}(),p.clone=a.clone,p.fromValues=a.fromValues,p.copy=a.copy,p.set=a.set,p.identity=function(e){return e[0]=0,e[1]=0,e[2]=0,e[3]=1,e},p.setAxisAngle=function(e,t,n){n*=.5;var r=Math.sin(n);return e[0]=r*t[0],e[1]=r*t[1],e[2]=r*t[2],e[3]=Math.cos(n),e},p.add=a.add,p.multiply=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=n[0],a=n[1],f=n[2],l=n[3];return e[0]=r*l+o*u+i*f-s*a,e[1]=i*l+o*a+s*u-r*f,e[2]=s*l+o*f+r*a-i*u,e[3]=o*l-r*u-i*a-s*f,e},p.mul=p.multiply,p.scale=a.scale,p.rotateX=function(e,t,n){n*=.5;var r=t[0],i=t[1],s=t[2],o=t[3],u=Math.sin(n),a=Math.cos(n);return e[0]=r*a+o*u,e[1]=i*a+s*u,e[2]=s*a-i*u,e[3]=o*a-r*u,e},p.rotateY=function(e,t,n){n*=.5;var r=t[0],i=t[1],s=t[2],o=t[3],u=Math.sin(n),a=Math.cos(n);return e[0]=r*a-s*u,e[1]=i*a+o*u,e[2]=s*a+r*u,e[3]=o*a-i*u,e},p.rotateZ=function(e,t,n){n*=.5;var r=t[0],i=t[1],s=t[2],o=t[3],u=Math.sin(n),a=Math.cos(n);return e[0]=r*a+i*u,e[1]=i*a-r*u,e[2]=s*a+o*u,e[3]=o*a-s*u,e},p.calculateW=function(e,t){var n=t[0],r=t[1],i=t[2];return e[0]=n,e[1]=r,e[2]=i,e[3]=-Math.sqrt(Math.abs(1-n*n-r*r-i*i)),e},p.dot=a.dot,p.lerp=a.lerp,p.slerp=function(e,t,n,r){var i=t[0],s=t[1],o=t[2],u=t[3],a=n[0],f=n[1],l=n[2],c=n[3],h,p,d,v,m;return p=i*a+s*f+o*l+u*c,p<0&&(p=-p,a=-a,f=-f,l=-l,c=-c),1-p>1e-6?(h=Math.acos(p),d=Math.sin(h),v=Math.sin((1-r)*h)/d,m=Math.sin(r*h)/d):(v=1-r,m=r),e[0]=v*i+m*a,e[1]=v*s+m*f,e[2]=v*o+m*l,e[3]=v*u+m*c,e},p.invert=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=n*n+r*r+i*i+s*s,u=o?1/o:0;return e[0]=-n*u,e[1]=-r*u,e[2]=-i*u,e[3]=s*u,e},p.conjugate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=t[3],e},p.length=a.length,p.len=p.length,p.squaredLength=a.squaredLength,p.sqrLen=p.squaredLength,p.normalize=a.normalize,p.fromMat3=function(e,t){var n=t[0]+t[4]+t[8],r;if(n>0)r=Math.sqrt(n+1),e[3]=.5*r,r=.5/r,e[0]=(t[7]-t[5])*r,e[1]=(t[2]-t[6])*r,e[2]=(t[3]-t[1])*r;else{var i=0;t[4]>t[0]&&(i=1),t[8]>t[i*3+i]&&(i=2);var s=(i+1)%3,o=(i+2)%3;r=Math.sqrt(t[i*3+i]-t[s*3+s]-t[o*3+o]+1),e[i]=.5*r,r=.5/r,e[3]=(t[o*3+s]-t[s*3+o])*r,e[s]=(t[s*3+i]+t[i*3+s])*r,e[o]=(t[o*3+i]+t[i*3+o])*r}return e},p.str=function(e){return"quat("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+")"},typeof e!="undefined"&&(e.quat=p)}(t.exports)})(this);
29 |
--------------------------------------------------------------------------------
/bower_components/gss/vendor/observe.js:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | (function(global) {
16 | 'use strict';
17 |
18 | function detectObjectObserve() {
19 | if (typeof Object.observe !== 'function' ||
20 | typeof Array.observe !== 'function') {
21 | return false;
22 | }
23 |
24 | var gotSplice = false;
25 | function callback(records) {
26 | if (records[0].type === 'splice' && records[1].type === 'splice')
27 | gotSplice = true;
28 | }
29 |
30 | var test = [0];
31 | Array.observe(test, callback);
32 | test[1] = 1;
33 | test.length = 0;
34 | Object.deliverChangeRecords(callback);
35 | return gotSplice;
36 | }
37 |
38 | var hasObserve = detectObjectObserve();
39 |
40 | function detectEval() {
41 | // don't test for eval if document has CSP securityPolicy object and we can see that
42 | // eval is not supported. This avoids an error message in console even when the exception
43 | // is caught
44 | if (global.document &&
45 | 'securityPolicy' in global.document &&
46 | !global.document.securityPolicy.allowsEval) {
47 | return false;
48 | }
49 |
50 | try {
51 | var f = new Function('', 'return true;');
52 | return f();
53 | } catch (ex) {
54 | return false;
55 | }
56 | }
57 |
58 | var hasEval = detectEval();
59 |
60 | function isIndex(s) {
61 | return +s === s >>> 0;
62 | }
63 |
64 | function toNumber(s) {
65 | return +s;
66 | }
67 |
68 | function isObject(obj) {
69 | return obj === Object(obj);
70 | }
71 |
72 | var numberIsNaN = global.Number.isNaN || function isNaN(value) {
73 | return typeof value === 'number' && global.isNaN(value);
74 | }
75 |
76 | function areSameValue(left, right) {
77 | if (left === right)
78 | return left !== 0 || 1 / left === 1 / right;
79 | if (numberIsNaN(left) && numberIsNaN(right))
80 | return true;
81 |
82 | return left !== left && right !== right;
83 | }
84 |
85 | var createObject = ('__proto__' in {}) ?
86 | function(obj) { return obj; } :
87 | function(obj) {
88 | var proto = obj.__proto__;
89 | if (!proto)
90 | return obj;
91 | var newObject = Object.create(proto);
92 | Object.getOwnPropertyNames(obj).forEach(function(name) {
93 | Object.defineProperty(newObject, name,
94 | Object.getOwnPropertyDescriptor(obj, name));
95 | });
96 | return newObject;
97 | };
98 |
99 | var identStart = '[\$_a-zA-Z]';
100 | var identPart = '[\$_a-zA-Z0-9]';
101 | var ident = identStart + '+' + identPart + '*';
102 | var elementIndex = '(?:[0-9]|[1-9]+[0-9]+)';
103 | var identOrElementIndex = '(?:' + ident + '|' + elementIndex + ')';
104 | var path = '(?:' + identOrElementIndex + ')(?:\\s*\\.\\s*' + identOrElementIndex + ')*';
105 | var pathRegExp = new RegExp('^' + path + '$');
106 |
107 | function isPathValid(s) {
108 | if (typeof s != 'string')
109 | return false;
110 | s = s.trim();
111 |
112 | if (s == '')
113 | return true;
114 |
115 | if (s[0] == '.')
116 | return false;
117 |
118 | return pathRegExp.test(s);
119 | }
120 |
121 | var constructorIsPrivate = {};
122 |
123 | function Path(s, privateToken) {
124 | if (privateToken !== constructorIsPrivate)
125 | throw Error('Use Path.get to retrieve path objects');
126 |
127 | if (s.trim() == '')
128 | return this;
129 |
130 | if (isIndex(s)) {
131 | this.push(s);
132 | return this;
133 | }
134 |
135 | s.split(/\s*\.\s*/).filter(function(part) {
136 | return part;
137 | }).forEach(function(part) {
138 | this.push(part);
139 | }, this);
140 |
141 | if (hasEval && !hasObserve && this.length) {
142 | this.getValueFrom = this.compiledGetValueFromFn();
143 | }
144 | }
145 |
146 | // TODO(rafaelw): Make simple LRU cache
147 | var pathCache = {};
148 |
149 | function getPath(pathString) {
150 | if (pathString instanceof Path)
151 | return pathString;
152 |
153 | if (pathString == null)
154 | pathString = '';
155 |
156 | if (typeof pathString !== 'string')
157 | pathString = String(pathString);
158 |
159 | var path = pathCache[pathString];
160 | if (path)
161 | return path;
162 | if (!isPathValid(pathString))
163 | return invalidPath;
164 | var path = new Path(pathString, constructorIsPrivate);
165 | pathCache[pathString] = path;
166 | return path;
167 | }
168 |
169 | Path.get = getPath;
170 |
171 | Path.prototype = createObject({
172 | __proto__: [],
173 | valid: true,
174 |
175 | toString: function() {
176 | return this.join('.');
177 | },
178 |
179 | getValueFrom: function(obj, observedSet) {
180 | for (var i = 0; i < this.length; i++) {
181 | if (obj == null)
182 | return;
183 | if (observedSet)
184 | observedSet.observe(obj);
185 | obj = obj[this[i]];
186 | }
187 | return obj;
188 | },
189 |
190 | compiledGetValueFromFn: function() {
191 | var accessors = this.map(function(ident) {
192 | return isIndex(ident) ? '["' + ident + '"]' : '.' + ident;
193 | });
194 |
195 | var str = '';
196 | var pathString = 'obj';
197 | str += 'if (obj != null';
198 | var i = 0;
199 | for (; i < (this.length - 1); i++) {
200 | var ident = this[i];
201 | pathString += accessors[i];
202 | str += ' &&\n ' + pathString + ' != null';
203 | }
204 | str += ')\n';
205 |
206 | pathString += accessors[i];
207 |
208 | str += ' return ' + pathString + ';\nelse\n return undefined;';
209 | return new Function('obj', str);
210 | },
211 |
212 | setValueFrom: function(obj, value) {
213 | if (!this.length)
214 | return false;
215 |
216 | for (var i = 0; i < this.length - 1; i++) {
217 | if (!isObject(obj))
218 | return false;
219 | obj = obj[this[i]];
220 | }
221 |
222 | if (!isObject(obj))
223 | return false;
224 |
225 | obj[this[i]] = value;
226 | return true;
227 | }
228 | });
229 |
230 | var invalidPath = new Path('', constructorIsPrivate);
231 | invalidPath.valid = false;
232 | invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
233 |
234 | var MAX_DIRTY_CHECK_CYCLES = 1000;
235 |
236 | function dirtyCheck(observer) {
237 | var cycles = 0;
238 | while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check()) {
239 | observer.report();
240 | cycles++;
241 | }
242 | if (global.testingExposeCycleCount)
243 | global.dirtyCheckCycleCount = cycles;
244 | }
245 |
246 | function objectIsEmpty(object) {
247 | for (var prop in object)
248 | return false;
249 | return true;
250 | }
251 |
252 | function diffIsEmpty(diff) {
253 | return objectIsEmpty(diff.added) &&
254 | objectIsEmpty(diff.removed) &&
255 | objectIsEmpty(diff.changed);
256 | }
257 |
258 | function diffObjectFromOldObject(object, oldObject) {
259 | var added = {};
260 | var removed = {};
261 | var changed = {};
262 | var oldObjectHas = {};
263 |
264 | for (var prop in oldObject) {
265 | var newValue = object[prop];
266 |
267 | if (newValue !== undefined && newValue === oldObject[prop])
268 | continue;
269 |
270 | if (!(prop in object)) {
271 | removed[prop] = undefined;
272 | continue;
273 | }
274 |
275 | if (newValue !== oldObject[prop])
276 | changed[prop] = newValue;
277 | }
278 |
279 | for (var prop in object) {
280 | if (prop in oldObject)
281 | continue;
282 |
283 | added[prop] = object[prop];
284 | }
285 |
286 | if (Array.isArray(object) && object.length !== oldObject.length)
287 | changed.length = object.length;
288 |
289 | return {
290 | added: added,
291 | removed: removed,
292 | changed: changed
293 | };
294 | }
295 |
296 | function copyObject(object, opt_copy) {
297 | var copy = opt_copy || (Array.isArray(object) ? [] : {});
298 | for (var prop in object) {
299 | copy[prop] = object[prop];
300 | };
301 | if (Array.isArray(object))
302 | copy.length = object.length;
303 | return copy;
304 | }
305 |
306 | function Observer(object, callback, target, token) {
307 | this.closed = false;
308 | this.object = object;
309 | this.callback = callback;
310 | // TODO(rafaelw): Hold this.target weakly when WeakRef is available.
311 | this.target = target;
312 | this.token = token;
313 | this.reporting = true;
314 | if (hasObserve) {
315 | var self = this;
316 | this.boundInternalCallback = function(records) {
317 | self.internalCallback(records);
318 | };
319 | }
320 |
321 | addToAll(this);
322 | }
323 |
324 | Observer.prototype = {
325 | internalCallback: function(records) {
326 | if (this.closed)
327 | return;
328 | if (this.reporting && this.check(records)) {
329 | this.report();
330 | if (this.testingResults)
331 | this.testingResults.anyChanged = true;
332 | }
333 | },
334 |
335 | close: function() {
336 | if (this.closed)
337 | return;
338 | if (this.object && typeof this.object.close === 'function')
339 | this.object.close();
340 |
341 | this.disconnect();
342 | this.object = undefined;
343 | this.closed = true;
344 | },
345 |
346 | deliver: function(testingResults) {
347 | if (this.closed)
348 | return;
349 | if (hasObserve) {
350 | this.testingResults = testingResults;
351 | Object.deliverChangeRecords(this.boundInternalCallback);
352 | this.testingResults = undefined;
353 | } else {
354 | dirtyCheck(this);
355 | }
356 | },
357 |
358 | report: function() {
359 | if (!this.reporting)
360 | return;
361 |
362 | this.sync(false);
363 | if (this.callback) {
364 | this.reportArgs.push(this.token);
365 | this.invokeCallback(this.reportArgs);
366 | }
367 | this.reportArgs = undefined;
368 | },
369 |
370 | invokeCallback: function(args) {
371 | try {
372 | this.callback.apply(this.target, args);
373 | } catch (ex) {
374 | Observer._errorThrownDuringCallback = true;
375 | console.error('Exception caught during observer callback: ' + (ex.stack || ex));
376 | }
377 | },
378 |
379 | reset: function() {
380 | if (this.closed)
381 | return;
382 |
383 | if (hasObserve) {
384 | this.reporting = false;
385 | Object.deliverChangeRecords(this.boundInternalCallback);
386 | this.reporting = true;
387 | }
388 |
389 | this.sync(true);
390 | }
391 | }
392 |
393 | var collectObservers = !hasObserve || global.forceCollectObservers;
394 | var allObservers;
395 | Observer._allObserversCount = 0;
396 |
397 | if (collectObservers) {
398 | allObservers = [];
399 | }
400 |
401 | function addToAll(observer) {
402 | if (!collectObservers)
403 | return;
404 |
405 | allObservers.push(observer);
406 | Observer._allObserversCount++;
407 | }
408 |
409 | var runningMicrotaskCheckpoint = false;
410 |
411 | var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'function';
412 |
413 | global.Platform = global.Platform || {};
414 |
415 | global.Platform.performMicrotaskCheckpoint = function() {
416 | if (runningMicrotaskCheckpoint)
417 | return;
418 |
419 | if (hasDebugForceFullDelivery) {
420 | Object.deliverAllChangeRecords();
421 | return;
422 | }
423 |
424 | if (!collectObservers)
425 | return;
426 |
427 | runningMicrotaskCheckpoint = true;
428 |
429 | var cycles = 0;
430 | var results = {};
431 |
432 | do {
433 | cycles++;
434 | var toCheck = allObservers;
435 | allObservers = [];
436 | results.anyChanged = false;
437 |
438 | for (var i = 0; i < toCheck.length; i++) {
439 | var observer = toCheck[i];
440 | if (observer.closed)
441 | continue;
442 |
443 | if (hasObserve) {
444 | observer.deliver(results);
445 | } else if (observer.check()) {
446 | results.anyChanged = true;
447 | observer.report();
448 | }
449 |
450 | allObservers.push(observer);
451 | }
452 | } while (cycles < MAX_DIRTY_CHECK_CYCLES && results.anyChanged);
453 |
454 | if (global.testingExposeCycleCount)
455 | global.dirtyCheckCycleCount = cycles;
456 |
457 | Observer._allObserversCount = allObservers.length;
458 | runningMicrotaskCheckpoint = false;
459 | };
460 |
461 | if (collectObservers) {
462 | global.Platform.clearObservers = function() {
463 | allObservers = [];
464 | };
465 | }
466 |
467 | function ObjectObserver(object, callback, target, token) {
468 | Observer.call(this, object, callback, target, token);
469 | this.connect();
470 | this.sync(true);
471 | }
472 |
473 | ObjectObserver.prototype = createObject({
474 | __proto__: Observer.prototype,
475 |
476 | connect: function() {
477 | if (hasObserve)
478 | Object.observe(this.object, this.boundInternalCallback);
479 | },
480 |
481 | sync: function(hard) {
482 | if (!hasObserve)
483 | this.oldObject = copyObject(this.object);
484 | },
485 |
486 | check: function(changeRecords) {
487 | var diff;
488 | var oldValues;
489 | if (hasObserve) {
490 | if (!changeRecords)
491 | return false;
492 |
493 | oldValues = {};
494 | diff = diffObjectFromChangeRecords(this.object, changeRecords,
495 | oldValues);
496 | } else {
497 | oldValues = this.oldObject;
498 | diff = diffObjectFromOldObject(this.object, this.oldObject);
499 | }
500 |
501 | if (diffIsEmpty(diff))
502 | return false;
503 |
504 | this.reportArgs =
505 | [diff.added || {}, diff.removed || {}, diff.changed || {}];
506 | this.reportArgs.push(function(property) {
507 | return oldValues[property];
508 | });
509 |
510 | return true;
511 | },
512 |
513 | disconnect: function() {
514 | if (!hasObserve)
515 | this.oldObject = undefined;
516 | else if (this.object)
517 | Object.unobserve(this.object, this.boundInternalCallback);
518 | }
519 | });
520 |
521 | function ArrayObserver(array, callback, target, token) {
522 | if (!Array.isArray(array))
523 | throw Error('Provided object is not an Array');
524 | ObjectObserver.call(this, array, callback, target, token);
525 | }
526 |
527 | ArrayObserver.prototype = createObject({
528 | __proto__: ObjectObserver.prototype,
529 |
530 | connect: function() {
531 | if (hasObserve)
532 | Array.observe(this.object, this.boundInternalCallback);
533 | },
534 |
535 | sync: function() {
536 | if (!hasObserve)
537 | this.oldObject = this.object.slice();
538 | },
539 |
540 | check: function(changeRecords) {
541 | var splices;
542 | if (hasObserve) {
543 | if (!changeRecords)
544 | return false;
545 | splices = projectArraySplices(this.object, changeRecords);
546 | } else {
547 | splices = calcSplices(this.object, 0, this.object.length,
548 | this.oldObject, 0, this.oldObject.length);
549 | }
550 |
551 | if (!splices || !splices.length)
552 | return false;
553 |
554 | this.reportArgs = [splices];
555 | return true;
556 | }
557 | });
558 |
559 | ArrayObserver.applySplices = function(previous, current, splices) {
560 | splices.forEach(function(splice) {
561 | var spliceArgs = [splice.index, splice.removed.length];
562 | var addIndex = splice.index;
563 | while (addIndex < splice.index + splice.addedCount) {
564 | spliceArgs.push(current[addIndex]);
565 | addIndex++;
566 | }
567 |
568 | Array.prototype.splice.apply(previous, spliceArgs);
569 | });
570 | };
571 |
572 | function ObservedSet(callback) {
573 | this.arr = [];
574 | this.callback = callback;
575 | this.isObserved = true;
576 | }
577 |
578 | var objProto = Object.getPrototypeOf({});
579 | var arrayProto = Object.getPrototypeOf([]);
580 | ObservedSet.prototype = {
581 | reset: function() {
582 | this.isObserved = !this.isObserved;
583 | },
584 |
585 | observe: function(obj) {
586 | if (!isObject(obj) || obj === objProto || obj === arrayProto)
587 | return;
588 | var i = this.arr.indexOf(obj);
589 | if (i >= 0 && this.arr[i+1] === this.isObserved)
590 | return;
591 |
592 | if (i < 0) {
593 | i = this.arr.length;
594 | this.arr[i] = obj;
595 | Object.observe(obj, this.callback);
596 | }
597 |
598 | this.arr[i+1] = this.isObserved;
599 | this.observe(Object.getPrototypeOf(obj));
600 | },
601 |
602 | cleanup: function() {
603 | var i = 0, j = 0;
604 | var isObserved = this.isObserved;
605 | while(j < this.arr.length) {
606 | var obj = this.arr[j];
607 | if (this.arr[j + 1] == isObserved) {
608 | if (i < j) {
609 | this.arr[i] = obj;
610 | this.arr[i + 1] = isObserved;
611 | }
612 | i += 2;
613 | } else {
614 | Object.unobserve(obj, this.callback);
615 | }
616 | j += 2;
617 | }
618 |
619 | this.arr.length = i;
620 | }
621 | };
622 |
623 | function PathObserver(object, path, callback, target, token, valueFn,
624 | setValueFn) {
625 | var path = path instanceof Path ? path : getPath(path);
626 | if (!path || !path.length || !isObject(object)) {
627 | this.value_ = path ? path.getValueFrom(object) : undefined;
628 | this.value = valueFn ? valueFn(this.value_) : this.value_;
629 | this.closed = true;
630 | return;
631 | }
632 |
633 | Observer.call(this, object, callback, target, token);
634 | this.valueFn = valueFn;
635 | this.setValueFn = setValueFn;
636 | this.path = path;
637 |
638 | this.connect();
639 | this.sync(true);
640 | }
641 |
642 | PathObserver.prototype = createObject({
643 | __proto__: Observer.prototype,
644 |
645 | connect: function() {
646 | if (hasObserve)
647 | this.observedSet = new ObservedSet(this.boundInternalCallback);
648 | },
649 |
650 | disconnect: function() {
651 | this.value = undefined;
652 | this.value_ = undefined;
653 | if (this.observedSet) {
654 | this.observedSet.reset();
655 | this.observedSet.cleanup();
656 | this.observedSet = undefined;
657 | }
658 | },
659 |
660 | check: function() {
661 | // Note: Extracting this to a member function for use here and below
662 | // regresses dirty-checking path perf by about 25% =-(.
663 | if (this.observedSet)
664 | this.observedSet.reset();
665 |
666 | this.value_ = this.path.getValueFrom(this.object, this.observedSet);
667 |
668 | if (this.observedSet)
669 | this.observedSet.cleanup();
670 |
671 | if (areSameValue(this.value_, this.oldValue_))
672 | return false;
673 |
674 | this.value = this.valueFn ? this.valueFn(this.value_) : this.value_;
675 | this.reportArgs = [this.value, this.oldValue];
676 | return true;
677 | },
678 |
679 | sync: function(hard) {
680 | if (hard) {
681 | if (this.observedSet)
682 | this.observedSet.reset();
683 |
684 | this.value_ = this.path.getValueFrom(this.object, this.observedSet);
685 | this.value = this.valueFn ? this.valueFn(this.value_) : this.value_;
686 |
687 | if (this.observedSet)
688 | this.observedSet.cleanup();
689 | }
690 |
691 | this.oldValue_ = this.value_;
692 | this.oldValue = this.value;
693 | },
694 |
695 | setValue: function(newValue) {
696 | if (!this.path)
697 | return;
698 | if (typeof this.setValueFn === 'function')
699 | newValue = this.setValueFn(newValue);
700 | this.path.setValueFrom(this.object, newValue);
701 | }
702 | });
703 |
704 | function CompoundPathObserver(callback, target, token, valueFn) {
705 | Observer.call(this, undefined, callback, target, token);
706 | this.valueFn = valueFn;
707 |
708 | this.observed = [];
709 | this.values = [];
710 | this.value = undefined;
711 | this.oldValue = undefined;
712 | this.oldValues = undefined;
713 | this.changeFlags = undefined;
714 | this.started = false;
715 | }
716 |
717 | CompoundPathObserver.prototype = createObject({
718 | __proto__: PathObserver.prototype,
719 |
720 | addPath: function(object, path) {
721 | if (this.started)
722 | throw Error('Cannot add more paths once started.');
723 |
724 | var path = path instanceof Path ? path : getPath(path);
725 | var value = path ? path.getValueFrom(object) : undefined;
726 |
727 | this.observed.push(object, path);
728 | this.values.push(value);
729 | },
730 |
731 | start: function() {
732 | this.connect();
733 | this.sync(true);
734 | },
735 |
736 | getValues: function() {
737 | if (this.observedSet)
738 | this.observedSet.reset();
739 |
740 | var anyChanged = false;
741 | for (var i = 0; i < this.observed.length; i = i+2) {
742 | var path = this.observed[i+1];
743 | if (!path)
744 | continue;
745 | var object = this.observed[i];
746 | var value = path.getValueFrom(object, this.observedSet);
747 | var oldValue = this.values[i/2];
748 | if (!areSameValue(value, oldValue)) {
749 | if (!anyChanged && !this.valueFn) {
750 | this.oldValues = this.oldValues || [];
751 | this.changeFlags = this.changeFlags || [];
752 | for (var j = 0; j < this.values.length; j++) {
753 | this.oldValues[j] = this.values[j];
754 | this.changeFlags[j] = false;
755 | }
756 | }
757 |
758 | if (!this.valueFn)
759 | this.changeFlags[i/2] = true;
760 |
761 | this.values[i/2] = value;
762 | anyChanged = true;
763 | }
764 | }
765 |
766 | if (this.observedSet)
767 | this.observedSet.cleanup();
768 |
769 | return anyChanged;
770 | },
771 |
772 | check: function() {
773 | if (!this.getValues())
774 | return;
775 |
776 | if (this.valueFn) {
777 | this.value = this.valueFn(this.values);
778 |
779 | if (areSameValue(this.value, this.oldValue))
780 | return false;
781 |
782 | this.reportArgs = [this.value, this.oldValue];
783 | } else {
784 | this.reportArgs = [this.values, this.oldValues, this.changeFlags];
785 | }
786 |
787 | return true;
788 | },
789 |
790 | sync: function(hard) {
791 | if (hard) {
792 | this.getValues();
793 | if (this.valueFn)
794 | this.value = this.valueFn(this.values);
795 | }
796 |
797 | if (this.valueFn)
798 | this.oldValue = this.value;
799 | },
800 |
801 | close: function() {
802 | if (this.observed) {
803 | for (var i = 0; i < this.observed.length; i = i + 2) {
804 | var object = this.observed[i];
805 | if (object && typeof object.close === 'function')
806 | object.close();
807 | }
808 | this.observed = undefined;
809 | this.values = undefined;
810 | }
811 |
812 | Observer.prototype.close.call(this);
813 | }
814 | });
815 |
816 | var knownRecordTypes = {
817 | 'new': true,
818 | 'updated': true,
819 | 'deleted': true
820 | };
821 |
822 | function notifyFunction(object, name) {
823 | if (typeof Object.observe !== 'function')
824 | return;
825 |
826 | var notifier = Object.getNotifier(object);
827 | return function(type, oldValue) {
828 | var changeRecord = {
829 | object: object,
830 | type: type,
831 | name: name
832 | };
833 | if (arguments.length === 2)
834 | changeRecord.oldValue = oldValue;
835 | notifier.notify(changeRecord);
836 | }
837 | }
838 |
839 | // TODO(rafaelw): It should be possible for the Object.observe case to have
840 | // every PathObserver used by defineProperty share a single Object.observe
841 | // callback, and thus get() can simply call observer.deliver() and any changes
842 | // to any dependent value will be observed.
843 | PathObserver.defineProperty = function(object, name, descriptor) {
844 | // TODO(rafaelw): Validate errors
845 | var obj = descriptor.object;
846 | var path = getPath(descriptor.path);
847 | var notify = notifyFunction(object, name);
848 |
849 | var observer = new PathObserver(obj, descriptor.path,
850 | function(newValue, oldValue) {
851 | if (notify)
852 | notify('updated', oldValue);
853 | }
854 | );
855 |
856 | Object.defineProperty(object, name, {
857 | get: function() {
858 | return path.getValueFrom(obj);
859 | },
860 | set: function(newValue) {
861 | path.setValueFrom(obj, newValue);
862 | },
863 | configurable: true
864 | });
865 |
866 | return {
867 | close: function() {
868 | var oldValue = path.getValueFrom(obj);
869 | if (notify)
870 | observer.deliver();
871 | observer.close();
872 | Object.defineProperty(object, name, {
873 | value: oldValue,
874 | writable: true,
875 | configurable: true
876 | });
877 | }
878 | };
879 | }
880 |
881 | function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
882 | var added = {};
883 | var removed = {};
884 |
885 | for (var i = 0; i < changeRecords.length; i++) {
886 | var record = changeRecords[i];
887 | if (!knownRecordTypes[record.type]) {
888 | console.error('Unknown changeRecord type: ' + record.type);
889 | console.error(record);
890 | continue;
891 | }
892 |
893 | if (!(record.name in oldValues))
894 | oldValues[record.name] = record.oldValue;
895 |
896 | if (record.type == 'updated')
897 | continue;
898 |
899 | if (record.type == 'new') {
900 | if (record.name in removed)
901 | delete removed[record.name];
902 | else
903 | added[record.name] = true;
904 |
905 | continue;
906 | }
907 |
908 | // type = 'deleted'
909 | if (record.name in added) {
910 | delete added[record.name];
911 | delete oldValues[record.name];
912 | } else {
913 | removed[record.name] = true;
914 | }
915 | }
916 |
917 | for (var prop in added)
918 | added[prop] = object[prop];
919 |
920 | for (var prop in removed)
921 | removed[prop] = undefined;
922 |
923 | var changed = {};
924 | for (var prop in oldValues) {
925 | if (prop in added || prop in removed)
926 | continue;
927 |
928 | var newValue = object[prop];
929 | if (oldValues[prop] !== newValue)
930 | changed[prop] = newValue;
931 | }
932 |
933 | return {
934 | added: added,
935 | removed: removed,
936 | changed: changed
937 | };
938 | }
939 |
940 | function newSplice(index, removed, addedCount) {
941 | return {
942 | index: index,
943 | removed: removed,
944 | addedCount: addedCount
945 | };
946 | }
947 |
948 | var EDIT_LEAVE = 0;
949 | var EDIT_UPDATE = 1;
950 | var EDIT_ADD = 2;
951 | var EDIT_DELETE = 3;
952 |
953 | function ArraySplice() {}
954 |
955 | ArraySplice.prototype = {
956 |
957 | // Note: This function is *based* on the computation of the Levenshtein
958 | // "edit" distance. The one change is that "updates" are treated as two
959 | // edits - not one. With Array splices, an update is really a delete
960 | // followed by an add. By retaining this, we optimize for "keeping" the
961 | // maximum array items in the original array. For example:
962 | //
963 | // 'xxxx123' -> '123yyyy'
964 | //
965 | // With 1-edit updates, the shortest path would be just to update all seven
966 | // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
967 | // leaves the substring '123' intact.
968 | calcEditDistances: function(current, currentStart, currentEnd,
969 | old, oldStart, oldEnd) {
970 | // "Deletion" columns
971 | var rowCount = oldEnd - oldStart + 1;
972 | var columnCount = currentEnd - currentStart + 1;
973 | var distances = new Array(rowCount);
974 |
975 | // "Addition" rows. Initialize null column.
976 | for (var i = 0; i < rowCount; i++) {
977 | distances[i] = new Array(columnCount);
978 | distances[i][0] = i;
979 | }
980 |
981 | // Initialize null row
982 | for (var j = 0; j < columnCount; j++)
983 | distances[0][j] = j;
984 |
985 | for (var i = 1; i < rowCount; i++) {
986 | for (var j = 1; j < columnCount; j++) {
987 | if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
988 | distances[i][j] = distances[i - 1][j - 1];
989 | else {
990 | var north = distances[i - 1][j] + 1;
991 | var west = distances[i][j - 1] + 1;
992 | distances[i][j] = north < west ? north : west;
993 | }
994 | }
995 | }
996 |
997 | return distances;
998 | },
999 |
1000 | // This starts at the final weight, and walks "backward" by finding
1001 | // the minimum previous weight recursively until the origin of the weight
1002 | // matrix.
1003 | spliceOperationsFromEditDistances: function(distances) {
1004 | var i = distances.length - 1;
1005 | var j = distances[0].length - 1;
1006 | var current = distances[i][j];
1007 | var edits = [];
1008 | while (i > 0 || j > 0) {
1009 | if (i == 0) {
1010 | edits.push(EDIT_ADD);
1011 | j--;
1012 | continue;
1013 | }
1014 | if (j == 0) {
1015 | edits.push(EDIT_DELETE);
1016 | i--;
1017 | continue;
1018 | }
1019 | var northWest = distances[i - 1][j - 1];
1020 | var west = distances[i - 1][j];
1021 | var north = distances[i][j - 1];
1022 |
1023 | var min;
1024 | if (west < north)
1025 | min = west < northWest ? west : northWest;
1026 | else
1027 | min = north < northWest ? north : northWest;
1028 |
1029 | if (min == northWest) {
1030 | if (northWest == current) {
1031 | edits.push(EDIT_LEAVE);
1032 | } else {
1033 | edits.push(EDIT_UPDATE);
1034 | current = northWest;
1035 | }
1036 | i--;
1037 | j--;
1038 | } else if (min == west) {
1039 | edits.push(EDIT_DELETE);
1040 | i--;
1041 | current = west;
1042 | } else {
1043 | edits.push(EDIT_ADD);
1044 | j--;
1045 | current = north;
1046 | }
1047 | }
1048 |
1049 | edits.reverse();
1050 | return edits;
1051 | },
1052 |
1053 | /**
1054 | * Splice Projection functions:
1055 | *
1056 | * A splice map is a representation of how a previous array of items
1057 | * was transformed into a new array of items. Conceptually it is a list of
1058 | * tuples of
1059 | *
1060 | *
1061 | *
1062 | * which are kept in ascending index order of. The tuple represents that at
1063 | * the |index|, |removed| sequence of items were removed, and counting forward
1064 | * from |index|, |addedCount| items were added.
1065 | */
1066 |
1067 | /**
1068 | * Lacking individual splice mutation information, the minimal set of
1069 | * splices can be synthesized given the previous state and final state of an
1070 | * array. The basic approach is to calculate the edit distance matrix and
1071 | * choose the shortest path through it.
1072 | *
1073 | * Complexity: O(l * p)
1074 | * l: The length of the current array
1075 | * p: The length of the old array
1076 | */
1077 | calcSplices: function(current, currentStart, currentEnd,
1078 | old, oldStart, oldEnd) {
1079 | var prefixCount = 0;
1080 | var suffixCount = 0;
1081 |
1082 | var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
1083 | if (currentStart == 0 && oldStart == 0)
1084 | prefixCount = this.sharedPrefix(current, old, minLength);
1085 |
1086 | if (currentEnd == current.length && oldEnd == old.length)
1087 | suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
1088 |
1089 | currentStart += prefixCount;
1090 | oldStart += prefixCount;
1091 | currentEnd -= suffixCount;
1092 | oldEnd -= suffixCount;
1093 |
1094 | if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
1095 | return [];
1096 |
1097 | if (currentStart == currentEnd) {
1098 | var splice = newSplice(currentStart, [], 0);
1099 | while (oldStart < oldEnd)
1100 | splice.removed.push(old[oldStart++]);
1101 |
1102 | return [ splice ];
1103 | } else if (oldStart == oldEnd)
1104 | return [ newSplice(currentStart, [], currentEnd - currentStart) ];
1105 |
1106 | var ops = this.spliceOperationsFromEditDistances(
1107 | this.calcEditDistances(current, currentStart, currentEnd,
1108 | old, oldStart, oldEnd));
1109 |
1110 | var splice = undefined;
1111 | var splices = [];
1112 | var index = currentStart;
1113 | var oldIndex = oldStart;
1114 | for (var i = 0; i < ops.length; i++) {
1115 | switch(ops[i]) {
1116 | case EDIT_LEAVE:
1117 | if (splice) {
1118 | splices.push(splice);
1119 | splice = undefined;
1120 | }
1121 |
1122 | index++;
1123 | oldIndex++;
1124 | break;
1125 | case EDIT_UPDATE:
1126 | if (!splice)
1127 | splice = newSplice(index, [], 0);
1128 |
1129 | splice.addedCount++;
1130 | index++;
1131 |
1132 | splice.removed.push(old[oldIndex]);
1133 | oldIndex++;
1134 | break;
1135 | case EDIT_ADD:
1136 | if (!splice)
1137 | splice = newSplice(index, [], 0);
1138 |
1139 | splice.addedCount++;
1140 | index++;
1141 | break;
1142 | case EDIT_DELETE:
1143 | if (!splice)
1144 | splice = newSplice(index, [], 0);
1145 |
1146 | splice.removed.push(old[oldIndex]);
1147 | oldIndex++;
1148 | break;
1149 | }
1150 | }
1151 |
1152 | if (splice) {
1153 | splices.push(splice);
1154 | }
1155 | return splices;
1156 | },
1157 |
1158 | sharedPrefix: function(current, old, searchLength) {
1159 | for (var i = 0; i < searchLength; i++)
1160 | if (!this.equals(current[i], old[i]))
1161 | return i;
1162 | return searchLength;
1163 | },
1164 |
1165 | sharedSuffix: function(current, old, searchLength) {
1166 | var index1 = current.length;
1167 | var index2 = old.length;
1168 | var count = 0;
1169 | while (count < searchLength && this.equals(current[--index1], old[--index2]))
1170 | count++;
1171 |
1172 | return count;
1173 | },
1174 |
1175 | calculateSplices: function(current, previous) {
1176 | return this.calcSplices(current, 0, current.length, previous, 0,
1177 | previous.length);
1178 | },
1179 |
1180 | equals: function(currentValue, previousValue) {
1181 | return currentValue === previousValue;
1182 | }
1183 | };
1184 |
1185 | var arraySplice = new ArraySplice();
1186 |
1187 | function calcSplices(current, currentStart, currentEnd,
1188 | old, oldStart, oldEnd) {
1189 | return arraySplice.calcSplices(current, currentStart, currentEnd,
1190 | old, oldStart, oldEnd);
1191 | }
1192 |
1193 | function intersect(start1, end1, start2, end2) {
1194 | // Disjoint
1195 | if (end1 < start2 || end2 < start1)
1196 | return -1;
1197 |
1198 | // Adjacent
1199 | if (end1 == start2 || end2 == start1)
1200 | return 0;
1201 |
1202 | // Non-zero intersect, span1 first
1203 | if (start1 < start2) {
1204 | if (end1 < end2)
1205 | return end1 - start2; // Overlap
1206 | else
1207 | return end2 - start2; // Contained
1208 | } else {
1209 | // Non-zero intersect, span2 first
1210 | if (end2 < end1)
1211 | return end2 - start1; // Overlap
1212 | else
1213 | return end1 - start1; // Contained
1214 | }
1215 | }
1216 |
1217 | function mergeSplice(splices, index, removed, addedCount) {
1218 |
1219 | var splice = newSplice(index, removed, addedCount);
1220 |
1221 | var inserted = false;
1222 | var insertionOffset = 0;
1223 |
1224 | for (var i = 0; i < splices.length; i++) {
1225 | var current = splices[i];
1226 | current.index += insertionOffset;
1227 |
1228 | if (inserted)
1229 | continue;
1230 |
1231 | var intersectCount = intersect(splice.index,
1232 | splice.index + splice.removed.length,
1233 | current.index,
1234 | current.index + current.addedCount);
1235 |
1236 | if (intersectCount >= 0) {
1237 | // Merge the two splices
1238 |
1239 | splices.splice(i, 1);
1240 | i--;
1241 |
1242 | insertionOffset -= current.addedCount - current.removed.length;
1243 |
1244 | splice.addedCount += current.addedCount - intersectCount;
1245 | var deleteCount = splice.removed.length +
1246 | current.removed.length - intersectCount;
1247 |
1248 | if (!splice.addedCount && !deleteCount) {
1249 | // merged splice is a noop. discard.
1250 | inserted = true;
1251 | } else {
1252 | var removed = current.removed;
1253 |
1254 | if (splice.index < current.index) {
1255 | // some prefix of splice.removed is prepended to current.removed.
1256 | var prepend = splice.removed.slice(0, current.index - splice.index);
1257 | Array.prototype.push.apply(prepend, removed);
1258 | removed = prepend;
1259 | }
1260 |
1261 | if (splice.index + splice.removed.length > current.index + current.addedCount) {
1262 | // some suffix of splice.removed is appended to current.removed.
1263 | var append = splice.removed.slice(current.index + current.addedCount - splice.index);
1264 | Array.prototype.push.apply(removed, append);
1265 | }
1266 |
1267 | splice.removed = removed;
1268 | if (current.index < splice.index) {
1269 | splice.index = current.index;
1270 | }
1271 | }
1272 | } else if (splice.index < current.index) {
1273 | // Insert splice here.
1274 |
1275 | inserted = true;
1276 |
1277 | splices.splice(i, 0, splice);
1278 | i++;
1279 |
1280 | var offset = splice.addedCount - splice.removed.length
1281 | current.index += offset;
1282 | insertionOffset += offset;
1283 | }
1284 | }
1285 |
1286 | if (!inserted)
1287 | splices.push(splice);
1288 | }
1289 |
1290 | function createInitialSplices(array, changeRecords) {
1291 | var splices = [];
1292 |
1293 | for (var i = 0; i < changeRecords.length; i++) {
1294 | var record = changeRecords[i];
1295 | switch(record.type) {
1296 | case 'splice':
1297 | mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
1298 | break;
1299 | case 'new':
1300 | case 'updated':
1301 | case 'deleted':
1302 | if (!isIndex(record.name))
1303 | continue;
1304 | var index = toNumber(record.name);
1305 | if (index < 0)
1306 | continue;
1307 | mergeSplice(splices, index, [record.oldValue], 1);
1308 | break;
1309 | default:
1310 | console.error('Unexpected record type: ' + JSON.stringify(record));
1311 | break;
1312 | }
1313 | }
1314 |
1315 | return splices;
1316 | }
1317 |
1318 | function projectArraySplices(array, changeRecords) {
1319 | var splices = [];
1320 |
1321 | createInitialSplices(array, changeRecords).forEach(function(splice) {
1322 | if (splice.addedCount == 1 && splice.removed.length == 1) {
1323 | if (splice.removed[0] !== array[splice.index])
1324 | splices.push(splice);
1325 |
1326 | return
1327 | };
1328 |
1329 | splices = splices.concat(calcSplices(array, splice.index, splice.index + splice.addedCount,
1330 | splice.removed, 0, splice.removed.length));
1331 | });
1332 |
1333 | return splices;
1334 | }
1335 |
1336 | global.Observer = Observer;
1337 | global.Observer.hasObjectObserve = hasObserve;
1338 | global.ArrayObserver = ArrayObserver;
1339 | global.ArrayObserver.calculateSplices = function(current, previous) {
1340 | return arraySplice.calculateSplices(current, previous);
1341 | };
1342 |
1343 | global.ArraySplice = ArraySplice;
1344 | global.ObjectObserver = ObjectObserver;
1345 | global.PathObserver = PathObserver;
1346 | global.CompoundPathObserver = CompoundPathObserver;
1347 | global.Path = Path;
1348 | })(typeof global !== 'undefined' && global ? global : this);
--------------------------------------------------------------------------------
/bower_components/gss/vendor/sidetable.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 The Polymer Authors. All rights reserved.
3 | * Use of this source code is goverened by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | // SideTable is a weak map where possible. If WeakMap is not available the
8 | // association is stored as an expando property.
9 | var SideTable;
10 | // TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox
11 | if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) {
12 | SideTable = WeakMap;
13 | } else {
14 | (function() {
15 | var defineProperty = Object.defineProperty;
16 | var hasOwnProperty = Object.hasOwnProperty;
17 | var counter = new Date().getTime() % 1e9;
18 |
19 | SideTable = function() {
20 | this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
21 | };
22 |
23 | SideTable.prototype = {
24 | set: function(key, value) {
25 | defineProperty(key, this.name, {value: value, writable: true});
26 | },
27 | get: function(key) {
28 | return hasOwnProperty.call(key, this.name) ? key[this.name] : undefined;
29 | },
30 | delete: function(key) {
31 | this.set(key, undefined);
32 | }
33 | }
34 | })();
35 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var cloneWithProps = require('react/lib/cloneWithProps');
4 |
5 | function invariant(cond, message) {
6 | if (!cond) {
7 | throw new Error('Invariant Violation: ' + message);
8 | }
9 | }
10 |
11 | function merge() {
12 | var a = {};
13 | Array.prototype.slice.call(arguments).forEach(function(x) {
14 | for (var k in x) {
15 | if (!x.hasOwnProperty(k)) {
16 | continue;
17 | }
18 | a[k] = x[k];
19 | }
20 | });
21 | return a;
22 | }
23 |
24 | var LAYOUT_KEYS = {
25 | 'width': 'width',
26 | 'height': 'height',
27 | 'left': 'left',
28 | 'right': 'right',
29 | 'top': 'top',
30 | 'bottom': 'bottom',
31 | 'centerX': 'center-x',
32 | 'centerY': 'center-y',
33 | 'intrinsicHeight': 'intrinsic-height',
34 | 'intrinsicWidth': 'intrinsic-width'
35 | };
36 |
37 | function interpolateIDsAndNormalizeKeys(constraints, mapping) {
38 | // TODO: use a real parser for better errors etc
39 | return constraints.replace(/(\w[\w\d_-]+)\.(\w[\w\d_-]+)/g, function(match, name, propertyName) {
40 | invariant(LAYOUT_KEYS[propertyName], 'Invalid layout property name: ' + propertyName);
41 | invariant(mapping[name], 'Unknown Box or AutoLayout name: ' + name);
42 | return mapping[name] + '[' + LAYOUT_KEYS[propertyName] + ']';
43 | });
44 | }
45 |
46 | var Box = React.createClass({
47 | render: function() {
48 | return React.Children.only(this.props.children);
49 | }
50 | });
51 |
52 | var idSeed = 0;
53 |
54 | var AutoLayout = React.createClass({
55 | getInitialState: function() {
56 | return {layoutCompleted: false};
57 | },
58 |
59 | componentWillMount: function() {
60 | invariant(typeof GSS !== 'undefined', 'GSS not set up on the page');
61 | var engine = GSS.engines[0];
62 | invariant(engine, 'GSS is not ready yet. Did you forget GSS.once(\'afterLoaded\', ...) ?');
63 | invariant(!GSS.config.observe, 'You cannot use GSS in observe mode. Did you set observe: false in GSS_CONFIG?');
64 | this.styleSheet = new GSS.StyleSheet({engine: engine, engineId: engine.id});
65 | },
66 |
67 | componentDidMount: function() {
68 | var constraints = this.getConstraints();
69 | this.styleSheet.addRules(GSS.compile(constraints));
70 | this.lastConstraints = constraints;
71 |
72 | GSS.on('display', this.handleDisplay);
73 | },
74 |
75 | handleDisplay: function() {
76 | if (this.isMounted() && !this.state.layoutCompleted) {
77 | this.setState({layoutCompleted: true});
78 | }
79 | },
80 |
81 | componentDidUpdate: function() {
82 | var constraints = this.getConstraints();
83 | if (this.lastConstraints != constraints) {
84 | this.styleSheet.destroyRules();
85 | this.styleSheet.addRules(GSS.compile(constraints));
86 | this.lastConstraints = constraints;
87 | }
88 | },
89 |
90 | componentWillUnmount: function() {
91 | this.styleSheet.destroyRules();
92 | },
93 |
94 | getDefaultProps: function() {
95 | return {name: 'this', constraints: ''};
96 | },
97 |
98 | getConstraintsForProps: function(props, layoutKeysOnly) {
99 | var constraints = '';
100 | for (var key in props) {
101 | // TODO: warn about this where the descriptor is constructed (in 0.12?)
102 | invariant(
103 | !layoutKeysOnly || (key === 'name' || key === 'children' || LAYOUT_KEYS[key]),
104 | 'Unknown layout prop: ' + key
105 | );
106 | if (LAYOUT_KEYS[key]) {
107 | var value = props[key].trim();
108 | var beginning = value.length >= 2 ? value.slice(0, 2) : '';
109 |
110 | if (beginning !== '==' && beginning !== '>=' && beginning !== '<=') {
111 | value = '== ' + value;
112 | }
113 |
114 | constraints += props.name + '.' + key + ' ' + value + ';\n';
115 | }
116 | }
117 | constraints = interpolateIDsAndNormalizeKeys(constraints, this.getMapping());
118 | return constraints;
119 | },
120 |
121 | getConstraints: function() {
122 | // lets build up the stylesheet mmkay
123 | var constraints = this.props.constraints;
124 |
125 | constraints += this.getConstraintsForProps(this.props, false);
126 |
127 | React.Children.forEach(this.props.children, function(box) {
128 | constraints += this.getConstraintsForProps(box.props, true);
129 | }, this);
130 |
131 | return constraints;
132 | },
133 |
134 | getSelector: function(component) {
135 | var node = component.getDOMNode();
136 |
137 | if (!node.hasAttribute('id')) {
138 | node.id = 'autoLayout' + (idSeed++);
139 | }
140 |
141 | return '#' + node.id;
142 | },
143 |
144 | getMapping: function() {
145 | var mapping = {
146 | 'window': '::window'
147 | };
148 | React.Children.forEach(this.props.children, function(box) {
149 | invariant(box.props.name, 'Box requires a name');
150 | mapping[box.props.name] = this.getSelector(this.refs[box.props.name]);
151 | }, this);
152 |
153 | mapping[this.props.name] = this.getSelector(this);
154 |
155 | return mapping;
156 | },
157 |
158 | render: function() {
159 | var children = React.Children.map(this.props.children, function(box) {
160 | return cloneWithProps(box, {
161 | children: box.props.children,
162 | key: box.props.name,
163 | ref: box.props.name
164 | });
165 | });
166 |
167 | return this.transferPropsTo(
168 | React.DOM.div({style: {visibility: this.state.layoutCompleted ? 'visible' : 'hidden'}}, children)
169 | );
170 | }
171 | });
172 |
173 | module.exports = {
174 | AutoLayout: AutoLayout,
175 | Box: Box
176 | };
177 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-gss",
3 | "version": "0.2.0",
4 | "description": "Grid stylesheets for React",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack-dev-server",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/petehunt/react-gss.git"
13 | },
14 | "author": "Pete Hunt",
15 | "license": "Apache 2",
16 | "bugs": {
17 | "url": "https://github.com/petehunt/react-gss/issues"
18 | },
19 | "homepage": "https://github.com/petehunt/react-gss",
20 | "peerDependencies": {
21 | "react": ">=0.11.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | // webpack.config.js
2 | module.exports = {
3 | entry: './app.js',
4 | output: {
5 | filename: 'bundle.js'
6 | },
7 | module: {
8 | loaders: [
9 | { test: /\.js$/, loader: 'jsx-loader?harmony' }
10 | ]
11 | }
12 | };
13 |
--------------------------------------------------------------------------------