{ "version": 3, "sources": ["../js/node_modules/symbol-observable/es/index.js", "../js/node_modules/symbol-observable/es/ponyfill.js", "../js/node_modules/redux/es/redux.js", "../js/node_modules/immer/src/common.js", "../js/node_modules/immer/src/scope.js", "../js/node_modules/immer/src/es5.js", "../js/node_modules/immer/src/proxy.js", "../js/node_modules/immer/src/patches.js", "../js/node_modules/immer/src/immer.js", "../js/node_modules/immer/src/index.js", "../js/node_modules/reselect/es/index.js", "../js/node_modules/redux-devtools-extension/index.js", "../js/src/isPlainObject.ts", "../js/node_modules/redux-thunk/es/index.js", "../js/src/serializableStateInvariantMiddleware.ts", "../js/src/getDefaultMiddleware.ts", "../js/src/createAction.ts", "../js/src/mapBuilders.ts", "../js/src/createReducer.ts", "../js/src/configureStore.ts", "../js/src/createSlice.ts", "../js/vendor/jquery-3.4.1.min.js", "../js/chat-api/chat-api.js", "../js/chat-api/redux-subscriber.js", "../js/chat-api/const.js", "../js/chat-api/redux-store.js", "../js/chat-api/utils.js", "../js/chat-api/presence-channel.js", "../js/chat-api/graylog.js", "../js/chat-api/chat-channel.js", "../js/chat-api/edge-connection.js", "../js/chat-api/statechart.js", "../js/chat-api/chat-hsm.js", "../js/chat-api/messenger/messenger-connection-hsm.js", "../js/chat-api/messenger/messenger-connection.js", "../js/chat-api/messenger/messenger.js", "../js/02-utils.js", "../../../webpack/src/chat-api.js"], "sourcesContent": ["/* global window */\nimport ponyfill from './ponyfill.js';\n\nvar root;\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = ponyfill(root);\nexport default result;\n", "export default function symbolObservablePonyfill(root) {\n\tvar result;\n\tvar Symbol = root.Symbol;\n\n\tif (typeof Symbol === 'function') {\n\t\tif (Symbol.observable) {\n\t\t\tresult = Symbol.observable;\n\t\t} else {\n\t\t\tresult = Symbol('observable');\n\t\t\tSymbol.observable = result;\n\t\t}\n\t} else {\n\t\tresult = '@@observable';\n\t}\n\n\treturn result;\n};\n", "import $$observable from 'symbol-observable';\n\n/**\n * These are private action types reserved by Redux.\n * For any unknown actions, you must return the current state.\n * If the current state is undefined, you must return the initial state.\n * Do not reference these action types directly in your code.\n */\nvar randomString = function randomString() {\n return Math.random().toString(36).substring(7).split('').join('.');\n};\n\nvar ActionTypes = {\n INIT: \"@@redux/INIT\" + randomString(),\n REPLACE: \"@@redux/REPLACE\" + randomString(),\n PROBE_UNKNOWN_ACTION: function PROBE_UNKNOWN_ACTION() {\n return \"@@redux/PROBE_UNKNOWN_ACTION\" + randomString();\n }\n};\n\n/**\n * @param {any} obj The object to inspect.\n * @returns {boolean} True if the argument appears to be a plain object.\n */\nfunction isPlainObject(obj) {\n if (typeof obj !== 'object' || obj === null) return false;\n var proto = obj;\n\n while (Object.getPrototypeOf(proto) !== null) {\n proto = Object.getPrototypeOf(proto);\n }\n\n return Object.getPrototypeOf(obj) === proto;\n}\n\n/**\n * Creates a Redux store that holds the state tree.\n * The only way to change the data in the store is to call `dispatch()` on it.\n *\n * There should only be a single store in your app. To specify how different\n * parts of the state tree respond to actions, you may combine several reducers\n * into a single reducer function by using `combineReducers`.\n *\n * @param {Function} reducer A function that returns the next state tree, given\n * the current state tree and the action to handle.\n *\n * @param {any} [preloadedState] The initial state. You may optionally specify it\n * to hydrate the state from the server in universal apps, or to restore a\n * previously serialized user session.\n * If you use `combineReducers` to produce the root reducer function, this must be\n * an object with the same shape as `combineReducers` keys.\n *\n * @param {Function} [enhancer] The store enhancer. You may optionally specify it\n * to enhance the store with third-party capabilities such as middleware,\n * time travel, persistence, etc. The only store enhancer that ships with Redux\n * is `applyMiddleware()`.\n *\n * @returns {Store} A Redux store that lets you read the state, dispatch actions\n * and subscribe to changes.\n */\n\nfunction createStore(reducer, preloadedState, enhancer) {\n var _ref2;\n\n if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {\n throw new Error('It looks like you are passing several store enhancers to ' + 'createStore(). This is not supported. Instead, compose them ' + 'together to a single function');\n }\n\n if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {\n enhancer = preloadedState;\n preloadedState = undefined;\n }\n\n if (typeof enhancer !== 'undefined') {\n if (typeof enhancer !== 'function') {\n throw new Error('Expected the enhancer to be a function.');\n }\n\n return enhancer(createStore)(reducer, preloadedState);\n }\n\n if (typeof reducer !== 'function') {\n throw new Error('Expected the reducer to be a function.');\n }\n\n var currentReducer = reducer;\n var currentState = preloadedState;\n var currentListeners = [];\n var nextListeners = currentListeners;\n var isDispatching = false;\n\n function ensureCanMutateNextListeners() {\n if (nextListeners === currentListeners) {\n nextListeners = currentListeners.slice();\n }\n }\n /**\n * Reads the state tree managed by the store.\n *\n * @returns {any} The current state tree of your application.\n */\n\n\n function getState() {\n if (isDispatching) {\n throw new Error('You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.');\n }\n\n return currentState;\n }\n /**\n * Adds a change listener. It will be called any time an action is dispatched,\n * and some part of the state tree may potentially have changed. You may then\n * call `getState()` to read the current state tree inside the callback.\n *\n * You may call `dispatch()` from a change listener, with the following\n * caveats:\n *\n * 1. The subscriptions are snapshotted just before every `dispatch()` call.\n * If you subscribe or unsubscribe while the listeners are being invoked, this\n * will not have any effect on the `dispatch()` that is currently in progress.\n * However, the next `dispatch()` call, whether nested or not, will use a more\n * recent snapshot of the subscription list.\n *\n * 2. The listener should not expect to see all state changes, as the state\n * might have been updated multiple times during a nested `dispatch()` before\n * the listener is called. It is, however, guaranteed that all subscribers\n * registered before the `dispatch()` started will be called with the latest\n * state by the time it exits.\n *\n * @param {Function} listener A callback to be invoked on every dispatch.\n * @returns {Function} A function to remove this change listener.\n */\n\n\n function subscribe(listener) {\n if (typeof listener !== 'function') {\n throw new Error('Expected the listener to be a function.');\n }\n\n if (isDispatching) {\n throw new Error('You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.');\n }\n\n var isSubscribed = true;\n ensureCanMutateNextListeners();\n nextListeners.push(listener);\n return function unsubscribe() {\n if (!isSubscribed) {\n return;\n }\n\n if (isDispatching) {\n throw new Error('You may not unsubscribe from a store listener while the reducer is executing. ' + 'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.');\n }\n\n isSubscribed = false;\n ensureCanMutateNextListeners();\n var index = nextListeners.indexOf(listener);\n nextListeners.splice(index, 1);\n };\n }\n /**\n * Dispatches an action. It is the only way to trigger a state change.\n *\n * The `reducer` function, used to create the store, will be called with the\n * current state tree and the given `action`. Its return value will\n * be considered the **next** state of the tree, and the change listeners\n * will be notified.\n *\n * The base implementation only supports plain object actions. If you want to\n * dispatch a Promise, an Observable, a thunk, or something else, you need to\n * wrap your store creating function into the corresponding middleware. For\n * example, see the documentation for the `redux-thunk` package. Even the\n * middleware will eventually dispatch plain object actions using this method.\n *\n * @param {Object} action A plain object representing “what changed”. It is\n * a good idea to keep actions serializable so you can record and replay user\n * sessions, or use the time travelling `redux-devtools`. An action must have\n * a `type` property which may not be `undefined`. It is a good idea to use\n * string constants for action types.\n *\n * @returns {Object} For convenience, the same action object you dispatched.\n *\n * Note that, if you use a custom middleware, it may wrap `dispatch()` to\n * return something else (for example, a Promise you can await).\n */\n\n\n function dispatch(action) {\n if (!isPlainObject(action)) {\n throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');\n }\n\n if (typeof action.type === 'undefined') {\n throw new Error('Actions may not have an undefined \"type\" property. ' + 'Have you misspelled a constant?');\n }\n\n if (isDispatching) {\n throw new Error('Reducers may not dispatch actions.');\n }\n\n try {\n isDispatching = true;\n currentState = currentReducer(currentState, action);\n } finally {\n isDispatching = false;\n }\n\n var listeners = currentListeners = nextListeners;\n\n for (var i = 0; i < listeners.length; i++) {\n var listener = listeners[i];\n listener();\n }\n\n return action;\n }\n /**\n * Replaces the reducer currently used by the store to calculate the state.\n *\n * You might need this if your app implements code splitting and you want to\n * load some of the reducers dynamically. You might also need this if you\n * implement a hot reloading mechanism for Redux.\n *\n * @param {Function} nextReducer The reducer for the store to use instead.\n * @returns {void}\n */\n\n\n function replaceReducer(nextReducer) {\n if (typeof nextReducer !== 'function') {\n throw new Error('Expected the nextReducer to be a function.');\n }\n\n currentReducer = nextReducer;\n dispatch({\n type: ActionTypes.REPLACE\n });\n }\n /**\n * Interoperability point for observable/reactive libraries.\n * @returns {observable} A minimal observable of state changes.\n * For more information, see the observable proposal:\n * https://github.com/tc39/proposal-observable\n */\n\n\n function observable() {\n var _ref;\n\n var outerSubscribe = subscribe;\n return _ref = {\n /**\n * The minimal observable subscription method.\n * @param {Object} observer Any object that can be used as an observer.\n * The observer object should have a `next` method.\n * @returns {subscription} An object with an `unsubscribe` method that can\n * be used to unsubscribe the observable from the store, and prevent further\n * emission of values from the observable.\n */\n subscribe: function subscribe(observer) {\n if (typeof observer !== 'object' || observer === null) {\n throw new TypeError('Expected the observer to be an object.');\n }\n\n function observeState() {\n if (observer.next) {\n observer.next(getState());\n }\n }\n\n observeState();\n var unsubscribe = outerSubscribe(observeState);\n return {\n unsubscribe: unsubscribe\n };\n }\n }, _ref[$$observable] = function () {\n return this;\n }, _ref;\n } // When a store is created, an \"INIT\" action is dispatched so that every\n // reducer returns their initial state. This effectively populates\n // the initial state tree.\n\n\n dispatch({\n type: ActionTypes.INIT\n });\n return _ref2 = {\n dispatch: dispatch,\n subscribe: subscribe,\n getState: getState,\n replaceReducer: replaceReducer\n }, _ref2[$$observable] = observable, _ref2;\n}\n\n/**\n * Prints a warning in the console if it exists.\n *\n * @param {String} message The warning message.\n * @returns {void}\n */\nfunction warning(message) {\n /* eslint-disable no-console */\n if (typeof console !== 'undefined' && typeof console.error === 'function') {\n console.error(message);\n }\n /* eslint-enable no-console */\n\n\n try {\n // This error was thrown as a convenience so that if you enable\n // \"break on all exceptions\" in your console,\n // it would pause the execution at this line.\n throw new Error(message);\n } catch (e) {} // eslint-disable-line no-empty\n\n}\n\nfunction getUndefinedStateErrorMessage(key, action) {\n var actionType = action && action.type;\n var actionDescription = actionType && \"action \\\"\" + String(actionType) + \"\\\"\" || 'an action';\n return \"Given \" + actionDescription + \", reducer \\\"\" + key + \"\\\" returned undefined. \" + \"To ignore an action, you must explicitly return the previous state. \" + \"If you want this reducer to hold no value, you can return null instead of undefined.\";\n}\n\nfunction getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) {\n var reducerKeys = Object.keys(reducers);\n var argumentName = action && action.type === ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer';\n\n if (reducerKeys.length === 0) {\n return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';\n }\n\n if (!isPlainObject(inputState)) {\n return \"The \" + argumentName + \" has unexpected type of \\\"\" + {}.toString.call(inputState).match(/\\s([a-z|A-Z]+)/)[1] + \"\\\". Expected argument to be an object with the following \" + (\"keys: \\\"\" + reducerKeys.join('\", \"') + \"\\\"\");\n }\n\n var unexpectedKeys = Object.keys(inputState).filter(function (key) {\n return !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key];\n });\n unexpectedKeys.forEach(function (key) {\n unexpectedKeyCache[key] = true;\n });\n if (action && action.type === ActionTypes.REPLACE) return;\n\n if (unexpectedKeys.length > 0) {\n return \"Unexpected \" + (unexpectedKeys.length > 1 ? 'keys' : 'key') + \" \" + (\"\\\"\" + unexpectedKeys.join('\", \"') + \"\\\" found in \" + argumentName + \". \") + \"Expected to find one of the known reducer keys instead: \" + (\"\\\"\" + reducerKeys.join('\", \"') + \"\\\". Unexpected keys will be ignored.\");\n }\n}\n\nfunction assertReducerShape(reducers) {\n Object.keys(reducers).forEach(function (key) {\n var reducer = reducers[key];\n var initialState = reducer(undefined, {\n type: ActionTypes.INIT\n });\n\n if (typeof initialState === 'undefined') {\n throw new Error(\"Reducer \\\"\" + key + \"\\\" returned undefined during initialization. \" + \"If the state passed to the reducer is undefined, you must \" + \"explicitly return the initial state. The initial state may \" + \"not be undefined. If you don't want to set a value for this reducer, \" + \"you can use null instead of undefined.\");\n }\n\n if (typeof reducer(undefined, {\n type: ActionTypes.PROBE_UNKNOWN_ACTION()\n }) === 'undefined') {\n throw new Error(\"Reducer \\\"\" + key + \"\\\" returned undefined when probed with a random type. \" + (\"Don't try to handle \" + ActionTypes.INIT + \" or other actions in \\\"redux/*\\\" \") + \"namespace. They are considered private. Instead, you must return the \" + \"current state for any unknown actions, unless it is undefined, \" + \"in which case you must return the initial state, regardless of the \" + \"action type. The initial state may not be undefined, but can be null.\");\n }\n });\n}\n/**\n * Turns an object whose values are different reducer functions, into a single\n * reducer function. It will call every child reducer, and gather their results\n * into a single state object, whose keys correspond to the keys of the passed\n * reducer functions.\n *\n * @param {Object} reducers An object whose values correspond to different\n * reducer functions that need to be combined into one. One handy way to obtain\n * it is to use ES6 `import * as reducers` syntax. The reducers may never return\n * undefined for any action. Instead, they should return their initial state\n * if the state passed to them was undefined, and the current state for any\n * unrecognized action.\n *\n * @returns {Function} A reducer function that invokes every reducer inside the\n * passed object, and builds a state object with the same shape.\n */\n\n\nfunction combineReducers(reducers) {\n var reducerKeys = Object.keys(reducers);\n var finalReducers = {};\n\n for (var i = 0; i < reducerKeys.length; i++) {\n var key = reducerKeys[i];\n\n if (process.env.NODE_ENV !== 'production') {\n if (typeof reducers[key] === 'undefined') {\n warning(\"No reducer provided for key \\\"\" + key + \"\\\"\");\n }\n }\n\n if (typeof reducers[key] === 'function') {\n finalReducers[key] = reducers[key];\n }\n }\n\n var finalReducerKeys = Object.keys(finalReducers);\n var unexpectedKeyCache;\n\n if (process.env.NODE_ENV !== 'production') {\n unexpectedKeyCache = {};\n }\n\n var shapeAssertionError;\n\n try {\n assertReducerShape(finalReducers);\n } catch (e) {\n shapeAssertionError = e;\n }\n\n return function combination(state, action) {\n if (state === void 0) {\n state = {};\n }\n\n if (shapeAssertionError) {\n throw shapeAssertionError;\n }\n\n if (process.env.NODE_ENV !== 'production') {\n var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);\n\n if (warningMessage) {\n warning(warningMessage);\n }\n }\n\n var hasChanged = false;\n var nextState = {};\n\n for (var _i = 0; _i < finalReducerKeys.length; _i++) {\n var _key = finalReducerKeys[_i];\n var reducer = finalReducers[_key];\n var previousStateForKey = state[_key];\n var nextStateForKey = reducer(previousStateForKey, action);\n\n if (typeof nextStateForKey === 'undefined') {\n var errorMessage = getUndefinedStateErrorMessage(_key, action);\n throw new Error(errorMessage);\n }\n\n nextState[_key] = nextStateForKey;\n hasChanged = hasChanged || nextStateForKey !== previousStateForKey;\n }\n\n return hasChanged ? nextState : state;\n };\n}\n\nfunction bindActionCreator(actionCreator, dispatch) {\n return function () {\n return dispatch(actionCreator.apply(this, arguments));\n };\n}\n/**\n * Turns an object whose values are action creators, into an object with the\n * same keys, but with every function wrapped into a `dispatch` call so they\n * may be invoked directly. This is just a convenience method, as you can call\n * `store.dispatch(MyActionCreators.doSomething())` yourself just fine.\n *\n * For convenience, you can also pass a single function as the first argument,\n * and get a function in return.\n *\n * @param {Function|Object} actionCreators An object whose values are action\n * creator functions. One handy way to obtain it is to use ES6 `import * as`\n * syntax. You may also pass a single function.\n *\n * @param {Function} dispatch The `dispatch` function available on your Redux\n * store.\n *\n * @returns {Function|Object} The object mimicking the original object, but with\n * every action creator wrapped into the `dispatch` call. If you passed a\n * function as `actionCreators`, the return value will also be a single\n * function.\n */\n\n\nfunction bindActionCreators(actionCreators, dispatch) {\n if (typeof actionCreators === 'function') {\n return bindActionCreator(actionCreators, dispatch);\n }\n\n if (typeof actionCreators !== 'object' || actionCreators === null) {\n throw new Error(\"bindActionCreators expected an object or a function, instead received \" + (actionCreators === null ? 'null' : typeof actionCreators) + \". \" + \"Did you write \\\"import ActionCreators from\\\" instead of \\\"import * as ActionCreators from\\\"?\");\n }\n\n var keys = Object.keys(actionCreators);\n var boundActionCreators = {};\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n var actionCreator = actionCreators[key];\n\n if (typeof actionCreator === 'function') {\n boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);\n }\n }\n\n return boundActionCreators;\n}\n\nfunction _defineProperty(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n}\n\nfunction _objectSpread(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i] != null ? arguments[i] : {};\n var ownKeys = Object.keys(source);\n\n if (typeof Object.getOwnPropertySymbols === 'function') {\n ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {\n return Object.getOwnPropertyDescriptor(source, sym).enumerable;\n }));\n }\n\n ownKeys.forEach(function (key) {\n _defineProperty(target, key, source[key]);\n });\n }\n\n return target;\n}\n\n/**\n * Composes single-argument functions from right to left. The rightmost\n * function can take multiple arguments as it provides the signature for\n * the resulting composite function.\n *\n * @param {...Function} funcs The functions to compose.\n * @returns {Function} A function obtained by composing the argument functions\n * from right to left. For example, compose(f, g, h) is identical to doing\n * (...args) => f(g(h(...args))).\n */\nfunction compose() {\n for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) {\n funcs[_key] = arguments[_key];\n }\n\n if (funcs.length === 0) {\n return function (arg) {\n return arg;\n };\n }\n\n if (funcs.length === 1) {\n return funcs[0];\n }\n\n return funcs.reduce(function (a, b) {\n return function () {\n return a(b.apply(void 0, arguments));\n };\n });\n}\n\n/**\n * Creates a store enhancer that applies middleware to the dispatch method\n * of the Redux store. This is handy for a variety of tasks, such as expressing\n * asynchronous actions in a concise manner, or logging every action payload.\n *\n * See `redux-thunk` package as an example of the Redux middleware.\n *\n * Because middleware is potentially asynchronous, this should be the first\n * store enhancer in the composition chain.\n *\n * Note that each middleware will be given the `dispatch` and `getState` functions\n * as named arguments.\n *\n * @param {...Function} middlewares The middleware chain to be applied.\n * @returns {Function} A store enhancer applying the middleware.\n */\n\nfunction applyMiddleware() {\n for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) {\n middlewares[_key] = arguments[_key];\n }\n\n return function (createStore) {\n return function () {\n var store = createStore.apply(void 0, arguments);\n\n var _dispatch = function dispatch() {\n throw new Error(\"Dispatching while constructing your middleware is not allowed. \" + \"Other middleware would not be applied to this dispatch.\");\n };\n\n var middlewareAPI = {\n getState: store.getState,\n dispatch: function dispatch() {\n return _dispatch.apply(void 0, arguments);\n }\n };\n var chain = middlewares.map(function (middleware) {\n return middleware(middlewareAPI);\n });\n _dispatch = compose.apply(void 0, chain)(store.dispatch);\n return _objectSpread({}, store, {\n dispatch: _dispatch\n });\n };\n };\n}\n\n/*\n * This is a dummy function to check if the function name has been altered by minification.\n * If the function has been minified and NODE_ENV !== 'production', warn the user.\n */\n\nfunction isCrushed() {}\n\nif (process.env.NODE_ENV !== 'production' && typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed') {\n warning('You are currently using minified code outside of NODE_ENV === \"production\". ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or setting mode to production in webpack (https://webpack.js.org/concepts/mode/) ' + 'to ensure you have the correct code for your production build.');\n}\n\nexport { createStore, combineReducers, bindActionCreators, applyMiddleware, compose, ActionTypes as __DO_NOT_USE__ActionTypes };\n", "export const NOTHING =\n\ttypeof Symbol !== \"undefined\"\n\t\t? Symbol(\"immer-nothing\")\n\t\t: {[\"immer-nothing\"]: true}\n\nexport const DRAFTABLE =\n\ttypeof Symbol !== \"undefined\" && Symbol.for\n\t\t? Symbol.for(\"immer-draftable\")\n\t\t: \"__$immer_draftable\"\n\nexport const DRAFT_STATE =\n\ttypeof Symbol !== \"undefined\" && Symbol.for\n\t\t? Symbol.for(\"immer-state\")\n\t\t: \"__$immer_state\"\n\nexport function isDraft(value) {\n\treturn !!value && !!value[DRAFT_STATE]\n}\n\nexport function isDraftable(value) {\n\tif (!value) return false\n\treturn (\n\t\tisPlainObject(value) || !!value[DRAFTABLE] || !!value.constructor[DRAFTABLE]\n\t)\n}\n\nexport function isPlainObject(value) {\n\tif (!value || typeof value !== \"object\") return false\n\tif (Array.isArray(value)) return true\n\tconst proto = Object.getPrototypeOf(value)\n\treturn !proto || proto === Object.prototype\n}\n\nexport function original(value) {\n\tif (value && value[DRAFT_STATE]) {\n\t\treturn value[DRAFT_STATE].base\n\t}\n\t// otherwise return undefined\n}\n\nexport const assign =\n\tObject.assign ||\n\tfunction assign(target, value) {\n\t\tfor (let key in value) {\n\t\t\tif (has(value, key)) {\n\t\t\t\ttarget[key] = value[key]\n\t\t\t}\n\t\t}\n\t\treturn target\n\t}\n\nexport const ownKeys =\n\ttypeof Reflect !== \"undefined\" && Reflect.ownKeys\n\t\t? Reflect.ownKeys\n\t\t: typeof Object.getOwnPropertySymbols !== \"undefined\"\n\t\t? obj =>\n\t\t\t\tObject.getOwnPropertyNames(obj).concat(\n\t\t\t\t\tObject.getOwnPropertySymbols(obj)\n\t\t\t\t)\n\t\t: Object.getOwnPropertyNames\n\nexport function shallowCopy(base, invokeGetters = false) {\n\tif (Array.isArray(base)) return base.slice()\n\tconst clone = Object.create(Object.getPrototypeOf(base))\n\townKeys(base).forEach(key => {\n\t\tif (key === DRAFT_STATE) {\n\t\t\treturn // Never copy over draft state.\n\t\t}\n\t\tconst desc = Object.getOwnPropertyDescriptor(base, key)\n\t\tlet {value} = desc\n\t\tif (desc.get) {\n\t\t\tif (!invokeGetters) {\n\t\t\t\tthrow new Error(\"Immer drafts cannot have computed properties\")\n\t\t\t}\n\t\t\tvalue = desc.get.call(base)\n\t\t}\n\t\tif (desc.enumerable) {\n\t\t\tclone[key] = value\n\t\t} else {\n\t\t\tObject.defineProperty(clone, key, {\n\t\t\t\tvalue,\n\t\t\t\twritable: true,\n\t\t\t\tconfigurable: true\n\t\t\t})\n\t\t}\n\t})\n\treturn clone\n}\n\nexport function each(value, cb) {\n\tif (Array.isArray(value)) {\n\t\tfor (let i = 0; i < value.length; i++) cb(i, value[i], value)\n\t} else {\n\t\townKeys(value).forEach(key => cb(key, value[key], value))\n\t}\n}\n\nexport function isEnumerable(base, prop) {\n\tconst desc = Object.getOwnPropertyDescriptor(base, prop)\n\treturn !!desc && desc.enumerable\n}\n\nexport function has(thing, prop) {\n\treturn Object.prototype.hasOwnProperty.call(thing, prop)\n}\n\nexport function is(x, y) {\n\t// From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js\n\tif (x === y) {\n\t\treturn x !== 0 || 1 / x === 1 / y\n\t} else {\n\t\treturn x !== x && y !== y\n\t}\n}\n\nexport function clone(obj) {\n\tif (!isDraftable(obj)) return obj\n\tif (Array.isArray(obj)) return obj.map(clone)\n\tconst cloned = Object.create(Object.getPrototypeOf(obj))\n\tfor (const key in obj) cloned[key] = clone(obj[key])\n\treturn cloned\n}\n\nexport function deepFreeze(obj) {\n\tif (!isDraftable(obj) || isDraft(obj) || Object.isFrozen(obj)) return\n\tObject.freeze(obj)\n\tif (Array.isArray(obj)) obj.forEach(deepFreeze)\n\telse for (const key in obj) deepFreeze(obj[key])\n}\n", "import {DRAFT_STATE} from \"./common\"\n\n/** Each scope represents a `produce` call. */\nexport class ImmerScope {\n\tconstructor(parent) {\n\t\tthis.drafts = []\n\t\tthis.parent = parent\n\n\t\t// Whenever the modified draft contains a draft from another scope, we\n\t\t// need to prevent auto-freezing so the unowned draft can be finalized.\n\t\tthis.canAutoFreeze = true\n\n\t\t// To avoid prototype lookups:\n\t\tthis.patches = null\n\t}\n\tusePatches(patchListener) {\n\t\tif (patchListener) {\n\t\t\tthis.patches = []\n\t\t\tthis.inversePatches = []\n\t\t\tthis.patchListener = patchListener\n\t\t}\n\t}\n\trevoke() {\n\t\tthis.leave()\n\t\tthis.drafts.forEach(revoke)\n\t\tthis.drafts = null // Make draft-related methods throw.\n\t}\n\tleave() {\n\t\tif (this === ImmerScope.current) {\n\t\t\tImmerScope.current = this.parent\n\t\t}\n\t}\n}\n\nImmerScope.current = null\nImmerScope.enter = function() {\n\treturn (this.current = new ImmerScope(this.current))\n}\n\nfunction revoke(draft) {\n\tdraft[DRAFT_STATE].revoke()\n}\n", "\"use strict\"\nimport {\n\teach,\n\thas,\n\tis,\n\tisDraft,\n\tisDraftable,\n\tisEnumerable,\n\tshallowCopy,\n\tDRAFT_STATE\n} from \"./common\"\nimport {ImmerScope} from \"./scope\"\n\n// property descriptors are recycled to make sure we don't create a get and set closure per property,\n// but share them all instead\nconst descriptors = {}\n\nexport function willFinalize(scope, result, isReplaced) {\n\tscope.drafts.forEach(draft => {\n\t\tdraft[DRAFT_STATE].finalizing = true\n\t})\n\tif (!isReplaced) {\n\t\tif (scope.patches) {\n\t\t\tmarkChangesRecursively(scope.drafts[0])\n\t\t}\n\t\t// This is faster when we don't care about which attributes changed.\n\t\tmarkChangesSweep(scope.drafts)\n\t}\n\t// When a child draft is returned, look for changes.\n\telse if (isDraft(result) && result[DRAFT_STATE].scope === scope) {\n\t\tmarkChangesSweep(scope.drafts)\n\t}\n}\n\nexport function createProxy(base, parent) {\n\tconst isArray = Array.isArray(base)\n\tconst draft = clonePotentialDraft(base)\n\teach(draft, prop => {\n\t\tproxyProperty(draft, prop, isArray || isEnumerable(base, prop))\n\t})\n\n\t// See \"proxy.js\" for property documentation.\n\tconst scope = parent ? parent.scope : ImmerScope.current\n\tconst state = {\n\t\tscope,\n\t\tmodified: false,\n\t\tfinalizing: false, // es5 only\n\t\tfinalized: false,\n\t\tassigned: {},\n\t\tparent,\n\t\tbase,\n\t\tdraft,\n\t\tcopy: null,\n\t\trevoke,\n\t\trevoked: false // es5 only\n\t}\n\n\tcreateHiddenProperty(draft, DRAFT_STATE, state)\n\tscope.drafts.push(draft)\n\treturn draft\n}\n\nfunction revoke() {\n\tthis.revoked = true\n}\n\nfunction source(state) {\n\treturn state.copy || state.base\n}\n\n// Access a property without creating an Immer draft.\nfunction peek(draft, prop) {\n\tconst state = draft[DRAFT_STATE]\n\tif (state && !state.finalizing) {\n\t\tstate.finalizing = true\n\t\tconst value = draft[prop]\n\t\tstate.finalizing = false\n\t\treturn value\n\t}\n\treturn draft[prop]\n}\n\nfunction get(state, prop) {\n\tassertUnrevoked(state)\n\tconst value = peek(source(state), prop)\n\tif (state.finalizing) return value\n\t// Create a draft if the value is unmodified.\n\tif (value === peek(state.base, prop) && isDraftable(value)) {\n\t\tprepareCopy(state)\n\t\treturn (state.copy[prop] = createProxy(value, state))\n\t}\n\treturn value\n}\n\nfunction set(state, prop, value) {\n\tassertUnrevoked(state)\n\tstate.assigned[prop] = true\n\tif (!state.modified) {\n\t\tif (is(value, peek(source(state), prop))) return\n\t\tmarkChanged(state)\n\t\tprepareCopy(state)\n\t}\n\tstate.copy[prop] = value\n}\n\nfunction markChanged(state) {\n\tif (!state.modified) {\n\t\tstate.modified = true\n\t\tif (state.parent) markChanged(state.parent)\n\t}\n}\n\nfunction prepareCopy(state) {\n\tif (!state.copy) state.copy = clonePotentialDraft(state.base)\n}\n\nfunction clonePotentialDraft(base) {\n\tconst state = base && base[DRAFT_STATE]\n\tif (state) {\n\t\tstate.finalizing = true\n\t\tconst draft = shallowCopy(state.draft, true)\n\t\tstate.finalizing = false\n\t\treturn draft\n\t}\n\treturn shallowCopy(base)\n}\n\nfunction proxyProperty(draft, prop, enumerable) {\n\tlet desc = descriptors[prop]\n\tif (desc) {\n\t\tdesc.enumerable = enumerable\n\t} else {\n\t\tdescriptors[prop] = desc = {\n\t\t\tconfigurable: true,\n\t\t\tenumerable,\n\t\t\tget() {\n\t\t\t\treturn get(this[DRAFT_STATE], prop)\n\t\t\t},\n\t\t\tset(value) {\n\t\t\t\tset(this[DRAFT_STATE], prop, value)\n\t\t\t}\n\t\t}\n\t}\n\tObject.defineProperty(draft, prop, desc)\n}\n\nfunction assertUnrevoked(state) {\n\tif (state.revoked === true)\n\t\tthrow new Error(\n\t\t\t\"Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? \" +\n\t\t\t\tJSON.stringify(source(state))\n\t\t)\n}\n\n// This looks expensive, but only proxies are visited, and only objects without known changes are scanned.\nfunction markChangesSweep(drafts) {\n\t// The natural order of drafts in the `scope` array is based on when they\n\t// were accessed. By processing drafts in reverse natural order, we have a\n\t// better chance of processing leaf nodes first. When a leaf node is known to\n\t// have changed, we can avoid any traversal of its ancestor nodes.\n\tfor (let i = drafts.length - 1; i >= 0; i--) {\n\t\tconst state = drafts[i][DRAFT_STATE]\n\t\tif (!state.modified) {\n\t\t\tif (Array.isArray(state.base)) {\n\t\t\t\tif (hasArrayChanges(state)) markChanged(state)\n\t\t\t} else if (hasObjectChanges(state)) markChanged(state)\n\t\t}\n\t}\n}\n\nfunction markChangesRecursively(object) {\n\tif (!object || typeof object !== \"object\") return\n\tconst state = object[DRAFT_STATE]\n\tif (!state) return\n\tconst {base, draft, assigned} = state\n\tif (!Array.isArray(object)) {\n\t\t// Look for added keys.\n\t\tObject.keys(draft).forEach(key => {\n\t\t\t// The `undefined` check is a fast path for pre-existing keys.\n\t\t\tif (base[key] === undefined && !has(base, key)) {\n\t\t\t\tassigned[key] = true\n\t\t\t\tmarkChanged(state)\n\t\t\t} else if (!assigned[key]) {\n\t\t\t\t// Only untouched properties trigger recursion.\n\t\t\t\tmarkChangesRecursively(draft[key])\n\t\t\t}\n\t\t})\n\t\t// Look for removed keys.\n\t\tObject.keys(base).forEach(key => {\n\t\t\t// The `undefined` check is a fast path for pre-existing keys.\n\t\t\tif (draft[key] === undefined && !has(draft, key)) {\n\t\t\t\tassigned[key] = false\n\t\t\t\tmarkChanged(state)\n\t\t\t}\n\t\t})\n\t} else if (hasArrayChanges(state)) {\n\t\tmarkChanged(state)\n\t\tassigned.length = true\n\t\tif (draft.length < base.length) {\n\t\t\tfor (let i = draft.length; i < base.length; i++) assigned[i] = false\n\t\t} else {\n\t\t\tfor (let i = base.length; i < draft.length; i++) assigned[i] = true\n\t\t}\n\t\tfor (let i = 0; i < draft.length; i++) {\n\t\t\t// Only untouched indices trigger recursion.\n\t\t\tif (assigned[i] === undefined) markChangesRecursively(draft[i])\n\t\t}\n\t}\n}\n\nfunction hasObjectChanges(state) {\n\tconst {base, draft} = state\n\n\t// Search for added keys and changed keys. Start at the back, because\n\t// non-numeric keys are ordered by time of definition on the object.\n\tconst keys = Object.keys(draft)\n\tfor (let i = keys.length - 1; i >= 0; i--) {\n\t\tconst key = keys[i]\n\t\tconst baseValue = base[key]\n\t\t// The `undefined` check is a fast path for pre-existing keys.\n\t\tif (baseValue === undefined && !has(base, key)) {\n\t\t\treturn true\n\t\t}\n\t\t// Once a base key is deleted, future changes go undetected, because its\n\t\t// descriptor is erased. This branch detects any missed changes.\n\t\telse {\n\t\t\tconst value = draft[key]\n\t\t\tconst state = value && value[DRAFT_STATE]\n\t\t\tif (state ? state.base !== baseValue : !is(value, baseValue)) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\t// At this point, no keys were added or changed.\n\t// Compare key count to determine if keys were deleted.\n\treturn keys.length !== Object.keys(base).length\n}\n\nfunction hasArrayChanges(state) {\n\tconst {draft} = state\n\tif (draft.length !== state.base.length) return true\n\t// See #116\n\t// If we first shorten the length, our array interceptors will be removed.\n\t// If after that new items are added, result in the same original length,\n\t// those last items will have no intercepting property.\n\t// So if there is no own descriptor on the last position, we know that items were removed and added\n\t// N.B.: splice, unshift, etc only shift values around, but not prop descriptors, so we only have to check\n\t// the last one\n\tconst descriptor = Object.getOwnPropertyDescriptor(draft, draft.length - 1)\n\t// descriptor can be null, but only for newly created sparse arrays, eg. new Array(10)\n\tif (descriptor && !descriptor.get) return true\n\t// For all other cases, we don't have to compare, as they would have been picked up by the index setters\n\treturn false\n}\n\nfunction createHiddenProperty(target, prop, value) {\n\tObject.defineProperty(target, prop, {\n\t\tvalue: value,\n\t\tenumerable: false,\n\t\twritable: true\n\t})\n}\n", "\"use strict\"\nimport {\n\tassign,\n\teach,\n\thas,\n\tis,\n\tisDraftable,\n\tisDraft,\n\tshallowCopy,\n\tDRAFT_STATE\n} from \"./common\"\nimport {ImmerScope} from \"./scope\"\n\n// Do nothing before being finalized.\nexport function willFinalize() {}\n\nexport function createProxy(base, parent) {\n\tconst scope = parent ? parent.scope : ImmerScope.current\n\tconst state = {\n\t\t// Track which produce call this is associated with.\n\t\tscope,\n\t\t// True for both shallow and deep changes.\n\t\tmodified: false,\n\t\t// Used during finalization.\n\t\tfinalized: false,\n\t\t// Track which properties have been assigned (true) or deleted (false).\n\t\tassigned: {},\n\t\t// The parent draft state.\n\t\tparent,\n\t\t// The base state.\n\t\tbase,\n\t\t// The base proxy.\n\t\tdraft: null,\n\t\t// Any property proxies.\n\t\tdrafts: {},\n\t\t// The base copy with any updated values.\n\t\tcopy: null,\n\t\t// Called by the `produce` function.\n\t\trevoke: null\n\t}\n\n\tconst {revoke, proxy} = Array.isArray(base)\n\t\t? // [state] is used for arrays, to make sure the proxy is array-ish and not violate invariants,\n\t\t // although state itself is an object\n\t\t Proxy.revocable([state], arrayTraps)\n\t\t: Proxy.revocable(state, objectTraps)\n\n\tstate.draft = proxy\n\tstate.revoke = revoke\n\n\tscope.drafts.push(proxy)\n\treturn proxy\n}\n\nconst objectTraps = {\n\tget,\n\thas(target, prop) {\n\t\treturn prop in source(target)\n\t},\n\townKeys(target) {\n\t\treturn Reflect.ownKeys(source(target))\n\t},\n\tset,\n\tdeleteProperty,\n\tgetOwnPropertyDescriptor,\n\tdefineProperty() {\n\t\tthrow new Error(\"Object.defineProperty() cannot be used on an Immer draft\") // prettier-ignore\n\t},\n\tgetPrototypeOf(target) {\n\t\treturn Object.getPrototypeOf(target.base)\n\t},\n\tsetPrototypeOf() {\n\t\tthrow new Error(\"Object.setPrototypeOf() cannot be used on an Immer draft\") // prettier-ignore\n\t}\n}\n\nconst arrayTraps = {}\neach(objectTraps, (key, fn) => {\n\tarrayTraps[key] = function() {\n\t\targuments[0] = arguments[0][0]\n\t\treturn fn.apply(this, arguments)\n\t}\n})\narrayTraps.deleteProperty = function(state, prop) {\n\tif (isNaN(parseInt(prop))) {\n\t\tthrow new Error(\"Immer only supports deleting array indices\") // prettier-ignore\n\t}\n\treturn objectTraps.deleteProperty.call(this, state[0], prop)\n}\narrayTraps.set = function(state, prop, value) {\n\tif (prop !== \"length\" && isNaN(parseInt(prop))) {\n\t\tthrow new Error(\"Immer only supports setting array indices and the 'length' property\") // prettier-ignore\n\t}\n\treturn objectTraps.set.call(this, state[0], prop, value)\n}\n\n// returns the object we should be reading the current value from, which is base, until some change has been made\nfunction source(state) {\n\treturn state.copy || state.base\n}\n\n// Access a property without creating an Immer draft.\nfunction peek(draft, prop) {\n\tconst state = draft[DRAFT_STATE]\n\tconst desc = Reflect.getOwnPropertyDescriptor(\n\t\tstate ? source(state) : draft,\n\t\tprop\n\t)\n\treturn desc && desc.value\n}\n\nfunction get(state, prop) {\n\tif (prop === DRAFT_STATE) return state\n\tlet {drafts} = state\n\n\t// Check for existing draft in unmodified state.\n\tif (!state.modified && has(drafts, prop)) {\n\t\treturn drafts[prop]\n\t}\n\n\tconst value = source(state)[prop]\n\tif (state.finalized || !isDraftable(value)) {\n\t\treturn value\n\t}\n\n\t// Check for existing draft in modified state.\n\tif (state.modified) {\n\t\t// Assigned values are never drafted. This catches any drafts we created, too.\n\t\tif (value !== peek(state.base, prop)) return value\n\t\t// Store drafts on the copy (when one exists).\n\t\tdrafts = state.copy\n\t}\n\n\treturn (drafts[prop] = createProxy(value, state))\n}\n\nfunction set(state, prop, value) {\n\tif (!state.modified) {\n\t\tconst baseValue = peek(state.base, prop)\n\t\t// Optimize based on value's truthiness. Truthy values are guaranteed to\n\t\t// never be undefined, so we can avoid the `in` operator. Lastly, truthy\n\t\t// values may be drafts, but falsy values are never drafts.\n\t\tconst isUnchanged = value\n\t\t\t? is(baseValue, value) || value === state.drafts[prop]\n\t\t\t: is(baseValue, value) && prop in state.base\n\t\tif (isUnchanged) return true\n\t\tmarkChanged(state)\n\t}\n\tstate.assigned[prop] = true\n\tstate.copy[prop] = value\n\treturn true\n}\n\nfunction deleteProperty(state, prop) {\n\t// The `undefined` check is a fast path for pre-existing keys.\n\tif (peek(state.base, prop) !== undefined || prop in state.base) {\n\t\tstate.assigned[prop] = false\n\t\tmarkChanged(state)\n\t} else if (state.assigned[prop]) {\n\t\t// if an originally not assigned property was deleted\n\t\tdelete state.assigned[prop]\n\t}\n\tif (state.copy) delete state.copy[prop]\n\treturn true\n}\n\n// Note: We never coerce `desc.value` into an Immer draft, because we can't make\n// the same guarantee in ES5 mode.\nfunction getOwnPropertyDescriptor(state, prop) {\n\tconst owner = source(state)\n\tconst desc = Reflect.getOwnPropertyDescriptor(owner, prop)\n\tif (desc) {\n\t\tdesc.writable = true\n\t\tdesc.configurable = !Array.isArray(owner) || prop !== \"length\"\n\t}\n\treturn desc\n}\n\nfunction markChanged(state) {\n\tif (!state.modified) {\n\t\tstate.modified = true\n\t\tstate.copy = assign(shallowCopy(state.base), state.drafts)\n\t\tstate.drafts = null\n\t\tif (state.parent) markChanged(state.parent)\n\t}\n}\n", "import {each, clone} from \"./common\"\nimport {createDraft} from \"./immer\"\n\nexport function generatePatches(state, basePath, patches, inversePatches) {\n\tArray.isArray(state.base)\n\t\t? generateArrayPatches(state, basePath, patches, inversePatches)\n\t\t: generateObjectPatches(state, basePath, patches, inversePatches)\n}\n\nfunction generateArrayPatches(state, basePath, patches, inversePatches) {\n\tlet {base, copy, assigned} = state\n\n\t// Reduce complexity by ensuring `base` is never longer.\n\tif (copy.length < base.length) {\n\t\t;[base, copy] = [copy, base]\n\t\t;[patches, inversePatches] = [inversePatches, patches]\n\t}\n\n\tconst delta = copy.length - base.length\n\n\t// Find the first replaced index.\n\tlet start = 0\n\twhile (base[start] === copy[start] && start < base.length) {\n\t\t++start\n\t}\n\n\t// Find the last replaced index. Search from the end to optimize splice patches.\n\tlet end = base.length\n\twhile (end > start && base[end - 1] === copy[end + delta - 1]) {\n\t\t--end\n\t}\n\n\t// Process replaced indices.\n\tfor (let i = start; i < end; ++i) {\n\t\tif (assigned[i] && copy[i] !== base[i]) {\n\t\t\tconst path = basePath.concat([i])\n\t\t\tpatches.push({\n\t\t\t\top: \"replace\",\n\t\t\t\tpath,\n\t\t\t\tvalue: copy[i]\n\t\t\t})\n\t\t\tinversePatches.push({\n\t\t\t\top: \"replace\",\n\t\t\t\tpath,\n\t\t\t\tvalue: base[i]\n\t\t\t})\n\t\t}\n\t}\n\n\tconst replaceCount = patches.length\n\n\t// Process added indices.\n\tfor (let i = end + delta - 1; i >= end; --i) {\n\t\tconst path = basePath.concat([i])\n\t\tpatches[replaceCount + i - end] = {\n\t\t\top: \"add\",\n\t\t\tpath,\n\t\t\tvalue: copy[i]\n\t\t}\n\t\tinversePatches.push({\n\t\t\top: \"remove\",\n\t\t\tpath\n\t\t})\n\t}\n}\n\nfunction generateObjectPatches(state, basePath, patches, inversePatches) {\n\tconst {base, copy} = state\n\teach(state.assigned, (key, assignedValue) => {\n\t\tconst origValue = base[key]\n\t\tconst value = copy[key]\n\t\tconst op = !assignedValue ? \"remove\" : key in base ? \"replace\" : \"add\"\n\t\tif (origValue === value && op === \"replace\") return\n\t\tconst path = basePath.concat(key)\n\t\tpatches.push(op === \"remove\" ? {op, path} : {op, path, value})\n\t\tinversePatches.push(\n\t\t\top === \"add\"\n\t\t\t\t? {op: \"remove\", path}\n\t\t\t\t: op === \"remove\"\n\t\t\t\t? {op: \"add\", path, value: origValue}\n\t\t\t\t: {op: \"replace\", path, value: origValue}\n\t\t)\n\t})\n}\n\nexport const applyPatches = (draft, patches) => {\n\tfor (const patch of patches) {\n\t\tconst {path, op} = patch\n\t\tconst value = clone(patch.value) // used to clone patch to ensure original patch is not modified, see #411\n\n\t\tif (!path.length) throw new Error(\"Illegal state\")\n\n\t\tlet base = draft\n\t\tfor (let i = 0; i < path.length - 1; i++) {\n\t\t\tbase = base[path[i]]\n\t\t\tif (!base || typeof base !== \"object\")\n\t\t\t\tthrow new Error(\"Cannot apply patch, path doesn't resolve: \" + path.join(\"/\")) // prettier-ignore\n\t\t}\n\n\t\tconst key = path[path.length - 1]\n\t\tswitch (op) {\n\t\t\tcase \"replace\":\n\t\t\t\t// if value is an object, then it's assigned by reference\n\t\t\t\t// in the following add or remove ops, the value field inside the patch will also be modifyed\n\t\t\t\t// so we use value from the cloned patch\n\t\t\t\tbase[key] = value\n\t\t\t\tbreak\n\t\t\tcase \"add\":\n\t\t\t\tif (Array.isArray(base)) {\n\t\t\t\t\t// TODO: support \"foo/-\" paths for appending to an array\n\t\t\t\t\tbase.splice(key, 0, value)\n\t\t\t\t} else {\n\t\t\t\t\tbase[key] = value\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase \"remove\":\n\t\t\t\tif (Array.isArray(base)) {\n\t\t\t\t\tbase.splice(key, 1)\n\t\t\t\t} else {\n\t\t\t\t\tdelete base[key]\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\tthrow new Error(\"Unsupported patch operation: \" + op)\n\t\t}\n\t}\n\n\treturn draft\n}\n", "import * as legacyProxy from \"./es5\"\nimport * as modernProxy from \"./proxy\"\nimport {applyPatches, generatePatches} from \"./patches\"\nimport {\n\tassign,\n\teach,\n\thas,\n\tis,\n\tisDraft,\n\tisDraftable,\n\tisEnumerable,\n\tshallowCopy,\n\tDRAFT_STATE,\n\tNOTHING,\n\tdeepFreeze\n} from \"./common\"\nimport {ImmerScope} from \"./scope\"\n\nfunction verifyMinified() {}\n\nconst configDefaults = {\n\tuseProxies:\n\t\ttypeof Proxy !== \"undefined\" &&\n\t\ttypeof Proxy.revocable !== \"undefined\" &&\n\t\ttypeof Reflect !== \"undefined\",\n\tautoFreeze:\n\t\ttypeof process !== \"undefined\"\n\t\t\t? process.env.NODE_ENV !== \"production\"\n\t\t\t: verifyMinified.name === \"verifyMinified\",\n\tonAssign: null,\n\tonDelete: null,\n\tonCopy: null\n}\n\nexport class Immer {\n\tconstructor(config) {\n\t\tassign(this, configDefaults, config)\n\t\tthis.setUseProxies(this.useProxies)\n\t\tthis.produce = this.produce.bind(this)\n\t}\n\tproduce(base, recipe, patchListener) {\n\t\t// curried invocation\n\t\tif (typeof base === \"function\" && typeof recipe !== \"function\") {\n\t\t\tconst defaultBase = recipe\n\t\t\trecipe = base\n\n\t\t\tconst self = this\n\t\t\treturn function curriedProduce(base = defaultBase, ...args) {\n\t\t\t\treturn self.produce(base, draft => recipe.call(this, draft, ...args)) // prettier-ignore\n\t\t\t}\n\t\t}\n\n\t\t// prettier-ignore\n\t\t{\n\t\t\tif (typeof recipe !== \"function\") {\n\t\t\t\tthrow new Error(\"The first or second argument to `produce` must be a function\")\n\t\t\t}\n\t\t\tif (patchListener !== undefined && typeof patchListener !== \"function\") {\n\t\t\t\tthrow new Error(\"The third argument to `produce` must be a function or undefined\")\n\t\t\t}\n\t\t}\n\n\t\tlet result\n\n\t\t// Only plain objects, arrays, and \"immerable classes\" are drafted.\n\t\tif (isDraftable(base)) {\n\t\t\tconst scope = ImmerScope.enter()\n\t\t\tconst proxy = this.createProxy(base)\n\t\t\tlet hasError = true\n\t\t\ttry {\n\t\t\t\tresult = recipe(proxy)\n\t\t\t\thasError = false\n\t\t\t} finally {\n\t\t\t\t// finally instead of catch + rethrow better preserves original stack\n\t\t\t\tif (hasError) scope.revoke()\n\t\t\t\telse scope.leave()\n\t\t\t}\n\t\t\tif (result instanceof Promise) {\n\t\t\t\treturn result.then(\n\t\t\t\t\tresult => {\n\t\t\t\t\t\tscope.usePatches(patchListener)\n\t\t\t\t\t\treturn this.processResult(result, scope)\n\t\t\t\t\t},\n\t\t\t\t\terror => {\n\t\t\t\t\t\tscope.revoke()\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t}\n\t\t\tscope.usePatches(patchListener)\n\t\t\treturn this.processResult(result, scope)\n\t\t} else {\n\t\t\tresult = recipe(base)\n\t\t\tif (result === NOTHING) return undefined\n\t\t\tif (result === undefined) result = base\n\t\t\tthis.maybeFreeze(result, true)\n\t\t\treturn result\n\t\t}\n\t}\n\tproduceWithPatches(arg1, arg2, arg3) {\n\t\tif (typeof arg1 === \"function\") {\n\t\t\tconst self = this\n\t\t\treturn (state, ...args) =>\n\t\t\t\tthis.produceWithPatches(state, draft => arg1(draft, ...args))\n\t\t}\n\t\t// non-curried form\n\t\tif (arg3)\n\t\t\tthrow new Error(\"A patch listener cannot be passed to produceWithPatches\")\n\t\tlet patches, inversePatches\n\t\tconst nextState = this.produce(arg1, arg2, (p, ip) => {\n\t\t\tpatches = p\n\t\t\tinversePatches = ip\n\t\t})\n\t\treturn [nextState, patches, inversePatches]\n\t}\n\tcreateDraft(base) {\n\t\tif (!isDraftable(base)) {\n\t\t\tthrow new Error(\"First argument to `createDraft` must be a plain object, an array, or an immerable object\") // prettier-ignore\n\t\t}\n\t\tconst scope = ImmerScope.enter()\n\t\tconst proxy = this.createProxy(base)\n\t\tproxy[DRAFT_STATE].isManual = true\n\t\tscope.leave()\n\t\treturn proxy\n\t}\n\tfinishDraft(draft, patchListener) {\n\t\tconst state = draft && draft[DRAFT_STATE]\n\t\tif (!state || !state.isManual) {\n\t\t\tthrow new Error(\"First argument to `finishDraft` must be a draft returned by `createDraft`\") // prettier-ignore\n\t\t}\n\t\tif (state.finalized) {\n\t\t\tthrow new Error(\"The given draft is already finalized\") // prettier-ignore\n\t\t}\n\t\tconst {scope} = state\n\t\tscope.usePatches(patchListener)\n\t\treturn this.processResult(undefined, scope)\n\t}\n\tsetAutoFreeze(value) {\n\t\tthis.autoFreeze = value\n\t}\n\tsetUseProxies(value) {\n\t\tthis.useProxies = value\n\t\tassign(this, value ? modernProxy : legacyProxy)\n\t}\n\tapplyPatches(base, patches) {\n\t\t// If a patch replaces the entire state, take that replacement as base\n\t\t// before applying patches\n\t\tlet i\n\t\tfor (i = patches.length - 1; i >= 0; i--) {\n\t\t\tconst patch = patches[i]\n\t\t\tif (patch.path.length === 0 && patch.op === \"replace\") {\n\t\t\t\tbase = patch.value\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (isDraft(base)) {\n\t\t\t// N.B: never hits if some patch a replacement, patches are never drafts\n\t\t\treturn applyPatches(base, patches)\n\t\t}\n\t\t// Otherwise, produce a copy of the base state.\n\t\treturn this.produce(base, draft =>\n\t\t\tapplyPatches(draft, patches.slice(i + 1))\n\t\t)\n\t}\n\t/** @internal */\n\tprocessResult(result, scope) {\n\t\tconst baseDraft = scope.drafts[0]\n\t\tconst isReplaced = result !== undefined && result !== baseDraft\n\t\tthis.willFinalize(scope, result, isReplaced)\n\t\tif (isReplaced) {\n\t\t\tif (baseDraft[DRAFT_STATE].modified) {\n\t\t\t\tscope.revoke()\n\t\t\t\tthrow new Error(\"An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.\") // prettier-ignore\n\t\t\t}\n\t\t\tif (isDraftable(result)) {\n\t\t\t\t// Finalize the result in case it contains (or is) a subset of the draft.\n\t\t\t\tresult = this.finalize(result, null, scope)\n\t\t\t\tthis.maybeFreeze(result)\n\t\t\t}\n\t\t\tif (scope.patches) {\n\t\t\t\tscope.patches.push({\n\t\t\t\t\top: \"replace\",\n\t\t\t\t\tpath: [],\n\t\t\t\t\tvalue: result\n\t\t\t\t})\n\t\t\t\tscope.inversePatches.push({\n\t\t\t\t\top: \"replace\",\n\t\t\t\t\tpath: [],\n\t\t\t\t\tvalue: baseDraft[DRAFT_STATE].base\n\t\t\t\t})\n\t\t\t}\n\t\t} else {\n\t\t\t// Finalize the base draft.\n\t\t\tresult = this.finalize(baseDraft, [], scope)\n\t\t}\n\t\tscope.revoke()\n\t\tif (scope.patches) {\n\t\t\tscope.patchListener(scope.patches, scope.inversePatches)\n\t\t}\n\t\treturn result !== NOTHING ? result : undefined\n\t}\n\t/**\n\t * @internal\n\t * Finalize a draft, returning either the unmodified base state or a modified\n\t * copy of the base state.\n\t */\n\tfinalize(draft, path, scope) {\n\t\tconst state = draft[DRAFT_STATE]\n\t\tif (!state) {\n\t\t\tif (Object.isFrozen(draft)) return draft\n\t\t\treturn this.finalizeTree(draft, null, scope)\n\t\t}\n\t\t// Never finalize drafts owned by another scope.\n\t\tif (state.scope !== scope) {\n\t\t\treturn draft\n\t\t}\n\t\tif (!state.modified) {\n\t\t\tthis.maybeFreeze(state.base, true)\n\t\t\treturn state.base\n\t\t}\n\t\tif (!state.finalized) {\n\t\t\tstate.finalized = true\n\t\t\tthis.finalizeTree(state.draft, path, scope)\n\n\t\t\tif (this.onDelete) {\n\t\t\t\t// The `assigned` object is unreliable with ES5 drafts.\n\t\t\t\tif (this.useProxies) {\n\t\t\t\t\tconst {assigned} = state\n\t\t\t\t\tfor (const prop in assigned) {\n\t\t\t\t\t\tif (!assigned[prop]) this.onDelete(state, prop)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst {base, copy} = state\n\t\t\t\t\teach(base, prop => {\n\t\t\t\t\t\tif (!has(copy, prop)) this.onDelete(state, prop)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.onCopy) {\n\t\t\t\tthis.onCopy(state)\n\t\t\t}\n\n\t\t\t// At this point, all descendants of `state.copy` have been finalized,\n\t\t\t// so we can be sure that `scope.canAutoFreeze` is accurate.\n\t\t\tif (this.autoFreeze && scope.canAutoFreeze) {\n\t\t\t\tObject.freeze(state.copy)\n\t\t\t}\n\n\t\t\tif (path && scope.patches) {\n\t\t\t\tgeneratePatches(state, path, scope.patches, scope.inversePatches)\n\t\t\t}\n\t\t}\n\t\treturn state.copy\n\t}\n\t/**\n\t * @internal\n\t * Finalize all drafts in the given state tree.\n\t */\n\tfinalizeTree(root, rootPath, scope) {\n\t\tconst state = root[DRAFT_STATE]\n\t\tif (state) {\n\t\t\tif (!this.useProxies) {\n\t\t\t\t// Create the final copy, with added keys and without deleted keys.\n\t\t\t\tstate.copy = shallowCopy(state.draft, true)\n\t\t\t}\n\t\t\troot = state.copy\n\t\t}\n\n\t\tconst needPatches = !!rootPath && !!scope.patches\n\t\tconst finalizeProperty = (prop, value, parent) => {\n\t\t\tif (value === parent) {\n\t\t\t\tthrow Error(\"Immer forbids circular references\")\n\t\t\t}\n\n\t\t\t// In the `finalizeTree` method, only the `root` object may be a draft.\n\t\t\tconst isDraftProp = !!state && parent === root\n\n\t\t\tif (isDraft(value)) {\n\t\t\t\tconst path =\n\t\t\t\t\tisDraftProp && needPatches && !state.assigned[prop]\n\t\t\t\t\t\t? rootPath.concat(prop)\n\t\t\t\t\t\t: null\n\n\t\t\t\t// Drafts owned by `scope` are finalized here.\n\t\t\t\tvalue = this.finalize(value, path, scope)\n\n\t\t\t\t// Drafts from another scope must prevent auto-freezing.\n\t\t\t\tif (isDraft(value)) {\n\t\t\t\t\tscope.canAutoFreeze = false\n\t\t\t\t}\n\n\t\t\t\t// Preserve non-enumerable properties.\n\t\t\t\tif (Array.isArray(parent) || isEnumerable(parent, prop)) {\n\t\t\t\t\tparent[prop] = value\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty(parent, prop, {value})\n\t\t\t\t}\n\n\t\t\t\t// Unchanged drafts are never passed to the `onAssign` hook.\n\t\t\t\tif (isDraftProp && value === state.base[prop]) return\n\t\t\t}\n\t\t\t// Unchanged draft properties are ignored.\n\t\t\telse if (isDraftProp && is(value, state.base[prop])) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Search new objects for unfinalized drafts. Frozen objects should never contain drafts.\n\t\t\telse if (isDraftable(value) && !Object.isFrozen(value)) {\n\t\t\t\teach(value, finalizeProperty)\n\t\t\t\tthis.maybeFreeze(value)\n\t\t\t}\n\n\t\t\tif (isDraftProp && this.onAssign) {\n\t\t\t\tthis.onAssign(state, prop, value)\n\t\t\t}\n\t\t}\n\n\t\teach(root, finalizeProperty)\n\t\treturn root\n\t}\n\tmaybeFreeze(value, deep = false) {\n\t\tif (this.autoFreeze && !isDraft(value)) {\n\t\t\tif (deep) deepFreeze(value)\n\t\t\telse Object.freeze(value)\n\t\t}\n\t}\n}\n", "import {Immer} from \"./immer\"\n\nconst immer = new Immer()\n\n/**\n * The `produce` function takes a value and a \"recipe function\" (whose\n * return value often depends on the base state). The recipe function is\n * free to mutate its first argument however it wants. All mutations are\n * only ever applied to a __copy__ of the base state.\n *\n * Pass only a function to create a \"curried producer\" which relieves you\n * from passing the recipe function every time.\n *\n * Only plain objects and arrays are made mutable. All other objects are\n * considered uncopyable.\n *\n * Note: This function is __bound__ to its `Immer` instance.\n *\n * @param {any} base - the initial state\n * @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified\n * @param {Function} patchListener - optional function that will be called with all the patches produced here\n * @returns {any} a new state, or the initial state if nothing was modified\n */\nexport const produce = immer.produce\nexport default produce\n\n/**\n * Like `produce`, but `produceWithPatches` always returns a tuple\n * [nextState, patches, inversePatches] (instead of just the next state)\n */\nexport const produceWithPatches = immer.produceWithPatches.bind(immer)\n\n/**\n * Pass true to automatically freeze all copies created by Immer.\n *\n * By default, auto-freezing is disabled in production.\n */\nexport const setAutoFreeze = immer.setAutoFreeze.bind(immer)\n\n/**\n * Pass true to use the ES2015 `Proxy` class when creating drafts, which is\n * always faster than using ES5 proxies.\n *\n * By default, feature detection is used, so calling this is rarely necessary.\n */\nexport const setUseProxies = immer.setUseProxies.bind(immer)\n\n/**\n * Apply an array of Immer patches to the first argument.\n *\n * This function is a producer, which means copy-on-write is in effect.\n */\nexport const applyPatches = immer.applyPatches.bind(immer)\n\n/**\n * Create an Immer draft from the given base state, which may be a draft itself.\n * The draft can be modified until you finalize it with the `finishDraft` function.\n */\nexport const createDraft = immer.createDraft.bind(immer)\n\n/**\n * Finalize an Immer draft from a `createDraft` call, returning the base state\n * (if no changes were made) or a modified copy. The draft must *not* be\n * mutated afterwards.\n *\n * Pass a function as the 2nd argument to generate Immer patches based on the\n * changes that were made.\n */\nexport const finishDraft = immer.finishDraft.bind(immer)\n\nexport {\n\toriginal,\n\tisDraft,\n\tisDraftable,\n\tNOTHING as nothing,\n\tDRAFTABLE as immerable\n} from \"./common\"\n\nexport {Immer}\n", "function defaultEqualityCheck(a, b) {\n return a === b;\n}\n\nfunction areArgumentsShallowlyEqual(equalityCheck, prev, next) {\n if (prev === null || next === null || prev.length !== next.length) {\n return false;\n }\n\n // Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.\n var length = prev.length;\n for (var i = 0; i < length; i++) {\n if (!equalityCheck(prev[i], next[i])) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function defaultMemoize(func) {\n var equalityCheck = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultEqualityCheck;\n\n var lastArgs = null;\n var lastResult = null;\n // we reference arguments instead of spreading them for performance reasons\n return function () {\n if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {\n // apply arguments instead of spreading for performance.\n lastResult = func.apply(null, arguments);\n }\n\n lastArgs = arguments;\n return lastResult;\n };\n}\n\nfunction getDependencies(funcs) {\n var dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs;\n\n if (!dependencies.every(function (dep) {\n return typeof dep === 'function';\n })) {\n var dependencyTypes = dependencies.map(function (dep) {\n return typeof dep;\n }).join(', ');\n throw new Error('Selector creators expect all input-selectors to be functions, ' + ('instead received the following types: [' + dependencyTypes + ']'));\n }\n\n return dependencies;\n}\n\nexport function createSelectorCreator(memoize) {\n for (var _len = arguments.length, memoizeOptions = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n memoizeOptions[_key - 1] = arguments[_key];\n }\n\n return function () {\n for (var _len2 = arguments.length, funcs = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n funcs[_key2] = arguments[_key2];\n }\n\n var recomputations = 0;\n var resultFunc = funcs.pop();\n var dependencies = getDependencies(funcs);\n\n var memoizedResultFunc = memoize.apply(undefined, [function () {\n recomputations++;\n // apply arguments instead of spreading for performance.\n return resultFunc.apply(null, arguments);\n }].concat(memoizeOptions));\n\n // If a selector is called with the exact same arguments we don't need to traverse our dependencies again.\n var selector = memoize(function () {\n var params = [];\n var length = dependencies.length;\n\n for (var i = 0; i < length; i++) {\n // apply arguments instead of spreading and mutate a local list of params for performance.\n params.push(dependencies[i].apply(null, arguments));\n }\n\n // apply arguments instead of spreading for performance.\n return memoizedResultFunc.apply(null, params);\n });\n\n selector.resultFunc = resultFunc;\n selector.dependencies = dependencies;\n selector.recomputations = function () {\n return recomputations;\n };\n selector.resetRecomputations = function () {\n return recomputations = 0;\n };\n return selector;\n };\n}\n\nexport var createSelector = createSelectorCreator(defaultMemoize);\n\nexport function createStructuredSelector(selectors) {\n var selectorCreator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : createSelector;\n\n if (typeof selectors !== 'object') {\n throw new Error('createStructuredSelector expects first argument to be an object ' + ('where each property is a selector, instead received a ' + typeof selectors));\n }\n var objectKeys = Object.keys(selectors);\n return selectorCreator(objectKeys.map(function (key) {\n return selectors[key];\n }), function () {\n for (var _len3 = arguments.length, values = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n values[_key3] = arguments[_key3];\n }\n\n return values.reduce(function (composition, value, index) {\n composition[objectKeys[index]] = value;\n return composition;\n }, {});\n });\n}", "\"use strict\";\n\nvar compose = require('redux').compose;\n\nexports.__esModule = true;\nexports.composeWithDevTools = (\n typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?\n window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ :\n function() {\n if (arguments.length === 0) return undefined;\n if (typeof arguments[0] === 'object') return compose;\n return compose.apply(null, arguments);\n }\n);\n\nexports.devToolsEnhancer = (\n typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ ?\n window.__REDUX_DEVTOOLS_EXTENSION__ :\n function() { return function(noop) { return noop; } }\n);\n", "/**\r\n * Returns true if the passed value is \"plain\" object, i.e. an object whose\r\n * protoype is the root `Object.prototype`. This includes objects created\r\n * using object literals, but not for instance for class instances.\r\n *\r\n * @param {any} value The value to inspect.\r\n * @returns {boolean} True if the argument appears to be a plain object.\r\n */\r\nexport default function isPlainObject(value: unknown): value is object {\r\n if (typeof value !== 'object' || value === null) return false\r\n\r\n let proto = value\r\n while (Object.getPrototypeOf(proto) !== null) {\r\n proto = Object.getPrototypeOf(proto)\r\n }\r\n\r\n return Object.getPrototypeOf(value) === proto\r\n}\r\n", "function createThunkMiddleware(extraArgument) {\n return function (_ref) {\n var dispatch = _ref.dispatch,\n getState = _ref.getState;\n return function (next) {\n return function (action) {\n if (typeof action === 'function') {\n return action(dispatch, getState, extraArgument);\n }\n\n return next(action);\n };\n };\n };\n}\n\nvar thunk = createThunkMiddleware();\nthunk.withExtraArgument = createThunkMiddleware;\n\nexport default thunk;", "import isPlainObject from './isPlainObject'\r\nimport { Middleware } from 'redux'\r\n\r\n/**\r\n * Returns true if the passed value is \"plain\", i.e. a value that is either\r\n * directly JSON-serializable (boolean, number, string, array, plain object)\r\n * or `undefined`.\r\n *\r\n * @param val The value to check.\r\n *\r\n * @public\r\n */\r\nexport function isPlain(val: any) {\r\n return (\r\n typeof val === 'undefined' ||\r\n val === null ||\r\n typeof val === 'string' ||\r\n typeof val === 'boolean' ||\r\n typeof val === 'number' ||\r\n Array.isArray(val) ||\r\n isPlainObject(val)\r\n )\r\n}\r\n\r\ninterface NonSerializableValue {\r\n keyPath: string\r\n value: unknown\r\n}\r\n\r\n/**\r\n * @public\r\n */\r\nexport function findNonSerializableValue(\r\n value: unknown,\r\n path: ReadonlyArray = [],\r\n isSerializable: (value: unknown) => boolean = isPlain,\r\n getEntries?: (value: unknown) => [string, any][],\r\n ignoredPaths: string[] = []\r\n): NonSerializableValue | false {\r\n let foundNestedSerializable: NonSerializableValue | false\r\n\r\n if (!isSerializable(value)) {\r\n return {\r\n keyPath: path.join('.') || '',\r\n value: value\r\n }\r\n }\r\n\r\n if (typeof value !== 'object' || value === null) {\r\n return false\r\n }\r\n\r\n const entries = getEntries != null ? getEntries(value) : Object.entries(value)\r\n\r\n const hasIgnoredPaths = ignoredPaths.length > 0\r\n\r\n for (const [property, nestedValue] of entries) {\r\n const nestedPath = path.concat(property)\r\n\r\n if (hasIgnoredPaths && ignoredPaths.indexOf(nestedPath.join('.')) >= 0) {\r\n continue\r\n }\r\n\r\n if (!isSerializable(nestedValue)) {\r\n return {\r\n keyPath: nestedPath.join('.'),\r\n value: nestedValue\r\n }\r\n }\r\n\r\n if (typeof nestedValue === 'object') {\r\n foundNestedSerializable = findNonSerializableValue(\r\n nestedValue,\r\n nestedPath,\r\n isSerializable,\r\n getEntries,\r\n ignoredPaths\r\n )\r\n\r\n if (foundNestedSerializable) {\r\n return foundNestedSerializable\r\n }\r\n }\r\n }\r\n\r\n return false\r\n}\r\n\r\n/**\r\n * Options for `createSerializableStateInvariantMiddleware()`.\r\n *\r\n * @public\r\n */\r\nexport interface SerializableStateInvariantMiddlewareOptions {\r\n /**\r\n * The function to check if a value is considered serializable. This\r\n * function is applied recursively to every value contained in the\r\n * state. Defaults to `isPlain()`.\r\n */\r\n isSerializable?: (value: any) => boolean\r\n /**\r\n * The function that will be used to retrieve entries from each\r\n * value. If unspecified, `Object.entries` will be used. Defaults\r\n * to `undefined`.\r\n */\r\n getEntries?: (value: any) => [string, any][]\r\n\r\n /**\r\n * An array of action types to ignore when checking for serializability, Defaults to []\r\n */\r\n ignoredActions?: string[]\r\n\r\n /**\r\n * An array of dot-separated path strings to ignore when checking for serializability, Defaults to []\r\n */\r\n ignoredPaths?: string[]\r\n}\r\n\r\n/**\r\n * Creates a middleware that, after every state change, checks if the new\r\n * state is serializable. If a non-serializable value is found within the\r\n * state, an error is printed to the console.\r\n *\r\n * @param options Middleware options.\r\n *\r\n * @public\r\n */\r\nexport function createSerializableStateInvariantMiddleware(\r\n options: SerializableStateInvariantMiddlewareOptions = {}\r\n): Middleware {\r\n const {\r\n isSerializable = isPlain,\r\n getEntries,\r\n ignoredActions = [],\r\n ignoredPaths = []\r\n } = options\r\n\r\n return storeAPI => next => action => {\r\n if (ignoredActions.length && ignoredActions.indexOf(action.type) !== -1) {\r\n return next(action)\r\n }\r\n\r\n const foundActionNonSerializableValue = findNonSerializableValue(\r\n action,\r\n [],\r\n isSerializable,\r\n getEntries\r\n )\r\n\r\n if (foundActionNonSerializableValue) {\r\n const { keyPath, value } = foundActionNonSerializableValue\r\n\r\n console.error(\r\n `A non-serializable value was detected in an action, in the path: \\`${keyPath}\\`. Value:`,\r\n value,\r\n '\\nTake a look at the logic that dispatched this action: ',\r\n action,\r\n '\\n(See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)'\r\n )\r\n }\r\n\r\n const result = next(action)\r\n\r\n const state = storeAPI.getState()\r\n\r\n const foundStateNonSerializableValue = findNonSerializableValue(\r\n state,\r\n [],\r\n isSerializable,\r\n getEntries,\r\n ignoredPaths\r\n )\r\n\r\n if (foundStateNonSerializableValue) {\r\n const { keyPath, value } = foundStateNonSerializableValue\r\n\r\n console.error(\r\n `A non-serializable value was detected in the state, in the path: \\`${keyPath}\\`. Value:`,\r\n value,\r\n `\r\nTake a look at the reducer(s) handling this action type: ${action.type}.\r\n(See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)`\r\n )\r\n }\r\n\r\n return result\r\n }\r\n}\r\n", "import { Middleware, AnyAction } from 'redux'\r\nimport thunkMiddleware, { ThunkMiddleware } from 'redux-thunk'\r\n/* PROD_START_REMOVE_UMD */\r\nimport createImmutableStateInvariantMiddleware from 'redux-immutable-state-invariant'\r\n/* PROD_STOP_REMOVE_UMD */\r\n\r\nimport {\r\n createSerializableStateInvariantMiddleware,\r\n SerializableStateInvariantMiddlewareOptions\r\n} from './serializableStateInvariantMiddleware'\r\n\r\nfunction isBoolean(x: any): x is boolean {\r\n return typeof x === 'boolean'\r\n}\r\n\r\ninterface ThunkOptions {\r\n extraArgument: E\r\n}\r\n\r\ninterface ImmutableStateInvariantMiddlewareOptions {\r\n isImmutable?: (value: any) => boolean\r\n ignore?: string[]\r\n}\r\n\r\ninterface GetDefaultMiddlewareOptions {\r\n thunk?: boolean | ThunkOptions\r\n immutableCheck?: boolean | ImmutableStateInvariantMiddlewareOptions\r\n serializableCheck?: boolean | SerializableStateInvariantMiddlewareOptions\r\n}\r\n\r\nexport type ThunkMiddlewareFor<\r\n S,\r\n O extends GetDefaultMiddlewareOptions = {}\r\n> = O extends {\r\n thunk: false\r\n}\r\n ? never\r\n : O extends { thunk: { extraArgument: infer E } }\r\n ? ThunkMiddleware\r\n :\r\n | ThunkMiddleware //The ThunkMiddleware with a `null` ExtraArgument is here to provide backwards-compatibility.\r\n | ThunkMiddleware\r\n\r\n/**\r\n * Returns any array containing the default middleware installed by\r\n * `configureStore()`. Useful if you want to configure your store with a custom\r\n * `middleware` array but still keep the default set.\r\n *\r\n * @return The default middleware used by `configureStore()`.\r\n *\r\n * @public\r\n */\r\nexport function getDefaultMiddleware<\r\n S = any,\r\n O extends Partial = {\r\n thunk: true\r\n immutableCheck: true\r\n serializableCheck: true\r\n }\r\n>(options: O = {} as O): Array | ThunkMiddlewareFor> {\r\n const {\r\n thunk = true,\r\n immutableCheck = true,\r\n serializableCheck = true\r\n } = options\r\n\r\n let middlewareArray: Middleware<{}, S>[] = []\r\n\r\n if (thunk) {\r\n if (isBoolean(thunk)) {\r\n middlewareArray.push(thunkMiddleware)\r\n } else {\r\n middlewareArray.push(\r\n thunkMiddleware.withExtraArgument(thunk.extraArgument)\r\n )\r\n }\r\n }\r\n\r\n if (process.env.NODE_ENV !== 'production') {\r\n if (immutableCheck) {\r\n /* PROD_START_REMOVE_UMD */\r\n let immutableOptions: ImmutableStateInvariantMiddlewareOptions = {}\r\n\r\n if (!isBoolean(immutableCheck)) {\r\n immutableOptions = immutableCheck\r\n }\r\n\r\n middlewareArray.unshift(\r\n createImmutableStateInvariantMiddleware(immutableOptions)\r\n )\r\n /* PROD_STOP_REMOVE_UMD */\r\n }\r\n\r\n if (serializableCheck) {\r\n let serializableOptions: SerializableStateInvariantMiddlewareOptions = {}\r\n\r\n if (!isBoolean(serializableCheck)) {\r\n serializableOptions = serializableCheck\r\n }\r\n\r\n middlewareArray.push(\r\n createSerializableStateInvariantMiddleware(serializableOptions)\r\n )\r\n }\r\n }\r\n\r\n return middlewareArray as any\r\n}\r\n", "import { Action } from 'redux'\r\nimport {\r\n IsUnknownOrNonInferrable,\r\n IfMaybeUndefined,\r\n IfVoid,\r\n IsAny\r\n} from './tsHelpers'\r\n\r\n/**\r\n * An action with a string type and an associated payload. This is the\r\n * type of action returned by `createAction()` action creators.\r\n *\r\n * @template P The type of the action's payload.\r\n * @template T the type used for the action type.\r\n * @template M The type of the action's meta (optional)\r\n * @template E The type of the action's error (optional)\r\n *\r\n * @public\r\n */\r\nexport type PayloadAction<\r\n P = void,\r\n T extends string = string,\r\n M = never,\r\n E = never\r\n> = {\r\n payload: P\r\n type: T\r\n} & ([M] extends [never]\r\n ? {}\r\n : {\r\n meta: M\r\n }) &\r\n ([E] extends [never]\r\n ? {}\r\n : {\r\n error: E\r\n })\r\n\r\n/**\r\n * A \"prepare\" method to be used as the second parameter of `createAction`.\r\n * Takes any number of arguments and returns a Flux Standard Action without\r\n * type (will be added later) that *must* contain a payload (might be undefined).\r\n *\r\n * @public\r\n */\r\nexport type PrepareAction

=\r\n | ((...args: any[]) => { payload: P })\r\n | ((...args: any[]) => { payload: P; meta: any })\r\n | ((...args: any[]) => { payload: P; error: any })\r\n | ((...args: any[]) => { payload: P; meta: any; error: any })\r\n\r\n/**\r\n * Internal version of `ActionCreatorWithPreparedPayload`. Not to be used externally.\r\n *\r\n * @internal\r\n */\r\nexport type _ActionCreatorWithPreparedPayload<\r\n PA extends PrepareAction | void,\r\n T extends string = string\r\n> = PA extends PrepareAction\r\n ? ActionCreatorWithPreparedPayload<\r\n Parameters,\r\n P,\r\n T,\r\n ReturnType extends {\r\n error: infer E\r\n }\r\n ? E\r\n : never,\r\n ReturnType extends {\r\n meta: infer M\r\n }\r\n ? M\r\n : never\r\n >\r\n : void\r\n\r\n/**\r\n * Basic type for all action creators.\r\n *\r\n * @inheritdoc {redux#ActionCreator}\r\n */\r\ninterface BaseActionCreator {\r\n type: T\r\n match(action: Action): action is PayloadAction\r\n}\r\n\r\n/**\r\n * An action creator that takes multiple arguments that are passed\r\n * to a `PrepareAction` method to create the final Action.\r\n * @typeParam Args arguments for the action creator function\r\n * @typeParam P `payload` type\r\n * @typeParam T `type` name\r\n * @typeParam E optional `error` type\r\n * @typeParam M optional `meta` type\r\n *\r\n * @inheritdoc {redux#ActionCreator}\r\n *\r\n * @public\r\n */\r\nexport interface ActionCreatorWithPreparedPayload<\r\n Args extends unknown[],\r\n P,\r\n T extends string = string,\r\n E = never,\r\n M = never\r\n> extends BaseActionCreator {\r\n /**\r\n * Calling this {@link redux#ActionCreator} with `Args` will return\r\n * an Action with a payload of type `P` and (depending on the `PrepareAction`\r\n * method used) a `meta`- and `error` property of types `M` and `E` respectively.\r\n */\r\n (...args: Args): PayloadAction\r\n}\r\n\r\n/**\r\n * An action creator of type `T` that takes an optional payload of type `P`.\r\n *\r\n * @inheritdoc {redux#ActionCreator}\r\n *\r\n * @public\r\n */\r\nexport interface ActionCreatorWithOptionalPayload\r\n extends BaseActionCreator {\r\n /**\r\n * Calling this {@link redux#ActionCreator} without arguments will\r\n * return a {@link PayloadAction} of type `T` with a payload of `undefined`\r\n */\r\n (payload?: undefined): PayloadAction\r\n /**\r\n * Calling this {@link redux#ActionCreator} with an argument will\r\n * return a {@link PayloadAction} of type `T` with a payload of `P`\r\n */\r\n >(payload?: PT): PayloadAction\r\n}\r\n\r\n/**\r\n * An action creator of type `T` that takes no payload.\r\n *\r\n * @inheritdoc {redux#ActionCreator}\r\n *\r\n * @public\r\n */\r\nexport interface ActionCreatorWithoutPayload\r\n extends BaseActionCreator {\r\n /**\r\n * Calling this {@link redux#ActionCreator} will\r\n * return a {@link PayloadAction} of type `T` with a payload of `undefined`\r\n */\r\n (): PayloadAction\r\n}\r\n\r\n/**\r\n * An action creator of type `T` that requires a payload of type P.\r\n *\r\n * @inheritdoc {redux#ActionCreator}\r\n *\r\n * @public\r\n */\r\nexport interface ActionCreatorWithPayload\r\n extends BaseActionCreator {\r\n /**\r\n * Calling this {@link redux#ActionCreator} with an argument will\r\n * return a {@link PayloadAction} of type `T` with a payload of `P`\r\n * If possible, `P` will be narrowed down to the exact type of the payload argument.\r\n */\r\n (payload: PT): PayloadAction\r\n /**\r\n * Calling this {@link redux#ActionCreator} with an argument will\r\n * return a {@link PayloadAction} of type `T` with a payload of `P`\r\n */\r\n (payload: P): PayloadAction\r\n}\r\n\r\n/**\r\n * An action creator of type `T` whose `payload` type could not be inferred. Accepts everything as `payload`.\r\n *\r\n * @inheritdoc {redux#ActionCreator}\r\n *\r\n * @public\r\n */\r\nexport interface ActionCreatorWithNonInferrablePayload<\r\n T extends string = string\r\n> extends BaseActionCreator {\r\n /**\r\n * Calling this {@link redux#ActionCreator} with an argument will\r\n * return a {@link PayloadAction} of type `T` with a payload\r\n * of exactly the type of the argument.\r\n */\r\n (payload: PT): PayloadAction\r\n}\r\n\r\n/**\r\n * An action creator that produces actions with a `payload` attribute.\r\n *\r\n * @typeParam P the `payload` type\r\n * @typeParam T the `type` of the resulting action\r\n * @typeParam PA if the resulting action is preprocessed by a `prepare` method, the signature of said method.\r\n *\r\n * @public\r\n */\r\nexport type PayloadActionCreator<\r\n P = void,\r\n T extends string = string,\r\n PA extends PrepareAction

| void = void\r\n> = IfPrepareActionMethodProvided<\r\n PA,\r\n _ActionCreatorWithPreparedPayload,\r\n // else\r\n IsAny<\r\n P,\r\n ActionCreatorWithPayload,\r\n IsUnknownOrNonInferrable<\r\n P,\r\n ActionCreatorWithNonInferrablePayload,\r\n // else\r\n IfVoid<\r\n P,\r\n ActionCreatorWithoutPayload,\r\n // else\r\n IfMaybeUndefined<\r\n P,\r\n ActionCreatorWithOptionalPayload,\r\n // else\r\n ActionCreatorWithPayload\r\n >\r\n >\r\n >\r\n >\r\n>\r\n\r\n/**\r\n * A utility function to create an action creator for the given action type\r\n * string. The action creator accepts a single argument, which will be included\r\n * in the action object as a field called payload. The action creator function\r\n * will also have its toString() overriden so that it returns the action type,\r\n * allowing it to be used in reducer logic that is looking for that action type.\r\n *\r\n * @param type The action type to use for created actions.\r\n * @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.\r\n * If this is given, the resulting action creator will pass it's arguments to this method to calculate payload & meta.\r\n *\r\n * @public\r\n */\r\nexport function createAction

(\r\n type: T\r\n): PayloadActionCreator\r\n\r\n/**\r\n * A utility function to create an action creator for the given action type\r\n * string. The action creator accepts a single argument, which will be included\r\n * in the action object as a field called payload. The action creator function\r\n * will also have its toString() overriden so that it returns the action type,\r\n * allowing it to be used in reducer logic that is looking for that action type.\r\n *\r\n * @param type The action type to use for created actions.\r\n * @param prepare (optional) a method that takes any number of arguments and returns { payload } or { payload, meta }.\r\n * If this is given, the resulting action creator will pass it's arguments to this method to calculate payload & meta.\r\n *\r\n * @public\r\n */\r\nexport function createAction<\r\n PA extends PrepareAction,\r\n T extends string = string\r\n>(\r\n type: T,\r\n prepareAction: PA\r\n): PayloadActionCreator['payload'], T, PA>\r\n\r\nexport function createAction(type: string, prepareAction?: Function): any {\r\n function actionCreator(...args: any[]) {\r\n if (prepareAction) {\r\n let prepared = prepareAction(...args)\r\n if (!prepared) {\r\n throw new Error('prepareAction did not return an object')\r\n }\r\n\r\n return {\r\n type,\r\n payload: prepared.payload,\r\n ...('meta' in prepared && { meta: prepared.meta }),\r\n ...('error' in prepared && { error: prepared.error })\r\n }\r\n }\r\n return { type, payload: args[0] }\r\n }\r\n\r\n actionCreator.toString = () => `${type}`\r\n\r\n actionCreator.type = type\r\n\r\n actionCreator.match = (action: Action): action is PayloadAction =>\r\n action.type === type\r\n\r\n return actionCreator\r\n}\r\n\r\n/**\r\n * Returns the action type of the actions created by the passed\r\n * `createAction()`-generated action creator (arbitrary action creators\r\n * are not supported).\r\n *\r\n * @param action The action creator whose action type to get.\r\n * @returns The action type used by the action creator.\r\n *\r\n * @public\r\n */\r\nexport function getType(\r\n actionCreator: PayloadActionCreator\r\n): T {\r\n return `${actionCreator}` as T\r\n}\r\n\r\n// helper types for more readable typings\r\n\r\ntype Diff = T extends U ? never : T\r\n\r\ntype IfPrepareActionMethodProvided<\r\n PA extends PrepareAction | void,\r\n True,\r\n False\r\n> = PA extends (...args: any[]) => any ? True : False\r\n", "import { Action } from 'redux'\r\nimport { CaseReducer, CaseReducers } from './createReducer'\r\n\r\nexport interface TypedActionCreator {\r\n (...args: any[]): Action\r\n type: Type\r\n}\r\n\r\n/**\r\n * A builder for an action <-> reducer map.\r\n *\r\n * @public\r\n */\r\nexport interface ActionReducerMapBuilder {\r\n /**\r\n * Add a case reducer for actions created by this action creator.\r\n * @param actionCreator\r\n * @param reducer\r\n */\r\n addCase>(\r\n actionCreator: ActionCreator,\r\n reducer: CaseReducer>\r\n ): ActionReducerMapBuilder\r\n /**\r\n * Add a case reducer for actions with the specified type.\r\n * @param type\r\n * @param reducer\r\n */\r\n addCase>(\r\n type: Type,\r\n reducer: CaseReducer\r\n ): ActionReducerMapBuilder\r\n}\r\n\r\nexport function executeReducerBuilderCallback(\r\n builderCallback: (builder: ActionReducerMapBuilder) => void\r\n): CaseReducers {\r\n const actionsMap: CaseReducers = {}\r\n const builder = {\r\n addCase(\r\n typeOrActionCreator: string | TypedActionCreator,\r\n reducer: CaseReducer\r\n ) {\r\n const type =\r\n typeof typeOrActionCreator === 'string'\r\n ? typeOrActionCreator\r\n : typeOrActionCreator.type\r\n if (type in actionsMap) {\r\n throw new Error(\r\n 'addCase cannot be called with two reducers for the same action type'\r\n )\r\n }\r\n actionsMap[type] = reducer\r\n return builder\r\n }\r\n }\r\n builderCallback(builder)\r\n return actionsMap\r\n}\r\n", "import createNextState, { Draft } from 'immer'\r\nimport { AnyAction, Action, Reducer } from 'redux'\r\nimport {\r\n executeReducerBuilderCallback,\r\n ActionReducerMapBuilder\r\n} from './mapBuilders'\r\n\r\n/**\r\n * Defines a mapping from action types to corresponding action object shapes.\r\n *\r\n * @deprecated This should not be used manually - it is only used for internal\r\n * inference purposes and should not have any further value.\r\n * It might be removed in the future.\r\n * @public\r\n */\r\nexport type Actions = Record\r\n\r\n/**\r\n * An *case reducer* is a reducer function for a specific action type. Case\r\n * reducers can be composed to full reducers using `createReducer()`.\r\n *\r\n * Unlike a normal Redux reducer, a case reducer is never called with an\r\n * `undefined` state to determine the initial state. Instead, the initial\r\n * state is explicitly specified as an argument to `createReducer()`.\r\n *\r\n * In addition, a case reducer can choose to mutate the passed-in `state`\r\n * value directly instead of returning a new state. This does not actually\r\n * cause the store state to be mutated directly; instead, thanks to\r\n * [immer](https://github.com/mweststrate/immer), the mutations are\r\n * translated to copy operations that result in a new state.\r\n *\r\n * @public\r\n */\r\nexport type CaseReducer = (\r\n state: Draft,\r\n action: A\r\n) => S | void\r\n\r\n/**\r\n * A mapping from action types to case reducers for `createReducer()`.\r\n *\r\n * @deprecated This should not be used manually - it is only used\r\n * for internal inference purposes and using it manually\r\n * would lead to type erasure.\r\n * It might be removed in the future.\r\n * @public\r\n */\r\nexport type CaseReducers = {\r\n [T in keyof AS]: AS[T] extends Action ? CaseReducer : void\r\n}\r\n\r\n/**\r\n * A utility function that allows defining a reducer as a mapping from action\r\n * type to *case reducer* functions that handle these action types. The\r\n * reducer's initial state is passed as the first argument.\r\n *\r\n * The body of every case reducer is implicitly wrapped with a call to\r\n * `produce()` from the [immer](https://github.com/mweststrate/immer) library.\r\n * This means that rather than returning a new state object, you can also\r\n * mutate the passed-in state object directly; these mutations will then be\r\n * automatically and efficiently translated into copies, giving you both\r\n * convenience and immutability.\r\n *\r\n * @param initialState The initial state to be returned by the reducer.\r\n * @param actionsMap A mapping from action types to action-type-specific\r\n * case reducers.\r\n *\r\n * @public\r\n */\r\nexport function createReducer<\r\n S,\r\n CR extends CaseReducers = CaseReducers\r\n>(initialState: S, actionsMap: CR): Reducer\r\n/**\r\n * A utility function that allows defining a reducer as a mapping from action\r\n * type to *case reducer* functions that handle these action types. The\r\n * reducer's initial state is passed as the first argument.\r\n *\r\n * The body of every case reducer is implicitly wrapped with a call to\r\n * `produce()` from the [immer](https://github.com/mweststrate/immer) library.\r\n * This means that rather than returning a new state object, you can also\r\n * mutate the passed-in state object directly; these mutations will then be\r\n * automatically and efficiently translated into copies, giving you both\r\n * convenience and immutability.\r\n * @param initialState The initial state to be returned by the reducer.\r\n * @param builderCallback A callback that receives a *builder* object to define\r\n * case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`.\r\n *\r\n * @public\r\n */\r\nexport function createReducer(\r\n initialState: S,\r\n builderCallback: (builder: ActionReducerMapBuilder) => void\r\n): Reducer\r\n\r\nexport function createReducer(\r\n initialState: S,\r\n mapOrBuilderCallback:\r\n | CaseReducers\r\n | ((builder: ActionReducerMapBuilder) => void)\r\n): Reducer {\r\n let actionsMap =\r\n typeof mapOrBuilderCallback === 'function'\r\n ? executeReducerBuilderCallback(mapOrBuilderCallback)\r\n : mapOrBuilderCallback\r\n\r\n return function(state = initialState, action): S {\r\n // @ts-ignore createNextState() produces an Immutable> rather\r\n // than an Immutable, and TypeScript cannot find out how to reconcile\r\n // these two types.\r\n return createNextState(state, (draft: Draft) => {\r\n const caseReducer = actionsMap[action.type]\r\n return caseReducer ? caseReducer(draft, action) : undefined\r\n })\r\n }\r\n}\r\n", "import {\r\n createStore,\r\n compose,\r\n applyMiddleware,\r\n combineReducers,\r\n Reducer,\r\n ReducersMapObject,\r\n Middleware,\r\n Action,\r\n AnyAction,\r\n StoreEnhancer,\r\n Store,\r\n DeepPartial,\r\n Dispatch\r\n} from 'redux'\r\nimport {\r\n composeWithDevTools,\r\n EnhancerOptions as DevToolsOptions\r\n} from 'redux-devtools-extension'\r\n\r\nimport isPlainObject from './isPlainObject'\r\nimport {\r\n getDefaultMiddleware,\r\n ThunkMiddlewareFor\r\n} from './getDefaultMiddleware'\r\nimport { DispatchForMiddlewares } from './tsHelpers'\r\n\r\nconst IS_PRODUCTION = process.env.NODE_ENV === 'production'\r\n\r\n/**\r\n * Callback function type, to be used in `ConfigureStoreOptions.enhancers`\r\n *\r\n * @public\r\n */\r\nexport type ConfigureEnhancersCallback = (\r\n defaultEnhancers: StoreEnhancer[]\r\n) => StoreEnhancer[]\r\n\r\n/**\r\n * Options for `configureStore()`.\r\n *\r\n * @public\r\n */\r\nexport interface ConfigureStoreOptions<\r\n S = any,\r\n A extends Action = AnyAction,\r\n M extends Middlewares = Middlewares\r\n> {\r\n /**\r\n * A single reducer function that will be used as the root reducer, or an\r\n * object of slice reducers that will be passed to `combineReducers()`.\r\n */\r\n reducer: Reducer | ReducersMapObject\r\n\r\n /**\r\n * An array of Redux middleware to install. If not supplied, defaults to\r\n * the set of middleware returned by `getDefaultMiddleware()`.\r\n */\r\n middleware?: M\r\n\r\n /**\r\n * Whether to enable Redux DevTools integration. Defaults to `true`.\r\n *\r\n * Additional configuration can be done by passing Redux DevTools options\r\n */\r\n devTools?: boolean | DevToolsOptions\r\n\r\n /**\r\n * The initial state, same as Redux's createStore.\r\n * You may optionally specify it to hydrate the state\r\n * from the server in universal apps, or to restore a previously serialized\r\n * user session. If you use `combineReducers()` to produce the root reducer\r\n * function (either directly or indirectly by passing an object as `reducer`),\r\n * this must be an object with the same shape as the reducer map keys.\r\n */\r\n // NOTE: The needlessly complicated `S extends any ? S : S` instead of just\r\n // `S` ensures that the TypeScript compiler doesn't attempt to infer `S`\r\n // based on the value passed as `preloadedState`, which might be a partial\r\n // state rather than the full thing.\r\n preloadedState?: DeepPartial\r\n\r\n /**\r\n * The store enhancers to apply. See Redux's `createStore()`.\r\n * All enhancers will be included before the DevTools Extension enhancer.\r\n * If you need to customize the order of enhancers, supply a callback\r\n * function that will receive the original array (ie, `[applyMiddleware]`),\r\n * and should return a new array (such as `[applyMiddleware, offline]`).\r\n * If you only need to add middleware, you can use the `middleware` parameter instaead.\r\n */\r\n enhancers?: StoreEnhancer[] | ConfigureEnhancersCallback\r\n}\r\n\r\ntype Middlewares = ReadonlyArray>\r\n\r\n/**\r\n * A Redux store returned by `configureStore()`. Supports dispatching\r\n * side-effectful _thunks_ in addition to plain actions.\r\n *\r\n * @public\r\n */\r\nexport interface EnhancedStore<\r\n S = any,\r\n A extends Action = AnyAction,\r\n M extends Middlewares = Middlewares\r\n> extends Store {\r\n /**\r\n * The `dispatch` method of your store, enhanced by all it's middlewares.\r\n *\r\n * @inheritdoc\r\n */\r\n dispatch: DispatchForMiddlewares & Dispatch\r\n}\r\n\r\n/**\r\n * A friendly abstraction over the standard Redux `createStore()` function.\r\n *\r\n * @param config The store configuration.\r\n * @returns A configured Redux store.\r\n *\r\n * @public\r\n */\r\nexport function configureStore<\r\n S = any,\r\n A extends Action = AnyAction,\r\n M extends Middlewares = [ThunkMiddlewareFor]\r\n>(options: ConfigureStoreOptions): EnhancedStore {\r\n const {\r\n reducer = undefined,\r\n middleware = getDefaultMiddleware(),\r\n devTools = true,\r\n preloadedState = undefined,\r\n enhancers = undefined\r\n } = options || {}\r\n\r\n let rootReducer: Reducer\r\n\r\n if (typeof reducer === 'function') {\r\n rootReducer = reducer\r\n } else if (isPlainObject(reducer)) {\r\n rootReducer = combineReducers(reducer)\r\n } else {\r\n throw new Error(\r\n '\"reducer\" is a required argument, and must be a function or an object of functions that can be passed to combineReducers'\r\n )\r\n }\r\n\r\n const middlewareEnhancer = applyMiddleware(...middleware)\r\n\r\n let finalCompose = compose\r\n\r\n if (devTools) {\r\n finalCompose = composeWithDevTools({\r\n // Enable capture of stack traces for dispatched Redux actions\r\n trace: !IS_PRODUCTION,\r\n ...(typeof devTools === 'object' && devTools)\r\n })\r\n }\r\n\r\n let storeEnhancers: StoreEnhancer[] = [middlewareEnhancer]\r\n\r\n if (Array.isArray(enhancers)) {\r\n storeEnhancers = [middlewareEnhancer, ...enhancers]\r\n } else if (typeof enhancers === 'function') {\r\n storeEnhancers = enhancers(storeEnhancers)\r\n }\r\n\r\n const composedEnhancer = finalCompose(...storeEnhancers) as any\r\n\r\n return createStore(\r\n rootReducer,\r\n preloadedState as DeepPartial,\r\n composedEnhancer\r\n )\r\n}\r\n", "import { Reducer } from 'redux'\r\nimport {\r\n createAction,\r\n PayloadAction,\r\n PayloadActionCreator,\r\n PrepareAction,\r\n ActionCreatorWithoutPayload,\r\n _ActionCreatorWithPreparedPayload\r\n} from './createAction'\r\nimport { createReducer, CaseReducers, CaseReducer } from './createReducer'\r\nimport {\r\n ActionReducerMapBuilder,\r\n executeReducerBuilderCallback\r\n} from './mapBuilders'\r\nimport { Omit } from './tsHelpers'\r\n\r\n/**\r\n * An action creator atttached to a slice.\r\n *\r\n * @deprecated please use PayloadActionCreator directly\r\n *\r\n * @public\r\n */\r\nexport type SliceActionCreator

= PayloadActionCreator

\r\n\r\n/**\r\n * The return value of `createSlice`\r\n *\r\n * @public\r\n */\r\nexport interface Slice<\r\n State = any,\r\n CaseReducers extends SliceCaseReducers = SliceCaseReducers\r\n> {\r\n /**\r\n * The slice name.\r\n */\r\n name: string\r\n\r\n /**\r\n * The slice's reducer.\r\n */\r\n reducer: Reducer\r\n\r\n /**\r\n * Action creators for the types of actions that are handled by the slice\r\n * reducer.\r\n */\r\n actions: CaseReducerActions\r\n\r\n /**\r\n * The individual case reducer functions that were passed in the `reducers` parameter.\r\n * This enables reuse and testing if they were defined inline when calling `createSlice`.\r\n */\r\n caseReducers: SliceDefinedCaseReducers\r\n}\r\n\r\n/**\r\n * Options for `createSlice()`.\r\n *\r\n * @public\r\n */\r\nexport interface CreateSliceOptions<\r\n State = any,\r\n CR extends SliceCaseReducers = SliceCaseReducers\r\n> {\r\n /**\r\n * The slice's name. Used to namespace the generated action types.\r\n */\r\n name: string\r\n\r\n /**\r\n * The initial state to be returned by the slice reducer.\r\n */\r\n initialState: State\r\n\r\n /**\r\n * A mapping from action types to action-type-specific *case reducer*\r\n * functions. For every action type, a matching action creator will be\r\n * generated using `createAction()`.\r\n */\r\n reducers: ValidateSliceCaseReducers\r\n\r\n /**\r\n * A mapping from action types to action-type-specific *case reducer*\r\n * functions. These reducers should have existing action types used\r\n * as the keys, and action creators will _not_ be generated.\r\n * Alternatively, a callback that receives a *builder* object to define\r\n * case reducers via calls to `builder.addCase(actionCreatorOrType, reducer)`.\r\n */\r\n extraReducers?:\r\n | CaseReducers, any>\r\n | ((builder: ActionReducerMapBuilder>) => void)\r\n}\r\n\r\n/**\r\n * A CaseReducer with a `prepare` method.\r\n *\r\n * @public\r\n */\r\nexport type CaseReducerWithPrepare = {\r\n reducer: CaseReducer\r\n prepare: PrepareAction\r\n}\r\n\r\n/**\r\n * The type describing a slice's `reducers` option.\r\n *\r\n * @public\r\n */\r\nexport type SliceCaseReducers = {\r\n [K: string]:\r\n | CaseReducer>\r\n | CaseReducerWithPrepare>\r\n}\r\n\r\n/**\r\n * Derives the slice's `actions` property from the `reducers` options\r\n *\r\n * @public\r\n */\r\nexport type CaseReducerActions> = {\r\n [Type in keyof CaseReducers]: CaseReducers[Type] extends { prepare: any }\r\n ? ActionCreatorForCaseReducerWithPrepare\r\n : ActionCreatorForCaseReducer\r\n}\r\n\r\n/**\r\n * Get a `PayloadActionCreator` type for a passed `CaseReducerWithPrepare`\r\n *\r\n * @internal\r\n */\r\ntype ActionCreatorForCaseReducerWithPrepare<\r\n CR extends { prepare: any }\r\n> = _ActionCreatorWithPreparedPayload\r\n\r\n/**\r\n * Get a `PayloadActionCreator` type for a passed `CaseReducer`\r\n *\r\n * @internal\r\n */\r\ntype ActionCreatorForCaseReducer = CR extends (\r\n state: any,\r\n action: infer Action\r\n) => any\r\n ? Action extends { payload: infer P }\r\n ? PayloadActionCreator

\r\n : ActionCreatorWithoutPayload\r\n : ActionCreatorWithoutPayload\r\n\r\n/**\r\n * Extracts the CaseReducers out of a `reducers` object, even if they are\r\n * tested into a `CaseReducerWithPrepare`.\r\n *\r\n * @internal\r\n */\r\ntype SliceDefinedCaseReducers> = {\r\n [Type in keyof CaseReducers]: CaseReducers[Type] extends {\r\n reducer: infer Reducer\r\n }\r\n ? Reducer\r\n : CaseReducers[Type]\r\n}\r\n\r\n/**\r\n * Helper type. Passes T out again, but boxes it in a way that it cannot\r\n * \"widen\" the type by accident if it is a generic that should be inferred\r\n * from elsewhere.\r\n *\r\n * @internal\r\n */\r\ntype NoInfer = [T][T extends any ? 0 : never]\r\n\r\n/**\r\n * Used on a SliceCaseReducers object.\r\n * Ensures that if a CaseReducer is a `CaseReducerWithPrepare`, that\r\n * the `reducer` and the `prepare` function use the same type of `payload`.\r\n *\r\n * Might do additional such checks in the future.\r\n *\r\n * This type is only ever useful if you want to write your own wrapper around\r\n * `createSlice`. Please don't use it otherwise!\r\n *\r\n * @public\r\n */\r\nexport type ValidateSliceCaseReducers<\r\n S,\r\n ACR extends SliceCaseReducers\r\n> = ACR &\r\n {\r\n [T in keyof ACR]: ACR[T] extends {\r\n reducer(s: S, action?: infer A): any\r\n }\r\n ? {\r\n prepare(...a: never[]): Omit\r\n }\r\n : {}\r\n }\r\n\r\nfunction getType(slice: string, actionKey: string): string {\r\n return `${slice}/${actionKey}`\r\n}\r\n\r\n/**\r\n * A function that accepts an initial state, an object full of reducer\r\n * functions, and a \"slice name\", and automatically generates\r\n * action creators and action types that correspond to the\r\n * reducers and state.\r\n *\r\n * The `reducer` argument is passed to `createReducer()`.\r\n *\r\n * @public\r\n */\r\nexport function createSlice<\r\n State,\r\n CaseReducers extends SliceCaseReducers\r\n>(\r\n options: CreateSliceOptions\r\n): Slice {\r\n const { name, initialState } = options\r\n if (!name) {\r\n throw new Error('`name` is a required option for createSlice')\r\n }\r\n const reducers = options.reducers || {}\r\n const extraReducers =\r\n typeof options.extraReducers === 'undefined'\r\n ? {}\r\n : typeof options.extraReducers === 'function'\r\n ? executeReducerBuilderCallback(options.extraReducers)\r\n : options.extraReducers\r\n\r\n const reducerNames = Object.keys(reducers)\r\n\r\n const sliceCaseReducersByName: Record = {}\r\n const sliceCaseReducersByType: Record = {}\r\n const actionCreators: Record = {}\r\n\r\n reducerNames.forEach(reducerName => {\r\n const maybeReducerWithPrepare = reducers[reducerName]\r\n const type = getType(name, reducerName)\r\n\r\n let caseReducer: CaseReducer\r\n let prepareCallback: PrepareAction | undefined\r\n\r\n if ('reducer' in maybeReducerWithPrepare) {\r\n caseReducer = maybeReducerWithPrepare.reducer\r\n prepareCallback = maybeReducerWithPrepare.prepare\r\n } else {\r\n caseReducer = maybeReducerWithPrepare\r\n }\r\n\r\n sliceCaseReducersByName[reducerName] = caseReducer\r\n sliceCaseReducersByType[type] = caseReducer\r\n actionCreators[reducerName] = prepareCallback\r\n ? createAction(type, prepareCallback)\r\n : createAction(type)\r\n })\r\n\r\n const finalCaseReducers = { ...extraReducers, ...sliceCaseReducersByType }\r\n const reducer = createReducer(initialState, finalCaseReducers as any)\r\n\r\n return {\r\n name,\r\n reducer,\r\n actions: actionCreators as any,\r\n caseReducers: sliceCaseReducersByName as any\r\n }\r\n}\r\n", "/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(C,e){\"use strict\";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.4.1\",k=function(e,t){return new k.fn.init(e,t)},p=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;function d(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0+~]|\"+M+\")\"+M+\"*\"),U=new RegExp(M+\"|>\"),X=new RegExp($),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+$),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+M+\"?|(\"+M+\")|.)\",\"ig\"),ne=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+\" \"]&&(!v||!v.test(t))&&(1!==p||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=k),o=(l=h(t)).length;while(o--)l[o]=\"#\"+s+\" \"+xe(l[o]);c=l.join(\",\"),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute(\"id\")}}}return g(t.replace(B,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),d.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML=\"\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+M+\"*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+k+\"-]\").length||v.push(\"~=\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+k+\"+*\").length||v.push(\".#.+[+~]\")}),ce(function(e){e.innerHTML=\"\";var t=C.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",$)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&p(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML=\"\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[\":\"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\\x20\\t\\r\\n\\f]*)/i,he=/^$|^module$|\\/(?:java|ecma)script/i,ge={option:[1,\"\"],thead:[1,\"\",\"
\"],col:[2,\"\",\"
\"],tr:[2,\"\",\"
\"],td:[3,\"\",\"
\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx\",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==(\"focus\"===t)}function Ae(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(R)||[\"\"]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(R)||[\"\"]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,\"events\")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,qe=/\\s*$/g;function Oe(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&k(e).children(\"tbody\")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Re(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n\")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\\?(?=&|$)|\\?\\?/;k.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Gt.pop()||k.expando+\"_\"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Yt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||k.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),\"script\"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument(\"\").body).innerHTML=\"

\",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1\").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,\"position\"),c=k(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=k.css(e,\"top\"),u=k.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===k.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===k.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,\"borderTopWidth\",!0),i.left+=k.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-k.css(r,\"marginTop\",!0),left:t.left-i.left-k.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===k.css(e,\"position\"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each([\"top\",\"left\"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+\"px\":t})}),k.each({Height:\"height\",Width:\"width\"},function(a,s){k.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){k.fn[n]=function(e,t){return 0 -1) {\n ws_emitter.addEventListener(eventName, listener);\n }\n };\n this.off = function (eventName, listener) {\n ui_emitter.removeEventListener(eventName, listener);\n if (wsEventsToPassToUI.indexOf(eventName) > -1) {\n ws_emitter.removeEventListener(eventName, listener);\n }\n };\n\n this.setUser = function(user_promise) {\n return Promise.all([user_promise, hsm_ready.promise]).then(([user, hsm]) => {\n console.log('user info ready', user);\n storeController.store.dispatch(storeController.user.actions.receive_user(user));\n grayLog.setUser(user);\n // login user to presence\n hsm.dispatch('user_login_credentials', [user]);\n user_ready.resolve();\n }).catch(error => {\n console.error('failed to get user info', error);\n sentryCaptureException(error);\n });\n };\n\n this.setPerformer = function (performer_promise) {\n return Promise.all([performer_promise, hsm_ready.promise, user_ready.promise]).then(([performer, hsm]) => {\n console.log('performer info ready', performer);\n fixPledgeEndTime(performer.pledge_configuration, performer.server_time);\n storeController.store.dispatch(storeController.performer.actions.receive_performer(performer));\n // This is initial request to join performer's public chat.\n // it is automatically set when we get performer and whole HSM comes into action\n hsm.dispatch('public_chat_login_request', [performer.public_room]);\n }).catch(error => {\n console.error('failed to get performer info', error);\n sentryCaptureException(error);\n });\n };\n\n // was made for service worker, not needed now\n /*\n this.on('internal_error', event => {\n var ss = document.createElement(\"link\");\n ss.type = \"text/css\";\n ss.rel = \"stylesheet\";\n ss.href = \"/embed/iziT/css/iziToast.css\";\n document.getElementsByTagName(\"head\")[0].appendChild(ss);\n import('/embed/iziT/js/iziToast.min.js').then(() => {\n iziToast.error({\n position: 'topRight',\n timeout: 50000,\n title: 'Internal Error',\n message: event.detail.reason,\n buttons: [\n ['', function (instance, toast) {\n\n instance.hide({transitionOut: 'fadeOut'}, toast, 'button');\n\n }, true],\n // ['', function (instance, toast) {\n //\n // instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');\n //\n // }],\n ],\n });\n });\n });\n */\n\n\n this.guestsMaySendMessages = true;\n this.basicsMaySendMessages = true;\n this.isIgnored = false;\n\n this.onPermissionsOnSendMessage = function (event) {\n const data = event.detail;\n const oldGuestsMSM = this.guestsMaySendMessages;\n const oldBasicsMSM = this.basicsMaySendMessages;\n this.guestsMaySendMessages = data.guest_allowed;\n this.basicsMaySendMessages = data.basic_allowed;\n const user = this.getUser();\n\n if (user.isGuest && oldGuestsMSM !== data.guest_allowed) {\n const msgObj = {type: data.guest_allowed ? 'guest_enabled' : 'guest_disabled'};\n storeController.store.dispatch(storeController.chat.actions.message(msgObj));\n } else if (user.isBasic && oldBasicsMSM !== data.basic_allowed) {\n const msgObj = {type: data.basic_allowed ? 'basic_enabled' : 'basic_disabled'};\n storeController.store.dispatch(storeController.chat.actions.message(msgObj));\n }\n }.bind(this);\n\n ws_emitter.addEventListener('permissions_on_send_message', this.onPermissionsOnSendMessage);\n\n this.getRoom = function () {\n return storeController.store.getState().chat.room;\n };\n\n this.startPrivateShow = function () {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n return;\n }\n if (user.tokens < 10) {\n tokenActivity.getMoreTokens('purchase_tokens_start_private_show');\n return;\n }\n const performer = this.getPerformer();\n\n // try to spy the show\n if (performer.status === STATUS_PRIVATE) {\n this.startSpyShow();\n return;\n }\n\n // allow only online and away performers to be asked for private show\n if ([STATUS_ONLINE, STATUS_AWAY].indexOf(performer.status) === -1) {\n console.info('startPrivateShow', 'performer is in status', performer.status);\n return;\n }\n\n if (performer.privateDisabled) {\n ui_emitter.dispatchEvent(new Event('performer_disabled_private_show'));\n return;\n }\n\n const cost = performer.true_private_setting ? performer.tariff.true_private : performer.tariff.private;\n if (user.ppu || confirm(`Private session with ${performer.username} costs ${cost} tokens per minute`)) {\n edgeConnection.send({action: 'presence_send_private_chat_invitation', performer_id: performer.id});\n }\n };\n\n this.startSpyShow = function () {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n return;\n }\n if (user.tokens < 10) {\n tokenActivity.getMoreTokens('purchase_tokens_start_spy_show');\n return;\n }\n\n const performer = storeController.store.getState().performer;\n if (performer.status != STATUS_PRIVATE) {\n console.info('startSpyShow', 'performer is in status', performer.status);\n return;\n }\n\n if (performer.privateDisabled) {\n ui_emitter.dispatchEvent(new Event('performer_disabled_private_show'));\n return;\n }\n if (performer.truePrivateChat) {\n ui_emitter.dispatchEvent(new Event('performer_disabled_spy_private_show'));\n return;\n }\n\n if (user.ppu || confirm(`Spy session with ${performer.username} costs ${performer.tariff.spy} tokens per minute`)) {\n edgeConnection.send({action: 'presence_spy_private_chat', performer_id: performer.id});\n }\n };\n\n this.stopPrivateShow = function () {\n const user = this.getUser();\n if (user.isGuest) return;\n const chatType = storeController.store.getState().chat.type;\n if ([CHAT_TYPE_PRIVATE, CHAT_TYPE_SPY].indexOf(chatType) == -1) return;\n hsm.dispatch('user_return_to_public');\n };\n\n this.sendMessage = function (text) {\n const chatType = storeController.store.getState().chat.type;\n if (chatType == CHAT_TYPE_SPY) {\n console.info('You may not send messages while spying.');\n return;\n }\n\n const user = this.getUser();\n // check if user may send messages\n if (user.isGuest && !this.guestsMaySendMessages) {\n storeController.store.dispatch(storeController.chat.actions.message({type: 'guest_disabled'}));\n return;\n } else if (user.isBasic && !this.basicsMaySendMessages) {\n storeController.store.dispatch(storeController.chat.actions.message({type: 'basic_disabled'}));\n return;\n }\n\n // user is in ignore list of the performer\n if (this.isIgnored) {\n //this.chatConn.onNewMessage({ senderName: user.displayname, content: text });\n return;\n }\n\n edgeConnection.send({action: 'send_message', room: this.getRoom(), message: text});\n };\n\n this.sendPledgeTokens = function (tokens) {\n const chatType = storeController.store.getState().chat.type;\n if ([CHAT_TYPE_PUBLIC, CHAT_TYPE_PLEDGE].indexOf(chatType) == -1) {\n return;\n }\n const performer = storeController.store.getState().performer;\n edgeConnection.send({action: 'presence_send_pledge_bid', performer_id: performer.id, tokens});\n };\n\n this.getPledgeBidAmount = function() {\n const { performer: { id: performerId }, pledgeBids } = storeController.store.getState();\n if (!pledgeBids) return 0;\n if (!pledgeBids[performerId]) return 0;\n return pledgeBids[performerId].tokens || 0;\n };\n\n this.getPledgeChatInfo = function() {\n const { performer: { id: performerId }, pledgeBids } = storeController.store.getState();\n if (!pledgeBids) return null;\n if (!pledgeBids[performerId]) return null;\n return pledgeBids[performerId].pledge_chat_info || null;\n };\n\n this.showRegisterModal = () => ui_emitter.dispatch('show_register_modal');\n this.showLoginModal = () => ui_emitter.dispatch('show_login_modal');\n this.showUpgradeToPremiumModal = () => ui_emitter.dispatch('show_upgrade_to_premium_modal');\n\n this.getMoreTokens = function(params) {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n return;\n }\n const source = params && params.source ? params.source : '';\n tokenActivity.getMoreTokens(source);\n };\n\n this.needShowConfirmEmailModal = function() {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n return true;\n }\n if (!user.is_confirmed && user.tokens > 0) {\n ui_emitter.dispatchEvent(new Event('show_confirm_to_tip_modal'));\n return true;\n }\n return false;\n };\n\n this.showTipModal = function (opts) {\n if (this.needShowConfirmEmailModal()) return;\n ui_emitter.dispatchEvent(new CustomEvent('show_tip_modal', { detail: opts }));\n };\n\n this.showVibraTipModal = function () {\n if (this.needShowConfirmEmailModal()) return;\n ui_emitter.dispatchEvent(new Event('show_vibratip_modal'));\n };\n\n this.addTips = function(amount) {\n if (amount < 1) return;\n if (this.needShowConfirmEmailModal()) return;\n const user = this.getUser();\n if (user.tokens < amount) {\n toastr.warning('You need to have more tokens!');\n return;\n }\n const tip_data = {\n tokens: parseInt(amount),\n message: '',\n notify_public: true,\n notify_anonym: false,\n };\n const performer = this.getPerformer();\n const room = this.getRoom() || undefined; // room not required, may send tips to offline performer\n window.tokenActivity.sendTips(tip_data, performer, room);\n };\n\n this.showGiftModal = function () {\n const user = this.getUser();\n const eventName = user.isGuest ? 'show_login_modal' : 'show_gift_modal';\n ui_emitter.dispatchEvent(new Event(eventName));\n };\n\n this.showPledgeModal = function () {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n } else {\n const performer = storeController.store.getState().performer;\n const pledge_configuration = performer.pledge_configuration;\n const min_amount = this.getPledgeBidAmount(performer.id) > 0 ? 1 : pledge_configuration.min_tokens_rate;\n ui_emitter.dispatchEvent(new CustomEvent('show_pledge_modal', {detail: {pledge_configuration, min_amount}}));\n }\n };\n\n this.getPerformers = function () {\n return storeController.store.getState().performers;\n };\n\n this.getPerformer = function () {\n return storeController.store.getState().performer;\n };\n\n this.getUser = function() {\n return storeController.store.getState().user;\n };\n\n this.updateUserTokens = function (tokens) {\n tokens = parseInt(tokens);\n if (isNaN(tokens) || tokens < 0) {\n console.warn('got incorrect tokens number');\n tokens = 0;\n }\n storeController.store.dispatch(storeController.user.actions.update_tokens(tokens));\n };\n\n this.updateUserTierLevel = function(level) {\n storeController.store.dispatch(storeController.user.actions.update_tier_level(level));\n };\n\n this.updateUserVerification = function(verification) {\n storeController.store.dispatch(storeController.user.actions.update_verification(verification));\n };\n\n this.openChattersList = function() {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n return;\n }\n this.messenger.openChattersList();\n };\n\n this.openIMUnreadOrChattersList = function(preferredCollocutor) {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n return;\n }\n this.messenger.openIMUnreadOrChattersList(preferredCollocutor);\n };\n\n this.startMessenger = function(performer) {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n return;\n }\n if (!user.isPremium) {\n this.showUpgradeToPremiumModal();\n return;\n }\n this.messenger.startMessenger(performer);\n };\n\n this.showMyWebcam = function() {\n const user = this.getUser();\n if (user.isGuest) {\n this.showLoginModal();\n return;\n }\n if (!user.isPremium) {\n this.showUpgradeToPremiumModal();\n return;\n }\n if (!user.webrtc_publish_stream_name) {\n console.error('premium user has no webrtc_publish_stream_name');\n sentryCaptureMessage('premium user has no webrtc_publish_stream_name');\n return;\n }\n ui_emitter.dispatchEvent(new CustomEvent('my_webcam_show', {detail: {webrtc_publish_stream_name: user.webrtc_publish_stream_name}}));\n };\n\n this.hideMyWebcam = function() {\n ui_emitter.dispatchEvent(new CustomEvent('my_webcam_hide'));\n };\n\n\n let isMobileInterface = false;\n this.isMobileInterface = () => isMobileInterface;\n // dimensions must match css values\n const updateInterfaceType = () => {\n if ((window.matchMedia('(orientation: landscape)').matches && window.innerHeight <= 480)\n || (window.matchMedia('(orientation: portrait)').matches && window.innerWidth <= 768)\n ) {\n isMobileInterface = true;\n } else {\n isMobileInterface = false;\n }\n };\n updateInterfaceType();\n window.addEventListener('resize', updateInterfaceType);\n\n // ====================================================================\n // ======================= MAIN ENTRY POINT ===========================\n // ====================================================================\n\n // should be called after dom loaded and all handlers are attached\n this.start = function() {\n console.info('FWC start...', 'config=', config);\n\n const hsmOptions = {};\n const presence = new PresenceChannel(config, ws_emitter, ui_emitter, storeController);\n const chat = new ChatChannel(config, edgeConnection, ws_emitter, storeController);\n\n if (0 && config.debug) {\n console.log('add debug to HSM');\n Object.assign(hsmOptions, {\n debug: (message, event) => {\n\n if (event && typeof message == 'string' && (\n event.type === 'empty'\n || event.type === 'entry'\n || event.type === 'exit'\n || event.type === 'init')) {\n return;\n }\n // if (event.indexOf('Unhandled event') > -1) return; // skip unhandled\n console.debug('HSM:', hsm.currentState().name, message);\n },\n log: (message, event) => {\n console.log('HSM:', hsm.currentState().name, message);\n }\n }\n )\n }\n\n hsm.run(hsmOptions);\n // login_info_promise.then(login_data => {\n // storeController.store.dispatch(storeController.user.actions.receive_user(login_data));\n // hsm.dispatch('user_login_credentials', [login_data]);\n // });\n\n hsm_ready.resolve(hsm);\n }\n\n}\n", "\n// https://github.com/mariocasciaro/object-path/blob/master/index.js\nfunction initObjectPathGet() {\n\n var options = {\n includeInheritedProps: true,\n };\n\n function getKey(key) {\n var intKey = parseInt(key);\n if (intKey.toString() === key) {\n return intKey;\n }\n return key;\n }\n\n function hasOwnProperty(obj, prop) {\n if (obj == null) {\n return false\n }\n //to handle objects with null prototypes (too edge case?)\n return Object.prototype.hasOwnProperty.call(obj, prop)\n }\n\n function hasShallowProperty(obj, prop) {\n return (options.includeInheritedProps || (typeof prop === 'number' && Array.isArray(obj)) || hasOwnProperty(obj, prop))\n }\n\n function getShallowProperty(obj, prop) {\n if (hasShallowProperty(obj, prop)) {\n return obj[prop];\n }\n }\n\n function get(obj, path, defaultValue) {\n if (typeof path === 'number') {\n path = [path];\n }\n if (!path || path.length === 0) {\n return obj;\n }\n if (obj == null) {\n return defaultValue;\n }\n if (typeof path === 'string') {\n return get(obj, path.split('.'), defaultValue);\n }\n\n var currentPath = getKey(path[0]);\n var nextObj = getShallowProperty(obj, currentPath);\n if (nextObj === void 0) {\n return defaultValue;\n }\n\n if (path.length === 1) {\n return nextObj;\n }\n\n return get(obj[currentPath], path.slice(1), defaultValue);\n }\n\n return get;\n}\n\n// https://github.com/ivantsov/redux-subscriber/blob/master/src/index.js\nexport function initReduxSubscriber() {\n\n const subscribers = {};\n const get = initObjectPathGet();\n\n function subscribe(key, cb) {\n if (subscribers.hasOwnProperty(key)) {\n subscribers[key].push(cb);\n } else {\n subscribers[key] = [cb];\n }\n\n // return \"unsubscribe\" function\n return function() {\n subscribers[key] = subscribers[key].filter(s => s !== cb);\n };\n }\n\n function initSubscriber(store) {\n let prevState = store.getState();\n\n store.subscribe(() => {\n const newState = store.getState();\n\n Object.keys(subscribers).forEach(key => {\n if (get(prevState, key) !== get(newState, key)) {\n subscribers[key].forEach(cb => cb(newState));\n }\n });\n\n prevState = newState;\n });\n\n return subscribe;\n }\n\n return initSubscriber;\n}\n", "\nexport const STATUS_OFFLINE = 'offline';\nexport const STATUS_ONLINE = 'online';\nexport const STATUS_AWAY = 'away';\nexport const STATUS_PRIVATE = 'private';\n//export const STATUS_GROUP = 'group';\nexport const STATUS_PLEDGE_INIT = 'pledge_init';\nexport const STATUS_PLEDGE_SHOW = 'pledge_show';\nexport const STATUS_HIDDEN_CAM = 'hidden_cam';\n\nexport const CHAT_TYPE_OFFLINE = 'offline';\nexport const CHAT_TYPE_PUBLIC = 'public';\nexport const CHAT_TYPE_PRIVATE = 'private';\nexport const CHAT_TYPE_SPY = 'spy';\n//export const CHAT_TYPE_GROUP = 'group';\nexport const CHAT_TYPE_PLEDGE = 'pledge';\n", "import { initReduxSubscriber } from './redux-subscriber.js';\nimport { CHAT_TYPE_OFFLINE } from './const.js';\n\n// https://redux-toolkit.js.org/\n// https://unpkg.com/browse/@reduxjs/toolkit@1.2.5/dist/\nexport function initStore(ui_emitter) {\n\n // all performers\n const performers = RTK.createSlice({\n name: 'performers',\n initialState: [],\n reducers: {\n receive_performers: (state, action) => action.payload,\n performer_join: (state, action) => {\n const performer = action.payload;\n const index = state.findIndex(p => p.id === performer.id);\n if (index === -1) {\n state.push(performer);\n } else {\n return [\n ...state.slice(0, index),\n ...state.slice(index+1),\n performer\n ]\n }\n },\n performer_leave: (state, action) => {\n state.some(p => {\n if (p.id == action.payload.user_id) {\n p.status = 'offline';\n return true;\n }\n })\n },\n performer_true_private_setting: (state, action) => {\n state.some(p => {\n if (p.id == action.payload.user_id) {\n p.true_private_setting = action.payload.true_private_setting;\n return true;\n }\n });\n },\n performer_change_status: (state, action) => {\n state.some(p => {\n if (p.id == action.payload.user_id) {\n p.status = action.payload.user_status;\n return true;\n }\n });\n },\n performer_change_vibratip: (state, action) => {\n state.some(p => {\n if (p.id == action.payload.user_id) {\n p.vibratip = action.payload.user_vibratip_setting;\n return true;\n }\n });\n },\n performer_add_stream: (state, action) => {\n state.some(p => {\n if (p.id == action.payload.user_id) {\n let streams = p.streams || [];\n p.streams = appendStream(streams, action.payload.stream);\n return true;\n }\n });\n },\n performer_delete_stream: (state, action) => {\n state.some(p => {\n if (p.id == action.payload.user_id) {\n let newStreams = []; // if streamId is null - delete all streams\n const deleteStreamId = action.payload.stream_id;\n if (deleteStreamId != null) {\n newStreams = p.streams.filter(s => s.stream_id !== deleteStreamId);\n }\n p.streams = newStreams;\n return true;\n }\n });\n },\n all_performers_delete_streams: (state) => {\n state.forEach(p => {\n p.streams = [];\n })\n },\n performer_pledge_configuration: (state, action) => {\n state.some(p => {\n if (p.id == action.payload.user_id) {\n p.pledge_configuration = action.payload.pledge_configuration;\n return true;\n }\n });\n },\n }\n });\n\n function appendStream(list, stream) {\n const index = list.findIndex(s => s.stream_id === stream.stream_id);\n let allStreams = [];\n if (index === -1) {\n allStreams = [...list, stream];\n } else {\n allStreams = [\n ...list.slice(0, index),\n ...list.slice(index + 1),\n stream\n ];\n }\n return allStreams;\n }\n\n // current performer\n const performer = RTK.createSlice({\n name: 'performer',\n initialState: {},\n reducers: {\n receive_performer: (state, action) => {\n return action.payload;\n }\n },\n extraReducers: {\n [performers.actions.receive_performers]: (state, action) => {\n action.payload.some(p => {\n if (state.id == p.id) {\n state.status = p.status;\n state.vibratip = p.vibratip;\n state.pledge_configuration = p.pledge_configuration;\n state.public_room = p.public_room;\n state.streams = p.streams;\n state.tariff = p.tariff;\n return true;\n }\n })\n },\n [performers.actions.performer_join]: (state, action) => {\n const performer = action.payload;\n if (state.id == performer.id) {\n return performer;\n }\n return state;\n },\n [performers.actions.performer_leave]: (state, action) => {\n if (state.id == action.payload.user_id) {\n state.status = 'offline';\n }\n },\n [performers.actions.performer_true_private_setting]: (state, action) => {\n if (state.id == action.payload.user_id) {\n state.true_private_setting = action.payload.true_private_setting;\n }\n },\n [performers.actions.performer_change_status]: (state, action) => {\n if (state.id == action.payload.user_id) {\n state.status = action.payload.user_status;\n }\n },\n [performers.actions.performer_change_vibratip]: (state, action) => {\n if (state.id == action.payload.user_id) {\n state.vibratip = action.payload.user_vibratip_setting;\n }\n },\n [performers.actions.performer_add_stream]: (state, action) => {\n if (state.id == action.payload.user_id) {\n let streams = state.streams || [];\n state.streams = appendStream(streams, action.payload.stream);\n }\n },\n [performers.actions.performer_delete_stream]: (state, action) => {\n const performerId = action.payload.user_id;\n const streamId = action.payload.stream_id;\n if (performerId == null && streamId == null) {\n state.streams = [];\n } else {\n let newStreams = []; // if streamId is null - delete all streams\n if (streamId != null && state.streams) {\n newStreams = state.streams.filter(s => s.stream_id !== streamId);\n }\n state.streams = newStreams;\n }\n },\n [performers.actions.all_performers_delete_streams]: (state) => {\n state.streams = [];\n },\n [performers.actions.performer_pledge_configuration]: (state, action) => {\n if (state.id == action.payload.user_id) {\n state.pledge_configuration = action.payload.pledge_configuration;\n }\n }\n }\n });\n\n const defaultRoomTopic = ''; // redux topic better be different from server topic, to trigger change event\n const chat = RTK.createSlice({\n name: 'chat',\n initialState: {\n room: null,\n type: CHAT_TYPE_OFFLINE,\n topic: defaultRoomTopic,\n users: [],\n usersUpdateTimeout: 0,\n usersUpdateCount: 0, // for subscriber to listen to redux fully changed the state\n messages: [],\n app_panel: null,\n },\n reducers: {\n room: (state, action) => { state.room = action.payload },\n type: (state, action) => { state.type = action.payload },\n chat_reset: (state) => {\n state.topic = defaultRoomTopic;\n state.users = [];\n state.messages = [];\n },\n topic: (state, action) => { state.topic = action.payload },\n history: (state, action) => {\n state.messages = action.payload;\n ui_emitter.dispatchEvent(new Event('chat_clear_messages'));\n state.messages.forEach(m => {\n ui_emitter.dispatchEvent(new CustomEvent('chat_message_' + m.type, {detail: m}));\n })\n },\n message: (state, action) => {\n state.messages.push(action.payload);\n ui_emitter.dispatchEvent(new CustomEvent('chat_message_' + action.payload.type, {detail: action.payload}));\n },\n clear_messages: (state, action) => {\n state.messages = [];\n ui_emitter.dispatchEvent(new Event('chat_clear_messages'));\n },\n clear_user_messages: (state, action) => {\n const clear_name = action.payload;\n let needUpdateUI = false;\n const filtered = state.messages.filter(m => {\n const silence = (m.senderName && m.senderName == clear_name) || (m.userName && m.userName == clear_name);\n if (!needUpdateUI && silence) needUpdateUI = true;\n return !silence;\n });\n if (needUpdateUI) {\n state.messages = filtered;\n ui_emitter.dispatchEvent(new Event('chat_clear_messages'));\n state.messages.forEach(m => {\n ui_emitter.dispatchEvent(new CustomEvent('chat_message_' + m.type, {detail: m}));\n })\n }\n },\n app_panel: (state, action) => {\n state.app_panel = action.payload.panel;\n },\n users: (state, action) => {\n state.users = action.payload.sort(usersSortFunction);\n state.usersUpdateTimeout = 0;\n state.usersUpdateCount++;\n },\n join: (state, action) => {\n const user = action.payload;\n const newUsers = state.users.slice();\n newUsers.push(user);\n state.users = newUsers.sort(usersSortFunction);\n let timeout = usersTimeoutGuest;\n if (user.level === 'model') timeout = usersTimeoutPerformer;\n else if (user.level === 'basic' || user.level === 'premium' || user.level === 'admin') timeout = usersTimeoutMember;\n state.usersUpdateTimeout = timeout;\n state.usersUpdateCount++;\n },\n leave: (state, action) => {\n const user = action.payload;\n state.users = state.users.filter(u => u.id != user.id);\n const users_count = state.users.length;\n ui_emitter.dispatchEvent(new CustomEvent('chat_user_leave', {detail: {user, users_count}}));\n },\n }\n });\n\n const usersTimeoutPerformer = 0;\n const usersTimeoutMember = 1000;\n const usersTimeoutGuest = 5000;\n let usersLastSent = new Date();\n let usersTimer = null;\n\n function sendEventChatUsersList(users, timeout) {\n if (timeout === 0) {\n clearTimeout(usersTimer);\n usersTimer = null;\n ui_emitter.dispatchEvent(new CustomEvent('chat_users', {detail:{users}}));\n usersLastSent = new Date();\n return;\n }\n\n const timePassed = new Date() - usersLastSent;\n\n if (timePassed >= timeout) {\n clearTimeout(usersTimer);\n usersTimer = null;\n ui_emitter.dispatchEvent(new CustomEvent('chat_users', {detail:{users}}));\n usersLastSent = new Date();\n\n } else {\n const timeToNextUpdate = timeout - timePassed;\n if (usersTimer) {\n clearTimeout(usersTimer);\n usersTimer = null;\n }\n usersTimer = setTimeout(() => {\n sendEventChatUsersList(users, 0)\n }, timeToNextUpdate);\n }\n }\n\n function usersSortFunction(u1, u2) {\n if (u1) {\n if (u1.level === u2.level) {\n if (u1.level === 'guest') {\n const d1 = u1.username.indexOf('Guest') === 0;\n const d2 = u2.username.indexOf('Guest') === 0;\n if (d1 && !d2) return 1;\n if (!d1 && d2) return -1;\n }\n\n if (u1.tier_level === u2.tier_level) {\n return u1.username < u2.username ? -1 : 1;\n }\n\n if (u1.tier_level !== u2.tier_level) {\n return u1.tier_level < u2.tier_level ? 1 : -1;\n }\n }\n\n if (u1.level === 'model') return -1;\n if (u2.level === 'model') return 1;\n\n if (u1.level === 'premium') return -1;\n if (u2.level === 'premium') return 1;\n\n if (u1.level === 'basic') return -1;\n if (u2.level === 'basic') return 1;\n }\n\n return 0;\n }\n\n const pledgeBids = RTK.createSlice({\n name: 'pledgeBids',\n initialState: {},\n reducers: {\n pledgeBids: (state, action) => { return action.payload },\n pledgeBidAdded: (state, action) => {\n const { user_id, tokens } = action.payload;\n if (state[user_id]) {\n state[user_id].tokens += tokens;\n } else {\n state[user_id] = {user_id, tokens};\n }\n },\n pledgeBidClear: (state, action) => {\n const user_id = action.payload;\n if (state[user_id]) {\n delete state[user_id];\n }\n },\n pledgeChatInfo: (state, action) => {\n const { user_id, pledge_chat_info } = action.payload;\n // user might pledge other performer, forget about it and switch to another room\n if (!state[user_id]) {\n console.warn('user_forgot_about_pledge_show');\n console.error('trying to change pledge chat info with no bids', user_id, pledge_chat_info);\n sentryCaptureMessage('trying to change pledge chat info with no bids', pledge_chat_info);\n return state;\n }\n state[user_id].pledge_chat_info = pledge_chat_info;\n },\n }\n });\n\n const user = RTK.createSlice({\n name: 'user',\n initialState: {},\n reducers: {\n receive_user: (state, action) => { return action.payload },\n update_user_from_chat_server: (state, action) => {\n let tokens = parseInt(action.payload.tokens, 10);\n if (tokens < 0 || isNaN(tokens)) {\n console.warn('incorrect tokens from chat server', action.payload.tokens);\n tokens = 0;\n }\n state.tokens = tokens;\n state.ip = action.payload.ip;\n const publish_stream_names = action.payload.publish_stream_names;\n state.publish_stream_names = publish_stream_names;\n // webrtc_publish_stream_name, for user to publish the video\n let webrtcPSN = null;\n if (publish_stream_names && publish_stream_names.length) {\n publish_stream_names.some(ps => {\n if (ps.stream_type === 'webrtc') {\n webrtcPSN = ps.stream_name;\n return true;\n }\n });\n }\n state.webrtc_publish_stream_name = webrtcPSN;\n },\n update_tokens: (state, action) => { state.tokens = action.payload },\n update_tier_level: (state, action) => { state.tier_level = action.payload },\n update_verification: (state, action) => { state.verification = action.payload },\n update_private_message_setting: (state, action) => { state.settings.s_private_message = action.payload }\n }\n });\n\n const hiddenCamAccess = RTK.createSlice({\n name: 'hiddenCamAccess',\n initialState: {},\n reducers: {\n update_access: (state, action) => {\n const { room, allowed } = action.payload;\n if (state[room]) {\n state[room].allowed = allowed;\n } else {\n state[room] = {room, allowed};\n }\n },\n },\n extraReducers: {\n [chat.actions.chat_reset]: () => {\n return {};\n }\n }\n });\n\n\n const initialCollocutor = {\n id: null,\n username: null,\n photo: false,\n gender: 'female',\n isAdmin: false,\n messages: [],\n opened: false,\n unread: false,\n bar: false, // visible in chat bar\n ready: false\n };\n\n // helper to convert proxy to plain object\n const proxy2obj = p => JSON.parse(JSON.stringify(p));\n\n const messenger = RTK.createSlice({\n name: 'messenger',\n initialState: {\n muted: false, // play sound\n opened: false, // show chatters list\n collocutors: [],\n },\n reducers: {\n create_messenger: (state, action) => {\n const collocutor = action.payload;\n let existCollocutor = null;\n state.collocutors.some(c => {\n if (c.id == collocutor.id) {\n existCollocutor = c;\n return true;\n }\n });\n if (existCollocutor) return state;\n\n const needProps = {\n id: collocutor.id,\n username: collocutor.username,\n isAdmin: collocutor.isAdmin,\n photo: collocutor.photo || collocutor.has_photo,\n };\n const newCol = Object.assign({}, initialCollocutor, needProps);\n state.collocutors.push(newCol);\n ui_emitter.dispatchEvent(new CustomEvent('messenger_create', {detail: {collocutor: newCol}}));\n },\n open_messenger: (state, action) => {\n const colId = action.payload;\n // close others, open requested\n state.collocutors.forEach(c => {\n // other\n if (c.opened && c.id != colId) {\n if (c.opened) {\n c.opened = false;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_close', {detail: {collocutor: proxy2obj(c)}}));\n }\n }\n // requested\n if (c.id == colId) {\n c.opened = true;\n c.unread = false;\n c.bar = true;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_open', {detail: {collocutor: proxy2obj(c)}}));\n }\n })\n },\n messenger_ready: (state, action) => {\n const colId = action.payload;\n state.collocutors.some(c => {\n if (c.id == colId) {\n c.ready = true;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_ready', {detail: {collocutor: proxy2obj(c)}}));\n return true;\n }\n });\n },\n messenger_offline: (state, action) => {\n const colId = action.payload;\n state.collocutors.some(c => {\n if (c.id == colId) {\n c.ready = false;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_offline', {detail: {collocutor: proxy2obj(c)}}));\n return true;\n }\n });\n },\n toggle_messenger: (state, action) => {\n const colId = action.payload;\n let needCloseOthers = false;\n state.collocutors.some(c => {\n if (c.id == colId) {\n needCloseOthers = !c.opened;\n return true;\n }\n });\n state.collocutors.forEach(c => {\n if (c.id == colId) {\n c.opened = !c.opened;\n if (c.opened) {\n c.unread = false;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_open', {detail: {collocutor: proxy2obj(c)}}));\n } else {\n ui_emitter.dispatchEvent(new CustomEvent('messenger_close', {detail: {collocutor: proxy2obj(c)}}));\n }\n } else {\n // close all others\n if (needCloseOthers && c.opened) {\n c.opened = false;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_close', {detail: {collocutor: proxy2obj(c)}}));\n }\n }\n });\n },\n close_messenger: (state, action) => {\n const colId = action.payload;\n state.collocutors.some(c => {\n if (c.id == colId) {\n c.opened = false;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_close', {detail: {collocutor: proxy2obj(c)}}));\n return true;\n }\n })\n },\n add_to_bar: (state, action) => {\n const colId = action.payload;\n state.collocutors.some(c => {\n if (c.id == colId) {\n c.bar = true;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_add_to_bar', {detail: {collocutor: proxy2obj(c)}}));\n return true;\n }\n })\n },\n hide_from_bar: (state, action) => {\n const colId = action.payload;\n state.collocutors.some(c => {\n if (c.id == colId) {\n c.unred = false;\n c.bar = false;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_hide_from_bar', {detail: {collocutor: proxy2obj(c)}}));\n return true;\n }\n })\n },\n history: (state, action) => {\n const { collocutorId, messages } = action.payload;\n state.collocutors.some(c => {\n if (c.id == collocutorId) {\n c.messages = messages;\n c.unread = !c.opened;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_clear_messages', {detail: {collocutor: proxy2obj(c)}}));\n messages.forEach(message => {\n ui_emitter.dispatchEvent(new CustomEvent('messenger_message', {detail: {collocutor: proxy2obj(c), message, muted: true}}));\n });\n return true;\n }\n });\n },\n message: (state, action) => {\n const { collocutor, message } = action.payload;\n state.collocutors.some(c => {\n if (c.id == collocutor.id) {\n c.messages.push(message);\n c.unread = !c.opened;\n c.bar = true;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_message', {detail: {collocutor: proxy2obj(c), message, muted: state.muted}}));\n return true;\n }\n });\n },\n messenger_unread: (state, action) => {\n const { collocutorId, unread } = action.payload;\n state.collocutors.some(c => {\n if (c.id == collocutorId) {\n c.unread = unread;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_unread', {detail: {collocutor: proxy2obj(c)}}));\n return true;\n }\n });\n },\n toggle_chatters_list: (state) => {\n state.opened = !state.opened;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_toggle_chatters_list', {detail: {opened: state.opened}}));\n },\n open_chatters_list: (state) => {\n state.opened = true;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_toggle_chatters_list', {detail: {opened: state.opened}}));\n },\n close_chatters_list: (state) => {\n state.opened = false;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_toggle_chatters_list', {detail: {opened: state.opened}}));\n },\n toggle_mute: (state) => {\n state.muted = !state.muted;\n ui_emitter.dispatchEvent(new CustomEvent('messenger_toggle_mute', {detail: {muted: state.muted}}));\n },\n }\n });\n\n const reducer = RTK.combineReducers({\n performers: performers.reducer, // all performers\n performer: performer.reducer, // current performer,\n chat: chat.reducer,\n pledgeBids: pledgeBids.reducer,\n user: user.reducer,\n hiddenCamAccess: hiddenCamAccess.reducer,\n messenger: messenger.reducer,\n });\n\n const store = RTK.configureStore({reducer: reducer});\n\n const initSubscriber = initReduxSubscriber();\n const subscribe = initSubscriber(store);\n\n subscribe('performer.vibratip', state => {\n console.log('rs performer.vibratip', state.performer.vibratip);\n ui_emitter.dispatchEvent(new CustomEvent('performer_vibratip', {detail: {performer: state.performer}}));\n });\n\n subscribe('performer.status', state => {\n const { performer, chat, hiddenCamAccess } = state;\n console.log('rs performer.status', performer.status);\n let camAccess = false;\n const room = chat.room;\n const hca = hiddenCamAccess;\n if (room in hca) camAccess = hca[room].allowed;\n const detail = { performer, camAccess };\n ui_emitter.dispatchEvent(new CustomEvent('chat_' + chat.type + '_performer_' + performer.status, {detail}));\n });\n\n subscribe('performer.streams', state => {\n ui_emitter.dispatchEvent(new CustomEvent('performer_streams', {detail: {performer: state.performer}}));\n });\n\n subscribe('chat.app_panel', state => {\n ui_emitter.dispatchEvent(new CustomEvent('app_panel', {detail: {app_panel: state.chat.app_panel}}));\n });\n\n subscribe('chat.usersUpdateCount', state => {\n const { users, usersUpdateTimeout } = state.chat;\n sendEventChatUsersList(users.slice(), usersUpdateTimeout);\n });\n\n subscribe('chat.topic', state => {\n const { topic } = state.chat;\n ui_emitter.dispatchEvent(new CustomEvent('topic', {detail: {topic}}));\n });\n\n subscribe('user.tokens', state => {\n const { tokens } = state.user;\n ui_emitter.dispatchEvent(new CustomEvent('user_tokens_left', {detail: {tokens}}));\n });\n\n subscribe('hiddenCamAccess', state => {\n const { hiddenCamAccess, chat, performer } = state;\n let camAccess = false;\n if (chat.room && chat.room in hiddenCamAccess) camAccess = hiddenCamAccess[chat.room].allowed;\n ui_emitter.dispatchEvent(new CustomEvent('performer_hidden_cam_access', {detail: {performer, camAccess}}));\n });\n\n subscribe('messenger', state => {\n let haveUnread = false;\n // save messenger state\n const save = Object.assign({}, state.messenger);\n save.collocutors.forEach(c => {\n c.messages = [];\n c.ready = false;\n if (c.unread) haveUnread = true;\n });\n save.save_time = new Date().getTime();\n save.save_user_id = state.user.id;\n localStorageSet('messenger', save);\n ui_emitter.dispatchEvent(new CustomEvent('messenger_have_any_unread', {detail: {unread: haveUnread}}));\n });\n\n return {\n store,\n subscribe,\n // slices:\n performers,\n performer,\n chat,\n pledgeBids,\n user,\n hiddenCamAccess,\n messenger,\n };\n}\n", "// https://stackoverflow.com/questions/22186467/how-to-use-javascript-eventtarget\nfunction Emitter() {\n var eventTarget = document.createDocumentFragment();\n var dispatchCallbacks = [];\n\n function delegate(method) {\n this[method] = eventTarget[method].bind(eventTarget)\n }\n\n [\n 'addEventListener',\n //'dispatchEvent',\n 'removeEventListener'\n ].forEach(delegate, this);\n\n this.dispatch = (eventName, detail) => {\n let event = new CustomEvent(eventName, {detail});\n eventTarget.dispatchEvent(event);\n dispatchCallbacks.forEach(func => {\n func(event);\n })\n };\n\n this.dispatchEvent = (event) => {\n eventTarget.dispatchEvent(event);\n dispatchCallbacks.forEach(func => {\n func(event);\n })\n };\n\n\n this.catchAllDispatchEvents = (callback) => {\n dispatchCallbacks.push(callback);\n }\n}\n\n\nexport function ChatApiEmitter() {\n Emitter.call(this)\n}\n\n\n\nconst genderList = {\n 1: 'Male',\n 2: 'Female',\n 3: 'Tranny'\n};\n\nexport function parsePerformer(rawPerformer, serverTime) {\n let performer = Object.assign({}, rawPerformer);\n\n performer.id = parseInt(performer.id);\n performer.modelCategories = [];\n if (performer.filterData) {\n if (performer.filterData instanceof Array) {\n performer.modelCategories = performer.filterData;\n } else if (performer.filterData instanceof String) {\n performer.modelCategories = performer.filterData.split(',');\n }\n }\n let intBlockedLocations = performer.blocked_locations ? parseBlockedLocations(performer.blocked_locations) : [];\n for (let i = 0; i < intBlockedLocations.length; i++) {\n intBlockedLocations[i] = parseInt(intBlockedLocations[i]);\n }\n performer.blocked_locations = intBlockedLocations;\n performer.country = parseInt(performer.country);\n performer.score = parseInt(performer.score);\n performer.age = parseInt(performer.age);\n performer.region = parseInt(performer.region);\n performer.nationality = parseInt(performer.nationality);\n let langs = [];\n if (performer.language && !(performer.language instanceof Array)) {\n const strLangs = performer.language.replace(/^\\<|\\>$/g, '');\n langs = strLangs.split('><').map(lng => parseInt(lng, 10));\n }\n performer.language = langs;\n performer.is_new = performer.is_new ? 1 : 0;\n performer.is_test_model = performer.hidden ? 1 : 0;\n if (!isNaN(performer.gender)) performer.gender = genderList[performer.gender];\n //performer.isHiddenByFilter = performer.isHiddenByFilter || false;\n performer.true_private_setting = performer.truePrivateChat || performer.true_private_setting || false;\n performer.vibratip = performer.vibratip || performer.vibraTip || performer.vibratip_setting || false;\n\n let photo = false;\n if (performer.isPhoto === true || performer.isPhoto === 1 || performer.isPhoto === 'true' || performer.isPhoto === '1') {\n photo = true;\n }\n if (performer.photo === true || performer.photo === 1 || performer.photo === 'true' || performer.photo === '1') {\n photo = true;\n }\n performer.photo = photo;\n\n performer.public_room = performer.public_room || performer.public_chat_info.room;\n\n // console.log('parsePerformer result', performer);\n\n // set stream profile id\n // also in presence-channel:onPresenceAddStream\n if (performer.streams) {\n performer.streams.forEach(stream => fixStreamProfilesId(stream));\n } else {\n performer.streams = [];\n }\n\n fixPledgeEndTime(performer.pledge_configuration, serverTime);\n\n return performer;\n}\n\nfunction parseBlockedLocations(bl) {\n if (bl instanceof Array) {\n return bl;\n } else if (bl) {\n const list = [];\n bl.split(',').forEach(v => {\n list.push(parseInt(v, 10));\n });\n return list;\n } else {\n return [];\n }\n}\n\nexport function fixStreamProfilesId(stream) {\n if (stream && stream.profiles) {\n stream.profiles.forEach((profile, idx) => {\n // add id (key) for all profiles\n profile.id = profile.type + ':' + profile.title + ':' + idx;\n })\n }\n}\n\n\nexport function fixPledgeEndTime(pledgeConfiguration, serverTime) {\n if (!pledgeConfiguration) return;\n if (pledgeConfiguration._endTimeFixed) return;\n if (!serverTime) return;\n const timeDiff = (new Date().getTime() / 1000) - serverTime;\n pledgeConfiguration.end_time += timeDiff;\n pledgeConfiguration._endTimeFixed = true;\n}\n\nexport function exponentialBackoff(toTry, max, delay, callback) {\n console.log('max', max, 'next delay', delay);\n var result = toTry();\n\n if (result) {\n callback(result);\n } else {\n if (max > 0) {\n return setTimeout(function () {\n exponentialBackoff(toTry, --max, delay * 2, callback);\n }, delay);\n\n } else {\n console.log('we give up');\n }\n }\n}\n\n\n\nexport function createConsoleLogger(enable, prefix) {\n return enable ? {\n log(...args) {\n args.unshift(prefix);\n console.log(...args);\n },\n info(...args) {\n args.unshift(prefix);\n console.info(...args);\n },\n warn(...args) {\n args.unshift(prefix);\n console.warn(...args);\n },\n error(...args) {\n args.unshift(prefix);\n console.error(...args);\n },\n debug(...args) {\n args.unshift(prefix);\n console.debug(...args);\n },\n group(...args) {\n args.unshift(prefix);\n console.group(...args);\n },\n groupCollapsed(...args) {\n args.unshift(prefix);\n console.groupCollapsed(...args);\n },\n groupEnd(...args) {\n console.groupEnd(...args);\n },\n trace(...args) {\n args.unshift(prefix);\n console.trace(...args);\n }\n } : {\n log() {},\n info() {},\n warn() {},\n error() {},\n debug() {},\n group() {},\n groupCollapsed() {},\n groupEnd() {},\n trace() {},\n };\n}\n", "import { parsePerformer, fixStreamProfilesId, fixPledgeEndTime } from './utils.js';\n\nexport function PresenceChannel(config, ws_emitter, ui_emitter, storeController) {\n\n ws_emitter.addEventListener('presence_login_success', event => {\n const { user } = event.detail;\n console.log('onPresenceLoginSuccess', user);\n storeController.store.dispatch(storeController.user.actions.update_user_from_chat_server(user));\n });\n\n ws_emitter.addEventListener('presence_login_error', event => {\n const data = event.detail;\n console.error('onPresenceLoginError', data);\n sentryCaptureMessage('presence_login_error', data);\n });\n\n ws_emitter.addEventListener('presence_login_timeout', event => {\n console.warn('onPresenceLoginTimeout', event.detail.error_message);\n });\n\n ws_emitter.addEventListener('presence_performers', event => {\n let performers = event.detail.performers;\n performers = performers.map(p => parsePerformer(p, event.detail.server_time));\n storeController.store.dispatch(storeController.performers.actions.receive_performers(performers));\n window.FWC.messenger.restartIfNeeded();\n });\n\n ws_emitter.addEventListener('presence_join_performer', event => {\n const performer = parsePerformer(event.detail.user, event.detail.server_time);\n storeController.store.dispatch(storeController.performers.actions.performer_join(performer));\n });\n\n ws_emitter.addEventListener('presence_leave_performer', event => {\n storeController.store.dispatch(storeController.performers.actions.performer_leave(event.detail));\n });\n\n ws_emitter.addEventListener('presence_change_status_performer', event => {\n storeController.store.dispatch(storeController.performers.actions.performer_change_status(event.detail));\n });\n\n ws_emitter.addEventListener('presence_vibratip_setting', event => {\n storeController.store.dispatch(storeController.performers.actions.performer_change_vibratip(event.detail));\n });\n\n ws_emitter.addEventListener('presence_true_private_setting', event => {\n storeController.store.dispatch(storeController.performers.actions.performer_true_private_setting(event.detail));\n });\n\n ws_emitter.addEventListener('presence_add_stream', event => {\n const user_id = event.detail.user_id;\n const stream = event.detail.stream_config;\n fixStreamProfilesId(stream);\n storeController.store.dispatch(storeController.performers.actions.performer_add_stream({user_id, stream}));\n });\n\n ws_emitter.addEventListener('presence_delete_stream', event => {\n const user_id = event.detail.user_id;\n const stream_id = event.detail.stream_id;\n storeController.store.dispatch(storeController.performers.actions.performer_delete_stream({user_id, stream_id}));\n if (user_id == null && stream_id == null) {\n // delete all streams for all performers\n storeController.store.dispatch(storeController.performers.actions.all_performers_delete_streams());\n }\n });\n\n ws_emitter.addEventListener('presence_answer_private_chat_invitation', event => {\n const accepted = event.detail.accepted;\n const performer = event.detail.user;\n if (!accepted) ui_emitter.dispatchEvent(new CustomEvent('performer_private_show_decline', {detail: {performer}}));\n });\n\n ws_emitter.addEventListener('presence_user_account_info', event => {\n // tokens, tier_level, displayname\n const info = event.detail.account_info;\n if ('tokens' in info) {\n window.FWC.updateUserTokens(info.tokens);\n }\n if ('tier_level' in info) {\n window.FWC.updateUserTierLevel(info.tier_level);\n }\n });\n\n ws_emitter.addEventListener('presence_my_pledge_bids', event => {\n const myBids = {};\n const { pledge_bids } = event.detail;\n if (pledge_bids) {\n for (let i=0; i {\n const { user_id, tokens, tokens_left } = event.detail;\n window.FWC.updateUserTokens(tokens_left);\n storeController.store.dispatch(storeController.pledgeBids.actions.pledgeBidAdded({user_id, tokens}));\n });\n\n ws_emitter.addEventListener('presence_pledge_bid_error', event => {\n const { user_id, error_message } = event.detail;\n console.error(error_message);\n sentryCaptureMessage('presence_pledge_bid_error', event.detail);\n });\n\n ws_emitter.addEventListener('presence_pledge_bid_refund', event => {\n const { user_id, tokens } = event.detail;\n const { user } = storeController.store.getState();\n const newTokens = user.tokens + tokens;\n window.FWC.updateUserTokens(newTokens);\n });\n\n ws_emitter.addEventListener('presence_im_chat_info', event => {\n const { im_chat_info, collocutor, initiator_id } = event.detail;\n window.FWC.messenger.onImChatInfo(im_chat_info, collocutor, initiator_id);\n });\n\n}\n", "const timers = {};\n\nconst timerCheckerStart = {\n ws_new_connection: [\n () => createTimerChecker('ws_new_connection_t1', 'ws_new_connection_timeout_', 1000),\n () => createTimerChecker('ws_new_connection_t2', 'ws_new_connection_timeout_', 1500),\n () => createTimerChecker('ws_new_connection_t3', 'ws_new_connection_timeout_', 2000),\n ],\n chat_login: [\n () => createTimerChecker('chat_login_t1', 'chat_login_timeout_', 1000),\n () => createTimerChecker('chat_login_t2', 'chat_login_timeout_', 1500),\n () => createTimerChecker('chat_login_t3', 'chat_login_timeout_', 2000),\n ],\n chat_get_history: [\n () => createTimerChecker('chat_get_users_t1', 'chat_get_users_timeout_', 1000),\n () => createTimerChecker('chat_get_users_t2', 'chat_get_users_timeout_', 1500),\n () => createTimerChecker('chat_get_users_t3', 'chat_get_users_timeout_', 2000),\n ],\n};\n\nconst timerCheckerFinish = {\n ws_connected: ['ws_new_connection_t1', 'ws_new_connection_t2', 'ws_new_connection_t3'],\n ws_disconnected: ['ws_new_connection_t1', 'ws_new_connection_t2', 'ws_new_connection_t3'],\n chat_login_success: ['chat_login_t1', 'chat_login_t2', 'chat_login_t3'],\n chat_login_error: ['chat_login_t1', 'chat_login_t2', 'chat_login_t3'],\n chat_get_users_success: ['chat_get_users_t1', 'chat_get_users_t2', 'chat_get_users_t3'],\n};\n\n\nclass GrayLog {\n constructor() {\n this.user = null;\n this.session = Math.random().toString(36).substring(2, 15);\n this.sequence = 1; // log messages sequence number\n this.enabled = false;\n this.url = '';\n }\n init(enabled, url) {\n this.enabled = enabled;\n this.url = url;\n }\n getSession() {\n return this.session;\n }\n setUser(user) {\n this.user = user;\n }\n log(message, options) {\n this._sendData('log', message, options);\n }\n warning(message, options) {\n this._sendData('warning', message, options);\n }\n _sendData(type, message, options) {\n if (!this.enabled) return;\n\n const url = this.url + 'log/' + type + '/' + message;\n\n const data = {\n full_message: message,\n _session: this.session,\n _sequence: this.sequence++,\n _user_id: this.user ? this.user.id : null,\n //_mobile: config.isMobile,\n _url: location.href,\n };\n\n if (options && 'ws_connection_time' in options) {\n data._ws_connection_time = options.ws_connection_time;\n }\n\n const params = {\n method: 'POST',\n headers: {\n 'Content-type': 'application/json; charset=UTF-8'\n },\n body: JSON.stringify(data),\n };\n\n console.log('gray_log', message, data);\n\n // stop timers if event finished\n if (timerCheckerFinish[message]) {\n timerCheckerFinish[message].forEach(timerKey => {\n clearTimeout(timers[timerKey])\n })\n }\n\n // start timers to check for event not ready in long time\n if (timerCheckerStart[message]) {\n timerCheckerStart[message].forEach(timerFunc => {\n timerFunc();\n });\n }\n\n fetch(url, params);\n }\n}\n\n\nconst grayLog = new GrayLog();\n//grayLog.setUser(config.user);\n\nexport default grayLog;\n\n\nfunction createTimerChecker(timerName, message, timeout) {\n if (timers[timerName]) {\n clearTimeout(timers[timerName]);\n }\n\n timers[timerName] = setTimeout(() => {\n grayLog.warning(message + timeout)\n }, timeout);\n}\n", "import grayLog from './graylog.js';\n\nexport function ChatChannel(config, edgeConnection, ws_emitter, storeController) {\n\n const currentRoom = () => storeController.store.getState().chat.room;\n\n ws_emitter.addEventListener('topic', event => {\n if (event.detail.room != currentRoom()) return;\n storeController.store.dispatch(storeController.chat.actions.topic(event.detail.message))\n });\n\n ws_emitter.addEventListener('history', event => {\n if (event.detail.room != currentRoom()) return;\n storeController.store.dispatch(storeController.chat.actions.history(event.detail.messages))\n });\n\n ws_emitter.addEventListener('message', event => {\n if (event.detail.room != currentRoom()) return;\n const message = event.detail.message;\n if ('content' in message) message.content = getFixedMessageText(message.content);\n storeController.store.dispatch(storeController.chat.actions.message(message));\n });\n\n ws_emitter.addEventListener('clear_messages', event => {\n console.log('clear_messages', event.detail);\n if (event.detail.room != currentRoom()) return;\n storeController.store.dispatch(storeController.chat.actions.clear_messages());\n });\n\n ws_emitter.addEventListener('clear_user_messages', event => {\n console.log('clear_user_messages', event.detail);\n if (event.detail.room != currentRoom()) return;\n const user = storeController.store.getState().user;\n const clear_name = event.detail.user_displayname;\n if (user.usename != clear_name && user.displayname != clear_name) {\n storeController.store.dispatch(storeController.chat.actions.clear_user_messages(clear_name));\n }\n });\n\n ws_emitter.addEventListener('app_panel', event => {\n const { panel, room } = event.detail;\n if (room != currentRoom()) return;\n const { user } = storeController.store.getState();\n if (!panel) {\n storeController.store.dispatch(storeController.chat.actions.app_panel({panel: null}));\n } else if (panel.cbp && !panel.personal && user && user.level !== 'guest') {\n edgeConnection.send({action: 'get_app_panel', room });\n } else {\n storeController.store.dispatch(storeController.chat.actions.app_panel({panel}));\n }\n });\n\n ws_emitter.addEventListener('app_hidden_cam_access', event => {\n storeController.store.dispatch(storeController.hiddenCamAccess.actions.update_access(event.detail));\n });\n\n ws_emitter.addEventListener('tokens_left', event =>\n window.FWC.updateUserTokens(event.detail.tokens_left)\n );\n\n ws_emitter.addEventListener('users', event => {\n const {room, users, virtual_users} = event.detail;\n if (room != currentRoom()) return;\n grayLog.log('chat_get_users_success');\n for (let i = 0; i < virtual_users; i++) {\n const virtualName = 'Guest' + Math.floor(Math.random() * 10000 + 1);\n const virtualUser = {\n id: 'guid-vu-' + Math.random().toString(36).substring(2, 15),\n username: virtualName,\n displayname: virtualName,\n gender: 'Male',\n level: 'guest',\n photo: false,\n color: '000000',\n };\n users.push(virtualUser);\n }\n storeController.store.dispatch(storeController.chat.actions.users(users));\n });\n\n ws_emitter.addEventListener('join', event => {\n if (event.detail.room != currentRoom()) return;\n storeController.store.dispatch(storeController.chat.actions.join(event.detail.user))\n });\n\n ws_emitter.addEventListener('leave', event =>\n storeController.store.dispatch(storeController.chat.actions.leave(event.detail.user))\n );\n\n\n const maxWordLength = 25; // max word length in chars, to split too long words\n\n function splitLongWords(str, length, splitWith = '') {\n let words = str.split(' ');\n for (let j = 0; j < words.length; j++) {\n let l = words[j].length;\n if (l > length) {\n let result = [], i = 0;\n while (i < l) {\n result.push(words[j].substr(i, length));\n i += length;\n }\n words[j] = result.join(splitWith);\n }\n }\n return words.join(' ');\n }\n\n function getFixedMessageText(text) {\n let fixed = '' + text;\n // remove tags\n fixed = fixed.replace(/<\\/?[^>]+>/gi, '');\n if (!fixed) return '';\n\n // remove links and sitenames from message\n fixed = fixed.replace(/(?:https?|ftp):\\/\\/[\\n\\S]+/g, '');\n if (!fixed) return '';\n fixed = fixed.replace(/(?:www\\.)[\\n\\S]+/g, '');\n if (!fixed) return '';\n\n // slit long words\n fixed = splitLongWords(fixed, maxWordLength);\n if (!fixed) return '';\n\n return fixed.trim();\n }\n\n}\n", "import grayLog from './graylog.js';\n\nlet instance_id = '';\n\nexport class EdgeConnection {\n\n constructor(ws_emitter) {\n this.ws_emitter = ws_emitter;\n this.pending = [];\n console.log('edgeConnection', this);\n this.hsm = null; // main chat hsm\n this.imHSMs = []; // instant messenger hsms\n }\n\n send(message) {\n console.warn('edgeConnection pending send', this, message);\n this.pending.push(message);\n }\n\n attach_transport() {\n while (this.pending.length) {\n let msg = this.pending.shift();\n console.log('send pending', msg);\n this.emit(msg);\n }\n this.send = (message) => this.emit(message);\n }\n\n emit(data) {\n this.connection.send(JSON.stringify(data));\n console.debug(instance_id + 'WS SEND >>> ', JSON.stringify(data));\n }\n\n close() {\n if (this.connection) {\n this.connection.onerror = null;\n this.connection.onclose = null;\n this.connection.onmessage = null;\n this.connection.onopen = null;\n this.connection.close()\n }\n }\n\n init_connection(connection_string) {\n console.info(instance_id + 'new WebSocket()', connection_string);\n grayLog.log('ws_new_connection');\n this.connection = new WebSocket(connection_string);\n this.connection.startDate = new Date();\n this.connection.onerror = this.onerror.bind(this);\n this.connection.onclose = this.onclose.bind(this);\n this.connection.onmessage = this.onmessage.bind(this);\n this.connection.onopen = this.onopen.bind(this);\n }\n\n onerror(event) {\n console.log(instance_id + 'WS onerror', event);\n clearInterval(this.presence_ping_interval);\n this.hsm.dispatch('ws_error', [event.toString()]);\n };\n\n onclose(event) {\n console.log(instance_id + 'WS onclose', event);\n clearInterval(this.presence_ping_interval);\n grayLog.log('ws_disconnected');\n this.hsm.dispatch('ws_closed', [event.toString()]);\n };\n\n onmessage(event) {\n let ws_msg = JSON.parse(event.data);\n // ws_msg['instance_id'] = instance_id;\n console.debug(instance_id + 'WS RECV <<<<', ws_msg);\n if (ws_msg.action) {\n //\n // if(ws_msg.action.startsWith('presence_')){\n //\n // }\n\n if (ws_msg.room && (ws_msg.room.indexOf('im_model_') !== -1 || ws_msg.room.indexOf('im_admin_') !== -1)) {\n // messenger\n const targetHSM = this.imHSMs.find(hsm => hsm.room === ws_msg.room);\n if (targetHSM) {\n targetHSM.dispatch(`sio_${ws_msg.action}`, [ws_msg]);\n } else {\n console.warn(instance_id + 'unknown messenger room', ws_msg)\n }\n } else {\n // chat\n this.hsm.dispatch(ws_msg.action,[ws_msg]);\n }\n\n this.ws_emitter.dispatch(ws_msg.action, ws_msg);\n } else {\n console.warn(instance_id + 'unknown message', ws_msg);\n }\n };\n\n start_presence_pings() {\n this.presence_ping_interval = setInterval(() => {\n this.emit({\n action: 'presence_ping'\n });\n }, 10 * 1000);\n }\n\n onopen(event) {\n console.log(instance_id + 'WS onopen', event);\n let ws_connection_time = (new Date() - this.connection.startDate) / 1000;\n ws_connection_time = Math.round(ws_connection_time * 100) / 100;\n grayLog.log('ws_connected', {ws_connection_time});\n this.hsm.dispatch('ws_connected', [event.toString()]);\n this.start_presence_pings();\n this.attach_transport();\n };\n\n /*\n websocket readyState\n 0 CONNECTING \u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0435\u0449\u0451 \u043D\u0435 \u043E\u0442\u043A\u0440\u044B\u0442\u043E.\n 1 OPEN \u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043E\u0442\u043A\u0440\u044B\u0442\u043E \u0438 \u0433\u043E\u0442\u043E\u0432\u043E \u043A \u043E\u0431\u043C\u0435\u043D\u0443 \u0434\u0430\u043D\u043D\u044B\u043C\u0438.\n 2 CLOSING \u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0432 \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0435 \u0437\u0430\u043A\u0440\u044B\u0442\u0438\u044F.\n 3 CLOSED \u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0437\u0430\u043A\u0440\u044B\u0442\u043E \u0438\u043B\u0438 \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u043E\u0442\u043A\u0440\u044B\u0442\u044C\u0441\u044F.\n */\n is_connected_to(connection_string) {\n return this.connection\n && this.connection.url === connection_string\n && this.connection.readyState === 1;\n }\n\n connect_to(connection_string) {\n if (this.connection\n && this.connection.url === connection_string\n && this.connection.readyState === 0\n ) {\n console.log('already connecting to:', connection_string);\n } else {\n this.close();\n this.init_connection(connection_string);\n }\n }\n\n attach_hsm(hsm) {\n this.hsm = hsm;\n }\n\n attach_im_hsm(hsm) {\n this.imHSMs.push(hsm);\n }\n}\n", "// https://github.com/DavidDurman/statechart/blob/master/lib/statechart.js\n// modified version\n//\n// Copyright (c) 2010 David Durman\n//\n// The contents of this file are subject to the MIT License (the \"License\");\n// you may not use this file except in compliance with the License. You may obtain a copy of the License at\n// http://opensource.org/licenses/MIT.\n//\n// This hierarchical state machine implementation has been inspired\n// by the QP active object framework, see http://www.state-machine.com/\n\n\nexport default function factory(){\n\n \"use strict\";\n\n var assert = function(assertion){\n if (!assertion) {\n throw new Error(\"Assertion failed.\");\n }\n };\n\n var events_queue = [];\n\n // Statechart.\n // -----------\n\n // `myState` - the current state\n // `mySource` - the source of the current transition\n\n var Statechart = {\n\n run: function(opt){\n opt = opt || {};\n this.debug = opt.debug ? opt.debug : function(){};\n this.log = opt.log ? opt.log : function(){};\n this.construct(this.initialState);\n this.init(null);\n },\n\n construct: function(initialState){\n this.myState = this.top();\n this.mySource = this.state(\"Initial\");\n\n // Initial pseudo-state\n this.states.Initial = {\n empty: function(){\n this.newInitialState(initialState);\n }\n };\n var handled = function(){ return null; };\n\n // TOP state\n this.states.TOP = {\n entry: handled,\n exit: handled,\n init: handled,\n empty: handled\n };\n this.flatten();\n },\n\n // Trigger the initial transition and recursively enter the submachine of the top state.\n // Must be called only once for a given Statechart before dispatching any events to it.\n init: function(anEventOrNull){\n assert(this.myState === this.top() && this.mySource !== null);\n var s = this.myState; // save top in temp\n this.mySource.trigger(anEventOrNull); // topmost initial transition\n assert(s.equals(this.myState.superstate())); // verify that we only went one level deep\n s = this.myState;\n s.enter();\n while (s.init() === null) { // while init is handled (i.e. till we reach a leaf node)\n assert(s.equals(this.myState.superstate())); // verify that we only went one level deep\n s = this.myState;\n s.enter();\n }\n },\n\n state: function(stateOrName){\n return (stateOrName && stateOrName instanceof QState) ? stateOrName : new QState(this, stateOrName);\n },\n\n top: function(stateOrName){\n // create the top state only once and store it to an auxiliary property\n return (this._topState || (this._topState = new QState(this, \"TOP\")));\n },\n\n currentState: function(){\n return this.myState;\n },\n\n flatten: function(){\n this.statesTable = this.statesTable || {};\n this._flatten(this.states, this.top().name);\n },\n\n _flatten: function(states, parent){\n if (!states) {\n return;\n }\n\n for (var state in states) {\n if (states.hasOwnProperty(state)) {\n this.statesTable[state] = states[state];\n this.statesTable[state].parent = parent;\n this._flatten(states[state].states, state);\n }\n }\n },\n\n selectState: function(stateName){\n return this.statesTable[stateName];\n },\n\n dispatchEvent: function(anEvent, state, act){\n act = act || state[anEvent.type];\n\n // Action might also be an array in which case it is assumed that evaluating guards decides\n // which target to enter.\n if (act instanceof Array) {\n for (var i = 0; i < act.length; i++) {\n this.dispatchEvent(anEvent, state, act[i]);\n }\n }\n\n // @todo This is terrible edge case used just for more fancy Statechart representation\n // It allows using \"MyState\": { init: \"MySubState\", ... } intead of\n // \"MyState\": { init: function(){ this.newInitialState(\"MySubState\"); }, ... }\n // In some cases the latter form can be useful for better control of the Statechart\n if (anEvent.type === \"init\" && typeof act === \"string\") {\n this.newInitialState(act);\n return null; // handled\n }\n\n if (act instanceof Function){\n try {\n var new_state = act.apply(this, anEvent.args);\n } catch (err) {\n console.warn('error in HSM', err);\n this.log(err,anEvent);\n var broken_evt = events_queue.shift();\n events_queue.unshift(new QEvent('exception', [err,broken_evt]));\n events_queue.unshift(QEventEmpty);\n }\n if (typeof new_state === \"string\" || new_state instanceof String) {\n this.newState(new_state);\n }\n return null; // handled\n } else if (act) {\n // no guard at all or the guard condition is met\n if (!act.guard || (act.guard && act.guard.call(this, anEvent.args))){\n if (act.action) {\n act.action.call(this, anEvent.args);\n }\n if (act.target) {\n this.newState(act.target);\n }\n return null; // handled\n }\n } else { // act is undefined (no handler in state for anEvent)\n if (state === this.selectState(\"TOP\")) {\n this.handleUnhandledEvent(anEvent); // not-handled\n return null; // handled (TOP state handles all events)\n }\n }\n return this.state(state.parent); // not-handled\n },\n\n // Override this when needed.\n handleUnhandledEvent: function(anEvent){\n this.debug(\"Unhandled event: \" + anEvent.type, anEvent);\n return null;\n },\n\n // Traverse the state hierarchy starting from the currently active state myState.\n // Advance up the state hierarchy (i.e., from substates to superstates), invoking all\n // the state handlers in succession. At each level of state nesting, it intercepts the value\n // returned from a state handler to obtain the superstate needed to advance to the next level.\n dispatch: function(anEvent, args){\n\n if (!anEvent || !(anEvent instanceof QEvent)) {\n anEvent = new QEvent(anEvent, args);\n }\n this.debug(\"Dispatch Event << \" + anEvent.type);\n events_queue.push(anEvent);\n if (events_queue.length > 1) return;\n while (events_queue.length) {\n var qevent = events_queue[0];\n this.mySource = this.myState;\n while (this.mySource) {\n this.mySource = this.mySource.trigger(qevent);\n }\n events_queue.shift();\n }\n },\n\n // Performs dynamic transition. (macro Q_TRAN_DYN())\n newState: function(aStateName){\n this.transition(this.state(aStateName));\n },\n\n // Used by handlers only in response to the #init event. (macro Q_INIT())\n // USAGE: return this.newInitialState(\"whatever\");\n // @return null for convenience\n\n newInitialState: function(aStateOrName){\n this.myState = this.state(aStateOrName);\n return null;\n },\n\n // Dynamic transition. (Q_TRAN_DYN())\n transition: function(target){\n assert(!target.equals(this.top()));\n\n var entry = [];\n var mySource = this.mySource;\n var s = this.myState;\n\n // exit all the nested states between myState and mySource\n assert(s !== null);\n assert(mySource !== null);\n while (!s.equals(mySource)) {\n s = s.exit() || s.superstate();\n }\n\n // check all seven possible source/target state combinations\n\n entry.push(target);\n\n // (a) mySource == target (self transition)\n if (mySource.equals(target)) {\n mySource.exit();\n return this.enterVia(target, entry);\n }\n\n // (b) mySource == target.superstate (one level deep)\n var p = target.superstate();\n if (mySource.equals(p)) {\n return this.enterVia(target, entry);\n }\n\n assert(mySource !== null);\n\n // (c) mySource.superstate == target.superstate (most common - fsa)\n var q = mySource.superstate();\n if (q.equals(p)) {\n mySource.exit();\n return this.enterVia(target, entry);\n }\n\n // (d) mySource.superstate == target (one level up)\n if (q.equals(target)) {\n mySource.exit();\n entry.pop(); // do not enter the LCA\n return this.enterVia(target, entry);\n }\n\n // (e) mySource == target.superstate.superstate... hierarchy (many levels deep)\n entry.push(p);\n s = p.superstate();\n while (s !== null) {\n if (mySource.equals(s)) {\n return this.enterVia(target, entry);\n }\n\n entry.push(s);\n s = s.superstate();\n }\n\n // otherwise we're definitely exiting mySource\n mySource.exit();\n\n // entry array is complete, save its length to avoid computing it repeatedly\n var entryLength = entry.length;\n\n // (f) mySource.superstate == target.superstate.superstate... hierarchy\n var lca;\n for (lca = entryLength - 1; lca >= 0; lca -= 1) {\n if (q.equals(entry[lca])) {\n return this.enterVia(target, entry.slice(0, lca)); // do not enter lca\n }\n }\n\n // (g) each mySource.superstate.superstate... for each target.superstate.superstate...\n s = q;\n while (s !== null) {\n for (lca = entryLength - 1; lca >= 0; lca -= 1) {\n if (s.equals(entry[lca])) {\n return this.enterVia(target, entry.slice(0, lca)); // do not enter lca\n }\n }\n s.exit();\n s = s.superstate();\n }\n },\n\n // tail of transition()\n // We are in the LCA of mySource and target.\n enterVia: function(target, entry){\n\n // retrace the entry path in reverse order\n var idx = entry.length;\n while (idx > 0) {\n idx--;\n entry[idx].enter();\n }\n\n this.myState = target;\n while (target.init() === null) {\n // initial transition must go one level deep\n assert(target.equals(this.myState.superstate()));\n target = this.myState;\n target.enter();\n }\n }\n };\n\n // QState.\n // -------\n\n function QState(fsm, name){\n this.fsm = fsm;\n this.name = name;\n }\n\n QState.prototype = {\n equals: function(state){\n return (this.name === state.name && this.fsm === state.fsm);\n },\n\n dispatchEvent: function(anEvent, state){\n\n return this.fsm.dispatchEvent(anEvent, state);\n },\n\n trigger: function(anEvent){\n var evt = anEvent || QEventEmpty;\n var state = this.fsm.selectState(this.name);\n return this.dispatchEvent(evt, state);\n },\n\n enter: function(){\n this.fsm.log(\"[\" + this.name + \"] enter\");\n return this.trigger(QEventEntry);\n },\n\n exit: function(){\n this.fsm.log(\"[\" + this.name + \"] exit\");\n return this.trigger(QEventExit);\n },\n\n init: function(){\n this.fsm.log(\"[\" + this.name + \"] init\");\n return this.trigger(QEventInit);\n },\n\n // Answer my superstate. Default is to return fsm top state.\n superstate: function(){\n var superstate = this.trigger(QEventEmpty);\n if (superstate && superstate instanceof QState) {\n return superstate;\n }\n superstate = this.fsm.top();\n if (this.name === superstate.name) {\n return null;\n }\n return superstate;\n }\n };\n\n // QEvent\n // ------\n\n function QEvent(type, args){\n this.type = type;\n this.args = args;\n }\n\n // these events are static, they do not carry any arguments\n // -> create them only once\n // moreover, they don't have to be exposed to the outer world\n var QEventEntry = new QEvent(\"entry\");\n var QEventExit = new QEvent(\"exit\");\n var QEventInit = new QEvent(\"init\");\n var QEventEmpty = new QEvent(\"empty\");\n\n\n return Statechart;\n};\n\n", "import Statechart from './statechart.js';\nimport {\n CHAT_TYPE_OFFLINE, CHAT_TYPE_PUBLIC, CHAT_TYPE_PRIVATE, CHAT_TYPE_SPY, CHAT_TYPE_PLEDGE\n} from './const.js';\nimport {fixPledgeEndTime, exponentialBackoff} from './utils.js';\nimport grayLog from './graylog.js';\n\n\nexport const createChatHSM = (chatObj, ws_emitter, ui_emitter, storeController, chat_server_address) => {\n\n const store = ev => storeController.store.dispatch(ev);\n const ws_send = ev => chatObj.edgeConnection.send(ev);\n let skipFirstTimeGetHistory = true; // do not ask chat messages already rendered in html\n\n return Object.assign({}, Statechart(), {\n chat_target_state: 'NO_CHAT',\n connection_retry_count: 5,\n user_login_info: null,\n presence_login_response: null,\n chatroom_login_action: {\n action: 'login',\n room: undefined, // will be set later with room request\n login_info: {\n uid: undefined, // will be set later with presence_login_success\n cwt: undefined, // will be set later with presence_login_success\n spy: false,\n truePrivateChat: false,\n client_version: 'ws/1'\n }\n },\n pledge_chat_info: null, // room info about active pledge show\n /* ***\n presence_login_success\n presence_login_error\n presence_login_timeout\n presence_performers\n presence_join_performer\n presence_leave_performer\n presence_change_status_performer\n presence_vibratip_setting\n presence_add_stream\n presence_delete_stream\n presence_answer_private_chat_invitation\n presence_private_chat_info\n presence_user_account_info\n presence_my_pledge_bids\n presence_pledge_configuration\n presence_pledge_bid_success\n presence_pledge_bid_error\n presence_pledge_bid_refund\n presence_pledge_chat_info\n */\n\n //\n initialState: 'SUPERSTATE',\n states: {\n SUPERSTATE: {\n init: 'CONNECTING',\n 'user_login_credentials': function (login_info) {\n // that's when API Object sets user credentials\n // for instance after /autoLogin or something similar\n this.user_login_info = login_info;\n console.log('save login info', login_info);\n },\n 'public_chat_login_request': function (chatroom_name) {\n // the only event that UI may post to join public chat,\n // all other chats are activated with some events from presence\n this.chat_target_state = 'PUBLIC';\n this.chatroom_login_action.room = chatroom_name;\n this.chatroom_login_action.login_info.spy = false;\n this.dispatch('chat_login_request');\n },\n 'ws_closed': function () {\n // TODO: what should we do if socket Closed?,\n // when and how exactly that may happen?\n console.warn('what should we do if socket closed?',this.connection_retry_count);\n this.connection_retry_count--;\n this.chat_target_state = 'PUBLIC';\n if (this.connection_retry_count) {\n return 'TRY_RECONNECT_AND_GIVE_UP'\n } else {\n return 'OFFLINE'\n }\n\n },\n 'ws_error': function () {\n // TODO: what should we do if socket \"Errored\"?,\n // when and how exactly that may happen?\n console.warn('what should we do if socket has an error?');\n return 'OFFLINE'\n },\n\n states: {\n OFFLINE: {\n // public_chat: {target: 'PUBLIC'},\n },\n TRY_RECONNECT_AND_GIVE_UP: {\n entry: function () {\n chatObj.messenger.needRestartAfterWsDisconnect = true; // tell messenger to restart after presence_login and presence_performers\n this.back_off_time = 500;\n this.reconnecting = setTimeout(() => {\n chatObj.edgeConnection.connect_to(chat_server_address);\n }, this.back_off_time);\n },\n 'ws_error': function () {\n this.connection_retry_count--;\n this.back_off_time += 1500;\n if (this.connection_retry_count) {\n this.reconnecting = setTimeout(() => {\n chatObj.edgeConnection.connect_to(chat_server_address);\n }, this.back_off_time);\n } else {\n return 'OFFLINE'\n }\n },\n 'ws_closed': function () {\n // this.connection_retry_count--;\n // we ignore closed event while reconnecting\n },\n 'ws_connected': {\n 'target': 'CONNECTED'\n },\n exit: function () {\n clearTimeout(this.reconnecting);\n }\n },\n CONNECTING: {\n entry: function () {\n chatObj.edgeConnection.connect_to(chat_server_address);\n },\n 'ws_connected': {\n 'target': 'CONNECTED'\n },\n states: {}\n },\n CONNECTED: {\n init: 'WAIT_USER_CREDENTIALS',\n entry: function () {\n if (this.user_login_info) {\n this.dispatch('user_login_credentials', [this.user_login_info]);\n }\n },\n states: {\n WAIT_USER_CREDENTIALS: {\n user_login_credentials: function (user_info) {\n ws_send({\n 'action': 'presence_login',\n 'login_info': {\n 'uid': user_info.hash,\n 'cwt': user_info.cwt,\n 'client_version': 'ws/1'\n },\n });\n return 'WAIT_PRESENCE_LOGIN';\n }\n },\n WAIT_PRESENCE_LOGIN: {\n 'presence_login_success': function (presence_login_response) {\n console.info('save presence login', presence_login_response);\n this.presence_login_response = presence_login_response.user;\n this.chatroom_login_action.login_info.uid = presence_login_response.user.uid;\n this.chatroom_login_action.login_info.cwt = presence_login_response.user.cwt;\n\n return 'PRESENCE_READY'\n },\n 'presence_login_error': {\n 'target': 'OFFLINE'\n }\n },\n PRESENCE_READY: {\n init: 'NO_CHAT',\n /*'presence_private_chat_info': function () {\n\n },\n 'performer_start_pledge_show': function () {\n\n },*/\n\n 'chat_login_request': function () {\n // this.chatroom_login_action.room = chatroom_name;\n // this.chatroom_login_action.login_info.spy = spy;\n this.chatroom_login_action.login_info.truePrivateChat = chatObj.getPerformer().true_private_setting;\n console.log('chat_login_request', 'target state=', this.chat_target_state, this.chatroom_login_action);\n ws_send(this.chatroom_login_action);\n grayLog.log('chat_login');\n return 'WAIT_CHAT_LOGIN'\n },\n\n presence_my_pledge_bids: function (data) {\n // check if we have active pledge show running\n const {pledge_bids} = data;\n const performerId = chatObj.getPerformer().id;\n this.pledge_chat_info = null;\n pledge_bids.some(pb => {\n if (pb.user_id == performerId && pb.pledge_chat_info) {\n this.pledge_chat_info = pb.pledge_chat_info;\n return true;\n }\n });\n },\n\n states: {\n NO_CHAT: {\n entry: function () {\n ws_send({ action: 'presence_get_performers' });\n chatObj.messenger.setupAvailabilityPresence();\n if (this.chat_target_state && this.chat_target_state !== 'NO_CHAT') {\n this.dispatch('chat_login_request');\n }\n },\n },\n WAIT_CHAT_LOGIN: {\n entry: function () {\n // this.chat_target_state\n },\n exit: function () {\n\n },\n login_success: function (event) {\n console.log('login_success', event);\n store(storeController.user.actions.update_user_from_chat_server(event.user));\n let cts = this.chat_target_state ;\n // we should always clear target state after leaving WAIT_CHAT_LOGIN\n // because it is one-off action.\n this.chat_target_state = false;\n grayLog.log('chat_login_success');\n return cts;\n },\n login_error: function (event) {\n this.chat_target_state = false;\n grayLog.warning('chat_login_error');\n return 'NO_CHAT'\n },\n\n },\n CHAT: {\n entry: function () {\n // that sets current room in store\n const chatroom_name = this.chatroom_login_action.room;\n store(storeController.chat.actions.room(chatroom_name));\n chatObj.messenger.setupAvailabilityChatRoom(chatroom_name);\n ui_emitter.dispatchEvent(new CustomEvent('chat_connected')); // UI event\n grayLog.log('chat_get_users');\n ws_send({action: 'get_users', room: chatroom_name});\n if (!skipFirstTimeGetHistory) ws_send({action: 'get_history', room: chatroom_name});\n skipFirstTimeGetHistory = false;\n },\n exit: function () {\n store(storeController.chat.actions.type(CHAT_TYPE_OFFLINE));\n ui_emitter.dispatchEvent(new CustomEvent('chat_disconnected'));\n ws_send({action: 'logout', room: chatObj.getRoom()});\n },\n user_return_to_public: function () {\n this.chat_target_state = 'PUBLIC';\n this.chatroom_login_action.login_info.spy = false;\n this.chatroom_login_action.room = chatObj.getPerformer().public_room;\n return 'NO_CHAT';\n },\n chat_stopped: function (event) {\n const {room, message} = event;\n if (message === 'kicked') {\n ui_emitter.dispatchEvent(new Event('chat_user_kick'));\n } else {\n this.chat_target_state = 'PUBLIC';\n this.chatroom_login_action.login_info.spy = false;\n this.chatroom_login_action.room = chatObj.getPerformer().public_room;\n return 'NO_CHAT';\n }\n },\n presence_pledge_configuration: function (data) {\n const {pledge_configuration, user_id, server_time} = data;\n // fix time difference\n fixPledgeEndTime(pledge_configuration, server_time);\n store(storeController.performers.actions.performer_pledge_configuration(data));\n if (!pledge_configuration) {\n store(storeController.pledgeBids.actions.pledgeBidClear(user_id));\n }\n if (user_id == chatObj.getPerformer().id) {\n this.dispatch('performer_pledge_configuration', [pledge_configuration]);\n }\n },\n presence_pledge_chat_info: function (data) {\n const {user_id, pledge_chat_info} = data;\n store(storeController.pledgeBids.actions.pledgeChatInfo({user_id, pledge_chat_info}));\n if (user_id == chatObj.getPerformer().id) {\n const pledge_chat_info = chatObj.getPledgeChatInfo();\n if (pledge_chat_info) {\n this.dispatch('performer_start_pledge_show', [pledge_chat_info])\n }\n }\n },\n states: {\n PUBLIC: {\n init: 'SIMPLE_CHAT',\n entry: function () {\n store(storeController.chat.actions.type(CHAT_TYPE_PUBLIC));\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_public_enter', {detail: {performer}}));\n if (!this.pledge_chat_info) {\n // add camAccess parameter, same as in redux-store.js\n let camAccess = false;\n const { chat, hiddenCamAccess } = storeController.store.getState();\n const room = chat.room;\n const hca = hiddenCamAccess;\n if (room in hca) camAccess = hca[room].allowed;\n const detail = { performer, camAccess };\n // do not stop webcam if user should go to running pledge show\n ui_emitter.dispatchEvent(new CustomEvent('chat_public_performer_' + performer.status, {detail}));\n }\n\n if (this.pledge_chat_info) {\n this.dispatch('performer_start_pledge_show', [this.pledge_chat_info]);\n this.pledge_chat_info = null;\n } else if (performer.pledge_configuration) {\n this.dispatch('performer_pledge_configuration', [performer.pledge_configuration]);\n }\n },\n exit: function () {\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_public_exit', {detail: {performer}}));\n },\n presence_private_chat_info: function (evt) {\n const {private_chat_info, user_id, join_mode} = evt;\n if (join_mode === 'private') {\n this.chat_target_state = 'PRIVATE';\n this.chatroom_login_action.room = private_chat_info.room;\n this.chatroom_login_action.login_info.spy = false;\n return 'NO_CHAT';\n } else if (join_mode === 'spy') {\n this.chat_target_state = 'SPY';\n this.chatroom_login_action.room = private_chat_info.room;\n this.chatroom_login_action.login_info.spy = true;\n return 'NO_CHAT'\n }\n },\n performer_pledge_configuration: function (pledge_configuration) {\n if (pledge_configuration) {\n return pledge_configuration.started ? 'PLEDGE_SHOW' : 'PLEDGE_INIT';\n } else {\n return 'SIMPLE_CHAT';\n }\n },\n performer_start_pledge_show: function (pledge_chat_info) {\n this.chat_target_state = 'PLEDGE';\n this.chatroom_login_action.room = pledge_chat_info.room;\n this.chatroom_login_action.login_info.spy = false;\n return 'NO_CHAT';\n },\n states: {\n SIMPLE_CHAT: {\n entry: function () {\n\n },\n },\n PLEDGE_INIT: {\n entry: function () {\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_public_performer_pledge_init_enter', {detail: {performer}}));\n },\n exit: function () {\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_public_performer_pledge_init_exit', {detail: {performer}}));\n }\n },\n PLEDGE_SHOW: {\n entry: function () {\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_public_performer_pledge_show_enter', {detail: {performer}}));\n },\n exit: function () {\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_public_performer_pledge_show_exit', {detail: {performer}}));\n }\n }\n },\n },\n PRIVATE: {\n entry: function () {\n store(storeController.chat.actions.type(CHAT_TYPE_PRIVATE));\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_private_enter', {detail: {performer}}));\n },\n exit: function () {\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_private_exit', {detail: {performer}}));\n },\n },\n SPY: {\n entry: function () {\n store(storeController.chat.actions.type(CHAT_TYPE_SPY));\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_spy_enter', {detail: {performer}}));\n },\n exit: function () {\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_spy_exit', {detail: {performer}}));\n },\n },\n PLEDGE: {\n entry: function () {\n store(storeController.chat.actions.type(CHAT_TYPE_PLEDGE));\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_pledge_enter', {detail: {performer}}));\n },\n exit: function () {\n const performer = chatObj.getPerformer();\n ui_emitter.dispatchEvent(new CustomEvent('chat_pledge_exit', {detail: {performer}}));\n },\n }\n }\n },\n }\n }\n }\n },\n\n\n }\n }\n },\n });\n\n};\n\n", "import Statechart from './../statechart.js';\nimport { createConsoleLogger } from './../utils.js';\n\nlet counter = 0;\n\nexport function createMessengerConnectionHSM(messengerConn, me, collocutor, edgeConnection) {\n const logger = createConsoleLogger(true, 'IMConnHSM (' + (++counter) + '/' + collocutor.username + '):');\n return Object.assign({}, Statechart(), {\n logger,\n // slots\n login_info: false,\n room: '',\n // machine\n initialState: 'SUPERSTATE',\n states: {\n SUPERSTATE: {\n init: 'OFFLINE',\n entry: function() {\n logger.info('SUPERSTATE entry');\n },\n emit_login: function() {\n logger.info('i want to login... when we are ready');\n this.login_info = ['emit_login'].concat(arguments);\n return 'OPERATIONAL';\n },\n restart: function() {\n logger.info('restart()');\n this.room = '';\n this.login_info = false;\n return 'OPERATIONAL';\n },\n sio_request_error: ({ message }) => {\n logger.error('sio_request_error()', message);\n if (message.indexOf('action [login]') !== -1) {\n //todo, all incoming goes to edgeConnection first\n }\n },\n go_to_offline: { target: 'OFFLINE' },\n states: {\n OFFLINE: {\n entry: function() {\n logger.info('OFFLINE entry');\n },\n go_to_operational: { target: 'OPERATIONAL' }\n },\n OPERATIONAL: {\n entry: function() {\n logger.info('OPERATIONAL entry');\n logger.info('login_info', this.login_info);\n if (this.login_info) this.dispatch.apply(this, this.login_info);\n },\n emit_login: function(imChatInfo) {\n this.login_info = ['emit_login'].concat(arguments);\n this.room = imChatInfo.room;\n logger.log('emit_login', this.login_info, imChatInfo, me);\n edgeConnection.send({\n action: 'login',\n room: imChatInfo.room,\n login_info: {\n uid: me.hash,\n cwt: me.cwt,\n client_version: 'ws/1'\n }\n });\n return 'AUTHENTICATING';\n },\n states: {\n AUTHENTICATING: {\n entry: function() { logger.info('AUTHENTICATING entry'); },\n sio_login_error: function({ message }) {\n messengerConn.onLoginError(message);\n },\n sio_login_success: function(data) {\n logger.log('got login from server', data);\n return 'ONLINE';\n },\n },\n ONLINE: {\n entry: function() {\n logger.log('ONLINE entry');\n messengerConn.onHsmOnlineEnter();\n edgeConnection.send({ action: 'get_history', room: this.room });\n },\n exit: function() {\n logger.log('ONLINE exit');\n messengerConn.onHsmOnlineExit();\n },\n emit_sendMessage: function(message) { edgeConnection.send({ action: 'send_message', room: this.room, message }); },\n sio_history: function({ messages }) { messengerConn.onMessagesList(messages); },\n sio_message: function({ message }) { messengerConn.onNewMessage(message); },\n sio_topic: function() {},\n sio_permissions_on_send_message: function() {},\n sio_join: function({ user, room }) { messengerConn.onPerformerJoin(); },\n sio_leave: function({ user, room }) { messengerConn.onPerformerLeave(); }\n }\n }\n }\n }\n }\n }\n });\n}\n", "import { createMessengerConnectionHSM } from './messenger-connection-hsm.js';\nimport { createConsoleLogger } from './../utils.js';\n\nexport class MessengerConnection {\n\n constructor(messenger, me, collocutor, imChatInfo) {\n this.messenger = messenger;\n this.me = me;\n this.collocutor = collocutor;\n this.imChatInfo = imChatInfo;\n\n const logger = this.logger = createConsoleLogger(true, 'IMConn (' + collocutor.username + '):');\n\n const hsm = this.hsm = createMessengerConnectionHSM(this, me, collocutor, messenger.edgeConnection);\n messenger.edgeConnection.attach_im_hsm(hsm);\n\n this.socket = {};\n this.socket.emit = function(event) {\n logger.log('socket.emit', event, Array.prototype.slice.call(arguments, 1));\n hsm.dispatch.apply(hsm, ['emit_' + event, Array.prototype.slice.call(arguments, 1)]);\n };\n\n const hsmOptions = (true)\n ? { debug:function(event) { hsm.logger.log(event, 'while', this.currentState().name); } }\n : {};\n this.hsm.run(hsmOptions);\n }\n\n login() {\n this.socket.emit('login', this.imChatInfo);\n }\n\n onLoginError(message) {\n this.logger.error('onLoginError()', message);\n }\n\n sendMessage(message) {\n this.logger.log('sendMessage()', message);\n this.socket.emit('sendMessage', message);\n }\n\n onMessagesList(messages) {\n this.logger.log('onMessagesList()', messages);\n this.messenger.onMessagesList(this.collocutor, messages);\n }\n\n onNewMessage(message) {\n this.logger.log('onNewMessage()', message);\n this.messenger.onNewMessage(this.collocutor, message);\n }\n\n onPerformerJoin() {\n this.logger.log('onPerformerJoin()');\n this.messenger.onPerformerJoin(this.collocutor.id);\n }\n\n onPerformerLeave() {\n this.logger.log('onPerformerLeave()');\n this.messenger.onPerformerLeave(this.collocutor.id);\n }\n\n onHsmOnlineEnter() {\n this.logger.log('onHsmOnlineEnter()');\n this.messenger.onConnectionHsmOnlineEnter(this.collocutor);\n }\n\n onHsmOnlineExit() {\n this.logger.log('onHsmOnlineExit()');\n this.messenger.onConnectionHsmOnlineExit(this.collocutor);\n }\n\n restart() {\n this.logger.info('restart()');\n this.hsm.dispatch('restart');\n this.login();\n }\n\n}\n", "import { MessengerConnection } from './messenger-connection.js';\nimport { createConsoleLogger } from './../utils.js';\n\nconst logger = createConsoleLogger(true, 'IM:');\nconst connections = {};\nlet performerInRoom = {};\n\nexport class Messenger {\n\n constructor(storeController, edgeConnection) {\n this.storeController = storeController;\n this.edgeConnection = edgeConnection;\n this.promisesStartIM = {};\n this.needRestartAfterWsDisconnect = false;\n this.needRestartAfterPageReload = true;\n }\n\n getImAvailabilityParam() {\n const {\n user: { isGuest, settings: { s_private_message }, favorites }\n } = this.storeController.store.getState();\n\n let enabled = 0;\n let acceptModelsList = 'none';\n\n if (isGuest) return acceptModelsList;\n\n if (s_private_message == 0) {\n enabled = 1;\n acceptModelsList = 'all'\n } else if (s_private_message == 1) {\n enabled = 1;\n // const allowedPerformers = _uniq([\n // ...friends.map(p => p.id),\n // ...favorites.map(p => p.id)\n // ]);\n acceptModelsList = favorites.map(p => p.id).join(',');\n\n if (acceptModelsList == '') {\n // no friends, favorites yet\n enabled = 0;\n acceptModelsList = 'none';\n }\n }\n\n logger.info('getImAvailabilityParam()', enabled, acceptModelsList);\n return acceptModelsList;\n }\n\n setupAvailabilityPresence() {\n const { user } = this.storeController.store.getState();\n if (!user || user.isGuest) return;\n this.edgeConnection.send({\n action: 'presence_set_im_availability',\n im_availability: this.getImAvailabilityParam()\n });\n }\n\n setupAvailabilityChatRoom(room) {\n const { user } = this.storeController.store.getState();\n if (!user || user.isGuest) return;\n this.edgeConnection.send({\n action: 'set_im_availability',\n im_availability: this.getImAvailabilityParam(),\n room\n });\n }\n\n updatePrivateMessageSetting(val) {\n this.storeController.store.dispatch(this.storeController.user.actions.update_private_message_setting(val));\n this.setupAvailabilityPresence();\n }\n\n startMessenger(collocutor) {\n let isNew = true;\n const { user, messenger: { collocutors } } = this.storeController.store.getState();\n collocutors.some(c => {\n if (c.id == collocutor.id) {\n isNew = false;\n return true;\n }\n });\n if (isNew) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.create_messenger(collocutor));\n // create new connection\n this.askPresenceToStartIm(collocutor).then(loginInfo => {\n const me = user;\n const mcKey = user.id + '_' + collocutor.id;\n if (!connections[mcKey]) {\n connections[mcKey] = new MessengerConnection(this, me, collocutor, loginInfo);\n }\n const conn = connections[mcKey];\n logger.info('connectInstMsgr', collocutor.username, loginInfo, conn);\n conn.login();\n });\n }\n\n if (0/*isPhone*/) this.storeController.store.dispatch(this.storeController.messenger.actions.toggle_chatters_list());\n this.storeController.store.dispatch(this.storeController.messenger.actions.open_messenger(collocutor.id));\n }\n\n askPresenceToStartIm(performer) {\n const simple = simplePromise();\n this.promisesStartIM[performer.id] = simple;\n this.edgeConnection.send({ action: 'presence_start_im_chat', collocutor_id: performer.id });\n return simple.promise;\n }\n\n onImChatInfo(im_chat_info, collocutor, initiator_id) {\n const simple = this.promisesStartIM[collocutor.id];\n logger.log('onImChatInfo', im_chat_info, 'collocutor', collocutor, 'initiator_id', initiator_id, 'simple', simple);\n\n if (simple) {\n // we started the IM\n if (!im_chat_info) {\n simple.reject('absent im_chat_info for collocutor ' + collocutor.id);\n } else {\n simple.resolve(im_chat_info);\n }\n // forget promise\n delete this.promisesStartIM[collocutor.id];\n } else {\n // performer started the IM\n this.onInvitationToInstMsgr(im_chat_info, collocutor, initiator_id);\n }\n }\n\n onInvitationToInstMsgr(im_chat_info, collocutor, initiator_id) {\n const { user } = this.storeController.store.getState();\n this.storeController.store.dispatch(this.storeController.messenger.actions.create_messenger(collocutor));\n const me = user;\n const mcKey = me.id + '_' + collocutor.id;\n if (!connections[mcKey]) {\n connections[mcKey] = new MessengerConnection(this, me, collocutor, im_chat_info);\n }\n const conn = connections[mcKey];\n logger.info('connect to IM on performer invitation', collocutor.username, im_chat_info, conn);\n conn.login();\n }\n\n onConnectionHsmOnlineEnter(collocutor) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.messenger_ready(collocutor.id));\n }\n\n onConnectionHsmOnlineExit(collocutor) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.messenger_offline(collocutor.id));\n }\n\n onMessagesList(collocutor, messages) {\n logger.log('onMessagesList()', '(' + collocutor.username + ')', messages);\n\n messages = messages.map(m => ({\n username: m.senderName,\n message: m.content\n }));\n\n this.storeController.store.dispatch(this.storeController.messenger.actions.history({collocutorId: collocutor.id, messages}));\n\n if (this.restoreData) {\n this.restoreData.collocutors.forEach(c => {\n if (c.id == collocutor.id) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.messenger_unread({collocutorId: c.id, unread: c.unread}));\n }\n })\n }\n\n }\n\n onNewMessage(collocutor, message) {\n logger.log('onNewMessage()', '(' + collocutor.username + ')', message, collocutor.id);\n message = {\n username: message.senderName,\n message: message.content\n };\n this.storeController.store.dispatch(this.storeController.messenger.actions.message({collocutor, message}));\n }\n\n onPerformerJoin(collocutorId) {\n performerInRoom[collocutorId] = true;\n }\n\n onPerformerLeave(collocutorId) {\n delete performerInRoom[collocutorId];\n }\n\n restartIfNeeded() {\n const { user, performers } = this.storeController.store.getState();\n if (!user || user.isGuest) return;\n\n if (this.needRestartAfterWsDisconnect) {\n // restart after websocket reconnect\n this.restart();\n return;\n }\n if (this.needRestartAfterPageReload) {\n // check if restart is needed after page reload\n const now = new Date().getTime();\n const data = localStorageGet('messenger');\n if (data && data.save_user_id == user.id && now - data.save_time < 60*60*1000) { // state updated less then 1 hour ago\n logger.log('restoreData', data);\n this.restoreData = data;\n\n if (data.muted) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.toggle_mute());\n }\n if (data.opened) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.toggle_chatters_list());\n }\n data.collocutors.forEach(collocutor => {\n let isOnline = false;\n performers.some(p => {\n if (collocutor.id == p.id) {\n isOnline = true;\n return true;\n }\n });\n if (!isOnline) return; // do not restore room for offline performer, it won't work\n\n this.storeController.store.dispatch(this.storeController.messenger.actions.create_messenger(collocutor));\n // create new connection\n this.askPresenceToStartIm(collocutor).then(loginInfo => {\n const me = user;\n const mcKey = user.id + '_' + collocutor.id;\n if (!connections[mcKey]) {\n connections[mcKey] = new MessengerConnection(this, me, collocutor, loginInfo);\n }\n const conn = connections[mcKey];\n logger.info('restart connectInstMsgr', collocutor.username, loginInfo, conn);\n conn.login();\n });\n if (collocutor.bar) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.add_to_bar(collocutor.id));\n }\n if (collocutor.opened) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.open_messenger(collocutor.id));\n }\n });\n\n }\n\n setTimeout(() => {\n this.restoreData = null;\n }, 10000);\n\n this.needRestartAfterPageReload = false;\n }\n }\n\n restart() {\n // after websocket reconnect\n logger.log('restart()');\n performerInRoom = {};\n Object.keys(connections).forEach(key => {\n logger.log('restart for key', key);\n connections[key].restart();\n });\n }\n\n toggleChattersList() {\n this.storeController.store.dispatch(this.storeController.messenger.actions.toggle_chatters_list());\n }\n\n openChattersList() {\n this.storeController.store.dispatch(this.storeController.messenger.actions.open_chatters_list());\n }\n\n closeChattersList() {\n this.storeController.store.dispatch(this.storeController.messenger.actions.close_chatters_list());\n }\n\n openIMUnreadOrChattersList(preferredCollocutor) {\n const { messenger: { collocutors } } = this.storeController.store.getState();\n let unreadCol = false;\n let preferredFound = false;\n let totalUnread = 0;\n collocutors.forEach(c => {\n if (c.unread && !unreadCol) {\n unreadCol = c;\n }\n if (c.unread) totalUnread++;\n if (preferredCollocutor && preferredCollocutor.id == c.id) {\n preferredFound = true;\n }\n });\n if (unreadCol && totalUnread > 1) {\n this.openChattersList();\n } else if (unreadCol) {\n this.openMessenger(unreadCol);\n } else if (preferredCollocutor) {\n if (preferredFound) this.openMessenger(preferredCollocutor);\n else this.startMessenger(preferredCollocutor);\n } else {\n this.openChattersList();\n }\n }\n\n toggleMute() {\n this.storeController.store.dispatch(this.storeController.messenger.actions.toggle_mute());\n }\n\n openMessenger(collocutor) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.open_messenger(collocutor.id));\n }\n\n toggleMessenger(collocutor) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.toggle_messenger(collocutor.id));\n }\n\n closeMessenger(collocutor) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.close_messenger(collocutor.id));\n }\n\n hideFromBar(collocutor) {\n this.storeController.store.dispatch(this.storeController.messenger.actions.hide_from_bar(collocutor.id));\n }\n\n sendMessage(collocutor, text) {\n const { user } = this.storeController.store.getState();\n const me = user;\n const mcKey = me.id + '_' + collocutor.id;\n connections[mcKey].sendMessage(text);\n if (!performerInRoom[collocutor.id]) {\n logger.log('invite performer to room', collocutor.id);\n this.edgeConnection.send({ action: 'presence_send_im_chat_invitation', collocutor_id: collocutor.id });\n }\n }\n\n}\n", "import $ from './vendor/jquery-3.4.1.min.js';\n\nwindow.originalConsole = window.console;\nwindow.fakeConsole = [];\nObject.keys(window.console).forEach(function(key) {\n fakeConsole[key] = function() {};\n});\nfunction disableConsoleLog() {\n window.console = window.fakeConsole;\n}\nfunction enableConsoleLog() {\n window.console = originalConsole;\n}\nif (window.appConfig && !window.appConfig.debug) {\n disableConsoleLog();\n}\n\nfunction updateOnlineList() {\n console.log('updateOnlineList');\n $.get('/performers/online-list', function(data) {\n //console.log('updateOnlineList data', data);\n $('#onlineList').html(data);\n });\n}\n\nfunction startOnlineListUpdater() {\n setInterval(updateOnlineList, 30000);\n}\n\n\nfunction withTiming(def, category, timing_var) {\n var call_started = Date.now();\n return def.always(function () {\n console.log('[Time]', category, timing_var, Date.now() - call_started);\n window.ga && ga('send', {\n hitType: 'timing',\n timingCategory: category,\n timingVar: timing_var,\n timingValue: Date.now() - call_started\n });\n });\n}\n\n\nfunction api(endpoint, data, rtype) {\n var result = $.Deferred();\n var settings = {\n url: appConfig.apiAddress + endpoint,\n contentType: 'application/json',\n type: rtype || 'GET',\n dataType: 'json',\n xhrFields: {\n withCredentials: true\n },\n error: function (jqXHR, exception) {\n var error;\n if (jqXHR.status === 0) {\n error = 'No connection.\\n Verify Network.';\n } else if (jqXHR.status == 404) {\n error = 'Requested page not found. [404]';\n } else if (jqXHR.status == 403) {\n //alert('forbidden');\n } else if (jqXHR.status == 500) {\n error = 'Internal Server Error [500].';\n } else if (jqXHR.status == 503) {\n error = 'Internal Server Error [503].';\n } else if (exception === 'parsererror') {\n error = 'Requested JSON parse failed.';\n } else if (exception === 'timeout') {\n error = 'Time out error.';\n } else if (exception === 'abort') {\n error = 'Ajax request aborted.';\n } else {\n error = 'Uncaught Error.\\n' + jqXHR.responseText;\n }\n //if (error) monitorHttpEvent(monitorEvents.app_service_unavailable);\n }\n };\n\n\n if (data && rtype !== 'GET') {\n settings['type'] = rtype || 'POST';\n settings['data'] = JSON.stringify(data);\n }\n if (data && rtype == 'GET') {\n settings['data'] = data;\n }\n if (data === null) {\n settings['type'] = rtype || 'POST'; //POST without data\n }\n\n var ajax = $.ajax(settings).done(function(response) {\n if (response.errors) {\n result.reject(response.errors)\n } else {\n result.resolve(response.data, response.paging || null)\n }\n }).fail(function(response) {\n var errors = {errorType: 'system', errorMessage: 'Error. Request can not be completed!', errorData: null};\n if (response.responseJSON && response.responseJSON.errors) {\n errors = response.responseJSON.errors;\n }\n result.reject(errors);\n\n var reason = 'unknown';\n if (errors.errorType == 'not_allowed') {\n reason = 'not_allowed';\n if (errors.errorData) {\n if (errors.errorData.force_verification) {\n reason = 'force_verification';\n //BLRep('API: sendHomeAlert FORCED VIP', data);\n window.location.href = '/vip/combined/verify/0';\n } else if (errors.errorData.is_ccsuspended) {\n reason = 'is_ccsuspended';\n //BLRep('API: sendHomeAlert is_ccsuspended', data);\n window.location.href = '/vip/combined/verify/0';\n } else if (errors.errorData.email && !errors.errorData.is_confirmed) {\n reason = 'email_not_confirmed';\n //BLRep('API: sendHomeAlert confirm_email', data);\n window.location.href = '/confirm-email/';\n } else if (errors.errorData.ppu_billing_attempts) {\n reason = 'ppu_billing_attempts';\n //BLRep('API: sendHomeAlert ppu_billing_attempts', data);\n //app.trigger('rebill_ppu');\n }\n } else {\n // that should not happen according to API doc\n //BLRep('API !!! : sendHomeAlert error', data);\n }\n }\n\n });\n result.progress(function (what) {\n if (what == 'abort') ajax.abort();\n });\n\n\n return result;\n}\n\n// apps/user_level.js self.on('refresh_level'\nfunction userRefreshLevel(user, verification) {\n if (user.force_verification) {\n window.location.href = '/vip/combined/verify/0';\n } else if (verification.level_claims) {\n window.location.href = '/user-level/' + verification.level_claims;\n }\n}\n\nfunction BLRep(msg, data) {\n appConfig.useRollbar && window.Rollbar && window.Rollbar.info(msg, data);\n if (!window.Rollbar || window.console) {\n console.info('BLREP', msg, data);\n }\n}\n\n\nfunction getDocHeight() {\n var d = window.document;\n var heights = [0];\n ['scrollHeight', 'offsetHeight', 'clientHeight'].forEach(function(field) {\n if (d.body && d.body[field]) heights.push(d.body[field]);\n if (d.documentElement && d.documentElement[field]) heights.push(d.documentElement[field]);\n });\n return Math.max.apply(null, heights);\n}\n// put messenger bar over footer block, if page scrolled to bottom\n$(window).on('load scroll resize', function () {\n var footerHeight = parseInt(getCssVar('--height-footer'));\n var scrollTop = $(window).scrollTop();\n var windowHeight = $(window).height();\n var docHeight = getDocHeight();\n if (docHeight - windowHeight - scrollTop <= footerHeight) {\n var footerVisiblePartHeight = Math.abs(docHeight - windowHeight - scrollTop - footerHeight);\n $('#chatbar').css('bottom', footerVisiblePartHeight+'px');\n } else {\n $('#chatbar').css('bottom', 0);\n }\n});\n\n\nfunction getApiErrorsAsHash(errors) {\n //console.log('getApiErrorsAsHash', errors);\n var emap = {}; // { fieldName: [error1, error2, error3] }\n if (Object.prototype.toString.call(errors) === '[object Array]') {\n errors.forEach(function(error){\n if (!emap[error.errorData.fieldName]) emap[error.errorData.fieldName] = [];\n emap[error.errorData.fieldName].push(error.errorData.errorMessage);\n });\n } else if ('errorData' in errors && errors.errorData != null && 'fieldName' in errors.errorData) {\n emap[errors.errorData.fieldName] = [errors.errorData.errorMessage];\n } else if ('errorMessage' in errors) {\n emap['no_field'] = [errors.errorMessage];\n }\n return emap;\n}\n\nfunction getApiErrorsTextFromHash(emap, delimiter) {\n delimiter = delimiter || '\\n';\n var errorText = '';\n for (var ef in emap) {\n for (var i=0; i wait) {\n if (timeout) {\n clearTimeout(timeout);\n timeout = null;\n }\n previous = now;\n result = func.apply(context, args);\n if (!timeout) context = args = null;\n } else if (!timeout && options.trailing !== false) {\n timeout = setTimeout(later, remaining);\n }\n return result;\n };\n}\n\nfunction Q(sel, element, callback) {\n var tpl = Q.flatten_template.apply(Q, arguments);\n // console.log('flatten query', tpl);\n // console.log('sel', sel);\n // console.log('element', element);\n // console.log('callback', callback);\n if (tpl) {\n sel = tpl;\n element = document;\n } else if (typeof element === 'function' ) {\n callback = element;\n element = document;\n var e = (element || document).querySelector(sel);\n if (e) {\n return callback(e) || e;\n }\n } else if (typeof callback === 'function') {\n var e = (element || document).querySelector(sel);\n if (e) {\n return callback(e) || e;\n }\n }\n return (element || document).querySelector(sel);\n}\n\nQ.flatten_template = function (strings) {\n if (strings instanceof Array) {\n var result = [];\n strings.forEach(function(val, i) {\n result.push(val, arguments[i + 1]);\n });\n return result.join('');\n }\n};\n\nfunction QQ(selector, callback) {\n var base = this === window ? document : this;\n var tpl = Q.flatten_template.apply(Q, arguments);\n if (tpl) return base.querySelectorAll(tpl);\n else if (callback) {\n return base.querySelectorAll(selector).forEach(function(node) { callback(node) })\n } else {\n return base.querySelectorAll(selector);\n }\n}\n\nElement.prototype.Q = Q;\nElement.prototype.QQ = QQ;\n\n\n\n\nfunction stopCountdownTimer(timer) {\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n}\n\nfunction secondsToMMSS(secs) {\n secs = parseInt(secs, 10);\n var hours = Math.floor(secs / 3600);\n var minutes = Math.floor((secs - (hours * 3600)) / 60);\n var seconds = secs - (hours * 3600) - (minutes * 60);\n\n if (hours < 10) hours = '0' + hours;\n if (minutes < 10) minutes = '0' + minutes;\n if (seconds < 10) seconds = '0' + seconds;\n // return hours + ':' + minutes + ':' + seconds;\n return minutes + ':' + seconds;\n}\n\n\nfunction renderCountdownTimer(endTime, renderTo) {\n\n function tick() {\n var timeLeft = (endTime * 1000 - (new Date()).getTime()) / 1000;\n if (timeLeft < 0) timeLeft = 0;\n timeLeft = parseInt(timeLeft, 10);\n if (renderTo.length) {\n for (var i=0; i