<commit_before>// Alexa Fact Skill - Sample for Beginners
/* eslint no-use-before-define: 0 */
// sets up dependencies
const Alexa = require('ask-sdk-core');
const i18n = require('i18next');
const sprintf = require('i18next-sprintf-postprocessor');

// core functionality for fact skill
const GetNewFactHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    // checks request type
    return request.type === 'LaunchRequest'
      || (request.type === 'IntentRequest'
        && request.intent.name === 'GetNewFactIntent');
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    // gets a random fact by assigning an array to the variable
    // the random item from the array will be selected by the i18next library
    // the i18next library is set up in the Request Interceptor
    const randomFact = requestAttributes.t('FACTS');
    // concatenates a standard message with the random fact
    const speakOutput = requestAttributes.t('GET_FACT_MESSAGE') + randomFact;

    return handlerInput.responseBuilder
      .speak(speakOutput)
      .withSimpleCard(requestAttributes.t('SKILL_NAME'), randomFact)
      .getResponse();
  },
};

const HelpHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('HELP_MESSAGE'))
      .reprompt(requestAttributes.t('HELP_REPROMPT'))
      .getResponse();
  },
};

const FallbackHandler = {
  // 2018-Aug-01: AMAZON.FallbackIntent is only currently available in en-* locales.
  //              This handler will not be triggered except in those locales, so it can be
  //              safely deployed for any locale.
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.FallbackIntent';
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('FALLBACK_MESSAGE'))
      .reprompt(requestAttributes.t('FALLBACK_REPROMPT'))
      .getResponse();
  },
};

const ExitHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && (request.intent.name === 'AMAZON.CancelIntent'
        || request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('STOP_MESSAGE'))
      .getResponse();
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    console.log(`Error handled: ${error.message}`);
    console.log(`Error stack: ${error.stack}`);
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('ERROR_MESSAGE'))
      .reprompt(requestAttributes.t('ERROR_MESSAGE'))
      .getResponse();
  },
};

const LocalizationInterceptor = {
  process(handlerInput) {
    const localizationClient = i18n.use(sprintf).init({
      lng: handlerInput.requestEnvelope.request.locale,
      resources: languageStrings,
    });
    localizationClient.localize = function localize() {
      const args = arguments;
      const values = [];
      for (let i = 1; i < args.length; i += 1) {
        values.push(args[i]);
      }
      const value = i18n.t(args[0], {
        returnObjects: true,
        postProcess: 'sprintf',
        sprintf: values,
      });
      if (Array.isArray(value)) {
        return value[Math.floor(Math.random() * value.length)];
      }
      return value;
    };
    const attributes = handlerInput.attributesManager.getRequestAttributes();
    attributes.t = function translate(...args) {
      return localizationClient.localize(...args);
    };
  },
};

const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    GetNewFactHandler,
    HelpHandler,
    ExitHandler,
    FallbackHandler,
    SessionEndedRequestHandler,
  )
  .addRequestInterceptors(LocalizationInterceptor)
  .addErrorHandlers(ErrorHandler)
  .lambda();

// translations
const deData = {
  translation: {
    SKILL_NAME: 'Weltraumwissen',
    GET_FACT_MESSAGE: 'Hier sind deine Fakten: ',
    HELP_MESSAGE: 'Du kannst sagen, „Nenne mir einen Fakt über den Weltraum“, oder du kannst „Beenden“ sagen... Wie kann ich dir helfen?',
    HELP_REPROMPT: 'Wie kann ich dir helfen?',
    FALLBACK_MESSAGE: 'Die Fähigkeit Weltraumwissen kann dir dabei nicht helfen. Es kann Ihnen helfen, Fakten über den Raum zu entdecken, wenn Sie sagen, sagen Sie mir eine Weltraumtatsache Wie kann ich dir helfen?',
    FALLBACK_REPROMPT: 'Wie kann ich dir helfen?',
    ERROR_MESSAGE: 'Es ist ein Fehler aufgetreten.',
    STOP_MESSAGE: 'Auf Wiedersehen!',
    FACTS:
      [
        'Ein Jahr dauert auf dem Merkur nur 88 Tage.',
        'Die Venus ist zwar weiter von der Sonne entfernt, hat aber höhere Temperaturen als Merkur.',
        'Venus dreht sich entgegen dem Uhrzeigersinn, möglicherweise aufgrund eines früheren Zusammenstoßes mit einem Asteroiden.',
        'Auf dem Mars erscheint die Sonne nur halb so groß wie auf der Erde.',
        'Jupiter hat den kürzesten Tag aller Planeten.',
      ],
  },
};

const dedeData = {
  translation: {
    SKILL_NAME: 'Weltraumwissen auf Deutsch',
  },
};

const enData = {
  translation: {
    SKILL_NAME: 'Space Facts',
    GET_FACT_MESSAGE: 'Here\'s your fact: ',
    HELP_MESSAGE: 'You can say tell me a space fact, or, you can say exit... What can I help you with?',
    HELP_REPROMPT: 'What can I help you with?',
    FALLBACK_MESSAGE: 'The Space Facts skill can\'t help you with that.  It can help you discover facts about space if you say tell me a space fact. What can I help you with?',
    FALLBACK_REPROMPT: 'What can I help you with?',
    ERROR_MESSAGE: 'Sorry, an error occurred.',
    STOP_MESSAGE: 'Goodbye!',
    FACTS:
      [
        'A year on Mercury is just 88 days long.',
        'Despite being farther from the Sun, Venus experiences higher temperatures than Mercury.',
        'On Mars, the Sun appears about half the size as it does on Earth.',
        'Jupiter has the shortest day of all the planets.',
        'The Sun is an almost perfect sphere.',
      ],
  },
};

const enauData = {
  translation: {
    SKILL_NAME: 'Austrailian Space Facts',
  },
};

const encaData = {
  translation: {
    SKILL_NAME: 'Canadian Space Facts',
  },
};

const engbData = {
  translation: {
    SKILL_NAME: 'British Space Facts',
  },
};

const eninData = {
  translation: {
    SKILL_NAME: 'Indian Space Facts',
  },
};

const enusData = {
  translation: {
    SKILL_NAME: 'American Space Facts',
  },
};

const esData = {
  translation: {
    SKILL_NAME: 'Curiosidades del Espacio',
    GET_FACT_MESSAGE: 'Aquí está tu curiosidad: ',
    HELP_MESSAGE: 'Puedes decir dime una curiosidad del espacio o puedes decir salir... Cómo te puedo ayudar?',
    HELP_REPROMPT: 'Como te puedo ayudar?',
    FALLBACK_MESSAGE: 'La skill Curiosidades del Espacio no te puede ayudar con eso.  Te puede ayudar a descubrir curiosidades sobre el espacio si dices dime una curiosidad del espacio. Como te puedo ayudar?',
    FALLBACK_REPROMPT: 'Como te puedo ayudar?',
    ERROR_MESSAGE: 'Lo sentimos, se ha producido un error.',
    STOP_MESSAGE: 'Adiós!',
    FACTS:
        [
          'Un año en Mercurio es de solo 88 días',
          'A pesar de estar más lejos del Sol, Venus tiene temperaturas más altas que Mercurio',
          'En Marte el sol se ve la mitad de grande que en la Tierra',
          'Jupiter tiene el día más corto de todos los planetas',
          'El sol es una esféra casi perfecta',
        ],
  },
};

const esesData = {
  translation: {
    SKILL_NAME: 'Curiosidades del Espacio para España',
  },
};

const esmxData = {
  translation: {
    SKILL_NAME: 'Curiosidades del Espacio para México',
  },
};

const frData = {
  translation: {
    SKILL_NAME: 'Anecdotes de l\'Espace',
    GET_FACT_MESSAGE: 'Voici votre anecdote : ',
    HELP_MESSAGE: 'Vous pouvez dire donne-moi une anecdote, ou, vous pouvez dire stop... Comment puis-je vous aider?',
    HELP_REPROMPT: 'Comment puis-je vous aider?',
    FALLBACK_MESSAGE: 'La skill des anecdotes de l\'espace ne peux vous aider avec cela. Je peux vous aider à découvrir des anecdotes sur l\'espace si vous dites par exemple, donne-moi une anecdote. Comment puis-je vous aider?',
    FALLBACK_REPROMPT: 'Comment puis-je vous aider?',
    ERROR_MESSAGE: 'Désolé, une erreur est survenue.',
    STOP_MESSAGE: 'Au revoir!',
    FACTS:
        [
          'Une année sur Mercure ne dure que 88 jours.',
          'En dépit de son éloignement du Soleil, Vénus connaît des températures plus élevées que sur Mercure.',
          'Sur Mars, le Soleil apparaît environ deux fois plus petit que sur Terre.',
          'De toutes les planètes, Jupiter a le jour le plus court.',
          'Le Soleil est une sphère presque parfaite.',
        ],
  },
};

const frfrData = {
  translation: {
    SKILL_NAME: 'Anecdotes françaises de l\'espace',
  },
};

const itData = {
  translation: {
    SKILL_NAME: 'Aneddoti dallo spazio',
    GET_FACT_MESSAGE: 'Ecco il tuo aneddoto: ',
    HELP_MESSAGE: 'Puoi chiedermi un aneddoto dallo spazio o puoi chiudermi dicendo "esci"... Come posso aiutarti?',
    HELP_REPROMPT: 'Come posso aiutarti?',
    FALLBACK_MESSAGE: 'Non posso aiutarti con questo. Posso aiutarti a scoprire fatti e aneddoti sullo spazio, basta che mi chiedi di dirti un aneddoto. Come posso aiutarti?',
    FALLBACK_REPROMPT: 'Come posso aiutarti?',
    ERROR_MESSAGE: 'Spiacenti, si è verificato un errore.',
    STOP_MESSAGE: 'A presto!',
    FACTS:
      [
        'Sul pianeta Mercurio, un anno dura solamente 88 giorni.',
        'Pur essendo più lontana dal Sole, Venere ha temperature più alte di Mercurio.',
        'Su Marte il sole appare grande la metà che su la terra. ',
        'Tra tutti i pianeti del sistema solare, la giornata più corta è su Giove.',
        'Il Sole è quasi una sfera perfetta.',
      ],
  },
};

const ititData = {
  translation: {
    SKILL_NAME: 'Aneddoti dallo spazio',
  },
};

const jpData = {
  translation: {
    SKILL_NAME: '日本語版豆知識',
    GET_FACT_MESSAGE: '知ってましたか？',
    HELP_MESSAGE: '豆知識を聞きたい時は「豆知識」と、終わりたい時は「おしまい」と言ってください。どうしますか？',
    HELP_REPROMPT: 'どうしますか？',
    ERROR_MESSAGE: '申し訳ありませんが、エラーが発生しました',
    STOP_MESSAGE: 'さようなら',
    FACTS:
      [
        '水星の一年はたった88日です。',
        '金星は水星と比べて太陽より遠くにありますが、気温は水星よりも高いです。',
        '金星は反時計回りに自転しています。過去に起こった隕石の衝突が原因と言われています。',
        '火星上から見ると、太陽の大きさは地球から見た場合の約半分に見えます。',
        '木星の1日は全惑星の中で一番短いです。',
        '天の川銀河は約50億年後にアンドロメダ星雲と衝突します。',
      ],
  },
};

const jpjpData = {
  translation: {
    SKILL_NAME: '日本語版豆知識',
  },
};

// constructs i18n and l10n data structure
// translations for this sample can be found at the end of this file
const languageStrings = {
  'de': deData,
  'de-DE': dedeData,
  'en': enData,
  'en-AU': enauData,
  'en-CA': encaData,
  'en-GB': engbData,
  'en-IN': eninData,
  'en-US': enusData,
  'es': esData,
  'es-ES': esesData,
  'es-MX': esmxData,
  'fr': frData,
  'fr-FR': frfrData,
  'it': itData,
  'it-IT': ititData,
  'ja': jpData,
  'ja-JP': jpjpData,
};
<commit_msg>Auf Sie zu Du<commit_after>// Alexa Fact Skill - Sample for Beginners
/* eslint no-use-before-define: 0 */
// sets up dependencies
const Alexa = require('ask-sdk-core');
const i18n = require('i18next');
const sprintf = require('i18next-sprintf-postprocessor');

// core functionality for fact skill
const GetNewFactHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    // checks request type
    return request.type === 'LaunchRequest'
      || (request.type === 'IntentRequest'
        && request.intent.name === 'GetNewFactIntent');
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    // gets a random fact by assigning an array to the variable
    // the random item from the array will be selected by the i18next library
    // the i18next library is set up in the Request Interceptor
    const randomFact = requestAttributes.t('FACTS');
    // concatenates a standard message with the random fact
    const speakOutput = requestAttributes.t('GET_FACT_MESSAGE') + randomFact;

    return handlerInput.responseBuilder
      .speak(speakOutput)
      .withSimpleCard(requestAttributes.t('SKILL_NAME'), randomFact)
      .getResponse();
  },
};

const HelpHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('HELP_MESSAGE'))
      .reprompt(requestAttributes.t('HELP_REPROMPT'))
      .getResponse();
  },
};

const FallbackHandler = {
  // 2018-Aug-01: AMAZON.FallbackIntent is only currently available in en-* locales.
  //              This handler will not be triggered except in those locales, so it can be
  //              safely deployed for any locale.
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.FallbackIntent';
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('FALLBACK_MESSAGE'))
      .reprompt(requestAttributes.t('FALLBACK_REPROMPT'))
      .getResponse();
  },
};

const ExitHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && (request.intent.name === 'AMAZON.CancelIntent'
        || request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('STOP_MESSAGE'))
      .getResponse();
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    console.log(`Error handled: ${error.message}`);
    console.log(`Error stack: ${error.stack}`);
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('ERROR_MESSAGE'))
      .reprompt(requestAttributes.t('ERROR_MESSAGE'))
      .getResponse();
  },
};

const LocalizationInterceptor = {
  process(handlerInput) {
    const localizationClient = i18n.use(sprintf).init({
      lng: handlerInput.requestEnvelope.request.locale,
      resources: languageStrings,
    });
    localizationClient.localize = function localize() {
      const args = arguments;
      const values = [];
      for (let i = 1; i < args.length; i += 1) {
        values.push(args[i]);
      }
      const value = i18n.t(args[0], {
        returnObjects: true,
        postProcess: 'sprintf',
        sprintf: values,
      });
      if (Array.isArray(value)) {
        return value[Math.floor(Math.random() * value.length)];
      }
      return value;
    };
    const attributes = handlerInput.attributesManager.getRequestAttributes();
    attributes.t = function translate(...args) {
      return localizationClient.localize(...args);
    };
  },
};

const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    GetNewFactHandler,
    HelpHandler,
    ExitHandler,
    FallbackHandler,
    SessionEndedRequestHandler,
  )
  .addRequestInterceptors(LocalizationInterceptor)
  .addErrorHandlers(ErrorHandler)
  .lambda();

// translations
const deData = {
  translation: {
    SKILL_NAME: 'Weltraumwissen',
    GET_FACT_MESSAGE: 'Hier sind deine Fakten: ',
    HELP_MESSAGE: 'Du kannst sagen, „Nenne mir einen Fakt über den Weltraum“, oder du kannst „Beenden“ sagen... Wie kann ich dir helfen?',
    HELP_REPROMPT: 'Wie kann ich dir helfen?',
    FALLBACK_MESSAGE: 'Die Weltraumwissen Skill kann dir dabei nicht helfen. Sie kann dir Fakten über den Raum erzählen, wenn du dannach fragst.',
    FALLBACK_REPROMPT: 'Wie kann ich dir helfen?',
    ERROR_MESSAGE: 'Es ist ein Fehler aufgetreten.',
    STOP_MESSAGE: 'Auf Wiedersehen!',
    FACTS:
      [
        'Ein Jahr dauert auf dem Merkur nur 88 Tage.',
        'Die Venus ist zwar weiter von der Sonne entfernt, hat aber höhere Temperaturen als Merkur.',
        'Venus dreht sich entgegen dem Uhrzeigersinn, möglicherweise aufgrund eines früheren Zusammenstoßes mit einem Asteroiden.',
        'Auf dem Mars erscheint die Sonne nur halb so groß wie auf der Erde.',
        'Jupiter hat den kürzesten Tag aller Planeten.',
      ],
  },
};

const dedeData = {
  translation: {
    SKILL_NAME: 'Weltraumwissen auf Deutsch',
  },
};

const enData = {
  translation: {
    SKILL_NAME: 'Space Facts',
    GET_FACT_MESSAGE: 'Here\'s your fact: ',
    HELP_MESSAGE: 'You can say tell me a space fact, or, you can say exit... What can I help you with?',
    HELP_REPROMPT: 'What can I help you with?',
    FALLBACK_MESSAGE: 'The Space Facts skill can\'t help you with that.  It can help you discover facts about space if you say tell me a space fact. What can I help you with?',
    FALLBACK_REPROMPT: 'What can I help you with?',
    ERROR_MESSAGE: 'Sorry, an error occurred.',
    STOP_MESSAGE: 'Goodbye!',
    FACTS:
      [
        'A year on Mercury is just 88 days long.',
        'Despite being farther from the Sun, Venus experiences higher temperatures than Mercury.',
        'On Mars, the Sun appears about half the size as it does on Earth.',
        'Jupiter has the shortest day of all the planets.',
        'The Sun is an almost perfect sphere.',
      ],
  },
};

const enauData = {
  translation: {
    SKILL_NAME: 'Austrailian Space Facts',
  },
};

const encaData = {
  translation: {
    SKILL_NAME: 'Canadian Space Facts',
  },
};

const engbData = {
  translation: {
    SKILL_NAME: 'British Space Facts',
  },
};

const eninData = {
  translation: {
    SKILL_NAME: 'Indian Space Facts',
  },
};

const enusData = {
  translation: {
    SKILL_NAME: 'American Space Facts',
  },
};

const esData = {
  translation: {
    SKILL_NAME: 'Curiosidades del Espacio',
    GET_FACT_MESSAGE: 'Aquí está tu curiosidad: ',
    HELP_MESSAGE: 'Puedes decir dime una curiosidad del espacio o puedes decir salir... Cómo te puedo ayudar?',
    HELP_REPROMPT: 'Como te puedo ayudar?',
    FALLBACK_MESSAGE: 'La skill Curiosidades del Espacio no te puede ayudar con eso.  Te puede ayudar a descubrir curiosidades sobre el espacio si dices dime una curiosidad del espacio. Como te puedo ayudar?',
    FALLBACK_REPROMPT: 'Como te puedo ayudar?',
    ERROR_MESSAGE: 'Lo sentimos, se ha producido un error.',
    STOP_MESSAGE: 'Adiós!',
    FACTS:
        [
          'Un año en Mercurio es de solo 88 días',
          'A pesar de estar más lejos del Sol, Venus tiene temperaturas más altas que Mercurio',
          'En Marte el sol se ve la mitad de grande que en la Tierra',
          'Jupiter tiene el día más corto de todos los planetas',
          'El sol es una esféra casi perfecta',
        ],
  },
};

const esesData = {
  translation: {
    SKILL_NAME: 'Curiosidades del Espacio para España',
  },
};

const esmxData = {
  translation: {
    SKILL_NAME: 'Curiosidades del Espacio para México',
  },
};

const frData = {
  translation: {
    SKILL_NAME: 'Anecdotes de l\'Espace',
    GET_FACT_MESSAGE: 'Voici votre anecdote : ',
    HELP_MESSAGE: 'Vous pouvez dire donne-moi une anecdote, ou, vous pouvez dire stop... Comment puis-je vous aider?',
    HELP_REPROMPT: 'Comment puis-je vous aider?',
    FALLBACK_MESSAGE: 'La skill des anecdotes de l\'espace ne peux vous aider avec cela. Je peux vous aider à découvrir des anecdotes sur l\'espace si vous dites par exemple, donne-moi une anecdote. Comment puis-je vous aider?',
    FALLBACK_REPROMPT: 'Comment puis-je vous aider?',
    ERROR_MESSAGE: 'Désolé, une erreur est survenue.',
    STOP_MESSAGE: 'Au revoir!',
    FACTS:
        [
          'Une année sur Mercure ne dure que 88 jours.',
          'En dépit de son éloignement du Soleil, Vénus connaît des températures plus élevées que sur Mercure.',
          'Sur Mars, le Soleil apparaît environ deux fois plus petit que sur Terre.',
          'De toutes les planètes, Jupiter a le jour le plus court.',
          'Le Soleil est une sphère presque parfaite.',
        ],
  },
};

const frfrData = {
  translation: {
    SKILL_NAME: 'Anecdotes françaises de l\'espace',
  },
};

const itData = {
  translation: {
    SKILL_NAME: 'Aneddoti dallo spazio',
    GET_FACT_MESSAGE: 'Ecco il tuo aneddoto: ',
    HELP_MESSAGE: 'Puoi chiedermi un aneddoto dallo spazio o puoi chiudermi dicendo "esci"... Come posso aiutarti?',
    HELP_REPROMPT: 'Come posso aiutarti?',
    FALLBACK_MESSAGE: 'Non posso aiutarti con questo. Posso aiutarti a scoprire fatti e aneddoti sullo spazio, basta che mi chiedi di dirti un aneddoto. Come posso aiutarti?',
    FALLBACK_REPROMPT: 'Come posso aiutarti?',
    ERROR_MESSAGE: 'Spiacenti, si è verificato un errore.',
    STOP_MESSAGE: 'A presto!',
    FACTS:
      [
        'Sul pianeta Mercurio, un anno dura solamente 88 giorni.',
        'Pur essendo più lontana dal Sole, Venere ha temperature più alte di Mercurio.',
        'Su Marte il sole appare grande la metà che su la terra. ',
        'Tra tutti i pianeti del sistema solare, la giornata più corta è su Giove.',
        'Il Sole è quasi una sfera perfetta.',
      ],
  },
};

const ititData = {
  translation: {
    SKILL_NAME: 'Aneddoti dallo spazio',
  },
};

const jpData = {
  translation: {
    SKILL_NAME: '日本語版豆知識',
    GET_FACT_MESSAGE: '知ってましたか？',
    HELP_MESSAGE: '豆知識を聞きたい時は「豆知識」と、終わりたい時は「おしまい」と言ってください。どうしますか？',
    HELP_REPROMPT: 'どうしますか？',
    ERROR_MESSAGE: '申し訳ありませんが、エラーが発生しました',
    STOP_MESSAGE: 'さようなら',
    FACTS:
      [
        '水星の一年はたった88日です。',
        '金星は水星と比べて太陽より遠くにありますが、気温は水星よりも高いです。',
        '金星は反時計回りに自転しています。過去に起こった隕石の衝突が原因と言われています。',
        '火星上から見ると、太陽の大きさは地球から見た場合の約半分に見えます。',
        '木星の1日は全惑星の中で一番短いです。',
        '天の川銀河は約50億年後にアンドロメダ星雲と衝突します。',
      ],
  },
};

const jpjpData = {
  translation: {
    SKILL_NAME: '日本語版豆知識',
  },
};

// constructs i18n and l10n data structure
// translations for this sample can be found at the end of this file
const languageStrings = {
  'de': deData,
  'de-DE': dedeData,
  'en': enData,
  'en-AU': enauData,
  'en-CA': encaData,
  'en-GB': engbData,
  'en-IN': eninData,
  'en-US': enusData,
  'es': esData,
  'es-ES': esesData,
  'es-MX': esmxData,
  'fr': frData,
  'fr-FR': frfrData,
  'it': itData,
  'it-IT': ititData,
  'ja': jpData,
  'ja-JP': jpjpData,
};
<|endoftext|>


<commit_before>// @flow strict

import { expect } from 'chai';
import { describe, it } from 'mocha';

import invariant from '../../jsutils/invariant';

import { parse } from '../../language/parser';

import { GraphQLSchema } from '../../type/schema';
import { GraphQLString, GraphQLBoolean } from '../../type/scalars';
import {
  GraphQLList,
  GraphQLObjectType,
  GraphQLInterfaceType,
  GraphQLUnionType,
} from '../../type/definition';

import { execute } from '../execute';

class Dog {
  name: string;
  barks: boolean;
  mother: Dog | null;
  father: Dog | null;
  progeny: Array<Dog>;

  constructor(name: string, barks: boolean) {
    this.name = name;
    this.barks = barks;
    this.mother = null;
    this.father = null;
    this.progeny = [];
  }
}

class Cat {
  name: string;
  meows: boolean;
  mother: ?Cat;
  father: ?Cat;
  progeny: Array<Cat>;

  constructor(name, meows) {
    this.name = name;
    this.meows = meows;
    this.mother = null;
    this.father = null;
    this.progeny = [];
  }
}

class Person {
  name: string;
  pets: ?Array<Dog | Cat>;
  friends: ?Array<Dog | Cat | Person>;

  constructor(name, pets, friends) {
    this.name = name;
    this.pets = pets;
    this.friends = friends;
  }
}

const NamedType = new GraphQLInterfaceType({
  name: 'Named',
  fields: {
    name: { type: GraphQLString },
  },
});

const LifeType = new GraphQLInterfaceType({
  name: 'Life',
  fields: () => ({
    progeny: { type: GraphQLList(LifeType) },
  }),
});

const MammalType = new GraphQLInterfaceType({
  name: 'Mammal',
  interfaces: [LifeType],
  fields: () => ({
    progeny: { type: GraphQLList(MammalType) },
    mother: { type: MammalType },
    father: { type: MammalType },
  }),
});

const DogType = new GraphQLObjectType({
  name: 'Dog',
  interfaces: [MammalType, LifeType, NamedType],
  fields: () => ({
    name: { type: GraphQLString },
    barks: { type: GraphQLBoolean },
    progeny: { type: GraphQLList(DogType) },
    mother: { type: DogType },
    father: { type: DogType },
  }),
  isTypeOf: (value) => value instanceof Dog,
});

const CatType = new GraphQLObjectType({
  name: 'Cat',
  interfaces: [MammalType, LifeType, NamedType],
  fields: () => ({
    name: { type: GraphQLString },
    meows: { type: GraphQLBoolean },
    progeny: { type: GraphQLList(CatType) },
    mother: { type: CatType },
    father: { type: CatType },
  }),
  isTypeOf: (value) => value instanceof Cat,
});

const PetType = new GraphQLUnionType({
  name: 'Pet',
  types: [DogType, CatType],
  resolveType(value) {
    if (value instanceof Dog) {
      return DogType;
    }
    // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
    if (value instanceof Cat) {
      return CatType;
    }

    // istanbul ignore next (Not reachable. All possible types have been considered)
    invariant(false);
  },
});

const PersonType = new GraphQLObjectType({
  name: 'Person',
  interfaces: [NamedType, MammalType, LifeType],
  fields: () => ({
    name: { type: GraphQLString },
    pets: { type: GraphQLList(PetType) },
    friends: { type: GraphQLList(NamedType) },
    progeny: { type: GraphQLList(PersonType) },
    mother: { type: PersonType },
    father: { type: PersonType },
  }),
  isTypeOf: (value) => value instanceof Person,
});

const schema = new GraphQLSchema({
  query: PersonType,
  types: [PetType],
});

const garfield = new Cat('Garfield', false);
garfield.mother = new Cat("Garfield's Mom", false);
garfield.mother.progeny = [garfield];

const odie = new Dog('Odie', true);
odie.mother = new Dog("Odie's Mom", true);
odie.mother.progeny = [odie];

const liz = new Person('Liz');
const john = new Person('John', [garfield, odie], [liz, odie]);

describe('Execute: Union and intersection types', () => {
  it('can introspect on union and intersection types', () => {
    const document = parse(`
      {
        Named: __type(name: "Named") {
          kind
          name
          fields { name }
          interfaces { name }
          possibleTypes { name }
          enumValues { name }
          inputFields { name }
        }
        Mammal: __type(name: "Mammal") {
          kind
          name
          fields { name }
          interfaces { name }
          possibleTypes { name }
          enumValues { name }
          inputFields { name }
        }
        Pet: __type(name: "Pet") {
          kind
          name
          fields { name }
          interfaces { name }
          possibleTypes { name }
          enumValues { name }
          inputFields { name }
        }
      }
    `);

    expect(execute({ schema, document })).to.deep.equal({
      data: {
        Named: {
          kind: 'INTERFACE',
          name: 'Named',
          fields: [{ name: 'name' }],
          interfaces: [],
          possibleTypes: [{ name: 'Dog' }, { name: 'Cat' }, { name: 'Person' }],
          enumValues: null,
          inputFields: null,
        },
        Mammal: {
          kind: 'INTERFACE',
          name: 'Mammal',
          fields: [{ name: 'progeny' }, { name: 'mother' }, { name: 'father' }],
          interfaces: [{ name: 'Life' }],
          possibleTypes: [{ name: 'Dog' }, { name: 'Cat' }, { name: 'Person' }],
          enumValues: null,
          inputFields: null,
        },
        Pet: {
          kind: 'UNION',
          name: 'Pet',
          fields: null,
          interfaces: null,
          possibleTypes: [{ name: 'Dog' }, { name: 'Cat' }],
          enumValues: null,
          inputFields: null,
        },
      },
    });
  });

  it('executes using union types', () => {
    // NOTE: This is an *invalid* query, but it should be an *executable* query.
    const document = parse(`
      {
        __typename
        name
        pets {
          __typename
          name
          barks
          meows
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        pets: [
          {
            __typename: 'Cat',
            name: 'Garfield',
            meows: false,
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
          },
        ],
      },
    });
  });

  it('executes union types with inline fragments', () => {
    // This is the valid version of the query in the above test.
    const document = parse(`
      {
        __typename
        name
        pets {
          __typename
          ... on Dog {
            name
            barks
          }
          ... on Cat {
            name
            meows
          }
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        pets: [
          {
            __typename: 'Cat',
            name: 'Garfield',
            meows: false,
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
          },
        ],
      },
    });
  });

  it('executes using interface types', () => {
    // NOTE: This is an *invalid* query, but it should be an *executable* query.
    const document = parse(`
      {
        __typename
        name
        friends {
          __typename
          name
          barks
          meows
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        friends: [
          { __typename: 'Person', name: 'Liz' },
          { __typename: 'Dog', name: 'Odie', barks: true },
        ],
      },
    });
  });

  it('executes interface types with inline fragments', () => {
    // This is the valid version of the query in the above test.
    const document = parse(`
      {
        __typename
        name
        friends {
          __typename
          name
          ... on Dog {
            barks
          }
          ... on Cat {
            meows
          }

          ... on Mammal {
            mother {
              __typename
              ... on Dog {
                name
                barks
              }
              ... on Cat {
                name
                meows
              }
            }
          }
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        friends: [
          {
            __typename: 'Person',
            name: 'Liz',
            mother: null,
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
            mother: { __typename: 'Dog', name: "Odie's Mom", barks: true },
          },
        ],
      },
    });
  });

  it('executes interface types with named fragments', () => {
    const document = parse(`
      {
        __typename
        name
        friends {
          __typename
          name
          ...DogBarks
          ...CatMeows
        }
      }

      fragment  DogBarks on Dog {
        barks
      }

      fragment  CatMeows on Cat {
        meows
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        friends: [
          {
            __typename: 'Person',
            name: 'Liz',
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
          },
        ],
      },
    });
  });

  it('allows fragment conditions to be abstract types', () => {
    const document = parse(`
      {
        __typename
        name
        pets {
          ...PetFields,
          ...on Mammal {
            mother {
              ...ProgenyFields
            }
          }
        }
        friends { ...FriendFields }
      }

      fragment PetFields on Pet {
        __typename
        ... on Dog {
          name
          barks
        }
        ... on Cat {
          name
          meows
        }
      }

      fragment FriendFields on Named {
        __typename
        name
        ... on Dog {
          barks
        }
        ... on Cat {
          meows
        }
      }

      fragment ProgenyFields on Life {
        progeny {
          __typename
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        pets: [
          {
            __typename: 'Cat',
            name: 'Garfield',
            meows: false,
            mother: { progeny: [{ __typename: 'Cat' }] },
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
            mother: { progeny: [{ __typename: 'Dog' }] },
          },
        ],
        friends: [
          {
            __typename: 'Person',
            name: 'Liz',
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
          },
        ],
      },
    });
  });

  it('gets execution info in resolver', () => {
    let encounteredContext;
    let encounteredSchema;
    let encounteredRootValue;

    const NamedType2 = new GraphQLInterfaceType({
      name: 'Named',
      fields: {
        name: { type: GraphQLString },
      },
      resolveType(_source, context, info) {
        encounteredContext = context;
        encounteredSchema = info.schema;
        encounteredRootValue = info.rootValue;
        return PersonType2;
      },
    });

    const PersonType2 = new GraphQLObjectType({
      name: 'Person',
      interfaces: [NamedType2],
      fields: {
        name: { type: GraphQLString },
        friends: { type: GraphQLList(NamedType2) },
      },
    });
    const schema2 = new GraphQLSchema({ query: PersonType2 });
    const document = parse('{ name, friends { name } }');
    const rootValue = new Person('John', [], [liz]);
    const contextValue = { authToken: '123abc' };

    const result = execute({
      schema: schema2,
      document,
      rootValue,
      contextValue,
    });
    expect(result).to.deep.equal({
      data: {
        name: 'John',
        friends: [{ name: 'Liz' }],
      },
    });

    expect(encounteredSchema).to.equal(schema2);
    expect(encounteredRootValue).to.equal(rootValue);
    expect(encounteredContext).to.equal(contextValue);
  });
});
<commit_msg>union-interface-test: Improve typings (#2660)<commit_after>// @flow strict

import { expect } from 'chai';
import { describe, it } from 'mocha';

import invariant from '../../jsutils/invariant';

import { parse } from '../../language/parser';

import { GraphQLSchema } from '../../type/schema';
import { GraphQLString, GraphQLBoolean } from '../../type/scalars';
import {
  GraphQLList,
  GraphQLObjectType,
  GraphQLInterfaceType,
  GraphQLUnionType,
} from '../../type/definition';

import { execute } from '../execute';

class Dog {
  name: string;
  barks: boolean;
  mother: Dog | void;
  father: Dog | void;
  progeny: Array<Dog>;

  constructor(name: string, barks: boolean) {
    this.name = name;
    this.barks = barks;
    this.progeny = [];
  }
}

class Cat {
  name: string;
  meows: boolean;
  mother: Cat | void;
  father: Cat | void;
  progeny: Array<Cat>;

  constructor(name: string, meows: boolean) {
    this.name = name;
    this.meows = meows;
    this.progeny = [];
  }
}

class Person {
  name: string;
  pets: Array<Dog | Cat> | void;
  friends: Array<Dog | Cat | Person> | void;

  constructor(
    name: string,
    pets?: Array<Dog | Cat>,
    friends?: Array<Dog | Cat | Person> | void,
  ) {
    this.name = name;
    this.pets = pets;
    this.friends = friends;
  }
}

const NamedType = new GraphQLInterfaceType({
  name: 'Named',
  fields: {
    name: { type: GraphQLString },
  },
});

const LifeType = new GraphQLInterfaceType({
  name: 'Life',
  fields: () => ({
    progeny: { type: GraphQLList(LifeType) },
  }),
});

const MammalType = new GraphQLInterfaceType({
  name: 'Mammal',
  interfaces: [LifeType],
  fields: () => ({
    progeny: { type: GraphQLList(MammalType) },
    mother: { type: MammalType },
    father: { type: MammalType },
  }),
});

const DogType = new GraphQLObjectType({
  name: 'Dog',
  interfaces: [MammalType, LifeType, NamedType],
  fields: () => ({
    name: { type: GraphQLString },
    barks: { type: GraphQLBoolean },
    progeny: { type: GraphQLList(DogType) },
    mother: { type: DogType },
    father: { type: DogType },
  }),
  isTypeOf: (value) => value instanceof Dog,
});

const CatType = new GraphQLObjectType({
  name: 'Cat',
  interfaces: [MammalType, LifeType, NamedType],
  fields: () => ({
    name: { type: GraphQLString },
    meows: { type: GraphQLBoolean },
    progeny: { type: GraphQLList(CatType) },
    mother: { type: CatType },
    father: { type: CatType },
  }),
  isTypeOf: (value) => value instanceof Cat,
});

const PetType = new GraphQLUnionType({
  name: 'Pet',
  types: [DogType, CatType],
  resolveType(value) {
    if (value instanceof Dog) {
      return DogType;
    }
    // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
    if (value instanceof Cat) {
      return CatType;
    }

    // istanbul ignore next (Not reachable. All possible types have been considered)
    invariant(false);
  },
});

const PersonType = new GraphQLObjectType({
  name: 'Person',
  interfaces: [NamedType, MammalType, LifeType],
  fields: () => ({
    name: { type: GraphQLString },
    pets: { type: GraphQLList(PetType) },
    friends: { type: GraphQLList(NamedType) },
    progeny: { type: GraphQLList(PersonType) },
    mother: { type: PersonType },
    father: { type: PersonType },
  }),
  isTypeOf: (value) => value instanceof Person,
});

const schema = new GraphQLSchema({
  query: PersonType,
  types: [PetType],
});

const garfield = new Cat('Garfield', false);
garfield.mother = new Cat("Garfield's Mom", false);
garfield.mother.progeny = [garfield];

const odie = new Dog('Odie', true);
odie.mother = new Dog("Odie's Mom", true);
odie.mother.progeny = [odie];

const liz = new Person('Liz');
const john = new Person('John', [garfield, odie], [liz, odie]);

describe('Execute: Union and intersection types', () => {
  it('can introspect on union and intersection types', () => {
    const document = parse(`
      {
        Named: __type(name: "Named") {
          kind
          name
          fields { name }
          interfaces { name }
          possibleTypes { name }
          enumValues { name }
          inputFields { name }
        }
        Mammal: __type(name: "Mammal") {
          kind
          name
          fields { name }
          interfaces { name }
          possibleTypes { name }
          enumValues { name }
          inputFields { name }
        }
        Pet: __type(name: "Pet") {
          kind
          name
          fields { name }
          interfaces { name }
          possibleTypes { name }
          enumValues { name }
          inputFields { name }
        }
      }
    `);

    expect(execute({ schema, document })).to.deep.equal({
      data: {
        Named: {
          kind: 'INTERFACE',
          name: 'Named',
          fields: [{ name: 'name' }],
          interfaces: [],
          possibleTypes: [{ name: 'Dog' }, { name: 'Cat' }, { name: 'Person' }],
          enumValues: null,
          inputFields: null,
        },
        Mammal: {
          kind: 'INTERFACE',
          name: 'Mammal',
          fields: [{ name: 'progeny' }, { name: 'mother' }, { name: 'father' }],
          interfaces: [{ name: 'Life' }],
          possibleTypes: [{ name: 'Dog' }, { name: 'Cat' }, { name: 'Person' }],
          enumValues: null,
          inputFields: null,
        },
        Pet: {
          kind: 'UNION',
          name: 'Pet',
          fields: null,
          interfaces: null,
          possibleTypes: [{ name: 'Dog' }, { name: 'Cat' }],
          enumValues: null,
          inputFields: null,
        },
      },
    });
  });

  it('executes using union types', () => {
    // NOTE: This is an *invalid* query, but it should be an *executable* query.
    const document = parse(`
      {
        __typename
        name
        pets {
          __typename
          name
          barks
          meows
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        pets: [
          {
            __typename: 'Cat',
            name: 'Garfield',
            meows: false,
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
          },
        ],
      },
    });
  });

  it('executes union types with inline fragments', () => {
    // This is the valid version of the query in the above test.
    const document = parse(`
      {
        __typename
        name
        pets {
          __typename
          ... on Dog {
            name
            barks
          }
          ... on Cat {
            name
            meows
          }
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        pets: [
          {
            __typename: 'Cat',
            name: 'Garfield',
            meows: false,
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
          },
        ],
      },
    });
  });

  it('executes using interface types', () => {
    // NOTE: This is an *invalid* query, but it should be an *executable* query.
    const document = parse(`
      {
        __typename
        name
        friends {
          __typename
          name
          barks
          meows
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        friends: [
          { __typename: 'Person', name: 'Liz' },
          { __typename: 'Dog', name: 'Odie', barks: true },
        ],
      },
    });
  });

  it('executes interface types with inline fragments', () => {
    // This is the valid version of the query in the above test.
    const document = parse(`
      {
        __typename
        name
        friends {
          __typename
          name
          ... on Dog {
            barks
          }
          ... on Cat {
            meows
          }

          ... on Mammal {
            mother {
              __typename
              ... on Dog {
                name
                barks
              }
              ... on Cat {
                name
                meows
              }
            }
          }
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        friends: [
          {
            __typename: 'Person',
            name: 'Liz',
            mother: null,
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
            mother: { __typename: 'Dog', name: "Odie's Mom", barks: true },
          },
        ],
      },
    });
  });

  it('executes interface types with named fragments', () => {
    const document = parse(`
      {
        __typename
        name
        friends {
          __typename
          name
          ...DogBarks
          ...CatMeows
        }
      }

      fragment  DogBarks on Dog {
        barks
      }

      fragment  CatMeows on Cat {
        meows
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        friends: [
          {
            __typename: 'Person',
            name: 'Liz',
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
          },
        ],
      },
    });
  });

  it('allows fragment conditions to be abstract types', () => {
    const document = parse(`
      {
        __typename
        name
        pets {
          ...PetFields,
          ...on Mammal {
            mother {
              ...ProgenyFields
            }
          }
        }
        friends { ...FriendFields }
      }

      fragment PetFields on Pet {
        __typename
        ... on Dog {
          name
          barks
        }
        ... on Cat {
          name
          meows
        }
      }

      fragment FriendFields on Named {
        __typename
        name
        ... on Dog {
          barks
        }
        ... on Cat {
          meows
        }
      }

      fragment ProgenyFields on Life {
        progeny {
          __typename
        }
      }
    `);

    expect(execute({ schema, document, rootValue: john })).to.deep.equal({
      data: {
        __typename: 'Person',
        name: 'John',
        pets: [
          {
            __typename: 'Cat',
            name: 'Garfield',
            meows: false,
            mother: { progeny: [{ __typename: 'Cat' }] },
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
            mother: { progeny: [{ __typename: 'Dog' }] },
          },
        ],
        friends: [
          {
            __typename: 'Person',
            name: 'Liz',
          },
          {
            __typename: 'Dog',
            name: 'Odie',
            barks: true,
          },
        ],
      },
    });
  });

  it('gets execution info in resolver', () => {
    let encounteredContext;
    let encounteredSchema;
    let encounteredRootValue;

    const NamedType2 = new GraphQLInterfaceType({
      name: 'Named',
      fields: {
        name: { type: GraphQLString },
      },
      resolveType(_source, context, info) {
        encounteredContext = context;
        encounteredSchema = info.schema;
        encounteredRootValue = info.rootValue;
        return PersonType2;
      },
    });

    const PersonType2 = new GraphQLObjectType({
      name: 'Person',
      interfaces: [NamedType2],
      fields: {
        name: { type: GraphQLString },
        friends: { type: GraphQLList(NamedType2) },
      },
    });
    const schema2 = new GraphQLSchema({ query: PersonType2 });
    const document = parse('{ name, friends { name } }');
    const rootValue = new Person('John', [], [liz]);
    const contextValue = { authToken: '123abc' };

    const result = execute({
      schema: schema2,
      document,
      rootValue,
      contextValue,
    });
    expect(result).to.deep.equal({
      data: {
        name: 'John',
        friends: [{ name: 'Liz' }],
      },
    });

    expect(encounteredSchema).to.equal(schema2);
    expect(encounteredRootValue).to.equal(rootValue);
    expect(encounteredContext).to.equal(contextValue);
  });
});
<|endoftext|>


<commit_before>import {  utils, mapEvents, MapDataManipulator, eventListeners, mapStates, log } from '../../../core/';
import { findPath } from '../pathFinding/findPath';
import * as hexaUtils from '../utils/';
const hexagons = {
  findPath,
  utils: hexaUtils
};

/*---------------------
------ VARIABLES ------
----------------------*/
const unitLayerFilter = new MapDataManipulator({
  type: 'filter',
  object: 'layer',
  property: 'selectable',
  value: true
});
const terrainLayerFilter = new MapDataManipulator({
  type: 'filter',
  object: 'layer',
  property: 'name',
  value: 'terrainLayer'
});
/* @todo This must be changed to outside the module */
let weight = () => 0;
let FTW;

/*---------------------
------- PUBLIC --------
----------------------*/
/**
 * Handles the eventlistner for selecting objects on the map. THe actual logic for detecting the objects under mouse
 * etc. are in selectHexagonPlugin
 *
 * @class extensions.hexagons.setupHexagonClick
 * @requires Hammer.js. Some events are done with Hammer.js, so we need it to handle those events correctly
 * @event                 Mapselect and objectsSelected (objectsSelected will have parameter for the objects that were selected)
 * @param  {Map} map      The currently use Map instance
 * @return {Boolean}      True
 */
function setupHexagonClick(mapInstance, weightFn, getData) {
  if (!mapInstance) {
    throw new Error('eventlisteners initialization requires flatworld instance as a parameter');
  }

  FTW = mapInstance;

  eventListeners.on('select', _tapListener);
  eventListeners.on('order', _orderListener);

  mapInstance.setPrototype('getData', getData);

  weight = weightFn || weight;

  return true;
}

/**
 * the listener that received the event object
 *
 * @private
 * @method _tapListener
 * @param  {Event} e      Event object
 */
function _tapListener(e) {
  const globalCoords = utils.mouse.eventData.getHAMMERPointerCoords(e);
  mapStates.objectSelect();

  let objects = FTW.getObjectsUnderArea(globalCoords, { filters: unitLayerFilter });
  objects = utils.dataManipulation.mapObjectsToArray(objects);
  objects = utils.dataManipulation.flattenArrayBy1Level(objects);

  FTW.currentlySelectedObjects = objects;

  FTW.drawOnNextTick();

  return true;
}
/**
 * This listener is for the situation, where we have an object and we issue an order / action to
 * that unit. For example to move from one hexagon to another.
 *
 * @private
 * @method _orderListener
 * @param  {Event} e      Event object
 */
function _orderListener(e) {
  // We want to wrap the whole functionality in try catch, to cancel the order state, if any
  // errors occur. Otherwise the states can get stuck more easily in a situation, where you can
  // not move anything (if objectOrder stays on, then the map won't allow you to move units)
  try {
    mapStates.objectOrder();

    if (!FTW.currentlySelectedObjects) {
      throw 'No objects selected for orders!';
    } else if (FTW.currentlySelectedObjects.length > 1) {
      throw 'the selected object is only supported to be one atm.' + JSON.stringify(FTW.currentlySelectedObjects[0]);
    }

    const selectedObject = FTW.currentlySelectedObjects[0];
    const selectedObjectsCoordinates = selectedObject.getMapCoordinates();
    const globalCoords = utils.mouse.eventData.getGlobalCoordinates(e);

    const objects = FTW.getObjectsUnderArea(globalCoords, { filters: terrainLayerFilter });

    if (!objects.length) {
      throw 'No terrain objects found for destination!';
    }

    const objectIndexes = hexagons.utils.hexagonMath.coordinatesToIndexes(selectedObjectsCoordinates);
    const centerCoords = {
      x: objects[0].getMapCoordinates().x,
      y: objects[0].getMapCoordinates().y
    } ;
    const destinationIndexes = hexagons.utils.hexagonMath.coordinatesToIndexes(centerCoords);

    let pathsToCoordinates;

    if (objectIndexes.x === destinationIndexes.x && objectIndexes.y === destinationIndexes.y) {
      pathsToCoordinates = [];
    } else {
      try {
        const timeUnits = selectedObject.getMovement();
        if (!Number.isInteger(timeUnits)) {
          throw new Error(`getMovement method, did not return an integer! Returned '${timeUnits.toString()} from object
            '${selectedObject.toString()}`)
        }
        pathsToCoordinates = hexagons.findPath(
          objectIndexes,
          destinationIndexes,
          +FTW.getMapsize().x,
          +FTW.getMapsize().y,
          +timeUnits,
          _isBlocked
        );
        pathsToCoordinates = pathsToCoordinates.map(coords => {
          return hexagons.utils.hexagonMath.indexesToCoordinates(coords);
        });
      } catch (e) {
        if (!pathsToCoordinates || pathsToCoordinates.length < 1) {
          e.message = 'the destination was farther than the given maximum distance';
        } else {
          e.message += `, EXTRA INFO: ' + 'start and end point are same, destination is blocked, unit could not reach the destination or
                        something else happened`;
        }

        throw e;
      }
    }

    selectedObject.move(pathsToCoordinates);

    mapEvents.publish('unitMoved', pathsToCoordinates);

    mapStates.objectOrderEnd();
    FTW.drawOnNextTick();
  } catch(e) {
    mapStates.objectOrderEnd();
    log.debug(e);
    return;
  }
}

function _isBlocked(nextCoordinates, queue) {
  /* We use the EARLIER path to test, how much moving to the next area will require. We can
   * not use the next area to test it, as that could lead to nasty surpises (like units
   * couldn't move to an area at all, because they have 1 move and it requires 2 moves)
   */
  const correctHexagon = FTW.hexagonIndexes[nextCoordinates.x] && FTW.hexagonIndexes[nextCoordinates.x][nextCoordinates.y];
  const returnedWeight = weight(correctHexagon, FTW.currentlySelectedObjects[0], { nextCoordinates, queue });

  if (!correctHexagon) {
    return -1;
  } else if ((returnedWeight || returnedWeight === 0) && isInteger(returnedWeight)) {
    return returnedWeight;
  } else if (returnedWeight && !isInteger(returnedWeight)) {
    throw new Error('weight callback has to return an integer');
  }

  return -1;
}

function isInteger(x) {
  return x === Math.floor(x) && isFinite(x);
}

/*---------------------
--------- API ---------
----------------------*/
const _tests = {
  _isBlocked,
  _orderListener,
  _tapListener
};
export {
  setupHexagonClick,
  _tests
};
<commit_msg>Feature: Added unitOrderFailed event, for detecting issues in giving orders<commit_after>import {  utils, mapEvents, MapDataManipulator, eventListeners, mapStates, log } from '../../../core/';
import { findPath } from '../pathFinding/findPath';
import * as hexaUtils from '../utils/';
const hexagons = {
  findPath,
  utils: hexaUtils
};

/*---------------------
------ VARIABLES ------
----------------------*/
const unitLayerFilter = new MapDataManipulator({
  type: 'filter',
  object: 'layer',
  property: 'selectable',
  value: true
});
const terrainLayerFilter = new MapDataManipulator({
  type: 'filter',
  object: 'layer',
  property: 'name',
  value: 'terrainLayer'
});
/* @todo This must be changed to outside the module */
let weight = () => 0;
let FTW;

/*---------------------
------- PUBLIC --------
----------------------*/
/**
 * Handles the eventlistner for selecting objects on the map. THe actual logic for detecting the objects under mouse
 * etc. are in selectHexagonPlugin
 *
 * @class extensions.hexagons.setupHexagonClick
 * @requires Hammer.js. Some events are done with Hammer.js, so we need it to handle those events correctly
 * @event                 Mapselect and objectsSelected (objectsSelected will have parameter for the objects that were selected)
 * @param  {Map} map      The currently use Map instance
 * @return {Boolean}      True
 */
function setupHexagonClick(mapInstance, weightFn, getData) {
  if (!mapInstance) {
    throw new Error('eventlisteners initialization requires flatworld instance as a parameter');
  }

  FTW = mapInstance;

  eventListeners.on('select', _tapListener);
  eventListeners.on('order', _orderListener);

  mapInstance.setPrototype('getData', getData);

  weight = weightFn || weight;

  return true;
}

/**
 * the listener that received the event object
 *
 * @private
 * @method _tapListener
 * @param  {Event} e      Event object
 */
function _tapListener(e) {
  const globalCoords = utils.mouse.eventData.getHAMMERPointerCoords(e);
  mapStates.objectSelect();

  let objects = FTW.getObjectsUnderArea(globalCoords, { filters: unitLayerFilter });
  objects = utils.dataManipulation.mapObjectsToArray(objects);
  objects = utils.dataManipulation.flattenArrayBy1Level(objects);

  FTW.currentlySelectedObjects = objects;

  FTW.drawOnNextTick();

  return true;
}
/**
 * This listener is for the situation, where we have an object and we issue an order / action to
 * that unit. For example to move from one hexagon to another.
 *
 * @private
 * @method _orderListener
 * @param  {Event} e      Event object
 * @throws Normal javascript error with special .customCode - property:
 * 100: No objects selected for orders
 * 110: The selected object is only supported to be one atm.
 * 120: No terrain objects found for destination
 * 130: GetMovement-method did not return an integer
 * 140: The destination was farther than the given maximum distance
 * 150: Some other unknown error occured
 */
function _orderListener(e) {
  // We want to wrap the whole functionality in try catch, to cancel the order state, if any
  // errors occur. Otherwise the states can get stuck more easily in a situation, where you can
  // not move anything (if objectOrder stays on, then the map won't allow you to move units)
  try {
    mapStates.objectOrder();

    if (!FTW.currentlySelectedObjects) {
      const error =  new Error('No objects selected for orders');
      error.customCode = 100;
      throw error;
    } else if (FTW.currentlySelectedObjects.length > 1) {
      const error = new Error('The selected object is only supported to be one atm.' + JSON.stringify(FTW.currentlySelectedObjects[0]));
      error.customCode = 110;
      throw error;
    }

    const selectedObject = FTW.currentlySelectedObjects[0];
    const selectedObjectsCoordinates = selectedObject.getMapCoordinates();
    const globalCoords = utils.mouse.eventData.getGlobalCoordinates(e);

    const objects = FTW.getObjectsUnderArea(globalCoords, { filters: terrainLayerFilter });

    if (!objects.length) {
      const error = new Error('No terrain objects found for destination');
      error.customCode = 120;
      throw error;
    }

    const objectIndexes = hexagons.utils.hexagonMath.coordinatesToIndexes(selectedObjectsCoordinates);
    const centerCoords = {
      x: objects[0].getMapCoordinates().x,
      y: objects[0].getMapCoordinates().y
    } ;
    const destinationIndexes = hexagons.utils.hexagonMath.coordinatesToIndexes(centerCoords);

    let pathsToCoordinates;

    if (objectIndexes.x === destinationIndexes.x && objectIndexes.y === destinationIndexes.y) {
      pathsToCoordinates = [];
    } else {
      try {
        const timeUnits = selectedObject.getMovement();
        if (!Number.isInteger(timeUnits)) {
          const error = new Error(`GetMovement-method did not return an integer. Returned '${timeUnits.toString()} from object
            '${selectedObject.toString()}`)
          error.customCode = 130;
          throw error;
        }
        pathsToCoordinates = hexagons.findPath(
          objectIndexes,
          destinationIndexes,
          +FTW.getMapsize().x,
          +FTW.getMapsize().y,
          +timeUnits,
          _isBlocked
        );
        pathsToCoordinates = pathsToCoordinates.map(coords => {
          return hexagons.utils.hexagonMath.indexesToCoordinates(coords);
        });
      } catch (e) {
        if (!pathsToCoordinates || pathsToCoordinates.length < 1) {
          e.message = 'The destination was farther than the given maximum distance';
          e.customCode = 140;
        } else {
          e.message += `, EXTRA INFO: ' + 'start and end point are same, destination is blocked, unit could not reach
            the destination or something else happened`;
          e.customCode = 150;
        }

        throw e;
      }
    }

    selectedObject.move(pathsToCoordinates);

    mapEvents.publish('unitMoved', pathsToCoordinates);

    mapStates.objectOrderEnd();
    FTW.drawOnNextTick();
  } catch(e) {
    mapStates.objectOrderEnd();
    mapEvents.publish('unitOrderFailed', e);
    log.debug(e);
    return;
  }
}

function _isBlocked(nextCoordinates, queue) {
  /* We use the EARLIER path to test, how much moving to the next area will require. We can
   * not use the next area to test it, as that could lead to nasty surpises (like units
   * couldn't move to an area at all, because they have 1 move and it requires 2 moves)
   */
  const correctHexagon = FTW.hexagonIndexes[nextCoordinates.x] && FTW.hexagonIndexes[nextCoordinates.x][nextCoordinates.y];
  const returnedWeight = weight(correctHexagon, FTW.currentlySelectedObjects[0], { nextCoordinates, queue });

  if (!correctHexagon) {
    return -1;
  } else if ((returnedWeight || returnedWeight === 0) && isInteger(returnedWeight)) {
    return returnedWeight;
  } else if (returnedWeight && !isInteger(returnedWeight)) {
    throw new Error('weight callback has to return an integer');
  }

  return -1;
}

function isInteger(x) {
  return x === Math.floor(x) && isFinite(x);
}

/*---------------------
--------- API ---------
----------------------*/
const _tests = {
  _isBlocked,
  _orderListener,
  _tapListener
};
export {
  setupHexagonClick,
  _tests
};
<|endoftext|>


<commit_before>const path = require('path');
const pkgUp = require('pkg-up');
let shelljs = require('shelljs');
let proxy = require('./proxy');
const Ipc = require('../../core/ipc');
const constants = require('../../constants.json');
const {defaultHost, dockerHostSwap} = require('../../utils/host');
const fs = require('../../core/fs.js');

class Simulator {
  constructor(options) {
    this.blockchainConfig = options.blockchainConfig;
    this.contractsConfig = options.contractsConfig;
    this.logger = options.logger;
  }

  /*eslint complexity: ["error", 22]*/
  run(options) {
    let cmds = [];

    const ganache_main = require.resolve('ganache-cli', {paths: fs.embarkPath('node_modules')});
    const ganache_json = pkgUp.sync(path.dirname(ganache_main));
    const ganache_root = path.dirname(ganache_json);
    const ganache_bin = require(ganache_json).bin;
    let ganache;
    if (typeof ganache_bin === 'string') {
      ganache = path.join(ganache_root, ganache_bin);
    } else {
      ganache = path.join(ganache_root, ganache_bin['ganache-cli']);
    }

    let useProxy = this.blockchainConfig.proxy || false;
    let host = (dockerHostSwap(options.host || this.blockchainConfig.rpcHost) || defaultHost);
    const configPort = this.contractsConfig.deployment.type === 'rpc' ? this.blockchainConfig.rpcPort : this.blockchainConfig.wsPort;
    let port = (options.port || configPort || 8545);
    port = parseInt(port, 10) + (useProxy ? constants.blockchain.servicePortOnProxy : 0);

    cmds.push("-p " + port);
    cmds.push("-h " + host);
    cmds.push("-a " + (options.numAccounts || 10));
    cmds.push("-e " + (options.defaultBalance || 100));
    cmds.push("-l " + (options.gasLimit || 8000000));

    // adding mnemonic only if it is defined in the blockchainConfig or options
    let simulatorMnemonic = this.blockchainConfig.simulatorMnemonic || options.simulatorMnemonic;
    if (simulatorMnemonic) {
      cmds.push("--mnemonic \"" + (simulatorMnemonic) +"\"");
    }

    // as ganache-cli documentation explains, the simulatorAccounts configuration overrides a mnemonic
    let simulatorAccounts = this.blockchainConfig.simulatorAccounts || options.simulatorAccounts;
    if (simulatorAccounts && simulatorAccounts.length > 0) {
      let web3 = new (require('web3'))();
      let AccountParser = require('../../utils/accountParser.js');
      let parsedAccounts = AccountParser.parseAccountsConfig(simulatorAccounts, web3, this.logger);
      parsedAccounts.forEach((account) => {
        let cmd = '--account="' + account.privateKey + ','+account.hexBalance + '"';
        cmds.push(cmd);
      });
    }

    // adding blocktime only if it is defined in the blockchainConfig or options
    let simulatorBlocktime = this.blockchainConfig.simulatorBlocktime || options.simulatorBlocktime;
    if (simulatorBlocktime) {
      cmds.push("-b \"" + (simulatorBlocktime) +"\"");
    }

    // Setting up network id for simulator from blockchainConfig or options.
    // Otherwise ganache-cli would make random network id.
    let networkId = this.blockchainConfig.networkId || options.networkId;
    if (networkId) { // Don't handle networkId=="0" because it is not a valid networkId for ganache-cli.
      cmds.push("--networkId " + networkId);
    }

    const programName = 'ganache-cli';
    const program = ganache;
    console.log(`running: ${programName} ${cmds.join(' ')}`);
    shelljs.exec(`${program} ${cmds.join(' ')}`, {async : true});

    if(useProxy){
      let ipcObject = new Ipc({ipcRole: 'client'});
      proxy.serve(ipcObject, host, port, false);
    }
  }
}

module.exports = Simulator;
<commit_msg>fix(simulator): use config's gas limit if no option provided<commit_after>const path = require('path');
const pkgUp = require('pkg-up');
let shelljs = require('shelljs');
let proxy = require('./proxy');
const Ipc = require('../../core/ipc');
const constants = require('../../constants.json');
const {defaultHost, dockerHostSwap} = require('../../utils/host');
const fs = require('../../core/fs.js');

class Simulator {
  constructor(options) {
    this.blockchainConfig = options.blockchainConfig;
    this.contractsConfig = options.contractsConfig;
    this.logger = options.logger;
  }

  /*eslint complexity: ["error", 23]*/
  run(options) {
    let cmds = [];

    const ganache_main = require.resolve('ganache-cli', {paths: fs.embarkPath('node_modules')});
    const ganache_json = pkgUp.sync(path.dirname(ganache_main));
    const ganache_root = path.dirname(ganache_json);
    const ganache_bin = require(ganache_json).bin;
    let ganache;
    if (typeof ganache_bin === 'string') {
      ganache = path.join(ganache_root, ganache_bin);
    } else {
      ganache = path.join(ganache_root, ganache_bin['ganache-cli']);
    }

    let useProxy = this.blockchainConfig.proxy || false;
    let host = (dockerHostSwap(options.host || this.blockchainConfig.rpcHost) || defaultHost);
    const configPort = this.contractsConfig.deployment.type === 'rpc' ? this.blockchainConfig.rpcPort : this.blockchainConfig.wsPort;
    let port = (options.port || configPort || 8545);
    port = parseInt(port, 10) + (useProxy ? constants.blockchain.servicePortOnProxy : 0);

    cmds.push("-p " + port);
    cmds.push("-h " + host);
    cmds.push("-a " + (options.numAccounts || 10));
    cmds.push("-e " + (options.defaultBalance || 100));
    cmds.push("-l " + (options.gasLimit || this.blockchainConfig.targetGasLimit || 8000000));

    // adding mnemonic only if it is defined in the blockchainConfig or options
    let simulatorMnemonic = this.blockchainConfig.simulatorMnemonic || options.simulatorMnemonic;
    if (simulatorMnemonic) {
      cmds.push("--mnemonic \"" + (simulatorMnemonic) +"\"");
    }

    // as ganache-cli documentation explains, the simulatorAccounts configuration overrides a mnemonic
    let simulatorAccounts = this.blockchainConfig.simulatorAccounts || options.simulatorAccounts;
    if (simulatorAccounts && simulatorAccounts.length > 0) {
      let web3 = new (require('web3'))();
      let AccountParser = require('../../utils/accountParser.js');
      let parsedAccounts = AccountParser.parseAccountsConfig(simulatorAccounts, web3, this.logger);
      parsedAccounts.forEach((account) => {
        let cmd = '--account="' + account.privateKey + ','+account.hexBalance + '"';
        cmds.push(cmd);
      });
    }

    // adding blocktime only if it is defined in the blockchainConfig or options
    let simulatorBlocktime = this.blockchainConfig.simulatorBlocktime || options.simulatorBlocktime;
    if (simulatorBlocktime) {
      cmds.push("-b \"" + (simulatorBlocktime) +"\"");
    }

    // Setting up network id for simulator from blockchainConfig or options.
    // Otherwise ganache-cli would make random network id.
    let networkId = this.blockchainConfig.networkId || options.networkId;
    if (networkId) { // Don't handle networkId=="0" because it is not a valid networkId for ganache-cli.
      cmds.push("--networkId " + networkId);
    }

    const programName = 'ganache-cli';
    const program = ganache;
    console.log(`running: ${programName} ${cmds.join(' ')}`);
    shelljs.exec(`${program} ${cmds.join(' ')}`, {async : true});

    if(useProxy){
      let ipcObject = new Ipc({ipcRole: 'client'});
      proxy.serve(ipcObject, host, port, false);
    }
  }
}

module.exports = Simulator;
<|endoftext|>


<commit_before>define(
  'ephox.alloy.api.ui.SplitDropdown',

  [
    'ephox.alloy.api.SystemEvents',
    'ephox.alloy.api.behaviour.Toggling',
    'ephox.alloy.api.ui.Button',
    'ephox.alloy.api.ui.CompositeBuilder',
    'ephox.alloy.dropdown.Beta',
    'ephox.alloy.parts.InternalSink',
    'ephox.alloy.parts.PartType',
    'ephox.alloy.ui.common.ButtonBase',
    'ephox.boulder.api.FieldSchema',
    'ephox.peanut.Fun',
    'ephox.perhaps.Option',
    'global!Error'
  ],

  function (SystemEvents, Toggling, Button, CompositeBuilder, Beta, InternalSink, PartType, ButtonBase, FieldSchema, Fun, Option, Error) {
    var schema = [
      FieldSchema.strict('toggleClass'),
      FieldSchema.strict('fetch'),
      FieldSchema.strict('onExecute'),
      FieldSchema.option('lazySink'),
      FieldSchema.strict('dom'),
      FieldSchema.defaulted('onOpen', Fun.noop),
      // FieldSchema.defaulted('onClose', Fun.noop),

      FieldSchema.defaulted('matchWidth', false)
    ];

    var arrowPart = PartType.internal(
      Button,
      'arrow',
      '<alloy.split-dropdown.arrow>',
      function (detail) {
        return {
          behaviours: {
            // FIX undefined
            tabstopping: undefined,
            focusing: undefined
          }
        };
      },
      function (detail) {
        return {
          action: function (arrow) {
            var hotspot = arrow.getSystem().getByUid(detail.uid()).getOrDie();
            hotspot.getSystem().triggerEvent(SystemEvents.execute(), hotspot.element(), { });
          },
          behaviours: {
            toggling: {
              toggleOnExecute: false
            }
          }
        };
      }
    );

    var buttonPart = PartType.internal(
      Button,
      'button',
      '<alloy.split-dropdown.button>',
      function (detail) {
        return {
          behaviours: {
          // FIX: Undefined false
            focusing: undefined
          }
        };
      },
      function (detail) {
        return {
          // uiType: 'button',
          action: detail.onExecute()
        };
      }
    );

    var partTypes = [
      arrowPart,
      buttonPart,
      PartType.external(
        { build: Fun.identity },
        'menu',
        function (detail) {
          return {
            onExecute: detail.onExecute()
          };
        },
        Fun.constant({ })
      ),
      InternalSink
    ];

    var make = function (detail, components, spec, externals) {
      var buttonEvents = ButtonBase.events(Option.some(
        function (component) {
          Beta.togglePopup(detail, {
            anchor: 'hotspot',
            hotspot: component
          }, component, externals).get(function (sandbox) {

          });
        }
      ));
      return {
        uid: detail.uid(),
        uiType: 'custom',
        dom: detail.dom(),
        components: components,
        eventOrder: {
          // Order, the button state is toggled first, so assumed !selected means close.
          'alloy.execute': [ 'toggling', 'alloy.base.behaviour' ]
        },

        events: buttonEvents,

        behaviours: {
          coupling: {
            others: {
              sandbox: function (hotspot) {
                var arrow = hotspot.getSystem().getByUid(detail.partUids().arrow).getOrDie();
                var extras = {
                  onOpen: function () {
                    Toggling.select(arrow);
                  },
                  onClose: function () {
                    Toggling.deselect(arrow);
                  }
                };

                return Beta.makeSandbox(detail, {
                  anchor: 'hotspot',
                  hotspot: hotspot
                }, hotspot, extras);
              }
            }
          },
          keying: {
            mode: 'execution',
            useSpace: true
          },
          focusing: true
        }
      };
    };

    var build = function (f) {
      return CompositeBuilder.build('split-dropdown', schema, partTypes, make, f);
    };

    // TODO: Remove likely dupe
    var parts = PartType.generate('split-dropdown', partTypes);

    return {
      build: build,
      parts: Fun.constant(parts)
    };
  }
);<commit_msg>VAN-44-wheel-hackery-apis-2: removing composite builder from Split dropdown<commit_after>define(
  'ephox.alloy.api.ui.SplitDropdown',

  [
    'ephox.alloy.api.SystemEvents',
    'ephox.alloy.api.behaviour.Toggling',
    'ephox.alloy.api.ui.Button',
    'ephox.alloy.api.ui.UiBuilder',
    'ephox.alloy.dropdown.Beta',
    'ephox.alloy.parts.InternalSink',
    'ephox.alloy.parts.PartType',
    'ephox.alloy.ui.common.ButtonBase',
    'ephox.boulder.api.FieldSchema',
    'ephox.peanut.Fun',
    'ephox.perhaps.Option',
    'global!Error'
  ],

  function (SystemEvents, Toggling, Button, UiBuilder, Beta, InternalSink, PartType, ButtonBase, FieldSchema, Fun, Option, Error) {
    var schema = [
      FieldSchema.strict('toggleClass'),
      FieldSchema.strict('fetch'),
      FieldSchema.strict('onExecute'),
      FieldSchema.option('lazySink'),
      FieldSchema.strict('dom'),
      FieldSchema.defaulted('onOpen', Fun.noop),
      // FieldSchema.defaulted('onClose', Fun.noop),

      FieldSchema.defaulted('matchWidth', false)
    ];

    var arrowPart = PartType.internal(
      Button,
      'arrow',
      '<alloy.split-dropdown.arrow>',
      function (detail) {
        return {
          behaviours: {
            // FIX undefined
            tabstopping: undefined,
            focusing: undefined
          }
        };
      },
      function (detail) {
        return {
          action: function (arrow) {
            var hotspot = arrow.getSystem().getByUid(detail.uid()).getOrDie();
            hotspot.getSystem().triggerEvent(SystemEvents.execute(), hotspot.element(), { });
          },
          behaviours: {
            toggling: {
              toggleOnExecute: false
            }
          }
        };
      }
    );

    var buttonPart = PartType.internal(
      Button,
      'button',
      '<alloy.split-dropdown.button>',
      function (detail) {
        return {
          behaviours: {
          // FIX: Undefined false
            focusing: undefined
          }
        };
      },
      function (detail) {
        return {
          // uiType: 'button',
          action: detail.onExecute()
        };
      }
    );

    var partTypes = [
      arrowPart,
      buttonPart,
      PartType.external(
        { build: Fun.identity },
        'menu',
        function (detail) {
          return {
            onExecute: detail.onExecute()
          };
        },
        Fun.constant({ })
      ),
      InternalSink
    ];

    var make = function (detail, components, spec, externals) {
      var buttonEvents = ButtonBase.events(Option.some(
        function (component) {
          Beta.togglePopup(detail, {
            anchor: 'hotspot',
            hotspot: component
          }, component, externals).get(function (sandbox) {

          });
        }
      ));
      return {
        uid: detail.uid(),
        uiType: 'custom',
        dom: detail.dom(),
        components: components,
        eventOrder: {
          // Order, the button state is toggled first, so assumed !selected means close.
          'alloy.execute': [ 'toggling', 'alloy.base.behaviour' ]
        },

        events: buttonEvents,

        behaviours: {
          coupling: {
            others: {
              sandbox: function (hotspot) {
                var arrow = hotspot.getSystem().getByUid(detail.partUids().arrow).getOrDie();
                var extras = {
                  onOpen: function () {
                    Toggling.select(arrow);
                  },
                  onClose: function () {
                    Toggling.deselect(arrow);
                  }
                };

                return Beta.makeSandbox(detail, {
                  anchor: 'hotspot',
                  hotspot: hotspot
                }, hotspot, extras);
              }
            }
          },
          keying: {
            mode: 'execution',
            useSpace: true
          },
          focusing: true
        }
      };
    };

    var build = function (f) {
      return UiBuilder.composite('split-dropdown', schema, partTypes, make, f);
    };

    // TODO: Remove likely dupe
    var parts = PartType.generate('split-dropdown', partTypes);

    return {
      build: build,
      parts: Fun.constant(parts)
    };
  }
);<|endoftext|>


<commit_before>
jQuery(function() {
    $(".column").sortable({
        acceptFrom: ".column",
        handle: '.card-header',
        hoverClass: "cursor-move",
        items: ":not(.unsort)",
        forcePlaceholderSize: true,
    }).each(function () {
        this.addEventListener('sortupdate',function( e ) {
            var pos = [];
            $('.column').each(function(){
                var col = [];
                $(this).find('.card').each(function(){
                    col.push($(this).attr('id'));
                });
                pos.push(col.join(','));
            });
            var pos_val = pos.join('|');
            var key = $('#_portal_key').val();
            $.save_user_settings(key, pos_val, function(){
                //alert('success');
            });
        });
    });
    var callback = function() {
        $( this ).find('.icon.chevron').toggleClass( "fa fa-chevron-up" ).toggleClass( "fa fa-chevron-down" );
    };
    // It guarantees that the event will not be registered twice and with that when the
    // quick-form plugin is called make the main form get strange behavior.
    $(".card-header .btn.btn-link" ).unbind("click").click(callback);
});
<commit_msg>Fix btn.link click.<commit_after>
jQuery(function() {
    $(".column").sortable({
        acceptFrom: ".column",
        handle: '.card-header',
        hoverClass: "cursor-move",
        items: ":not(.unsort)",
        forcePlaceholderSize: true,
    }).each(function () {
        this.addEventListener('sortupdate',function( e ) {
            var pos = [];
            $('.column').each(function(){
                var col = [];
                $(this).find('.card').each(function(){
                    col.push($(this).attr('id'));
                });
                pos.push(col.join(','));
            });
            var pos_val = pos.join('|');
            var key = $('#_portal_key').val();
            $.save_user_settings(key, pos_val, function(){
                //alert('success');
            });
        });
    });
    $(".card-header .btn.btn-link" ).each(function () {
        var $el = $(this);
        if (!$el.data("chevron-up-down-click")) {
            $el.click(function() {
                $(this).find(".icon.chevron")
                    .toggleClass( "fa fa-chevron-up" )
                    .toggleClass( "fa fa-chevron-down" );
            });
            $el.data("chevron-up-down-click", true);
        }
    })
});
<|endoftext|>


<commit_before>// Unit test the search_suggestion.js module.
//
// These tests are framework-free and run sequentially; they are invoked
// immediately after being defined.  The contract here is that tests should
// clean up after themselves, and they should explicitly stub all
// dependencies.

add_dependencies({
    util: 'js/util.js',
    Handlebars: 'handlebars',
    Filter: 'js/filter.js',
    typeahead_helper: 'js/typeahead_helper.js',
    stream_data: 'js/stream_data.js',
    narrow: 'js/narrow.js'
});

var search = require('js/search_suggestion.js');

set_global('feature_flags', {});
set_global('page_params', {
    email: 'bob@zulip.com'
});
set_global('recent_subjects', new global.Dict({fold_case: true}));

var stream_data = require('js/stream_data.js');
set_global('stream_data', {
    get_name: stream_data.get_name
});

set_global('narrow', {});

(function test_basic_get_suggestions() {
    var query = 'fred';

    global.stream_data.subscribed_streams = function () {
        return [];
    };

    global.narrow.stream = function () {
        return 'office';
    };

    var suggestions = search.get_suggestions(query);

    var expected = [
        'fred'
    ];
    assert.deepEqual(suggestions.strings, expected);
}());

(function test_subset_suggestions() {
    var query = 'stream:Denmark topic:Hamlet shakespeare';

    global.stream_data.subscribed_streams = function () {
        return [];
    };

    global.narrow.stream = function () {
        return undefined;
    };

    var suggestions = search.get_suggestions(query);

    var expected = [
        "stream:Denmark topic:Hamlet shakespeare",
        "stream:Denmark topic:Hamlet",
        "stream:Denmark"
    ];

    assert.deepEqual(suggestions.strings, expected);
}());

(function test_private_suggestions() {
    global.stream_data.subscribed_streams = function () {
        return [];
    };

    global.narrow.stream = function () {
        return undefined;
    };

    global.page_params.people_list = [
        {
            email: 'ted@zulip.com',
            full_name: 'Ted Smith'
        },
        {
            email: 'alice@zulip.com',
            full_name: 'Alice Ignore'
        }
    ];

    var query = 'is:private';
    var suggestions = search.get_suggestions(query);
    var expected = [
        "is:private",
        "pm-with:alice@zulip.com",
        "pm-with:ted@zulip.com"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'is:private al';
    suggestions = search.get_suggestions(query);
    expected = [
        "is:private al",
        "pm-with:alice@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'pm-with:t';
    suggestions = search.get_suggestions(query);
    expected = [
        "pm-with:t",
        "pm-with:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'pm-with:ted@zulip.com';
    suggestions = search.get_suggestions(query);
    expected = [
        "pm-with:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'sender:ted';
    suggestions = search.get_suggestions(query);
    expected = [
        "sender:ted",
        "sender:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'sender:te';
    suggestions = search.get_suggestions(query);
    expected = [
        "sender:te",
        "sender:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'sender:ted@zulip.com';
    suggestions = search.get_suggestions(query);
    expected = [
        "sender:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    // Users can enter bizarre queries, and if they do, we want to
    // be conservative with suggestions.
    query = 'is:private near:3';
    suggestions = search.get_suggestions(query);
    expected = [
        "is:private near:3",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'pm-with:ted@zulip.com near:3';
    suggestions = search.get_suggestions(query);
    expected = [
        "pm-with:ted@zulip.com near:3",
        "pm-with:ted@zulip.com"
    ];
    assert.deepEqual(suggestions.strings, expected);

    global.page_params.people_list = [];
}());

(function test_empty_query_suggestions() {
    var query = '';

    global.stream_data.subscribed_streams = function () {
        return ['devel', 'office'];
    };

    global.narrow.stream = function () {
        return undefined;
    };

    var suggestions = search.get_suggestions(query);

    var expected = [
        "",
        "in:all",
        "is:private",
        "is:starred",
        "is:mentioned",
        "is:alerted",
        "sender:bob@zulip.com",
        "stream:devel",
        "stream:office"
    ];

    assert.deepEqual(suggestions.strings, expected);

    function describe(q) {
        return suggestions.lookup_table[q].description;
    }
    assert.equal(describe('in:all'), 'All messages');
    assert.equal(describe('is:private'), 'Private messages');
    assert.equal(describe('is:starred'), 'Starred messages');
    assert.equal(describe('is:mentioned'), '@-mentions');
    assert.equal(describe('is:alerted'), 'Alerted messages');
    assert.equal(describe('sender:bob@zulip.com'), 'Sent by me');
    assert.equal(describe('stream:devel'), 'Narrow to stream devel');
}());

(function test_topic_suggestions() {
    var query = 'te';

    global.stream_data.subscribed_streams = function () {
        return ['office'];
    };

    global.narrow.stream = function () {
        return 'office';
    };

    global.recent_subjects = new global.Dict.from({
        office: [
            {subject: 'team'},
            {subject: 'ignore'},
            {subject: 'test'}
        ]
    }, {fold_case: true});

    var suggestions = search.get_suggestions(query);

    var expected = [
        "te",
        "stream:office topic:team",
        "stream:office topic:test"
    ];

    assert.deepEqual(suggestions.strings, expected);

    function describe(q) {
        return suggestions.lookup_table[q].description;
    }
    assert.equal(describe('te'), "Search for te");
    assert.equal(describe('stream:office topic:team'), "Narrow to office > team");

}());

(function test_whitespace_glitch() {
    var query = 'stream:office '; // note trailing space

    global.stream_data.subscribed_streams = function () {
        return ['office'];
    };

    global.narrow.stream = function () {
        return;
    };

    global.recent_subjects = new global.Dict({fold_case: true});

    var suggestions = search.get_suggestions(query);

    var expected = [
        "stream:office"
    ];

    assert.deepEqual(suggestions.strings, expected);
}());

(function test_people_suggestions() {
    var query = 'te';

    global.stream_data.subscribed_streams = function () {
        return [];
    };

    global.narrow.stream = function () {
        return;
    };

    global.page_params.people_list = [
        {
            email: 'ted@zulip.com',
            full_name: 'Ted Smith'
        },
        {
            email: 'alice@zulip.com',
            full_name: 'Alice Ignore'
        }
    ];

    global.recent_subjects = new global.Dict.from({
        office: [
            {subject: 'team'},
            {subject: 'ignore'},
            {subject: 'test'}
        ]
    }, {fold_case: true});

    var suggestions = search.get_suggestions(query);

    var expected = [
        "te",
        "pm-with:ted@zulip.com",
        "sender:ted@zulip.com"
    ];

    assert.deepEqual(suggestions.strings, expected);
    function describe(q) {
        return suggestions.lookup_table[q].description;
    }
    assert.equal(describe('pm-with:ted@zulip.com'),
        "Narrow to private messages with Ted Smith <ted@zulip.com>");
    assert.equal(describe('sender:ted@zulip.com'),
        "Narrow to messages sent by Ted Smith <ted@zulip.com>");

    suggestions = search.get_suggestions('Ted '); // note space

    expected = [
        "Ted",
        "pm-with:ted@zulip.com",
        "sender:ted@zulip.com"
    ];

    assert.deepEqual(suggestions.strings, expected);
}());
<commit_msg>Add test_stream_completion() to search_suggestion unit tests.<commit_after>// Unit test the search_suggestion.js module.
//
// These tests are framework-free and run sequentially; they are invoked
// immediately after being defined.  The contract here is that tests should
// clean up after themselves, and they should explicitly stub all
// dependencies.

add_dependencies({
    util: 'js/util.js',
    Handlebars: 'handlebars',
    Filter: 'js/filter.js',
    typeahead_helper: 'js/typeahead_helper.js',
    stream_data: 'js/stream_data.js',
    narrow: 'js/narrow.js'
});

var search = require('js/search_suggestion.js');

set_global('feature_flags', {});
set_global('page_params', {
    email: 'bob@zulip.com'
});
set_global('recent_subjects', new global.Dict({fold_case: true}));

var stream_data = require('js/stream_data.js');
set_global('stream_data', {
    get_name: stream_data.get_name
});

set_global('narrow', {});

(function test_basic_get_suggestions() {
    var query = 'fred';

    global.stream_data.subscribed_streams = function () {
        return [];
    };

    global.narrow.stream = function () {
        return 'office';
    };

    var suggestions = search.get_suggestions(query);

    var expected = [
        'fred'
    ];
    assert.deepEqual(suggestions.strings, expected);
}());

(function test_subset_suggestions() {
    var query = 'stream:Denmark topic:Hamlet shakespeare';

    global.stream_data.subscribed_streams = function () {
        return [];
    };

    global.narrow.stream = function () {
        return undefined;
    };

    var suggestions = search.get_suggestions(query);

    var expected = [
        "stream:Denmark topic:Hamlet shakespeare",
        "stream:Denmark topic:Hamlet",
        "stream:Denmark"
    ];

    assert.deepEqual(suggestions.strings, expected);
}());

(function test_private_suggestions() {
    global.stream_data.subscribed_streams = function () {
        return [];
    };

    global.narrow.stream = function () {
        return undefined;
    };

    global.page_params.people_list = [
        {
            email: 'ted@zulip.com',
            full_name: 'Ted Smith'
        },
        {
            email: 'alice@zulip.com',
            full_name: 'Alice Ignore'
        }
    ];

    var query = 'is:private';
    var suggestions = search.get_suggestions(query);
    var expected = [
        "is:private",
        "pm-with:alice@zulip.com",
        "pm-with:ted@zulip.com"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'is:private al';
    suggestions = search.get_suggestions(query);
    expected = [
        "is:private al",
        "pm-with:alice@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'pm-with:t';
    suggestions = search.get_suggestions(query);
    expected = [
        "pm-with:t",
        "pm-with:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'pm-with:ted@zulip.com';
    suggestions = search.get_suggestions(query);
    expected = [
        "pm-with:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'sender:ted';
    suggestions = search.get_suggestions(query);
    expected = [
        "sender:ted",
        "sender:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'sender:te';
    suggestions = search.get_suggestions(query);
    expected = [
        "sender:te",
        "sender:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'sender:ted@zulip.com';
    suggestions = search.get_suggestions(query);
    expected = [
        "sender:ted@zulip.com",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    // Users can enter bizarre queries, and if they do, we want to
    // be conservative with suggestions.
    query = 'is:private near:3';
    suggestions = search.get_suggestions(query);
    expected = [
        "is:private near:3",
        "is:private"
    ];
    assert.deepEqual(suggestions.strings, expected);

    query = 'pm-with:ted@zulip.com near:3';
    suggestions = search.get_suggestions(query);
    expected = [
        "pm-with:ted@zulip.com near:3",
        "pm-with:ted@zulip.com"
    ];
    assert.deepEqual(suggestions.strings, expected);

    global.page_params.people_list = [];
}());

(function test_empty_query_suggestions() {
    var query = '';

    global.stream_data.subscribed_streams = function () {
        return ['devel', 'office'];
    };

    global.narrow.stream = function () {
        return undefined;
    };

    var suggestions = search.get_suggestions(query);

    var expected = [
        "",
        "in:all",
        "is:private",
        "is:starred",
        "is:mentioned",
        "is:alerted",
        "sender:bob@zulip.com",
        "stream:devel",
        "stream:office"
    ];

    assert.deepEqual(suggestions.strings, expected);

    function describe(q) {
        return suggestions.lookup_table[q].description;
    }
    assert.equal(describe('in:all'), 'All messages');
    assert.equal(describe('is:private'), 'Private messages');
    assert.equal(describe('is:starred'), 'Starred messages');
    assert.equal(describe('is:mentioned'), '@-mentions');
    assert.equal(describe('is:alerted'), 'Alerted messages');
    assert.equal(describe('sender:bob@zulip.com'), 'Sent by me');
    assert.equal(describe('stream:devel'), 'Narrow to stream devel');
}());

(function test_topic_suggestions() {
    var query = 'te';

    global.stream_data.subscribed_streams = function () {
        return ['office'];
    };

    global.narrow.stream = function () {
        return 'office';
    };

    global.recent_subjects = new global.Dict.from({
        office: [
            {subject: 'team'},
            {subject: 'ignore'},
            {subject: 'test'}
        ]
    }, {fold_case: true});

    var suggestions = search.get_suggestions(query);

    var expected = [
        "te",
        "stream:office topic:team",
        "stream:office topic:test"
    ];

    assert.deepEqual(suggestions.strings, expected);

    function describe(q) {
        return suggestions.lookup_table[q].description;
    }
    assert.equal(describe('te'), "Search for te");
    assert.equal(describe('stream:office topic:team'), "Narrow to office > team");

}());

(function test_whitespace_glitch() {
    var query = 'stream:office '; // note trailing space

    global.stream_data.subscribed_streams = function () {
        return ['office'];
    };

    global.narrow.stream = function () {
        return;
    };

    global.recent_subjects = new global.Dict({fold_case: true});

    var suggestions = search.get_suggestions(query);

    var expected = [
        "stream:office"
    ];

    assert.deepEqual(suggestions.strings, expected);
}());

(function test_stream_completion() {
    var query = 'stream:of';

    global.stream_data.subscribed_streams = function () {
        return ['office'];
    };

    global.narrow.stream = function () {
        return;
    };

    global.recent_subjects = new global.Dict({fold_case: true});

    var suggestions = search.get_suggestions(query);

    var expected = [
        "stream:of",
        "stream:office"
    ];

    assert.deepEqual(suggestions.strings, expected);
}());

(function test_people_suggestions() {
    var query = 'te';

    global.stream_data.subscribed_streams = function () {
        return [];
    };

    global.narrow.stream = function () {
        return;
    };

    global.page_params.people_list = [
        {
            email: 'ted@zulip.com',
            full_name: 'Ted Smith'
        },
        {
            email: 'alice@zulip.com',
            full_name: 'Alice Ignore'
        }
    ];

    global.recent_subjects = new global.Dict.from({
        office: [
            {subject: 'team'},
            {subject: 'ignore'},
            {subject: 'test'}
        ]
    }, {fold_case: true});

    var suggestions = search.get_suggestions(query);

    var expected = [
        "te",
        "pm-with:ted@zulip.com",
        "sender:ted@zulip.com"
    ];

    assert.deepEqual(suggestions.strings, expected);
    function describe(q) {
        return suggestions.lookup_table[q].description;
    }
    assert.equal(describe('pm-with:ted@zulip.com'),
        "Narrow to private messages with Ted Smith <ted@zulip.com>");
    assert.equal(describe('sender:ted@zulip.com'),
        "Narrow to messages sent by Ted Smith <ted@zulip.com>");

    suggestions = search.get_suggestions('Ted '); // note space

    expected = [
        "Ted",
        "pm-with:ted@zulip.com",
        "sender:ted@zulip.com"
    ];

    assert.deepEqual(suggestions.strings, expected);
}());
<|endoftext|>