docs: function callbackMiddleware () {
  
      /**
       * Sets action, where to go back, when user responds with text
       *
       * @param {string} action - relative or absolute action (usualy current action)
       * @param {string|null} [callbackContext] - context of callback
       * @param {string|null} [callbackText] - custom text response
       * @returns {this}
       * @alias module:callbackMiddleware
       * @deprecated - use res.runBookmark()
       * @typicalname res
       * @example
       *
       * bot.use('myAction', (req, res) => {
       *     res.setCallback('myAction'); // return back
       * });
       */
      function setCallback (action, callbackContext = null, callbackText = null) {
          const callbackAction = this.toAbsoluteAction(action);
  
          this.setState({
              [ACTION]: callbackAction,
              [CONTEXT]: callbackContext || DEFAULT,
              [TEXT]: callbackText
          });
  
          return this;
      }
  
      /**
       * Returns true, when callback has been prevously set.
       * It's usefull, when you don't want to bouce back the methods.
       *
       * @param {string} [callbackContext]
       * @returns {boolean}
       * @alias module:callbackMiddleware
       * @deprecated - use res.runBookmark()
       * @example
       * bot.use(['fooRoute', /^foo$/], (req, res) => {
       *     // set callback, only when this request does not have one
       *     if (!req.hasCallback()) {
       *         res.setCallback('fooRoute');
       *     }
       * });
       */
      function hasCallback (callbackContext = null) {
          if (!this.state[ACTION]
              || callbackContext === this.state[CONTEXT]
              || !this.isText()) {
  
              return false;
          }
          return true;
      }
  
      /**
       * Returns true, when user is comming back from callback
       * Comeback is initialised with `res.proceedCallback()` or quick reply
       * Usefull for hidding the text, user has already seen
       *
       * @param {string} [callbackContext]
       * @returns {boolean}
       * @alias module:callbackMiddleware
       * @deprecated - use res.runBookmark()
       * @example
       * bot.use(['fooRoute', /^foo$/], (req, res) => {
       *     // set callback, only when this request does not have one
       *     if (!req.isFromCallback()) {
       *         res.text('this is the response, you dont want to read again');
       *     }
       * });
       */
      function isFromCallback (callbackContext = null) {
          const fromCallback = this.action(true)._isFromCallback;
  
          if (callbackContext === null) {
              return !!fromCallback;
          }
          return fromCallback === callbackContext;
      }
  
      /**
       * Proceed a callback, when exists
       * (go to action, where the callback has been previously set)
       * Returns true, when postback will occur
       *
       * @param {Object} state - conversation state
       * @param {boolean} isText - true if the request is text
       * @param {Function} rootPostBack - the root router postback function
       * @returns {boolean}
       * @alias module:callbackMiddleware
       * @deprecated - use res.runBookmark()
       * @example
       * bot.use(['fooRoute', /^foo$/], (req, res) => {
       *     // set callback, only when this request does not have one
       *     if (!res.proceedCallback()) {
       *         res.text('this is the followup question', {
       *             followupAction: 'Continue'
       *         });
       *     }
       * });
       */
      function proceedCallback (state, isText, rootPostBack) {
  
          return function (callbackContext = null) {
              if (!state[ACTION]
                  || !isText
                  || callbackContext === state[CONTEXT]
                  || state[ACTION] === `${this.path === '/' ? '' : this.path}${this.routePath}`) {
  
                  return false;
              }
              rootPostBack(state[ACTION], {
                  _isFromCallback: state[CONTEXT]
              });
              return true;
          };
      }
  
      /**
       * Adds "back" quick reply to other replies
       * (alternative to `proceedCallback()`)
       *
       * @param {Object} state - conversation state
       * @param {boolean} isText - true if the request is text
       * @returns {this}
       * @alias module:callbackMiddleware
       * @deprecated - use res.runBookmark()
       * @example
       * bot.use(['fooRoute', /^foo$/], (req, res) => {
       *     // ability get back to previous context
       *     res.addCallbackQuickReply('Go back');
       *
       *     res.text('So, what you want?', {
       *         barRoute: 'Go to bar'
       *     });
       * });
       */
      function addCallbackQuickReply (state, isText) {
          return function (replyText) {
              if (!state[ACTION]
                      || !isText
                      || state[ACTION] === `${this.path === '/' ? '' : this.path}${this.routePath}`) {
                  return this;
              }
  
              const text = state[TEXT] || replyText;
  
              if (!text) {
                  return this;
              }
  
              return this.addQuickReply(state[ACTION], text, {
                  _isFromCallback: state[CONTEXT]
              }, true);
          };
      }
  
  
      return (req, res, postBack) => {
  
          const isText = req.isText();
  
          Object.assign(res, {
              addCallbackQuickReply: addCallbackQuickReply(req.state, isText),
              proceedCallback: proceedCallback(req.state, isText, postBack),
              setCallback
          });
  
          Object.assign(req, {
              isFromCallback,
              hasCallback
          });
  
          if (req.state[ACTION]) {
              res.setState({
                  [ACTION]: null,
                  [CONTEXT]: null,
                  [TEXT]: null
              });
          }
  
          return Router.CONTINUE;
      };
  }