text: const Alexa = require('ask-sdk-core');
  // i18n dependency
  const i18n = require('i18next');
  const languageStrings = require('./languageStrings');
  const constants = require('./constants');
  
  // This request interceptor will log all incoming requests to this lambda
  const LoggingRequestInterceptor = {
      process(handlerInput) {
          console.log(`Incoming request: ${JSON.stringify(handlerInput.requestEnvelope)}`);
      }
  };
  
  // This response interceptor will log all outgoing responses of this lambda
  const LoggingResponseInterceptor = {
      process(handlerInput, response) {
          console.log(`Outgoing response: ${JSON.stringify(response)}`);
      }
  };
  
  // This request interceptor will bind a translation function 't' to the handlerInput
  // Additionally it will handle picking a random value if instead of a string it receives an array
  const LocalisationRequestInterceptor = {
      process(handlerInput) {
          const localisationClient = i18n.init({
              lng: Alexa.getLocale(handlerInput.requestEnvelope),
              resources: languageStrings,
              returnObjects: true
          });
          localisationClient.localise = function localise() {
              const args = arguments;
              const value = i18n.t(...args);
              if (Array.isArray(value)) {
                  return value[Math.floor(Math.random() * value.length)];
              }
              return value;
          };
          handlerInput.t = function translate(...args) {
              return localisationClient.localise(...args);
          }
      }
  };
  
  /* *
   * Below we use async and await ( more info: javascript.info/async-await )
   * It's a way to wrap promises and waait for the result of an external async operation
   * Like getting and saving the persistent attributes
   * */
  const LoadAttributesRequestInterceptor = {
      async process(handlerInput) {
          const {attributesManager, requestEnvelope} = handlerInput;
          const sessionAttributes = attributesManager.getSessionAttributes();
          // the "loaded" check is because the "new" session flag is lost if there's a one shot utterance that hits an intent with auto-delegate
          if (Alexa.isNewSession(requestEnvelope) || !sessionAttributes['loaded']){ //is this a new session? not loaded from db?
              const persistentAttributes = await attributesManager.getPersistentAttributes() || {};
              console.log('Loading from persistent storage: ' + JSON.stringify(persistentAttributes));
              persistentAttributes['loaded'] = true;
              //copy persistent attribute to session attributes
              attributesManager.setSessionAttributes(persistentAttributes); // ALL persistent attributtes are now session attributes
          }
      }
  };
  
  // If you disable the skill and reenable it the userId might change and you loose the persistent attributes saved below as userId is the primary key
  const SaveAttributesResponseInterceptor = {
      async process(handlerInput, response) {
          if (!response) return; // avoid intercepting calls that have no outgoing response due to errors
          const {attributesManager, requestEnvelope} = handlerInput;
          const sessionAttributes = attributesManager.getSessionAttributes();
          const shouldEndSession = (typeof response.shouldEndSession === "undefined" ? true : response.shouldEndSession); //is this a session end?
          // the "loaded" check is because the session "new" flag is lost if there's a one shot utterance that hits an intent with auto-delegate
          const loadedThisSession = sessionAttributes['loaded'];
          if ((shouldEndSession || Alexa.getRequestType(requestEnvelope) === 'SessionEndedRequest') && loadedThisSession) { // skill was stopped or timed out
              // we increment a persistent session counter here
              sessionAttributes['sC'] = sessionAttributes['sC'] ? sessionAttributes['sC'] + 1 : 1;
              // limiting save of session attributes to the ones we want to make persistent
              for (var key in sessionAttributes) {
                  if (!constants.PERSISTENT_ATTRIBUTES_NAMES.includes(key))
                      delete sessionAttributes[key];
              }
              console.log('Saving to persistent storage:' + JSON.stringify(sessionAttributes));
              attributesManager.setPersistentAttributes(sessionAttributes);
              await attributesManager.savePersistentAttributes();
          }
      }
  };
  
  // If you disable the skill and reenable it the userId might change and the user will have to grant the permission to access the name again
  const LoadNameRequestInterceptor = {
      async process(handlerInput) {
          const {attributesManager, serviceClientFactory, requestEnvelope} = handlerInput;
          const sessionAttributes = attributesManager.getSessionAttributes();
          
          console.log("LoadNameRequestInterceptor");
          
          if (!sessionAttributes['name']){
              // let's try to get the given name via the Customer Profile API
              // don't forget to enable this permission in your skill configuratiuon (Build tab -> Permissions)
              // or you'll get a SessionEndedRequest with an ERROR of type INVALID_RESPONSE
              // Per our policies you can't make personal data persistent so we limit "name" to session attributes
              try {
                  const {permissions} = requestEnvelope.context.System.user;
                  
                  console.log("requestEnvelope.context.System.user: " + requestEnvelope.context.System.user);
          
                  if (!(permissions && permissions.consentToken))
                      throw { statusCode: 401, message: 'No permissions available' }; // there are zero permissions, no point in intializing the API
                  const upsServiceClient = serviceClientFactory.getUpsServiceClient();
                  const profileName = await upsServiceClient.getProfileGivenName();
                  console.log("profileName: " + profileName);
                  if (profileName) { // the user might not have set the name
                      //save to session attributes
                      sessionAttributes['name'] = profileName;
                      console.log("profileName added to session: " + JSON.stringify(sessionAttributes));
                  }
              } catch (error) {
                  console.log(JSON.stringify(error));
                  if (error.statusCode === 401 || error.statusCode === 403) {
                      // the user needs to enable the permissions for given name, let's append a permissions card to the response.
                      handlerInput.responseBuilder.withAskForPermissionsConsentCard(constants.GIVEN_NAME_PERMISSION);
                  }
              }
          }
      }
  };
  
  const LoadTimezoneRequestInterceptor = {
      async process(handlerInput) {
          const {attributesManager, serviceClientFactory, requestEnvelope} = handlerInput;
          const sessionAttributes = attributesManager.getSessionAttributes();
          const deviceId = Alexa.getDeviceId(requestEnvelope);
  
          if (!sessionAttributes['timezone']){
              // let's try to get the timezone via the UPS API
              // (no permissions required but it might not be set up)
              try {
                  const upsServiceClient = serviceClientFactory.getUpsServiceClient();
                  const timezone = await upsServiceClient.getSystemTimeZone(deviceId);
                  if (timezone) { // the user might not have set the timezone yet
                      console.log('Got timezone from device: ' + timezone);
                      //save to session and persisten attributes
                      sessionAttributes['timezone'] = timezone;
                  }
              } catch (error) {
                  console.log(JSON.stringify(error));
              }
          }
      }
  };
  
  module.exports = {
      LoggingRequestInterceptor,
      LoggingResponseInterceptor,
      LocalisationRequestInterceptor,
      LoadAttributesRequestInterceptor,
      SaveAttributesResponseInterceptor,
      LoadNameRequestInterceptor,
      LoadTimezoneRequestInterceptor
  }