>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join(\"\")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<\nl;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\"}})();\n\n// BlockCipher\n(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},\n_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),\nf=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,\nm,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,\nE,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/\n4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);\n(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,\nthis,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,\n1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},\ndecrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return\"string\"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,\nb.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();\n\n// AES\n(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,\n16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;dd||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>\n8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=\nd[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();\n\n// Mode ECB\nCryptoJS.mode.ECB = (function () {\n var ECB = CryptoJS.lib.BlockCipherMode.extend();\n\n ECB.Encryptor = ECB.extend({\n processBlock: function (words, offset) {\n this._cipher.encryptBlock(words, offset);\n }\n });\n\n ECB.Decryptor = ECB.extend({\n processBlock: function (words, offset) {\n this._cipher.decryptBlock(words, offset);\n }\n });\n\n return ECB;\n}());// Moved to hmac-sha-256.js\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./bower_components/pubnub/web/pubnub.js\n ** module id = 10\n ** module chunks = 0\n **/","export default class Cache {\n\n static defaultPrefix = 'rc-';\n\n constructor(storage, prefix) {\n this.setPrefix(prefix);\n this._storage = storage;\n }\n\n setPrefix(prefix) {\n this._prefix = prefix || Cache.defaultPrefix;\n return this;\n }\n\n setItem(key, data) {\n this._storage[this._prefixKey(key)] = JSON.stringify(data);\n return this;\n }\n\n removeItem(key) {\n delete this._storage[this._prefixKey(key)];\n return this;\n }\n\n getItem(key) {\n var item = this._storage[this._prefixKey(key)];\n if (!item) return null;\n return JSON.parse(item);\n }\n\n clean() {\n\n for (var key in this._storage) {\n\n if (!this._storage.hasOwnProperty(key)) continue;\n\n if (key.indexOf(this._prefix) === 0) {\n delete this._storage[key];\n }\n\n }\n\n return this;\n\n }\n\n _prefixKey(key) {\n return this._prefix + key;\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/core/Cache.js\n **/","export default class Observable {\n\n constructor() {\n this.off();\n }\n\n hasListeners(event) {\n return (event in this._listeners);\n }\n\n on(events, callback) {\n\n if (typeof events == 'string') events = [events];\n if (!events) throw new Error('No events to subscribe to');\n if (typeof callback !== 'function') throw new Error('Callback must be a function');\n\n events.forEach((event) => {\n\n if (!this.hasListeners(event)) this._listeners[event] = [];\n\n this._listeners[event].push(callback);\n\n });\n\n return this;\n\n }\n\n emit(event, ...args) {\n\n var result = null;\n\n if (!this.hasListeners(event)) return null;\n\n this._listeners[event].some((callback) => {\n\n result = callback.apply(this, args);\n return (result === false);\n\n });\n\n return result;\n\n }\n\n off(event, callback) {\n\n if (!event) {\n\n this._listeners = {};\n\n } else {\n\n if (!callback) {\n\n delete this._listeners[event];\n\n } else {\n\n if (!this.hasListeners(event)) return this;\n\n this._listeners[event].forEach((cb, i) => {\n\n if (cb === callback) delete this._listeners[event][i];\n\n });\n\n }\n\n }\n\n return this;\n\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/core/Observable.js\n **/","import {Promise} from '../core/Externals';\nimport {poll, stopPolling} from './Utils';\n\nexport default class Queue {\n\n static _pollInterval = 250;\n static _releaseTimeout = 5000;\n\n constructor(cache, cacheId) {\n\n this._cache = cache;\n this._cacheId = cacheId;\n this._promise = null;\n\n }\n\n isPaused() {\n\n var time = this._cache.getItem(this._cacheId);\n\n return !!time && Date.now() - parseInt(time) < Queue._releaseTimeout;\n }\n\n pause() {\n this._cache.setItem(this._cacheId, Date.now());\n return this;\n }\n\n resume() {\n this._cache.removeItem(this._cacheId);\n return this;\n }\n\n poll() {\n\n if (this._promise) return this._promise;\n\n this._promise = new Promise((resolve, reject) => {\n\n poll((next) => {\n\n if (this.isPaused()) return next();\n\n this._promise = null;\n\n this.resume(); // this is actually not needed but why not\n\n resolve(null);\n\n }, Queue._pollInterval);\n\n });\n\n return this._promise;\n\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/core/Queue.js\n **/","import {fetch, Request, Response, Headers, Promise} from '../core/Externals';\nimport {queryStringify} from '../core/Utils';\nimport {findHeaderName} from './Utils';\nimport Observable from '../core/Observable';\nimport ApiResponse from './ApiResponse';\n\nexport default class Client extends Observable {\n\n static _allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'];\n\n events = {\n beforeRequest: 'beforeRequest',\n requestSuccess: 'requestSuccess',\n requestError: 'requestError'\n };\n\n /**\n * @param {Request} request\n * @return {Promise}\n */\n async sendRequest(request) {\n\n var apiResponse = new ApiResponse(request);\n\n try {\n\n //TODO Stop request if listeners return false\n this.emit(this.events.beforeRequest, apiResponse);\n\n apiResponse._response = await this._loadResponse(request);\n\n if (apiResponse._isMultipart() || apiResponse._isJson()) {\n apiResponse._text = await apiResponse.response().text();\n }\n\n if (!apiResponse.ok()) throw new Error('Response has unsuccessful status');\n\n this.emit(this.events.requestSuccess, apiResponse);\n\n return apiResponse;\n\n } catch (e) {\n\n if (!e.apiResponse) e = this.makeError(e, apiResponse);\n\n this.emit(this.events.requestError, e);\n\n throw e;\n\n }\n\n }\n\n /**\n * @param {Request} request\n * @return {Promise}\n * @private\n */\n async _loadResponse(request) {\n return await fetch.call(null, request);\n }\n\n /**\n * Wraps the JS Error object with transaction information\n * @param {Error|IApiError} e\n * @param {ApiResponse} apiResponse\n * @return {IApiError}\n */\n makeError(e, apiResponse) {\n\n // Wrap only if regular error\n if (!e.hasOwnProperty('apiResponse') && !e.hasOwnProperty('originalMessage')) {\n\n e.apiResponse = apiResponse;\n e.originalMessage = e.message;\n e.message = (apiResponse && apiResponse.error(true)) || e.originalMessage;\n\n }\n\n return e;\n\n }\n\n /**\n *\n * @param {object} init\n * @param {object} [init.url]\n * @param {object} [init.body]\n * @param {string} [init.method]\n * @param {object} [init.query]\n * @param {object} [init.headers]\n * @return {Request}\n */\n createRequest(init) {\n\n init = init || {};\n init.headers = init.headers || {};\n\n // Sanity checks\n if (!init.url) throw new Error('Url is not defined');\n if (!init.method) init.method = 'GET';\n if (init.method && Client._allowedMethods.indexOf(init.method) < 0) throw new Error('Method has wrong value: ' + init.method);\n\n // Defaults\n init.credentials = init.credentials || 'include';\n init.mode = init.mode || 'cors';\n\n // Append Query String\n if (init.query) {\n init.url = init.url + (init.url.indexOf('?') > -1 ? '&' : '?') + queryStringify(init.query);\n }\n\n if (!(findHeaderName('Accept', init.headers))) {\n init.headers['Accept'] = ApiResponse._jsonContentType;\n }\n\n // Serialize body\n //TODO Check that body is a plain object\n if (typeof init.body !== 'string' || !init.body) {\n\n var contentTypeHeaderName = findHeaderName(ApiResponse._contentType, init.headers);\n\n if (!contentTypeHeaderName) {\n contentTypeHeaderName = ApiResponse._contentType;\n init.headers[contentTypeHeaderName] = ApiResponse._jsonContentType;\n }\n\n var contentType = init.headers[contentTypeHeaderName];\n\n // Assign a new encoded body\n if (contentType.indexOf(ApiResponse._jsonContentType) > -1) {\n init.body = JSON.stringify(init.body);\n } else if (contentType.indexOf(ApiResponse._urlencodedContentType) > -1) {\n init.body = queryStringify(init.body);\n }\n\n }\n\n // Create a request with encoded body\n var req = new Request(init.url, init);\n\n // Keep the original body accessible directly (for mocks)\n req.originalBody = init.body;\n\n return req;\n\n }\n\n}\n\n/**\n * @name IApiError\n * @property {string} stack\n * @property {string} originalMessage\n * @property {ApiResponse} apiResponse\n */\n\n\n/** WEBPACK FOOTER **\n ** ./src/http/Client.js\n **/","import {fetch, Request, Response, Headers, Promise} from '../core/Externals';\nimport * as utils from '../core/Utils';\n\n/**\n * Creates a response\n * @param stringBody\n * @param init\n * @return {Response}\n */\nexport function createResponse(stringBody, init) {\n\n init = init || {};\n\n var response = new Response(stringBody, init);\n\n //TODO Wait for https://github.com/bitinn/node-fetch/issues/38\n if (utils.isNodeJS()) {\n\n response._text = stringBody;\n response._decode = function() {\n return this._text;\n };\n\n }\n\n return response;\n\n}\n\nexport function findHeaderName(name, headers) {\n name = name.toLowerCase();\n return Object.keys(headers).reduce(function(res, key) {\n if (res) return res;\n if (name == key.toLowerCase()) return key;\n return res;\n }, null);\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/http/Utils.js\n **/","import {fetch, Request, Response, Headers, Promise} from '../core/Externals';\nimport * as utils from './Utils';\n\nexport default class ApiResponse {\n\n static _contentType = 'Content-Type';\n static _jsonContentType = 'application/json';\n static _multipartContentType = 'multipart/mixed';\n static _urlencodedContentType = 'application/x-www-form-urlencoded';\n static _headerSeparator = ':';\n static _bodySeparator = '\\n\\n';\n static _boundarySeparator = '--';\n\n /**\n * @param {Request} request\n * @param {Response} response\n * @param {string} responseText\n */\n constructor(request, response, responseText) {\n\n /** @type {Request} */\n this._request = request;\n\n /** @type {Response} */\n this._response = response;\n\n this._text = responseText;\n this._json = null;\n this._multipart = [];\n\n }\n\n /**\n * @return {Response}\n */\n response() {\n return this._response;\n }\n\n /**\n * @return {Request}\n */\n request() {\n return this._request;\n }\n\n /**\n * @return {boolean}\n */\n ok() {\n return this._response && this._response.ok;\n }\n\n /**\n * @return {string}\n */\n text() {\n if (!this._isJson() && !this._isMultipart()) throw new Error('Response is not text');\n return this._text;\n }\n\n /**\n * @return {object}\n */\n json() {\n if (!this._isJson()) throw new Error('Response is not JSON');\n if (!this._json) {\n this._json = this._text ? JSON.parse(this._text) : null;\n }\n return this._json;\n }\n\n /**\n * @param [skipOKCheck]\n * @return {string}\n */\n error(skipOKCheck) {\n\n if (this.ok() && !skipOKCheck) return null;\n\n var message = (this._response && this._response.status ? this._response.status + ' ' : '') +\n (this._response && this._response.statusText ? this._response.statusText : '');\n\n try {\n\n if (this.json().message) message = this.json().message;\n if (this.json().error_description) message = this.json().error_description;\n if (this.json().description) message = this.json().description;\n\n } catch (e) {}\n\n return message;\n\n }\n\n /**\n * @return {ApiResponse[]}\n */\n multipart() {\n\n if (!this._isMultipart()) throw new Error('Response is not multipart');\n\n if (!this._multipart.length) {\n\n // Step 1. Split multipart response\n\n var text = this.text();\n\n if (!text) throw new Error('No response body');\n\n var boundary = this._getContentType().match(/boundary=([^;]+)/i)[1];\n\n if (!boundary) throw new Error('Cannot find boundary');\n\n var parts = text.toString().split(ApiResponse._boundarySeparator + boundary);\n\n if (parts[0].trim() === '') parts.shift();\n if (parts[parts.length - 1].trim() == ApiResponse._boundarySeparator) parts.pop();\n\n if (parts.length < 1) throw new Error('No parts in body');\n\n // Step 2. Parse status info\n\n var statusInfo = ApiResponse.create(parts.shift(), this._response.status, this._response.statusText).json();\n\n // Step 3. Parse all other parts\n\n this._multipart = parts.map((part:string, i) => {\n\n var status = statusInfo.response[i].status;\n\n return ApiResponse.create(part, status);\n\n });\n\n }\n\n return this._multipart;\n\n }\n\n _isContentType(contentType) {\n return this._getContentType().indexOf(contentType) > -1;\n }\n\n _getContentType() {\n return this._response.headers.get(ApiResponse._contentType) || '';\n }\n\n _isMultipart() {\n return this._isContentType(ApiResponse._multipartContentType);\n }\n\n _isUrlEncoded() {\n return this._isContentType(ApiResponse._urlencodedContentType);\n }\n\n _isJson() {\n return this._isContentType(ApiResponse._jsonContentType);\n }\n\n /**\n * Method is used to create ApiResponse object from string parts of multipart/mixed response\n * @param {string} [text]\n * @param {number} [status]\n * @param {string} [statusText]\n * @return {ApiResponse}\n */\n static create(text, status, statusText) {\n\n text = text || '';\n status = status || 200;\n statusText = statusText || 'OK';\n\n text = text.replace(/\\r/g, '');\n\n var headers = new Headers(),\n headersAndBody = text.split(ApiResponse._bodySeparator),\n headersText = (headersAndBody.length > 1) ? headersAndBody.shift() : '';\n\n text = headersAndBody.join(ApiResponse._bodySeparator);\n\n (headersText || '')\n .split('\\n')\n .forEach((header:string) => {\n\n var split = header.trim().split(ApiResponse._headerSeparator),\n key = split.shift().trim(),\n value = split.join(ApiResponse._headerSeparator).trim();\n\n if (key) headers.append(key, value);\n\n });\n\n return new ApiResponse(null, utils.createResponse(text, {\n headers: headers,\n status: status,\n statusText: statusText\n }), text);\n\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/http/ApiResponse.js\n **/","import Registry from './Registry';\nimport {default as HttpClient} from '../http/Client';\n\nexport default class Client extends HttpClient {\n\n constructor() {\n super();\n this._registry = new Registry();\n }\n\n registry() {\n return this._registry;\n }\n\n async _loadResponse(request) {\n\n var mock = this._registry.find(request);\n\n return await mock.getResponse(request);\n\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/mocks/ClientMock.js\n **/","import Mock from './Mock';\n\nexport default class Registry {\n\n constructor() {\n this._mocks = [];\n }\n\n add(mock) {\n this._mocks.push(mock);\n return this;\n }\n\n clear() {\n this._mocks = [];\n return this;\n }\n\n find(request) {\n\n //console.log('Registry is looking for', request);\n\n var mock = this._mocks.shift();\n\n if (!mock) throw new Error('No mock in registry for request ' + request.method + ' ' + request.url);\n\n if (!mock.test(request)) throw new Error('Wrong request ' + request.method + ' ' + request.url +\n ' for expected mock ' + mock.method() + ' ' + mock.path());\n\n return mock;\n\n }\n\n apiCall(method:string, path:string, response:any, status, statusText) {\n\n this.add(new Mock(method, path, response, status, statusText));\n\n return this;\n\n }\n\n authentication() {\n\n this.apiCall('POST', '/restapi/oauth/token', {\n 'access_token': 'ACCESS_TOKEN',\n 'token_type': 'bearer',\n 'expires_in': 3600,\n 'refresh_token': 'REFRESH_TOKEN',\n 'refresh_token_expires_in': 60480,\n 'scope': 'SMS RCM Foo Boo',\n 'expireTime': new Date().getTime() + 3600000\n });\n\n return this;\n\n }\n\n logout() {\n\n this.apiCall('POST', '/restapi/oauth/revoke', {});\n\n return this;\n\n }\n\n presenceLoad(id) {\n\n this.apiCall('GET', '/restapi/v1.0/account/~/extension/' + id + '/presence', {\n \"uri\": \"https://platform.ringcentral.com/restapi/v1.0/account/123/extension/\" + id + \"/presence\",\n \"extension\": {\n \"uri\": \"https://platform.ringcentral.com/restapi/v1.0/account/123/extension/\" + id,\n \"id\": id,\n \"extensionNumber\": \"101\"\n },\n \"activeCalls\": [],\n \"presenceStatus\": \"Available\",\n \"telephonyStatus\": \"Ringing\",\n \"userStatus\": \"Available\",\n \"dndStatus\": \"TakeAllCalls\",\n \"extensionId\": id\n });\n\n return this;\n\n }\n\n subscribeGeneric(expiresIn) {\n\n expiresIn = expiresIn || 15 * 60 * 60;\n\n var date = new Date();\n\n this.apiCall('POST', '/restapi/v1.0/subscription', {\n 'eventFilters': [\n '/restapi/v1.0/account/~/extension/~/presence'\n ],\n 'expirationTime': new Date(date.getTime() + (expiresIn * 1000)).toISOString(),\n 'expiresIn': expiresIn,\n 'deliveryMode': {\n 'transportType': 'PubNub',\n 'encryption': false,\n 'address': '123_foo',\n 'subscriberKey': 'sub-c-foo',\n 'secretKey': 'sec-c-bar'\n },\n 'id': 'foo-bar-baz',\n 'creationTime': date.toISOString(),\n 'status': 'Active',\n 'uri': 'https://platform.ringcentral.com/restapi/v1.0/subscription/foo-bar-baz'\n });\n\n return this;\n\n }\n\n subscribeOnPresence(id, detailed) {\n\n id = id || '1';\n\n var date = new Date();\n\n this.apiCall('POST', '/restapi/v1.0/subscription', {\n 'eventFilters': ['/restapi/v1.0/account/~/extension/' + id + '/presence' + (detailed ? '?detailedTelephonyState=true' : '')],\n 'expirationTime': new Date(date.getTime() + (15 * 60 * 60 * 1000)).toISOString(),\n 'deliveryMode': {\n 'transportType': 'PubNub',\n 'encryption': true,\n 'address': '123_foo',\n 'subscriberKey': 'sub-c-foo',\n 'secretKey': 'sec-c-bar',\n 'encryptionAlgorithm': 'AES',\n 'encryptionKey': 'VQwb6EVNcQPBhE/JgFZ2zw=='\n },\n 'creationTime': date.toISOString(),\n 'id': 'foo-bar-baz',\n 'status': 'Active',\n 'uri': 'https://platform.ringcentral.com/restapi/v1.0/subscription/foo-bar-baz'\n });\n\n return this;\n\n }\n\n tokenRefresh(failure) {\n\n if (!failure) {\n\n this.apiCall('POST', '/restapi/oauth/token', {\n 'access_token': 'ACCESS_TOKEN_FROM_REFRESH',\n 'token_type': 'bearer',\n 'expires_in': 3600,\n 'refresh_token': 'REFRESH_TOKEN_FROM_REFRESH',\n 'refresh_token_expires_in': 60480,\n 'scope': 'SMS RCM Foo Boo'\n });\n\n } else {\n\n this.apiCall('POST', '/restapi/oauth/token', {\n 'message': 'Wrong token',\n 'error_description': 'Wrong token',\n 'description': 'Wrong token'\n }, 400);\n\n }\n\n return this;\n\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/mocks/Registry.js\n **/","import ApiResponse from '../http/ApiResponse';\nimport {delay} from '../core/Utils';\nimport {createResponse} from '../http/Utils';\n\nexport default class Mock {\n\n constructor(method, path, json, status, statusText, delay) {\n this._method = method.toUpperCase();\n this._path = path;\n this._json = json || {};\n this._delay = delay || 10;\n this._status = status || 200;\n this._statusText = statusText || 'OK';\n }\n\n path() {\n return this._path;\n }\n\n method() {\n return this._method;\n }\n\n test(request:Request) {\n\n return request.url.indexOf(this._path) > -1 &&\n request.method.toUpperCase() == this._method;\n\n }\n\n async getResponse(request) {\n\n await delay(this._delay);\n\n return this.createResponse(this._json);\n\n }\n\n createResponse(json, init) {\n\n init = init || {};\n\n init.status = init.status || this._status;\n init.statusText = init.statusText || this._statusText;\n\n var str = JSON.stringify(json),\n res = createResponse(str, init);\n\n res.headers.set(ApiResponse._contentType, ApiResponse._jsonContentType);\n\n return res;\n\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/mocks/Mock.js\n **/","import Observable from '../core/Observable';\nimport Queue from '../core/Queue';\nimport Auth from './Auth';\nimport {Promise} from '../core/Externals';\nimport {queryStringify, parseQueryString, delay} from '../core/Utils';\n\nexport default class Platform extends Observable {\n\n static _urlPrefix = '/restapi';\n static _apiVersion = 'v1.0';\n static _accessTokenTtl = null; // Platform server by default sets it to 60 * 60 = 1 hour\n static _refreshTokenTtl = 10 * 60 * 60; // 10 hours\n static _refreshTokenTtlRemember = 7 * 24 * 60 * 60; // 1 week\n static _tokenEndpoint = '/restapi/oauth/token';\n static _revokeEndpoint = '/restapi/oauth/revoke';\n static _authorizeEndpoint = '/restapi/oauth/authorize';\n static _refreshDelayMs = 100;\n static _cacheId = 'platform';\n static _clearCacheOnRefreshError = true;\n\n events = {\n beforeLogin: 'beforeLogin',\n loginSuccess: 'loginSuccess',\n loginError: 'loginError',\n beforeRefresh: 'beforeRefresh',\n refreshSuccess: 'refreshSuccess',\n refreshError: 'refreshError',\n beforeLogout: 'beforeLogout',\n logoutSuccess: 'logoutSuccess',\n logoutError: 'logoutError'\n };\n\n constructor(client, cache, server, appKey, appSecret) {\n\n super();\n\n this._server = server;\n this._appKey = appKey;\n this._appSecret = appSecret;\n\n /** @type {Cache} */\n this._cache = cache;\n\n /** @type {Client} */\n this._client = client;\n\n this._queue = new Queue(this._cache, Platform._cacheId + '-refresh');\n\n this._auth = new Auth(this._cache, Platform._cacheId);\n\n }\n\n /**\n * @return {Auth}\n */\n auth() {\n return this._auth;\n }\n\n /**\n * @return {Client}\n */\n client() {\n return this._client;\n }\n\n /**\n * @param {string} path\n * @param {object} [options]\n * @param {boolean} [options.addServer]\n * @param {string} [options.addMethod]\n * @param {boolean} [options.addToken]\n * @return {string}\n */\n createUrl(path, options) {\n\n path = path || '';\n options = options || {};\n\n var builtUrl = '',\n hasHttp = path.indexOf('http://') != -1 || path.indexOf('https://') != -1;\n\n if (options.addServer && !hasHttp) builtUrl += this._server;\n\n if (path.indexOf(Platform._urlPrefix) == -1 && !hasHttp) builtUrl += Platform._urlPrefix + '/' + Platform._apiVersion;\n\n builtUrl += path;\n\n if (options.addMethod || options.addToken) builtUrl += (path.indexOf('?') > -1 ? '&' : '?');\n\n if (options.addMethod) builtUrl += '_method=' + options.addMethod;\n if (options.addToken) builtUrl += (options.addMethod ? '&' : '') + 'access_token=' + this._auth.accessToken();\n\n return builtUrl;\n\n }\n\n /**\n * @param {string} options.redirectUri\n * @param {string} options.state\n * @param {string} options.brandId\n * @param {string} options.display\n * @param {string} options.prompt\n * @return {string}\n */\n authUrl(options) {\n\n options = options || {};\n\n return this.createUrl(Platform._authorizeEndpoint + '?' + queryStringify({\n 'response_type': 'code',\n 'redirect_uri': options.redirectUri || '',\n 'client_id': this._appKey,\n 'state': options.state || '',\n 'brand_id': options.brandId || '',\n 'display': options.display || '',\n 'prompt': options.prompt || ''\n }), {addServer: true})\n\n }\n\n /**\n * @param {string} url\n * @return {Object}\n */\n parseAuthRedirectUrl(url:string) {\n\n var qs = parseQueryString(url.split('?').reverse()[0]),\n error = qs.error_description || qs.error;\n\n if (error) {\n var e = new Error(error);\n e.error = qs.error;\n throw e;\n }\n\n return qs;\n\n }\n\n /**\n * @return {Promise}\n */\n async loggedIn() {\n\n try {\n await this._ensureAuthentication();\n return true;\n } catch (e) {\n return false;\n }\n\n }\n\n /**\n * @param {string} options.username\n * @param {string} options.password\n * @param {string} options.extension\n * @param {string} options.code\n * @param {string} options.redirectUri\n * @param {string} options.endpointId\n * @returns {Promise}\n */\n async login(options) {\n\n try {\n\n options = options || {};\n\n options.remember = options.remember || false;\n\n this.emit(this.events.beforeLogin);\n\n var body = {\n \"access_token_ttl\": Platform._accessTokenTtl,\n \"refresh_token_ttl\": options.remember ? Platform._refreshTokenTtlRemember : Platform._refreshTokenTtl\n };\n\n if (!options.code) {\n\n body.grant_type = 'password';\n body.username = options.username;\n body.password = options.password;\n body.extension = options.extension || '';\n\n } else if (options.code) {\n\n body.grant_type = 'authorization_code';\n body.code = options.code;\n body.redirect_uri = options.redirectUri;\n //body.client_id = this.getCredentials().key; // not needed\n\n }\n\n if (options.endpointId) body.endpoint_id = options.endpointId;\n\n var apiResponse = await this._tokenRequest(Platform._tokenEndpoint, body),\n json = apiResponse.json();\n\n this._auth\n .setData(json)\n .setRemember(options.remember);\n\n this.emit(this.events.loginSuccess, apiResponse);\n\n return apiResponse;\n\n } catch (e) {\n\n this._cache.clean();\n\n this.emit(this.events.loginError, e);\n\n throw e;\n\n }\n\n }\n\n /**\n * @returns {Promise}\n */\n async refresh() {\n\n try {\n\n this.emit(this.events.beforeRefresh);\n\n if (this._queue.isPaused()) {\n\n await this._queue.poll();\n\n if (!this._isAccessTokenValid()) {\n throw new Error('Automatic authentification timeout');\n }\n\n this.emit(this.events.refreshSuccess, null);\n\n return null;\n\n }\n\n this._queue.pause();\n\n // Make sure all existing AJAX calls had a chance to reach the server\n await delay(Platform._refreshDelayMs);\n\n // Perform sanity checks\n if (!this._auth.refreshToken()) throw new Error('Refresh token is missing');\n if (!this._auth.refreshTokenValid()) throw new Error('Refresh token has expired');\n if (!this._queue.isPaused()) throw new Error('Queue was resumed before refresh call');\n\n /** @type {ApiResponse} */\n var res = await this._tokenRequest(Platform._tokenEndpoint, {\n \"grant_type\": \"refresh_token\",\n \"refresh_token\": this._auth.refreshToken(),\n \"access_token_ttl\": Platform._accessTokenTtl,\n \"refresh_token_ttl\": this._auth.remember() ? Platform._refreshTokenTtlRemember : Platform._refreshTokenTtl\n }),\n json = res.json();\n\n if (!json.access_token) {\n throw this._client.makeError(new Error('Malformed OAuth response'), res);\n }\n\n this._auth.setData(json);\n this._queue.resume();\n\n this.emit(this.events.refreshSuccess, res);\n\n return res;\n\n } catch (e) {\n\n e = this._client.makeError(e);\n\n if (Platform._clearCacheOnRefreshError) {\n this._cache.clean();\n }\n\n this.emit(this.events.refreshError, e);\n\n throw e;\n\n }\n\n }\n\n /**\n * @returns {Promise}\n */\n async logout() {\n\n try {\n\n this.emit(this.events.beforeLogout);\n\n this._queue.pause();\n\n var res = await this._tokenRequest(Platform._revokeEndpoint, {\n token: this._auth.accessToken()\n });\n\n this._queue.resume();\n this._cache.clean();\n\n this.emit(this.events.logoutSuccess, res);\n\n return res;\n\n } catch (e) {\n\n this._queue.resume();\n\n this.emit(this.events.logoutError, e);\n\n throw e;\n\n }\n\n }\n\n /**\n * @param {Request} request\n * @param {object} [options]\n * @param {boolean} [options.skipAuthCheck]\n * @return {Promise}\n */\n async inflateRequest(request, options) {\n\n options = options || {};\n\n if (options.skipAuthCheck) return request;\n\n await this._ensureAuthentication();\n\n request.headers.set('Authorization', this._authHeader());\n //request.url = this.createUrl(request.url, {addServer: true}); //FIXME Spec prevents this...\n\n //TODO Add User-Agent here\n\n return request;\n\n }\n\n /**\n * @param {Request} request\n * @param {object} [options]\n * @param {boolean} [options.skipAuthCheck]\n * @return {Promise}\n */\n async sendRequest(request, options) {\n\n try {\n\n request = await this.inflateRequest(request, options);\n\n return (await this._client.sendRequest(request));\n\n } catch (e) {\n\n // Guard is for errors that come from polling\n if (!e.apiResponse || !e.apiResponse.response() || (e.apiResponse.response().status != 401)) throw e;\n\n this._auth.cancelAccessToken();\n\n return (await this.sendRequest(request, options));\n\n }\n\n }\n\n /**\n * General purpose function to send anything to server\n * @param {string} options.url\n * @param {object} [options.body]\n * @param {string} [options.method]\n * @param {object} [options.query]\n * @param {object} [options.headers]\n * @param {boolean} [options.skipAuthCheck]\n * @return {Promise}\n */\n async send(options = {}) {\n\n //FIXME https://github.com/bitinn/node-fetch/issues/43\n options.url = this.createUrl(options.url, {addServer: true});\n\n return await this.sendRequest(this._client.createRequest(options), options);\n\n }\n\n /**\n * @param {string} url\n * @param {object} [query]\n * @param {object} [options]\n * @param {object} [options.headers]\n * @param {boolean} [options.skipAuthCheck]\n * @return {Promise}\n */\n async get(url, query, options) {\n options = options || {};\n options.method = 'GET';\n options.url = url;\n options.query = query;\n return await this.send(options);\n }\n\n /**\n * @param {string} url\n * @param {object} body\n * @param {object} [query]\n * @param {object} [options]\n * @param {object} [options.headers]\n * @param {boolean} [options.skipAuthCheck]\n * @return {Promise}\n */\n async post(url, body, query, options) {\n options = options || {};\n options.method = 'POST';\n options.url = url;\n options.query = query;\n options.body = body;\n return await this.send(options);\n }\n\n /**\n * @param {string} url\n * @param {object} [body]\n * @param {object} [query]\n * @param {object} [options]\n * @param {object} [options.headers]\n * @param {boolean} [options.skipAuthCheck]\n * @return {Promise}\n */\n async put(url, body, query, options) {\n options = options || {};\n options.method = 'PUT';\n options.url = url;\n options.query = query;\n options.body = body;\n return await this.send(options);\n }\n\n /**\n * @param {string} url\n * @param {string} [query]\n * @param {object} [options]\n * @param {object} [options.headers]\n * @param {boolean} [options.skipAuthCheck]\n * @return {Promise}\n */\n async 'delete'(url, query, options) {\n options = options || {};\n options.method = 'DELETE';\n options.url = url;\n options.query = query;\n return await this.send(options);\n }\n\n async _tokenRequest(path, body) {\n\n return await this.send({\n url: path,\n skipAuthCheck: true,\n body: body,\n method: 'POST',\n headers: {\n 'Authorization': 'Basic ' + this._apiKey(),\n 'Content-Type': 'application/x-www-form-urlencoded'\n }\n });\n\n }\n\n async _ensureAuthentication() {\n\n if (this._isAccessTokenValid()) return null;\n return await this.refresh();\n\n }\n\n _isAccessTokenValid() {\n\n return (this._auth.accessTokenValid() && !this._queue.isPaused());\n\n }\n\n _apiKey() {\n var apiKey = this._appKey + ':' + this._appSecret;\n return (typeof btoa == 'function') ? btoa(apiKey) : new Buffer(apiKey).toString('base64');\n }\n\n _authHeader() {\n var token = this._auth.accessToken();\n return this._auth.tokenType() + (token ? ' ' + token : '');\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/platform/Platform.js\n **/","export default class Auth {\n\n static refreshHandicapMs:number = 60 * 1000; // 1 minute\n static forcedTokenType = 'forced';\n\n constructor(cache, cacheId:string) {\n\n /** @type {Cache} */\n this._cache = cache;\n this._cacheId = cacheId;\n\n }\n\n accessToken() {\n return this.data().access_token;\n }\n\n refreshToken() {\n return this.data().refresh_token;\n }\n\n tokenType() {\n return this.data().token_type;\n }\n\n /**\n * @return {{token_type: string, access_token: string, expires_in: number, refresh_token: string, refresh_token_expires_in: number}}\n */\n data() {\n\n return this._cache.getItem(this._cacheId) || {\n token_type: '',\n access_token: '',\n expires_in: 0,\n refresh_token: '',\n refresh_token_expires_in: 0\n };\n\n }\n\n /**\n * @param {object} newData\n * @return {Auth}\n */\n setData(newData) {\n\n newData = newData || {};\n\n var data = this.data();\n\n Object.keys(newData).forEach((key) => {\n data[key] = newData[key];\n });\n\n data.expire_time = Date.now() + (data.expires_in * 1000);\n data.refresh_token_expire_time = Date.now() + (data.refresh_token_expires_in * 1000);\n\n this._cache.setItem(this._cacheId, data);\n\n return this;\n\n }\n\n /**\n * Check if there is a valid (not expired) access token\n * @return {boolean}\n */\n accessTokenValid() {\n\n var authData = this.data();\n return (authData.token_type === Auth.forcedTokenType || (authData.expire_time - Auth.refreshHandicapMs > Date.now()));\n\n }\n\n /**\n * Check if there is a valid (not expired) access token\n * @return {boolean}\n */\n refreshTokenValid() {\n\n return (this.data().refresh_token_expire_time > Date.now());\n\n }\n\n /**\n * @return {Auth}\n */\n cancelAccessToken() {\n\n return this.setData({\n access_token: '',\n expires_in: 0\n });\n\n }\n\n /**\n * This method sets a special authentication mode used in Service Web\n * @return {Auth}\n */\n forceAuthentication() {\n\n this.setData({\n token_type: Auth.forcedTokenType,\n access_token: '',\n expires_in: 0,\n refresh_token: '',\n refresh_token_expires_in: 0\n });\n\n return this;\n\n }\n\n /**\n * @param remember\n * @return {Auth}\n */\n setRemember(remember) {\n\n return this.setData({remember: remember});\n\n }\n\n /**\n * @return {boolean}\n */\n remember() {\n\n return !!this.data().remember;\n\n }\n\n}\n\n//export interface IAuthData {\n// remember?:boolean;\n// token_type?:string;\n// access_token?:string;\n// expires_in?:number; // actually it's string\n// expire_time?:number;\n// refresh_token?:string;\n// refresh_token_expires_in?:number; // actually it's string\n// refresh_token_expire_time?:number;\n// scope?:string;\n//}\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/platform/Auth.js\n **/","import PubnubMock from './PubnubMock.js';\nimport {PUBNUB} from '../core/Externals';\n\nexport default class PubnubMockFactory {\n\n constructor() {\n this.crypto_obj = PUBNUB.crypto_obj;\n }\n\n init(options:PUBNUBInitOptions) {\n return new PubnubMock(options);\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/pubnub/PubnubFactory.js\n **/","import Observable from '../core/Observable';\nimport {PUBNUB} from '../core/Externals';\n\nexport default class PubnubMock extends Observable {\n\n constructor(options) {\n super();\n this.options = options;\n this.crypto_obj = PUBNUB.crypto_obj;\n }\n\n ready() {}\n\n subscribe(options:PUBNUBSubscribeOptions) {\n this.on('message-' + options.channel, options.message);\n }\n\n unsubscribe(options:PUBNUBUnsubscribeOptions) {\n this.off('message-' + options.channel);\n }\n\n receiveMessage(msg, channel) {\n this.emit('message-' + channel, msg, 'env', channel);\n }\n\n}\n\n\n/** WEBPACK FOOTER **\n ** ./src/pubnub/PubnubMock.js\n **/","import Observable from '../core/Observable';\nimport Client from '../http/Client';\nimport {poll, stopPolling, delay} from '../core/Utils';\n\nexport default class Subscription extends Observable {\n\n static _renewHandicapMs = 2 * 60 * 1000;\n static _pollInterval = 10 * 1000;\n\n events = {\n notification: 'notification',\n removeSuccess: 'removeSuccess',\n removeError: 'removeError',\n renewSuccess: 'renewSuccess',\n renewError: 'renewError',\n subscribeSuccess: 'subscribeSuccess',\n subscribeError: 'subscribeError'\n };\n\n constructor(pubnubFactory, platform) {\n\n super();\n\n this._pubnubFactory = pubnubFactory;\n this._platform = platform;\n this._pubnub = null;\n this._timeout = null;\n this._subscription = {};\n\n }\n\n subscribed(){\n\n return !!(this._subscription.id &&\n this._subscription.deliveryMode &&\n this._subscription.deliveryMode.subscriberKey &&\n this._subscription.deliveryMode.address);\n\n }\n\n /**\n * @return {boolean}\n */\n alive() {\n\n return this.subscribed() && Date.now() < this.expirationTime();\n\n }\n\n expirationTime() {\n return new Date(this._subscription.expirationTime || 0).getTime() - Subscription._renewHandicapMs;\n }\n\n setSubscription(subscription) {\n\n subscription = subscription || {};\n\n this._clearTimeout();\n\n this._subscription = subscription;\n\n if (!this._pubnub) this._subscribeAtPubnub();\n\n this._setTimeout();\n\n return this;\n\n }\n\n subscription() {\n return this._subscription;\n }\n\n /**\n * Creates or updates subscription if there is an active one\n * @returns {Promise}\n */\n async register() {\n\n if (this.alive()) {\n return await this.renew();\n } else {\n return await this.subscribe();\n }\n\n }\n\n eventFilters() {\n return this._subscription.eventFilters || [];\n }\n\n /**\n * @param {string[]} events\n * @return {Subscription}\n */\n addEventFilters(events) {\n this.setEventFilters(this.eventFilters().concat(events));\n return this;\n }\n\n /**\n * @param {string[]} events\n * @return {Subscription}\n */\n setEventFilters(events) {\n this._subscription.eventFilters = events;\n return this;\n }\n\n /**\n * @returns {Promise}\n */\n async subscribe() {\n\n try {\n\n this._clearTimeout();\n\n if (!this.eventFilters().length) throw new Error('Events are undefined');\n\n var response = await this._platform.post('/restapi/v1.0/subscription', {\n eventFilters: this._getFullEventFilters(),\n deliveryMode: {\n transportType: 'PubNub'\n }\n }),\n json = response.json();\n\n this.setSubscription(json)\n .emit(this.events.subscribeSuccess, response);\n\n return response;\n\n\n } catch (e) {\n\n e = this._platform.client().makeError(e);\n\n this.reset()\n .emit(this.events.subscribeError, e);\n\n throw e;\n\n }\n\n }\n\n /**\n * @returns {Promise}\n */\n async renew() {\n\n try {\n\n this._clearTimeout();\n\n if (!this.alive()) throw new Error('Subscription is not alive');\n\n if (!this.eventFilters().length) throw new Error('Events are undefined');\n\n var response = await this._platform.put('/restapi/v1.0/subscription/' + this._subscription.id, {\n eventFilters: this._getFullEventFilters()\n });\n\n var json = response.json();\n\n this.setSubscription(json)\n .emit(this.events.renewSuccess, response);\n\n return response;\n\n } catch (e) {\n\n e = this._platform.client().makeError(e);\n\n this.reset()\n .emit(this.events.renewError, e);\n\n throw e;\n\n }\n\n }\n\n /**\n * @returns {Promise}\n */\n async remove() {\n\n try {\n\n if (!this.subscribed()) throw new Error('No subscription');\n\n var response = await this._platform.delete('/restapi/v1.0/subscription/' + this._subscription.id);\n\n this.reset()\n .emit(this.events.removeSuccess, response);\n\n return response;\n\n } catch (e) {\n\n e = this._platform.client().makeError(e);\n\n this.emit(this.events.removeError, e);\n\n throw e;\n\n }\n\n }\n\n /**\n * @returns {Promise}\n */\n resubscribe() {\n\n return this.reset().setEventFilters(this.eventFilters()).subscribe();\n\n }\n\n /**\n * Remove subscription and disconnect from PUBNUB\n * This method resets subscription at client side but backend is not notified\n */\n reset() {\n this._clearTimeout();\n if (this.subscribed() && this._pubnub) this._pubnub.unsubscribe({channel: this._subscription.deliveryMode.address});\n this._subscription = {};\n return this;\n }\n\n _getFullEventFilters() {\n\n return this.eventFilters().map((event) => {\n return this._platform.createUrl(event);\n });\n\n }\n\n _setTimeout() {\n\n this._clearTimeout();\n\n if (!this.alive()) throw new Error('Subscription is not alive');\n\n poll((next)=> {\n\n if (this.alive()) return next();\n\n this.renew();\n\n }, Subscription._pollInterval, this._timeout);\n\n return this;\n\n }\n\n _clearTimeout() {\n\n stopPolling(this._timeout);\n\n return this;\n\n }\n\n _decrypt(message:any) {\n\n if (!this.subscribed()) throw new Error('No subscription');\n\n if (this._subscription.deliveryMode.encryptionKey) {\n\n var PUBNUB = this._pubnubFactory;\n\n message = PUBNUB.crypto_obj.decrypt(message, this._subscription.deliveryMode.encryptionKey, {\n encryptKey: false,\n keyEncoding: 'base64',\n keyLength: 128,\n mode: 'ecb'\n });\n\n }\n\n return message;\n\n }\n\n _notify(message:any) {\n\n this.emit(this.events.notification, this._decrypt(message));\n\n return this;\n\n }\n\n _subscribeAtPubnub():Subscription {\n\n if (!this.alive()) throw new Error('Subscription is not alive');\n\n var PUBNUB = this._pubnubFactory;\n\n this._pubnub = PUBNUB.init({\n ssl: true,\n subscribe_key: this._subscription.deliveryMode.subscriberKey\n });\n\n this._pubnub.ready();\n\n this._pubnub.subscribe({\n channel: this._subscription.deliveryMode.address,\n message: this._notify.bind(this),\n connect: () => {}\n });\n\n return this;\n\n }\n\n}\n\n//export interface ISubscription {\n// id?:string;\n// uri?: string;\n// eventFilters?:string[];\n// expirationTime?:string; // 2014-03-12T19:54:35.613Z\n// expiresIn?:number;\n// deliveryMode?: {\n// transportType?:string;\n// encryption?:boolean;\n// address?:string;\n// subscriberKey?:string;\n// encryptionKey?:string;\n// secretKey?:string;\n// };\n// creationTime?:string; // 2014-03-12T19:54:35.613Z\n// status?:string; // Active\n//}\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/subscription/Subscription.js\n **/","import Subscription from './Subscription';\nimport Queue from '../core/Queue';\n\nexport default class CachedSubscription extends Subscription {\n\n constructor(pubnubFactory, platform, cache, cacheKey) {\n\n super(pubnubFactory, platform);\n\n this._cache = cache;\n this._cacheKey = cacheKey;\n this._renewQueue = new Queue(this._cache, cacheKey + '-renew');\n this._resubscribeQueue = new Queue(this._cache, cacheKey + '-resubscribe');\n\n this.events = {\n ...this.events,\n queuedRenewSuccess: 'queuedRenewSuccess',\n queuedRenewError: 'queuedRenewError',\n queuedResubscribeSuccess: 'queuedResubscribeSuccess',\n queuedResubscribeError: 'queuedResubscribeError'\n };\n\n this.on(this.events.renewError, () => {\n this.resubscribe();\n });\n\n this.on([this.events.subscribeSuccess, this.events.renewSuccess], () => {\n this._cache.setItem(this._cacheKey, this.subscription());\n });\n\n this.on(this.events.removeSuccess, () => {\n this._cache.removeItem(this._cacheKey);\n });\n\n }\n\n /**\n * TODO Combine with Platform.refresh and move elsewhere\n * @param actionCb\n * @param queue\n * @param successEvent\n * @param errorEvent\n * @param errorMessage\n * @return {*}\n * @private\n */\n async _queue(actionCb, queue, successEvent, errorEvent, errorMessage) {\n\n try {\n\n if (queue.isPaused()) {\n\n await queue.poll();\n\n if (!this.alive()) {\n throw new Error(errorMessage);\n }\n\n this.emit(successEvent, null);\n\n return null;\n\n }\n\n queue.pause();\n\n var res = await actionCb.call(this);\n\n queue.resume();\n\n this.emit(successEvent, res);\n\n return res;\n\n } catch (e) {\n\n this.emit(errorEvent, e);\n\n throw e;\n\n }\n\n }\n\n /**\n * @returns {Promise