├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmrc ├── CHANGELOG.md ├── DEVELOPMENT.md ├── LICENSE ├── README.md ├── lib ├── cjs │ ├── index.js │ ├── inject.js │ └── types.js ├── es │ ├── index.js │ ├── inject.js │ └── types.js └── umd │ ├── react-signalr.js │ ├── react-signalr.min.js │ └── react-signalr.min.js.map ├── package-lock.json ├── package.json ├── src ├── index.js ├── inject.jsx └── types.jsx ├── tools └── babel.preset.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "./tools/babel.preset" ] 3 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | charset = utf-8 11 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "plugins": [ 4 | "react" 5 | ], 6 | "parser": "babel-eslint", 7 | "parserOptions": { 8 | "ecmaVersion": 6, 9 | "sourceType": "module", 10 | "ecmaFeatures": { 11 | "jsx": true 12 | } 13 | }, 14 | "globals": { 15 | "document": false, 16 | "escape": false, 17 | "navigator": false, 18 | "unescape": false, 19 | "window": false, 20 | "describe": true, 21 | "before": true, 22 | "it": true, 23 | "expect": true, 24 | "sinon": true 25 | }, 26 | "env": { 27 | "es6": true, 28 | "browser": true, 29 | "node": true, 30 | "jquery": false, 31 | "mocha": true 32 | }, 33 | "rules": { 34 | "import/no-extraneous-dependencies": ["error", { 35 | "devDependencies": true, 36 | "optionalDependencies": true, 37 | "peerDependencies": true}], 38 | "react/prefer-stateless-function": "off", 39 | "no-console": "off" 40 | } 41 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # IntelliJ configs 30 | .idea 31 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact = true -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | * In general follow (https://docs.npmjs.com/getting-started/semantic-versioning) versioning. 4 | 5 | ## 3.3.0 6 | * Configuration change: negotiation phase will be skipped from now on 7 | * Rearranged src folder and removed .npmignore in order to fix npm related problems 8 | * Fixed ejs/es package paths in package.json 9 | * Reverted to a previous version of @aspnet/signalr 10 | * Fixed a bug in stopHub fn. 11 | 12 | ## 3.2.2 13 | * Rearranged src folder and removed .npmignore in order to fix npm related problems 14 | 15 | ## 3.2.1 16 | * Fixed ejs/es package paths in package.json 17 | 18 | ## 3.2.0 19 | * Package updates, incl. @aspnet/signalr update from version 1.0.0 to 1.1.0. 20 | 21 | ## 3.1.0 22 | * Implemented methods in hub proxy for adding and removing clients to and from named groups 23 | 24 | ## 3.0.0 25 | * injectSignalR can now be used as a decorator (contains breaking changes) 26 | * Superficial code restructuring, linter fixes, etc. 27 | 28 | ## 2.0.0 29 | * Migrated to .NET Core 2.1 30 | 31 | ## 1.0.0 32 | * Initial release 33 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | ### Development workflow 2 | * Make a new branch 3 | * Run `npm run hot` to start examples in watch hot module replacement mode 4 | * Open `http://localhost:5555` 5 | 6 | ### Development workflow with project using the package 7 | ##### Link local package to your project 8 | * Run `npm link` at Component root to make your local package linkable 9 | * Run `npm link @opuscapita/react-signalr` at project's dir that's using the component to use local package 10 | ##### Build and watch the package 11 | * Run `npm run watch[:cjs, :es, :umd]` to run dev builds in watch mode 12 | ##### Unlink local package 13 | * Run `npm unlink @opuscapita/react-signalr` at project's dir that's using the component 14 | 15 | ### Preparing the PR 16 | * Reset `docs` and `lib` directories to master branch state `git checkout master -- docs/* lib/*` 17 | * Update `CHANGELOG.md` with your changes under the `` header 18 | * Make a pull request 19 | 20 | ### Preparing for new version 21 | * Use `master` branch 22 | * Add new version header to `CHANGELOG.md` and move everyting from `` there (leave next header empty) 23 | * Make sure `npm test` and `npm run lint` runs without errors 24 | 25 | ### Creating a new release 26 | * Run `npm version [major|minor|patch]` [Info](https://docs.npmjs.com/cli/version) 27 | 28 | ### Publish new version to NPM 29 | * Run `npm publish` 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-signalr 2 | 3 | ### Description 4 | Higher-Order Component that provides a connection to a SignalR hub. This component adds a hub proxy, that 5 | may be used to register and unregister event listeners, and also to invoke a hub controller and send data to it. 6 | 7 | This component is built using the [SignalR JavaScript client](https://github.com/aspnet/SignalR/tree/release/2.1/clients/ts/signalr) of 8 | the [ASP.NET Core 2.1 Signalr](https://github.com/aspnet/SignalR/tree/release/2.1) product. 9 | 10 | ### Installation 11 | ``` 12 | npm install @opuscapita/react-signalr --save 13 | ``` 14 | 15 | ### Builds 16 | #### UMD 17 | The default build with compiled styles in the .js file. Also minified version available in the lib/umd directory. 18 | #### CommonJS/ES Module 19 | You need to configure your module loader to use `cjs` or `es` fields of the package.json to use these module types. 20 | Also you need to configure sass loader, since all the styles are in sass format. 21 | * With webpack use [resolve.mainFields](https://webpack.js.org/configuration/resolve/#resolve-mainfields) to configure the module type. 22 | * Add [SASS loader](https://github.com/webpack-contrib/sass-loader) to support importing of SASS styles. 23 | 24 | ### API 25 | 26 | #### Options for ```injectSignalR``` 27 | | Option | Type | Default | Description | 28 | | ------------------------ | ---------------- | ------------------------ | -------------------------------------------------------- | 29 | | hubName | string | required | Name of the signalr hub | 30 | | baseAddress | string \| func | required | Base address for signalr server | 31 | | accessToken | string \| func | | Access token for authorization on the server | 32 | | signalrPath | string | 'signalr' | Path to signalr hubs | 33 | | controller | string | <hubName> | Name of the controller (if different from hubName) | 34 | | retries | integer | 3 | Number of retries to connect after a failure | 35 | 36 | #### Methods in hub proxy 37 | | Method | Parameters | Description | 38 | | ---------------------------- | --------------------------------- | ---------------------------------------------- | 39 | | invoke(target, query) | target: string, query: string | Invokes hub controller with GET | 40 | | send(target, payload) | target: string, payload: object | Invokes hub controller with POST | 41 | | register(event, listener) | event: string, listener: func | Registers a listener for an event | 42 | | unregister(event, listener) | event: string, listener: func | Unregisters a listener for an event | 43 | | add(group) | group: string | Adds client to a named group1) | 44 | | remove(group) | group: string | Removes client from a named group1) | 45 | 46 | 1) To be able to use group messaging the SignalR hub must implement two methods, `AddToGroup(string group)` and `RemoveFromGroup(string group)`, which respectively add and remove the client to and from the specified named group *(cf. [code example](#addingremoving-the-client-tofrom-a-named-group))*. 47 | 48 | ### Code example 49 | 50 | #### Injecting signalr HOC to a component 51 | 52 | ##### As a HOC 53 | ```jsx 54 | import React from 'react'; 55 | import { injectSignalR, hubShape } from '@opuscapita/react-signalr'; 56 | 57 | class MyComponent extends React.Component { 58 | // ... 59 | } 60 | 61 | MyComponent.propTypes = { 62 | // PropType for the hub proxy. 63 | mynotifier: hubShape, 64 | }; 65 | 66 | export default injectSignalR({ 67 | // Defines both the last part of the route to the hub, 68 | // and also the key of the hub proxy in this.props. 69 | // In this case it hub proxy is found in this.props.mynotifier. 70 | hubName: 'mynotifier', 71 | // Either 1) a string containing the server url, or 72 | // 2) a function getting the server url from the state (example). 73 | baseAddress: (state) => state.configuration.server, 74 | // 1) A string containing the access token, or 75 | // 2) a function getting the access token from the state (example), or 76 | // 3) a function using the state to return a function that 77 | // gets the access token. 78 | accessToken: (state) => state.configuration.accessToken, 79 | })(MyComponent); 80 | ``` 81 | 82 | ##### As a decorator 83 | ```jsx 84 | import React from 'react'; 85 | import { injectSignalR, hubShape } from '@opuscapita/react-signalr'; 86 | 87 | @injectSignalR({ 88 | hubName: 'mynotifier', 89 | baseAddress: (state) => state.configuration.server, 90 | accessToken: (state) => state.configuration.accessToken, 91 | }) 92 | export default class MyComponent extends React.Component { 93 | // ... 94 | } 95 | 96 | MyComponent.propTypes = { 97 | // PropType for the hub proxy. 98 | mynotifier: hubShape, 99 | }; 100 | ``` 101 | 102 | #### Passing the hub proxy to child component(s) 103 | ```jsx 104 | class MyComponent extends React.Component { 105 | 106 | // ... 107 | 108 | render() { 109 | // Passing the hub proxy from this.props to child component(s) allows 110 | // also the child component(s) to register its (their) own listeners. 111 | const { ...passThroughProps } = this.props; 112 | return (); 114 | } 115 | } 116 | ``` 117 | 118 | #### Registering and unregistering listeners 119 | ```jsx 120 | class MyComponent extends React.Component { 121 | 122 | // ... 123 | 124 | // Listeners may be registered in componentDidMount (recommended). 125 | componentDidMount() { 126 | // Hub proxy is found in this.props. 127 | const { mynotifier } = this.props; 128 | if (mynotifier) { 129 | // Register this.onInserted to listen 'inserted' event. 130 | mynotifier.register('inserted', this.onInserted); 131 | // Register this.onUpdated to listen 'updated' event. 132 | mynotifier.register('updated', this.onUpdated); 133 | } 134 | } 135 | 136 | // Listeners may be unregistered in componentWillUnmount (recommended). 137 | componentWillUnmount() { 138 | const { mynotifier } = this.props; 139 | if (mynotifier) { 140 | // Unregister this.onInserted from listening to 'inserted' event. 141 | mynotifier.unregister('inserted', this.onInserted); 142 | // Unregister this.onUpdated from listening to 'updated' event. 143 | mynotifier.unregister('updated', this.onUpdated); 144 | } 145 | } 146 | 147 | // Parameter list should match the response sent from the server. 148 | onInserted = (target, id) => { 149 | // Handle inserted event ... 150 | } 151 | 152 | onUpdated = (target, id) => { 153 | // Handle updated event ... 154 | } 155 | 156 | // ... 157 | } 158 | ``` 159 | 160 | #### Invoking controller or sending data to it 161 | ```jsx 162 | class MyComponent extends React.Component { 163 | 164 | // ... 165 | 166 | invoke() { 167 | // Requests '//target/123' with GET 168 | this.props.mynotifier.invoke('target', 123); 169 | } 170 | 171 | send(data) { 172 | // Requests '//target' with POST 173 | // and the JS object `data` as payload in JSON format 174 | this.props.mynotifier.send('target', data); 175 | } 176 | 177 | // ... 178 | } 179 | ``` 180 | 181 | #### Adding/removing the client to/from a named group 182 | 183 | ##### The SignalR hub 184 | ```csharp 185 | public class MyNotifier : Hub 186 | { 187 | // ... 188 | 189 | public Task AddToGroup(string group) 190 | => Groups.AddToGroupAsync(group); 191 | 192 | public Task RemoveFromGroup(string group) 193 | => Groups.RemoveFromGroupAsync(group); 194 | 195 | // ... 196 | } 197 | ``` 198 | 199 | ##### The client component 200 | ```jsx 201 | class MyComponent extends React.Component { 202 | 203 | // ... 204 | 205 | add(group) { 206 | this.props.mynotifier.add(group); 207 | } 208 | 209 | remove(group) { 210 | this.props.mynotifier.remove(group); 211 | } 212 | 213 | // ... 214 | } 215 | ``` 216 | -------------------------------------------------------------------------------- /lib/cjs/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _types = require('./types'); 6 | 7 | Object.defineProperty(exports, 'hubShape', { 8 | enumerable: true, 9 | get: function get() { 10 | return _interopRequireDefault(_types).default; 11 | } 12 | }); 13 | 14 | var _inject = require('./inject'); 15 | 16 | Object.defineProperty(exports, 'injectSignalR', { 17 | enumerable: true, 18 | get: function get() { 19 | return _interopRequireDefault(_inject).default; 20 | } 21 | }); 22 | 23 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 24 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbmRleC5qcyJdLCJuYW1lcyI6WyJkZWZhdWx0Il0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7MENBQVNBLE87Ozs7Ozs7OzsyQ0FDQUEsTyIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IGRlZmF1bHQgYXMgaHViU2hhcGUgfSBmcm9tICcuL3R5cGVzJztcbmV4cG9ydCB7IGRlZmF1bHQgYXMgaW5qZWN0U2lnbmFsUiB9IGZyb20gJy4vaW5qZWN0JztcbiJdfQ== -------------------------------------------------------------------------------- /lib/cjs/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 6 | 7 | var _react = require('react'); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | var _propTypes = require('prop-types'); 12 | 13 | var _propTypes2 = _interopRequireDefault(_propTypes); 14 | 15 | var _axios = require('axios'); 16 | 17 | var _axios2 = _interopRequireDefault(_axios); 18 | 19 | var _redux = require('redux'); 20 | 21 | var _reactRedux = require('react-redux'); 22 | 23 | var _immutable = require('immutable'); 24 | 25 | var _signalr = require('@aspnet/signalr'); 26 | 27 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 28 | 29 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } 30 | 31 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 32 | 33 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 34 | 35 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 36 | 37 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 38 | 39 | var getDisplayName = function getDisplayName(Component) { 40 | return Component.displayName || Component.name || 'Component'; 41 | }; 42 | 43 | var injectSignalR = function injectSignalR(options) { 44 | return function (WrappedComponent) { 45 | var _class, _temp; 46 | 47 | var _options$hubName = options.hubName, 48 | hubName = _options$hubName === undefined ? '' : _options$hubName, 49 | _options$baseAddress = options.baseAddress, 50 | baseAddress = _options$baseAddress === undefined ? 'http://localhost:5555' : _options$baseAddress, 51 | _options$accessToken = options.accessToken, 52 | accessToken = _options$accessToken === undefined ? null : _options$accessToken, 53 | _options$signalrPath = options.signalrPath, 54 | signalrPath = _options$signalrPath === undefined ? 'signalr' : _options$signalrPath, 55 | _options$retries = options.retries, 56 | retries = _options$retries === undefined ? 3 : _options$retries; 57 | var _options$controller = options.controller, 58 | controller = _options$controller === undefined ? hubName : _options$controller; 59 | var InjectSignalR = (_temp = _class = function (_React$PureComponent) { 60 | _inherits(InjectSignalR, _React$PureComponent); 61 | 62 | function InjectSignalR(props) { 63 | _classCallCheck(this, InjectSignalR); 64 | 65 | var _this = _possibleConstructorReturn(this, _React$PureComponent.call(this, props)); 66 | 67 | _this.count = function (c, s) { 68 | return c + s.count(); 69 | }; 70 | 71 | _this.addToGroup = function (group) { 72 | var hub = _this.state.hub; 73 | 74 | if (hub) { 75 | var connection = hub.connection; 76 | 77 | if (connection && connection.connectionState === 1) { 78 | hub.invoke('addToGroup', group).catch(function (err) { 79 | console.error('Error: Adding client to group ' + group + ' in ' + hubName + ' failed.\n\n' + err); 80 | }); 81 | } 82 | } 83 | }; 84 | 85 | _this.removeFromGroup = function (group) { 86 | var hub = _this.state.hub; 87 | 88 | if (hub) { 89 | var connection = hub.connection; 90 | 91 | if (connection && connection.connectionState === 1) { 92 | return hub.invoke('removeFromGroup', group).catch(function (err) { 93 | console.error('Error: Removing client from group ' + group + ' in ' + hubName + ' failed.\n\n' + err); 94 | }); 95 | } 96 | } 97 | return Promise.resolve(); 98 | }; 99 | 100 | _this.sendToController = function (target) { 101 | var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; 102 | 103 | var url = _this.props.baseUrl + '/' + controller + '/' + target; 104 | var payload = data ? data.toJS() : null; 105 | return _axios2.default.post(url, payload).catch(function (err) { 106 | console.error('Error: Sending data to ' + controller + ' failed.\n\n' + err); 107 | }); 108 | }; 109 | 110 | _this.invokeController = function (targetMethod) { 111 | var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; 112 | 113 | var urlBase = _this.props.baseUrl + '/' + controller + '/' + targetMethod; 114 | var url = data ? urlBase + '/' + data : urlBase; 115 | return _axios2.default.get(url).catch(function (err) { 116 | console.error('Error: Invoking ' + controller + ' failed.\n\n' + err); 117 | }); 118 | }; 119 | 120 | _this.handleError = function (err) { 121 | var response = err.response, 122 | statusCode = err.statusCode; 123 | 124 | var _ref = response || {}, 125 | status = _ref.status; 126 | 127 | switch (status || statusCode) { 128 | case 500: 129 | break; 130 | case 401: 131 | _this.oldToken = _this.token; // fall through 132 | default: 133 | _this.setState({ hub: null }); 134 | break; 135 | } 136 | }; 137 | 138 | _this.registerListener = function (name, handler) { 139 | var _this$state = _this.state, 140 | pending = _this$state.pending, 141 | active = _this$state.active, 142 | moribund = _this$state.moribund; 143 | // Remove listener from moribund listeners 144 | 145 | if (!_this.moribund) _this.moribund = moribund || (0, _immutable.Map)(); 146 | var existingMoribund = _this.moribund.getIn([name], (0, _immutable.Set)()); 147 | if (existingMoribund.has(handler)) { 148 | var remainingMoribund = existingMoribund.filterNot(function (h) { 149 | return h === handler; 150 | }); 151 | _this.moribund = remainingMoribund.size ? _this.moribund.setIn([name], remainingMoribund) : _this.moribund.delete(name); 152 | } 153 | // Add listener to pending listeners (if it is NOT active) 154 | if (!_this.active) _this.active = active || (0, _immutable.Map)(); 155 | var existingActive = _this.active.getIn([name], (0, _immutable.Set)()); 156 | if (!existingActive.has(handler)) { 157 | if (!_this.pending) _this.pending = pending || (0, _immutable.Map)(); 158 | var existingPending = _this.pending.getIn([name], (0, _immutable.Set)()); 159 | if (!existingPending.has(handler)) { 160 | _this.pending = _this.pending.setIn([name], existingPending.add(handler)); 161 | } 162 | } 163 | if (_this.pending !== pending || _this.moribund !== moribund) { 164 | _this.setState({ 165 | pending: _this.pending, 166 | moribund: _this.moribund 167 | }); 168 | } 169 | }; 170 | 171 | _this.unregisterListener = function (name, handler) { 172 | var _this$state2 = _this.state, 173 | pending = _this$state2.pending, 174 | active = _this$state2.active, 175 | moribund = _this$state2.moribund; 176 | // Remove listener from pending listeners 177 | 178 | if (!_this.pending) _this.pending = pending || (0, _immutable.Map)(); 179 | var existingPending = _this.pending.getIn([name], (0, _immutable.Set)()); 180 | if (existingPending.has(handler)) { 181 | var remainingPending = existingPending.filterNot(function (h) { 182 | return h === handler; 183 | }); 184 | _this.pending = remainingPending.count() ? _this.pending.setIn([name], remainingPending) : _this.pending.delete(name); 185 | } 186 | // Add listener to moribund listeners (if it is active) 187 | if (!_this.active) _this.active = active || (0, _immutable.Map)(); 188 | var existingActive = _this.active.getIn([name], (0, _immutable.Set)()); 189 | if (existingActive.has(handler)) { 190 | if (!_this.moribund) _this.moribund = moribund || (0, _immutable.Map)(); 191 | var existingMoribund = _this.moribund.getIn([name], (0, _immutable.Set)()); 192 | if (!existingMoribund.has(handler)) { 193 | _this.moribund = _this.moribund.setIn([name], existingMoribund.add(handler)); 194 | } 195 | } 196 | if (_this.pending !== pending || _this.moribund !== moribund) { 197 | _this.setState({ 198 | pending: _this.pending, 199 | moribund: _this.moribund 200 | }); 201 | } 202 | }; 203 | 204 | _this.state = { 205 | hub: null, 206 | pending: undefined, 207 | active: undefined, 208 | moribund: undefined, 209 | retry: 0, 210 | create: 0 211 | }; 212 | return _this; 213 | } 214 | 215 | InjectSignalR.prototype.componentWillMount = function componentWillMount() { 216 | this.hubProxy = { 217 | send: this.sendToController, 218 | invoke: this.invokeController, 219 | add: this.addToGroup, 220 | remove: this.removeFromGroup, 221 | connectionId: undefined, 222 | register: this.registerListener, 223 | unregister: this.unregisterListener 224 | }; 225 | }; 226 | 227 | InjectSignalR.prototype.componentDidMount = function componentDidMount() { 228 | this.createHub(); 229 | }; 230 | 231 | InjectSignalR.prototype.componentWillUpdate = function componentWillUpdate(nextProps, nextState) { 232 | if (this.state.hub !== nextState.hub) { 233 | if (this.state.hub) this.stopHub(this.state.hub, false); 234 | if (nextState.hub) { 235 | this.startHub(nextState.hub); 236 | } else { 237 | this.createHub(nextState.create); 238 | } 239 | } else if (!nextState.hub) { 240 | this.createHub(nextState.create); 241 | } else { 242 | var pending = nextState.pending, 243 | moribund = nextState.moribund; 244 | 245 | if (!moribund) { 246 | moribund = this.moribund || (0, _immutable.Map)(); 247 | } else if (this.moribund) { 248 | moribund = moribund.mergeDeep(this.moribund); 249 | } 250 | var moribundCount = moribund.reduce(this.count, 0); 251 | if (moribundCount) { 252 | this.moribund = this.inactivateListeners(this.state.hub, moribund); 253 | } 254 | if (!pending) { 255 | pending = this.pending || (0, _immutable.Map)(); 256 | } else if (this.pending) { 257 | pending = pending.mergeDeep(this.pending); 258 | } 259 | var pendingCount = pending.reduce(this.count, 0); 260 | if (pendingCount) { 261 | this.pending = this.activateListeners(nextState.hub, pending); 262 | } 263 | } 264 | }; 265 | 266 | InjectSignalR.prototype.componentWillUnmount = function componentWillUnmount() { 267 | this.stopHub(this.state.hub, true); 268 | }; 269 | 270 | InjectSignalR.prototype.createHub = function () { 271 | var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(curCreate) { 272 | var _this2 = this; 273 | 274 | var _state, retry, create, _props, baseUrl, signalrActions, hubAddress, hub; 275 | 276 | return regeneratorRuntime.wrap(function _callee$(_context) { 277 | while (1) { 278 | switch (_context.prev = _context.next) { 279 | case 0: 280 | _state = this.state, retry = _state.retry, create = _state.create; 281 | 282 | if (!(retry > retries)) { 283 | _context.next = 6; 284 | break; 285 | } 286 | 287 | console.error('Error: Ran out of retries for starting ' + hubName + '!'); 288 | this.setState({ 289 | retry: 0, 290 | create: 0 291 | }); 292 | _context.next = 20; 293 | break; 294 | 295 | case 6: 296 | _props = this.props, baseUrl = _props.baseUrl, signalrActions = _props.signalrActions; 297 | 298 | if (!(baseUrl && hubName)) { 299 | _context.next = 20; 300 | break; 301 | } 302 | 303 | hubAddress = baseUrl; 304 | 305 | if (signalrPath) hubAddress = hubAddress + '/' + signalrPath; 306 | hubAddress = hubAddress + '/' + hubName; 307 | this.token = signalrActions.accessTokenFactory(accessToken); 308 | 309 | if (!this.token) { 310 | _context.next = 17; 311 | break; 312 | } 313 | 314 | if (!(this.oldToken === this.token)) { 315 | _context.next = 16; 316 | break; 317 | } 318 | 319 | if ((curCreate || create) > retries) { 320 | console.warn('Warning: Unable to get up-to-date access token.'); 321 | } else { 322 | this.setState({ 323 | hub: null, 324 | create: (curCreate || create) + 1 325 | }); 326 | } 327 | return _context.abrupt('return'); 328 | 329 | case 16: 330 | this.oldToken = undefined; 331 | 332 | case 17: 333 | hub = new _signalr.HubConnectionBuilder().withUrl(hubAddress, { 334 | skipNegotiation: true, 335 | transport: _signalr.HttpTransportType.WebSockets, 336 | accessTokenFactory: function accessTokenFactory() { 337 | return _this2.token; 338 | } 339 | }).build(); 340 | 341 | hub.onclose = this.handleError; 342 | this.setState({ 343 | hub: hub, 344 | retry: retry + 1, 345 | create: 0 346 | }); 347 | 348 | case 20: 349 | case 'end': 350 | return _context.stop(); 351 | } 352 | } 353 | }, _callee, this); 354 | })); 355 | 356 | function createHub(_x3) { 357 | return _ref2.apply(this, arguments); 358 | } 359 | 360 | return createHub; 361 | }(); 362 | 363 | InjectSignalR.prototype.startHub = function startHub(hub) { 364 | var _this3 = this; 365 | 366 | if (hub) { 367 | hub.start().then(function () { 368 | var _state2 = _this3.state, 369 | pending = _state2.pending, 370 | active = _state2.active; 371 | 372 | if (!_this3.pending) _this3.pending = pending || (0, _immutable.Map)(); 373 | if (!_this3.active) _this3.active = active || (0, _immutable.Map)(); 374 | _this3.setState({ 375 | active: _this3.active, 376 | pending: _this3.pending, 377 | retry: 0 378 | }); 379 | }).catch(function (err) { 380 | console.warn('Warning: Error while establishing connection to hub ' + hubName + '.\n\n' + err); 381 | hub.stop(); 382 | _this3.handleError(err); 383 | }); 384 | } 385 | }; 386 | 387 | InjectSignalR.prototype.stopHub = function stopHub(hub, clear) { 388 | if (hub) { 389 | var promises = []; 390 | 391 | if (clear) { 392 | // Clear pending 393 | this.pending = undefined; 394 | promises.push(this.removeFromGroup('')); 395 | // Merge active to pending 396 | } else if (!this.pending) { 397 | this.pending = this.state.active; 398 | } else if (this.state.active) { 399 | this.pending = this.pending.mergeDeep(this.state.active); 400 | } 401 | 402 | Promise.all(promises).then(function () { 403 | hub.stop(); 404 | }); 405 | 406 | this.active = undefined; 407 | this.setState({ 408 | pending: this.pending, 409 | active: this.active 410 | }); 411 | } 412 | }; 413 | 414 | InjectSignalR.prototype.activateListeners = function activateListeners(hub, pendingParam) { 415 | var _this4 = this; 416 | 417 | var pending = pendingParam; 418 | if (hub && pendingParam) { 419 | var connection = hub.connection; 420 | 421 | if (connection && connection.connectionState === 1) { 422 | var active = this.state.active; 423 | 424 | if (!this.active) this.active = active || (0, _immutable.Map)(); 425 | if (this.active.reduce(this.count, 0)) { 426 | pending = pending.mapEntries(function (_ref3) { 427 | var name = _ref3[0], 428 | curHandlers = _ref3[1]; 429 | 430 | var existing = _this4.active.getIn([name]); 431 | var handlers = existing ? curHandlers.filterNot(function (handler) { 432 | return existing.has(handler); 433 | }) : curHandlers; 434 | return [name, handlers]; 435 | }); 436 | } 437 | pending.mapEntries(function (_ref4) { 438 | var name = _ref4[0], 439 | handlers = _ref4[1]; 440 | return handlers.map(function (handler) { 441 | return hub.on(name, handler); 442 | }); 443 | }); 444 | this.active = this.active.mergeDeep(pending); 445 | this.setState({ 446 | pending: undefined, 447 | active: this.active 448 | }); 449 | return undefined; 450 | } 451 | } 452 | return pending; 453 | }; 454 | 455 | InjectSignalR.prototype.inactivateListeners = function inactivateListeners(hub, moribund) { 456 | if (hub && moribund) { 457 | moribund.mapEntries(function (_ref5) { 458 | var name = _ref5[0], 459 | handlers = _ref5[1]; 460 | return handlers.map(function (handler) { 461 | return hub.off(name, handler); 462 | }); 463 | }); 464 | var active = this.state.active; 465 | 466 | if (!this.active) this.active = active || (0, _immutable.Map)(); 467 | this.active = this.active.mapEntries(function (_ref6) { 468 | var name = _ref6[0], 469 | curHandlers = _ref6[1]; 470 | 471 | var removable = moribund.getIn([name]); 472 | var handlers = removable ? curHandlers.filterNot(function (handler) { 473 | return removable.has(handler); 474 | }) : curHandlers; 475 | return [name, handlers]; 476 | }); 477 | this.setState({ 478 | active: this.active, 479 | moribund: undefined 480 | }); 481 | return undefined; 482 | } 483 | return moribund; 484 | }; 485 | 486 | InjectSignalR.prototype.render = function render() { 487 | var _hubProp; 488 | 489 | var _props2 = this.props, 490 | baseUrl = _props2.baseUrl, 491 | signalrActions = _props2.signalrActions, 492 | passThroughProps = _objectWithoutProperties(_props2, ['baseUrl', 'signalrActions']); 493 | 494 | var hubProp = (_hubProp = {}, _hubProp[hubName] = this.hubProxy, _hubProp); 495 | return _react2.default.createElement(WrappedComponent, _extends({}, passThroughProps, hubProp)); 496 | }; 497 | 498 | return InjectSignalR; 499 | }(_react2.default.PureComponent), _class.WrappedComponent = WrappedComponent, _temp); 500 | 501 | 502 | InjectSignalR.displayName = 'InjectSignalR(' + getDisplayName(WrappedComponent) + ')'; 503 | 504 | var getValueFromState = function getValueFromState(state, source) { 505 | if (typeof source === 'function') return source(state); 506 | if (typeof source === 'string') return source; 507 | return ''; 508 | }; 509 | 510 | var mapDispatchToProps = function mapDispatchToProps(dispatch) { 511 | return { 512 | signalrActions: (0, _redux.bindActionCreators)({ 513 | accessTokenFactory: function accessTokenFactory() { 514 | return function (dispatcher, getState) { 515 | var state = getState(); 516 | return getValueFromState(state, accessToken); 517 | }; 518 | } 519 | }, dispatch) 520 | }; 521 | }; 522 | 523 | var mapStateToProps = function mapStateToProps(state) { 524 | var baseUrl = getValueFromState(state, baseAddress); 525 | return { baseUrl: baseUrl }; 526 | }; 527 | 528 | return (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)(InjectSignalR); 529 | }; 530 | }; 531 | 532 | exports.default = injectSignalR; 533 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbmplY3QuanN4Il0sIm5hbWVzIjpbImdldERpc3BsYXlOYW1lIiwiQ29tcG9uZW50IiwiZGlzcGxheU5hbWUiLCJuYW1lIiwiaW5qZWN0U2lnbmFsUiIsIldyYXBwZWRDb21wb25lbnQiLCJvcHRpb25zIiwiaHViTmFtZSIsImJhc2VBZGRyZXNzIiwiYWNjZXNzVG9rZW4iLCJzaWduYWxyUGF0aCIsInJldHJpZXMiLCJjb250cm9sbGVyIiwiSW5qZWN0U2lnbmFsUiIsInByb3BzIiwiY291bnQiLCJjIiwicyIsImFkZFRvR3JvdXAiLCJncm91cCIsImh1YiIsInN0YXRlIiwiY29ubmVjdGlvbiIsImNvbm5lY3Rpb25TdGF0ZSIsImludm9rZSIsImNhdGNoIiwiZXJyIiwiY29uc29sZSIsImVycm9yIiwicmVtb3ZlRnJvbUdyb3VwIiwiUHJvbWlzZSIsInJlc29sdmUiLCJzZW5kVG9Db250cm9sbGVyIiwidGFyZ2V0IiwiZGF0YSIsInVybCIsImJhc2VVcmwiLCJwYXlsb2FkIiwidG9KUyIsImF4aW9zIiwicG9zdCIsImludm9rZUNvbnRyb2xsZXIiLCJ0YXJnZXRNZXRob2QiLCJ1cmxCYXNlIiwiZ2V0IiwiaGFuZGxlRXJyb3IiLCJyZXNwb25zZSIsInN0YXR1c0NvZGUiLCJzdGF0dXMiLCJvbGRUb2tlbiIsInRva2VuIiwic2V0U3RhdGUiLCJyZWdpc3Rlckxpc3RlbmVyIiwiaGFuZGxlciIsInBlbmRpbmciLCJhY3RpdmUiLCJtb3JpYnVuZCIsImV4aXN0aW5nTW9yaWJ1bmQiLCJnZXRJbiIsImhhcyIsInJlbWFpbmluZ01vcmlidW5kIiwiZmlsdGVyTm90IiwiaCIsInNpemUiLCJzZXRJbiIsImRlbGV0ZSIsImV4aXN0aW5nQWN0aXZlIiwiZXhpc3RpbmdQZW5kaW5nIiwiYWRkIiwidW5yZWdpc3Rlckxpc3RlbmVyIiwicmVtYWluaW5nUGVuZGluZyIsInVuZGVmaW5lZCIsInJldHJ5IiwiY3JlYXRlIiwiY29tcG9uZW50V2lsbE1vdW50IiwiaHViUHJveHkiLCJzZW5kIiwicmVtb3ZlIiwiY29ubmVjdGlvbklkIiwicmVnaXN0ZXIiLCJ1bnJlZ2lzdGVyIiwiY29tcG9uZW50RGlkTW91bnQiLCJjcmVhdGVIdWIiLCJjb21wb25lbnRXaWxsVXBkYXRlIiwibmV4dFByb3BzIiwibmV4dFN0YXRlIiwic3RvcEh1YiIsInN0YXJ0SHViIiwibWVyZ2VEZWVwIiwibW9yaWJ1bmRDb3VudCIsInJlZHVjZSIsImluYWN0aXZhdGVMaXN0ZW5lcnMiLCJwZW5kaW5nQ291bnQiLCJhY3RpdmF0ZUxpc3RlbmVycyIsImNvbXBvbmVudFdpbGxVbm1vdW50IiwiY3VyQ3JlYXRlIiwic2lnbmFsckFjdGlvbnMiLCJodWJBZGRyZXNzIiwiYWNjZXNzVG9rZW5GYWN0b3J5Iiwid2FybiIsIkh1YkNvbm5lY3Rpb25CdWlsZGVyIiwid2l0aFVybCIsInNraXBOZWdvdGlhdGlvbiIsInRyYW5zcG9ydCIsIkh0dHBUcmFuc3BvcnRUeXBlIiwiV2ViU29ja2V0cyIsImJ1aWxkIiwib25jbG9zZSIsInN0YXJ0IiwidGhlbiIsInN0b3AiLCJjbGVhciIsInByb21pc2VzIiwicHVzaCIsImFsbCIsInBlbmRpbmdQYXJhbSIsIm1hcEVudHJpZXMiLCJjdXJIYW5kbGVycyIsImV4aXN0aW5nIiwiaGFuZGxlcnMiLCJtYXAiLCJvbiIsIm9mZiIsInJlbW92YWJsZSIsInJlbmRlciIsInBhc3NUaHJvdWdoUHJvcHMiLCJodWJQcm9wIiwiUmVhY3QiLCJQdXJlQ29tcG9uZW50IiwiZ2V0VmFsdWVGcm9tU3RhdGUiLCJzb3VyY2UiLCJtYXBEaXNwYXRjaFRvUHJvcHMiLCJkaXNwYXRjaGVyIiwiZ2V0U3RhdGUiLCJkaXNwYXRjaCIsIm1hcFN0YXRlVG9Qcm9wcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FBRUEsSUFBTUEsaUJBQWlCLFNBQWpCQSxjQUFpQjtBQUFBLFNB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QVh5Qjs7O0FBK1ZyRFEsa0JBQWNYLFdBQWQsc0JBQTZDRixlQUFlSyxnQkFBZixDQUE3Qzs7QUFTQSxRQUFNNEgsb0JBQW9CLFNBQXBCQSxpQkFBb0IsQ0FBQzVHLEtBQUQsRUFBUTZHLE1BQVIsRUFBbUI7QUFDM0MsVUFBSSxPQUFPQSxNQUFQLEtBQWtCLFVBQXRCLEVBQWtDLE9BQU9BLE9BQU83RyxLQUFQLENBQVA7QUFDbEMsVUFBSSxPQUFPNkcsTUFBUCxLQUFrQixRQUF0QixFQUFnQyxPQUFPQSxNQUFQO0FBQ2hDLGFBQU8sRUFBUDtBQUNELEtBSkQ7O0FBTUEsUUFBTUMscUJBQXFCLFNBQXJCQSxrQkFBcUI7QUFBQSxhQUFhO0FBQ3RDbkMsd0JBQWdCLCtCQUFtQjtBQUNqQ0UsOEJBQW9CO0FBQUEsbUJBQU0sVUFBQ2tDLFVBQUQsRUFBYUMsUUFBYixFQUEwQjtBQUNsRCxrQkFBTWhILFFBQVFnSCxVQUFkO0FBQ0EscUJBQU9KLGtCQUFrQjVHLEtBQWxCLEVBQXlCWixXQUF6QixDQUFQO0FBQ0QsYUFIbUI7QUFBQTtBQURhLFNBQW5CLEVBS2I2SCxRQUxhO0FBRHNCLE9BQWI7QUFBQSxLQUEzQjs7QUFTQSxRQUFNQyxrQkFBa0IsU0FBbEJBLGVBQWtCLENBQUNsSCxLQUFELEVBQVc7QUFDakMsVUFBTWUsVUFBVTZGLGtCQUFrQjVHLEtBQWxCLEVBQXlCYixXQUF6QixDQUFoQjtBQUNBLGFBQU8sRUFBRTRCLGdCQUFGLEVBQVA7QUFDRCxLQUhEOztBQUtBLFdBQU8seUJBQVFtRyxlQUFSLEVBQXlCSixrQkFBekIsRUFBNkN0SCxhQUE3QyxDQUFQO0FBQ0QsR0E3WHFCO0FBQUEsQ0FBdEI7O2tCQStYZVQsYSIsImZpbGUiOiJpbmplY3QuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IFByb3BUeXBlcyBmcm9tICdwcm9wLXR5cGVzJztcbmltcG9ydCBheGlvcyBmcm9tICdheGlvcyc7XG5pbXBvcnQgeyBiaW5kQWN0aW9uQ3JlYXRvcnMgfSBmcm9tICdyZWR1eCc7XG5pbXBvcnQgeyBjb25uZWN0IH0gZnJvbSAncmVhY3QtcmVkdXgnO1xuaW1wb3J0IHsgTWFwLCBTZXQgfSBmcm9tICdpbW11dGFibGUnO1xuaW1wb3J0IHsgSHViQ29ubmVjdGlvbkJ1aWxkZXIsIEh0dHBUcmFuc3BvcnRUeXBlIH0gZnJvbSAnQGFzcG5ldC9zaWduYWxyJztcblxuY29uc3QgZ2V0RGlzcGxheU5hbWUgPSBDb21wb25lbnQgPT4gQ29tcG9uZW50LmRpc3BsYXlOYW1lIHx8IENvbXBvbmVudC5uYW1lIHx8ICdDb21wb25lbnQnO1xuXG5jb25zdCBpbmplY3RTaWduYWxSID0gb3B0aW9ucyA9PiAoV3JhcHBlZENvbXBvbmVudCkgPT4ge1xuICBjb25zdCB7XG4gICAgaHViTmFtZSA9ICcnLFxuICAgIGJhc2VBZGRyZXNzID0gJ2h0dHA6Ly9sb2NhbGhvc3Q6NTU1NScsXG4gICAgYWNjZXNzVG9rZW4gPSBudWxsLFxuICAgIHNpZ25hbHJQYXRoID0gJ3NpZ25hbHInLFxuICAgIHJldHJpZXMgPSAzLFxuICB9ID0gb3B0aW9ucztcbiAgY29uc3QgeyBjb250cm9sbGVyID0gaHViTmFtZSB9ID0gb3B0aW9ucztcblxuICBjbGFzcyBJbmplY3RTaWduYWxSIGV4dGVuZHMgUmVhY3QuUHVyZUNvbXBvbmVudCB7XG4gICAgc3RhdGljIFdyYXBwZWRDb21wb25lbnQgPSBXcmFwcGVkQ29tcG9uZW50O1xuXG4gICAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICAgIHN1cGVyKHByb3BzKTtcbiAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgIGh1YjogbnVsbCxcbiAgICAgICAgcGVuZGluZzogdW5kZWZpbmVkLFxuICAgICAgICBhY3RpdmU6IHVuZGVmaW5lZCxcbiAgICAgICAgbW9yaWJ1bmQ6IHVuZGVmaW5lZCxcbiAgICAgICAgcmV0cnk6IDAsXG4gICAgICAgIGNyZWF0ZTogMCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29tcG9uZW50V2lsbE1vdW50KCkge1xuICAgICAgdGhpcy5odWJQcm94eSA9IHtcbiAgICAgICAgc2VuZDogdGhpcy5zZW5kVG9Db250cm9sbGVyLFxuICAgICAgICBpbnZva2U6IHRoaXMuaW52b2tlQ29udHJvbGxlcixcbiAgICAgICAgYWRkOiB0aGlzLmFkZFRvR3JvdXAsXG4gICAgICAgIHJlbW92ZTogdGhpcy5yZW1vdmVGcm9tR3JvdXAsXG4gICAgICAgIGNvbm5lY3Rpb25JZDogdW5kZWZpbmVkLFxuICAgICAgICByZWdpc3RlcjogdGhpcy5yZWdpc3Rlckxpc3RlbmVyLFxuICAgICAgICB1bnJlZ2lzdGVyOiB0aGlzLnVucmVnaXN0ZXJMaXN0ZW5lcixcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICB0aGlzLmNyZWF0ZUh1YigpO1xuICAgIH1cblxuICAgIGNvbXBvbmVudFdpbGxVcGRhdGUobmV4dFByb3BzLCBuZXh0U3RhdGUpIHtcbiAgICAgIGlmICh0aGlzLnN0YXRlLmh1YiAhPT0gbmV4dFN0YXRlLmh1Yikge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5odWIpIHRoaXMuc3RvcEh1Yih0aGlzLnN0YXRlLmh1YiwgZmFsc2UpO1xuICAgICAgICBpZiAobmV4dFN0YXRlLmh1Yikge1xuICAgICAgICAgIHRoaXMuc3RhcnRIdWIobmV4dFN0YXRlLmh1Yik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5jcmVhdGVIdWIobmV4dFN0YXRlLmNyZWF0ZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoIW5leHRTdGF0ZS5odWIpIHtcbiAgICAgICAgdGhpcy5jcmVhdGVIdWIobmV4dFN0YXRlLmNyZWF0ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgeyBwZW5kaW5nLCBtb3JpYnVuZCB9ID0gbmV4dFN0YXRlO1xuICAgICAgICBpZiAoIW1vcmlidW5kKSB7XG4gICAgICAgICAgbW9yaWJ1bmQgPSB0aGlzLm1vcmlidW5kIHx8IE1hcCgpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMubW9yaWJ1bmQpIHtcbiAgICAgICAgICBtb3JpYnVuZCA9IG1vcmlidW5kLm1lcmdlRGVlcCh0aGlzLm1vcmlidW5kKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBtb3JpYnVuZENvdW50ID0gbW9yaWJ1bmQucmVkdWNlKHRoaXMuY291bnQsIDApO1xuICAgICAgICBpZiAobW9yaWJ1bmRDb3VudCkge1xuICAgICAgICAgIHRoaXMubW9yaWJ1bmQgPSB0aGlzLmluYWN0aXZhdGVMaXN0ZW5lcnModGhpcy5zdGF0ZS5odWIsIG1vcmlidW5kKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXBlbmRpbmcpIHtcbiAgICAgICAgICBwZW5kaW5nID0gdGhpcy5wZW5kaW5nIHx8IE1hcCgpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMucGVuZGluZykge1xuICAgICAgICAgIHBlbmRpbmcgPSBwZW5kaW5nLm1lcmdlRGVlcCh0aGlzLnBlbmRpbmcpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHBlbmRpbmdDb3VudCA9IHBlbmRpbmcucmVkdWNlKHRoaXMuY291bnQsIDApO1xuICAgICAgICBpZiAocGVuZGluZ0NvdW50KSB7XG4gICAgICAgICAgdGhpcy5wZW5kaW5nID0gdGhpcy5hY3RpdmF0ZUxpc3RlbmVycyhuZXh0U3RhdGUuaHViLCBwZW5kaW5nKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgdGhpcy5zdG9wSHViKHRoaXMuc3RhdGUuaHViLCB0cnVlKTtcbiAgICB9XG5cbiAgICBjb3VudCA9IChjLCBzKSA9PiBjICsgcy5jb3VudCgpO1xuXG4gICAgYWRkVG9Hcm91cCA9IChncm91cCkgPT4ge1xuICAgICAgY29uc3QgeyBodWIgfSA9IHRoaXMuc3RhdGU7XG4gICAgICBpZiAoaHViKSB7XG4gICAgICAgIGNvbnN0IHsgY29ubmVjdGlvbiB9ID0gaHViO1xuICAgICAgICBpZiAoY29ubmVjdGlvbiAmJiBjb25uZWN0aW9uLmNvbm5lY3Rpb25TdGF0ZSA9PT0gMSkge1xuICAgICAgICAgIGh1Yi5pbnZva2UoJ2FkZFRvR3JvdXAnLCBncm91cClcbiAgICAgICAgICAgIC5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yOiBBZGRpbmcgY2xpZW50IHRvIGdyb3VwICR7Z3JvdXB9IGluICR7aHViTmFtZX0gZmFpbGVkLlxcblxcbiR7ZXJyfWApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgcmVtb3ZlRnJvbUdyb3VwID0gKGdyb3VwKSA9PiB7XG4gICAgICBjb25zdCB7IGh1YiB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgIGlmIChodWIpIHtcbiAgICAgICAgY29uc3QgeyBjb25uZWN0aW9uIH0gPSBodWI7XG4gICAgICAgIGlmIChjb25uZWN0aW9uICYmIGNvbm5lY3Rpb24uY29ubmVjdGlvblN0YXRlID09PSAxKSB7XG4gICAgICAgICAgcmV0dXJuIGh1Yi5pbnZva2UoJ3JlbW92ZUZyb21Hcm91cCcsIGdyb3VwKVxuICAgICAgICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3I6IFJlbW92aW5nIGNsaWVudCBmcm9tIGdyb3VwICR7Z3JvdXB9IGluICR7aHViTmFtZX0gZmFpbGVkLlxcblxcbiR7ZXJyfWApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9O1xuXG4gICAgc2VuZFRvQ29udHJvbGxlciA9ICh0YXJnZXQsIGRhdGEgPSBudWxsKSA9PiB7XG4gICAgICBjb25zdCB1cmwgPSBgJHt0aGlzLnByb3BzLmJhc2VVcmx9LyR7Y29udHJvbGxlcn0vJHt0YXJnZXR9YDtcbiAgICAgIGNvbnN0IHBheWxvYWQgPSBkYXRhID8gZGF0YS50b0pTKCkgOiBudWxsO1xuICAgICAgcmV0dXJuIGF4aW9zLnBvc3QodXJsLCBwYXlsb2FkKVxuICAgICAgICAuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yOiBTZW5kaW5nIGRhdGEgdG8gJHtjb250cm9sbGVyfSBmYWlsZWQuXFxuXFxuJHtlcnJ9YCk7XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBpbnZva2VDb250cm9sbGVyID0gKHRhcmdldE1ldGhvZCwgZGF0YSA9IG51bGwpID0+IHtcbiAgICAgIGNvbnN0IHVybEJhc2UgPSBgJHt0aGlzLnByb3BzLmJhc2VVcmx9LyR7Y29udHJvbGxlcn0vJHt0YXJnZXRNZXRob2R9YDtcbiAgICAgIGNvbnN0IHVybCA9IGRhdGEgPyBgJHt1cmxCYXNlfS8ke2RhdGF9YCA6IHVybEJhc2U7XG4gICAgICByZXR1cm4gYXhpb3MuZ2V0KHVybClcbiAgICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvcjogSW52b2tpbmcgJHtjb250cm9sbGVyfSBmYWlsZWQuXFxuXFxuJHtlcnJ9YCk7XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBhc3luYyBjcmVhdGVIdWIoY3VyQ3JlYXRlKSB7XG4gICAgICBjb25zdCB7IHJldHJ5LCBjcmVhdGUgfSA9IHRoaXMuc3RhdGU7XG4gICAgICBpZiAocmV0cnkgPiByZXRyaWVzKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yOiBSYW4gb3V0IG9mIHJldHJpZXMgZm9yIHN0YXJ0aW5nICR7aHViTmFtZX0hYCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHJldHJ5OiAwLFxuICAgICAgICAgIGNyZWF0ZTogMCxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB7IGJhc2VVcmwsIHNpZ25hbHJBY3Rpb25zIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBpZiAoYmFzZVVybCAmJiBodWJOYW1lKSB7XG4gICAgICAgICAgbGV0IGh1YkFkZHJlc3MgPSBiYXNlVXJsO1xuICAgICAgICAgIGlmIChzaWduYWxyUGF0aCkgaHViQWRkcmVzcyA9IGAke2h1YkFkZHJlc3N9LyR7c2lnbmFsclBhdGh9YDtcbiAgICAgICAgICBodWJBZGRyZXNzID0gYCR7aHViQWRkcmVzc30vJHtodWJOYW1lfWA7XG4gICAgICAgICAgdGhpcy50b2tlbiA9IHNpZ25hbHJBY3Rpb25zLmFjY2Vzc1Rva2VuRmFjdG9yeShhY2Nlc3NUb2tlbik7XG4gICAgICAgICAgaWYgKHRoaXMudG9rZW4pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLm9sZFRva2VuID09PSB0aGlzLnRva2VuKSB7XG4gICAgICAgICAgICAgIGlmICgoY3VyQ3JlYXRlIHx8IGNyZWF0ZSkgPiByZXRyaWVzKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdXYXJuaW5nOiBVbmFibGUgdG8gZ2V0IHVwLXRvLWRhdGUgYWNjZXNzIHRva2VuLicpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgaHViOiBudWxsLFxuICAgICAgICAgICAgICAgICAgY3JlYXRlOiAoY3VyQ3JlYXRlIHx8IGNyZWF0ZSkgKyAxLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMub2xkVG9rZW4gPSB1bmRlZmluZWQ7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IGh1YiA9IG5ldyBIdWJDb25uZWN0aW9uQnVpbGRlcigpXG4gICAgICAgICAgICAud2l0aFVybChodWJBZGRyZXNzLCB7XG4gICAgICAgICAgICAgIHNraXBOZWdvdGlhdGlvbjogdHJ1ZSxcbiAgICAgICAgICAgICAgdHJhbnNwb3J0OiBIdHRwVHJhbnNwb3J0VHlwZS5XZWJTb2NrZXRzLFxuICAgICAgICAgICAgICBhY2Nlc3NUb2tlbkZhY3Rvcnk6ICgpID0+IHRoaXMudG9rZW4sXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmJ1aWxkKCk7XG4gICAgICAgICAgaHViLm9uY2xvc2UgPSB0aGlzLmhhbmRsZUVycm9yO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgaHViLFxuICAgICAgICAgICAgcmV0cnk6IHJldHJ5ICsgMSxcbiAgICAgICAgICAgIGNyZWF0ZTogMCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHN0YXJ0SHViKGh1Yikge1xuICAgICAgaWYgKGh1Yikge1xuICAgICAgICBodWIuc3RhcnQoKVxuICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHsgcGVuZGluZywgYWN0aXZlIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICAgICAgaWYgKCF0aGlzLnBlbmRpbmcpIHRoaXMucGVuZGluZyA9IHBlbmRpbmcgfHwgTWFwKCk7XG4gICAgICAgICAgICBpZiAoIXRoaXMuYWN0aXZlKSB0aGlzLmFjdGl2ZSA9IGFjdGl2ZSB8fCBNYXAoKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBhY3RpdmU6IHRoaXMuYWN0aXZlLFxuICAgICAgICAgICAgICBwZW5kaW5nOiB0aGlzLnBlbmRpbmcsXG4gICAgICAgICAgICAgIHJldHJ5OiAwLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGBXYXJuaW5nOiBFcnJvciB3aGlsZSBlc3RhYmxpc2hpbmcgY29ubmVjdGlvbiB0byBodWIgJHtodWJOYW1lfS5cXG5cXG4ke2Vycn1gKTtcbiAgICAgICAgICAgIGh1Yi5zdG9wKCk7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZUVycm9yKGVycik7XG4gICAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaGFuZGxlRXJyb3IgPSAoZXJyKSA9PiB7XG4gICAgICBjb25zdCB7IHJlc3BvbnNlLCBzdGF0dXNDb2RlIH0gPSBlcnI7XG4gICAgICBjb25zdCB7IHN0YXR1cyB9ID0gcmVzcG9uc2UgfHwge307XG4gICAgICBzd2l0Y2ggKHN0YXR1cyB8fCBzdGF0dXNDb2RlKSB7XG4gICAgICAgIGNhc2UgNTAwOlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDQwMTpcbiAgICAgICAgICB0aGlzLm9sZFRva2VuID0gdGhpcy50b2tlbjsgLy8gZmFsbCB0aHJvdWdoXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGh1YjogbnVsbCB9KTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgc3RvcEh1YihodWIsIGNsZWFyKSB7XG4gICAgICBpZiAoaHViKSB7XG4gICAgICAgIGNvbnN0IHByb21pc2VzID0gW107XG5cbiAgICAgICAgaWYgKGNsZWFyKSB7XG4gICAgICAgICAgLy8gQ2xlYXIgcGVuZGluZ1xuICAgICAgICAgIHRoaXMucGVuZGluZyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICBwcm9taXNlcy5wdXNoKHRoaXMucmVtb3ZlRnJvbUdyb3VwKCcnKSk7XG4gICAgICAgICAgLy8gTWVyZ2UgYWN0aXZlIHRvIHBlbmRpbmdcbiAgICAgICAgfSBlbHNlIGlmICghdGhpcy5wZW5kaW5nKSB7XG4gICAgICAgICAgdGhpcy5wZW5kaW5nID0gdGhpcy5zdGF0ZS5hY3RpdmU7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmUpIHtcbiAgICAgICAgICB0aGlzLnBlbmRpbmcgPSB0aGlzLnBlbmRpbmcubWVyZ2VEZWVwKHRoaXMuc3RhdGUuYWN0aXZlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKCgpID0+IHtcbiAgICAgICAgICBodWIuc3RvcCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmFjdGl2ZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcGVuZGluZzogdGhpcy5wZW5kaW5nLFxuICAgICAgICAgIGFjdGl2ZTogdGhpcy5hY3RpdmUsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJlZ2lzdGVyTGlzdGVuZXIgPSAobmFtZSwgaGFuZGxlcikgPT4ge1xuICAgICAgY29uc3QgeyBwZW5kaW5nLCBhY3RpdmUsIG1vcmlidW5kIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgLy8gUmVtb3ZlIGxpc3RlbmVyIGZyb20gbW9yaWJ1bmQgbGlzdGVuZXJzXG4gICAgICBpZiAoIXRoaXMubW9yaWJ1bmQpIHRoaXMubW9yaWJ1bmQgPSBtb3JpYnVuZCB8fCBNYXAoKTtcbiAgICAgIGNvbnN0IGV4aXN0aW5nTW9yaWJ1bmQgPSB0aGlzLm1vcmlidW5kLmdldEluKFtuYW1lXSwgU2V0KCkpO1xuICAgICAgaWYgKGV4aXN0aW5nTW9yaWJ1bmQuaGFzKGhhbmRsZXIpKSB7XG4gICAgICAgIGNvbnN0IHJlbWFpbmluZ01vcmlidW5kID0gZXhpc3RpbmdNb3JpYnVuZC5maWx0ZXJOb3QoaCA9PiBoID09PSBoYW5kbGVyKTtcbiAgICAgICAgdGhpcy5tb3JpYnVuZCA9IHJlbWFpbmluZ01vcmlidW5kLnNpemVcbiAgICAgICAgICA/IHRoaXMubW9yaWJ1bmQuc2V0SW4oW25hbWVdLCByZW1haW5pbmdNb3JpYnVuZCkgOiB0aGlzLm1vcmlidW5kLmRlbGV0ZShuYW1lKTtcbiAgICAgIH1cbiAgICAgIC8vIEFkZCBsaXN0ZW5lciB0byBwZW5kaW5nIGxpc3RlbmVycyAoaWYgaXQgaXMgTk9UIGFjdGl2ZSlcbiAgICAgIGlmICghdGhpcy5hY3RpdmUpIHRoaXMuYWN0aXZlID0gYWN0aXZlIHx8IE1hcCgpO1xuICAgICAgY29uc3QgZXhpc3RpbmdBY3RpdmUgPSB0aGlzLmFjdGl2ZS5nZXRJbihbbmFtZV0sIFNldCgpKTtcbiAgICAgIGlmICghZXhpc3RpbmdBY3RpdmUuaGFzKGhhbmRsZXIpKSB7XG4gICAgICAgIGlmICghdGhpcy5wZW5kaW5nKSB0aGlzLnBlbmRpbmcgPSBwZW5kaW5nIHx8IE1hcCgpO1xuICAgICAgICBjb25zdCBleGlzdGluZ1BlbmRpbmcgPSB0aGlzLnBlbmRpbmcuZ2V0SW4oW25hbWVdLCBTZXQoKSk7XG4gICAgICAgIGlmICghZXhpc3RpbmdQZW5kaW5nLmhhcyhoYW5kbGVyKSkge1xuICAgICAgICAgIHRoaXMucGVuZGluZyA9IHRoaXMucGVuZGluZy5zZXRJbihbbmFtZV0sIGV4aXN0aW5nUGVuZGluZy5hZGQoaGFuZGxlcikpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5wZW5kaW5nICE9PSBwZW5kaW5nIHx8IHRoaXMubW9yaWJ1bmQgIT09IG1vcmlidW5kKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHBlbmRpbmc6IHRoaXMucGVuZGluZyxcbiAgICAgICAgICBtb3JpYnVuZDogdGhpcy5tb3JpYnVuZCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHVucmVnaXN0ZXJMaXN0ZW5lciA9IChuYW1lLCBoYW5kbGVyKSA9PiB7XG4gICAgICBjb25zdCB7IHBlbmRpbmcsIGFjdGl2ZSwgbW9yaWJ1bmQgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAvLyBSZW1vdmUgbGlzdGVuZXIgZnJvbSBwZW5kaW5nIGxpc3RlbmVyc1xuICAgICAgaWYgKCF0aGlzLnBlbmRpbmcpIHRoaXMucGVuZGluZyA9IHBlbmRpbmcgfHwgTWFwKCk7XG4gICAgICBjb25zdCBleGlzdGluZ1BlbmRpbmcgPSB0aGlzLnBlbmRpbmcuZ2V0SW4oW25hbWVdLCBTZXQoKSk7XG4gICAgICBpZiAoZXhpc3RpbmdQZW5kaW5nLmhhcyhoYW5kbGVyKSkge1xuICAgICAgICBjb25zdCByZW1haW5pbmdQZW5kaW5nID0gZXhpc3RpbmdQZW5kaW5nLmZpbHRlck5vdChoID0+IGggPT09IGhhbmRsZXIpO1xuICAgICAgICB0aGlzLnBlbmRpbmcgPSByZW1haW5pbmdQZW5kaW5nLmNvdW50KClcbiAgICAgICAgICA/IHRoaXMucGVuZGluZy5zZXRJbihbbmFtZV0sIHJlbWFpbmluZ1BlbmRpbmcpXG4gICAgICAgICAgOiB0aGlzLnBlbmRpbmcuZGVsZXRlKG5hbWUpO1xuICAgICAgfVxuICAgICAgLy8gQWRkIGxpc3RlbmVyIHRvIG1vcmlidW5kIGxpc3RlbmVycyAoaWYgaXQgaXMgYWN0aXZlKVxuICAgICAgaWYgKCF0aGlzLmFjdGl2ZSkgdGhpcy5hY3RpdmUgPSBhY3RpdmUgfHwgTWFwKCk7XG4gICAgICBjb25zdCBleGlzdGluZ0FjdGl2ZSA9IHRoaXMuYWN0aXZlLmdldEluKFtuYW1lXSwgU2V0KCkpO1xuICAgICAgaWYgKGV4aXN0aW5nQWN0aXZlLmhhcyhoYW5kbGVyKSkge1xuICAgICAgICBpZiAoIXRoaXMubW9yaWJ1bmQpIHRoaXMubW9yaWJ1bmQgPSBtb3JpYnVuZCB8fCBNYXAoKTtcbiAgICAgICAgY29uc3QgZXhpc3RpbmdNb3JpYnVuZCA9IHRoaXMubW9yaWJ1bmQuZ2V0SW4oW25hbWVdLCBTZXQoKSk7XG4gICAgICAgIGlmICghZXhpc3RpbmdNb3JpYnVuZC5oYXMoaGFuZGxlcikpIHtcbiAgICAgICAgICB0aGlzLm1vcmlidW5kID0gdGhpcy5tb3JpYnVuZC5zZXRJbihbbmFtZV0sIGV4aXN0aW5nTW9yaWJ1bmQuYWRkKGhhbmRsZXIpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHRoaXMucGVuZGluZyAhPT0gcGVuZGluZyB8fCB0aGlzLm1vcmlidW5kICE9PSBtb3JpYnVuZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nOiB0aGlzLnBlbmRpbmcsXG4gICAgICAgICAgbW9yaWJ1bmQ6IHRoaXMubW9yaWJ1bmQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBhY3RpdmF0ZUxpc3RlbmVycyhodWIsIHBlbmRpbmdQYXJhbSkge1xuICAgICAgbGV0IHBlbmRpbmcgPSBwZW5kaW5nUGFyYW07XG4gICAgICBpZiAoaHViICYmIHBlbmRpbmdQYXJhbSkge1xuICAgICAgICBjb25zdCB7IGNvbm5lY3Rpb24gfSA9IGh1YjtcbiAgICAgICAgaWYgKGNvbm5lY3Rpb24gJiYgY29ubmVjdGlvbi5jb25uZWN0aW9uU3RhdGUgPT09IDEpIHtcbiAgICAgICAgICBjb25zdCB7IGFjdGl2ZSB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgICBpZiAoIXRoaXMuYWN0aXZlKSB0aGlzLmFjdGl2ZSA9IGFjdGl2ZSB8fCBNYXAoKTtcbiAgICAgICAgICBpZiAodGhpcy5hY3RpdmUucmVkdWNlKHRoaXMuY291bnQsIDApKSB7XG4gICAgICAgICAgICBwZW5kaW5nID0gcGVuZGluZy5tYXBFbnRyaWVzKChbbmFtZSwgY3VySGFuZGxlcnNdKSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5hY3RpdmUuZ2V0SW4oW25hbWVdKTtcbiAgICAgICAgICAgICAgY29uc3QgaGFuZGxlcnMgPSBleGlzdGluZ1xuICAgICAgICAgICAgICAgID8gY3VySGFuZGxlcnMuZmlsdGVyTm90KGhhbmRsZXIgPT4gZXhpc3RpbmcuaGFzKGhhbmRsZXIpKVxuICAgICAgICAgICAgICAgIDogY3VySGFuZGxlcnM7XG4gICAgICAgICAgICAgIHJldHVybiBbbmFtZSwgaGFuZGxlcnNdO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHBlbmRpbmcubWFwRW50cmllcygoW25hbWUsIGhhbmRsZXJzXSkgPT4gaGFuZGxlcnMubWFwKGhhbmRsZXIgPT4gaHViLm9uKG5hbWUsIGhhbmRsZXIpKSk7XG4gICAgICAgICAgdGhpcy5hY3RpdmUgPSB0aGlzLmFjdGl2ZS5tZXJnZURlZXAocGVuZGluZyk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwZW5kaW5nOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBhY3RpdmU6IHRoaXMuYWN0aXZlLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBwZW5kaW5nO1xuICAgIH1cblxuICAgIGluYWN0aXZhdGVMaXN0ZW5lcnMoaHViLCBtb3JpYnVuZCkge1xuICAgICAgaWYgKGh1YiAmJiBtb3JpYnVuZCkge1xuICAgICAgICBtb3JpYnVuZC5tYXBFbnRyaWVzKChbbmFtZSwgaGFuZGxlcnNdKSA9PiBoYW5kbGVycy5tYXAoaGFuZGxlciA9PiBodWIub2ZmKG5hbWUsIGhhbmRsZXIpKSk7XG4gICAgICAgIGNvbnN0IHsgYWN0aXZlIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICBpZiAoIXRoaXMuYWN0aXZlKSB0aGlzLmFjdGl2ZSA9IGFjdGl2ZSB8fCBNYXAoKTtcbiAgICAgICAgdGhpcy5hY3RpdmUgPSB0aGlzLmFjdGl2ZS5tYXBFbnRyaWVzKChbbmFtZSwgY3VySGFuZGxlcnNdKSA9PiB7XG4gICAgICAgICAgY29uc3QgcmVtb3ZhYmxlID0gbW9yaWJ1bmQuZ2V0SW4oW25hbWVdKTtcbiAgICAgICAgICBjb25zdCBoYW5kbGVycyA9IHJlbW92YWJsZVxuICAgICAgICAgICAgPyBjdXJIYW5kbGVycy5maWx0ZXJOb3QoaGFuZGxlciA9PiByZW1vdmFibGUuaGFzKGhhbmRsZXIpKVxuICAgICAgICAgICAgOiBjdXJIYW5kbGVycztcbiAgICAgICAgICByZXR1cm4gW25hbWUsIGhhbmRsZXJzXTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZTogdGhpcy5hY3RpdmUsXG4gICAgICAgICAgbW9yaWJ1bmQ6IHVuZGVmaW5lZCxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICByZXR1cm4gbW9yaWJ1bmQ7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgY29uc3QgeyBiYXNlVXJsLCBzaWduYWxyQWN0aW9ucywgLi4ucGFzc1Rocm91Z2hQcm9wcyB9ID0gdGhpcy5wcm9wcztcbiAgICAgIGNvbnN0IGh1YlByb3AgPSB7IFtodWJOYW1lXTogdGhpcy5odWJQcm94eSB9O1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgPFdyYXBwZWRDb21wb25lbnRcbiAgICAgICAgICB7Li4ucGFzc1Rocm91Z2hQcm9wc31cbiAgICAgICAgICB7Li4uaHViUHJvcH1cbiAgICAgICAgLz5cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgSW5qZWN0U2lnbmFsUi5kaXNwbGF5TmFtZSA9IGBJbmplY3RTaWduYWxSKCR7Z2V0RGlzcGxheU5hbWUoV3JhcHBlZENvbXBvbmVudCl9KWA7XG5cbiAgSW5qZWN0U2lnbmFsUi5wcm9wVHlwZXMgPSB7XG4gICAgYmFzZVVybDogUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICAgIHNpZ25hbHJBY3Rpb25zOiBQcm9wVHlwZXMuc2hhcGUoe1xuICAgICAgZ2V0QWNjZXNzVG9rZW46IFByb3BUeXBlcy5mdW5jLFxuICAgIH0pLmlzUmVxdWlyZWQsXG4gIH07XG5cbiAgY29uc3QgZ2V0VmFsdWVGcm9tU3RhdGUgPSAoc3RhdGUsIHNvdXJjZSkgPT4ge1xuICAgIGlmICh0eXBlb2Ygc291cmNlID09PSAnZnVuY3Rpb24nKSByZXR1cm4gc291cmNlKHN0YXRlKTtcbiAgICBpZiAodHlwZW9mIHNvdXJjZSA9PT0gJ3N0cmluZycpIHJldHVybiBzb3VyY2U7XG4gICAgcmV0dXJuICcnO1xuICB9O1xuXG4gIGNvbnN0IG1hcERpc3BhdGNoVG9Qcm9wcyA9IGRpc3BhdGNoID0+ICh7XG4gICAgc2lnbmFsckFjdGlvbnM6IGJpbmRBY3Rpb25DcmVhdG9ycyh7XG4gICAgICBhY2Nlc3NUb2tlbkZhY3Rvcnk6ICgpID0+IChkaXNwYXRjaGVyLCBnZXRTdGF0ZSkgPT4ge1xuICAgICAgICBjb25zdCBzdGF0ZSA9IGdldFN0YXRlKCk7XG4gICAgICAgIHJldHVybiBnZXRWYWx1ZUZyb21TdGF0ZShzdGF0ZSwgYWNjZXNzVG9rZW4pO1xuICAgICAgfSxcbiAgICB9LCBkaXNwYXRjaCksXG4gIH0pO1xuXG4gIGNvbnN0IG1hcFN0YXRlVG9Qcm9wcyA9IChzdGF0ZSkgPT4ge1xuICAgIGNvbnN0IGJhc2VVcmwgPSBnZXRWYWx1ZUZyb21TdGF0ZShzdGF0ZSwgYmFzZUFkZHJlc3MpO1xuICAgIHJldHVybiB7IGJhc2VVcmwgfTtcbiAgfTtcblxuICByZXR1cm4gY29ubmVjdChtYXBTdGF0ZVRvUHJvcHMsIG1hcERpc3BhdGNoVG9Qcm9wcykoSW5qZWN0U2lnbmFsUik7XG59O1xuXG5leHBvcnQgZGVmYXVsdCBpbmplY3RTaWduYWxSO1xuIl19 -------------------------------------------------------------------------------- /lib/cjs/types.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _propTypes = require('prop-types'); 6 | 7 | var _propTypes2 = _interopRequireDefault(_propTypes); 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 10 | 11 | var func = _propTypes2.default.func; 12 | 13 | 14 | var hubShape = _propTypes2.default.shape({ 15 | invoke: func.isRequired, 16 | send: func.isRequired, 17 | add: func.isRequired, 18 | remove: func.isRequired, 19 | register: func.isRequired, 20 | unregister: func.isRequired 21 | }); 22 | 23 | exports.default = hubShape; 24 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eXBlcy5qc3giXSwibmFtZXMiOlsiZnVuYyIsIlByb3BUeXBlcyIsImh1YlNoYXBlIiwic2hhcGUiLCJpbnZva2UiLCJpc1JlcXVpcmVkIiwic2VuZCIsImFkZCIsInJlbW92ZSIsInJlZ2lzdGVyIiwidW5yZWdpc3RlciJdLCJtYXBwaW5ncyI6Ijs7OztBQUFBOzs7Ozs7SUFFUUEsSSxHQUFTQyxtQixDQUFURCxJOzs7QUFFUixJQUFNRSxXQUFXRCxvQkFBVUUsS0FBVixDQUFnQjtBQUMvQkMsVUFBUUosS0FBS0ssVUFEa0I7QUFFL0JDLFFBQU1OLEtBQUtLLFVBRm9CO0FBRy9CRSxPQUFLUCxLQUFLSyxVQUhxQjtBQUkvQkcsVUFBUVIsS0FBS0ssVUFKa0I7QUFLL0JJLFlBQVVULEtBQUtLLFVBTGdCO0FBTS9CSyxjQUFZVixLQUFLSztBQU5jLENBQWhCLENBQWpCOztrQkFTZUgsUSIsImZpbGUiOiJ0eXBlcy5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBQcm9wVHlwZXMgZnJvbSAncHJvcC10eXBlcyc7XG5cbmNvbnN0IHsgZnVuYyB9ID0gUHJvcFR5cGVzO1xuXG5jb25zdCBodWJTaGFwZSA9IFByb3BUeXBlcy5zaGFwZSh7XG4gIGludm9rZTogZnVuYy5pc1JlcXVpcmVkLFxuICBzZW5kOiBmdW5jLmlzUmVxdWlyZWQsXG4gIGFkZDogZnVuYy5pc1JlcXVpcmVkLFxuICByZW1vdmU6IGZ1bmMuaXNSZXF1aXJlZCxcbiAgcmVnaXN0ZXI6IGZ1bmMuaXNSZXF1aXJlZCxcbiAgdW5yZWdpc3RlcjogZnVuYy5pc1JlcXVpcmVkLFxufSk7XG5cbmV4cG9ydCBkZWZhdWx0IGh1YlNoYXBlO1xuIl19 -------------------------------------------------------------------------------- /lib/es/index.js: -------------------------------------------------------------------------------- 1 | export { default as hubShape } from './types'; 2 | export { default as injectSignalR } from './inject'; 3 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbmRleC5qcyJdLCJuYW1lcyI6WyJkZWZhdWx0IiwiaHViU2hhcGUiLCJpbmplY3RTaWduYWxSIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxXQUFXQyxRQUFwQixRQUFvQyxTQUFwQztBQUNBLFNBQVNELFdBQVdFLGFBQXBCLFFBQXlDLFVBQXpDIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgZGVmYXVsdCBhcyBodWJTaGFwZSB9IGZyb20gJy4vdHlwZXMnO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBpbmplY3RTaWduYWxSIH0gZnJvbSAnLi9pbmplY3QnO1xuIl19 -------------------------------------------------------------------------------- /lib/es/inject.js: -------------------------------------------------------------------------------- 1 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 2 | 3 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } 4 | 5 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 6 | 7 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 8 | 9 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 10 | 11 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 12 | 13 | import React from 'react'; 14 | import PropTypes from 'prop-types'; 15 | import axios from 'axios'; 16 | import { bindActionCreators } from 'redux'; 17 | import { connect } from 'react-redux'; 18 | import { Map, Set } from 'immutable'; 19 | import { HubConnectionBuilder, HttpTransportType } from '@aspnet/signalr'; 20 | 21 | var getDisplayName = function getDisplayName(Component) { 22 | return Component.displayName || Component.name || 'Component'; 23 | }; 24 | 25 | var injectSignalR = function injectSignalR(options) { 26 | return function (WrappedComponent) { 27 | var _class, _temp; 28 | 29 | var _options$hubName = options.hubName, 30 | hubName = _options$hubName === undefined ? '' : _options$hubName, 31 | _options$baseAddress = options.baseAddress, 32 | baseAddress = _options$baseAddress === undefined ? 'http://localhost:5555' : _options$baseAddress, 33 | _options$accessToken = options.accessToken, 34 | accessToken = _options$accessToken === undefined ? null : _options$accessToken, 35 | _options$signalrPath = options.signalrPath, 36 | signalrPath = _options$signalrPath === undefined ? 'signalr' : _options$signalrPath, 37 | _options$retries = options.retries, 38 | retries = _options$retries === undefined ? 3 : _options$retries; 39 | var _options$controller = options.controller, 40 | controller = _options$controller === undefined ? hubName : _options$controller; 41 | var InjectSignalR = (_temp = _class = function (_React$PureComponent) { 42 | _inherits(InjectSignalR, _React$PureComponent); 43 | 44 | function InjectSignalR(props) { 45 | _classCallCheck(this, InjectSignalR); 46 | 47 | var _this = _possibleConstructorReturn(this, _React$PureComponent.call(this, props)); 48 | 49 | _this.count = function (c, s) { 50 | return c + s.count(); 51 | }; 52 | 53 | _this.addToGroup = function (group) { 54 | var hub = _this.state.hub; 55 | 56 | if (hub) { 57 | var connection = hub.connection; 58 | 59 | if (connection && connection.connectionState === 1) { 60 | hub.invoke('addToGroup', group).catch(function (err) { 61 | console.error('Error: Adding client to group ' + group + ' in ' + hubName + ' failed.\n\n' + err); 62 | }); 63 | } 64 | } 65 | }; 66 | 67 | _this.removeFromGroup = function (group) { 68 | var hub = _this.state.hub; 69 | 70 | if (hub) { 71 | var connection = hub.connection; 72 | 73 | if (connection && connection.connectionState === 1) { 74 | return hub.invoke('removeFromGroup', group).catch(function (err) { 75 | console.error('Error: Removing client from group ' + group + ' in ' + hubName + ' failed.\n\n' + err); 76 | }); 77 | } 78 | } 79 | return Promise.resolve(); 80 | }; 81 | 82 | _this.sendToController = function (target) { 83 | var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; 84 | 85 | var url = _this.props.baseUrl + '/' + controller + '/' + target; 86 | var payload = data ? data.toJS() : null; 87 | return axios.post(url, payload).catch(function (err) { 88 | console.error('Error: Sending data to ' + controller + ' failed.\n\n' + err); 89 | }); 90 | }; 91 | 92 | _this.invokeController = function (targetMethod) { 93 | var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; 94 | 95 | var urlBase = _this.props.baseUrl + '/' + controller + '/' + targetMethod; 96 | var url = data ? urlBase + '/' + data : urlBase; 97 | return axios.get(url).catch(function (err) { 98 | console.error('Error: Invoking ' + controller + ' failed.\n\n' + err); 99 | }); 100 | }; 101 | 102 | _this.handleError = function (err) { 103 | var response = err.response, 104 | statusCode = err.statusCode; 105 | 106 | var _ref = response || {}, 107 | status = _ref.status; 108 | 109 | switch (status || statusCode) { 110 | case 500: 111 | break; 112 | case 401: 113 | _this.oldToken = _this.token; // fall through 114 | default: 115 | _this.setState({ hub: null }); 116 | break; 117 | } 118 | }; 119 | 120 | _this.registerListener = function (name, handler) { 121 | var _this$state = _this.state, 122 | pending = _this$state.pending, 123 | active = _this$state.active, 124 | moribund = _this$state.moribund; 125 | // Remove listener from moribund listeners 126 | 127 | if (!_this.moribund) _this.moribund = moribund || Map(); 128 | var existingMoribund = _this.moribund.getIn([name], Set()); 129 | if (existingMoribund.has(handler)) { 130 | var remainingMoribund = existingMoribund.filterNot(function (h) { 131 | return h === handler; 132 | }); 133 | _this.moribund = remainingMoribund.size ? _this.moribund.setIn([name], remainingMoribund) : _this.moribund.delete(name); 134 | } 135 | // Add listener to pending listeners (if it is NOT active) 136 | if (!_this.active) _this.active = active || Map(); 137 | var existingActive = _this.active.getIn([name], Set()); 138 | if (!existingActive.has(handler)) { 139 | if (!_this.pending) _this.pending = pending || Map(); 140 | var existingPending = _this.pending.getIn([name], Set()); 141 | if (!existingPending.has(handler)) { 142 | _this.pending = _this.pending.setIn([name], existingPending.add(handler)); 143 | } 144 | } 145 | if (_this.pending !== pending || _this.moribund !== moribund) { 146 | _this.setState({ 147 | pending: _this.pending, 148 | moribund: _this.moribund 149 | }); 150 | } 151 | }; 152 | 153 | _this.unregisterListener = function (name, handler) { 154 | var _this$state2 = _this.state, 155 | pending = _this$state2.pending, 156 | active = _this$state2.active, 157 | moribund = _this$state2.moribund; 158 | // Remove listener from pending listeners 159 | 160 | if (!_this.pending) _this.pending = pending || Map(); 161 | var existingPending = _this.pending.getIn([name], Set()); 162 | if (existingPending.has(handler)) { 163 | var remainingPending = existingPending.filterNot(function (h) { 164 | return h === handler; 165 | }); 166 | _this.pending = remainingPending.count() ? _this.pending.setIn([name], remainingPending) : _this.pending.delete(name); 167 | } 168 | // Add listener to moribund listeners (if it is active) 169 | if (!_this.active) _this.active = active || Map(); 170 | var existingActive = _this.active.getIn([name], Set()); 171 | if (existingActive.has(handler)) { 172 | if (!_this.moribund) _this.moribund = moribund || Map(); 173 | var existingMoribund = _this.moribund.getIn([name], Set()); 174 | if (!existingMoribund.has(handler)) { 175 | _this.moribund = _this.moribund.setIn([name], existingMoribund.add(handler)); 176 | } 177 | } 178 | if (_this.pending !== pending || _this.moribund !== moribund) { 179 | _this.setState({ 180 | pending: _this.pending, 181 | moribund: _this.moribund 182 | }); 183 | } 184 | }; 185 | 186 | _this.state = { 187 | hub: null, 188 | pending: undefined, 189 | active: undefined, 190 | moribund: undefined, 191 | retry: 0, 192 | create: 0 193 | }; 194 | return _this; 195 | } 196 | 197 | InjectSignalR.prototype.componentWillMount = function componentWillMount() { 198 | this.hubProxy = { 199 | send: this.sendToController, 200 | invoke: this.invokeController, 201 | add: this.addToGroup, 202 | remove: this.removeFromGroup, 203 | connectionId: undefined, 204 | register: this.registerListener, 205 | unregister: this.unregisterListener 206 | }; 207 | }; 208 | 209 | InjectSignalR.prototype.componentDidMount = function componentDidMount() { 210 | this.createHub(); 211 | }; 212 | 213 | InjectSignalR.prototype.componentWillUpdate = function componentWillUpdate(nextProps, nextState) { 214 | if (this.state.hub !== nextState.hub) { 215 | if (this.state.hub) this.stopHub(this.state.hub, false); 216 | if (nextState.hub) { 217 | this.startHub(nextState.hub); 218 | } else { 219 | this.createHub(nextState.create); 220 | } 221 | } else if (!nextState.hub) { 222 | this.createHub(nextState.create); 223 | } else { 224 | var pending = nextState.pending, 225 | moribund = nextState.moribund; 226 | 227 | if (!moribund) { 228 | moribund = this.moribund || Map(); 229 | } else if (this.moribund) { 230 | moribund = moribund.mergeDeep(this.moribund); 231 | } 232 | var moribundCount = moribund.reduce(this.count, 0); 233 | if (moribundCount) { 234 | this.moribund = this.inactivateListeners(this.state.hub, moribund); 235 | } 236 | if (!pending) { 237 | pending = this.pending || Map(); 238 | } else if (this.pending) { 239 | pending = pending.mergeDeep(this.pending); 240 | } 241 | var pendingCount = pending.reduce(this.count, 0); 242 | if (pendingCount) { 243 | this.pending = this.activateListeners(nextState.hub, pending); 244 | } 245 | } 246 | }; 247 | 248 | InjectSignalR.prototype.componentWillUnmount = function componentWillUnmount() { 249 | this.stopHub(this.state.hub, true); 250 | }; 251 | 252 | InjectSignalR.prototype.createHub = function () { 253 | var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(curCreate) { 254 | var _this2 = this; 255 | 256 | var _state, retry, create, _props, baseUrl, signalrActions, hubAddress, hub; 257 | 258 | return regeneratorRuntime.wrap(function _callee$(_context) { 259 | while (1) { 260 | switch (_context.prev = _context.next) { 261 | case 0: 262 | _state = this.state, retry = _state.retry, create = _state.create; 263 | 264 | if (!(retry > retries)) { 265 | _context.next = 6; 266 | break; 267 | } 268 | 269 | console.error('Error: Ran out of retries for starting ' + hubName + '!'); 270 | this.setState({ 271 | retry: 0, 272 | create: 0 273 | }); 274 | _context.next = 20; 275 | break; 276 | 277 | case 6: 278 | _props = this.props, baseUrl = _props.baseUrl, signalrActions = _props.signalrActions; 279 | 280 | if (!(baseUrl && hubName)) { 281 | _context.next = 20; 282 | break; 283 | } 284 | 285 | hubAddress = baseUrl; 286 | 287 | if (signalrPath) hubAddress = hubAddress + '/' + signalrPath; 288 | hubAddress = hubAddress + '/' + hubName; 289 | this.token = signalrActions.accessTokenFactory(accessToken); 290 | 291 | if (!this.token) { 292 | _context.next = 17; 293 | break; 294 | } 295 | 296 | if (!(this.oldToken === this.token)) { 297 | _context.next = 16; 298 | break; 299 | } 300 | 301 | if ((curCreate || create) > retries) { 302 | console.warn('Warning: Unable to get up-to-date access token.'); 303 | } else { 304 | this.setState({ 305 | hub: null, 306 | create: (curCreate || create) + 1 307 | }); 308 | } 309 | return _context.abrupt('return'); 310 | 311 | case 16: 312 | this.oldToken = undefined; 313 | 314 | case 17: 315 | hub = new HubConnectionBuilder().withUrl(hubAddress, { 316 | skipNegotiation: true, 317 | transport: HttpTransportType.WebSockets, 318 | accessTokenFactory: function accessTokenFactory() { 319 | return _this2.token; 320 | } 321 | }).build(); 322 | 323 | hub.onclose = this.handleError; 324 | this.setState({ 325 | hub: hub, 326 | retry: retry + 1, 327 | create: 0 328 | }); 329 | 330 | case 20: 331 | case 'end': 332 | return _context.stop(); 333 | } 334 | } 335 | }, _callee, this); 336 | })); 337 | 338 | function createHub(_x3) { 339 | return _ref2.apply(this, arguments); 340 | } 341 | 342 | return createHub; 343 | }(); 344 | 345 | InjectSignalR.prototype.startHub = function startHub(hub) { 346 | var _this3 = this; 347 | 348 | if (hub) { 349 | hub.start().then(function () { 350 | var _state2 = _this3.state, 351 | pending = _state2.pending, 352 | active = _state2.active; 353 | 354 | if (!_this3.pending) _this3.pending = pending || Map(); 355 | if (!_this3.active) _this3.active = active || Map(); 356 | _this3.setState({ 357 | active: _this3.active, 358 | pending: _this3.pending, 359 | retry: 0 360 | }); 361 | }).catch(function (err) { 362 | console.warn('Warning: Error while establishing connection to hub ' + hubName + '.\n\n' + err); 363 | hub.stop(); 364 | _this3.handleError(err); 365 | }); 366 | } 367 | }; 368 | 369 | InjectSignalR.prototype.stopHub = function stopHub(hub, clear) { 370 | if (hub) { 371 | var promises = []; 372 | 373 | if (clear) { 374 | // Clear pending 375 | this.pending = undefined; 376 | promises.push(this.removeFromGroup('')); 377 | // Merge active to pending 378 | } else if (!this.pending) { 379 | this.pending = this.state.active; 380 | } else if (this.state.active) { 381 | this.pending = this.pending.mergeDeep(this.state.active); 382 | } 383 | 384 | Promise.all(promises).then(function () { 385 | hub.stop(); 386 | }); 387 | 388 | this.active = undefined; 389 | this.setState({ 390 | pending: this.pending, 391 | active: this.active 392 | }); 393 | } 394 | }; 395 | 396 | InjectSignalR.prototype.activateListeners = function activateListeners(hub, pendingParam) { 397 | var _this4 = this; 398 | 399 | var pending = pendingParam; 400 | if (hub && pendingParam) { 401 | var connection = hub.connection; 402 | 403 | if (connection && connection.connectionState === 1) { 404 | var active = this.state.active; 405 | 406 | if (!this.active) this.active = active || Map(); 407 | if (this.active.reduce(this.count, 0)) { 408 | pending = pending.mapEntries(function (_ref3) { 409 | var name = _ref3[0], 410 | curHandlers = _ref3[1]; 411 | 412 | var existing = _this4.active.getIn([name]); 413 | var handlers = existing ? curHandlers.filterNot(function (handler) { 414 | return existing.has(handler); 415 | }) : curHandlers; 416 | return [name, handlers]; 417 | }); 418 | } 419 | pending.mapEntries(function (_ref4) { 420 | var name = _ref4[0], 421 | handlers = _ref4[1]; 422 | return handlers.map(function (handler) { 423 | return hub.on(name, handler); 424 | }); 425 | }); 426 | this.active = this.active.mergeDeep(pending); 427 | this.setState({ 428 | pending: undefined, 429 | active: this.active 430 | }); 431 | return undefined; 432 | } 433 | } 434 | return pending; 435 | }; 436 | 437 | InjectSignalR.prototype.inactivateListeners = function inactivateListeners(hub, moribund) { 438 | if (hub && moribund) { 439 | moribund.mapEntries(function (_ref5) { 440 | var name = _ref5[0], 441 | handlers = _ref5[1]; 442 | return handlers.map(function (handler) { 443 | return hub.off(name, handler); 444 | }); 445 | }); 446 | var active = this.state.active; 447 | 448 | if (!this.active) this.active = active || Map(); 449 | this.active = this.active.mapEntries(function (_ref6) { 450 | var name = _ref6[0], 451 | curHandlers = _ref6[1]; 452 | 453 | var removable = moribund.getIn([name]); 454 | var handlers = removable ? curHandlers.filterNot(function (handler) { 455 | return removable.has(handler); 456 | }) : curHandlers; 457 | return [name, handlers]; 458 | }); 459 | this.setState({ 460 | active: this.active, 461 | moribund: undefined 462 | }); 463 | return undefined; 464 | } 465 | return moribund; 466 | }; 467 | 468 | InjectSignalR.prototype.render = function render() { 469 | var _hubProp; 470 | 471 | var _props2 = this.props, 472 | baseUrl = _props2.baseUrl, 473 | signalrActions = _props2.signalrActions, 474 | passThroughProps = _objectWithoutProperties(_props2, ['baseUrl', 'signalrActions']); 475 | 476 | var hubProp = (_hubProp = {}, _hubProp[hubName] = this.hubProxy, _hubProp); 477 | return React.createElement(WrappedComponent, _extends({}, passThroughProps, hubProp)); 478 | }; 479 | 480 | return InjectSignalR; 481 | }(React.PureComponent), _class.WrappedComponent = WrappedComponent, _temp); 482 | 483 | 484 | InjectSignalR.displayName = 'InjectSignalR(' + getDisplayName(WrappedComponent) + ')'; 485 | 486 | var getValueFromState = function getValueFromState(state, source) { 487 | if (typeof source === 'function') return source(state); 488 | if (typeof source === 'string') return source; 489 | return ''; 490 | }; 491 | 492 | var mapDispatchToProps = function mapDispatchToProps(dispatch) { 493 | return { 494 | signalrActions: bindActionCreators({ 495 | accessTokenFactory: function accessTokenFactory() { 496 | return function (dispatcher, getState) { 497 | var state = getState(); 498 | return getValueFromState(state, accessToken); 499 | }; 500 | } 501 | }, dispatch) 502 | }; 503 | }; 504 | 505 | var mapStateToProps = function mapStateToProps(state) { 506 | var baseUrl = getValueFromState(state, baseAddress); 507 | return { baseUrl: baseUrl }; 508 | }; 509 | 510 | return connect(mapStateToProps, mapDispatchToProps)(InjectSignalR); 511 | }; 512 | }; 513 | 514 | export default injectSignalR; 515 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbmplY3QuanN4Il0sIm5hbWVzIjpbIlJlYWN0IiwiUHJvcFR5cGVzIiwiYXhpb3MiLCJiaW5kQWN0aW9uQ3JlYXRvcnMiLCJjb25uZWN0IiwiTWFwIiwiU2V0IiwiSHViQ29ubmVjdGlvbkJ1aWxkZXIiLCJIdHRwVHJhbnNwb3J0VHlwZSIsImdldERpc3BsYXlOYW1lIiwiQ29tcG9uZW50IiwiZGlzcGxheU5hbWUiLCJuYW1lIiwiaW5qZWN0U2lnbmFsUiIsIldyYXBwZWRDb21wb25lbnQiLCJvcHRpb25zIiwiaHViTmFtZSIsImJhc2VBZGRyZXNzIiwiYWNjZXNzVG9rZW4iLCJzaWduYWxyUGF0aCIsInJldHJpZXMiLCJjb250cm9sbGVyIiwiSW5qZWN0U2lnbmFsUiIsInByb3BzIiwiY291bnQiLCJjIiwicyIsImFkZFRvR3JvdXAiLCJncm91cCIsImh1YiIsInN0YXRlIiwiY29ubmVjdGlvbiIsImNvbm5lY3Rpb25TdGF0ZSIsImludm9rZSIsImNhdGNoIiwiZXJyIiwiY29uc29sZSIsImVycm9yIiwicmVtb3ZlRnJvbUdyb3VwIiwiUHJvbWlzZSIsInJlc29sdmUiLCJzZW5kVG9Db250cm9sbGVyIiwidGFyZ2V0IiwiZGF0YSIsInVybCIsImJhc2VVcmwiLCJwYXlsb2FkIiwidG9KUyIsInBvc3QiLCJpbnZva2VDb250cm9sbGVyIiwidGFyZ2V0TWV0aG9kIiwidXJsQmFzZSIsImdldCIsImhhbmRsZUVycm9yIiwicmVzcG9uc2UiLCJzdGF0dXNDb2RlIiwic3RhdHVzIiwib2xkVG9rZW4iLCJ0b2tlbiIsInNldFN0YXRlIiwicmVnaXN0ZXJMaXN0ZW5lciIsImhhbmRsZXIiLCJwZW5kaW5nIiwiYWN0aXZlIiwibW9yaWJ1bmQiLCJleGlzdGluZ01vcmlidW5kIiwiZ2V0SW4iLCJoYXMiLCJyZW1haW5pbmdNb3JpYnVuZCIsImZpbHRlck5vdCIsImgiLCJzaXplIiwic2V0SW4iLCJkZWxldGUiLCJleGlzdGluZ0FjdGl2ZSIsImV4aXN0aW5nUGVuZGluZyIsImFkZCIsInVucmVnaXN0ZXJMaXN0ZW5lciIsInJlbWFpbmluZ1BlbmRpbmciLCJ1bmRlZmluZWQiLCJyZXRyeSIsImNyZWF0ZSIsImNvbXBvbmVudFdpbGxNb3VudCIsImh1YlByb3h5Iiwic2VuZCIsInJlbW92ZSIsImNvbm5lY3Rpb25JZCIsInJlZ2lzdGVyIiwidW5yZWdpc3RlciIsImNvbXBvbmVudERpZE1vdW50IiwiY3JlYXRlSHViIiwiY29tcG9uZW50V2lsbFVwZGF0ZSIsIm5leHRQcm9wcyIsIm5leHRTdGF0ZSIsInN0b3BIdWIiLCJzdGFydEh1YiIsIm1lcmdlRGVlcCIsIm1vcmlidW5kQ291bnQiLCJyZWR1Y2UiLCJpbmFjdGl2YXRlTGlzdGVuZXJzIiwicGVuZGluZ0NvdW50IiwiYWN0aXZhdGVMaXN0ZW5lcnMiLCJjb21wb25lbnRXaWxsVW5tb3VudCIsImN1ckNyZWF0ZSIsInNpZ25hbHJBY3Rpb25zIiwiaHViQWRkcmVzcyIsImFjY2Vzc1Rva2VuRmFjdG9yeSIsIndhcm4iLCJ3aXRoVXJsIiwic2tpcE5lZ290aWF0aW9uIiwidHJhbnNwb3J0IiwiV2ViU29ja2V0cyIsImJ1aWxkIiwib25jbG9zZSIsInN0YXJ0IiwidGhlbiIsInN0b3AiLCJjbGVhciIsInByb21pc2VzIiwicHVzaCIsImFsbCIsInBlbmRpbmdQYXJhbSIsIm1hcEVudHJpZXMiLCJjdXJIYW5kbGVycyIsImV4aXN0aW5nIiwiaGFuZGxlcnMiLCJtYXAiLCJvbiIsIm9mZiIsInJlbW92YWJsZSIsInJlbmRlciIsInBhc3NUaHJvdWdoUHJvcHMiLCJodWJQcm9wIiwiUHVyZUNvbXBvbmVudCIsImdldFZhbHVlRnJvbVN0YXRlIiwic291cmNlIiwibWFwRGlzcGF0Y2hUb1Byb3BzIiwiZGlzcGF0Y2hlciIsImdldFN0YXRlIiwiZGlzcGF0Y2giLCJtYXBTdGF0ZVRvUHJvcHMiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBLE9BQU9BLEtBQVAsTUFBa0IsT0FBbEI7QUFDQSxPQUFPQyxTQUFQLE1BQXNCLFlBQXRCO0FBQ0EsT0FBT0MsS0FBUCxNQUFrQixPQUFsQjtBQUNBLFNBQVNDLGtCQUFULFFBQW1DLE9BQW5DO0FBQ0EsU0FBU0MsT0FBVCxRQUF3QixhQUF4QjtBQUNBLFNBQVNDLEdBQVQsRUFBY0MsR0FBZCxRQUF5QixXQUF6QjtBQUNBLFNBQVNDLG9CQUFULEVBQStCQyxpQkFBL0IsUUFBd0QsaUJBQXhEOztBQUVBLElBQU1DLGlCQUFpQixTQUFqQkEsY0FBaUI7QUFBQSxTQUFhQyxVQUFVQyxXQUFWLElBQXlCRCxVQUFVRSxJQUFuQyxJQUEyQyxXQUF4RDtBQUFBLENBQXZCOztBQUVBLElBQU1DLGdCQUFnQixTQUFoQkEsYUFBZ0I7QUFBQSxTQUFXLFVBQUNDLGdCQUFELEVBQXNCO0FBQUE7O0FBQUEsMkJBT2pEQyxPQVBpRCxDQUVuREMsT0FGbUQ7QUFBQSxRQUVuREEsT0FGbUQsb0NBRXpDLEVBRnlDO0FBQUEsK0JBT2pERCxPQVBpRCxDQUduREUsV0FIbUQ7QUFBQSxRQUduREEsV0FIbUQsd0NBR3JDLHVCQUhxQztBQUFBLCtCQU9qREYsT0FQaUQsQ0FJbkRHLFdBSm1EO0FBQUEsUUFJbkRBLFdBSm1ELHdDQUlyQyxJQUpxQztBQUFBLCtCQU9qREgsT0FQaUQsQ0FLbkRJLFdBTG1EO0FBQUEsUUFLbkRBLFdBTG1ELHdDQUtyQyxTQUxxQztBQUFBLDJCQU9qREosT0FQaUQsQ0FNbkRLLE9BTm1EO0FBQUEsUUFNbkRBLE9BTm1ELG9DQU16QyxDQU55QztBQUFBLDhCQVFwQkwsT0FSb0IsQ0FRN0NNLFVBUjZDO0FBQUEsUUFRN0NBLFVBUjZDLHVDQVFoQ0wsT0FSZ0M7QUFBQSxRQVUvQ00sYUFWK0M7QUFBQTs7QUFhbkQsNkJBQVlDLEtBQVosRUFBbUI7QUFBQTs7QUFBQSxxREFDakIsZ0NBQU1BLEtBQU4sQ0FEaUI7O0FBQUEsY0FpRW5CQyxLQWpFbUIsR0FpRVgsVUFBQ0MsQ0FBRCxFQUFJQyxDQUFKO0FBQUEsaUJBQVVELElBQUlDLEVBQUVGLEtBQUYsRUFBZDtBQUFBLFNBakVXOztBQUFBLGNBbUVuQkcsVUFuRW1CLEdBbUVOLFVBQUNDLEtBQUQsRUFBVztBQUFBLGNBQ2RDLEdBRGMsR0FDTixNQUFLQyxLQURDLENBQ2RELEdBRGM7O0FBRXRCLGNBQUlBLEdBQUosRUFBUztBQUFBLGdCQUNDRSxVQURELEdBQ2dCRixHQURoQixDQUNDRSxVQUREOztBQUVQLGdCQUFJQSxjQUFjQSxXQUFXQyxlQUFYLEtBQStCLENBQWpELEVBQW9EO0FBQ2xESCxrQkFBSUksTUFBSixDQUFXLFlBQVgsRUFBeUJMLEtBQXpCLEVBQ0dNLEtBREgsQ0FDUyxVQUFDQyxHQUFELEVBQVM7QUFDZEMsd0JBQVFDLEtBQVIsb0NBQStDVCxLQUEvQyxZQUEyRFosT0FBM0Qsb0JBQWlGbUIsR0FBakY7QUFDRCxlQUhIO0FBSUQ7QUFDRjtBQUNGLFNBOUVrQjs7QUFBQSxjQWdGbkJHLGVBaEZtQixHQWdGRCxVQUFDVixLQUFELEVBQVc7QUFBQSxjQUNuQkMsR0FEbUIsR0FDWCxNQUFLQyxLQURNLENBQ25CRCxHQURtQjs7QUFFM0IsY0FBSUEsR0FBSixFQUFTO0FBQUEsZ0JBQ0NFLFVBREQsR0FDZ0JGLEdBRGhCLENBQ0NFLFVBREQ7O0FBRVAsZ0JBQUlBLGNBQWNBLFdBQVdDLGVBQVgsS0FBK0IsQ0FBakQsRUFBb0Q7QUFDbEQscUJBQU9ILElBQUlJLE1BQUosQ0FBVyxpQkFBWCxFQUE4QkwsS0FBOUIsRUFDSk0sS0FESSxDQUNFLFVBQUNDLEdBQUQsRUFBUztBQUNkQyx3QkFBUUMsS0FBUix3Q0FBbURULEtBQW5ELFlBQStEWixPQUEvRCxvQkFBcUZtQixHQUFyRjtBQUNELGVBSEksQ0FBUDtBQUlEO0FBQ0Y7QUFDRCxpQkFBT0ksUUFBUUMsT0FBUixFQUFQO0FBQ0QsU0E1RmtCOztBQUFBLGNBOEZuQkMsZ0JBOUZtQixHQThGQSxVQUFDQyxNQUFELEVBQXlCO0FBQUEsY0FBaEJDLElBQWdCLHVFQUFULElBQVM7O0FBQzFDLGNBQU1DLE1BQVMsTUFBS3JCLEtBQUwsQ0FBV3NCLE9BQXBCLFNBQStCeEIsVUFBL0IsU0FBNkNxQixNQUFuRDtBQUNBLGNBQU1JLFVBQVVILE9BQU9BLEtBQUtJLElBQUwsRUFBUCxHQUFxQixJQUFyQztBQUNBLGlCQUFPN0MsTUFBTThDLElBQU4sQ0FBV0osR0FBWCxFQUFnQkUsT0FBaEIsRUFDSlosS0FESSxDQUNFLFVBQUNDLEdBQUQsRUFBUztBQUNkQyxvQkFBUUMsS0FBUiw2QkFBd0NoQixVQUF4QyxvQkFBaUVjLEdBQWpFO0FBQ0QsV0FISSxDQUFQO0FBSUQsU0FyR2tCOztBQUFBLGNBdUduQmMsZ0JBdkdtQixHQXVHQSxVQUFDQyxZQUFELEVBQStCO0FBQUEsY0FBaEJQLElBQWdCLHVFQUFULElBQVM7O0FBQ2hELGNBQU1RLFVBQWEsTUFBSzVCLEtBQUwsQ0FBV3NCLE9BQXhCLFNBQW1DeEIsVUFBbkMsU0FBaUQ2QixZQUF2RDtBQUNBLGNBQU1OLE1BQU1ELE9BQVVRLE9BQVYsU0FBcUJSLElBQXJCLEdBQThCUSxPQUExQztBQUNBLGlCQUFPakQsTUFBTWtELEdBQU4sQ0FBVVIsR0FBVixFQUNKVixLQURJLENBQ0UsVUFBQ0MsR0FBRCxFQUFTO0FBQ2RDLG9CQUFRQyxLQUFSLHNCQUFpQ2hCLFVBQWpDLG9CQUEwRGMsR0FBMUQ7QUFDRCxXQUhJLENBQVA7QUFJRCxTQTlHa0I7O0FBQUEsY0FtTG5Ca0IsV0FuTG1CLEdBbUxMLFVBQUNsQixHQUFELEVBQVM7QUFBQSxjQUNibUIsUUFEYSxHQUNZbkIsR0FEWixDQUNibUIsUUFEYTtBQUFBLGNBQ0hDLFVBREcsR0FDWXBCLEdBRFosQ0FDSG9CLFVBREc7O0FBQUEscUJBRUZELFlBQVksRUFGVjtBQUFBLGNBRWJFLE1BRmEsUUFFYkEsTUFGYTs7QUFHckIsa0JBQVFBLFVBQVVELFVBQWxCO0FBQ0UsaUJBQUssR0FBTDtBQUNFO0FBQ0YsaUJBQUssR0FBTDtBQUNFLG9CQUFLRSxRQUFMLEdBQWdCLE1BQUtDLEtBQXJCLENBSkosQ0FJZ0M7QUFDOUI7QUFDRSxvQkFBS0MsUUFBTCxDQUFjLEVBQUU5QixLQUFLLElBQVAsRUFBZDtBQUNBO0FBUEo7QUFTRCxTQS9Ma0I7O0FBQUEsY0E0Tm5CK0IsZ0JBNU5tQixHQTROQSxVQUFDaEQsSUFBRCxFQUFPaUQsT0FBUCxFQUFtQjtBQUFBLDRCQUNFLE1BQUsvQixLQURQO0FBQUEsY0FDNUJnQyxPQUQ0QixlQUM1QkEsT0FENEI7QUFBQSxjQUNuQkMsTUFEbUIsZUFDbkJBLE1BRG1CO0FBQUEsY0FDWEMsUUFEVyxlQUNYQSxRQURXO0FBRXBDOztBQUNBLGNBQUksQ0FBQyxNQUFLQSxRQUFWLEVBQW9CLE1BQUtBLFFBQUwsR0FBZ0JBLFlBQVkzRCxLQUE1QjtBQUNwQixjQUFNNEQsbUJBQW1CLE1BQUtELFFBQUwsQ0FBY0UsS0FBZCxDQUFvQixDQUFDdEQsSUFBRCxDQUFwQixFQUE0Qk4sS0FBNUIsQ0FBekI7QUFDQSxjQUFJMkQsaUJBQWlCRSxHQUFqQixDQUFxQk4sT0FBckIsQ0FBSixFQUFtQztBQUNqQyxnQkFBTU8sb0JBQW9CSCxpQkFBaUJJLFNBQWpCLENBQTJCO0FBQUEscUJBQUtDLE1BQU1ULE9BQVg7QUFBQSxhQUEzQixDQUExQjtBQUNBLGtCQUFLRyxRQUFMLEdBQWdCSSxrQkFBa0JHLElBQWxCLEdBQ1osTUFBS1AsUUFBTCxDQUFjUSxLQUFkLENBQW9CLENBQUM1RCxJQUFELENBQXBCLEVBQTRCd0QsaUJBQTVCLENBRFksR0FDcUMsTUFBS0osUUFBTCxDQUFjUyxNQUFkLENBQXFCN0QsSUFBckIsQ0FEckQ7QUFFRDtBQUNEO0FBQ0EsY0FBSSxDQUFDLE1BQUttRCxNQUFWLEVBQWtCLE1BQUtBLE1BQUwsR0FBY0EsVUFBVTFELEtBQXhCO0FBQ2xCLGNBQU1xRSxpQkFBaUIsTUFBS1gsTUFBTCxDQUFZRyxLQUFaLENBQWtCLENBQUN0RCxJQUFELENBQWxCLEVBQTBCTixLQUExQixDQUF2QjtBQUNBLGNBQUksQ0FBQ29FLGVBQWVQLEdBQWYsQ0FBbUJOLE9BQW5CLENBQUwsRUFBa0M7QUFDaEMsZ0JBQUksQ0FBQyxNQUFLQyxPQUFWLEVBQW1CLE1BQUtBLE9BQUwsR0FBZUEsV0FBV3pELEtBQTFCO0FBQ25CLGdCQUFNc0Usa0JBQWtCLE1BQUtiLE9BQUwsQ0FBYUksS0FBYixDQUFtQixDQUFDdEQsSUFBRCxDQUFuQixFQUEyQk4sS0FBM0IsQ0FBeEI7QUFDQSxnQkFBSSxDQUFDcUUsZ0JBQWdCUixHQUFoQixDQUFvQk4sT0FBcEIsQ0FBTCxFQUFtQztBQUNqQyxvQkFBS0MsT0FBTCxHQUFlLE1BQUtBLE9BQUwsQ0FBYVUsS0FBYixDQUFtQixDQUFDNUQsSUFBRCxDQUFuQixFQUEyQitELGdCQUFnQkMsR0FBaEIsQ0FBb0JmLE9BQXBCLENBQTNCLENBQWY7QUFDRDtBQUNGO0FBQ0QsY0FBSSxNQUFLQyxPQUFMLEtBQWlCQSxPQUFqQixJQUE0QixNQUFLRSxRQUFMLEtBQWtCQSxRQUFsRCxFQUE0RDtBQUMxRCxrQkFBS0wsUUFBTCxDQUFjO0FBQ1pHLHVCQUFTLE1BQUtBLE9BREY7QUFFWkUsd0JBQVUsTUFBS0E7QUFGSCxhQUFkO0FBSUQ7QUFDRixTQXRQa0I7O0FBQUEsY0F3UG5CYSxrQkF4UG1CLEdBd1BFLFVBQUNqRSxJQUFELEVBQU9pRCxPQUFQLEVBQW1CO0FBQUEsNkJBQ0EsTUFBSy9CLEtBREw7QUFBQSxjQUM5QmdDLE9BRDhCLGdCQUM5QkEsT0FEOEI7QUFBQSxjQUNyQkMsTUFEcUIsZ0JBQ3JCQSxNQURxQjtBQUFBLGNBQ2JDLFFBRGEsZ0JBQ2JBLFFBRGE7QUFFdEM7O0FBQ0EsY0FBSSxDQUFDLE1BQUtGLE9BQVYsRUFBbUIsTUFBS0EsT0FBTCxHQUFlQSxXQUFXekQsS0FBMUI7QUFDbkIsY0FBTXNFLGtCQUFrQixNQUFLYixPQUFMLENBQWFJLEtBQWIsQ0FBbUIsQ0FBQ3RELElBQUQsQ0FBbkIsRUFBMkJOLEtBQTNCLENBQXhCO0FBQ0EsY0FBSXFFLGdCQUFnQlIsR0FBaEIsQ0FBb0JOLE9BQXBCLENBQUosRUFBa0M7QUFDaEMsZ0JBQU1pQixtQkFBbUJILGdCQUFnQk4sU0FBaEIsQ0FBMEI7QUFBQSxxQkFBS0MsTUFBTVQsT0FBWDtBQUFBLGFBQTFCLENBQXpCO0FBQ0Esa0JBQUtDLE9BQUwsR0FBZWdCLGlCQUFpQnRELEtBQWpCLEtBQ1gsTUFBS3NDLE9BQUwsQ0FBYVUsS0FBYixDQUFtQixDQUFDNUQsSUFBRCxDQUFuQixFQUEyQmtFLGdCQUEzQixDQURXLEdBRVgsTUFBS2hCLE9BQUwsQ0FBYVcsTUFBYixDQUFvQjdELElBQXBCLENBRko7QUFHRDtBQUNEO0FBQ0EsY0FBSSxDQUFDLE1BQUttRCxNQUFWLEVBQWtCLE1BQUtBLE1BQUwsR0FBY0EsVUFBVTFELEtBQXhCO0FBQ2xCLGNBQU1xRSxpQkFBaUIsTUFBS1gsTUFBTCxDQUFZRyxLQUFaLENBQWtCLENBQUN0RCxJQUFELENBQWxCLEVBQTBCTixLQUExQixDQUF2QjtBQUNBLGNBQUlvRSxlQUFlUCxHQUFmLENBQW1CTixPQUFuQixDQUFKLEVBQWlDO0FBQy9CLGdCQUFJLENBQUMsTUFBS0csUUFBVixFQUFvQixNQUFLQSxRQUFMLEdBQWdCQSxZQUFZM0QsS0FBNUI7QUFDcEIsZ0JBQU00RCxtQkFBbUIsTUFBS0QsUUFBTCxDQUFjRSxLQUFkLENBQW9CLENBQUN0RCxJQUFELENBQXBCLEVBQTRCTixLQUE1QixDQUF6QjtBQUNBLGdCQUFJLENBQUMyRCxpQkFBaUJFLEdBQWpCLENBQXFCTixPQUFyQixDQUFMLEVBQW9DO0FBQ2xDLG9CQUFLRyxRQUFMLEdBQWdCLE1BQUtBLFFBQUwsQ0FBY1EsS0FBZCxDQUFvQixDQUFDNUQsSUFBRCxDQUFwQixFQUE0QnFELGlCQUFpQlcsR0FBakIsQ0FBcUJmLE9BQXJCLENBQTVCLENBQWhCO0FBQ0Q7QUFDRjtBQUNELGNBQUksTUFBS0MsT0FBTCxLQUFpQkEsT0FBakIsSUFBNEIsTUFBS0UsUUFBTCxLQUFrQkEsUUFBbEQsRUFBNEQ7QUFDMUQsa0JBQUtMLFFBQUwsQ0FBYztBQUNaRyx1QkFBUyxNQUFLQSxPQURGO0FBRVpFLHdCQUFVLE1BQUtBO0FBRkgsYUFBZDtBQUlEO0FBQ0YsU0FuUmtCOztBQUVqQixjQUFLbEMsS0FBTCxHQUFhO0FBQ1hELGVBQUssSUFETTtBQUVYaUMsbUJBQVNpQixTQUZFO0FBR1hoQixrQkFBUWdCLFNBSEc7QUFJWGYsb0JBQVVlLFNBSkM7QUFLWEMsaUJBQU8sQ0FMSTtBQU1YQyxrQkFBUTtBQU5HLFNBQWI7QUFGaUI7QUFVbEI7O0FBdkJrRCw4QkF5Qm5EQyxrQkF6Qm1ELGlDQXlCOUI7QUFDbkIsYUFBS0MsUUFBTCxHQUFnQjtBQUNkQyxnQkFBTSxLQUFLM0MsZ0JBREc7QUFFZFIsa0JBQVEsS0FBS2dCLGdCQUZDO0FBR2QyQixlQUFLLEtBQUtqRCxVQUhJO0FBSWQwRCxrQkFBUSxLQUFLL0MsZUFKQztBQUtkZ0Qsd0JBQWNQLFNBTEE7QUFNZFEsb0JBQVUsS0FBSzNCLGdCQU5EO0FBT2Q0QixzQkFBWSxLQUFLWDtBQVBILFNBQWhCO0FBU0QsT0FuQ2tEOztBQUFBLDhCQXFDbkRZLGlCQXJDbUQsZ0NBcUMvQjtBQUNsQixhQUFLQyxTQUFMO0FBQ0QsT0F2Q2tEOztBQUFBLDhCQXlDbkRDLG1CQXpDbUQsZ0NBeUMvQkMsU0F6QytCLEVBeUNwQkMsU0F6Q29CLEVBeUNUO0FBQ3hDLFlBQUksS0FBSy9ELEtBQUwsQ0FBV0QsR0FBWCxLQUFtQmdFLFVBQVVoRSxHQUFqQyxFQUFzQztBQUNwQyxjQUFJLEtBQUtDLEtBQUwsQ0FBV0QsR0FBZixFQUFvQixLQUFLaUUsT0FBTCxDQUFhLEtBQUtoRSxLQUFMLENBQVdELEdBQXhCLEVBQTZCLEtBQTdCO0FBQ3BCLGNBQUlnRSxVQUFVaEUsR0FBZCxFQUFtQjtBQUNqQixpQkFBS2tFLFFBQUwsQ0FBY0YsVUFBVWhFLEdBQXhCO0FBQ0QsV0FGRCxNQUVPO0FBQ0wsaUJBQUs2RCxTQUFMLENBQWVHLFVBQVVaLE1BQXpCO0FBQ0Q7QUFDRixTQVBELE1BT08sSUFBSSxDQUFDWSxVQUFVaEUsR0FBZixFQUFvQjtBQUN6QixlQUFLNkQsU0FBTCxDQUFlRyxVQUFVWixNQUF6QjtBQUNELFNBRk0sTUFFQTtBQUFBLGNBQ0NuQixPQURELEdBQ3VCK0IsU0FEdkIsQ0FDQy9CLE9BREQ7QUFBQSxjQUNVRSxRQURWLEdBQ3VCNkIsU0FEdkIsQ0FDVTdCLFFBRFY7O0FBRUwsY0FBSSxDQUFDQSxRQUFMLEVBQWU7QUFDYkEsdUJBQVcsS0FBS0EsUUFBTCxJQUFpQjNELEtBQTVCO0FBQ0QsV0FGRCxNQUVPLElBQUksS0FBSzJELFFBQVQsRUFBbUI7QUFDeEJBLHVCQUFXQSxTQUFTZ0MsU0FBVCxDQUFtQixLQUFLaEMsUUFBeEIsQ0FBWDtBQUNEO0FBQ0QsY0FBTWlDLGdCQUFnQmpDLFNBQVNrQyxNQUFULENBQWdCLEtBQUsxRSxLQUFyQixFQUE0QixDQUE1QixDQUF0QjtBQUNBLGNBQUl5RSxhQUFKLEVBQW1CO0FBQ2pCLGlCQUFLakMsUUFBTCxHQUFnQixLQUFLbUMsbUJBQUwsQ0FBeUIsS0FBS3JFLEtBQUwsQ0FBV0QsR0FBcEMsRUFBeUNtQyxRQUF6QyxDQUFoQjtBQUNEO0FBQ0QsY0FBSSxDQUFDRixPQUFMLEVBQWM7QUFDWkEsc0JBQVUsS0FBS0EsT0FBTCxJQUFnQnpELEtBQTFCO0FBQ0QsV0FGRCxNQUVPLElBQUksS0FBS3lELE9BQVQsRUFBa0I7QUFDdkJBLHNCQUFVQSxRQUFRa0MsU0FBUixDQUFrQixLQUFLbEMsT0FBdkIsQ0FBVjtBQUNEO0FBQ0QsY0FBTXNDLGVBQWV0QyxRQUFRb0MsTUFBUixDQUFlLEtBQUsxRSxLQUFwQixFQUEyQixDQUEzQixDQUFyQjtBQUNBLGNBQUk0RSxZQUFKLEVBQWtCO0FBQ2hCLGlCQUFLdEMsT0FBTCxHQUFlLEtBQUt1QyxpQkFBTCxDQUF1QlIsVUFBVWhFLEdBQWpDLEVBQXNDaUMsT0FBdEMsQ0FBZjtBQUNEO0FBQ0Y7QUFDRixPQXhFa0Q7O0FBQUEsOEJBMEVuRHdDLG9CQTFFbUQsbUNBMEU1QjtBQUNyQixhQUFLUixPQUFMLENBQWEsS0FBS2hFLEtBQUwsQ0FBV0QsR0FBeEIsRUFBNkIsSUFBN0I7QUFDRCxPQTVFa0Q7O0FBQUEsOEJBNkg3QzZELFNBN0g2QztBQUFBLDZGQTZIbkNhLFNBN0htQztBQUFBOztBQUFBOztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsMkJBOEh2QixLQUFLekUsS0E5SGtCLEVBOEh6Q2tELEtBOUh5QyxVQThIekNBLEtBOUh5QyxFQThIbENDLE1BOUhrQyxVQThIbENBLE1BOUhrQzs7QUFBQSx3QkErSDdDRCxRQUFRNUQsT0EvSHFDO0FBQUE7QUFBQTtBQUFBOztBQWdJL0NnQiwwQkFBUUMsS0FBUiw2Q0FBd0RyQixPQUF4RDtBQUNBLHVCQUFLMkMsUUFBTCxDQUFjO0FBQ1pxQiwyQkFBTyxDQURLO0FBRVpDLDRCQUFRO0FBRkksbUJBQWQ7QUFqSStDO0FBQUE7O0FBQUE7QUFBQSwyQkFzSVgsS0FBSzFELEtBdElNLEVBc0l2Q3NCLE9BdEl1QyxVQXNJdkNBLE9BdEl1QyxFQXNJOUIyRCxjQXRJOEIsVUFzSTlCQSxjQXRJOEI7O0FBQUEsd0JBdUkzQzNELFdBQVc3QixPQXZJZ0M7QUFBQTtBQUFBO0FBQUE7O0FBd0l6Q3lGLDRCQXhJeUMsR0F3STVCNUQsT0F4STRCOztBQXlJN0Msc0JBQUkxQixXQUFKLEVBQWlCc0YsYUFBZ0JBLFVBQWhCLFNBQThCdEYsV0FBOUI7QUFDakJzRiwrQkFBZ0JBLFVBQWhCLFNBQThCekYsT0FBOUI7QUFDQSx1QkFBSzBDLEtBQUwsR0FBYThDLGVBQWVFLGtCQUFmLENBQWtDeEYsV0FBbEMsQ0FBYjs7QUEzSTZDLHVCQTRJekMsS0FBS3dDLEtBNUlvQztBQUFBO0FBQUE7QUFBQTs7QUFBQSx3QkE2SXZDLEtBQUtELFFBQUwsS0FBa0IsS0FBS0MsS0E3SWdCO0FBQUE7QUFBQTtBQUFBOztBQThJekMsc0JBQUksQ0FBQzZDLGFBQWF0QixNQUFkLElBQXdCN0QsT0FBNUIsRUFBcUM7QUFDbkNnQiw0QkFBUXVFLElBQVIsQ0FBYSxpREFBYjtBQUNELG1CQUZELE1BRU87QUFDTCx5QkFBS2hELFFBQUwsQ0FBYztBQUNaOUIsMkJBQUssSUFETztBQUVab0QsOEJBQVEsQ0FBQ3NCLGFBQWF0QixNQUFkLElBQXdCO0FBRnBCLHFCQUFkO0FBSUQ7QUFySndDOztBQUFBO0FBd0ozQyx1QkFBS3hCLFFBQUwsR0FBZ0JzQixTQUFoQjs7QUF4SjJDO0FBMEp2Q2xELHFCQTFKdUMsR0EwSmpDLElBQUl0QixvQkFBSixHQUNUcUcsT0FEUyxDQUNESCxVQURDLEVBQ1c7QUFDbkJJLHFDQUFpQixJQURFO0FBRW5CQywrQkFBV3RHLGtCQUFrQnVHLFVBRlY7QUFHbkJMLHdDQUFvQjtBQUFBLDZCQUFNLE9BQUtoRCxLQUFYO0FBQUE7QUFIRCxtQkFEWCxFQU1Uc0QsS0FOUyxFQTFKaUM7O0FBaUs3Q25GLHNCQUFJb0YsT0FBSixHQUFjLEtBQUs1RCxXQUFuQjtBQUNBLHVCQUFLTSxRQUFMLENBQWM7QUFDWjlCLDRCQURZO0FBRVptRCwyQkFBT0EsUUFBUSxDQUZIO0FBR1pDLDRCQUFRO0FBSEksbUJBQWQ7O0FBbEs2QztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTs7QUFBQTtBQUFBO0FBQUE7O0FBQUE7QUFBQTs7QUFBQSw4QkEyS25EYyxRQTNLbUQscUJBMksxQ2xFLEdBM0swQyxFQTJLckM7QUFBQTs7QUFDWixZQUFJQSxHQUFKLEVBQVM7QUFDUEEsY0FBSXFGLEtBQUosR0FDR0MsSUFESCxDQUNRLFlBQU07QUFBQSwwQkFDa0IsT0FBS3JGLEtBRHZCO0FBQUEsZ0JBQ0ZnQyxPQURFLFdBQ0ZBLE9BREU7QUFBQSxnQkFDT0MsTUFEUCxXQUNPQSxNQURQOztBQUVWLGdCQUFJLENBQUMsT0FBS0QsT0FBVixFQUFtQixPQUFLQSxPQUFMLEdBQWVBLFdBQVd6RCxLQUExQjtBQUNuQixnQkFBSSxDQUFDLE9BQUswRCxNQUFWLEVBQWtCLE9BQUtBLE1BQUwsR0FBY0EsVUFBVTFELEtBQXhCO0FBQ2xCLG1CQUFLc0QsUUFBTCxDQUFjO0FBQ1pJLHNCQUFRLE9BQUtBLE1BREQ7QUFFWkQsdUJBQVMsT0FBS0EsT0FGRjtBQUdaa0IscUJBQU87QUFISyxhQUFkO0FBS0QsV0FWSCxFQVdHOUMsS0FYSCxDQVdTLFVBQUNDLEdBQUQsRUFBUztBQUNkQyxvQkFBUXVFLElBQVIsMERBQW9FM0YsT0FBcEUsYUFBbUZtQixHQUFuRjtBQUNBTixnQkFBSXVGLElBQUo7QUFDQSxtQkFBSy9ELFdBQUwsQ0FBaUJsQixHQUFqQjtBQUNELFdBZkg7QUFnQkQ7QUFDRixPQTlMa0Q7O0FBQUEsOEJBOE1uRDJELE9BOU1tRCxvQkE4TTNDakUsR0E5TTJDLEVBOE10Q3dGLEtBOU1zQyxFQThNL0I7QUFDbEIsWUFBSXhGLEdBQUosRUFBUztBQUNQLGNBQU15RixXQUFXLEVBQWpCOztBQUVBLGNBQUlELEtBQUosRUFBVztBQUNUO0FBQ0EsaUJBQUt2RCxPQUFMLEdBQWVpQixTQUFmO0FBQ0F1QyxxQkFBU0MsSUFBVCxDQUFjLEtBQUtqRixlQUFMLENBQXFCLEVBQXJCLENBQWQ7QUFDQTtBQUNELFdBTEQsTUFLTyxJQUFJLENBQUMsS0FBS3dCLE9BQVYsRUFBbUI7QUFDeEIsaUJBQUtBLE9BQUwsR0FBZSxLQUFLaEMsS0FBTCxDQUFXaUMsTUFBMUI7QUFDRCxXQUZNLE1BRUEsSUFBSSxLQUFLakMsS0FBTCxDQUFXaUMsTUFBZixFQUF1QjtBQUM1QixpQkFBS0QsT0FBTCxHQUFlLEtBQUtBLE9BQUwsQ0FBYWtDLFNBQWIsQ0FBdUIsS0FBS2xFLEtBQUwsQ0FBV2lDLE1BQWxDLENBQWY7QUFDRDs7QUFFRHhCLGtCQUFRaUYsR0FBUixDQUFZRixRQUFaLEVBQXNCSCxJQUF0QixDQUEyQixZQUFNO0FBQy9CdEYsZ0JBQUl1RixJQUFKO0FBQ0QsV0FGRDs7QUFJQSxlQUFLckQsTUFBTCxHQUFjZ0IsU0FBZDtBQUNBLGVBQUtwQixRQUFMLENBQWM7QUFDWkcscUJBQVMsS0FBS0EsT0FERjtBQUVaQyxvQkFBUSxLQUFLQTtBQUZELFdBQWQ7QUFJRDtBQUNGLE9Bdk9rRDs7QUFBQSw4QkFrU25Ec0MsaUJBbFNtRCw4QkFrU2pDeEUsR0FsU2lDLEVBa1M1QjRGLFlBbFM0QixFQWtTZDtBQUFBOztBQUNuQyxZQUFJM0QsVUFBVTJELFlBQWQ7QUFDQSxZQUFJNUYsT0FBTzRGLFlBQVgsRUFBeUI7QUFBQSxjQUNmMUYsVUFEZSxHQUNBRixHQURBLENBQ2ZFLFVBRGU7O0FBRXZCLGNBQUlBLGNBQWNBLFdBQVdDLGVBQVgsS0FBK0IsQ0FBakQsRUFBb0Q7QUFBQSxnQkFDMUMrQixNQUQwQyxHQUMvQixLQUFLakMsS0FEMEIsQ0FDMUNpQyxNQUQwQzs7QUFFbEQsZ0JBQUksQ0FBQyxLQUFLQSxNQUFWLEVBQWtCLEtBQUtBLE1BQUwsR0FBY0EsVUFBVTFELEtBQXhCO0FBQ2xCLGdCQUFJLEtBQUswRCxNQUFMLENBQVltQyxNQUFaLENBQW1CLEtBQUsxRSxLQUF4QixFQUErQixDQUEvQixDQUFKLEVBQXVDO0FBQ3JDc0Msd0JBQVVBLFFBQVE0RCxVQUFSLENBQW1CLGlCQUF5QjtBQUFBLG9CQUF2QjlHLElBQXVCO0FBQUEsb0JBQWpCK0csV0FBaUI7O0FBQ3BELG9CQUFNQyxXQUFXLE9BQUs3RCxNQUFMLENBQVlHLEtBQVosQ0FBa0IsQ0FBQ3RELElBQUQsQ0FBbEIsQ0FBakI7QUFDQSxvQkFBTWlILFdBQVdELFdBQ2JELFlBQVl0RCxTQUFaLENBQXNCO0FBQUEseUJBQVd1RCxTQUFTekQsR0FBVCxDQUFhTixPQUFiLENBQVg7QUFBQSxpQkFBdEIsQ0FEYSxHQUViOEQsV0FGSjtBQUdBLHVCQUFPLENBQUMvRyxJQUFELEVBQU9pSCxRQUFQLENBQVA7QUFDRCxlQU5TLENBQVY7QUFPRDtBQUNEL0Qsb0JBQVE0RCxVQUFSLENBQW1CO0FBQUEsa0JBQUU5RyxJQUFGO0FBQUEsa0JBQVFpSCxRQUFSO0FBQUEscUJBQXNCQSxTQUFTQyxHQUFULENBQWE7QUFBQSx1QkFBV2pHLElBQUlrRyxFQUFKLENBQU9uSCxJQUFQLEVBQWFpRCxPQUFiLENBQVg7QUFBQSxlQUFiLENBQXRCO0FBQUEsYUFBbkI7QUFDQSxpQkFBS0UsTUFBTCxHQUFjLEtBQUtBLE1BQUwsQ0FBWWlDLFNBQVosQ0FBc0JsQyxPQUF0QixDQUFkO0FBQ0EsaUJBQUtILFFBQUwsQ0FBYztBQUNaRyx1QkFBU2lCLFNBREc7QUFFWmhCLHNCQUFRLEtBQUtBO0FBRkQsYUFBZDtBQUlBLG1CQUFPZ0IsU0FBUDtBQUNEO0FBQ0Y7QUFDRCxlQUFPakIsT0FBUDtBQUNELE9BNVRrRDs7QUFBQSw4QkE4VG5EcUMsbUJBOVRtRCxnQ0E4VC9CdEUsR0E5VCtCLEVBOFQxQm1DLFFBOVQwQixFQThUaEI7QUFDakMsWUFBSW5DLE9BQU9tQyxRQUFYLEVBQXFCO0FBQ25CQSxtQkFBUzBELFVBQVQsQ0FBb0I7QUFBQSxnQkFBRTlHLElBQUY7QUFBQSxnQkFBUWlILFFBQVI7QUFBQSxtQkFBc0JBLFNBQVNDLEdBQVQsQ0FBYTtBQUFBLHFCQUFXakcsSUFBSW1HLEdBQUosQ0FBUXBILElBQVIsRUFBY2lELE9BQWQsQ0FBWDtBQUFBLGFBQWIsQ0FBdEI7QUFBQSxXQUFwQjtBQURtQixjQUVYRSxNQUZXLEdBRUEsS0FBS2pDLEtBRkwsQ0FFWGlDLE1BRlc7O0FBR25CLGNBQUksQ0FBQyxLQUFLQSxNQUFWLEVBQWtCLEtBQUtBLE1BQUwsR0FBY0EsVUFBVTFELEtBQXhCO0FBQ2xCLGVBQUswRCxNQUFMLEdBQWMsS0FBS0EsTUFBTCxDQUFZMkQsVUFBWixDQUF1QixpQkFBeUI7QUFBQSxnQkFBdkI5RyxJQUF1QjtBQUFBLGdCQUFqQitHLFdBQWlCOztBQUM1RCxnQkFBTU0sWUFBWWpFLFNBQVNFLEtBQVQsQ0FBZSxDQUFDdEQsSUFBRCxDQUFmLENBQWxCO0FBQ0EsZ0JBQU1pSCxXQUFXSSxZQUNiTixZQUFZdEQsU0FBWixDQUFzQjtBQUFBLHFCQUFXNEQsVUFBVTlELEdBQVYsQ0FBY04sT0FBZCxDQUFYO0FBQUEsYUFBdEIsQ0FEYSxHQUViOEQsV0FGSjtBQUdBLG1CQUFPLENBQUMvRyxJQUFELEVBQU9pSCxRQUFQLENBQVA7QUFDRCxXQU5hLENBQWQ7QUFPQSxlQUFLbEUsUUFBTCxDQUFjO0FBQ1pJLG9CQUFRLEtBQUtBLE1BREQ7QUFFWkMsc0JBQVVlO0FBRkUsV0FBZDtBQUlBLGlCQUFPQSxTQUFQO0FBQ0Q7QUFDRCxlQUFPZixRQUFQO0FBQ0QsT0FqVmtEOztBQUFBLDhCQW1WbkRrRSxNQW5WbUQscUJBbVYxQztBQUFBOztBQUFBLHNCQUNrRCxLQUFLM0csS0FEdkQ7QUFBQSxZQUNDc0IsT0FERCxXQUNDQSxPQUREO0FBQUEsWUFDVTJELGNBRFYsV0FDVUEsY0FEVjtBQUFBLFlBQzZCMkIsZ0JBRDdCOztBQUVQLFlBQU1DLG1DQUFhcEgsT0FBYixJQUF1QixLQUFLbUUsUUFBNUIsV0FBTjtBQUNBLGVBQ0Usb0JBQUMsZ0JBQUQsZUFDTWdELGdCQUROLEVBRU1DLE9BRk4sRUFERjtBQU1ELE9BNVZrRDs7QUFBQTtBQUFBLE1BVXpCcEksTUFBTXFJLGFBVm1CLFVBVzVDdkgsZ0JBWDRDLEdBV3pCQSxnQkFYeUI7OztBQStWckRRLGtCQUFjWCxXQUFkLHNCQUE2Q0YsZUFBZUssZ0JBQWYsQ0FBN0M7O0FBU0EsUUFBTXdILG9CQUFvQixTQUFwQkEsaUJBQW9CLENBQUN4RyxLQUFELEVBQVF5RyxNQUFSLEVBQW1CO0FBQzNDLFVBQUksT0FBT0EsTUFBUCxLQUFrQixVQUF0QixFQUFrQyxPQUFPQSxPQUFPekcsS0FBUCxDQUFQO0FBQ2xDLFVBQUksT0FBT3lHLE1BQVAsS0FBa0IsUUFBdEIsRUFBZ0MsT0FBT0EsTUFBUDtBQUNoQyxhQUFPLEVBQVA7QUFDRCxLQUpEOztBQU1BLFFBQU1DLHFCQUFxQixTQUFyQkEsa0JBQXFCO0FBQUEsYUFBYTtBQUN0Q2hDLHdCQUFnQnJHLG1CQUFtQjtBQUNqQ3VHLDhCQUFvQjtBQUFBLG1CQUFNLFVBQUMrQixVQUFELEVBQWFDLFFBQWIsRUFBMEI7QUFDbEQsa0JBQU01RyxRQUFRNEcsVUFBZDtBQUNBLHFCQUFPSixrQkFBa0J4RyxLQUFsQixFQUF5QlosV0FBekIsQ0FBUDtBQUNELGFBSG1CO0FBQUE7QUFEYSxTQUFuQixFQUtieUgsUUFMYTtBQURzQixPQUFiO0FBQUEsS0FBM0I7O0FBU0EsUUFBTUMsa0JBQWtCLFNBQWxCQSxlQUFrQixDQUFDOUcsS0FBRCxFQUFXO0FBQ2pDLFVBQU1lLFVBQVV5RixrQkFBa0J4RyxLQUFsQixFQUF5QmIsV0FBekIsQ0FBaEI7QUFDQSxhQUFPLEVBQUU0QixnQkFBRixFQUFQO0FBQ0QsS0FIRDs7QUFLQSxXQUFPekMsUUFBUXdJLGVBQVIsRUFBeUJKLGtCQUF6QixFQUE2Q2xILGFBQTdDLENBQVA7QUFDRCxHQTdYcUI7QUFBQSxDQUF0Qjs7QUErWEEsZUFBZVQsYUFBZiIsImZpbGUiOiJpbmplY3QuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IFByb3BUeXBlcyBmcm9tICdwcm9wLXR5cGVzJztcbmltcG9ydCBheGlvcyBmcm9tICdheGlvcyc7XG5pbXBvcnQgeyBiaW5kQWN0aW9uQ3JlYXRvcnMgfSBmcm9tICdyZWR1eCc7XG5pbXBvcnQgeyBjb25uZWN0IH0gZnJvbSAncmVhY3QtcmVkdXgnO1xuaW1wb3J0IHsgTWFwLCBTZXQgfSBmcm9tICdpbW11dGFibGUnO1xuaW1wb3J0IHsgSHViQ29ubmVjdGlvbkJ1aWxkZXIsIEh0dHBUcmFuc3BvcnRUeXBlIH0gZnJvbSAnQGFzcG5ldC9zaWduYWxyJztcblxuY29uc3QgZ2V0RGlzcGxheU5hbWUgPSBDb21wb25lbnQgPT4gQ29tcG9uZW50LmRpc3BsYXlOYW1lIHx8IENvbXBvbmVudC5uYW1lIHx8ICdDb21wb25lbnQnO1xuXG5jb25zdCBpbmplY3RTaWduYWxSID0gb3B0aW9ucyA9PiAoV3JhcHBlZENvbXBvbmVudCkgPT4ge1xuICBjb25zdCB7XG4gICAgaHViTmFtZSA9ICcnLFxuICAgIGJhc2VBZGRyZXNzID0gJ2h0dHA6Ly9sb2NhbGhvc3Q6NTU1NScsXG4gICAgYWNjZXNzVG9rZW4gPSBudWxsLFxuICAgIHNpZ25hbHJQYXRoID0gJ3NpZ25hbHInLFxuICAgIHJldHJpZXMgPSAzLFxuICB9ID0gb3B0aW9ucztcbiAgY29uc3QgeyBjb250cm9sbGVyID0gaHViTmFtZSB9ID0gb3B0aW9ucztcblxuICBjbGFzcyBJbmplY3RTaWduYWxSIGV4dGVuZHMgUmVhY3QuUHVyZUNvbXBvbmVudCB7XG4gICAgc3RhdGljIFdyYXBwZWRDb21wb25lbnQgPSBXcmFwcGVkQ29tcG9uZW50O1xuXG4gICAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICAgIHN1cGVyKHByb3BzKTtcbiAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgIGh1YjogbnVsbCxcbiAgICAgICAgcGVuZGluZzogdW5kZWZpbmVkLFxuICAgICAgICBhY3RpdmU6IHVuZGVmaW5lZCxcbiAgICAgICAgbW9yaWJ1bmQ6IHVuZGVmaW5lZCxcbiAgICAgICAgcmV0cnk6IDAsXG4gICAgICAgIGNyZWF0ZTogMCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29tcG9uZW50V2lsbE1vdW50KCkge1xuICAgICAgdGhpcy5odWJQcm94eSA9IHtcbiAgICAgICAgc2VuZDogdGhpcy5zZW5kVG9Db250cm9sbGVyLFxuICAgICAgICBpbnZva2U6IHRoaXMuaW52b2tlQ29udHJvbGxlcixcbiAgICAgICAgYWRkOiB0aGlzLmFkZFRvR3JvdXAsXG4gICAgICAgIHJlbW92ZTogdGhpcy5yZW1vdmVGcm9tR3JvdXAsXG4gICAgICAgIGNvbm5lY3Rpb25JZDogdW5kZWZpbmVkLFxuICAgICAgICByZWdpc3RlcjogdGhpcy5yZWdpc3Rlckxpc3RlbmVyLFxuICAgICAgICB1bnJlZ2lzdGVyOiB0aGlzLnVucmVnaXN0ZXJMaXN0ZW5lcixcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICB0aGlzLmNyZWF0ZUh1YigpO1xuICAgIH1cblxuICAgIGNvbXBvbmVudFdpbGxVcGRhdGUobmV4dFByb3BzLCBuZXh0U3RhdGUpIHtcbiAgICAgIGlmICh0aGlzLnN0YXRlLmh1YiAhPT0gbmV4dFN0YXRlLmh1Yikge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5odWIpIHRoaXMuc3RvcEh1Yih0aGlzLnN0YXRlLmh1YiwgZmFsc2UpO1xuICAgICAgICBpZiAobmV4dFN0YXRlLmh1Yikge1xuICAgICAgICAgIHRoaXMuc3RhcnRIdWIobmV4dFN0YXRlLmh1Yik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5jcmVhdGVIdWIobmV4dFN0YXRlLmNyZWF0ZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoIW5leHRTdGF0ZS5odWIpIHtcbiAgICAgICAgdGhpcy5jcmVhdGVIdWIobmV4dFN0YXRlLmNyZWF0ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgeyBwZW5kaW5nLCBtb3JpYnVuZCB9ID0gbmV4dFN0YXRlO1xuICAgICAgICBpZiAoIW1vcmlidW5kKSB7XG4gICAgICAgICAgbW9yaWJ1bmQgPSB0aGlzLm1vcmlidW5kIHx8IE1hcCgpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMubW9yaWJ1bmQpIHtcbiAgICAgICAgICBtb3JpYnVuZCA9IG1vcmlidW5kLm1lcmdlRGVlcCh0aGlzLm1vcmlidW5kKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBtb3JpYnVuZENvdW50ID0gbW9yaWJ1bmQucmVkdWNlKHRoaXMuY291bnQsIDApO1xuICAgICAgICBpZiAobW9yaWJ1bmRDb3VudCkge1xuICAgICAgICAgIHRoaXMubW9yaWJ1bmQgPSB0aGlzLmluYWN0aXZhdGVMaXN0ZW5lcnModGhpcy5zdGF0ZS5odWIsIG1vcmlidW5kKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXBlbmRpbmcpIHtcbiAgICAgICAgICBwZW5kaW5nID0gdGhpcy5wZW5kaW5nIHx8IE1hcCgpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMucGVuZGluZykge1xuICAgICAgICAgIHBlbmRpbmcgPSBwZW5kaW5nLm1lcmdlRGVlcCh0aGlzLnBlbmRpbmcpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHBlbmRpbmdDb3VudCA9IHBlbmRpbmcucmVkdWNlKHRoaXMuY291bnQsIDApO1xuICAgICAgICBpZiAocGVuZGluZ0NvdW50KSB7XG4gICAgICAgICAgdGhpcy5wZW5kaW5nID0gdGhpcy5hY3RpdmF0ZUxpc3RlbmVycyhuZXh0U3RhdGUuaHViLCBwZW5kaW5nKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgdGhpcy5zdG9wSHViKHRoaXMuc3RhdGUuaHViLCB0cnVlKTtcbiAgICB9XG5cbiAgICBjb3VudCA9IChjLCBzKSA9PiBjICsgcy5jb3VudCgpO1xuXG4gICAgYWRkVG9Hcm91cCA9IChncm91cCkgPT4ge1xuICAgICAgY29uc3QgeyBodWIgfSA9IHRoaXMuc3RhdGU7XG4gICAgICBpZiAoaHViKSB7XG4gICAgICAgIGNvbnN0IHsgY29ubmVjdGlvbiB9ID0gaHViO1xuICAgICAgICBpZiAoY29ubmVjdGlvbiAmJiBjb25uZWN0aW9uLmNvbm5lY3Rpb25TdGF0ZSA9PT0gMSkge1xuICAgICAgICAgIGh1Yi5pbnZva2UoJ2FkZFRvR3JvdXAnLCBncm91cClcbiAgICAgICAgICAgIC5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yOiBBZGRpbmcgY2xpZW50IHRvIGdyb3VwICR7Z3JvdXB9IGluICR7aHViTmFtZX0gZmFpbGVkLlxcblxcbiR7ZXJyfWApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgcmVtb3ZlRnJvbUdyb3VwID0gKGdyb3VwKSA9PiB7XG4gICAgICBjb25zdCB7IGh1YiB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgIGlmIChodWIpIHtcbiAgICAgICAgY29uc3QgeyBjb25uZWN0aW9uIH0gPSBodWI7XG4gICAgICAgIGlmIChjb25uZWN0aW9uICYmIGNvbm5lY3Rpb24uY29ubmVjdGlvblN0YXRlID09PSAxKSB7XG4gICAgICAgICAgcmV0dXJuIGh1Yi5pbnZva2UoJ3JlbW92ZUZyb21Hcm91cCcsIGdyb3VwKVxuICAgICAgICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3I6IFJlbW92aW5nIGNsaWVudCBmcm9tIGdyb3VwICR7Z3JvdXB9IGluICR7aHViTmFtZX0gZmFpbGVkLlxcblxcbiR7ZXJyfWApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9O1xuXG4gICAgc2VuZFRvQ29udHJvbGxlciA9ICh0YXJnZXQsIGRhdGEgPSBudWxsKSA9PiB7XG4gICAgICBjb25zdCB1cmwgPSBgJHt0aGlzLnByb3BzLmJhc2VVcmx9LyR7Y29udHJvbGxlcn0vJHt0YXJnZXR9YDtcbiAgICAgIGNvbnN0IHBheWxvYWQgPSBkYXRhID8gZGF0YS50b0pTKCkgOiBudWxsO1xuICAgICAgcmV0dXJuIGF4aW9zLnBvc3QodXJsLCBwYXlsb2FkKVxuICAgICAgICAuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yOiBTZW5kaW5nIGRhdGEgdG8gJHtjb250cm9sbGVyfSBmYWlsZWQuXFxuXFxuJHtlcnJ9YCk7XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBpbnZva2VDb250cm9sbGVyID0gKHRhcmdldE1ldGhvZCwgZGF0YSA9IG51bGwpID0+IHtcbiAgICAgIGNvbnN0IHVybEJhc2UgPSBgJHt0aGlzLnByb3BzLmJhc2VVcmx9LyR7Y29udHJvbGxlcn0vJHt0YXJnZXRNZXRob2R9YDtcbiAgICAgIGNvbnN0IHVybCA9IGRhdGEgPyBgJHt1cmxCYXNlfS8ke2RhdGF9YCA6IHVybEJhc2U7XG4gICAgICByZXR1cm4gYXhpb3MuZ2V0KHVybClcbiAgICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvcjogSW52b2tpbmcgJHtjb250cm9sbGVyfSBmYWlsZWQuXFxuXFxuJHtlcnJ9YCk7XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBhc3luYyBjcmVhdGVIdWIoY3VyQ3JlYXRlKSB7XG4gICAgICBjb25zdCB7IHJldHJ5LCBjcmVhdGUgfSA9IHRoaXMuc3RhdGU7XG4gICAgICBpZiAocmV0cnkgPiByZXRyaWVzKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yOiBSYW4gb3V0IG9mIHJldHJpZXMgZm9yIHN0YXJ0aW5nICR7aHViTmFtZX0hYCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHJldHJ5OiAwLFxuICAgICAgICAgIGNyZWF0ZTogMCxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB7IGJhc2VVcmwsIHNpZ25hbHJBY3Rpb25zIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBpZiAoYmFzZVVybCAmJiBodWJOYW1lKSB7XG4gICAgICAgICAgbGV0IGh1YkFkZHJlc3MgPSBiYXNlVXJsO1xuICAgICAgICAgIGlmIChzaWduYWxyUGF0aCkgaHViQWRkcmVzcyA9IGAke2h1YkFkZHJlc3N9LyR7c2lnbmFsclBhdGh9YDtcbiAgICAgICAgICBodWJBZGRyZXNzID0gYCR7aHViQWRkcmVzc30vJHtodWJOYW1lfWA7XG4gICAgICAgICAgdGhpcy50b2tlbiA9IHNpZ25hbHJBY3Rpb25zLmFjY2Vzc1Rva2VuRmFjdG9yeShhY2Nlc3NUb2tlbik7XG4gICAgICAgICAgaWYgKHRoaXMudG9rZW4pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLm9sZFRva2VuID09PSB0aGlzLnRva2VuKSB7XG4gICAgICAgICAgICAgIGlmICgoY3VyQ3JlYXRlIHx8IGNyZWF0ZSkgPiByZXRyaWVzKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdXYXJuaW5nOiBVbmFibGUgdG8gZ2V0IHVwLXRvLWRhdGUgYWNjZXNzIHRva2VuLicpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgaHViOiBudWxsLFxuICAgICAgICAgICAgICAgICAgY3JlYXRlOiAoY3VyQ3JlYXRlIHx8IGNyZWF0ZSkgKyAxLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMub2xkVG9rZW4gPSB1bmRlZmluZWQ7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IGh1YiA9IG5ldyBIdWJDb25uZWN0aW9uQnVpbGRlcigpXG4gICAgICAgICAgICAud2l0aFVybChodWJBZGRyZXNzLCB7XG4gICAgICAgICAgICAgIHNraXBOZWdvdGlhdGlvbjogdHJ1ZSxcbiAgICAgICAgICAgICAgdHJhbnNwb3J0OiBIdHRwVHJhbnNwb3J0VHlwZS5XZWJTb2NrZXRzLFxuICAgICAgICAgICAgICBhY2Nlc3NUb2tlbkZhY3Rvcnk6ICgpID0+IHRoaXMudG9rZW4sXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmJ1aWxkKCk7XG4gICAgICAgICAgaHViLm9uY2xvc2UgPSB0aGlzLmhhbmRsZUVycm9yO1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgaHViLFxuICAgICAgICAgICAgcmV0cnk6IHJldHJ5ICsgMSxcbiAgICAgICAgICAgIGNyZWF0ZTogMCxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHN0YXJ0SHViKGh1Yikge1xuICAgICAgaWYgKGh1Yikge1xuICAgICAgICBodWIuc3RhcnQoKVxuICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHsgcGVuZGluZywgYWN0aXZlIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICAgICAgaWYgKCF0aGlzLnBlbmRpbmcpIHRoaXMucGVuZGluZyA9IHBlbmRpbmcgfHwgTWFwKCk7XG4gICAgICAgICAgICBpZiAoIXRoaXMuYWN0aXZlKSB0aGlzLmFjdGl2ZSA9IGFjdGl2ZSB8fCBNYXAoKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICBhY3RpdmU6IHRoaXMuYWN0aXZlLFxuICAgICAgICAgICAgICBwZW5kaW5nOiB0aGlzLnBlbmRpbmcsXG4gICAgICAgICAgICAgIHJldHJ5OiAwLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGBXYXJuaW5nOiBFcnJvciB3aGlsZSBlc3RhYmxpc2hpbmcgY29ubmVjdGlvbiB0byBodWIgJHtodWJOYW1lfS5cXG5cXG4ke2Vycn1gKTtcbiAgICAgICAgICAgIGh1Yi5zdG9wKCk7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZUVycm9yKGVycik7XG4gICAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaGFuZGxlRXJyb3IgPSAoZXJyKSA9PiB7XG4gICAgICBjb25zdCB7IHJlc3BvbnNlLCBzdGF0dXNDb2RlIH0gPSBlcnI7XG4gICAgICBjb25zdCB7IHN0YXR1cyB9ID0gcmVzcG9uc2UgfHwge307XG4gICAgICBzd2l0Y2ggKHN0YXR1cyB8fCBzdGF0dXNDb2RlKSB7XG4gICAgICAgIGNhc2UgNTAwOlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDQwMTpcbiAgICAgICAgICB0aGlzLm9sZFRva2VuID0gdGhpcy50b2tlbjsgLy8gZmFsbCB0aHJvdWdoXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGh1YjogbnVsbCB9KTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgc3RvcEh1YihodWIsIGNsZWFyKSB7XG4gICAgICBpZiAoaHViKSB7XG4gICAgICAgIGNvbnN0IHByb21pc2VzID0gW107XG5cbiAgICAgICAgaWYgKGNsZWFyKSB7XG4gICAgICAgICAgLy8gQ2xlYXIgcGVuZGluZ1xuICAgICAgICAgIHRoaXMucGVuZGluZyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICBwcm9taXNlcy5wdXNoKHRoaXMucmVtb3ZlRnJvbUdyb3VwKCcnKSk7XG4gICAgICAgICAgLy8gTWVyZ2UgYWN0aXZlIHRvIHBlbmRpbmdcbiAgICAgICAgfSBlbHNlIGlmICghdGhpcy5wZW5kaW5nKSB7XG4gICAgICAgICAgdGhpcy5wZW5kaW5nID0gdGhpcy5zdGF0ZS5hY3RpdmU7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5hY3RpdmUpIHtcbiAgICAgICAgICB0aGlzLnBlbmRpbmcgPSB0aGlzLnBlbmRpbmcubWVyZ2VEZWVwKHRoaXMuc3RhdGUuYWN0aXZlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKCgpID0+IHtcbiAgICAgICAgICBodWIuc3RvcCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmFjdGl2ZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgcGVuZGluZzogdGhpcy5wZW5kaW5nLFxuICAgICAgICAgIGFjdGl2ZTogdGhpcy5hY3RpdmUsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJlZ2lzdGVyTGlzdGVuZXIgPSAobmFtZSwgaGFuZGxlcikgPT4ge1xuICAgICAgY29uc3QgeyBwZW5kaW5nLCBhY3RpdmUsIG1vcmlidW5kIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgLy8gUmVtb3ZlIGxpc3RlbmVyIGZyb20gbW9yaWJ1bmQgbGlzdGVuZXJzXG4gICAgICBpZiAoIXRoaXMubW9yaWJ1bmQpIHRoaXMubW9yaWJ1bmQgPSBtb3JpYnVuZCB8fCBNYXAoKTtcbiAgICAgIGNvbnN0IGV4aXN0aW5nTW9yaWJ1bmQgPSB0aGlzLm1vcmlidW5kLmdldEluKFtuYW1lXSwgU2V0KCkpO1xuICAgICAgaWYgKGV4aXN0aW5nTW9yaWJ1bmQuaGFzKGhhbmRsZXIpKSB7XG4gICAgICAgIGNvbnN0IHJlbWFpbmluZ01vcmlidW5kID0gZXhpc3RpbmdNb3JpYnVuZC5maWx0ZXJOb3QoaCA9PiBoID09PSBoYW5kbGVyKTtcbiAgICAgICAgdGhpcy5tb3JpYnVuZCA9IHJlbWFpbmluZ01vcmlidW5kLnNpemVcbiAgICAgICAgICA/IHRoaXMubW9yaWJ1bmQuc2V0SW4oW25hbWVdLCByZW1haW5pbmdNb3JpYnVuZCkgOiB0aGlzLm1vcmlidW5kLmRlbGV0ZShuYW1lKTtcbiAgICAgIH1cbiAgICAgIC8vIEFkZCBsaXN0ZW5lciB0byBwZW5kaW5nIGxpc3RlbmVycyAoaWYgaXQgaXMgTk9UIGFjdGl2ZSlcbiAgICAgIGlmICghdGhpcy5hY3RpdmUpIHRoaXMuYWN0aXZlID0gYWN0aXZlIHx8IE1hcCgpO1xuICAgICAgY29uc3QgZXhpc3RpbmdBY3RpdmUgPSB0aGlzLmFjdGl2ZS5nZXRJbihbbmFtZV0sIFNldCgpKTtcbiAgICAgIGlmICghZXhpc3RpbmdBY3RpdmUuaGFzKGhhbmRsZXIpKSB7XG4gICAgICAgIGlmICghdGhpcy5wZW5kaW5nKSB0aGlzLnBlbmRpbmcgPSBwZW5kaW5nIHx8IE1hcCgpO1xuICAgICAgICBjb25zdCBleGlzdGluZ1BlbmRpbmcgPSB0aGlzLnBlbmRpbmcuZ2V0SW4oW25hbWVdLCBTZXQoKSk7XG4gICAgICAgIGlmICghZXhpc3RpbmdQZW5kaW5nLmhhcyhoYW5kbGVyKSkge1xuICAgICAgICAgIHRoaXMucGVuZGluZyA9IHRoaXMucGVuZGluZy5zZXRJbihbbmFtZV0sIGV4aXN0aW5nUGVuZGluZy5hZGQoaGFuZGxlcikpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5wZW5kaW5nICE9PSBwZW5kaW5nIHx8IHRoaXMubW9yaWJ1bmQgIT09IG1vcmlidW5kKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIHBlbmRpbmc6IHRoaXMucGVuZGluZyxcbiAgICAgICAgICBtb3JpYnVuZDogdGhpcy5tb3JpYnVuZCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIHVucmVnaXN0ZXJMaXN0ZW5lciA9IChuYW1lLCBoYW5kbGVyKSA9PiB7XG4gICAgICBjb25zdCB7IHBlbmRpbmcsIGFjdGl2ZSwgbW9yaWJ1bmQgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAvLyBSZW1vdmUgbGlzdGVuZXIgZnJvbSBwZW5kaW5nIGxpc3RlbmVyc1xuICAgICAgaWYgKCF0aGlzLnBlbmRpbmcpIHRoaXMucGVuZGluZyA9IHBlbmRpbmcgfHwgTWFwKCk7XG4gICAgICBjb25zdCBleGlzdGluZ1BlbmRpbmcgPSB0aGlzLnBlbmRpbmcuZ2V0SW4oW25hbWVdLCBTZXQoKSk7XG4gICAgICBpZiAoZXhpc3RpbmdQZW5kaW5nLmhhcyhoYW5kbGVyKSkge1xuICAgICAgICBjb25zdCByZW1haW5pbmdQZW5kaW5nID0gZXhpc3RpbmdQZW5kaW5nLmZpbHRlck5vdChoID0+IGggPT09IGhhbmRsZXIpO1xuICAgICAgICB0aGlzLnBlbmRpbmcgPSByZW1haW5pbmdQZW5kaW5nLmNvdW50KClcbiAgICAgICAgICA/IHRoaXMucGVuZGluZy5zZXRJbihbbmFtZV0sIHJlbWFpbmluZ1BlbmRpbmcpXG4gICAgICAgICAgOiB0aGlzLnBlbmRpbmcuZGVsZXRlKG5hbWUpO1xuICAgICAgfVxuICAgICAgLy8gQWRkIGxpc3RlbmVyIHRvIG1vcmlidW5kIGxpc3RlbmVycyAoaWYgaXQgaXMgYWN0aXZlKVxuICAgICAgaWYgKCF0aGlzLmFjdGl2ZSkgdGhpcy5hY3RpdmUgPSBhY3RpdmUgfHwgTWFwKCk7XG4gICAgICBjb25zdCBleGlzdGluZ0FjdGl2ZSA9IHRoaXMuYWN0aXZlLmdldEluKFtuYW1lXSwgU2V0KCkpO1xuICAgICAgaWYgKGV4aXN0aW5nQWN0aXZlLmhhcyhoYW5kbGVyKSkge1xuICAgICAgICBpZiAoIXRoaXMubW9yaWJ1bmQpIHRoaXMubW9yaWJ1bmQgPSBtb3JpYnVuZCB8fCBNYXAoKTtcbiAgICAgICAgY29uc3QgZXhpc3RpbmdNb3JpYnVuZCA9IHRoaXMubW9yaWJ1bmQuZ2V0SW4oW25hbWVdLCBTZXQoKSk7XG4gICAgICAgIGlmICghZXhpc3RpbmdNb3JpYnVuZC5oYXMoaGFuZGxlcikpIHtcbiAgICAgICAgICB0aGlzLm1vcmlidW5kID0gdGhpcy5tb3JpYnVuZC5zZXRJbihbbmFtZV0sIGV4aXN0aW5nTW9yaWJ1bmQuYWRkKGhhbmRsZXIpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHRoaXMucGVuZGluZyAhPT0gcGVuZGluZyB8fCB0aGlzLm1vcmlidW5kICE9PSBtb3JpYnVuZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBwZW5kaW5nOiB0aGlzLnBlbmRpbmcsXG4gICAgICAgICAgbW9yaWJ1bmQ6IHRoaXMubW9yaWJ1bmQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBhY3RpdmF0ZUxpc3RlbmVycyhodWIsIHBlbmRpbmdQYXJhbSkge1xuICAgICAgbGV0IHBlbmRpbmcgPSBwZW5kaW5nUGFyYW07XG4gICAgICBpZiAoaHViICYmIHBlbmRpbmdQYXJhbSkge1xuICAgICAgICBjb25zdCB7IGNvbm5lY3Rpb24gfSA9IGh1YjtcbiAgICAgICAgaWYgKGNvbm5lY3Rpb24gJiYgY29ubmVjdGlvbi5jb25uZWN0aW9uU3RhdGUgPT09IDEpIHtcbiAgICAgICAgICBjb25zdCB7IGFjdGl2ZSB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgICBpZiAoIXRoaXMuYWN0aXZlKSB0aGlzLmFjdGl2ZSA9IGFjdGl2ZSB8fCBNYXAoKTtcbiAgICAgICAgICBpZiAodGhpcy5hY3RpdmUucmVkdWNlKHRoaXMuY291bnQsIDApKSB7XG4gICAgICAgICAgICBwZW5kaW5nID0gcGVuZGluZy5tYXBFbnRyaWVzKChbbmFtZSwgY3VySGFuZGxlcnNdKSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5hY3RpdmUuZ2V0SW4oW25hbWVdKTtcbiAgICAgICAgICAgICAgY29uc3QgaGFuZGxlcnMgPSBleGlzdGluZ1xuICAgICAgICAgICAgICAgID8gY3VySGFuZGxlcnMuZmlsdGVyTm90KGhhbmRsZXIgPT4gZXhpc3RpbmcuaGFzKGhhbmRsZXIpKVxuICAgICAgICAgICAgICAgIDogY3VySGFuZGxlcnM7XG4gICAgICAgICAgICAgIHJldHVybiBbbmFtZSwgaGFuZGxlcnNdO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHBlbmRpbmcubWFwRW50cmllcygoW25hbWUsIGhhbmRsZXJzXSkgPT4gaGFuZGxlcnMubWFwKGhhbmRsZXIgPT4gaHViLm9uKG5hbWUsIGhhbmRsZXIpKSk7XG4gICAgICAgICAgdGhpcy5hY3RpdmUgPSB0aGlzLmFjdGl2ZS5tZXJnZURlZXAocGVuZGluZyk7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwZW5kaW5nOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBhY3RpdmU6IHRoaXMuYWN0aXZlLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBwZW5kaW5nO1xuICAgIH1cblxuICAgIGluYWN0aXZhdGVMaXN0ZW5lcnMoaHViLCBtb3JpYnVuZCkge1xuICAgICAgaWYgKGh1YiAmJiBtb3JpYnVuZCkge1xuICAgICAgICBtb3JpYnVuZC5tYXBFbnRyaWVzKChbbmFtZSwgaGFuZGxlcnNdKSA9PiBoYW5kbGVycy5tYXAoaGFuZGxlciA9PiBodWIub2ZmKG5hbWUsIGhhbmRsZXIpKSk7XG4gICAgICAgIGNvbnN0IHsgYWN0aXZlIH0gPSB0aGlzLnN0YXRlO1xuICAgICAgICBpZiAoIXRoaXMuYWN0aXZlKSB0aGlzLmFjdGl2ZSA9IGFjdGl2ZSB8fCBNYXAoKTtcbiAgICAgICAgdGhpcy5hY3RpdmUgPSB0aGlzLmFjdGl2ZS5tYXBFbnRyaWVzKChbbmFtZSwgY3VySGFuZGxlcnNdKSA9PiB7XG4gICAgICAgICAgY29uc3QgcmVtb3ZhYmxlID0gbW9yaWJ1bmQuZ2V0SW4oW25hbWVdKTtcbiAgICAgICAgICBjb25zdCBoYW5kbGVycyA9IHJlbW92YWJsZVxuICAgICAgICAgICAgPyBjdXJIYW5kbGVycy5maWx0ZXJOb3QoaGFuZGxlciA9PiByZW1vdmFibGUuaGFzKGhhbmRsZXIpKVxuICAgICAgICAgICAgOiBjdXJIYW5kbGVycztcbiAgICAgICAgICByZXR1cm4gW25hbWUsIGhhbmRsZXJzXTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGFjdGl2ZTogdGhpcy5hY3RpdmUsXG4gICAgICAgICAgbW9yaWJ1bmQ6IHVuZGVmaW5lZCxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICByZXR1cm4gbW9yaWJ1bmQ7XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgY29uc3QgeyBiYXNlVXJsLCBzaWduYWxyQWN0aW9ucywgLi4ucGFzc1Rocm91Z2hQcm9wcyB9ID0gdGhpcy5wcm9wcztcbiAgICAgIGNvbnN0IGh1YlByb3AgPSB7IFtodWJOYW1lXTogdGhpcy5odWJQcm94eSB9O1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgPFdyYXBwZWRDb21wb25lbnRcbiAgICAgICAgICB7Li4ucGFzc1Rocm91Z2hQcm9wc31cbiAgICAgICAgICB7Li4uaHViUHJvcH1cbiAgICAgICAgLz5cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgSW5qZWN0U2lnbmFsUi5kaXNwbGF5TmFtZSA9IGBJbmplY3RTaWduYWxSKCR7Z2V0RGlzcGxheU5hbWUoV3JhcHBlZENvbXBvbmVudCl9KWA7XG5cbiAgSW5qZWN0U2lnbmFsUi5wcm9wVHlwZXMgPSB7XG4gICAgYmFzZVVybDogUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICAgIHNpZ25hbHJBY3Rpb25zOiBQcm9wVHlwZXMuc2hhcGUoe1xuICAgICAgZ2V0QWNjZXNzVG9rZW46IFByb3BUeXBlcy5mdW5jLFxuICAgIH0pLmlzUmVxdWlyZWQsXG4gIH07XG5cbiAgY29uc3QgZ2V0VmFsdWVGcm9tU3RhdGUgPSAoc3RhdGUsIHNvdXJjZSkgPT4ge1xuICAgIGlmICh0eXBlb2Ygc291cmNlID09PSAnZnVuY3Rpb24nKSByZXR1cm4gc291cmNlKHN0YXRlKTtcbiAgICBpZiAodHlwZW9mIHNvdXJjZSA9PT0gJ3N0cmluZycpIHJldHVybiBzb3VyY2U7XG4gICAgcmV0dXJuICcnO1xuICB9O1xuXG4gIGNvbnN0IG1hcERpc3BhdGNoVG9Qcm9wcyA9IGRpc3BhdGNoID0+ICh7XG4gICAgc2lnbmFsckFjdGlvbnM6IGJpbmRBY3Rpb25DcmVhdG9ycyh7XG4gICAgICBhY2Nlc3NUb2tlbkZhY3Rvcnk6ICgpID0+IChkaXNwYXRjaGVyLCBnZXRTdGF0ZSkgPT4ge1xuICAgICAgICBjb25zdCBzdGF0ZSA9IGdldFN0YXRlKCk7XG4gICAgICAgIHJldHVybiBnZXRWYWx1ZUZyb21TdGF0ZShzdGF0ZSwgYWNjZXNzVG9rZW4pO1xuICAgICAgfSxcbiAgICB9LCBkaXNwYXRjaCksXG4gIH0pO1xuXG4gIGNvbnN0IG1hcFN0YXRlVG9Qcm9wcyA9IChzdGF0ZSkgPT4ge1xuICAgIGNvbnN0IGJhc2VVcmwgPSBnZXRWYWx1ZUZyb21TdGF0ZShzdGF0ZSwgYmFzZUFkZHJlc3MpO1xuICAgIHJldHVybiB7IGJhc2VVcmwgfTtcbiAgfTtcblxuICByZXR1cm4gY29ubmVjdChtYXBTdGF0ZVRvUHJvcHMsIG1hcERpc3BhdGNoVG9Qcm9wcykoSW5qZWN0U2lnbmFsUik7XG59O1xuXG5leHBvcnQgZGVmYXVsdCBpbmplY3RTaWduYWxSO1xuIl19 -------------------------------------------------------------------------------- /lib/es/types.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | var func = PropTypes.func; 4 | 5 | 6 | var hubShape = PropTypes.shape({ 7 | invoke: func.isRequired, 8 | send: func.isRequired, 9 | add: func.isRequired, 10 | remove: func.isRequired, 11 | register: func.isRequired, 12 | unregister: func.isRequired 13 | }); 14 | 15 | export default hubShape; 16 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eXBlcy5qc3giXSwibmFtZXMiOlsiUHJvcFR5cGVzIiwiZnVuYyIsImh1YlNoYXBlIiwic2hhcGUiLCJpbnZva2UiLCJpc1JlcXVpcmVkIiwic2VuZCIsImFkZCIsInJlbW92ZSIsInJlZ2lzdGVyIiwidW5yZWdpc3RlciJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBT0EsU0FBUCxNQUFzQixZQUF0Qjs7SUFFUUMsSSxHQUFTRCxTLENBQVRDLEk7OztBQUVSLElBQU1DLFdBQVdGLFVBQVVHLEtBQVYsQ0FBZ0I7QUFDL0JDLFVBQVFILEtBQUtJLFVBRGtCO0FBRS9CQyxRQUFNTCxLQUFLSSxVQUZvQjtBQUcvQkUsT0FBS04sS0FBS0ksVUFIcUI7QUFJL0JHLFVBQVFQLEtBQUtJLFVBSmtCO0FBSy9CSSxZQUFVUixLQUFLSSxVQUxnQjtBQU0vQkssY0FBWVQsS0FBS0k7QUFOYyxDQUFoQixDQUFqQjs7QUFTQSxlQUFlSCxRQUFmIiwiZmlsZSI6InR5cGVzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFByb3BUeXBlcyBmcm9tICdwcm9wLXR5cGVzJztcblxuY29uc3QgeyBmdW5jIH0gPSBQcm9wVHlwZXM7XG5cbmNvbnN0IGh1YlNoYXBlID0gUHJvcFR5cGVzLnNoYXBlKHtcbiAgaW52b2tlOiBmdW5jLmlzUmVxdWlyZWQsXG4gIHNlbmQ6IGZ1bmMuaXNSZXF1aXJlZCxcbiAgYWRkOiBmdW5jLmlzUmVxdWlyZWQsXG4gIHJlbW92ZTogZnVuYy5pc1JlcXVpcmVkLFxuICByZWdpc3RlcjogZnVuYy5pc1JlcXVpcmVkLFxuICB1bnJlZ2lzdGVyOiBmdW5jLmlzUmVxdWlyZWQsXG59KTtcblxuZXhwb3J0IGRlZmF1bHQgaHViU2hhcGU7XG4iXX0= -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "OpusCapita (www.opuscapita.com)", 3 | "name": "@opuscapita/react-signalr", 4 | "version": "3.3.0", 5 | "private": false, 6 | "license": "MIT", 7 | "description": "OpusCapita react signalr", 8 | "main": "lib/umd/index.js", 9 | "cjs": "lib/cjs/index.js", 10 | "es": "lib/es/index.js", 11 | "scripts": { 12 | "clean": "rimraf lib", 13 | "build": "npm-run-all clean build:*", 14 | "build:cjs": "cross-env NODE_ENV=production BUILD_ENV=cjs babel src --out-dir lib/cjs --copy-files --source-maps inline", 15 | "build:es": "cross-env NODE_ENV=production BUILD_ENV=es babel src --out-dir lib/es --copy-files --source-maps inline", 16 | "build:umd": "cross-env NODE_ENV=development BUILD_ENV=umd webpack", 17 | "build:umd-min": "cross-env NODE_ENV=production BUILD_ENV=umd webpack", 18 | "watch": "npm-run-all --parallel watch:*", 19 | "watch:cjs": "cross-env NODE_ENV=development BUILD_ENV=cjs babel ./src/index.js --out-dir lib/cjs --copy-files --watch", 20 | "watch:es": "cross-env NODE_ENV=development BUILD_ENV=es babel ./src/index.js --out-dir lib/es --copy-files --watch", 21 | "watch:umd": "cross-env NODE_ENV=development BUILD_ENV=umd webpack --progress --colors --watch", 22 | "lint": "node_modules/.bin/eslint --ext .jsx,.js src/", 23 | "preversion": "npm run lint", 24 | "version": "npm run build && git add -A lib", 25 | "postversion": "git push && git push --tags" 26 | }, 27 | "files": [ 28 | "/lib" 29 | ], 30 | "engines": { 31 | "node": ">=6.10.0", 32 | "npm": ">=5.4.0" 33 | }, 34 | "peerDependencies": { 35 | "prop-types": "15", 36 | "react": "15 || 16", 37 | "react-dom": "15 || 16" 38 | }, 39 | "devDependencies": { 40 | "autoprefixer": "9.4.6", 41 | "babel-cli": "6.26.0", 42 | "babel-eslint": "10.0.1", 43 | "babel-loader": "7.1.5", 44 | "babel-plugin-dynamic-import-node": "2.2.0", 45 | "babel-plugin-react-transform": "3.0.0", 46 | "babel-plugin-transform-decorators-legacy": "1.3.5", 47 | "babel-plugin-transform-react-remove-prop-types": "0.4.23", 48 | "babel-polyfill": "6.26.0", 49 | "babel-preset-env": "1.7.0", 50 | "babel-preset-react": "6.24.1", 51 | "babel-preset-stage-1": "6.24.1", 52 | "babel-register": "6.26.0", 53 | "bootstrap-sass": "3.4.0", 54 | "clean-webpack-plugin": "1.0.1", 55 | "cross-env": "5.2.0", 56 | "css-loader": "0.28.11", 57 | "enzyme": "3.8.0", 58 | "enzyme-adapter-react-16": "1.7.1", 59 | "eslint": "5.12.1", 60 | "eslint-config-airbnb": "16.1.0", 61 | "eslint-plugin-import": "2.15.0", 62 | "eslint-plugin-jsx-a11y": "6.1.2", 63 | "eslint-plugin-react": "7.12.4", 64 | "file-loader": "3.0.1", 65 | "global-jsdom": "4.2.0", 66 | "html-webpack-plugin": "2.30.1", 67 | "ignore-styles": "5.0.1", 68 | "immutable": "3.8.2", 69 | "jsdom": "13.1.0", 70 | "mocha": "5.2.0", 71 | "node-sass": "4.11.0", 72 | "npm-run-all": "4.1.5", 73 | "postcss-flexbugs-fixes": "4.1.0", 74 | "postcss-loader": "2.1.6", 75 | "precss": "4.0.0", 76 | "progress-bar-webpack-plugin": "1.11.0", 77 | "prop-types": "15.6.2", 78 | "react": "16.7.0", 79 | "react-bootstrap": "0.32.4", 80 | "react-dom": "16.7.0", 81 | "react-hot-loader": "4.3.11", 82 | "react-router": "4.3.1", 83 | "react-router-dom": "4.3.1", 84 | "react-svg-loader": "2.1.0", 85 | "react-test-renderer": "16.7.0", 86 | "rimraf": "2.6.3", 87 | "sass-loader": "7.1.0", 88 | "sinon": "7.2.3", 89 | "style-loader": "0.23.1", 90 | "url-loader": "1.1.2", 91 | "webpack": "3.12.0", 92 | "webpack-dev-server": "2.11.3", 93 | "webpack-merge": "4.2.1", 94 | "webpack-node-externals": "1.7.2", 95 | "webpack-notifier": "1.7.0", 96 | "write-file-webpack-plugin": "4.5.0" 97 | }, 98 | "dependencies": { 99 | "@aspnet/signalr": "1.0.0", 100 | "axios": "0.18.0", 101 | "react-redux": "5.0.7", 102 | "redux": "4.0.1", 103 | "tslib": "1.9.3" 104 | }, 105 | "repository": { 106 | "type": "git", 107 | "url": "https://github.com/OpusCapita/react-signalr.git" 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { default as hubShape } from './types'; 2 | export { default as injectSignalR } from './inject'; 3 | -------------------------------------------------------------------------------- /src/inject.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import axios from 'axios'; 4 | import { bindActionCreators } from 'redux'; 5 | import { connect } from 'react-redux'; 6 | import { Map, Set } from 'immutable'; 7 | import { HubConnectionBuilder, HttpTransportType } from '@aspnet/signalr'; 8 | 9 | const getDisplayName = Component => Component.displayName || Component.name || 'Component'; 10 | 11 | const injectSignalR = options => (WrappedComponent) => { 12 | const { 13 | hubName = '', 14 | baseAddress = 'http://localhost:5555', 15 | accessToken = null, 16 | signalrPath = 'signalr', 17 | retries = 3, 18 | } = options; 19 | const { controller = hubName } = options; 20 | 21 | class InjectSignalR extends React.PureComponent { 22 | static WrappedComponent = WrappedComponent; 23 | 24 | constructor(props) { 25 | super(props); 26 | this.state = { 27 | hub: null, 28 | pending: undefined, 29 | active: undefined, 30 | moribund: undefined, 31 | retry: 0, 32 | create: 0, 33 | }; 34 | } 35 | 36 | componentWillMount() { 37 | this.hubProxy = { 38 | send: this.sendToController, 39 | invoke: this.invokeController, 40 | add: this.addToGroup, 41 | remove: this.removeFromGroup, 42 | connectionId: undefined, 43 | register: this.registerListener, 44 | unregister: this.unregisterListener, 45 | }; 46 | } 47 | 48 | componentDidMount() { 49 | this.createHub(); 50 | } 51 | 52 | componentWillUpdate(nextProps, nextState) { 53 | if (this.state.hub !== nextState.hub) { 54 | if (this.state.hub) this.stopHub(this.state.hub, false); 55 | if (nextState.hub) { 56 | this.startHub(nextState.hub); 57 | } else { 58 | this.createHub(nextState.create); 59 | } 60 | } else if (!nextState.hub) { 61 | this.createHub(nextState.create); 62 | } else { 63 | let { pending, moribund } = nextState; 64 | if (!moribund) { 65 | moribund = this.moribund || Map(); 66 | } else if (this.moribund) { 67 | moribund = moribund.mergeDeep(this.moribund); 68 | } 69 | const moribundCount = moribund.reduce(this.count, 0); 70 | if (moribundCount) { 71 | this.moribund = this.inactivateListeners(this.state.hub, moribund); 72 | } 73 | if (!pending) { 74 | pending = this.pending || Map(); 75 | } else if (this.pending) { 76 | pending = pending.mergeDeep(this.pending); 77 | } 78 | const pendingCount = pending.reduce(this.count, 0); 79 | if (pendingCount) { 80 | this.pending = this.activateListeners(nextState.hub, pending); 81 | } 82 | } 83 | } 84 | 85 | componentWillUnmount() { 86 | this.stopHub(this.state.hub, true); 87 | } 88 | 89 | count = (c, s) => c + s.count(); 90 | 91 | addToGroup = (group) => { 92 | const { hub } = this.state; 93 | if (hub) { 94 | const { connection } = hub; 95 | if (connection && connection.connectionState === 1) { 96 | hub.invoke('addToGroup', group) 97 | .catch((err) => { 98 | console.error(`Error: Adding client to group ${group} in ${hubName} failed.\n\n${err}`); 99 | }); 100 | } 101 | } 102 | }; 103 | 104 | removeFromGroup = (group) => { 105 | const { hub } = this.state; 106 | if (hub) { 107 | const { connection } = hub; 108 | if (connection && connection.connectionState === 1) { 109 | return hub.invoke('removeFromGroup', group) 110 | .catch((err) => { 111 | console.error(`Error: Removing client from group ${group} in ${hubName} failed.\n\n${err}`); 112 | }); 113 | } 114 | } 115 | return Promise.resolve(); 116 | }; 117 | 118 | sendToController = (target, data = null) => { 119 | const url = `${this.props.baseUrl}/${controller}/${target}`; 120 | const payload = data ? data.toJS() : null; 121 | return axios.post(url, payload) 122 | .catch((err) => { 123 | console.error(`Error: Sending data to ${controller} failed.\n\n${err}`); 124 | }); 125 | }; 126 | 127 | invokeController = (targetMethod, data = null) => { 128 | const urlBase = `${this.props.baseUrl}/${controller}/${targetMethod}`; 129 | const url = data ? `${urlBase}/${data}` : urlBase; 130 | return axios.get(url) 131 | .catch((err) => { 132 | console.error(`Error: Invoking ${controller} failed.\n\n${err}`); 133 | }); 134 | }; 135 | 136 | async createHub(curCreate) { 137 | const { retry, create } = this.state; 138 | if (retry > retries) { 139 | console.error(`Error: Ran out of retries for starting ${hubName}!`); 140 | this.setState({ 141 | retry: 0, 142 | create: 0, 143 | }); 144 | } else { 145 | const { baseUrl, signalrActions } = this.props; 146 | if (baseUrl && hubName) { 147 | let hubAddress = baseUrl; 148 | if (signalrPath) hubAddress = `${hubAddress}/${signalrPath}`; 149 | hubAddress = `${hubAddress}/${hubName}`; 150 | this.token = signalrActions.accessTokenFactory(accessToken); 151 | if (this.token) { 152 | if (this.oldToken === this.token) { 153 | if ((curCreate || create) > retries) { 154 | console.warn('Warning: Unable to get up-to-date access token.'); 155 | } else { 156 | this.setState({ 157 | hub: null, 158 | create: (curCreate || create) + 1, 159 | }); 160 | } 161 | return; 162 | } 163 | this.oldToken = undefined; 164 | } 165 | const hub = new HubConnectionBuilder() 166 | .withUrl(hubAddress, { 167 | skipNegotiation: true, 168 | transport: HttpTransportType.WebSockets, 169 | accessTokenFactory: () => this.token, 170 | }) 171 | .build(); 172 | hub.onclose = this.handleError; 173 | this.setState({ 174 | hub, 175 | retry: retry + 1, 176 | create: 0, 177 | }); 178 | } 179 | } 180 | } 181 | 182 | startHub(hub) { 183 | if (hub) { 184 | hub.start() 185 | .then(() => { 186 | const { pending, active } = this.state; 187 | if (!this.pending) this.pending = pending || Map(); 188 | if (!this.active) this.active = active || Map(); 189 | this.setState({ 190 | active: this.active, 191 | pending: this.pending, 192 | retry: 0, 193 | }); 194 | }) 195 | .catch((err) => { 196 | console.warn(`Warning: Error while establishing connection to hub ${hubName}.\n\n${err}`); 197 | hub.stop(); 198 | this.handleError(err); 199 | }); 200 | } 201 | } 202 | 203 | handleError = (err) => { 204 | const { response, statusCode } = err; 205 | const { status } = response || {}; 206 | switch (status || statusCode) { 207 | case 500: 208 | break; 209 | case 401: 210 | this.oldToken = this.token; // fall through 211 | default: 212 | this.setState({ hub: null }); 213 | break; 214 | } 215 | }; 216 | 217 | stopHub(hub, clear) { 218 | if (hub) { 219 | const promises = []; 220 | 221 | if (clear) { 222 | // Clear pending 223 | this.pending = undefined; 224 | promises.push(this.removeFromGroup('')); 225 | // Merge active to pending 226 | } else if (!this.pending) { 227 | this.pending = this.state.active; 228 | } else if (this.state.active) { 229 | this.pending = this.pending.mergeDeep(this.state.active); 230 | } 231 | 232 | Promise.all(promises).then(() => { 233 | hub.stop(); 234 | }); 235 | 236 | this.active = undefined; 237 | this.setState({ 238 | pending: this.pending, 239 | active: this.active, 240 | }); 241 | } 242 | } 243 | 244 | registerListener = (name, handler) => { 245 | const { pending, active, moribund } = this.state; 246 | // Remove listener from moribund listeners 247 | if (!this.moribund) this.moribund = moribund || Map(); 248 | const existingMoribund = this.moribund.getIn([name], Set()); 249 | if (existingMoribund.has(handler)) { 250 | const remainingMoribund = existingMoribund.filterNot(h => h === handler); 251 | this.moribund = remainingMoribund.size 252 | ? this.moribund.setIn([name], remainingMoribund) : this.moribund.delete(name); 253 | } 254 | // Add listener to pending listeners (if it is NOT active) 255 | if (!this.active) this.active = active || Map(); 256 | const existingActive = this.active.getIn([name], Set()); 257 | if (!existingActive.has(handler)) { 258 | if (!this.pending) this.pending = pending || Map(); 259 | const existingPending = this.pending.getIn([name], Set()); 260 | if (!existingPending.has(handler)) { 261 | this.pending = this.pending.setIn([name], existingPending.add(handler)); 262 | } 263 | } 264 | if (this.pending !== pending || this.moribund !== moribund) { 265 | this.setState({ 266 | pending: this.pending, 267 | moribund: this.moribund, 268 | }); 269 | } 270 | }; 271 | 272 | unregisterListener = (name, handler) => { 273 | const { pending, active, moribund } = this.state; 274 | // Remove listener from pending listeners 275 | if (!this.pending) this.pending = pending || Map(); 276 | const existingPending = this.pending.getIn([name], Set()); 277 | if (existingPending.has(handler)) { 278 | const remainingPending = existingPending.filterNot(h => h === handler); 279 | this.pending = remainingPending.count() 280 | ? this.pending.setIn([name], remainingPending) 281 | : this.pending.delete(name); 282 | } 283 | // Add listener to moribund listeners (if it is active) 284 | if (!this.active) this.active = active || Map(); 285 | const existingActive = this.active.getIn([name], Set()); 286 | if (existingActive.has(handler)) { 287 | if (!this.moribund) this.moribund = moribund || Map(); 288 | const existingMoribund = this.moribund.getIn([name], Set()); 289 | if (!existingMoribund.has(handler)) { 290 | this.moribund = this.moribund.setIn([name], existingMoribund.add(handler)); 291 | } 292 | } 293 | if (this.pending !== pending || this.moribund !== moribund) { 294 | this.setState({ 295 | pending: this.pending, 296 | moribund: this.moribund, 297 | }); 298 | } 299 | }; 300 | 301 | activateListeners(hub, pendingParam) { 302 | let pending = pendingParam; 303 | if (hub && pendingParam) { 304 | const { connection } = hub; 305 | if (connection && connection.connectionState === 1) { 306 | const { active } = this.state; 307 | if (!this.active) this.active = active || Map(); 308 | if (this.active.reduce(this.count, 0)) { 309 | pending = pending.mapEntries(([name, curHandlers]) => { 310 | const existing = this.active.getIn([name]); 311 | const handlers = existing 312 | ? curHandlers.filterNot(handler => existing.has(handler)) 313 | : curHandlers; 314 | return [name, handlers]; 315 | }); 316 | } 317 | pending.mapEntries(([name, handlers]) => handlers.map(handler => hub.on(name, handler))); 318 | this.active = this.active.mergeDeep(pending); 319 | this.setState({ 320 | pending: undefined, 321 | active: this.active, 322 | }); 323 | return undefined; 324 | } 325 | } 326 | return pending; 327 | } 328 | 329 | inactivateListeners(hub, moribund) { 330 | if (hub && moribund) { 331 | moribund.mapEntries(([name, handlers]) => handlers.map(handler => hub.off(name, handler))); 332 | const { active } = this.state; 333 | if (!this.active) this.active = active || Map(); 334 | this.active = this.active.mapEntries(([name, curHandlers]) => { 335 | const removable = moribund.getIn([name]); 336 | const handlers = removable 337 | ? curHandlers.filterNot(handler => removable.has(handler)) 338 | : curHandlers; 339 | return [name, handlers]; 340 | }); 341 | this.setState({ 342 | active: this.active, 343 | moribund: undefined, 344 | }); 345 | return undefined; 346 | } 347 | return moribund; 348 | } 349 | 350 | render() { 351 | const { baseUrl, signalrActions, ...passThroughProps } = this.props; 352 | const hubProp = { [hubName]: this.hubProxy }; 353 | return ( 354 | 358 | ); 359 | } 360 | } 361 | 362 | InjectSignalR.displayName = `InjectSignalR(${getDisplayName(WrappedComponent)})`; 363 | 364 | InjectSignalR.propTypes = { 365 | baseUrl: PropTypes.string.isRequired, 366 | signalrActions: PropTypes.shape({ 367 | getAccessToken: PropTypes.func, 368 | }).isRequired, 369 | }; 370 | 371 | const getValueFromState = (state, source) => { 372 | if (typeof source === 'function') return source(state); 373 | if (typeof source === 'string') return source; 374 | return ''; 375 | }; 376 | 377 | const mapDispatchToProps = dispatch => ({ 378 | signalrActions: bindActionCreators({ 379 | accessTokenFactory: () => (dispatcher, getState) => { 380 | const state = getState(); 381 | return getValueFromState(state, accessToken); 382 | }, 383 | }, dispatch), 384 | }); 385 | 386 | const mapStateToProps = (state) => { 387 | const baseUrl = getValueFromState(state, baseAddress); 388 | return { baseUrl }; 389 | }; 390 | 391 | return connect(mapStateToProps, mapDispatchToProps)(InjectSignalR); 392 | }; 393 | 394 | export default injectSignalR; 395 | -------------------------------------------------------------------------------- /src/types.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | const { func } = PropTypes; 4 | 5 | const hubShape = PropTypes.shape({ 6 | invoke: func.isRequired, 7 | send: func.isRequired, 8 | add: func.isRequired, 9 | remove: func.isRequired, 10 | register: func.isRequired, 11 | unregister: func.isRequired, 12 | }); 13 | 14 | export default hubShape; 15 | -------------------------------------------------------------------------------- /tools/babel.preset.js: -------------------------------------------------------------------------------- 1 | const { NODE_ENV, BUILD_ENV } = process.env; 2 | const presetOptions = BUILD_ENV === 'hot' || BUILD_ENV === 'umd' || BUILD_ENV === 'es' ? 3 | { loose: true, modules: false } : 4 | { loose: true }; 5 | 6 | const plugins = [ 7 | 'transform-decorators-legacy', 8 | ]; 9 | 10 | if (NODE_ENV === 'production') { 11 | plugins.push('transform-react-remove-prop-types'); 12 | } 13 | 14 | if (BUILD_ENV === 'hot') { 15 | plugins.push('react-hot-loader/babel'); 16 | } 17 | 18 | if (BUILD_ENV === 'test') { 19 | plugins.push('dynamic-import-node'); 20 | } 21 | 22 | module.exports = { 23 | presets: [ 24 | ['env', presetOptions], 25 | 'stage-1', 26 | 'react', 27 | ], 28 | plugins, 29 | }; 30 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const merge = require('webpack-merge'); 4 | const WebpackNotifierPlugin = require('webpack-notifier'); 5 | const autoprefixer = require('autoprefixer'); 6 | const precss = require('precss'); 7 | const flexbugs = require('postcss-flexbugs-fixes'); 8 | 9 | const libraryName = 'react-signalr'; 10 | 11 | const isProd = process.env.NODE_ENV === 'production'; 12 | 13 | const PATHS = { 14 | root: __dirname, 15 | build: path.join(__dirname, 'lib', 'umd'), 16 | context: path.join(__dirname, 'src'), 17 | jsFileName: isProd ? `${libraryName}.min.js` : `${libraryName}.js`, 18 | entry: path.join(__dirname, 'src', 'index.js'), 19 | }; 20 | 21 | /* 22 | * BASE CONFIG FOR ALL ENVS 23 | */ 24 | const baseConfig = { 25 | context: PATHS.context, 26 | entry: [ 27 | PATHS.entry, 28 | ], 29 | output: { 30 | path: PATHS.build, 31 | filename: PATHS.jsFileName, 32 | library: libraryName, 33 | libraryTarget: 'umd', 34 | umdNamedDefine: true, 35 | }, 36 | module: { 37 | rules: [ 38 | { 39 | test: /(\.jsx|\.js)$/, 40 | exclude: { 41 | test: path.resolve(__dirname, 'node_modules'), 42 | exclude: path.resolve(__dirname, 'node_modules', '@aspnet'), 43 | }, 44 | use: [ 45 | 'babel-loader', 46 | ], 47 | }, 48 | { 49 | test: /\.css$/, 50 | use: [ 51 | 'style-loader', 52 | { 53 | loader: 'css-loader', 54 | options: { 55 | minimize: !!isProd, 56 | }, 57 | }, 58 | { 59 | loader: 'postcss-loader', 60 | options: { 61 | plugins: () => [flexbugs, precss, autoprefixer], 62 | }, 63 | }, 64 | ], 65 | }, 66 | { 67 | test: /\.scss$/, 68 | use: [ 69 | 'style-loader', 70 | { 71 | loader: 'css-loader', 72 | options: { 73 | minimize: !!isProd, 74 | }, 75 | }, 76 | { 77 | loader: 'postcss-loader', 78 | options: { 79 | plugins: () => [flexbugs, precss, autoprefixer], 80 | }, 81 | }, 82 | 'sass-loader', 83 | ], 84 | }, 85 | { 86 | test: /\.svg$/, 87 | exclude: path.resolve(__dirname, 'node_modules', 'font-awesome'), 88 | use: ['babel-loader', 'react-svg-loader'], 89 | }, 90 | { 91 | test: /\.svg$/, 92 | include: path.resolve(__dirname, 'node_modules', 'font-awesome'), 93 | use: [{ 94 | loader: 'file-loader', 95 | options: { 96 | name: '[name].[ext]', 97 | outputPath: 'fonts/', 98 | }, 99 | }], 100 | }, 101 | { 102 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 103 | use: [{ 104 | loader: 'url-loader', 105 | options: { 106 | name: '[name].[ext]', 107 | outputPath: 'fonts/', 108 | limit: 100, 109 | mimetype: 'application/font-woff', 110 | }, 111 | }], 112 | }, 113 | { 114 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 115 | use: [{ 116 | loader: 'url-loader', 117 | options: { 118 | name: '[name].[ext]', 119 | outputPath: 'fonts/', 120 | limit: 100, 121 | mimetype: 'application/octet-stream', 122 | }, 123 | }], 124 | }, 125 | { 126 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 127 | use: [{ 128 | loader: 'file-loader', 129 | options: { 130 | name: '[name].[ext]', 131 | outputPath: 'fonts/', 132 | }, 133 | }], 134 | }, 135 | { 136 | test: /\.ico$/, 137 | use: [{ 138 | loader: 'file-loader', 139 | options: { 140 | name: '[name].[ext]', 141 | }, 142 | }], 143 | }, 144 | ], 145 | }, 146 | node: { 147 | fs: 'empty', 148 | }, 149 | resolve: { 150 | modules: [ 151 | path.resolve('./src'), 152 | 'node_modules', 153 | ], 154 | extensions: ['.js', '.jsx'], 155 | mainFields: ['es', 'cjs', 'browser', 'module', 'es:next', 'main'], 156 | alias: { 157 | axios: path.resolve('./node_modules/axios'), 158 | react: path.resolve('./node_modules/react'), 159 | 'react-dom': path.resolve('./node_modules/react-dom'), 160 | }, 161 | }, 162 | // Add your peer dependencies here to avoid bundling them to build 163 | externals: { 164 | '@aspnet/signalr-client': '@aspnet/signalr-client', 165 | axios: 'axios', 166 | react: { 167 | root: 'React', 168 | commonjs2: 'react', 169 | commonjs: 'react', 170 | amd: 'react', 171 | umd: 'react', 172 | }, 173 | 'react-dom': { 174 | root: 'ReactDOM', 175 | commonjs2: 'react-dom', 176 | commonjs: 'react-dom', 177 | amd: 'react-dom', 178 | umd: 'react-dom', 179 | }, 180 | }, 181 | }; 182 | 183 | /* 184 | * DEVELOPMENT CONFIG 185 | */ 186 | const devConfig = { 187 | devtool: 'eval-source-map', 188 | plugins: [ 189 | new webpack.DefinePlugin({ 190 | 'process.env': { 191 | NODE_ENV: JSON.stringify('development'), 192 | }, 193 | }), 194 | new WebpackNotifierPlugin(), 195 | new webpack.NamedModulesPlugin(), 196 | ], 197 | }; 198 | 199 | /* 200 | * PRODUCTION CONFIG 201 | */ 202 | const prodConfig = { 203 | devtool: 'source-map', 204 | plugins: [ 205 | new webpack.DefinePlugin({ 206 | 'process.env': { 207 | NODE_ENV: JSON.stringify('production'), 208 | }, 209 | }), 210 | new webpack.optimize.ModuleConcatenationPlugin(), 211 | new webpack.optimize.UglifyJsPlugin({ 212 | sourceMap: true, 213 | output: { 214 | comments: false, 215 | }, 216 | }), 217 | ], 218 | }; 219 | 220 | module.exports = merge(baseConfig, isProd ? prodConfig : devConfig); 221 | --------------------------------------------------------------------------------