├── .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 | 69 | ``` 70 | 71 | ### Update a Model 72 | 73 | The same as creating, but instead it issues a `PUT`. 74 | 75 | ```html 76 | 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 |
93 | {{ customer.name }} 94 | (Refresh) 95 | (Delete) 96 |
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 | 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 | 167 |
168 | 169 | 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 | 630 | 631 | 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 | 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 | 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 | --------------------------------------------------------------------------------