├── .gitignore
├── LICENSE
├── README.md
├── karma.conf.js
├── package-lock.json
├── package.json
└── src
├── Defaults.js
├── Errors.js
├── Model.js
├── PubSub.js
├── VueModel.js
├── VueModel.spec.js
└── lib
├── promise-delay.js
└── set-nested.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/**/*
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Aaron Francis
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## About
2 | Vue-model is a Javascript plugin for Vue.js that gives you the ability to transform your plain data into rich models with built-in and customizable HTTP actions, computed properties, and methods.
3 |
4 | This project started because I work in Vue relatively often and really wanted to be able to call `customer.save()`, have it `POST` the data to the server, show the user feedback that the action was in progress, and then apply the server's results to the model.
5 |
6 | So that's what this plugin does.
7 |
8 | ## TOC
9 | - [Installation](#installation)
10 | - [Quick Examples](#quick-examples)
11 | - [Create a Model](#create-a-model)
12 | - [Update a Model](#update-a-model)
13 | - [Fetch or Delete a Model](#fetch-or-delete-a-model)
14 | - [Defining Models](#defining-models)
15 | - [Definition Options](#definition-options)
16 | - [Attributes](#attributes)
17 | - [Methods & Computed](#methods--computed)
18 | - [HTTP](#http)
19 | - [Action Definitions](#action-definitions)
20 | - [Data](#data)
21 | - [Registering Models](#registering-models)
22 | - [Creating Models](#creating-models)
23 | - [Manually](#manually)
24 | - [A Single Model](#a-single-model)
25 | - [Multiple Models](#multiple-models)
26 | - [Automatically](#automatically)
27 | - [Performing HTTP Actions](#performing-http-actions)
28 | - [Route Interpolation](#route-interpolation)
29 | - [Applying Response Data (or Not)](#applying-response-data-or-not)
30 | - [Busy Indicators](#busy-indicators)
31 | - [Global](#global)
32 | - [Action-Specific](#action-specific)
33 | - [Events](#events)
34 | - [Naming](#naming)
35 | - [Data](#data-1)
36 | - [Listeners](#listeners)
37 | - [Automatically Adding Listeners](#automatically-adding-listeners)
38 | - [Manually Adding Listeners](#manually-adding-listeners)
39 | - [Testing](#testing)
40 |
41 | ## Installation
42 |
43 | ```
44 | > npm install --save vue-model
45 | ```
46 |
47 | ```javascript
48 | Vue.use(require('vue-model'));
49 | ```
50 |
51 | ## Quick Examples
52 |
53 | Here are a few very basic examples to show you a little bit of what you can do with vue-model.
54 |
55 | ### Create a Model
56 |
57 | `POST` the model to the backend and show a spinner while it's happening.
58 |
59 | ```html
60 |
61 |
62 |
63 | Creating...
64 |
65 |
66 | Create Customer
67 |
68 |
69 | ```
70 |
71 | ### Update a Model
72 |
73 | The same as creating, but instead it issues a `PUT`.
74 |
75 | ```html
76 |
77 |
78 |
79 | Saving...
80 |
81 |
82 | Save Customer
83 |
84 |
85 | ```
86 |
87 | ### Fetch or Delete a Model
88 |
89 | Some of the other default actions you can execute, right out of the box.
90 |
91 | ```html
92 |
97 | ```
98 |
99 | ## Defining Models
100 |
101 | Defining your models is as simple as providing a plain JSON object, but it's often better to keep them in dedicated files.
102 |
103 | Here's an example of a `customer` model that defines a few of the model's attributes, some `http` options, methods, and computed properties.
104 |
105 | ```javascript
106 | var Customer = module.exports = {
107 | attributes: [
108 | 'id',
109 | 'name',
110 | 'email',
111 | ],
112 |
113 | http: {
114 | baseRoute: '/api/customers/',
115 | actions: {
116 | // Don't expose the destroy action
117 | destroy: false
118 | }
119 | },
120 |
121 | methods: {
122 | sayHello() {
123 | alert('Hello ' + this.name);
124 | }
125 | },
126 |
127 | computed: {
128 | is_aaron: function () {
129 | return this.email === 'aarondfrancis@gmail.com'
130 | }
131 | }
132 | }
133 | ```
134 |
135 | Once you create a model (which we'll talk about in a bit), you now have a super powerful object you can play with in your views.
136 |
137 | Here's a simple form that allows a user to update their name and persist it to the backend. (Bonus: it also shows a loading indicator!)
138 |
139 | ```html
140 | Change your name:
141 |
142 |
143 |
144 |
145 |
146 | Saving...
147 |
148 |
149 | Save
150 |
151 |
152 | ```
153 |
154 | And here's the same form, with feedback for errors:
155 |
156 | ```html
157 | Change your name:
158 |
159 |
160 |
161 | Uh oh!
162 |
163 |
164 | {{ error.field }}: {{ error.message }}
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 | Saving...
173 |
174 |
175 | Save
176 |
177 |
178 | ```
179 |
180 | The crazy thing about this it's all done right there with our model: putting the data, showing loading indicators, receiving the response, and mapping the validation errors!
181 |
182 | ### Definition Options
183 |
184 | Your model definitions are merged with the values in `Defaults.js` to create a fully fleshed out model. Let's take a look at some of the options you can define.
185 |
186 | #### Attributes
187 | The top level `attributes` key defines your model's... attributes. When a model is created, we'll default all these keys to `null` so that Vue tracks them. Just like plain objects in Vue, if you set a previously undefined key on an object, Vue may not track it and you'll run into unexpected (and frustrating) results.
188 |
189 | The `attributes` array also forms the basis for what data is sent to the server for HTTP requests. You can of course modify what data is sent, but the starting point is the keys in the `attributes` array.
190 |
191 | #### Methods & Computed
192 | This will be familiar to you if you're familiar with Vue. They work the same way.
193 |
194 | #### HTTP
195 | Now we're getting to the really good stuff. The top level `http` key holds all of our configuration for making requests. Let's look at some of the keys in the `http` object.
196 |
197 | `baseRoute`: This may be something like `/customers/`, or `/api/customers/`, resulting in final urls like `/customers/{id}`
198 |
199 | `eventPrefix`: The namespace for events sent from this model. If you don't define a value for this, then it is automatically set to the `name` that you register your model with. (See the Events section for more on this.)
200 |
201 | `takeAtLeast`: If you want your actions to take at _least_ a certain amount of time, you can set this value to something greater than 0. Sometimes if an action takes < 100ms, it can seem like it didn't work. I learned this from watching an Adam Wathan live-stream, and then later saw it on [his twitter](https://twitter.com/adamwathan/status/885130802513752065). By default it's set to 0ms.
202 |
203 | `axios`: a function that lets you customize the axios request configuration option, if you want.
204 |
205 | `getDataFromResponse`: this is the function that takes the axios response from the server and turns it into a key-value map of data. This just depends on how your backend returns the data. You may return it in a nested `data` key, or you may return it with no nesting at all.
206 |
207 | `getErrorsFromResponse`: same idea as `getDataFromResponse`, but for validation errors. This function takes the `response` and returns a map where keys are field names, and values are **arrays** of errors. By default this is set up for Laravel 5.5 by returning `response.data.errors`.
208 |
209 | `isValidationError`: there are lots of things that can go wrong with a request, but we only want to try to map validation errors when the thing that went wrong was validation. This function receives an error and returns a bool if it was a validation error. By default, this is set up to return `true` if the response code is `422`, which is what Laravel sends when validation fails.
210 |
211 | `errorKey`: by default, we nest the errors on the `http` key, making access from your model look something like `customer.http.errors.{method}`. If you don't like that, you can change it! You can set this value to e.g. `errors`, and it will live at the top of your model, making access a little easier: `customer.errors.{method}`. (Make sure your model doesn't have an `errors` attribute, method, or computed property though!)
212 |
213 | ##### Action Definitions
214 |
215 | `actionDefaults` the defaults that are applied to every action:
216 |
217 | ```javascript
218 | {
219 | // Apply the response data to the model
220 | apply: false,
221 |
222 | // The server validates this request and could
223 | // return a validation error in response
224 | validation: true,
225 |
226 | // Modify what data we should send to the server
227 | data: {
228 | // only: [],
229 | // with: [],
230 | // without: [],
231 | // custom: function(data, definition) {
232 | // return data;
233 | // }
234 | }
235 | }
236 | ```
237 |
238 | The actions live in the `actions` key. This defines the http actions available on your model. You can simply use the defaults, or make up your own! By default, we have `index`, `store`, `fetch`, `update`, and `destroy`.
239 |
240 | If you wanted to make your own, you could do so like this:
241 |
242 | ```javascript
243 | {
244 | actions: {
245 | favorite: {
246 | method: 'PUT',
247 | route: '{id}/favorite',
248 | apply: true,
249 | data: false
250 | },
251 | unfavorite: {
252 | method: 'DELETE',
253 | route: '{id}/favorite',
254 | apply: true,
255 | data: false
256 | }
257 | }
258 | }
259 | ```
260 |
261 | Now you have two new methods on your model, `favorite` and `unfavorite`, which you'd call by e.g.: `customer.http.favorite()`. (Why you would favorite a customer is beyond me, but you get the idea.)
262 |
263 | Assuming your `baseRoute` is `/customers/` and its `id` is 1, the favorite action will `PUT` to `/customers/1/favorite` with no data (`data`: false), and apply whatever response comes back from the server. (The server could respond with `{favorited: true}` for example.)
264 |
265 | If you want to disable one of the default actions, just set the value to `false`
266 |
267 | ```javascript
268 | {
269 | actions: {
270 | destroy: false
271 | }
272 | }
273 | ```
274 |
275 | `customer.http.destroy` will be undefined now.
276 |
277 | ##### Data
278 |
279 | By default, we'll send all the keys + values from your model's `attributes` array. This may not be ideal in many cases though, so you can modify what data gets sent for each action. (Some of these examples may be contrived, but bear with me...)
280 |
281 | - `false` means no data will be sent at all
282 | ```javascript
283 | {
284 | favorite: {
285 | data: false
286 | }
287 | }
288 | ```
289 |
290 | - `only: []` defines the **only** keys from the `attributes` you want sent.
291 | ```javascript
292 | {
293 | setName: {
294 | data: {
295 | only: ['name']
296 | }
297 | }
298 | }
299 | ```
300 |
301 | - `without: []` defines which keys you want to **exclude**
302 | ```javascript
303 | {
304 | update: {
305 | data: {
306 | // Maybe this a separate resource?
307 | without: ['favorited']
308 | }
309 | }
310 | }
311 | ```
312 |
313 | - `with: []` keys present on `this` but not in `attributes` that you want to include, perhaps a computed property or method
314 | ```javascript
315 | {
316 | update: {
317 | data: {
318 | with: ['computed_property', 'method']
319 | }
320 | }
321 | }
322 | ```
323 |
324 | - `custom: function` after all of the above are computed, as the very last step we'll check for a `custom` function. The function receives the `payload` we're about send as well as the action's definition. **You must return** a payload, otherwise nothing will be sent.
325 | ```javascript
326 | {
327 | recent: {
328 | data: {
329 | custom: function(payload, definition) {
330 | payload.lastFetched = localStorage.get('last_fetched');
331 | return payload;
332 | }
333 | }
334 | }
335 | }
336 | ```
337 |
338 | `only`, `with`, and `without` can be arrays, or functions that return arrays.
339 |
340 | The arrays themselves can be full of strings, which are accessible from the model (attributes, methods, computed properties) or they can be plain objects.
341 |
342 | For example:
343 |
344 | ```javascript
345 | {
346 | favorited: {
347 | route: '',
348 | method: 'GET',
349 | data: {
350 | only: [],
351 | with: [{
352 | active: 1,
353 | favorited: 1
354 | }]
355 | }
356 | }
357 | }
358 | ```
359 |
360 | That action would send a `GET` to `/customers/?active=1&favorited=1`. We dropped every key via the `only:[]`, and then added some static data via `with`.
361 |
362 | ## Registering Models
363 |
364 | Now that we know alllll about model definition, let's talk about registration. The registration process is simple using the `Vue.models.register` method, eg:
365 |
366 | ```javascript
367 | var VueModel = require('vue-model');
368 | Vue.use(VueModel);
369 |
370 | Vue.models.register('customer', {
371 | // model definition
372 | });
373 |
374 | Vue.models.register('foo', {
375 | // model definition
376 | });
377 | ```
378 |
379 | The first argument is the `name` argument, the second argument is a plain object that lets you define some options that are specific to your model.
380 |
381 | Here's an example of registering a `customer` model that has a base route of `/customers`:
382 | ```javascript
383 | Vue.models.register('customer', {
384 | http: {
385 | baseRoute: '/customers'
386 | }
387 | });
388 | ```
389 |
390 | You can also register many at once during the plugin install:
391 |
392 | ```javascript
393 | var VueModel = require('vue-model');
394 | Vue.use(VueModel, {
395 | customer: require('./models/customer'),
396 | foo: require('./models/foo'),
397 | bar: require('./models/bar'),
398 | });
399 | ```
400 |
401 | In this case, they key is the `name` and the value is the model's definition object.
402 |
403 | Now you're ready to start creating and using your models.
404 |
405 | ## Creating Models
406 |
407 | There are two different ways to create models in vue-model: You can create them manually whenever you please, or you can have vue-model create them automatically.
408 |
409 | ### Manually
410 |
411 | #### A Single Model
412 | To manually create a model, use the `$model()` Vue Instance method.
413 |
414 | Within a Vue Instance:
415 |
416 | ```javascript
417 | this.$model(name, data, options);
418 | ```
419 |
420 | The `$model()` method accepts 3 parameters:
421 | - `name`: (string) The type of model. This is the same key you used to register the model
422 | - `data`: (object) The model data
423 | - `options`: (object) Any _instance_ specific model definitions
424 |
425 | You can create the model wherever you please. For example, you can call the method inside the `data` function:
426 |
427 | ```javascript
428 | new Vue({
429 | el: '#app',
430 |
431 | data: function() {
432 | return {
433 | customer: this.$model('customer', {
434 | name: 'Aaron'
435 | })
436 | };
437 | }
438 | });
439 | ```
440 |
441 | Or you can call it anywhere else! Here's an example where we instantiate a model within Vue's `created` lifecycle hook.
442 | ```javascript
443 | new Vue({
444 | el: '#app',
445 |
446 | data: {
447 | customer: {
448 | name: 'Aaron'
449 | }
450 | },
451 |
452 | created: function() {
453 | this.customer = this.$model('customer', this.customer);
454 | }
455 | });
456 | ```
457 | #### Multiple Models
458 | Do you have a whole set of models that need to be created? Great! Just use the `this.$models` method. It's the same as `this.$model` except the data parameter is an array of objects.
459 |
460 | - `name`: (string) The type of model. This is the same key you used to register the model
461 | - `data`: (array) A collection model data
462 | - `options`: (object) Any _instance_ specific model definitions
463 |
464 | This will return an array of models.
465 |
466 | > You can definitely do this yourself using a `for` loop and the `this.$model` method, `this.$models` is just a little more convenient.
467 |
468 | ### Automatically
469 | Manually creating models gives you ultimate flexibility, but sometimes you just want it to work right away. That's where automatic model creation comes into play.
470 |
471 | To automatically create models, you simply need to add a `models` array to your Vue Instance. A `models` array element can take two forms. The first form is just a string:
472 |
473 | ```javascript
474 | new Vue({
475 | el: '#app',
476 |
477 | models: ['customer'],
478 |
479 | data: {
480 | customer: {
481 | name: 'Aaron'
482 | }
483 | }
484 | });
485 | ```
486 |
487 | When you pass a string in, the **model type the data key must be the same**. In the example above, the model type must be `customer`, and the data key must also be `customer`.
488 |
489 | If you need more flexibility in naming, you can pass in a proper object.
490 |
491 | ```javascript
492 | new Vue({
493 | el: 'body',
494 |
495 | models: [{
496 | type: 'customer'
497 | key: 'newCustomer'
498 | }],
499 |
500 | data: {
501 | newCustomer: {
502 | name: 'Aaron'
503 | }
504 | }
505 | });
506 | ```
507 |
508 | In this example, the model type is still `customer`, but the actual data lives on the data key `newCustomer`.
509 |
510 | > Under the hood, vue-model adds a mixin that latches on to the `created` lifecycle event to create models automatically. [Read more about the Vue Instance lifecycle](https://vuejs.org/guide/instance.html#Lifecycle-Diagram)
511 |
512 | Depending on what the data is will depend on whether one or many models are automatically created. If the data is an array, many model will be created. For example:
513 |
514 | ```javascript
515 | new Vue({
516 | el: '#app',
517 |
518 | models: [{
519 | type: 'customer'
520 | key: 'customers'
521 | }],
522 |
523 | data: {
524 | customers: [{
525 | name: 'Aaron'
526 | },{
527 | name: 'Evan'
528 | }]
529 | }
530 | });
531 | ```
532 |
533 | We told vue-model to automatically create the `customer` model for the data that lives at the `customers` key. Because the data at `customers` is an array, vue-model will loop through and make each item a model.
534 |
535 |
536 | ## Performing HTTP Actions
537 |
538 | Performing HTTP Actions is the heart of vue-model. The whole purpose of this plugin is to make it painless for your models to interact with your application's backend.
539 |
540 | All the actions are available on the `http` key. To perform an action, you just need to call the corresponding method.
541 |
542 | Examples:
543 |
544 | ```javascript
545 | // Create a new customer
546 | customer.http.store();
547 |
548 | // Fetch this customer from the server
549 | customer.http.fetch();
550 |
551 | // Save this customer
552 | customer.http.update();
553 |
554 | // Delete this customer
555 | customer.http.destroy();
556 |
557 | // Retrieve a list of customers
558 | customer.http.index()
559 | ```
560 |
561 | These are the 5 actions that vue-model ships with, but you are welcome to disable those and/or set up your own.
562 |
563 | ### Route Interpolation
564 |
565 | All of your action's routes will be interpolated with your model's data. So if your model has an `id` of `10`, a route of
566 |
567 | ```
568 | /videos/{id}
569 | ```
570 |
571 | becomes
572 |
573 | ```
574 | /videos/10
575 | ```
576 |
577 | You can do this with any attribute from your model. If your model's `type` has a value of `watched`, a route defined as
578 |
579 | ```
580 | /videos/{type}/increment
581 | ```
582 |
583 | would become
584 |
585 | ```
586 | /videos/watched/increment
587 | ```
588 |
589 |
590 | ### Applying Response Data (or Not)
591 |
592 | Another great thing about vue-model is that you can automatically update your models with the response that comes back from the server.
593 |
594 | If you define your action with `apply = true`, vue-model will take the response from the server, loop through all the data and set the values.
595 |
596 | ```javascript
597 | {
598 | favorite: {
599 | method: 'PUT',
600 | route: '{id}/favorite',
601 | apply: true,
602 | data: false
603 | }
604 | }
605 | ```
606 |
607 | If the server returns
608 |
609 | ```javascript
610 | {
611 | favorited: 1
612 | }
613 | ```
614 |
615 | as its payload from the `complete` action, then the `completed` attribute on our model will automatically be updated.
616 |
617 | ```javascript
618 | customer.http.favorite();
619 | // Once it finishes...
620 | console.log(customer.favorited);
621 | // > 1
622 | ```
623 |
624 | That lets us create toggle buttons very easily, all in HTML.
625 |
626 | ```html
627 |
628 | Favorited
629 |
630 |
631 |
632 | Mark as Favorite
633 |
634 | ```
635 |
636 |
637 | ## Busy Indicators
638 |
639 | You'll often want to know when the model is busy, so that you can show loading indicators or prevent other actions. Vue-model provides two types of busy indicators: Global, and Action Specific.
640 |
641 | ### Global
642 | The global busy indicator lives in the http object under the `inProgress` key.
643 |
644 | For example, if you have a model named `customer`, you can observe the `customer.http.inProgress` attribute. This is helpful for showing/hiding elements or disabling buttons.
645 |
646 | Here's one way you can disable a button, should the model be busy performing an HTTP action:
647 |
648 | ```html
649 |
650 | Mark as Favorite
651 |
652 | ```
653 |
654 | ### Action-Specific
655 |
656 | If you have loading indicators scattered across the page and only want to show the correct indicator based on the specific action, then you should use an action-specific busy indicator.
657 |
658 | For every action, there is a corresponding property that indicates whether or not that action is currently in process. For example, if the action is named `update`, then the property would be named `updateInProgress`.
659 |
660 | Consider a case where you have a `complete` action for a `video` model and would like to show a loading indicator on the button.
661 |
662 | ```html
663 |
664 |
665 | Mark as Complete
666 |
667 | ```
668 |
669 | This button will disable itself and show the lovely Font Awesome loading indicator while the model finishes the `complete` action. This provides feedback and a good experience for your users. However, in this example if a different action is being performed, say a `favorite` action, the button will not show the loading indicator because it is bound to `completeInProgress` and not `inProgress` or `favoriteInProgress`.
670 |
671 | > When _any_ of the action-specific loading indicators (`{action}InProgress`) are `true`, the global `inProgress` indicator will also be `true`.
672 |
673 | ## Events
674 |
675 | Vue-model emits several events that you can listen for and respond to, giving you many different ways to seamlessly tie your app into vue-model.
676 |
677 | ### Naming
678 |
679 | Vue-model events follow a naming scheme of `{eventPrefix}.{action}.{result}`. The `eventPrefix` can be set in your model definition.
680 |
681 | By default, if you don't pass in an `eventPrefix` while registering your model, vue-model will set it to the `name` of model you register.
682 |
683 | ```javascript
684 |
685 | // No eventPrefix, model type is 'customer'
686 | Vue.models.register('customer', {});
687 |
688 | // --> eventPrefix is equal to 'customer'
689 |
690 |
691 | // Explicit eventPrefix passed in
692 | Vue.models.register('customer', {
693 | http: {
694 | eventPrefix: 'cst'
695 | }
696 | });
697 |
698 | // --> eventPrefix is equal to 'cst'
699 | ```
700 |
701 | `{action}` is always equal to the name of the action on your API. If you call `customer.http.update()`, `action` will be equal to `update`.
702 |
703 | `{result}` is one of the following:
704 |
705 | - `before` - Before the action takes place
706 | - `success` - Successful completion of the action
707 | - `complete` - Action *finished*, regardless of outcome
708 | - `error` - Action failed
709 |
710 | Putting it all together, the event name will look similar to the following examples:
711 |
712 | - `customer.update.before`
713 | - `customer.destroy.success`
714 | - `customer.list.complete`
715 | - `customer.fetch.error`
716 |
717 | ### Data
718 |
719 | Each event comes with `data` payload:
720 |
721 | - `{eventPrefix}.{action}.before` - Before the action takes place. Receives a plain object with a function you can call to prevent the action from happening.
722 |
723 | ```javascript
724 | {
725 | cancel: fn
726 | }
727 | ```
728 |
729 | - `{eventPrefix}.{action}.success` - Successful completion of the action. Receives the `response` from the server.
730 |
731 | - `{eventPrefix}.{action}.error` - Action failed. Receives the axios `error` object.
732 |
733 |
734 | - `{eventPrefix}.{action}.complete` - Action *finished*, regardless of outcome. No data. (Not fired if the action was cancelled manually by calling the `cancel` function in the `before` event.)
735 |
736 | ### Listeners
737 |
738 | #### Automatically Adding Listeners
739 |
740 | Events aren't much good without event listeners. To add event listeners, define a `listeners` key in your `models` option. Any model registration then moves to a `register` key. E.g:
741 |
742 | ```javascript
743 | new Vue({
744 | el: '#app',
745 |
746 | models: {
747 | register: ['customer']
748 | listeners: [
749 | 'customer.update.success'
750 | ]
751 | },
752 | });
753 | ```
754 |
755 | **When you add listeners automatically like this, they are bound during the Vue instance's `mounted` hook and automatically destroyed in the `beforeDestroy` lifecycle hook.**
756 |
757 | There are a couple different ways to register listeners within the `listeners` array. The first is a simple string, e.g. `customer.update.success`. This serves as **both the event and the handler**. Vue-model will try to call a method named `customer.update.success`.
758 |
759 | In that case, you'd set your Vue instance up like this:
760 |
761 | ```javascript
762 | new Vue({
763 | el: '#app',
764 |
765 | models: {
766 | register: ['customer']
767 | listeners: [
768 | 'customer.update.success'
769 | ]
770 | },
771 |
772 | methods: {
773 | 'customer.update.success': function() {
774 | console.log('great success!')
775 | }
776 | }
777 | });
778 | ```
779 |
780 | If you don't like that, then you can add listeners as a map, with the key being the event and the value being the method to call, either a string or a function.
781 |
782 | ```javascript
783 | new Vue({
784 | el: '#app',
785 |
786 | models: {
787 | register: ['customer']
788 | listeners: [{
789 | 'customer.update.success': 'customerUpdated',
790 | 'customer.update.error': function() {
791 | console.log('oh no!');
792 | }
793 | }]
794 | },
795 |
796 | methods: {
797 | customerUpdated: function() {
798 | console.log('great success!')
799 | }
800 | }
801 | });
802 | ```
803 |
804 | You can mix and match however you please. If you want to map multiple handlers to a single event, you're free to just keep adding elements to the array.
805 |
806 | ```javascript
807 | new Vue({
808 | el: '#app',
809 |
810 | models: {
811 | register: ['customer']
812 | listeners: [
813 | 'customer.update.success',
814 | {
815 | 'customer.update.error': function() {
816 | console.log('oh no!');
817 | }
818 | }, {
819 | 'customer.update.error': function() {
820 | console.log('two handlers for the same event, why not');
821 | }
822 | }]
823 | },
824 |
825 | methods: {
826 | 'customer.update.success': function() {
827 | console.log('great success!')
828 | }
829 | }
830 | });
831 | ```
832 |
833 |
834 | #### Manually Adding Listeners
835 |
836 | There may be times when you don't want to add listeners when your instance is mounted, which is when the automatic listeners are bound. If that's the case, you're in luck because you can use the `$addModelListeners` and `$removeModelListeners` methods.
837 |
838 |
839 | ```javascript
840 | new Vue({
841 | el: '#app',
842 |
843 | // No automatic listeners
844 | models: {
845 | register: ['customer']
846 | },
847 |
848 | watch: {
849 | // Some property that determines if this
850 | // component is "active"
851 | componentIsActive: function(val) {
852 | var method = val ? '$add' : '$remove';
853 |
854 | // Add or remove our listeners
855 | this[method + 'ModelListeners']([
856 | 'customer.update.success'
857 | ]);
858 | }
859 | }
860 |
861 | methods: {
862 | 'customer.update.success': function() {
863 | console.log('great success!')
864 | }
865 | }
866 | });
867 | ```
868 |
869 |
870 | **Remember:** When you don't use automatic event listeners, you are responsible for cleaning up your event listeners.
871 |
872 | ## Testing
873 |
874 | - Run `npm t` or `npm test` to run all tests once.
875 | - Run `npm run test:watch` to watch and rerun tests.
876 |
877 |
878 |
879 |
880 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 |
3 | module.exports = function(config) {
4 | config.set({
5 |
6 | // base path that will be used to resolve all patterns (eg. files, exclude)
7 | basePath: '',
8 |
9 |
10 | // frameworks to use
11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
12 | frameworks: ['jasmine', 'browserify'],
13 |
14 |
15 | // list of files / patterns to load in the browser
16 | files: [
17 | 'src/**/*.spec.js'
18 | ],
19 |
20 |
21 | // list of files to exclude
22 | exclude: [
23 | '**/*.swp'
24 | ],
25 |
26 |
27 | // preprocess matching files before serving them to the browser
28 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
29 | preprocessors: {
30 | 'src/**/*.spec.js' : [ 'browserify' ]
31 | },
32 |
33 | // test results reporter to use
34 | // possible values: 'dots', 'progress'
35 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
36 | reporters: ['mocha'],
37 |
38 | // web server port
39 | port: 9876,
40 |
41 |
42 | // enable / disable colors in the output (reporters and logs)
43 | colors: true,
44 |
45 |
46 | // level of logging
47 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
48 | logLevel: config.LOG_INFO,
49 |
50 |
51 | // enable / disable watching file and executing tests whenever any file changes
52 | autoWatch: true,
53 |
54 |
55 | // start these browsers
56 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
57 | browsers: ['Chrome'],
58 |
59 |
60 | // Continuous Integration mode
61 | // if true, Karma captures browsers, runs the tests and exits
62 | singleRun: false,
63 |
64 | // Concurrency level
65 | // how many browser should be started simultaneous
66 | concurrency: Infinity
67 | })
68 | }
69 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-model",
3 | "version": "2.0.7",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "JSONStream": {
8 | "version": "1.3.1",
9 | "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
10 | "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=",
11 | "dev": true,
12 | "requires": {
13 | "jsonparse": "1.3.1",
14 | "through": "2.3.8"
15 | }
16 | },
17 | "accepts": {
18 | "version": "1.3.3",
19 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
20 | "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=",
21 | "dev": true,
22 | "requires": {
23 | "mime-types": "2.1.17",
24 | "negotiator": "0.6.1"
25 | }
26 | },
27 | "acorn": {
28 | "version": "4.0.13",
29 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
30 | "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
31 | "dev": true
32 | },
33 | "after": {
34 | "version": "0.8.2",
35 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
36 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
37 | "dev": true
38 | },
39 | "ansi-regex": {
40 | "version": "3.0.0",
41 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
42 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
43 | "dev": true
44 | },
45 | "ansi-styles": {
46 | "version": "3.2.0",
47 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
48 | "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
49 | "dev": true,
50 | "requires": {
51 | "color-convert": "1.9.0"
52 | }
53 | },
54 | "anymatch": {
55 | "version": "1.3.2",
56 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
57 | "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
58 | "dev": true,
59 | "requires": {
60 | "micromatch": "2.3.11",
61 | "normalize-path": "2.1.1"
62 | }
63 | },
64 | "arr-diff": {
65 | "version": "2.0.0",
66 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
67 | "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
68 | "dev": true,
69 | "requires": {
70 | "arr-flatten": "1.1.0"
71 | }
72 | },
73 | "arr-flatten": {
74 | "version": "1.1.0",
75 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
76 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
77 | "dev": true
78 | },
79 | "array-filter": {
80 | "version": "0.0.1",
81 | "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
82 | "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
83 | "dev": true
84 | },
85 | "array-map": {
86 | "version": "0.0.0",
87 | "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
88 | "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
89 | "dev": true
90 | },
91 | "array-reduce": {
92 | "version": "0.0.0",
93 | "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
94 | "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
95 | "dev": true
96 | },
97 | "array-slice": {
98 | "version": "0.2.3",
99 | "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
100 | "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
101 | "dev": true
102 | },
103 | "array-unique": {
104 | "version": "0.2.1",
105 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
106 | "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
107 | "dev": true
108 | },
109 | "arraybuffer.slice": {
110 | "version": "0.0.6",
111 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz",
112 | "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=",
113 | "dev": true
114 | },
115 | "asap": {
116 | "version": "2.0.6",
117 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
118 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
119 | },
120 | "asn1.js": {
121 | "version": "4.9.1",
122 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz",
123 | "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=",
124 | "dev": true,
125 | "requires": {
126 | "bn.js": "4.11.8",
127 | "inherits": "2.0.3",
128 | "minimalistic-assert": "1.0.0"
129 | }
130 | },
131 | "assert": {
132 | "version": "1.4.1",
133 | "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
134 | "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
135 | "dev": true,
136 | "requires": {
137 | "util": "0.10.3"
138 | }
139 | },
140 | "astw": {
141 | "version": "2.2.0",
142 | "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz",
143 | "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=",
144 | "dev": true,
145 | "requires": {
146 | "acorn": "4.0.13"
147 | }
148 | },
149 | "async-each": {
150 | "version": "1.0.1",
151 | "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
152 | "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
153 | "dev": true
154 | },
155 | "axios": {
156 | "version": "0.16.2",
157 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.16.2.tgz",
158 | "integrity": "sha1-uk+S8XFn37q0CYN4VFS5rBScPG0=",
159 | "requires": {
160 | "follow-redirects": "1.2.5",
161 | "is-buffer": "1.1.6"
162 | }
163 | },
164 | "backo2": {
165 | "version": "1.0.2",
166 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
167 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
168 | "dev": true
169 | },
170 | "balanced-match": {
171 | "version": "1.0.0",
172 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
173 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
174 | "dev": true
175 | },
176 | "base64-arraybuffer": {
177 | "version": "0.1.5",
178 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
179 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
180 | "dev": true
181 | },
182 | "base64-js": {
183 | "version": "1.2.1",
184 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
185 | "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==",
186 | "dev": true
187 | },
188 | "base64id": {
189 | "version": "1.0.0",
190 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
191 | "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=",
192 | "dev": true
193 | },
194 | "better-assert": {
195 | "version": "1.0.2",
196 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
197 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
198 | "dev": true,
199 | "requires": {
200 | "callsite": "1.0.0"
201 | }
202 | },
203 | "binary-extensions": {
204 | "version": "1.10.0",
205 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz",
206 | "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=",
207 | "dev": true
208 | },
209 | "blob": {
210 | "version": "0.0.4",
211 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
212 | "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=",
213 | "dev": true
214 | },
215 | "bluebird": {
216 | "version": "3.5.1",
217 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
218 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==",
219 | "dev": true
220 | },
221 | "bn.js": {
222 | "version": "4.11.8",
223 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
224 | "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
225 | "dev": true
226 | },
227 | "body-parser": {
228 | "version": "1.18.2",
229 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
230 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
231 | "dev": true,
232 | "requires": {
233 | "bytes": "3.0.0",
234 | "content-type": "1.0.4",
235 | "debug": "2.6.9",
236 | "depd": "1.1.1",
237 | "http-errors": "1.6.2",
238 | "iconv-lite": "0.4.19",
239 | "on-finished": "2.3.0",
240 | "qs": "6.5.1",
241 | "raw-body": "2.3.2",
242 | "type-is": "1.6.15"
243 | }
244 | },
245 | "brace-expansion": {
246 | "version": "1.1.8",
247 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
248 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
249 | "dev": true,
250 | "requires": {
251 | "balanced-match": "1.0.0",
252 | "concat-map": "0.0.1"
253 | }
254 | },
255 | "braces": {
256 | "version": "1.8.5",
257 | "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
258 | "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
259 | "dev": true,
260 | "requires": {
261 | "expand-range": "1.8.2",
262 | "preserve": "0.2.0",
263 | "repeat-element": "1.1.2"
264 | }
265 | },
266 | "brorand": {
267 | "version": "1.1.0",
268 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
269 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
270 | "dev": true
271 | },
272 | "browser-pack": {
273 | "version": "6.0.2",
274 | "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.2.tgz",
275 | "integrity": "sha1-+GzWzvT1MAyOY+B6TVEvZfv/RTE=",
276 | "dev": true,
277 | "requires": {
278 | "JSONStream": "1.3.1",
279 | "combine-source-map": "0.7.2",
280 | "defined": "1.0.0",
281 | "through2": "2.0.3",
282 | "umd": "3.0.1"
283 | }
284 | },
285 | "browser-resolve": {
286 | "version": "1.11.2",
287 | "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz",
288 | "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=",
289 | "dev": true,
290 | "requires": {
291 | "resolve": "1.1.7"
292 | },
293 | "dependencies": {
294 | "resolve": {
295 | "version": "1.1.7",
296 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
297 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
298 | "dev": true
299 | }
300 | }
301 | },
302 | "browserify": {
303 | "version": "14.5.0",
304 | "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.5.0.tgz",
305 | "integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==",
306 | "dev": true,
307 | "requires": {
308 | "JSONStream": "1.3.1",
309 | "assert": "1.4.1",
310 | "browser-pack": "6.0.2",
311 | "browser-resolve": "1.11.2",
312 | "browserify-zlib": "0.2.0",
313 | "buffer": "5.0.8",
314 | "cached-path-relative": "1.0.1",
315 | "concat-stream": "1.5.2",
316 | "console-browserify": "1.1.0",
317 | "constants-browserify": "1.0.0",
318 | "crypto-browserify": "3.11.1",
319 | "defined": "1.0.0",
320 | "deps-sort": "2.0.0",
321 | "domain-browser": "1.1.7",
322 | "duplexer2": "0.1.4",
323 | "events": "1.1.1",
324 | "glob": "7.1.2",
325 | "has": "1.0.1",
326 | "htmlescape": "1.1.1",
327 | "https-browserify": "1.0.0",
328 | "inherits": "2.0.3",
329 | "insert-module-globals": "7.0.1",
330 | "labeled-stream-splicer": "2.0.0",
331 | "module-deps": "4.1.1",
332 | "os-browserify": "0.3.0",
333 | "parents": "1.0.1",
334 | "path-browserify": "0.0.0",
335 | "process": "0.11.10",
336 | "punycode": "1.4.1",
337 | "querystring-es3": "0.2.1",
338 | "read-only-stream": "2.0.0",
339 | "readable-stream": "2.3.3",
340 | "resolve": "1.5.0",
341 | "shasum": "1.0.2",
342 | "shell-quote": "1.6.1",
343 | "stream-browserify": "2.0.1",
344 | "stream-http": "2.7.2",
345 | "string_decoder": "1.0.3",
346 | "subarg": "1.0.0",
347 | "syntax-error": "1.3.0",
348 | "through2": "2.0.3",
349 | "timers-browserify": "1.4.2",
350 | "tty-browserify": "0.0.0",
351 | "url": "0.11.0",
352 | "util": "0.10.3",
353 | "vm-browserify": "0.0.4",
354 | "xtend": "4.0.1"
355 | }
356 | },
357 | "browserify-aes": {
358 | "version": "1.1.1",
359 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz",
360 | "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==",
361 | "dev": true,
362 | "requires": {
363 | "buffer-xor": "1.0.3",
364 | "cipher-base": "1.0.4",
365 | "create-hash": "1.1.3",
366 | "evp_bytestokey": "1.0.3",
367 | "inherits": "2.0.3",
368 | "safe-buffer": "5.1.1"
369 | }
370 | },
371 | "browserify-cipher": {
372 | "version": "1.0.0",
373 | "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz",
374 | "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=",
375 | "dev": true,
376 | "requires": {
377 | "browserify-aes": "1.1.1",
378 | "browserify-des": "1.0.0",
379 | "evp_bytestokey": "1.0.3"
380 | }
381 | },
382 | "browserify-des": {
383 | "version": "1.0.0",
384 | "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz",
385 | "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=",
386 | "dev": true,
387 | "requires": {
388 | "cipher-base": "1.0.4",
389 | "des.js": "1.0.0",
390 | "inherits": "2.0.3"
391 | }
392 | },
393 | "browserify-rsa": {
394 | "version": "4.0.1",
395 | "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
396 | "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
397 | "dev": true,
398 | "requires": {
399 | "bn.js": "4.11.8",
400 | "randombytes": "2.0.5"
401 | }
402 | },
403 | "browserify-sign": {
404 | "version": "4.0.4",
405 | "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
406 | "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
407 | "dev": true,
408 | "requires": {
409 | "bn.js": "4.11.8",
410 | "browserify-rsa": "4.0.1",
411 | "create-hash": "1.1.3",
412 | "create-hmac": "1.1.6",
413 | "elliptic": "6.4.0",
414 | "inherits": "2.0.3",
415 | "parse-asn1": "5.1.0"
416 | }
417 | },
418 | "browserify-zlib": {
419 | "version": "0.2.0",
420 | "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
421 | "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
422 | "dev": true,
423 | "requires": {
424 | "pako": "1.0.6"
425 | }
426 | },
427 | "buffer": {
428 | "version": "5.0.8",
429 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.0.8.tgz",
430 | "integrity": "sha512-xXvjQhVNz50v2nPeoOsNqWCLGfiv4ji/gXZM28jnVwdLJxH4mFyqgqCKfaK9zf1KUbG6zTkjLOy7ou+jSMarGA==",
431 | "dev": true,
432 | "requires": {
433 | "base64-js": "1.2.1",
434 | "ieee754": "1.1.8"
435 | }
436 | },
437 | "buffer-xor": {
438 | "version": "1.0.3",
439 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
440 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
441 | "dev": true
442 | },
443 | "builtin-status-codes": {
444 | "version": "3.0.0",
445 | "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
446 | "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
447 | "dev": true
448 | },
449 | "bytes": {
450 | "version": "3.0.0",
451 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
452 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
453 | "dev": true
454 | },
455 | "cached-path-relative": {
456 | "version": "1.0.1",
457 | "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz",
458 | "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=",
459 | "dev": true
460 | },
461 | "callsite": {
462 | "version": "1.0.0",
463 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
464 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
465 | "dev": true
466 | },
467 | "chalk": {
468 | "version": "2.3.0",
469 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
470 | "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
471 | "dev": true,
472 | "requires": {
473 | "ansi-styles": "3.2.0",
474 | "escape-string-regexp": "1.0.5",
475 | "supports-color": "4.5.0"
476 | }
477 | },
478 | "chokidar": {
479 | "version": "1.7.0",
480 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
481 | "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
482 | "dev": true,
483 | "requires": {
484 | "anymatch": "1.3.2",
485 | "async-each": "1.0.1",
486 | "glob-parent": "2.0.0",
487 | "inherits": "2.0.3",
488 | "is-binary-path": "1.0.1",
489 | "is-glob": "2.0.1",
490 | "path-is-absolute": "1.0.1",
491 | "readdirp": "2.1.0"
492 | }
493 | },
494 | "cipher-base": {
495 | "version": "1.0.4",
496 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
497 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
498 | "dev": true,
499 | "requires": {
500 | "inherits": "2.0.3",
501 | "safe-buffer": "5.1.1"
502 | }
503 | },
504 | "color-convert": {
505 | "version": "1.9.0",
506 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
507 | "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
508 | "dev": true,
509 | "requires": {
510 | "color-name": "1.1.3"
511 | }
512 | },
513 | "color-name": {
514 | "version": "1.1.3",
515 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
516 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
517 | "dev": true
518 | },
519 | "colors": {
520 | "version": "1.1.2",
521 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
522 | "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
523 | "dev": true
524 | },
525 | "combine-lists": {
526 | "version": "1.0.1",
527 | "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz",
528 | "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=",
529 | "dev": true,
530 | "requires": {
531 | "lodash": "4.17.4"
532 | },
533 | "dependencies": {
534 | "lodash": {
535 | "version": "4.17.4",
536 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
537 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
538 | "dev": true
539 | }
540 | }
541 | },
542 | "combine-source-map": {
543 | "version": "0.7.2",
544 | "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz",
545 | "integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=",
546 | "dev": true,
547 | "requires": {
548 | "convert-source-map": "1.1.3",
549 | "inline-source-map": "0.6.2",
550 | "lodash.memoize": "3.0.4",
551 | "source-map": "0.5.7"
552 | }
553 | },
554 | "component-bind": {
555 | "version": "1.0.0",
556 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
557 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
558 | "dev": true
559 | },
560 | "component-emitter": {
561 | "version": "1.1.2",
562 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz",
563 | "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=",
564 | "dev": true
565 | },
566 | "component-inherit": {
567 | "version": "0.0.3",
568 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
569 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
570 | "dev": true
571 | },
572 | "concat-map": {
573 | "version": "0.0.1",
574 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
575 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
576 | "dev": true
577 | },
578 | "concat-stream": {
579 | "version": "1.5.2",
580 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
581 | "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=",
582 | "dev": true,
583 | "requires": {
584 | "inherits": "2.0.3",
585 | "readable-stream": "2.0.6",
586 | "typedarray": "0.0.6"
587 | },
588 | "dependencies": {
589 | "readable-stream": {
590 | "version": "2.0.6",
591 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
592 | "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
593 | "dev": true,
594 | "requires": {
595 | "core-util-is": "1.0.2",
596 | "inherits": "2.0.3",
597 | "isarray": "1.0.0",
598 | "process-nextick-args": "1.0.7",
599 | "string_decoder": "0.10.31",
600 | "util-deprecate": "1.0.2"
601 | }
602 | },
603 | "string_decoder": {
604 | "version": "0.10.31",
605 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
606 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
607 | "dev": true
608 | }
609 | }
610 | },
611 | "connect": {
612 | "version": "3.6.5",
613 | "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz",
614 | "integrity": "sha1-+43ee6B2OHfQ7J352sC0tA5yx9o=",
615 | "dev": true,
616 | "requires": {
617 | "debug": "2.6.9",
618 | "finalhandler": "1.0.6",
619 | "parseurl": "1.3.2",
620 | "utils-merge": "1.0.1"
621 | }
622 | },
623 | "console-browserify": {
624 | "version": "1.1.0",
625 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
626 | "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
627 | "dev": true,
628 | "requires": {
629 | "date-now": "0.1.4"
630 | }
631 | },
632 | "constants-browserify": {
633 | "version": "1.0.0",
634 | "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
635 | "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
636 | "dev": true
637 | },
638 | "content-type": {
639 | "version": "1.0.4",
640 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
641 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
642 | "dev": true
643 | },
644 | "convert-source-map": {
645 | "version": "1.1.3",
646 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
647 | "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=",
648 | "dev": true
649 | },
650 | "cookie": {
651 | "version": "0.3.1",
652 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
653 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
654 | "dev": true
655 | },
656 | "core-js": {
657 | "version": "2.5.1",
658 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
659 | "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=",
660 | "dev": true
661 | },
662 | "core-util-is": {
663 | "version": "1.0.2",
664 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
665 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
666 | "dev": true
667 | },
668 | "create-ecdh": {
669 | "version": "4.0.0",
670 | "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
671 | "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=",
672 | "dev": true,
673 | "requires": {
674 | "bn.js": "4.11.8",
675 | "elliptic": "6.4.0"
676 | }
677 | },
678 | "create-hash": {
679 | "version": "1.1.3",
680 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
681 | "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=",
682 | "dev": true,
683 | "requires": {
684 | "cipher-base": "1.0.4",
685 | "inherits": "2.0.3",
686 | "ripemd160": "2.0.1",
687 | "sha.js": "2.4.9"
688 | }
689 | },
690 | "create-hmac": {
691 | "version": "1.1.6",
692 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
693 | "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=",
694 | "dev": true,
695 | "requires": {
696 | "cipher-base": "1.0.4",
697 | "create-hash": "1.1.3",
698 | "inherits": "2.0.3",
699 | "ripemd160": "2.0.1",
700 | "safe-buffer": "5.1.1",
701 | "sha.js": "2.4.9"
702 | }
703 | },
704 | "crypto-browserify": {
705 | "version": "3.11.1",
706 | "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz",
707 | "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==",
708 | "dev": true,
709 | "requires": {
710 | "browserify-cipher": "1.0.0",
711 | "browserify-sign": "4.0.4",
712 | "create-ecdh": "4.0.0",
713 | "create-hash": "1.1.3",
714 | "create-hmac": "1.1.6",
715 | "diffie-hellman": "5.0.2",
716 | "inherits": "2.0.3",
717 | "pbkdf2": "3.0.14",
718 | "public-encrypt": "4.0.0",
719 | "randombytes": "2.0.5"
720 | }
721 | },
722 | "custom-event": {
723 | "version": "1.0.1",
724 | "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
725 | "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
726 | "dev": true
727 | },
728 | "date-now": {
729 | "version": "0.1.4",
730 | "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
731 | "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
732 | "dev": true
733 | },
734 | "debug": {
735 | "version": "2.6.9",
736 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
737 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
738 | "requires": {
739 | "ms": "2.0.0"
740 | }
741 | },
742 | "define-properties": {
743 | "version": "1.1.2",
744 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
745 | "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
746 | "requires": {
747 | "foreach": "2.0.5",
748 | "object-keys": "1.0.11"
749 | }
750 | },
751 | "defined": {
752 | "version": "1.0.0",
753 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
754 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
755 | "dev": true
756 | },
757 | "depd": {
758 | "version": "1.1.1",
759 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
760 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=",
761 | "dev": true
762 | },
763 | "deps-sort": {
764 | "version": "2.0.0",
765 | "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
766 | "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=",
767 | "dev": true,
768 | "requires": {
769 | "JSONStream": "1.3.1",
770 | "shasum": "1.0.2",
771 | "subarg": "1.0.0",
772 | "through2": "2.0.3"
773 | }
774 | },
775 | "des.js": {
776 | "version": "1.0.0",
777 | "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
778 | "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
779 | "dev": true,
780 | "requires": {
781 | "inherits": "2.0.3",
782 | "minimalistic-assert": "1.0.0"
783 | }
784 | },
785 | "detective": {
786 | "version": "4.5.0",
787 | "resolved": "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz",
788 | "integrity": "sha1-blqMaybmx6JUsca210kNmOyR7dE=",
789 | "dev": true,
790 | "requires": {
791 | "acorn": "4.0.13",
792 | "defined": "1.0.0"
793 | }
794 | },
795 | "di": {
796 | "version": "0.0.1",
797 | "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
798 | "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
799 | "dev": true
800 | },
801 | "diffie-hellman": {
802 | "version": "5.0.2",
803 | "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
804 | "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=",
805 | "dev": true,
806 | "requires": {
807 | "bn.js": "4.11.8",
808 | "miller-rabin": "4.0.1",
809 | "randombytes": "2.0.5"
810 | }
811 | },
812 | "dom-serialize": {
813 | "version": "2.2.1",
814 | "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
815 | "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
816 | "dev": true,
817 | "requires": {
818 | "custom-event": "1.0.1",
819 | "ent": "2.2.0",
820 | "extend": "3.0.1",
821 | "void-elements": "2.0.1"
822 | }
823 | },
824 | "domain-browser": {
825 | "version": "1.1.7",
826 | "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
827 | "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=",
828 | "dev": true
829 | },
830 | "duplexer2": {
831 | "version": "0.1.4",
832 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
833 | "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
834 | "dev": true,
835 | "requires": {
836 | "readable-stream": "2.3.3"
837 | }
838 | },
839 | "ee-first": {
840 | "version": "1.1.1",
841 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
842 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
843 | "dev": true
844 | },
845 | "elliptic": {
846 | "version": "6.4.0",
847 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
848 | "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
849 | "dev": true,
850 | "requires": {
851 | "bn.js": "4.11.8",
852 | "brorand": "1.1.0",
853 | "hash.js": "1.1.3",
854 | "hmac-drbg": "1.0.1",
855 | "inherits": "2.0.3",
856 | "minimalistic-assert": "1.0.0",
857 | "minimalistic-crypto-utils": "1.0.1"
858 | }
859 | },
860 | "encodeurl": {
861 | "version": "1.0.1",
862 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
863 | "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=",
864 | "dev": true
865 | },
866 | "engine.io": {
867 | "version": "1.8.3",
868 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.3.tgz",
869 | "integrity": "sha1-jef5eJXSDTm4X4ju7nd7K9QrE9Q=",
870 | "dev": true,
871 | "requires": {
872 | "accepts": "1.3.3",
873 | "base64id": "1.0.0",
874 | "cookie": "0.3.1",
875 | "debug": "2.3.3",
876 | "engine.io-parser": "1.3.2",
877 | "ws": "1.1.2"
878 | },
879 | "dependencies": {
880 | "debug": {
881 | "version": "2.3.3",
882 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
883 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
884 | "dev": true,
885 | "requires": {
886 | "ms": "0.7.2"
887 | }
888 | },
889 | "ms": {
890 | "version": "0.7.2",
891 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
892 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
893 | "dev": true
894 | }
895 | }
896 | },
897 | "engine.io-client": {
898 | "version": "1.8.3",
899 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.3.tgz",
900 | "integrity": "sha1-F5jtk0USRkU9TG9jXXogH+lA1as=",
901 | "dev": true,
902 | "requires": {
903 | "component-emitter": "1.2.1",
904 | "component-inherit": "0.0.3",
905 | "debug": "2.3.3",
906 | "engine.io-parser": "1.3.2",
907 | "has-cors": "1.1.0",
908 | "indexof": "0.0.1",
909 | "parsejson": "0.0.3",
910 | "parseqs": "0.0.5",
911 | "parseuri": "0.0.5",
912 | "ws": "1.1.2",
913 | "xmlhttprequest-ssl": "1.5.3",
914 | "yeast": "0.1.2"
915 | },
916 | "dependencies": {
917 | "component-emitter": {
918 | "version": "1.2.1",
919 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
920 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
921 | "dev": true
922 | },
923 | "debug": {
924 | "version": "2.3.3",
925 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
926 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
927 | "dev": true,
928 | "requires": {
929 | "ms": "0.7.2"
930 | }
931 | },
932 | "ms": {
933 | "version": "0.7.2",
934 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
935 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
936 | "dev": true
937 | }
938 | }
939 | },
940 | "engine.io-parser": {
941 | "version": "1.3.2",
942 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz",
943 | "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=",
944 | "dev": true,
945 | "requires": {
946 | "after": "0.8.2",
947 | "arraybuffer.slice": "0.0.6",
948 | "base64-arraybuffer": "0.1.5",
949 | "blob": "0.0.4",
950 | "has-binary": "0.1.7",
951 | "wtf-8": "1.0.0"
952 | }
953 | },
954 | "ent": {
955 | "version": "2.2.0",
956 | "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
957 | "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
958 | "dev": true
959 | },
960 | "es-abstract": {
961 | "version": "1.9.0",
962 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz",
963 | "integrity": "sha512-kk3IJoKo7A3pWJc0OV8yZ/VEX2oSUytfekrJiqoxBlKJMFAJVJVpGdHClCCTdv+Fn2zHfpDHHIelMFhZVfef3Q==",
964 | "requires": {
965 | "es-to-primitive": "1.1.1",
966 | "function-bind": "1.1.1",
967 | "has": "1.0.1",
968 | "is-callable": "1.1.3",
969 | "is-regex": "1.0.4"
970 | }
971 | },
972 | "es-to-primitive": {
973 | "version": "1.1.1",
974 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
975 | "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
976 | "requires": {
977 | "is-callable": "1.1.3",
978 | "is-date-object": "1.0.1",
979 | "is-symbol": "1.0.1"
980 | }
981 | },
982 | "escape-html": {
983 | "version": "1.0.3",
984 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
985 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
986 | "dev": true
987 | },
988 | "escape-string-regexp": {
989 | "version": "1.0.5",
990 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
991 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
992 | "dev": true
993 | },
994 | "eventemitter3": {
995 | "version": "1.2.0",
996 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
997 | "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=",
998 | "dev": true
999 | },
1000 | "events": {
1001 | "version": "1.1.1",
1002 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
1003 | "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
1004 | "dev": true
1005 | },
1006 | "evp_bytestokey": {
1007 | "version": "1.0.3",
1008 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
1009 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
1010 | "dev": true,
1011 | "requires": {
1012 | "md5.js": "1.3.4",
1013 | "safe-buffer": "5.1.1"
1014 | }
1015 | },
1016 | "expand-braces": {
1017 | "version": "0.1.2",
1018 | "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz",
1019 | "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=",
1020 | "dev": true,
1021 | "requires": {
1022 | "array-slice": "0.2.3",
1023 | "array-unique": "0.2.1",
1024 | "braces": "0.1.5"
1025 | },
1026 | "dependencies": {
1027 | "braces": {
1028 | "version": "0.1.5",
1029 | "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz",
1030 | "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=",
1031 | "dev": true,
1032 | "requires": {
1033 | "expand-range": "0.1.1"
1034 | }
1035 | },
1036 | "expand-range": {
1037 | "version": "0.1.1",
1038 | "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz",
1039 | "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=",
1040 | "dev": true,
1041 | "requires": {
1042 | "is-number": "0.1.1",
1043 | "repeat-string": "0.2.2"
1044 | }
1045 | },
1046 | "is-number": {
1047 | "version": "0.1.1",
1048 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz",
1049 | "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=",
1050 | "dev": true
1051 | },
1052 | "repeat-string": {
1053 | "version": "0.2.2",
1054 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz",
1055 | "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=",
1056 | "dev": true
1057 | }
1058 | }
1059 | },
1060 | "expand-brackets": {
1061 | "version": "0.1.5",
1062 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
1063 | "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
1064 | "dev": true,
1065 | "requires": {
1066 | "is-posix-bracket": "0.1.1"
1067 | }
1068 | },
1069 | "expand-range": {
1070 | "version": "1.8.2",
1071 | "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
1072 | "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
1073 | "dev": true,
1074 | "requires": {
1075 | "fill-range": "2.2.3"
1076 | }
1077 | },
1078 | "extend": {
1079 | "version": "3.0.1",
1080 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
1081 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
1082 | "dev": true
1083 | },
1084 | "extglob": {
1085 | "version": "0.3.2",
1086 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
1087 | "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
1088 | "dev": true,
1089 | "requires": {
1090 | "is-extglob": "1.0.0"
1091 | }
1092 | },
1093 | "filename-regex": {
1094 | "version": "2.0.1",
1095 | "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
1096 | "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
1097 | "dev": true
1098 | },
1099 | "fill-range": {
1100 | "version": "2.2.3",
1101 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
1102 | "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
1103 | "dev": true,
1104 | "requires": {
1105 | "is-number": "2.1.0",
1106 | "isobject": "2.1.0",
1107 | "randomatic": "1.1.7",
1108 | "repeat-element": "1.1.2",
1109 | "repeat-string": "1.6.1"
1110 | }
1111 | },
1112 | "finalhandler": {
1113 | "version": "1.0.6",
1114 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz",
1115 | "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=",
1116 | "dev": true,
1117 | "requires": {
1118 | "debug": "2.6.9",
1119 | "encodeurl": "1.0.1",
1120 | "escape-html": "1.0.3",
1121 | "on-finished": "2.3.0",
1122 | "parseurl": "1.3.2",
1123 | "statuses": "1.3.1",
1124 | "unpipe": "1.0.0"
1125 | },
1126 | "dependencies": {
1127 | "statuses": {
1128 | "version": "1.3.1",
1129 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
1130 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=",
1131 | "dev": true
1132 | }
1133 | }
1134 | },
1135 | "follow-redirects": {
1136 | "version": "1.2.5",
1137 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.2.5.tgz",
1138 | "integrity": "sha512-lMhwQTryFbG+wYsAIEKC1Kf5IGDlVNnONRogIBllh7LLoV7pNIxW0z9fhjRar9NBql+hd2Y49KboVVNxf6GEfg==",
1139 | "requires": {
1140 | "debug": "2.6.9"
1141 | }
1142 | },
1143 | "for-in": {
1144 | "version": "1.0.2",
1145 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
1146 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
1147 | "dev": true
1148 | },
1149 | "for-own": {
1150 | "version": "0.1.5",
1151 | "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
1152 | "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
1153 | "dev": true,
1154 | "requires": {
1155 | "for-in": "1.0.2"
1156 | }
1157 | },
1158 | "foreach": {
1159 | "version": "2.0.5",
1160 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
1161 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
1162 | },
1163 | "fs-access": {
1164 | "version": "1.0.1",
1165 | "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz",
1166 | "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=",
1167 | "dev": true,
1168 | "requires": {
1169 | "null-check": "1.0.0"
1170 | }
1171 | },
1172 | "fs.realpath": {
1173 | "version": "1.0.0",
1174 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
1175 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
1176 | "dev": true
1177 | },
1178 | "function-bind": {
1179 | "version": "1.1.1",
1180 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
1181 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
1182 | },
1183 | "glob": {
1184 | "version": "7.1.2",
1185 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
1186 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
1187 | "dev": true,
1188 | "requires": {
1189 | "fs.realpath": "1.0.0",
1190 | "inflight": "1.0.6",
1191 | "inherits": "2.0.3",
1192 | "minimatch": "3.0.4",
1193 | "once": "1.4.0",
1194 | "path-is-absolute": "1.0.1"
1195 | }
1196 | },
1197 | "glob-base": {
1198 | "version": "0.3.0",
1199 | "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
1200 | "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
1201 | "dev": true,
1202 | "requires": {
1203 | "glob-parent": "2.0.0",
1204 | "is-glob": "2.0.1"
1205 | }
1206 | },
1207 | "glob-parent": {
1208 | "version": "2.0.0",
1209 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
1210 | "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
1211 | "dev": true,
1212 | "requires": {
1213 | "is-glob": "2.0.1"
1214 | }
1215 | },
1216 | "graceful-fs": {
1217 | "version": "4.1.11",
1218 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
1219 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
1220 | "dev": true
1221 | },
1222 | "has": {
1223 | "version": "1.0.1",
1224 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
1225 | "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=",
1226 | "requires": {
1227 | "function-bind": "1.1.1"
1228 | }
1229 | },
1230 | "has-binary": {
1231 | "version": "0.1.7",
1232 | "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz",
1233 | "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=",
1234 | "dev": true,
1235 | "requires": {
1236 | "isarray": "0.0.1"
1237 | },
1238 | "dependencies": {
1239 | "isarray": {
1240 | "version": "0.0.1",
1241 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
1242 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
1243 | "dev": true
1244 | }
1245 | }
1246 | },
1247 | "has-cors": {
1248 | "version": "1.1.0",
1249 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
1250 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
1251 | "dev": true
1252 | },
1253 | "has-flag": {
1254 | "version": "2.0.0",
1255 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
1256 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
1257 | "dev": true
1258 | },
1259 | "hash-base": {
1260 | "version": "2.0.2",
1261 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
1262 | "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=",
1263 | "dev": true,
1264 | "requires": {
1265 | "inherits": "2.0.3"
1266 | }
1267 | },
1268 | "hash.js": {
1269 | "version": "1.1.3",
1270 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
1271 | "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
1272 | "dev": true,
1273 | "requires": {
1274 | "inherits": "2.0.3",
1275 | "minimalistic-assert": "1.0.0"
1276 | }
1277 | },
1278 | "hat": {
1279 | "version": "0.0.3",
1280 | "resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz",
1281 | "integrity": "sha1-uwFKnmSzeIrtgAWRdBPU/z1QLYo=",
1282 | "dev": true
1283 | },
1284 | "hmac-drbg": {
1285 | "version": "1.0.1",
1286 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
1287 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
1288 | "dev": true,
1289 | "requires": {
1290 | "hash.js": "1.1.3",
1291 | "minimalistic-assert": "1.0.0",
1292 | "minimalistic-crypto-utils": "1.0.1"
1293 | }
1294 | },
1295 | "htmlescape": {
1296 | "version": "1.1.1",
1297 | "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
1298 | "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=",
1299 | "dev": true
1300 | },
1301 | "http-errors": {
1302 | "version": "1.6.2",
1303 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
1304 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
1305 | "dev": true,
1306 | "requires": {
1307 | "depd": "1.1.1",
1308 | "inherits": "2.0.3",
1309 | "setprototypeof": "1.0.3",
1310 | "statuses": "1.4.0"
1311 | }
1312 | },
1313 | "http-proxy": {
1314 | "version": "1.16.2",
1315 | "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz",
1316 | "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=",
1317 | "dev": true,
1318 | "requires": {
1319 | "eventemitter3": "1.2.0",
1320 | "requires-port": "1.0.0"
1321 | }
1322 | },
1323 | "https-browserify": {
1324 | "version": "1.0.0",
1325 | "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
1326 | "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
1327 | "dev": true
1328 | },
1329 | "iconv-lite": {
1330 | "version": "0.4.19",
1331 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
1332 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==",
1333 | "dev": true
1334 | },
1335 | "ieee754": {
1336 | "version": "1.1.8",
1337 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
1338 | "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=",
1339 | "dev": true
1340 | },
1341 | "indexof": {
1342 | "version": "0.0.1",
1343 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
1344 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
1345 | "dev": true
1346 | },
1347 | "inflight": {
1348 | "version": "1.0.6",
1349 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
1350 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
1351 | "dev": true,
1352 | "requires": {
1353 | "once": "1.4.0",
1354 | "wrappy": "1.0.2"
1355 | }
1356 | },
1357 | "inherits": {
1358 | "version": "2.0.3",
1359 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
1360 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
1361 | "dev": true
1362 | },
1363 | "inline-source-map": {
1364 | "version": "0.6.2",
1365 | "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
1366 | "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=",
1367 | "dev": true,
1368 | "requires": {
1369 | "source-map": "0.5.7"
1370 | }
1371 | },
1372 | "insert-module-globals": {
1373 | "version": "7.0.1",
1374 | "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz",
1375 | "integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=",
1376 | "dev": true,
1377 | "requires": {
1378 | "JSONStream": "1.3.1",
1379 | "combine-source-map": "0.7.2",
1380 | "concat-stream": "1.5.2",
1381 | "is-buffer": "1.1.6",
1382 | "lexical-scope": "1.2.0",
1383 | "process": "0.11.10",
1384 | "through2": "2.0.3",
1385 | "xtend": "4.0.1"
1386 | }
1387 | },
1388 | "is-binary-path": {
1389 | "version": "1.0.1",
1390 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
1391 | "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
1392 | "dev": true,
1393 | "requires": {
1394 | "binary-extensions": "1.10.0"
1395 | }
1396 | },
1397 | "is-buffer": {
1398 | "version": "1.1.6",
1399 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
1400 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
1401 | },
1402 | "is-callable": {
1403 | "version": "1.1.3",
1404 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
1405 | "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI="
1406 | },
1407 | "is-date-object": {
1408 | "version": "1.0.1",
1409 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
1410 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
1411 | },
1412 | "is-dotfile": {
1413 | "version": "1.0.3",
1414 | "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
1415 | "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
1416 | "dev": true
1417 | },
1418 | "is-equal-shallow": {
1419 | "version": "0.1.3",
1420 | "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
1421 | "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
1422 | "dev": true,
1423 | "requires": {
1424 | "is-primitive": "2.0.0"
1425 | }
1426 | },
1427 | "is-extendable": {
1428 | "version": "0.1.1",
1429 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
1430 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
1431 | "dev": true
1432 | },
1433 | "is-extglob": {
1434 | "version": "1.0.0",
1435 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
1436 | "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
1437 | "dev": true
1438 | },
1439 | "is-glob": {
1440 | "version": "2.0.1",
1441 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
1442 | "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
1443 | "dev": true,
1444 | "requires": {
1445 | "is-extglob": "1.0.0"
1446 | }
1447 | },
1448 | "is-number": {
1449 | "version": "2.1.0",
1450 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
1451 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
1452 | "dev": true,
1453 | "requires": {
1454 | "kind-of": "3.2.2"
1455 | }
1456 | },
1457 | "is-posix-bracket": {
1458 | "version": "0.1.1",
1459 | "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
1460 | "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
1461 | "dev": true
1462 | },
1463 | "is-primitive": {
1464 | "version": "2.0.0",
1465 | "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
1466 | "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
1467 | "dev": true
1468 | },
1469 | "is-regex": {
1470 | "version": "1.0.4",
1471 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
1472 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
1473 | "requires": {
1474 | "has": "1.0.1"
1475 | }
1476 | },
1477 | "is-symbol": {
1478 | "version": "1.0.1",
1479 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
1480 | "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI="
1481 | },
1482 | "isarray": {
1483 | "version": "1.0.0",
1484 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
1485 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
1486 | "dev": true
1487 | },
1488 | "isbinaryfile": {
1489 | "version": "3.0.2",
1490 | "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz",
1491 | "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=",
1492 | "dev": true
1493 | },
1494 | "isexe": {
1495 | "version": "2.0.0",
1496 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1497 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
1498 | "dev": true
1499 | },
1500 | "isobject": {
1501 | "version": "2.1.0",
1502 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
1503 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
1504 | "dev": true,
1505 | "requires": {
1506 | "isarray": "1.0.0"
1507 | }
1508 | },
1509 | "jasmine-core": {
1510 | "version": "2.8.0",
1511 | "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz",
1512 | "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=",
1513 | "dev": true
1514 | },
1515 | "js-string-escape": {
1516 | "version": "1.0.1",
1517 | "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
1518 | "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=",
1519 | "dev": true
1520 | },
1521 | "json-stable-stringify": {
1522 | "version": "0.0.1",
1523 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
1524 | "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=",
1525 | "dev": true,
1526 | "requires": {
1527 | "jsonify": "0.0.0"
1528 | }
1529 | },
1530 | "json3": {
1531 | "version": "3.3.2",
1532 | "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
1533 | "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=",
1534 | "dev": true
1535 | },
1536 | "jsonify": {
1537 | "version": "0.0.0",
1538 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
1539 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
1540 | "dev": true
1541 | },
1542 | "jsonparse": {
1543 | "version": "1.3.1",
1544 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
1545 | "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
1546 | "dev": true
1547 | },
1548 | "karma": {
1549 | "version": "1.7.1",
1550 | "resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz",
1551 | "integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==",
1552 | "dev": true,
1553 | "requires": {
1554 | "bluebird": "3.5.1",
1555 | "body-parser": "1.18.2",
1556 | "chokidar": "1.7.0",
1557 | "colors": "1.1.2",
1558 | "combine-lists": "1.0.1",
1559 | "connect": "3.6.5",
1560 | "core-js": "2.5.1",
1561 | "di": "0.0.1",
1562 | "dom-serialize": "2.2.1",
1563 | "expand-braces": "0.1.2",
1564 | "glob": "7.1.2",
1565 | "graceful-fs": "4.1.11",
1566 | "http-proxy": "1.16.2",
1567 | "isbinaryfile": "3.0.2",
1568 | "lodash": "3.10.1",
1569 | "log4js": "0.6.38",
1570 | "mime": "1.4.1",
1571 | "minimatch": "3.0.4",
1572 | "optimist": "0.6.1",
1573 | "qjobs": "1.1.5",
1574 | "range-parser": "1.2.0",
1575 | "rimraf": "2.6.2",
1576 | "safe-buffer": "5.1.1",
1577 | "socket.io": "1.7.3",
1578 | "source-map": "0.5.7",
1579 | "tmp": "0.0.31",
1580 | "useragent": "2.2.1"
1581 | },
1582 | "dependencies": {
1583 | "lodash": {
1584 | "version": "3.10.1",
1585 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
1586 | "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
1587 | "dev": true
1588 | }
1589 | }
1590 | },
1591 | "karma-browserify": {
1592 | "version": "5.1.1",
1593 | "resolved": "https://registry.npmjs.org/karma-browserify/-/karma-browserify-5.1.1.tgz",
1594 | "integrity": "sha1-9kLXDXdtmrO3NSbFcyq8/qJAAxk=",
1595 | "dev": true,
1596 | "requires": {
1597 | "convert-source-map": "1.1.3",
1598 | "hat": "0.0.3",
1599 | "js-string-escape": "1.0.1",
1600 | "lodash": "3.10.1",
1601 | "minimatch": "3.0.4",
1602 | "os-shim": "0.1.3"
1603 | },
1604 | "dependencies": {
1605 | "lodash": {
1606 | "version": "3.10.1",
1607 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
1608 | "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
1609 | "dev": true
1610 | }
1611 | }
1612 | },
1613 | "karma-chrome-launcher": {
1614 | "version": "2.2.0",
1615 | "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz",
1616 | "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==",
1617 | "dev": true,
1618 | "requires": {
1619 | "fs-access": "1.0.1",
1620 | "which": "1.3.0"
1621 | }
1622 | },
1623 | "karma-jasmine": {
1624 | "version": "1.1.0",
1625 | "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.0.tgz",
1626 | "integrity": "sha1-IuTAa/mhguUpTR9wXjczgRuBCs8=",
1627 | "dev": true
1628 | },
1629 | "karma-mocha-reporter": {
1630 | "version": "2.2.5",
1631 | "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz",
1632 | "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=",
1633 | "dev": true,
1634 | "requires": {
1635 | "chalk": "2.3.0",
1636 | "log-symbols": "2.1.0",
1637 | "strip-ansi": "4.0.0"
1638 | }
1639 | },
1640 | "kind-of": {
1641 | "version": "3.2.2",
1642 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1643 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1644 | "dev": true,
1645 | "requires": {
1646 | "is-buffer": "1.1.6"
1647 | }
1648 | },
1649 | "labeled-stream-splicer": {
1650 | "version": "2.0.0",
1651 | "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz",
1652 | "integrity": "sha1-pS4dE4AkwAuGscDJH2d5GLiuClk=",
1653 | "dev": true,
1654 | "requires": {
1655 | "inherits": "2.0.3",
1656 | "isarray": "0.0.1",
1657 | "stream-splicer": "2.0.0"
1658 | },
1659 | "dependencies": {
1660 | "isarray": {
1661 | "version": "0.0.1",
1662 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
1663 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
1664 | "dev": true
1665 | }
1666 | }
1667 | },
1668 | "lexical-scope": {
1669 | "version": "1.2.0",
1670 | "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz",
1671 | "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=",
1672 | "dev": true,
1673 | "requires": {
1674 | "astw": "2.2.0"
1675 | }
1676 | },
1677 | "lodash": {
1678 | "version": "4.17.4",
1679 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
1680 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
1681 | },
1682 | "lodash.memoize": {
1683 | "version": "3.0.4",
1684 | "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
1685 | "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=",
1686 | "dev": true
1687 | },
1688 | "log-symbols": {
1689 | "version": "2.1.0",
1690 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.1.0.tgz",
1691 | "integrity": "sha512-zLeLrzMA1A2vRF1e/0Mo+LNINzi6jzBylHj5WqvQ/WK/5WCZt8si9SyN4p9llr/HRYvVR1AoXHRHl4WTHyQAzQ==",
1692 | "dev": true,
1693 | "requires": {
1694 | "chalk": "2.3.0"
1695 | }
1696 | },
1697 | "log4js": {
1698 | "version": "0.6.38",
1699 | "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz",
1700 | "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=",
1701 | "dev": true,
1702 | "requires": {
1703 | "readable-stream": "1.0.34",
1704 | "semver": "4.3.6"
1705 | },
1706 | "dependencies": {
1707 | "isarray": {
1708 | "version": "0.0.1",
1709 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
1710 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
1711 | "dev": true
1712 | },
1713 | "readable-stream": {
1714 | "version": "1.0.34",
1715 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
1716 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
1717 | "dev": true,
1718 | "requires": {
1719 | "core-util-is": "1.0.2",
1720 | "inherits": "2.0.3",
1721 | "isarray": "0.0.1",
1722 | "string_decoder": "0.10.31"
1723 | }
1724 | },
1725 | "string_decoder": {
1726 | "version": "0.10.31",
1727 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
1728 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
1729 | "dev": true
1730 | }
1731 | }
1732 | },
1733 | "lru-cache": {
1734 | "version": "2.2.4",
1735 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz",
1736 | "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=",
1737 | "dev": true
1738 | },
1739 | "md5.js": {
1740 | "version": "1.3.4",
1741 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
1742 | "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=",
1743 | "dev": true,
1744 | "requires": {
1745 | "hash-base": "3.0.4",
1746 | "inherits": "2.0.3"
1747 | },
1748 | "dependencies": {
1749 | "hash-base": {
1750 | "version": "3.0.4",
1751 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
1752 | "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
1753 | "dev": true,
1754 | "requires": {
1755 | "inherits": "2.0.3",
1756 | "safe-buffer": "5.1.1"
1757 | }
1758 | }
1759 | }
1760 | },
1761 | "media-typer": {
1762 | "version": "0.3.0",
1763 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1764 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
1765 | "dev": true
1766 | },
1767 | "micromatch": {
1768 | "version": "2.3.11",
1769 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
1770 | "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
1771 | "dev": true,
1772 | "requires": {
1773 | "arr-diff": "2.0.0",
1774 | "array-unique": "0.2.1",
1775 | "braces": "1.8.5",
1776 | "expand-brackets": "0.1.5",
1777 | "extglob": "0.3.2",
1778 | "filename-regex": "2.0.1",
1779 | "is-extglob": "1.0.0",
1780 | "is-glob": "2.0.1",
1781 | "kind-of": "3.2.2",
1782 | "normalize-path": "2.1.1",
1783 | "object.omit": "2.0.1",
1784 | "parse-glob": "3.0.4",
1785 | "regex-cache": "0.4.4"
1786 | }
1787 | },
1788 | "miller-rabin": {
1789 | "version": "4.0.1",
1790 | "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
1791 | "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
1792 | "dev": true,
1793 | "requires": {
1794 | "bn.js": "4.11.8",
1795 | "brorand": "1.1.0"
1796 | }
1797 | },
1798 | "mime": {
1799 | "version": "1.4.1",
1800 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
1801 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==",
1802 | "dev": true
1803 | },
1804 | "mime-db": {
1805 | "version": "1.30.0",
1806 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
1807 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=",
1808 | "dev": true
1809 | },
1810 | "mime-types": {
1811 | "version": "2.1.17",
1812 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
1813 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
1814 | "dev": true,
1815 | "requires": {
1816 | "mime-db": "1.30.0"
1817 | }
1818 | },
1819 | "minimalistic-assert": {
1820 | "version": "1.0.0",
1821 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
1822 | "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=",
1823 | "dev": true
1824 | },
1825 | "minimalistic-crypto-utils": {
1826 | "version": "1.0.1",
1827 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
1828 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
1829 | "dev": true
1830 | },
1831 | "minimatch": {
1832 | "version": "3.0.4",
1833 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1834 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1835 | "dev": true,
1836 | "requires": {
1837 | "brace-expansion": "1.1.8"
1838 | }
1839 | },
1840 | "minimist": {
1841 | "version": "0.0.10",
1842 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
1843 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
1844 | "dev": true
1845 | },
1846 | "module-deps": {
1847 | "version": "4.1.1",
1848 | "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz",
1849 | "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=",
1850 | "dev": true,
1851 | "requires": {
1852 | "JSONStream": "1.3.1",
1853 | "browser-resolve": "1.11.2",
1854 | "cached-path-relative": "1.0.1",
1855 | "concat-stream": "1.5.2",
1856 | "defined": "1.0.0",
1857 | "detective": "4.5.0",
1858 | "duplexer2": "0.1.4",
1859 | "inherits": "2.0.3",
1860 | "parents": "1.0.1",
1861 | "readable-stream": "2.3.3",
1862 | "resolve": "1.5.0",
1863 | "stream-combiner2": "1.1.1",
1864 | "subarg": "1.0.0",
1865 | "through2": "2.0.3",
1866 | "xtend": "4.0.1"
1867 | }
1868 | },
1869 | "ms": {
1870 | "version": "2.0.0",
1871 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1872 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
1873 | },
1874 | "negotiator": {
1875 | "version": "0.6.1",
1876 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
1877 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
1878 | "dev": true
1879 | },
1880 | "normalize-path": {
1881 | "version": "2.1.1",
1882 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
1883 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
1884 | "dev": true,
1885 | "requires": {
1886 | "remove-trailing-separator": "1.1.0"
1887 | }
1888 | },
1889 | "null-check": {
1890 | "version": "1.0.0",
1891 | "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz",
1892 | "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=",
1893 | "dev": true
1894 | },
1895 | "object-assign": {
1896 | "version": "4.1.0",
1897 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
1898 | "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=",
1899 | "dev": true
1900 | },
1901 | "object-component": {
1902 | "version": "0.0.3",
1903 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
1904 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
1905 | "dev": true
1906 | },
1907 | "object-keys": {
1908 | "version": "1.0.11",
1909 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
1910 | "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0="
1911 | },
1912 | "object.omit": {
1913 | "version": "2.0.1",
1914 | "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
1915 | "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
1916 | "dev": true,
1917 | "requires": {
1918 | "for-own": "0.1.5",
1919 | "is-extendable": "0.1.1"
1920 | }
1921 | },
1922 | "on-finished": {
1923 | "version": "2.3.0",
1924 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
1925 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
1926 | "dev": true,
1927 | "requires": {
1928 | "ee-first": "1.1.1"
1929 | }
1930 | },
1931 | "once": {
1932 | "version": "1.4.0",
1933 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1934 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1935 | "dev": true,
1936 | "requires": {
1937 | "wrappy": "1.0.2"
1938 | }
1939 | },
1940 | "optimist": {
1941 | "version": "0.6.1",
1942 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
1943 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
1944 | "dev": true,
1945 | "requires": {
1946 | "minimist": "0.0.10",
1947 | "wordwrap": "0.0.3"
1948 | }
1949 | },
1950 | "options": {
1951 | "version": "0.0.6",
1952 | "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
1953 | "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=",
1954 | "dev": true
1955 | },
1956 | "os-browserify": {
1957 | "version": "0.3.0",
1958 | "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
1959 | "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
1960 | "dev": true
1961 | },
1962 | "os-shim": {
1963 | "version": "0.1.3",
1964 | "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz",
1965 | "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=",
1966 | "dev": true
1967 | },
1968 | "os-tmpdir": {
1969 | "version": "1.0.2",
1970 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
1971 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
1972 | "dev": true
1973 | },
1974 | "outpipe": {
1975 | "version": "1.1.1",
1976 | "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz",
1977 | "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=",
1978 | "dev": true,
1979 | "requires": {
1980 | "shell-quote": "1.6.1"
1981 | }
1982 | },
1983 | "pako": {
1984 | "version": "1.0.6",
1985 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
1986 | "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==",
1987 | "dev": true
1988 | },
1989 | "parents": {
1990 | "version": "1.0.1",
1991 | "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
1992 | "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=",
1993 | "dev": true,
1994 | "requires": {
1995 | "path-platform": "0.11.15"
1996 | }
1997 | },
1998 | "parse-asn1": {
1999 | "version": "5.1.0",
2000 | "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz",
2001 | "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=",
2002 | "dev": true,
2003 | "requires": {
2004 | "asn1.js": "4.9.1",
2005 | "browserify-aes": "1.1.1",
2006 | "create-hash": "1.1.3",
2007 | "evp_bytestokey": "1.0.3",
2008 | "pbkdf2": "3.0.14"
2009 | }
2010 | },
2011 | "parse-glob": {
2012 | "version": "3.0.4",
2013 | "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
2014 | "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
2015 | "dev": true,
2016 | "requires": {
2017 | "glob-base": "0.3.0",
2018 | "is-dotfile": "1.0.3",
2019 | "is-extglob": "1.0.0",
2020 | "is-glob": "2.0.1"
2021 | }
2022 | },
2023 | "parsejson": {
2024 | "version": "0.0.3",
2025 | "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz",
2026 | "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=",
2027 | "dev": true,
2028 | "requires": {
2029 | "better-assert": "1.0.2"
2030 | }
2031 | },
2032 | "parseqs": {
2033 | "version": "0.0.5",
2034 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
2035 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
2036 | "dev": true,
2037 | "requires": {
2038 | "better-assert": "1.0.2"
2039 | }
2040 | },
2041 | "parseuri": {
2042 | "version": "0.0.5",
2043 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
2044 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
2045 | "dev": true,
2046 | "requires": {
2047 | "better-assert": "1.0.2"
2048 | }
2049 | },
2050 | "parseurl": {
2051 | "version": "1.3.2",
2052 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
2053 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=",
2054 | "dev": true
2055 | },
2056 | "path-browserify": {
2057 | "version": "0.0.0",
2058 | "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
2059 | "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
2060 | "dev": true
2061 | },
2062 | "path-is-absolute": {
2063 | "version": "1.0.1",
2064 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
2065 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
2066 | "dev": true
2067 | },
2068 | "path-parse": {
2069 | "version": "1.0.5",
2070 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
2071 | "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
2072 | "dev": true
2073 | },
2074 | "path-platform": {
2075 | "version": "0.11.15",
2076 | "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
2077 | "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=",
2078 | "dev": true
2079 | },
2080 | "pbkdf2": {
2081 | "version": "3.0.14",
2082 | "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz",
2083 | "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==",
2084 | "dev": true,
2085 | "requires": {
2086 | "create-hash": "1.1.3",
2087 | "create-hmac": "1.1.6",
2088 | "ripemd160": "2.0.1",
2089 | "safe-buffer": "5.1.1",
2090 | "sha.js": "2.4.9"
2091 | }
2092 | },
2093 | "preserve": {
2094 | "version": "0.2.0",
2095 | "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
2096 | "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
2097 | "dev": true
2098 | },
2099 | "process": {
2100 | "version": "0.11.10",
2101 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
2102 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
2103 | "dev": true
2104 | },
2105 | "process-nextick-args": {
2106 | "version": "1.0.7",
2107 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
2108 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
2109 | "dev": true
2110 | },
2111 | "promise": {
2112 | "version": "8.0.1",
2113 | "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.1.tgz",
2114 | "integrity": "sha1-5F1osAoXZHttpxG/he1u1HII9FA=",
2115 | "requires": {
2116 | "asap": "2.0.6"
2117 | }
2118 | },
2119 | "promise.prototype.finally": {
2120 | "version": "3.1.0",
2121 | "resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz",
2122 | "integrity": "sha512-7p/K2f6dI+dM8yjRQEGrTQs5hTQixUAdOGpMEA3+pVxpX5oHKRSKAXyLw9Q9HUWDTdwtoo39dSHGQtN90HcEwQ==",
2123 | "requires": {
2124 | "define-properties": "1.1.2",
2125 | "es-abstract": "1.9.0",
2126 | "function-bind": "1.1.1"
2127 | }
2128 | },
2129 | "public-encrypt": {
2130 | "version": "4.0.0",
2131 | "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz",
2132 | "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=",
2133 | "dev": true,
2134 | "requires": {
2135 | "bn.js": "4.11.8",
2136 | "browserify-rsa": "4.0.1",
2137 | "create-hash": "1.1.3",
2138 | "parse-asn1": "5.1.0",
2139 | "randombytes": "2.0.5"
2140 | }
2141 | },
2142 | "punycode": {
2143 | "version": "1.4.1",
2144 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
2145 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
2146 | "dev": true
2147 | },
2148 | "qjobs": {
2149 | "version": "1.1.5",
2150 | "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz",
2151 | "integrity": "sha1-ZZ3p8s+NzCehSBJ28gU3cnI4LnM=",
2152 | "dev": true
2153 | },
2154 | "qs": {
2155 | "version": "6.5.1",
2156 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
2157 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==",
2158 | "dev": true
2159 | },
2160 | "querystring": {
2161 | "version": "0.2.0",
2162 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
2163 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
2164 | "dev": true
2165 | },
2166 | "querystring-es3": {
2167 | "version": "0.2.1",
2168 | "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
2169 | "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
2170 | "dev": true
2171 | },
2172 | "randomatic": {
2173 | "version": "1.1.7",
2174 | "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
2175 | "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
2176 | "dev": true,
2177 | "requires": {
2178 | "is-number": "3.0.0",
2179 | "kind-of": "4.0.0"
2180 | },
2181 | "dependencies": {
2182 | "is-number": {
2183 | "version": "3.0.0",
2184 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
2185 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
2186 | "dev": true,
2187 | "requires": {
2188 | "kind-of": "3.2.2"
2189 | },
2190 | "dependencies": {
2191 | "kind-of": {
2192 | "version": "3.2.2",
2193 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
2194 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
2195 | "dev": true,
2196 | "requires": {
2197 | "is-buffer": "1.1.6"
2198 | }
2199 | }
2200 | }
2201 | },
2202 | "kind-of": {
2203 | "version": "4.0.0",
2204 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
2205 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
2206 | "dev": true,
2207 | "requires": {
2208 | "is-buffer": "1.1.6"
2209 | }
2210 | }
2211 | }
2212 | },
2213 | "randombytes": {
2214 | "version": "2.0.5",
2215 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
2216 | "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
2217 | "dev": true,
2218 | "requires": {
2219 | "safe-buffer": "5.1.1"
2220 | }
2221 | },
2222 | "range-parser": {
2223 | "version": "1.2.0",
2224 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
2225 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
2226 | "dev": true
2227 | },
2228 | "raw-body": {
2229 | "version": "2.3.2",
2230 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
2231 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
2232 | "dev": true,
2233 | "requires": {
2234 | "bytes": "3.0.0",
2235 | "http-errors": "1.6.2",
2236 | "iconv-lite": "0.4.19",
2237 | "unpipe": "1.0.0"
2238 | }
2239 | },
2240 | "read-only-stream": {
2241 | "version": "2.0.0",
2242 | "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
2243 | "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=",
2244 | "dev": true,
2245 | "requires": {
2246 | "readable-stream": "2.3.3"
2247 | }
2248 | },
2249 | "readable-stream": {
2250 | "version": "2.3.3",
2251 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
2252 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
2253 | "dev": true,
2254 | "requires": {
2255 | "core-util-is": "1.0.2",
2256 | "inherits": "2.0.3",
2257 | "isarray": "1.0.0",
2258 | "process-nextick-args": "1.0.7",
2259 | "safe-buffer": "5.1.1",
2260 | "string_decoder": "1.0.3",
2261 | "util-deprecate": "1.0.2"
2262 | }
2263 | },
2264 | "readdirp": {
2265 | "version": "2.1.0",
2266 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
2267 | "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
2268 | "dev": true,
2269 | "requires": {
2270 | "graceful-fs": "4.1.11",
2271 | "minimatch": "3.0.4",
2272 | "readable-stream": "2.3.3",
2273 | "set-immediate-shim": "1.0.1"
2274 | }
2275 | },
2276 | "regex-cache": {
2277 | "version": "0.4.4",
2278 | "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
2279 | "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
2280 | "dev": true,
2281 | "requires": {
2282 | "is-equal-shallow": "0.1.3"
2283 | }
2284 | },
2285 | "remove-trailing-separator": {
2286 | "version": "1.1.0",
2287 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
2288 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
2289 | "dev": true
2290 | },
2291 | "repeat-element": {
2292 | "version": "1.1.2",
2293 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
2294 | "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
2295 | "dev": true
2296 | },
2297 | "repeat-string": {
2298 | "version": "1.6.1",
2299 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
2300 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
2301 | "dev": true
2302 | },
2303 | "requires-port": {
2304 | "version": "1.0.0",
2305 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
2306 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
2307 | "dev": true
2308 | },
2309 | "resolve": {
2310 | "version": "1.5.0",
2311 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
2312 | "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==",
2313 | "dev": true,
2314 | "requires": {
2315 | "path-parse": "1.0.5"
2316 | }
2317 | },
2318 | "rimraf": {
2319 | "version": "2.6.2",
2320 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
2321 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
2322 | "dev": true,
2323 | "requires": {
2324 | "glob": "7.1.2"
2325 | }
2326 | },
2327 | "ripemd160": {
2328 | "version": "2.0.1",
2329 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
2330 | "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=",
2331 | "dev": true,
2332 | "requires": {
2333 | "hash-base": "2.0.2",
2334 | "inherits": "2.0.3"
2335 | }
2336 | },
2337 | "safe-buffer": {
2338 | "version": "5.1.1",
2339 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
2340 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
2341 | "dev": true
2342 | },
2343 | "semver": {
2344 | "version": "4.3.6",
2345 | "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
2346 | "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=",
2347 | "dev": true
2348 | },
2349 | "set-immediate-shim": {
2350 | "version": "1.0.1",
2351 | "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
2352 | "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
2353 | "dev": true
2354 | },
2355 | "setprototypeof": {
2356 | "version": "1.0.3",
2357 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
2358 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=",
2359 | "dev": true
2360 | },
2361 | "sha.js": {
2362 | "version": "2.4.9",
2363 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz",
2364 | "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==",
2365 | "dev": true,
2366 | "requires": {
2367 | "inherits": "2.0.3",
2368 | "safe-buffer": "5.1.1"
2369 | }
2370 | },
2371 | "shasum": {
2372 | "version": "1.0.2",
2373 | "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
2374 | "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=",
2375 | "dev": true,
2376 | "requires": {
2377 | "json-stable-stringify": "0.0.1",
2378 | "sha.js": "2.4.9"
2379 | }
2380 | },
2381 | "shell-quote": {
2382 | "version": "1.6.1",
2383 | "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
2384 | "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
2385 | "dev": true,
2386 | "requires": {
2387 | "array-filter": "0.0.1",
2388 | "array-map": "0.0.0",
2389 | "array-reduce": "0.0.0",
2390 | "jsonify": "0.0.0"
2391 | }
2392 | },
2393 | "socket.io": {
2394 | "version": "1.7.3",
2395 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.3.tgz",
2396 | "integrity": "sha1-uK+cq6AJSeVo42nxMn6pvp6iRhs=",
2397 | "dev": true,
2398 | "requires": {
2399 | "debug": "2.3.3",
2400 | "engine.io": "1.8.3",
2401 | "has-binary": "0.1.7",
2402 | "object-assign": "4.1.0",
2403 | "socket.io-adapter": "0.5.0",
2404 | "socket.io-client": "1.7.3",
2405 | "socket.io-parser": "2.3.1"
2406 | },
2407 | "dependencies": {
2408 | "debug": {
2409 | "version": "2.3.3",
2410 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
2411 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
2412 | "dev": true,
2413 | "requires": {
2414 | "ms": "0.7.2"
2415 | }
2416 | },
2417 | "ms": {
2418 | "version": "0.7.2",
2419 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
2420 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
2421 | "dev": true
2422 | }
2423 | }
2424 | },
2425 | "socket.io-adapter": {
2426 | "version": "0.5.0",
2427 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz",
2428 | "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=",
2429 | "dev": true,
2430 | "requires": {
2431 | "debug": "2.3.3",
2432 | "socket.io-parser": "2.3.1"
2433 | },
2434 | "dependencies": {
2435 | "debug": {
2436 | "version": "2.3.3",
2437 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
2438 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
2439 | "dev": true,
2440 | "requires": {
2441 | "ms": "0.7.2"
2442 | }
2443 | },
2444 | "ms": {
2445 | "version": "0.7.2",
2446 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
2447 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
2448 | "dev": true
2449 | }
2450 | }
2451 | },
2452 | "socket.io-client": {
2453 | "version": "1.7.3",
2454 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.3.tgz",
2455 | "integrity": "sha1-sw6GqhDV7zVGYBwJzeR2Xjgdo3c=",
2456 | "dev": true,
2457 | "requires": {
2458 | "backo2": "1.0.2",
2459 | "component-bind": "1.0.0",
2460 | "component-emitter": "1.2.1",
2461 | "debug": "2.3.3",
2462 | "engine.io-client": "1.8.3",
2463 | "has-binary": "0.1.7",
2464 | "indexof": "0.0.1",
2465 | "object-component": "0.0.3",
2466 | "parseuri": "0.0.5",
2467 | "socket.io-parser": "2.3.1",
2468 | "to-array": "0.1.4"
2469 | },
2470 | "dependencies": {
2471 | "component-emitter": {
2472 | "version": "1.2.1",
2473 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
2474 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
2475 | "dev": true
2476 | },
2477 | "debug": {
2478 | "version": "2.3.3",
2479 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
2480 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
2481 | "dev": true,
2482 | "requires": {
2483 | "ms": "0.7.2"
2484 | }
2485 | },
2486 | "ms": {
2487 | "version": "0.7.2",
2488 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
2489 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
2490 | "dev": true
2491 | }
2492 | }
2493 | },
2494 | "socket.io-parser": {
2495 | "version": "2.3.1",
2496 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz",
2497 | "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=",
2498 | "dev": true,
2499 | "requires": {
2500 | "component-emitter": "1.1.2",
2501 | "debug": "2.2.0",
2502 | "isarray": "0.0.1",
2503 | "json3": "3.3.2"
2504 | },
2505 | "dependencies": {
2506 | "debug": {
2507 | "version": "2.2.0",
2508 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
2509 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
2510 | "dev": true,
2511 | "requires": {
2512 | "ms": "0.7.1"
2513 | }
2514 | },
2515 | "isarray": {
2516 | "version": "0.0.1",
2517 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
2518 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
2519 | "dev": true
2520 | },
2521 | "ms": {
2522 | "version": "0.7.1",
2523 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
2524 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
2525 | "dev": true
2526 | }
2527 | }
2528 | },
2529 | "source-map": {
2530 | "version": "0.5.7",
2531 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
2532 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
2533 | "dev": true
2534 | },
2535 | "statuses": {
2536 | "version": "1.4.0",
2537 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
2538 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==",
2539 | "dev": true
2540 | },
2541 | "stream-browserify": {
2542 | "version": "2.0.1",
2543 | "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
2544 | "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
2545 | "dev": true,
2546 | "requires": {
2547 | "inherits": "2.0.3",
2548 | "readable-stream": "2.3.3"
2549 | }
2550 | },
2551 | "stream-combiner2": {
2552 | "version": "1.1.1",
2553 | "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
2554 | "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
2555 | "dev": true,
2556 | "requires": {
2557 | "duplexer2": "0.1.4",
2558 | "readable-stream": "2.3.3"
2559 | }
2560 | },
2561 | "stream-http": {
2562 | "version": "2.7.2",
2563 | "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
2564 | "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",
2565 | "dev": true,
2566 | "requires": {
2567 | "builtin-status-codes": "3.0.0",
2568 | "inherits": "2.0.3",
2569 | "readable-stream": "2.3.3",
2570 | "to-arraybuffer": "1.0.1",
2571 | "xtend": "4.0.1"
2572 | }
2573 | },
2574 | "stream-splicer": {
2575 | "version": "2.0.0",
2576 | "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz",
2577 | "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=",
2578 | "dev": true,
2579 | "requires": {
2580 | "inherits": "2.0.3",
2581 | "readable-stream": "2.3.3"
2582 | }
2583 | },
2584 | "string_decoder": {
2585 | "version": "1.0.3",
2586 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
2587 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
2588 | "dev": true,
2589 | "requires": {
2590 | "safe-buffer": "5.1.1"
2591 | }
2592 | },
2593 | "strip-ansi": {
2594 | "version": "4.0.0",
2595 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
2596 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
2597 | "dev": true,
2598 | "requires": {
2599 | "ansi-regex": "3.0.0"
2600 | }
2601 | },
2602 | "subarg": {
2603 | "version": "1.0.0",
2604 | "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
2605 | "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
2606 | "dev": true,
2607 | "requires": {
2608 | "minimist": "1.2.0"
2609 | },
2610 | "dependencies": {
2611 | "minimist": {
2612 | "version": "1.2.0",
2613 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
2614 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
2615 | "dev": true
2616 | }
2617 | }
2618 | },
2619 | "supports-color": {
2620 | "version": "4.5.0",
2621 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
2622 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
2623 | "dev": true,
2624 | "requires": {
2625 | "has-flag": "2.0.0"
2626 | }
2627 | },
2628 | "syntax-error": {
2629 | "version": "1.3.0",
2630 | "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.3.0.tgz",
2631 | "integrity": "sha1-HtkmbE1AvnXcVb+bsct3Biu5bKE=",
2632 | "dev": true,
2633 | "requires": {
2634 | "acorn": "4.0.13"
2635 | }
2636 | },
2637 | "through": {
2638 | "version": "2.3.8",
2639 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
2640 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
2641 | "dev": true
2642 | },
2643 | "through2": {
2644 | "version": "2.0.3",
2645 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
2646 | "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
2647 | "dev": true,
2648 | "requires": {
2649 | "readable-stream": "2.3.3",
2650 | "xtend": "4.0.1"
2651 | }
2652 | },
2653 | "timers-browserify": {
2654 | "version": "1.4.2",
2655 | "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
2656 | "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=",
2657 | "dev": true,
2658 | "requires": {
2659 | "process": "0.11.10"
2660 | }
2661 | },
2662 | "tmp": {
2663 | "version": "0.0.31",
2664 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
2665 | "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=",
2666 | "dev": true,
2667 | "requires": {
2668 | "os-tmpdir": "1.0.2"
2669 | }
2670 | },
2671 | "to-array": {
2672 | "version": "0.1.4",
2673 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
2674 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
2675 | "dev": true
2676 | },
2677 | "to-arraybuffer": {
2678 | "version": "1.0.1",
2679 | "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
2680 | "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
2681 | "dev": true
2682 | },
2683 | "tty-browserify": {
2684 | "version": "0.0.0",
2685 | "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
2686 | "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
2687 | "dev": true
2688 | },
2689 | "type-is": {
2690 | "version": "1.6.15",
2691 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
2692 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
2693 | "dev": true,
2694 | "requires": {
2695 | "media-typer": "0.3.0",
2696 | "mime-types": "2.1.17"
2697 | }
2698 | },
2699 | "typedarray": {
2700 | "version": "0.0.6",
2701 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
2702 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
2703 | "dev": true
2704 | },
2705 | "ultron": {
2706 | "version": "1.0.2",
2707 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
2708 | "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=",
2709 | "dev": true
2710 | },
2711 | "umd": {
2712 | "version": "3.0.1",
2713 | "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.1.tgz",
2714 | "integrity": "sha1-iuVW4RAR9jwllnCKiDclnwGz1g4=",
2715 | "dev": true
2716 | },
2717 | "unpipe": {
2718 | "version": "1.0.0",
2719 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
2720 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
2721 | "dev": true
2722 | },
2723 | "url": {
2724 | "version": "0.11.0",
2725 | "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
2726 | "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
2727 | "dev": true,
2728 | "requires": {
2729 | "punycode": "1.3.2",
2730 | "querystring": "0.2.0"
2731 | },
2732 | "dependencies": {
2733 | "punycode": {
2734 | "version": "1.3.2",
2735 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
2736 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
2737 | "dev": true
2738 | }
2739 | }
2740 | },
2741 | "useragent": {
2742 | "version": "2.2.1",
2743 | "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz",
2744 | "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=",
2745 | "dev": true,
2746 | "requires": {
2747 | "lru-cache": "2.2.4",
2748 | "tmp": "0.0.31"
2749 | }
2750 | },
2751 | "util": {
2752 | "version": "0.10.3",
2753 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
2754 | "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
2755 | "dev": true,
2756 | "requires": {
2757 | "inherits": "2.0.1"
2758 | },
2759 | "dependencies": {
2760 | "inherits": {
2761 | "version": "2.0.1",
2762 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
2763 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
2764 | "dev": true
2765 | }
2766 | }
2767 | },
2768 | "util-deprecate": {
2769 | "version": "1.0.2",
2770 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
2771 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
2772 | "dev": true
2773 | },
2774 | "utils-merge": {
2775 | "version": "1.0.1",
2776 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
2777 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
2778 | "dev": true
2779 | },
2780 | "vm-browserify": {
2781 | "version": "0.0.4",
2782 | "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
2783 | "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
2784 | "dev": true,
2785 | "requires": {
2786 | "indexof": "0.0.1"
2787 | }
2788 | },
2789 | "void-elements": {
2790 | "version": "2.0.1",
2791 | "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
2792 | "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
2793 | "dev": true
2794 | },
2795 | "vue": {
2796 | "version": "2.5.2",
2797 | "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.2.tgz",
2798 | "integrity": "sha512-Au9rf8fPkBulFHfZ406UaQDd1jH9fqGRIM+0IHilrXnJ/0TeeMH4SBkNxWf2dGevl2S3aVeu0E/WklEv0/msag=="
2799 | },
2800 | "watchify": {
2801 | "version": "3.9.0",
2802 | "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.9.0.tgz",
2803 | "integrity": "sha1-8HX9LoqGrN6Eztum5cKgvt1SPZ4=",
2804 | "dev": true,
2805 | "requires": {
2806 | "anymatch": "1.3.2",
2807 | "browserify": "14.5.0",
2808 | "chokidar": "1.7.0",
2809 | "defined": "1.0.0",
2810 | "outpipe": "1.1.1",
2811 | "through2": "2.0.3",
2812 | "xtend": "4.0.1"
2813 | }
2814 | },
2815 | "which": {
2816 | "version": "1.3.0",
2817 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
2818 | "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
2819 | "dev": true,
2820 | "requires": {
2821 | "isexe": "2.0.0"
2822 | }
2823 | },
2824 | "wordwrap": {
2825 | "version": "0.0.3",
2826 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
2827 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
2828 | "dev": true
2829 | },
2830 | "wrappy": {
2831 | "version": "1.0.2",
2832 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2833 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
2834 | "dev": true
2835 | },
2836 | "ws": {
2837 | "version": "1.1.2",
2838 | "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz",
2839 | "integrity": "sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8=",
2840 | "dev": true,
2841 | "requires": {
2842 | "options": "0.0.6",
2843 | "ultron": "1.0.2"
2844 | }
2845 | },
2846 | "wtf-8": {
2847 | "version": "1.0.0",
2848 | "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz",
2849 | "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=",
2850 | "dev": true
2851 | },
2852 | "xmlhttprequest-ssl": {
2853 | "version": "1.5.3",
2854 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz",
2855 | "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=",
2856 | "dev": true
2857 | },
2858 | "xtend": {
2859 | "version": "4.0.1",
2860 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
2861 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
2862 | "dev": true
2863 | },
2864 | "yeast": {
2865 | "version": "0.1.2",
2866 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
2867 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
2868 | "dev": true
2869 | }
2870 | }
2871 | }
2872 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-model",
3 | "version": "2.0.7",
4 | "description": "A Javascript plugin for the excellent Vue.js framework that gives you the ability to transform your plain data into rich models with built-in and customizable HTTP actions.",
5 | "main": "src/VueModel.js",
6 | "scripts": {
7 | "test": "karma start --single-run",
8 | "test:watch": "karma start"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/aarondfrancis/vue-model.git"
13 | },
14 | "keywords": [
15 | "vuejs",
16 | "vue",
17 | "model",
18 | "restful"
19 | ],
20 | "author": "Aaron Francis (http://aaronfrancis.com)",
21 | "license": "MIT",
22 | "bugs": {
23 | "url": "https://github.com/aarondfrancis/vue-model/issues"
24 | },
25 | "homepage": "https://github.com/aarondfrancis/vue-model#readme",
26 | "dependencies": {
27 | "axios": "^0.16.2",
28 | "lodash": "^4.17.4",
29 | "vue": "^2.0",
30 | "promise": "^8.0.1",
31 | "promise.prototype.finally": "^3.0.1"
32 | },
33 | "devDependencies": {
34 | "browserify": "^14.5.0",
35 | "jasmine-core": "^2.8.0",
36 | "karma": "^1.7.1",
37 | "karma-browserify": "^5.1.1",
38 | "karma-chrome-launcher": "^2.2.0",
39 | "karma-jasmine": "^1.1.0",
40 | "karma-mocha-reporter": "^2.2.5",
41 | "watchify": "^3.9.0"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Defaults.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 |
3 | module.exports = {
4 | // The default model attributes. We'll initialize them all to
5 | // null if there are no values for them. This is the starting
6 | // point for the data that is sent to the server
7 | attributes: [],
8 |
9 | methods: {},
10 |
11 | computed: {},
12 |
13 | http: {
14 | baseRoute: null,
15 |
16 | eventPrefix: null,
17 |
18 | // The _minimum_ amount of time that a successful ajax
19 | // request should take. If the request fails it will
20 | // return immediately, but if it's successful it won't
21 | // return until `takeAtLeast` milliseconds have passed
22 | takeAtLeast: 0,
23 |
24 | // Return an axios request configuration object
25 | // https://github.com/axios/axios#request-config
26 | axios(configuration, action, definition, runtimeArgs) {
27 | return configuration;
28 | },
29 |
30 | // Turn an axios response into the model data
31 | getDataFromResponse(response) {
32 | return response.data.data;
33 | },
34 |
35 | // Where you want your errors to live. You can use a
36 | // dot delimited path or put them at the top level
37 | errorKey: 'http.errors',
38 |
39 | // Determine whether an error response is a model
40 | // validation error. 422 is the correct status code,
41 | // so if you use Laravel, no need to update this.
42 | isValidationError (error) {
43 | return _.get(error, 'response.status') === 422;
44 | },
45 |
46 | // The error object should have the field names
47 | // as the keys and an array of errors as the
48 | // values. This default is set for Laravel 5.5.
49 | getErrorsFromResponse(response) {
50 | return response.data.errors;
51 | },
52 |
53 | // Base defaults for every action
54 | actionDefaults: {
55 | // Apply the response data to the model
56 | apply: false,
57 |
58 | // The server validates this request and could
59 | // return a validation error in response
60 | validation: true,
61 |
62 | // Modify what data we should send to the server
63 | data: {
64 | // only: [],
65 | // with: [],
66 | // without: [],
67 | // custom: function(data, definition) {
68 | // return data;
69 | // }
70 | }
71 | },
72 |
73 | // Default HTTP Actions that every model gets. You can
74 | // set an action to `false` to disable it in a model
75 | actions: {
76 | index: {
77 | method: 'GET',
78 | route: '',
79 | data: false
80 | },
81 | store: {
82 | method: 'POST',
83 | route: '',
84 | },
85 | fetch: {
86 | method: 'GET',
87 | route: '{id}',
88 | apply: true,
89 | data: false
90 | },
91 | update: {
92 | method: 'PUT',
93 | route: '{id}',
94 | apply: true,
95 | },
96 | destroy: {
97 | method: 'DELETE',
98 | route: '{id}',
99 | data: false
100 | }
101 | },
102 | },
103 |
104 | };
--------------------------------------------------------------------------------
/src/Errors.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | var Vue = require('vue');
3 |
4 | module.exports = class Errors {
5 |
6 | constructor(errors) {
7 | this.set(errors);
8 | }
9 |
10 | set (errors) {
11 | if (_.isEmpty(errors)) {
12 | errors = {};
13 | }
14 |
15 | if (!_.isPlainObject(errors)) {
16 | throw new Error('ModelErrors data must be a plain object');
17 | }
18 |
19 | for (const [field, messages] of Object.entries(errors)) {
20 | errors[field] = _.castArray(messages);
21 | }
22 |
23 | Vue.set(this, 'errors', errors);
24 | }
25 |
26 | all() {
27 | return this.errors;
28 | }
29 |
30 | flat() {
31 | var flat = [];
32 |
33 | for (const [field, messages] of Object.entries(this.errors)) {
34 | for (var i = 0; i < messages.length; i++) {
35 | flat.push({
36 | field: field,
37 | message: messages[i]
38 | });
39 | }
40 | }
41 |
42 | return flat;
43 | }
44 |
45 | any() {
46 | return this.flat().length > 0;
47 | }
48 |
49 | has(field) {
50 | return !!_.get(this.errors, field, []).length;
51 | }
52 |
53 | get (field) {
54 | return _.get(this.errors, field, []);
55 | }
56 |
57 | first(field) {
58 | return _.head(this.get(field));
59 | }
60 |
61 | clear(field) {
62 | if (_.isUndefined(field)) {
63 | this.errors = {};
64 | return;
65 | }
66 |
67 | this.errors[field] = [];
68 | }
69 |
70 | add(field, message) {
71 | return this.push(field, message);
72 | }
73 |
74 | push(field, message) {
75 | Vue.set(this.errors, field, this.get(field).concat(_.castArray(message)));
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/src/Model.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | var axios = require('axios');
3 | var Vue = require('vue');
4 | require('promise.prototype.finally').shim();
5 | require('./lib/promise-delay');
6 |
7 | module.exports = class Model {
8 | constructor(data, settings, classes) {
9 | this.classes = classes;
10 | this.settings = settings;
11 |
12 | this.setData(data);
13 | this.setComputed();
14 | this.setMethods();
15 | this.setHttp();
16 |
17 | Vue.set(this, 'data', this.data);
18 | }
19 |
20 | setBus(bus) {
21 | this.bus = bus;
22 | }
23 |
24 | setData(data) {
25 | this.data = _.defaultsDeep(...[
26 | _.toPlainObject(data),
27 |
28 | // Initialize all the attributes as nulls
29 | this.settings.attributes.reduce((carry, key) => _.set(carry, key, null), {}),
30 |
31 | // Set the key that will contain our Errors class
32 | _.set({}, this.settings.http.errorKey, new this.classes.errors)
33 | ]);
34 | }
35 |
36 | setComputed() {
37 | for (const [key, method] of Object.entries(this.settings.computed)) {
38 | Object.defineProperty(this.data, key, {
39 | enumerable: true,
40 | get: method.bind(this.data)
41 | });
42 | }
43 | }
44 |
45 | setMethods() {
46 | for (const [key, method] of Object.entries(this.settings.methods)) {
47 | this.data[key] = method.bind(this.data);
48 | }
49 | }
50 |
51 | setHttp() {
52 | // Exclude any actions set to false
53 | var actions = _.pickBy(this.settings.http.actions);
54 |
55 | var http = _.get(this.data, 'http', {});
56 | var defaults = this.settings.http.actionDefaults;
57 |
58 | for (const [key, definition] of Object.entries(actions)) {
59 | http[key] = runtimeArgs => this.request(runtimeArgs, _.defaultsDeep(definition, defaults), key);
60 | http[key + 'InProgress'] = false;
61 | }
62 |
63 | // One global HTTP indicator
64 | Object.defineProperty(http, 'inProgress', {
65 | enumerable: true,
66 | get: () => {
67 | return Object
68 | .keys(actions)
69 | // Turn the key into the name of the indicator
70 | .map(key => http[key + 'InProgress'])
71 | // If any are true, then it's true
72 | .reduce((carry, key) => carry || key)
73 | }
74 | });
75 |
76 | this.data.http = http;
77 | }
78 |
79 | request(runtimeArgs, definition, key) {
80 | var canceled = false;
81 |
82 | this.emit([key, 'before'], {
83 | cancel: () => canceled = true
84 | });
85 |
86 | if (canceled) {
87 | return;
88 | }
89 |
90 | this.data.http[key + 'InProgress'] = true;
91 |
92 | var axios = this.getAxiosInstance();
93 | var config = this.getAxiosConfiguration(runtimeArgs, definition, key);
94 |
95 | var promise = axios.request(config)
96 | .takeAtLeast(this.settings.http.takeAtLeast)
97 | .catch(error => this.requestFailed(error, definition, key))
98 | // Always set the progress indicator to false and send the final event
99 | .finally(() => {
100 | this.data.http[key + 'InProgress'] = false
101 | this.emit([key, 'complete']);
102 | });
103 |
104 | if (definition.apply) {
105 | // Apply the results of the response to the model
106 | promise = promise.then(response => this.apply(response));
107 | }
108 |
109 | // Emit a success event _after_ the response has
110 | // been applied (if applicable)
111 | promise = promise.then(response => {
112 | this.emit([key, 'success'], {response});
113 | return response;
114 | })
115 |
116 | return promise;
117 | }
118 |
119 | getAxiosInstance() {
120 | return axios.create();
121 | }
122 |
123 | getAxiosConfiguration(runtimeArgs, definition, key) {
124 | var baseRoute = definition.baseRoute || this.settings.http.baseRoute || '';
125 |
126 | if (_.startsWith(definition.route, '/')) {
127 | baseRoute = '';
128 | }
129 |
130 | var config = {
131 | method: definition.method,
132 | url: this.interpolate(baseRoute + definition.route),
133 | }
134 |
135 | var key = (['PUT', 'POST', 'PATCH'].indexOf(config.method.toUpperCase()) == -1) ? 'params' : 'data';
136 | config[key] = this.getRequestPayload(definition, runtimeArgs);
137 |
138 | return this.settings.http.axios.call({
139 | // Share some methods that might be helpful
140 | interpolate: this.interpolate,
141 | getRequestData: this.getRequestPayload
142 | }, config, key, definition, runtimeArgs);
143 | }
144 |
145 | getRequestPayload(definition) {
146 | // Shorthand for no data
147 | if (definition.data === false) {
148 | definition.data = {
149 | only: []
150 | }
151 | }
152 |
153 | // Shorthand for only keys
154 | if (_.isArray(definition.data)) {
155 | definition.data = {
156 | only: definition.data
157 | }
158 | }
159 |
160 | var result = key => {
161 | var value = _.get(definition, 'data.' + key);
162 | return _.isFunction(value) ? value.call(this.data, definition) : value;
163 | }
164 |
165 | // Base level for every request is the value the
166 | // developer put in as the model's attributes
167 | var payload = this.settings.attributes;
168 |
169 | var only = result('only');
170 | if (_.isArray(only)) {
171 | payload = only;
172 | }
173 |
174 | var without = result('without');
175 | if (_.isArray(without)) {
176 | payload = _.difference(payload, without);
177 | }
178 |
179 | var wth = result('with');
180 | if (_.isArray(wth)) {
181 | payload = _.union(payload, wth);
182 | }
183 |
184 | payload = payload
185 | .map(value => {
186 | if (!_.isString(value)) {
187 | return value;
188 | }
189 |
190 | return {
191 | [value]: _.get(this.data, value)
192 | }
193 | })
194 | .reduce(_.merge, {});
195 |
196 | for (const [key, value] of Object.entries(payload)) {
197 | if (_.isFunction(value)) {
198 | payload[key] = value.call(this.data);
199 | }
200 | }
201 |
202 | var custom = _.get(definition, 'data.custom');
203 | if (_.isFunction(custom)) {
204 | payload = custom.call(this.data, payload, definition);
205 | }
206 |
207 | return payload;
208 | }
209 |
210 | requestFailed(error, definition, key) {
211 | this.emit([key, 'error'], {error});
212 |
213 | if (definition.validation) {
214 | this.setValidationErrors(error);
215 | }
216 |
217 | return Promise.reject(error);
218 | }
219 |
220 | setValidationErrors(error) {
221 | var http = this.settings.http;
222 | if (!http.isValidationError(error)) {
223 | return;
224 | }
225 | var errors = http.getErrorsFromResponse(error.response);
226 |
227 | // errorKey can be a dot delimited path
228 | Vue.setNested(this.data, http.errorKey, new this.classes.errors(errors));
229 | }
230 |
231 | apply(response) {
232 | var data = this.settings.http.getDataFromResponse(response);
233 | for (const [key, value] of Object.entries(data)) {
234 | Vue.set(this.data, key, value);
235 | }
236 |
237 | // Give the response back so we can keep chaining promises
238 | return response;
239 | }
240 |
241 | emit(action, data) {
242 | action = [this.settings.http.eventPrefix]
243 | .concat(_.castArray(action))
244 | .filter(_.identity)
245 | .join('.');
246 |
247 | data = _.defaultTo(data, {});
248 | data.model = this.data;
249 |
250 | this.bus.emit(action, data);
251 | }
252 |
253 | /**
254 | * Interpolate a string with the model's data
255 | * @param template
256 | * @returns string
257 | */
258 | interpolate(template) {
259 | _.templateSettings.interpolate = /{([\s\S]+?)}/g;
260 | return _.template(template)(this.data);
261 | }
262 |
263 | }
--------------------------------------------------------------------------------
/src/PubSub.js:
--------------------------------------------------------------------------------
1 | // Waiting for a new release that includes: https://github.com/konsumer/emitonoff/pull/3
2 |
3 | var EmitOnOff = module.exports = function (thing) {
4 | if (!thing) thing = {};
5 |
6 | thing._subs = [];
7 | thing._paused = false;
8 | thing._pending = [];
9 |
10 | /**
11 | * Sub of pubsub
12 | * @param {String} name name of event
13 | * @param {Function} cb your callback
14 | */
15 | thing.on = function (name, cb) {
16 | thing._subs[name] = thing._subs[name] || [];
17 | thing._subs[name].push(cb);
18 | };
19 |
20 | /**
21 | * remove sub of pubsub
22 | * @param {String} name name of event
23 | * @param {Function} cb your callback
24 | */
25 | thing.off = function (name, cb) {
26 | if (!thing._subs[name]) return;
27 | for (var i in thing._subs[name]) {
28 | if (thing._subs[name][i] === cb) {
29 | thing._subs[name].splice(i, 1);
30 | break;
31 | }
32 | }
33 | };
34 |
35 | /**
36 | * Pub of pubsub
37 | * @param {String} name name of event
38 | * @param {Mixed} data the data to publish
39 | */
40 | thing.emit = function (name) {
41 | if (!thing._subs[name]) return;
42 |
43 | var args = Array.prototype.slice.call(arguments, 1);
44 |
45 | if (thing._paused) {
46 | thing._pending[name] = thing._pending[name] || [];
47 | thing._pending[name].push(args)
48 | return
49 | }
50 |
51 | for (var i in thing._subs[name]) {
52 | thing._subs[name][i].apply(thing, args);
53 | }
54 | };
55 |
56 | thing.pause = function () {
57 | thing._paused = true;
58 | };
59 |
60 | thing.resume = function () {
61 | thing._paused = false;
62 |
63 | for (var name in thing._pending) {
64 | for (var i = 0; i < thing._pending[name].length; i++) {
65 | thing.emit(name, thing._pending[name][i])
66 | }
67 | }
68 | };
69 |
70 | return thing;
71 | };
--------------------------------------------------------------------------------
/src/VueModel.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | var Bus = require('./PubSub');
3 | var setNested = require('./lib/set-nested');
4 |
5 | class VueModel {
6 | constructor() {
7 | this.bus = Bus();
8 | this.registry = {};
9 | }
10 |
11 | register(name, definition) {
12 | definition = _.toPlainObject(definition);
13 |
14 | // Set the name of the model as the Event Prefix,
15 | // but only if there isn't a prefix set yet
16 | if (! _.get(definition, 'http.eventPrefix', false)) {
17 | _.set(definition, 'http.eventPrefix', name);
18 | }
19 |
20 | this.registry[name] = definition;
21 | }
22 |
23 | $model(VueInstance, name, data, definitionOverrides) {
24 | if (!_.has(this.registry, name)) {
25 | throw new Error("[vue-model] Unrecognized model: " + name);
26 | }
27 |
28 | // Order of importance for options
29 | // 1. Explicitly passed in
30 | // 2. Model definition
31 | // 3. Defaults
32 | var definition = _.defaultsDeep(...[
33 | _.toPlainObject(definitionOverrides),
34 | this.registry[name],
35 | this.classes.defaults
36 | ]);
37 |
38 | var model = new this.classes.model(data, definition, this.classes);
39 | model.setBus(this.bus);
40 |
41 | // Only return the data
42 | return model.data;
43 | }
44 |
45 | $models(VueInstance, name, datas, definitionOverrides) {
46 | return datas.map(data => VueInstance.$model(name, data, definitionOverrides));
47 | }
48 |
49 | $addModelListeners(VueInstance, listeners) {
50 | this.modelListeners(VueInstance, true, listeners);
51 | }
52 |
53 | $removeModelListeners(VueInstance, listeners) {
54 | this.modelListeners(VueInstance, false, listeners);
55 | }
56 |
57 | modelListeners(VueInstance, add, listeners) {
58 | var method = add ? 'on' : 'off';
59 |
60 | _.castArray(listeners)
61 | .map(listener => {
62 | // When the handler has the same name as the
63 | // event itself, a single string suffices
64 | if (_.isString(listener)) {
65 | listener = {
66 | [listener]: listener
67 | }
68 | }
69 |
70 | return listener;
71 | })
72 |
73 | // Reduce down to a single array
74 | .reduce((carry, listener) => {
75 | for (let [event, handler] of Object.entries(listener)) {
76 | // Handlers that are strings are methods on the instance
77 | if (_.isString(handler)) {
78 | handler = VueInstance[handler];
79 | }
80 |
81 | carry.push({
82 | event: event,
83 | handler: handler
84 | });
85 | }
86 | return carry;
87 | }, [])
88 | // Call the method on the bus
89 | .map(listener => {
90 | console.log(method, listener);
91 | this.bus[method](listener.event, listener.handler);
92 | });
93 | }
94 |
95 | getOptions(VueInstance) {
96 | var options = _.clone(_.get(VueInstance.$options, 'models', []));
97 |
98 | // If the `models` option is an array, we assume
99 | // that's a set of models to register
100 | if (_.isArray(options)) {
101 | options = {
102 | register: options
103 | }
104 | }
105 |
106 | return _.defaults(options, {
107 | register: [],
108 | listeners: []
109 | });
110 | }
111 |
112 | created(VueInstance) {
113 | this.getOptions(VueInstance)
114 | .register
115 | .map(model => {
116 | return _.isString(model) ? {
117 | type: model,
118 | key: model,
119 | } : model;
120 | })
121 | .map(model => {
122 | var data = VueInstance[model.key];
123 | var method = _.isArray(data) ? '$models' : '$model';
124 | VueInstance[model.key] = VueInstance[method](model.type, data, model.options);
125 | });
126 | }
127 |
128 | mounted(VueInstance) {
129 | VueInstance.$addModelListeners(this.getOptions(VueInstance).listeners);
130 | }
131 |
132 | beforeDestroy(VueInstance) {
133 | VueInstance.$removeModelListeners(this.getOptions(VueInstance).listeners);
134 | }
135 |
136 | // Called by Vue to install the plugin
137 | install(Vue, options) {
138 | // If the keys 'models' & 'classes' aren't present, we make an
139 | // assumption that the object passed in is a map of models
140 | if (!_.has(options, 'models') && !_.has(options, 'classes')) {
141 | options = {
142 | models: options,
143 | classes: {}
144 | }
145 | }
146 |
147 | this.classes = _.defaults(options.classes, {
148 | model: require('./Model'),
149 | errors: require('./Errors'),
150 | defaults: require('./Defaults'),
151 | });
152 |
153 | var registry = _.get(options, 'models', {});
154 | for (const [name, definition] of Object.entries(registry)) {
155 | this.register(name, definition);
156 | }
157 |
158 | // Our augmented `Vue.set` method
159 | Vue.setNested = setNested;
160 |
161 | // Methods where we want `this` to be equal to VueModel,
162 | // but still have access to the Vue instance that called
163 | // it, via the first argument
164 | var bind = name => {
165 | var VueModel = this;
166 | return function (...args) {
167 | var partial = (function (instance) {
168 | var method = VueModel[name].bind(VueModel);
169 | return _.partial(method, instance);
170 | })(this);
171 | return partial(...args);
172 | }
173 | }
174 |
175 | Vue.prototype.$model = bind('$model');
176 | Vue.prototype.$models = bind('$models');
177 | Vue.prototype.$addModelListeners = bind('$addModelListeners');
178 | Vue.prototype.$removeModelListeners = bind('$removeModelListeners');
179 |
180 | Vue.prototype.$bus = () => {
181 | console.log(this.bus._subs);
182 | };
183 |
184 | Vue.mixin({
185 | created: bind('created'),
186 | mounted: bind('mounted'),
187 | beforeDestroy: bind('beforeDestroy')
188 | });
189 |
190 | Vue.models = {
191 | register: this.register.bind(this),
192 | addEventListener: this.bus.on,
193 | removeEventListener: this.bus.off,
194 | };
195 | }
196 | }
197 |
198 | module.exports = new VueModel();
199 |
--------------------------------------------------------------------------------
/src/VueModel.spec.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 | const Vue = require("vue");
3 | const VueModel = require('./VueModel');
4 |
5 | describe("VueModel", () => {
6 |
7 | // This is need because Vue.use caches installed plugins
8 | var fakeVueUse = (plugin, ...args) => {
9 | plugin.install.apply(plugin, [Vue].concat(args));
10 | };
11 |
12 | describe("Vue.models.register() should", () => {
13 | beforeEach(() => {
14 | VueModel.registry = {};
15 | spyOn(VueModel, 'register').and.callThrough();
16 | });
17 |
18 | it("register model(s)", () => {
19 | expect(VueModel.register).not.toHaveBeenCalled();
20 |
21 | fakeVueUse(VueModel);
22 |
23 | const baseRoute = '/test'
24 |
25 | Vue.models.register('users', {
26 | http: {
27 | baseRoute
28 | }
29 | });
30 |
31 | expect(VueModel.register).toHaveBeenCalled();
32 | expect(VueModel.registry.users).toBeTruthy();
33 | expect(_.get(VueModel.registry.users, 'http.baseRoute')).toBe(baseRoute);
34 | });
35 |
36 | it("register model(s) when Vue.use(VueModel, options) is called", () => {
37 | expect(VueModel.register).not.toHaveBeenCalled();
38 | const baseRoute = '/test2'
39 |
40 | fakeVueUse(VueModel, {
41 | users: {
42 | http: {
43 | baseRoute
44 | }
45 | }
46 | });
47 |
48 | expect(VueModel.register).toHaveBeenCalled();
49 | expect(VueModel.registry.users).toBeTruthy();
50 | expect(_.get(VueModel.registry.users, 'http.baseRoute')).toBe(baseRoute);
51 | });
52 | });
53 | });
--------------------------------------------------------------------------------
/src/lib/promise-delay.js:
--------------------------------------------------------------------------------
1 | // Adam Wathan https://twitter.com/adamwathan/status/885130802513752065?lang=en
2 | // https://gist.github.com/adamwathan/babd10ed0e971404c5d8a86358d01b61
3 |
4 | // Creates a new promise that automatically resolves after some timeout:
5 | Promise.delay = function (time) {
6 | return new Promise(resolve => {
7 | setTimeout(resolve, time)
8 | })
9 | }
10 |
11 | // Throttle this promise to resolve no faster than the specified time:
12 | Promise.prototype.takeAtLeast = function (time) {
13 | return new Promise((resolve, reject) => {
14 | Promise.all([this, Promise.delay(time)]).then(([result]) => {
15 | resolve(result)
16 | }, reject)
17 | })
18 | }
--------------------------------------------------------------------------------
/src/lib/set-nested.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | var Vue = require('vue');
3 |
4 | module.exports = function (obj, path, value) {
5 | var parts = _.toPath(path);
6 | var key = _.last(parts);
7 |
8 | value = _.set({}, parts, value);
9 |
10 | for (var i = 0; i < parts.length; i++) {
11 | var part = parts[i];
12 |
13 | value = _.get(value, part);
14 |
15 | if (_.has(obj, part) && part !== _.last(parts)) {
16 | obj = obj[part];
17 | continue;
18 | }
19 |
20 | key = part;
21 | break;
22 | }
23 |
24 | return Vue.set(obj, key, value);
25 | }
26 |
27 | // var test = [{
28 | // base: {
29 | // something: ['a', 'b', 'c']
30 | // },
31 | // value: 1,
32 | // path: 'something[0]',
33 | // expects: {
34 | // something: [1, 'b', 'c']
35 | // }
36 | // }, {
37 | // base: {
38 | // top: {},
39 | // },
40 | // value: 'set',
41 | // path: 'top',
42 | // expects: {
43 | // top: 'set'
44 | // }
45 | // }, {
46 | // base: {
47 | // top: {},
48 | // },
49 | // value: 'set',
50 | // path: 'top.foo.bar',
51 | // expects: {
52 | // top: {
53 | // foo: {
54 | // bar: 'set'
55 | // }
56 | // }
57 | // }
58 | // }, {
59 | // base: {
60 | // top: {
61 | // foo: {
62 | // bar: {}
63 | // }
64 | // },
65 | // },
66 | // value: 'set',
67 | // path: 'top.foo.bar',
68 | // expects: {
69 | // top: {
70 | // foo: {
71 | // bar: 'set'
72 | // }
73 | // }
74 | // }
75 | // }, {
76 | // base: ['a', 'b', 'c'],
77 | // value: 'set',
78 | // path: '0',
79 | // expects: ['set', 'b', 'c']
80 | // }];
81 | //
82 | // for (var i = 0; i < test.length; i++) {
83 | // console.log('----------------');
84 | // var testcase = test[i];
85 | // nestSet(testcase.base, testcase.path, testcase.value);
86 | // console.log(_.isMatch(testcase.base, testcase.expects))
87 | // }
88 |
--------------------------------------------------------------------------------