text: (function webpackUniversalModuleDefinition(root, factory) {
  	if(typeof exports === 'object' && typeof module === 'object')
  		module.exports = factory();
  	else if(typeof define === 'function' && define.amd)
  		define("library", [], factory);
  	else if(typeof exports === 'object')
  		exports["library"] = factory();
  	else
  		root["library"] = factory();
  })(global, function() {
  return /******/ (function(modules) { // webpackBootstrap
  /******/ 	// The module cache
  /******/ 	var installedModules = {};
  /******/
  /******/ 	// The require function
  /******/ 	function __webpack_require__(moduleId) {
  /******/
  /******/ 		// Check if module is in cache
  /******/ 		if(installedModules[moduleId]) {
  /******/ 			return installedModules[moduleId].exports;
  /******/ 		}
  /******/ 		// Create a new module (and put it into the cache)
  /******/ 		var module = installedModules[moduleId] = {
  /******/ 			i: moduleId,
  /******/ 			l: false,
  /******/ 			exports: {}
  /******/ 		};
  /******/
  /******/ 		// Execute the module function
  /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  /******/
  /******/ 		// Flag the module as loaded
  /******/ 		module.l = true;
  /******/
  /******/ 		// Return the exports of the module
  /******/ 		return module.exports;
  /******/ 	}
  /******/
  /******/
  /******/ 	// expose the modules object (__webpack_modules__)
  /******/ 	__webpack_require__.m = modules;
  /******/
  /******/ 	// expose the module cache
  /******/ 	__webpack_require__.c = installedModules;
  /******/
  /******/ 	// define getter function for harmony exports
  /******/ 	__webpack_require__.d = function(exports, name, getter) {
  /******/ 		if(!__webpack_require__.o(exports, name)) {
  /******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
  /******/ 		}
  /******/ 	};
  /******/
  /******/ 	// define __esModule on exports
  /******/ 	__webpack_require__.r = function(exports) {
  /******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  /******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  /******/ 		}
  /******/ 		Object.defineProperty(exports, '__esModule', { value: true });
  /******/ 	};
  /******/
  /******/ 	// create a fake namespace object
  /******/ 	// mode & 1: value is a module id, require it
  /******/ 	// mode & 2: merge all properties of value into the ns
  /******/ 	// mode & 4: return value when already ns object
  /******/ 	// mode & 8|1: behave like require
  /******/ 	__webpack_require__.t = function(value, mode) {
  /******/ 		if(mode & 1) value = __webpack_require__(value);
  /******/ 		if(mode & 8) return value;
  /******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
  /******/ 		var ns = Object.create(null);
  /******/ 		__webpack_require__.r(ns);
  /******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
  /******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
  /******/ 		return ns;
  /******/ 	};
  /******/
  /******/ 	// getDefaultExport function for compatibility with non-harmony modules
  /******/ 	__webpack_require__.n = function(module) {
  /******/ 		var getter = module && module.__esModule ?
  /******/ 			function getDefault() { return module['default']; } :
  /******/ 			function getModuleExports() { return module; };
  /******/ 		__webpack_require__.d(getter, 'a', getter);
  /******/ 		return getter;
  /******/ 	};
  /******/
  /******/ 	// Object.prototype.hasOwnProperty.call
  /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  /******/
  /******/ 	// __webpack_public_path__
  /******/ 	__webpack_require__.p = "";
  /******/
  /******/
  /******/ 	// Load entry module and return exports
  /******/ 	return __webpack_require__(__webpack_require__.s = "./src/index.js");
  /******/ })
  /************************************************************************/
  /******/ ({
  
  /***/ "./src/hooks/cache.js":
  /*!****************************!*\
    !*** ./src/hooks/cache.js ***!
    \****************************/
  /*! no static exports found */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.cache = cache;
  exports.removeCacheInformation = removeCacheInformation;
  
  /**
   * After hook - generates a cache object that is needed
   * for the redis hook and the express middelware.
   */
  const defaults = {
    defaultDuration: 3600 * 24
  };
  
  function cache(options) {
    // eslint-disable-line no-unused-vars
    return function (hook) {
      const cacheOptions = hook.app.get('redisCache');
      options = Object.assign({}, defaults, cacheOptions, options);
  
      if (!hook.result.hasOwnProperty('cache')) {
        let cache = {};
  
        if (Array.isArray(hook.result)) {
          const array = hook.result;
          cache.wrapped = array;
          hook.result = {};
        }
  
        cache = Object.assign({}, cache, {
          cached: false,
          duration: options.duration || options.defaultDuration
        });
        hook.result.cache = cache;
      }
  
      return Promise.resolve(hook);
    };
  }
  
  ;
  
  function removeCacheInformation(options) {
    // eslint-disable-line no-unused-vars
    return function (hook) {
      if (hook.result.hasOwnProperty('cache')) {
        delete hook.result.cache;
      }
  
      return Promise.resolve(hook);
    };
  }
  
  ;
  
  /***/ }),
  
  /***/ "./src/hooks/helpers/path.js":
  /*!***********************************!*\
    !*** ./src/hooks/helpers/path.js ***!
    \***********************************/
  /*! no static exports found */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.parsePath = parsePath;
  
  var _qs = _interopRequireDefault(__webpack_require__(/*! qs */ "qs"));
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function parseNestedPath(path, params) {
    const re = new RegExp(':([^\\/\\?]+)\\??', 'g');
    let match = null;
  
    while ((match = re.exec(path)) !== null) {
      if (Object.keys(params.route).includes(match[1])) {
        path = path.replace(match[0], params.route[match[1]]);
      }
    }
  
    return path;
  }
  
  function parsePath(hook, config = {
    removePathFromCacheKey: false,
    parseNestedRoutes: false
  }) {
    const q = hook.params.query || {};
    const remove = config.removePathFromCacheKey;
    const parseNestedRoutes = config.parseNestedRoutes;
    let path = remove && hook.id ? '' : `${hook.path}`;
  
    if (!remove && parseNestedRoutes) {
      path = parseNestedPath(path, hook.params);
    }
  
    if (hook.id) {
      if (path.length !== 0 && !remove) {
        path += '/';
      }
  
      if (Object.keys(q).length > 0) {
        path += `${hook.id}?${_qs.default.stringify(q, {
          encode: false
        })}`;
      } else {
        path += `${hook.id}`;
      }
    } else {
      if (Object.keys(q).length > 0) {
        path += `?${_qs.default.stringify(q, {
          encode: false
        })}`;
      }
    }
  
    return path;
  }
  
  /***/ }),
  
  /***/ "./src/hooks/redis.js":
  /*!****************************!*\
    !*** ./src/hooks/redis.js ***!
    \****************************/
  /*! no static exports found */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.before = before;
  exports.after = after;
  
  var _moment = _interopRequireDefault(__webpack_require__(/*! moment */ "moment"));
  
  var _chalk = _interopRequireDefault(__webpack_require__(/*! chalk */ "chalk"));
  
  var _path = __webpack_require__(/*! ./helpers/path */ "./src/hooks/helpers/path.js");
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  const defaults = {
    env: 'production',
    defaultDuration: 3600 * 24,
    immediateCacheKey: false
  };
  
  function before(options) {
    // eslint-disable-line no-unused-vars
    return function (hook) {
      const cacheOptions = hook.app.get('redisCache');
      options = Object.assign({}, defaults, cacheOptions, options);
      return new Promise(resolve => {
        const client = hook.app.get('redisClient');
  
        if (!client) {
          resolve(hook);
        }
  
        const path = (0, _path.parsePath)(hook, options);
        client.get(path, (err, reply) => {
          if (err !== null) resolve(hook);
  
          if (reply) {
            let data = JSON.parse(reply);
            const duration = (0, _moment.default)(data.cache.expiresOn).format('DD MMMM YYYY - HH:mm:ss');
            hook.result = data;
            resolve(hook);
            /* istanbul ignore next */
  
            if (options.env !== 'test') {
              console.log(`${_chalk.default.cyan('[redis]')} returning cached value for ${_chalk.default.green(path)}.`);
              console.log(`> Expires on ${duration}.`);
            }
          } else {
            if (options.immediateCacheKey === true) {
              hook.params.cacheKey = path;
            }
  
            resolve(hook);
          }
        });
      });
    };
  }
  
  ;
  
  function after(options) {
    // eslint-disable-line no-unused-vars
    return function (hook) {
      const cacheOptions = hook.app.get('redisCache');
      options = Object.assign({}, defaults, cacheOptions, options);
      return new Promise(resolve => {
        if (!hook.result.cache.cached) {
          const duration = hook.result.cache.duration || options.defaultDuration;
          const client = hook.app.get('redisClient');
  
          if (!client) {
            resolve(hook);
          }
  
          const path = hook.params.cacheKey || (0, _path.parsePath)(hook, options); // adding a cache object
  
          Object.assign(hook.result.cache, {
            cached: true,
            duration: duration,
            expiresOn: (0, _moment.default)().add(_moment.default.duration(duration, 'seconds')),
            parent: hook.path,
            group: hook.path ? `group-${hook.path}` : '',
            key: path
          });
          client.set(path, JSON.stringify(hook.result));
          client.expire(path, hook.result.cache.duration);
  
          if (hook.path) {
            client.rpush(hook.result.cache.group, path);
          }
          /* istanbul ignore next */
  
  
          if (options.env !== 'test') {
            console.log(`${_chalk.default.cyan('[redis]')} added ${_chalk.default.green(path)} to the cache.`);
            console.log(`> Expires in ${_moment.default.duration(duration, 'seconds').humanize()}.`);
          }
        }
  
        if (hook.result.cache.hasOwnProperty('wrapped')) {
          const {
            wrapped
          } = hook.result.cache;
          hook.result = wrapped;
        }
  
        resolve(hook);
      });
    };
  }
  
  ;
  
  /***/ }),
  
  /***/ "./src/index.js":
  /*!**********************!*\
    !*** ./src/index.js ***!
    \**********************/
  /*! no static exports found */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = void 0;
  
  var _cache = _interopRequireDefault(__webpack_require__(/*! ./routes/cache */ "./src/routes/cache.js"));
  
  var _redisClient = _interopRequireDefault(__webpack_require__(/*! ./redisClient */ "./src/redisClient.js"));
  
  var _cache2 = __webpack_require__(/*! ./hooks/cache */ "./src/hooks/cache.js");
  
  var _redis = __webpack_require__(/*! ./hooks/redis */ "./src/hooks/redis.js");
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  var _default = {
    redisClient: _redisClient.default,
    cacheRoutes: _cache.default,
    hookCache: _cache2.cache,
    hookRemoveCacheInformation: _cache2.removeCacheInformation,
    redisBeforeHook: _redis.before,
    redisAfterHook: _redis.after
  };
  exports.default = _default;
  module.exports = exports.default;
  
  /***/ }),
  
  /***/ "./src/redisClient.js":
  /*!****************************!*\
    !*** ./src/redisClient.js ***!
    \****************************/
  /*! no static exports found */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = redisClient;
  
  var _redis = _interopRequireDefault(__webpack_require__(/*! redis */ "redis"));
  
  var _chalk = _interopRequireDefault(__webpack_require__(/*! chalk */ "chalk"));
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function redisClient() {
    // eslint-disable-line no-unused-vars
    const app = this;
    const cacheOptions = app.get('redisCache') || {};
    const retryInterval = cacheOptions.retryInterval || 10000;
    const redisOptions = Object.assign({}, this.get('redis'), {
      retry_strategy: function (options) {
        // eslint-disable-line camelcase
        app.set('redisClient', undefined);
        /* istanbul ignore next */
  
        if (cacheOptions.env !== 'test') {
          console.log(`${_chalk.default.yellow('[redis]')} not connected`);
        }
  
        return retryInterval;
      }
    });
  
    const client = _redis.default.createClient(redisOptions);
  
    app.set('redisClient', client);
    client.on('ready', () => {
      app.set('redisClient', client);
      /* istanbul ignore next */
  
      if (cacheOptions.env !== 'test') {
        console.log(`${_chalk.default.green('[redis]')} connected`);
      }
    });
    return this;
  }
  
  module.exports = exports.default;
  
  /***/ }),
  
  /***/ "./src/routes/cache.js":
  /*!*****************************!*\
    !*** ./src/routes/cache.js ***!
    \*****************************/
  /*! no static exports found */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = void 0;
  
  var _express = _interopRequireDefault(__webpack_require__(/*! express */ "express"));
  
  var _redis = _interopRequireDefault(__webpack_require__(/*! ./helpers/redis */ "./src/routes/helpers/redis.js"));
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  const HTTP_OK = 200;
  const HTTP_NO_CONTENT = 204;
  const HTTP_SERVER_ERROR = 500;
  const HTTP_NOT_FOUND = 404;
  
  function routes(app) {
    const router = _express.default.Router();
  
    const client = app.get('redisClient');
    const h = new _redis.default(client);
    router.get('/clear', (req, res) => {
      client.flushall('ASYNC', () => {
        res.status(HTTP_OK).json({
          message: 'Cache cleared',
          status: HTTP_OK
        });
      });
    }); // clear a unique route
    // clear a unique route
  
    router.get('/clear/single/*', (req, res) => {
      let target = decodeURIComponent(req.params[0]); // Formated options following ?
  
      const query = req.query;
      const hasQueryString = query && Object.keys(query).length !== 0; // Target should always be defined as Express router raises 404
      // as route is not handled
  
      if (target.length) {
        if (hasQueryString) {
          // Keep queries in a single string with the taget
          target = decodeURIComponent(req.url.split('/').slice(3).join('/'));
        } // Gets the value of a key in the redis client
  
  
        client.get(`${target}`, (err, reply) => {
          if (err) {
            res.status(HTTP_SERVER_ERROR).json({
              message: 'something went wrong' + err.message
            });
          } else {
            // If the key existed
            if (reply) {
              // Clear existing cached key
              h.clearSingle(target).then(r => {
                res.status(HTTP_OK).json({
                  message: `cache cleared for key (${hasQueryString ? 'with' : 'without'} params): ${target}`,
                  status: HTTP_OK
                });
              });
            } else {
              /**
               * Empty reply means the key does not exist.
               * Must use HTTP_OK with express as HTTP's RFC stats 204 should not
               * provide a body, message would then be lost.
               */
              res.status(HTTP_OK).json({
                message: `cache already cleared for key (${hasQueryString ? 'with' : 'without'} params): ${target}`,
                status: HTTP_NO_CONTENT
              });
            }
          }
        });
      } else {
        res.status(HTTP_NOT_FOUND).end();
      }
    }); // clear a group
  
    router.get('/clear/group/*', (req, res) => {
      let target = decodeURIComponent(req.params[0]); // Target should always be defined as Express router raises 404
      // as route is not handled
  
      if (target.length) {
        target = 'group-' + target; // Returns elements of the list associated to the target/key 0 being the
        // first and -1 specifying get all till the latest
  
        client.lrange(target, 0, -1, (err, reply) => {
          if (err) {
            res.status(HTTP_SERVER_ERROR).json({
              message: 'something went wrong' + err.message
            });
          } else {
            // If the list/group existed and contains something
            if (reply && Array.isArray(reply) && reply.length > 0) {
              // Clear existing cached group key
              h.clearGroup(target).then(r => {
                res.status(HTTP_OK).json({
                  message: `cache cleared for the group key: ${decodeURIComponent(req.params[0])}`,
                  status: HTTP_OK
                });
              });
            } else {
              /**
               * Empty reply means the key does not exist.
               * Must use HTTP_OK with express as HTTP's RFC stats 204 should not
               * provide a body, message would then be lost.
               */
              res.status(HTTP_OK).json({
                message: `cache already cleared for the group key: ${decodeURIComponent(req.params[0])}`,
                status: HTTP_NO_CONTENT
              });
            }
          }
        });
      } else {
        res.status(HTTP_NOT_FOUND).end();
      }
    }); // add route to display cache index
    // this has been removed for performance issues
    // router.get('/index', (req, res) => {
    //   let results = new Set();
    //   h.scanAsync('0', '*', results)
    //     .then(data => {
    //       res.status(200).json(data);
    //     })
    //     .catch(err => {
    //       res.status(404).json(err);
    //     });
    // });
  
    return router;
  }
  
  var _default = routes;
  exports.default = _default;
  module.exports = exports.default;
  
  /***/ }),
  
  /***/ "./src/routes/helpers/redis.js":
  /*!*************************************!*\
    !*** ./src/routes/helpers/redis.js ***!
    \*************************************/
  /*! no static exports found */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = void 0;
  
  class RedisCache {
    constructor(client) {
      this.client = client;
    }
    /**
     * scan the redis index
     */
    // scan() {
    //   // starts at 0 if cursor is again 0 it means the iteration is finished
    //   let cursor = '0';
    //   return new Promise((resolve, reject) => {
    //     this.client.scan(cursor, 'MATCH', '*', 'COUNT', '100', (err, reply) => {
    //       if (err) {
    //         reject(err);
    //       }
    //       cursor = reply[0];
    //       if (cursor === '0') {
    //         resolve(reply[1]);
    //       } else {
    //         // do your processing
    //         // reply[1] is an array of matched keys.
    //         // console.log(reply[1]);
    //         return this.scan();
    //       }
    //       return false;
    //     });
    //   });
    // }
  
    /**
     * Async scan of the redis index
     * Do not for get to passin a Set
     * myResults = new Set();
     *
     * scanAsync('0', "NOC-*[^listen]*", myResults).map(
     *   myResults => { console.log( myResults); }
     * );
     *
     * @param {String} cursor - string '0'
     * @param {String} patern - string '0'
     * @param {Set} returnSet - pass a set to have unique keys
     */
    // scanAsync(cursor, pattern, returnSet) {
    //   // starts at 0 if cursor is again 0 it means the iteration is finished
    //   return new Promise((resolve, reject) => {
    //     this.client.scan(cursor, 'MATCH', pattern, 'COUNT', '100', (err, reply) => {
    //       if (err) {
    //         reject(err);
    //       }
    //       cursor = reply[0];
    //       const keys = reply[1];
    //       keys.forEach((key, i) => {
    //         returnSet.add(key);
    //       });
    //       if (cursor === '0') {
    //         resolve(Array.from(returnSet));
    //       }
    //       return this.scanAsync(cursor, pattern, returnSet);
    //     });
    //   });
    // }
  
    /**
     * Clean single item from the cache
     * @param {string} key - the key to find in redis
     */
  
  
    clearSingle(key) {
      return new Promise((resolve, reject) => {
        this.client.del(`${key}`, (err, reply) => {
          if (err) reject(false);
  
          if (reply === 1) {
            resolve(true);
          }
  
          resolve(false);
        });
      });
    }
    /**
     * Clear a group
     * @param {string} key - key of the group to clean
     */
  
  
    clearGroup(key) {
      return new Promise((resolve, reject) => {
        this.client.lrange(key, 0, -1, (err, reply) => {
          if (err) {
            reject(err);
          }
  
          this.clearAll(reply).then(this.client.del(key, (e, r) => {
            resolve(r === 1);
          }));
        });
      });
    }
    /**
     * Clear all keys of a redis list
     * @param {Object[]} array
     */
  
  
    clearAll(array) {
      return new Promise(resolve => {
        if (!array.length) resolve(false);
        let i = 0;
  
        for (i; i < array.length; i++) {
          this.clearSingle(array[i]).then(r => {
            if (i === array.length - 1) {
              resolve(r);
            }
          });
        }
      });
    }
  
  }
  
  exports.default = RedisCache;
  ;
  module.exports = exports.default;
  
  /***/ }),
  
  /***/ "chalk":
  /*!************************!*\
    !*** external "chalk" ***!
    \************************/
  /*! no static exports found */
  /***/ (function(module, exports) {
  
  module.exports = require("chalk");
  
  /***/ }),
  
  /***/ "express":
  /*!**************************!*\
    !*** external "express" ***!
    \**************************/
  /*! no static exports found */
  /***/ (function(module, exports) {
  
  module.exports = require("express");
  
  /***/ }),
  
  /***/ "moment":
  /*!*************************!*\
    !*** external "moment" ***!
    \*************************/
  /*! no static exports found */
  /***/ (function(module, exports) {
  
  module.exports = require("moment");
  
  /***/ }),
  
  /***/ "qs":
  /*!*********************!*\
    !*** external "qs" ***!
    \*********************/
  /*! no static exports found */
  /***/ (function(module, exports) {
  
  module.exports = require("qs");
  
  /***/ }),
  
  /***/ "redis":
  /*!************************!*\
    !*** external "redis" ***!
    \************************/
  /*! no static exports found */
  /***/ (function(module, exports) {
  
  module.exports = require("redis");
  
  /***/ })
  
  /******/ });
  });
  //# sourceMappingURL=library.js.map