<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 */

/**
 * GraphQL.js provides a reference implementation for the GraphQL specification
 * but is also a useful utility for operating on GraphQL files and building
 * sophisticated tools.
 *
 * This primary module exports a general purpose function for fulfilling all
 * steps of the GraphQL specification in a single operation, but also includes
 * utilities for every part of the GraphQL specification:
 *
 *   - Parsing the GraphQL language.
 *   - Building a GraphQL type schema.
 *   - Validating a GraphQL request against a type schema.
 *   - Executing a GraphQL request against a type schema.
 *
 * This also includes utility functions for operating on GraphQL types and
 * GraphQL documents to facilitate building tools.
 *
 * You may also import from each sub-directory directly. For example, the
 * following two import statements are equivalent:
 *
 *     import { parse } from 'graphql';
 *     import { parse } from 'graphql/language';
 */

// The primary entry point into fulfilling a GraphQL request.
export type { GraphQLArgs } from './graphql';
export { graphql, graphqlSync } from './graphql';

// Create and operate on GraphQL type definitions and schema.
export {
  GraphQLSchema,
  // Definitions
  GraphQLScalarType,
  GraphQLObjectType,
  GraphQLInterfaceType,
  GraphQLUnionType,
  GraphQLEnumType,
  GraphQLInputObjectType,
  GraphQLList,
  GraphQLNonNull,
  GraphQLDirective,
  // "Enum" of Type Kinds
  TypeKind,
  // Scalars
  specifiedScalarTypes,
  GraphQLInt,
  GraphQLFloat,
  GraphQLString,
  GraphQLBoolean,
  GraphQLID,
  // Built-in Directives defined by the Spec
  specifiedDirectives,
  GraphQLIncludeDirective,
  GraphQLSkipDirective,
  GraphQLDeprecatedDirective,
  // Constant Deprecation Reason
  DEFAULT_DEPRECATION_REASON,
  // Meta-field definitions.
  SchemaMetaFieldDef,
  TypeMetaFieldDef,
  TypeNameMetaFieldDef,
  // GraphQL Types for introspection.
  introspectionTypes,
  __Schema,
  __Directive,
  __DirectiveLocation,
  __Type,
  __Field,
  __InputValue,
  __EnumValue,
  __TypeKind,
  // Predicates
  isSchema,
  isDirective,
  isType,
  isScalarType,
  isObjectType,
  isInterfaceType,
  isUnionType,
  isEnumType,
  isInputObjectType,
  isListType,
  isNonNullType,
  isInputType,
  isOutputType,
  isLeafType,
  isCompositeType,
  isAbstractType,
  isWrappingType,
  isNullableType,
  isNamedType,
  isSpecifiedScalarType,
  isIntrospectionType,
  isSpecifiedDirective,
  // Assertions
  assertType,
  assertScalarType,
  assertObjectType,
  assertInterfaceType,
  assertUnionType,
  assertEnumType,
  assertInputObjectType,
  assertListType,
  assertNonNullType,
  assertInputType,
  assertOutputType,
  assertLeafType,
  assertCompositeType,
  assertAbstractType,
  assertWrappingType,
  assertNullableType,
  assertNamedType,
  // Un-modifiers
  getNullableType,
  getNamedType,
  // Validate GraphQL schema.
  validateSchema,
  assertValidSchema,
} from './type';

export type {
  GraphQLType,
  GraphQLInputType,
  GraphQLOutputType,
  GraphQLLeafType,
  GraphQLCompositeType,
  GraphQLAbstractType,
  GraphQLWrappingType,
  GraphQLNullableType,
  GraphQLNamedType,
  Thunk,
  GraphQLSchemaConfig,
  GraphQLArgument,
  GraphQLArgumentConfig,
  GraphQLEnumTypeConfig,
  GraphQLEnumValue,
  GraphQLEnumValueConfig,
  GraphQLEnumValueConfigMap,
  GraphQLField,
  GraphQLFieldConfig,
  GraphQLFieldConfigArgumentMap,
  GraphQLFieldConfigMap,
  GraphQLFieldMap,
  GraphQLFieldResolver,
  GraphQLInputField,
  GraphQLInputFieldConfig,
  GraphQLInputFieldConfigMap,
  GraphQLInputFieldMap,
  GraphQLInputObjectTypeConfig,
  GraphQLInterfaceTypeConfig,
  GraphQLIsTypeOfFn,
  GraphQLObjectTypeConfig,
  GraphQLResolveInfo,
  ResponsePath,
  GraphQLScalarTypeConfig,
  GraphQLTypeResolver,
  GraphQLUnionTypeConfig,
  GraphQLDirectiveConfig,
} from './type';

// Parse and operate on GraphQL language source files.
export {
  Source,
  getLocation,
  // Parse
  parse,
  parseValue,
  parseType,
  // Print
  print,
  // Visit
  visit,
  visitInParallel,
  visitWithTypeInfo,
  getVisitFn,
  Kind,
  TokenKind,
  DirectiveLocation,
  BREAK,
} from './language';

export type {
  Lexer,
  ParseOptions,
  SourceLocation,
  // Visitor utilities
  ASTVisitor,
  Visitor,
  VisitFn,
  VisitorKeyMap,
  // AST nodes
  Location,
  Token,
  ASTNode,
  ASTKindToNode,
  NameNode,
  DocumentNode,
  DefinitionNode,
  OperationDefinitionNode,
  OperationTypeNode,
  VariableDefinitionNode,
  VariableNode,
  SelectionSetNode,
  SelectionNode,
  FieldNode,
  ArgumentNode,
  FragmentSpreadNode,
  InlineFragmentNode,
  FragmentDefinitionNode,
  ValueNode,
  IntValueNode,
  FloatValueNode,
  StringValueNode,
  BooleanValueNode,
  NullValueNode,
  EnumValueNode,
  ListValueNode,
  ObjectValueNode,
  ObjectFieldNode,
  DirectiveNode,
  TypeNode,
  NamedTypeNode,
  ListTypeNode,
  NonNullTypeNode,
  TypeSystemDefinitionNode,
  SchemaDefinitionNode,
  OperationTypeDefinitionNode,
  TypeDefinitionNode,
  ScalarTypeDefinitionNode,
  ObjectTypeDefinitionNode,
  FieldDefinitionNode,
  InputValueDefinitionNode,
  InterfaceTypeDefinitionNode,
  UnionTypeDefinitionNode,
  EnumTypeDefinitionNode,
  EnumValueDefinitionNode,
  InputObjectTypeDefinitionNode,
  TypeExtensionNode,
  ObjectTypeExtensionNode,
  DirectiveDefinitionNode,
  KindEnum,
  TokenKindEnum,
  DirectiveLocationEnum,
} from './language';

// Execute GraphQL queries.
export {
  execute,
  defaultFieldResolver,
  responsePathAsArray,
  getDirectiveValues,
} from './execution';

export type { ExecutionArgs, ExecutionResult } from './execution';

export { subscribe, createSourceEventStream } from './subscription';

// Validate GraphQL queries.
export {
  validate,
  ValidationContext,
  // All validation rules in the GraphQL Specification.
  specifiedRules,
  // Individual validation rules.
  FieldsOnCorrectTypeRule,
  FragmentsOnCompositeTypesRule,
  KnownArgumentNamesRule,
  KnownDirectivesRule,
  KnownFragmentNamesRule,
  KnownTypeNamesRule,
  LoneAnonymousOperationRule,
  NoFragmentCyclesRule,
  NoUndefinedVariablesRule,
  NoUnusedFragmentsRule,
  NoUnusedVariablesRule,
  OverlappingFieldsCanBeMergedRule,
  PossibleFragmentSpreadsRule,
  ProvidedNonNullArgumentsRule,
  ScalarLeafsRule,
  SingleFieldSubscriptionsRule,
  UniqueArgumentNamesRule,
  UniqueDirectivesPerLocationRule,
  UniqueFragmentNamesRule,
  UniqueInputFieldNamesRule,
  UniqueOperationNamesRule,
  UniqueVariableNamesRule,
  ValuesOfCorrectTypeRule,
  VariablesAreInputTypesRule,
  VariablesDefaultValueAllowedRule,
  VariablesInAllowedPositionRule,
} from './validation';

// Create, format, and print GraphQL errors.
export { GraphQLError, formatError, printError } from './error';

export type { GraphQLFormattedError } from './error';

// Utilities for operating on GraphQL type schema and parsed sources.
export {
  // Produce the GraphQL query recommended for a full schema introspection.
  // Accepts optional IntrospectionOptions.
  getIntrospectionQuery,
  // Deprecated: use getIntrospectionQuery
  introspectionQuery,
  // Gets the target Operation from a Document
  getOperationAST,
  // Convert a GraphQLSchema to an IntrospectionQuery
  introspectionFromSchema,
  // Build a GraphQLSchema from an introspection result.
  buildClientSchema,
  // Build a GraphQLSchema from a parsed GraphQL Schema language AST.
  buildASTSchema,
  // Build a GraphQLSchema from a GraphQL schema language document.
  buildSchema,
  // Get the description from a schema AST node.
  getDescription,
  // Extends an existing GraphQLSchema from a parsed GraphQL Schema
  // language AST.
  extendSchema,
  // Sort a GraphQLSchema.
  lexicographicSortSchema,
  // Print a GraphQLSchema to GraphQL Schema language.
  printSchema,
  // Prints the built-in introspection schema in the Schema Language
  // format.
  printIntrospectionSchema,
  // Print a GraphQLType to GraphQL Schema language.
  printType,
  // Create a GraphQLType from a GraphQL language AST.
  typeFromAST,
  // Create a JavaScript value from a GraphQL language AST with a Type.
  valueFromAST,
  // Create a JavaScript value from a GraphQL language AST without a Type.
  valueFromASTUntyped,
  // Create a GraphQL language AST from a JavaScript value.
  astFromValue,
  // A helper to use within recursive-descent visitors which need to be aware of
  // the GraphQL type system.
  TypeInfo,
  // Coerces a JavaScript value to a GraphQL type, or produces errors.
  coerceValue,
  // @deprecated use coerceValue
  isValidJSValue,
  // Determine if AST values adhere to a GraphQL type.
  isValidLiteralValue,
  // Concatenates multiple AST together.
  concatAST,
  // Separates an AST into an AST per Operation.
  separateOperations,
  // Comparators for types
  isEqualType,
  isTypeSubTypeOf,
  doTypesOverlap,
  // Asserts a string is a valid GraphQL name.
  assertValidName,
  // Compares two GraphQLSchemas and detects breaking changes.
  findBreakingChanges,
  findDangerousChanges,
  BreakingChangeType,
  DangerousChangeType,
  // Report all deprecated usage within a GraphQL document.
  findDeprecatedUsages,
} from './utilities';

export type {
  assertValidName,
  isValidNameError,
  BreakingChange,
  DangerousChange,
  IntrospectionOptions,
  IntrospectionDirective,
  IntrospectionEnumType,
  IntrospectionEnumValue,
  IntrospectionField,
  IntrospectionInputObjectType,
  IntrospectionInputType,
  IntrospectionInputTypeRef,
  IntrospectionInputValue,
  IntrospectionInterfaceType,
  IntrospectionListTypeRef,
  IntrospectionNamedTypeRef,
  IntrospectionNonNullTypeRef,
  IntrospectionObjectType,
  IntrospectionOutputType,
  IntrospectionOutputTypeRef,
  IntrospectionQuery,
  IntrospectionScalarType,
  IntrospectionSchema,
  IntrospectionType,
  IntrospectionTypeRef,
  IntrospectionUnionType,
} from './utilities';
<commit_msg>export isValidNameError<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 */

/**
 * GraphQL.js provides a reference implementation for the GraphQL specification
 * but is also a useful utility for operating on GraphQL files and building
 * sophisticated tools.
 *
 * This primary module exports a general purpose function for fulfilling all
 * steps of the GraphQL specification in a single operation, but also includes
 * utilities for every part of the GraphQL specification:
 *
 *   - Parsing the GraphQL language.
 *   - Building a GraphQL type schema.
 *   - Validating a GraphQL request against a type schema.
 *   - Executing a GraphQL request against a type schema.
 *
 * This also includes utility functions for operating on GraphQL types and
 * GraphQL documents to facilitate building tools.
 *
 * You may also import from each sub-directory directly. For example, the
 * following two import statements are equivalent:
 *
 *     import { parse } from 'graphql';
 *     import { parse } from 'graphql/language';
 */

// The primary entry point into fulfilling a GraphQL request.
export type { GraphQLArgs } from './graphql';
export { graphql, graphqlSync } from './graphql';

// Create and operate on GraphQL type definitions and schema.
export {
  GraphQLSchema,
  // Definitions
  GraphQLScalarType,
  GraphQLObjectType,
  GraphQLInterfaceType,
  GraphQLUnionType,
  GraphQLEnumType,
  GraphQLInputObjectType,
  GraphQLList,
  GraphQLNonNull,
  GraphQLDirective,
  // "Enum" of Type Kinds
  TypeKind,
  // Scalars
  specifiedScalarTypes,
  GraphQLInt,
  GraphQLFloat,
  GraphQLString,
  GraphQLBoolean,
  GraphQLID,
  // Built-in Directives defined by the Spec
  specifiedDirectives,
  GraphQLIncludeDirective,
  GraphQLSkipDirective,
  GraphQLDeprecatedDirective,
  // Constant Deprecation Reason
  DEFAULT_DEPRECATION_REASON,
  // Meta-field definitions.
  SchemaMetaFieldDef,
  TypeMetaFieldDef,
  TypeNameMetaFieldDef,
  // GraphQL Types for introspection.
  introspectionTypes,
  __Schema,
  __Directive,
  __DirectiveLocation,
  __Type,
  __Field,
  __InputValue,
  __EnumValue,
  __TypeKind,
  // Predicates
  isSchema,
  isDirective,
  isType,
  isScalarType,
  isObjectType,
  isInterfaceType,
  isUnionType,
  isEnumType,
  isInputObjectType,
  isListType,
  isNonNullType,
  isInputType,
  isOutputType,
  isLeafType,
  isCompositeType,
  isAbstractType,
  isWrappingType,
  isNullableType,
  isNamedType,
  isSpecifiedScalarType,
  isIntrospectionType,
  isSpecifiedDirective,
  // Assertions
  assertType,
  assertScalarType,
  assertObjectType,
  assertInterfaceType,
  assertUnionType,
  assertEnumType,
  assertInputObjectType,
  assertListType,
  assertNonNullType,
  assertInputType,
  assertOutputType,
  assertLeafType,
  assertCompositeType,
  assertAbstractType,
  assertWrappingType,
  assertNullableType,
  assertNamedType,
  // Un-modifiers
  getNullableType,
  getNamedType,
  // Validate GraphQL schema.
  validateSchema,
  assertValidSchema,
} from './type';

export type {
  GraphQLType,
  GraphQLInputType,
  GraphQLOutputType,
  GraphQLLeafType,
  GraphQLCompositeType,
  GraphQLAbstractType,
  GraphQLWrappingType,
  GraphQLNullableType,
  GraphQLNamedType,
  Thunk,
  GraphQLSchemaConfig,
  GraphQLArgument,
  GraphQLArgumentConfig,
  GraphQLEnumTypeConfig,
  GraphQLEnumValue,
  GraphQLEnumValueConfig,
  GraphQLEnumValueConfigMap,
  GraphQLField,
  GraphQLFieldConfig,
  GraphQLFieldConfigArgumentMap,
  GraphQLFieldConfigMap,
  GraphQLFieldMap,
  GraphQLFieldResolver,
  GraphQLInputField,
  GraphQLInputFieldConfig,
  GraphQLInputFieldConfigMap,
  GraphQLInputFieldMap,
  GraphQLInputObjectTypeConfig,
  GraphQLInterfaceTypeConfig,
  GraphQLIsTypeOfFn,
  GraphQLObjectTypeConfig,
  GraphQLResolveInfo,
  ResponsePath,
  GraphQLScalarTypeConfig,
  GraphQLTypeResolver,
  GraphQLUnionTypeConfig,
  GraphQLDirectiveConfig,
} from './type';

// Parse and operate on GraphQL language source files.
export {
  Source,
  getLocation,
  // Parse
  parse,
  parseValue,
  parseType,
  // Print
  print,
  // Visit
  visit,
  visitInParallel,
  visitWithTypeInfo,
  getVisitFn,
  Kind,
  TokenKind,
  DirectiveLocation,
  BREAK,
} from './language';

export type {
  Lexer,
  ParseOptions,
  SourceLocation,
  // Visitor utilities
  ASTVisitor,
  Visitor,
  VisitFn,
  VisitorKeyMap,
  // AST nodes
  Location,
  Token,
  ASTNode,
  ASTKindToNode,
  NameNode,
  DocumentNode,
  DefinitionNode,
  OperationDefinitionNode,
  OperationTypeNode,
  VariableDefinitionNode,
  VariableNode,
  SelectionSetNode,
  SelectionNode,
  FieldNode,
  ArgumentNode,
  FragmentSpreadNode,
  InlineFragmentNode,
  FragmentDefinitionNode,
  ValueNode,
  IntValueNode,
  FloatValueNode,
  StringValueNode,
  BooleanValueNode,
  NullValueNode,
  EnumValueNode,
  ListValueNode,
  ObjectValueNode,
  ObjectFieldNode,
  DirectiveNode,
  TypeNode,
  NamedTypeNode,
  ListTypeNode,
  NonNullTypeNode,
  TypeSystemDefinitionNode,
  SchemaDefinitionNode,
  OperationTypeDefinitionNode,
  TypeDefinitionNode,
  ScalarTypeDefinitionNode,
  ObjectTypeDefinitionNode,
  FieldDefinitionNode,
  InputValueDefinitionNode,
  InterfaceTypeDefinitionNode,
  UnionTypeDefinitionNode,
  EnumTypeDefinitionNode,
  EnumValueDefinitionNode,
  InputObjectTypeDefinitionNode,
  TypeExtensionNode,
  ObjectTypeExtensionNode,
  DirectiveDefinitionNode,
  KindEnum,
  TokenKindEnum,
  DirectiveLocationEnum,
} from './language';

// Execute GraphQL queries.
export {
  execute,
  defaultFieldResolver,
  responsePathAsArray,
  getDirectiveValues,
} from './execution';

export type { ExecutionArgs, ExecutionResult } from './execution';

export { subscribe, createSourceEventStream } from './subscription';

// Validate GraphQL queries.
export {
  validate,
  ValidationContext,
  // All validation rules in the GraphQL Specification.
  specifiedRules,
  // Individual validation rules.
  FieldsOnCorrectTypeRule,
  FragmentsOnCompositeTypesRule,
  KnownArgumentNamesRule,
  KnownDirectivesRule,
  KnownFragmentNamesRule,
  KnownTypeNamesRule,
  LoneAnonymousOperationRule,
  NoFragmentCyclesRule,
  NoUndefinedVariablesRule,
  NoUnusedFragmentsRule,
  NoUnusedVariablesRule,
  OverlappingFieldsCanBeMergedRule,
  PossibleFragmentSpreadsRule,
  ProvidedNonNullArgumentsRule,
  ScalarLeafsRule,
  SingleFieldSubscriptionsRule,
  UniqueArgumentNamesRule,
  UniqueDirectivesPerLocationRule,
  UniqueFragmentNamesRule,
  UniqueInputFieldNamesRule,
  UniqueOperationNamesRule,
  UniqueVariableNamesRule,
  ValuesOfCorrectTypeRule,
  VariablesAreInputTypesRule,
  VariablesDefaultValueAllowedRule,
  VariablesInAllowedPositionRule,
} from './validation';

// Create, format, and print GraphQL errors.
export { GraphQLError, formatError, printError } from './error';

export type { GraphQLFormattedError } from './error';

// Utilities for operating on GraphQL type schema and parsed sources.
export {
  // Produce the GraphQL query recommended for a full schema introspection.
  // Accepts optional IntrospectionOptions.
  getIntrospectionQuery,
  // Deprecated: use getIntrospectionQuery
  introspectionQuery,
  // Gets the target Operation from a Document
  getOperationAST,
  // Convert a GraphQLSchema to an IntrospectionQuery
  introspectionFromSchema,
  // Build a GraphQLSchema from an introspection result.
  buildClientSchema,
  // Build a GraphQLSchema from a parsed GraphQL Schema language AST.
  buildASTSchema,
  // Build a GraphQLSchema from a GraphQL schema language document.
  buildSchema,
  // Get the description from a schema AST node.
  getDescription,
  // Extends an existing GraphQLSchema from a parsed GraphQL Schema
  // language AST.
  extendSchema,
  // Sort a GraphQLSchema.
  lexicographicSortSchema,
  // Print a GraphQLSchema to GraphQL Schema language.
  printSchema,
  // Prints the built-in introspection schema in the Schema Language
  // format.
  printIntrospectionSchema,
  // Print a GraphQLType to GraphQL Schema language.
  printType,
  // Create a GraphQLType from a GraphQL language AST.
  typeFromAST,
  // Create a JavaScript value from a GraphQL language AST with a Type.
  valueFromAST,
  // Create a JavaScript value from a GraphQL language AST without a Type.
  valueFromASTUntyped,
  // Create a GraphQL language AST from a JavaScript value.
  astFromValue,
  // A helper to use within recursive-descent visitors which need to be aware of
  // the GraphQL type system.
  TypeInfo,
  // Coerces a JavaScript value to a GraphQL type, or produces errors.
  coerceValue,
  // @deprecated use coerceValue
  isValidJSValue,
  // Determine if AST values adhere to a GraphQL type.
  isValidLiteralValue,
  // Concatenates multiple AST together.
  concatAST,
  // Separates an AST into an AST per Operation.
  separateOperations,
  // Comparators for types
  isEqualType,
  isTypeSubTypeOf,
  doTypesOverlap,
  // Asserts a string is a valid GraphQL name.
  assertValidName,
  // Determine if a string is a valid GraphQL name.
  isValidNameError
  // Compares two GraphQLSchemas and detects breaking changes.
  findBreakingChanges,
  findDangerousChanges,
  BreakingChangeType,
  DangerousChangeType,
  // Report all deprecated usage within a GraphQL document.
  findDeprecatedUsages,
} from './utilities';

export type {
  BreakingChange,
  DangerousChange,
  IntrospectionOptions,
  IntrospectionDirective,
  IntrospectionEnumType,
  IntrospectionEnumValue,
  IntrospectionField,
  IntrospectionInputObjectType,
  IntrospectionInputType,
  IntrospectionInputTypeRef,
  IntrospectionInputValue,
  IntrospectionInterfaceType,
  IntrospectionListTypeRef,
  IntrospectionNamedTypeRef,
  IntrospectionNonNullTypeRef,
  IntrospectionObjectType,
  IntrospectionOutputType,
  IntrospectionOutputTypeRef,
  IntrospectionQuery,
  IntrospectionScalarType,
  IntrospectionSchema,
  IntrospectionType,
  IntrospectionTypeRef,
  IntrospectionUnionType,
} from './utilities';
<|endoftext|>


<commit_before>// Module must be started with environment variables
//
//  accesskey="api.ai client access key"
//  subscriptionkey="api.ai subscription key"
//  slackkey="slack bot key"
//

'use strict';

const Botkit = require('botkit');

const apiai = require('apiai');
const uuid = require('node-uuid');

const http = require('http');

const Entities = require('html-entities').XmlEntities;
const decoder = new Entities();

const apiAiAccessToken = process.env.accesstoken;
const apiAiSubscriptionKey = process.env.subscriptionkey;
const slackBotKey = process.env.slackkey;

const apiAiService = apiai(apiAiAccessToken, apiAiSubscriptionKey);

var sessionIds = {};

const controller = Botkit.slackbot({
    debug: false
    //include "log: false" to disable logging
});

var bot = controller.spawn({
    token: slackBotKey
}).startRTM();

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

controller.hears(['.*'], ['bot_message'], function (bot, message) {

    try {
        if (message.type == 'message') {
            if (message.user == bot.identity.id) {
                // message from bot can be skipped
            }
            else if (message.text.indexOf("<@U") == 0 && message.text.indexOf(bot.identity.id) == -1) {
                // skip other users direct mentions
            }
            else if (message.text.includes("Sent text to")) {
                // skip sent text confirmations from Burner
                console.log('Skipping Burner response.');
            }
            else {

                var requestText = decoder.decode(message.text);
                requestText = requestText.replace("’", "'");

                var burnerMessageRegex = /Inbound message from \+(\d*):\s(.*)/;
                var returnNumber = '';
                var smsMessage;

                // Parse the SMS message and return number out of Burner's slackbot message
                if ((smsMessage = burnerMessageRegex.exec(requestText)) !== null) {
                    returnNumber = '@' + smsMessage[1];
                    requestText = smsMessage[2];

                    console.log('returnNumber', returnNumber);
                    console.log('requestText', requestText);
                } else {
                    // If message pattern is not matched, exit and ignore the message.
                    return null;
                }

                var channel = message.channel;
                var messageType = message.event;
                var botId = "<@" + bot.identity.id + ">";

                console.log(messageType);

                if (requestText.indexOf(botId) > -1) {
                    requestText = requestText.replace(botId, '');
                }

                if (!(channel in sessionIds)) {
                    sessionIds[channel] = uuid.v1();
                }

                var request = apiAiService.textRequest(requestText,
                    {
                        sessionId: sessionIds[channel]
                    });

                request.on('response', function (response) {
                    console.log('response', response);

                    if (isDefined(response.result)) {
                        // Message everyone in the channel if the question was not answered by the
                        // Api.ai agent.
                        if ( response.result.fulfillment.speech === '' ) {
                            var responseText = '<!channel> The Api.ai agent encountered a request' +
                              ' it could not answer. Simply prepend a message with `/burner text ' +
                              returnNumber + '` to reply to the unanswered request.';
                        // Otherwise, the question was answered, so send an SMS response.
                        } else {
                            // Preface the response with the appropriate return SMS number.
                            var responseText = returnNumber + ' ' + response.result.fulfillment.speech;
                        }

                        bot.reply( message, responseText, function( err, resp ) {
                            console.log( err, resp );
                        } );
                    }
                });

                request.on('error', function (error) {
                    console.error(error);
                });

                request.end();
            }
        }
    } catch (err) {
        console.error(err);
    }

});

//Create a server to prevent Heroku kills the bot
var server = http.createServer(function (req, res) {
    res.end()
});

//Lets start our server
server.listen((process.env.PORT || 5000), function () {
    console.log("Server listening");
});<commit_msg>Prepend return numbers with the appropriate character<commit_after>// Module must be started with environment variables
//
//  accesskey="api.ai client access key"
//  subscriptionkey="api.ai subscription key"
//  slackkey="slack bot key"
//

'use strict';

const Botkit = require('botkit');

const apiai = require('apiai');
const uuid = require('node-uuid');

const http = require('http');

const Entities = require('html-entities').XmlEntities;
const decoder = new Entities();

const apiAiAccessToken = process.env.accesstoken;
const apiAiSubscriptionKey = process.env.subscriptionkey;
const slackBotKey = process.env.slackkey;

const apiAiService = apiai(apiAiAccessToken, apiAiSubscriptionKey);

var sessionIds = {};

const controller = Botkit.slackbot({
    debug: false
    //include "log: false" to disable logging
});

var bot = controller.spawn({
    token: slackBotKey
}).startRTM();

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

controller.hears(['.*'], ['bot_message'], function (bot, message) {

    try {
        if (message.type == 'message') {
            if (message.user == bot.identity.id) {
                // message from bot can be skipped
            }
            else if (message.text.indexOf("<@U") == 0 && message.text.indexOf(bot.identity.id) == -1) {
                // skip other users direct mentions
            }
            else if (message.text.includes("Sent text to")) {
                // skip sent text confirmations from Burner
                console.log('Skipping Burner response.');
            }
            else {

                var requestText = decoder.decode(message.text);
                requestText = requestText.replace("’", "'");

                var burnerMessageRegex = /Inbound message from \+(\d*):\s(.*)/;
                var returnNumber = '';
                var smsMessage;

                // Parse the SMS message and return number out of Burner's slackbot message
                if ((smsMessage = burnerMessageRegex.exec(requestText)) !== null) {
                    returnNumber = smsMessage[1];
                    requestText = smsMessage[2];

                    console.log('returnNumber', returnNumber);
                    console.log('requestText', requestText);
                } else {
                    // If message pattern is not matched, exit and ignore the message.
                    return null;
                }

                var channel = message.channel;
                var messageType = message.event;
                var botId = "<@" + bot.identity.id + ">";

                console.log(messageType);

                if (requestText.indexOf(botId) > -1) {
                    requestText = requestText.replace(botId, '');
                }

                if (!(channel in sessionIds)) {
                    sessionIds[channel] = uuid.v1();
                }

                var request = apiAiService.textRequest(requestText,
                    {
                        sessionId: sessionIds[channel]
                    });

                request.on('response', function (response) {
                    console.log('response', response);

                    if (isDefined(response.result)) {
                        // Message everyone in the channel if the question was not answered by the
                        // Api.ai agent.
                        if ( response.result.fulfillment.speech === '' ) {
                            var responseText = '<!channel> The Api.ai agent encountered a request' +
                              ' it could not answer. Simply prepend a message with `/burner text ' +
                              '+' + returnNumber + '` to reply to the unanswered request.';
                        // Otherwise, the question was answered, so send an SMS response.
                        } else {
                            // Preface the response with the appropriate return SMS number.
                            var responseText = '@' + returnNumber + ' ' + response.result.fulfillment.speech;
                        }

                        bot.reply( message, responseText, function( err, resp ) {
                            console.log( err, resp );
                        } );
                    }
                });

                request.on('error', function (error) {
                    console.error(error);
                });

                request.end();
            }
        }
    } catch (err) {
        console.error(err);
    }

});

//Create a server to prevent Heroku kills the bot
var server = http.createServer(function (req, res) {
    res.end()
});

//Lets start our server
server.listen((process.env.PORT || 5000), function () {
    console.log("Server listening");
});<|endoftext|>


<commit_before>import deepstream from 'deepstream.io-client-js';
import merge from 'lodash.merge';

export const statuses = deepstream.CONSTANTS.CONNECTION_STATE;

/**
 * Add entry to a DS List (avoiding duplicates).
 * !! Always use this instead of list.addEntry !!
 * @param {Object} list Deepstream List handle
 * @param {String} str  Entry to add
 */
export function addEntry(list, str) {
  if (list.getEntries().indexOf(str) > -1) return undefined;
  return list.addEntry(str);
}

function getRecordP(name) {
  return new Promise(resolve => this.record.getRecord(name).whenReady(r => resolve(r)));
}

function getListP(name) {
  return new Promise(resolve => this.record.getList(name).whenReady(r => resolve(r)));
}

function getExistingP(type, pathStr) {
  return new Promise((resolve, reject) =>
    this.record.has(pathStr, (error, hasRecord) => {
      if (error) reject(new Error(error));
      if (hasRecord) this.record[`get${type}`](pathStr).whenReady(r => resolve(r));
      else reject(new Error(`${type} does not exist: ${pathStr}`));
    }),
  );
}

function removeFromList(listPath, id) {
  return this.record.getExistingListP(listPath).then(l => {
    l.removeEntry(id);
    return l;
  });
}

function snapshotP(name) {
  return new Promise((resolve, reject) =>
    this.record.snapshot(name, (error, data) => {
      if (error) reject(new Error(error));
      else resolve(data);
    }),
  );
}

function listedRecordP(listPath, recordId, obj, deepMerge, overwrite, fullPathList = true) {
  const id = recordId || this.getUid();
  const rPath = `${listPath}/${id}`;
  return Promise.all([
    this.record.getRecordP(rPath),
    this.record.getListP(listPath),
  ]).then(([r, l]) => {
    // Update list:
    if (fullPathList) addEntry(l, rPath);
    else addEntry(l, id);
    // Update record:
    let created = false;
    const record = r.get();
    const newRecord = { ...obj, id: recordId };
    if (Object.keys(record).length === 0) {
      r.set(newRecord);
      created = true;
    } else if (deepMerge) {
      r.set(merge(record, obj));
    } else if (overwrite) {
      r.set(newRecord);
    } else {
      Object.keys(newRecord).forEach(key => r.set(key, newRecord[key]));
    }
    return [id, created];
  });
}

function setExistingRecordP(name, obj, deepMerge, overwrite) {
  return this.record.getExistingRecordP(name).then(r => {
    if (deepMerge) {
      const record = r.get();
      r.set(merge(record, obj));
    } else if (overwrite) {
      r.set(obj);
    } else {
      Object.keys(obj).forEach(key => r.set(key, obj[key]));
    }
    return r;
  });
}

function loginP(authParams) {
  return new Promise((resolve, reject) =>
    this.login(authParams, (success, data) => {
      if (success) resolve(data);
      else reject(new Error(data));
    }),
  );
}

function hasP(name) {
  return new Promise((resolve, reject) =>
    this.record.has(name, (error, hasRecord) => {
      if (error) reject(new Error(error));
      else resolve(hasRecord);
    }),
  );
}

export default function getClient(url, options) {
  const c = deepstream(url, options);
  c.record.getRecordP = getRecordP.bind(c);
  c.record.getListP = getListP.bind(c);
  c.record.getExistingRecordP = getExistingP.bind(c, 'Record');
  c.record.getExistingListP = getExistingP.bind(c, 'List');
  c.record.setExistingRecordP = setExistingRecordP.bind(c);
  c.record.snapshotP = snapshotP.bind(c);
  c.record.hasP = hasP.bind(c);
  c.record.removeFromList = removeFromList.bind(c);
  c.record.listedRecordP = listedRecordP.bind(c);
  c.loginP = loginP.bind(c);
  return c;
}

function withTenant(func, name, ...args) {
  return this.record[func](`${this.getTenant()}/${name}`, ...args);
}

export function getClientWithTenant(url, options, tenant = 'demo') {
  const c = getClient(url, options);
  c.getTenant = function () {
    return this;
  }.bind(tenant); // non-closure getter
  c.record.getRecordPT = withTenant.bind(c, 'getRecordP');
  c.record.getRecordT = withTenant.bind(c, 'getRecord');
  c.record.getListPT = withTenant.bind(c, 'getListP');
  c.record.getListT = withTenant.bind(c, 'getList');
  c.record.snapshotPT = withTenant.bind(c, 'snapshotP');
  c.record.snapshotT = withTenant.bind(c, 'snapshot');
  c.record.hasPT = withTenant.bind(c, 'hasP');
  c.record.hasT = withTenant.bind(c, 'has');
  c.record.removeFromListT = withTenant.bind(c, 'removeFromList');
  c.record.getExistingRecordPT = withTenant.bind(c, 'getExistingRecordP');
  c.record.getExistingListPT = withTenant.bind(c, 'getExistingListP');
  c.record.listedRecordPT = withTenant.bind(c, 'listedRecordP');
  c.record.setExistingRecordPT = withTenant.bind(c, 'setExistingRecordP');
  return c;
}

// ------------------------------------------------------------
//  FOR SINGLETON USE
export const ds = { client: undefined };
<commit_msg>Added "P" to removeFromList for consistency, and a "TT" version<commit_after>import deepstream from 'deepstream.io-client-js';
import merge from 'lodash.merge';

export const statuses = deepstream.CONSTANTS.CONNECTION_STATE;

/**
 * Add entry to a DS List (avoiding duplicates).
 * !! Always use this instead of list.addEntry !!
 * @param {Object} list Deepstream List handle
 * @param {String} str  Entry to add
 */
export function addEntry(list, str) {
  if (list.getEntries().indexOf(str) > -1) return undefined;
  return list.addEntry(str);
}

function getRecordP(name) {
  return new Promise(resolve => this.record.getRecord(name).whenReady(r => resolve(r)));
}

function getListP(name) {
  return new Promise(resolve => this.record.getList(name).whenReady(r => resolve(r)));
}

function getExistingP(type, pathStr) {
  return new Promise((resolve, reject) =>
    this.record.has(pathStr, (error, hasRecord) => {
      if (error) reject(new Error(error));
      if (hasRecord) this.record[`get${type}`](pathStr).whenReady(r => resolve(r));
      else reject(new Error(`${type} does not exist: ${pathStr}`));
    }),
  );
}

function removeFromListP(listPath, id) {
  return this.record.getExistingListP(listPath).then(l => {
    l.removeEntry(id);
    return l;
  });
}

function snapshotP(name) {
  return new Promise((resolve, reject) =>
    this.record.snapshot(name, (error, data) => {
      if (error) reject(new Error(error));
      else resolve(data);
    }),
  );
}

function listedRecordP(listPath, recordId, obj, deepMerge, overwrite, fullPathList = true) {
  const id = recordId || this.getUid();
  const rPath = `${listPath}/${id}`;
  return Promise.all([
    this.record.getRecordP(rPath),
    this.record.getListP(listPath),
  ]).then(([r, l]) => {
    // Update list:
    if (fullPathList) addEntry(l, rPath);
    else addEntry(l, id);
    // Update record:
    let created = false;
    const record = r.get();
    const newRecord = { ...obj, id: recordId };
    if (Object.keys(record).length === 0) {
      r.set(newRecord);
      created = true;
    } else if (deepMerge) {
      r.set(merge(record, obj));
    } else if (overwrite) {
      r.set(newRecord);
    } else {
      Object.keys(newRecord).forEach(key => r.set(key, newRecord[key]));
    }
    return [id, created];
  });
}

function setExistingRecordP(name, obj, deepMerge, overwrite) {
  return this.record.getExistingRecordP(name).then(r => {
    if (deepMerge) {
      const record = r.get();
      r.set(merge(record, obj));
    } else if (overwrite) {
      r.set(obj);
    } else {
      Object.keys(obj).forEach(key => r.set(key, obj[key]));
    }
    return r;
  });
}

function loginP(authParams) {
  return new Promise((resolve, reject) =>
    this.login(authParams, (success, data) => {
      if (success) resolve(data);
      else reject(new Error(data));
    }),
  );
}

function hasP(name) {
  return new Promise((resolve, reject) =>
    this.record.has(name, (error, hasRecord) => {
      if (error) reject(new Error(error));
      else resolve(hasRecord);
    }),
  );
}

export default function getClient(url, options) {
  const c = deepstream(url, options);
  c.record.getRecordP = getRecordP.bind(c);
  c.record.getListP = getListP.bind(c);
  c.record.getExistingRecordP = getExistingP.bind(c, 'Record');
  c.record.getExistingListP = getExistingP.bind(c, 'List');
  c.record.setExistingRecordP = setExistingRecordP.bind(c);
  c.record.snapshotP = snapshotP.bind(c);
  c.record.hasP = hasP.bind(c);
  c.record.removeFromListP = removeFromListP.bind(c);
  c.record.listedRecordP = listedRecordP.bind(c);
  c.loginP = loginP.bind(c);
  return c;
}

function withTenant(func, name, ...args) {
  return this.record[func](`${this.getTenant()}/${name}`, ...args);
}

export function getClientWithTenant(url, options, tenant = 'demo') {
  const c = getClient(url, options);
  c.getTenant = function () {
    return this;
  }.bind(tenant); // non-closure getter
  c.record.getRecordPT = withTenant.bind(c, 'getRecordP');
  c.record.getRecordT = withTenant.bind(c, 'getRecord');
  c.record.getListPT = withTenant.bind(c, 'getListP');
  c.record.getListT = withTenant.bind(c, 'getList');
  c.record.snapshotPT = withTenant.bind(c, 'snapshotP');
  c.record.snapshotT = withTenant.bind(c, 'snapshot');
  c.record.hasPT = withTenant.bind(c, 'hasP');
  c.record.hasT = withTenant.bind(c, 'has');
  c.record.removeFromListPT = withTenant.bind(c, 'removeFromListP');
  c.record.removeFromListPTT = function (name, id) {
    return this.record.removeFromListP(`${this.getTenant()}/${name}`, `${this.getTenant()}/${id}`);
  }.bind(c);
  c.record.getExistingRecordPT = withTenant.bind(c, 'getExistingRecordP');
  c.record.getExistingListPT = withTenant.bind(c, 'getExistingListP');
  c.record.listedRecordPT = withTenant.bind(c, 'listedRecordP');
  c.record.setExistingRecordPT = withTenant.bind(c, 'setExistingRecordP');
  return c;
}

// ------------------------------------------------------------
//  FOR SINGLETON USE
export const ds = { client: undefined };
<|endoftext|>


<commit_before>'use strict';

const Cannery = {
    Model: require('./model')
};

Cannery.registerType = require('./util/registerType')(Cannery);

module.exports = Cannery
    .registerType('AnyType', require('./types/base'))
    .registerType('BooleanType', require('./types/boolean'))
    .registerType('DateType', require('./types/date'))
    .registerType('StringType', require('./types/string'))
    .registerType('NumberType', require('./types/number'))
    .registerType('ArrayType', require('./types/array'))
    .registerType('ObjectType', require('./types/object'))
    .registerType('HasMany', require('./types/hasMany'))
    .registerType('HasOne', require('./types/hasOne'));
<commit_msg>fixed missing types object<commit_after>'use strict';

const Cannery = {
    Model: require('./model'),
    Types: {}
};

Cannery.registerType = require('./util/registerType')(Cannery);

module.exports = Cannery
    .registerType('AnyType', require('./types/base'))
    .registerType('BooleanType', require('./types/boolean'))
    .registerType('DateType', require('./types/date'))
    .registerType('StringType', require('./types/string'))
    .registerType('NumberType', require('./types/number'))
    .registerType('ArrayType', require('./types/array'))
    .registerType('ObjectType', require('./types/object'))
    .registerType('HasMany', require('./types/hasMany'))
    .registerType('HasOne', require('./types/hasOne'));
<|endoftext|>


<commit_before>module.exports = {
  AppBar: require('./app-bar'),
  AppCanvas: require('./app-canvas'),
  Checkbox: require('./checkbox'),
  DatePicker: require('./date-picker/date-picker'),
  Dialog: require('./dialog'),
  DialogWindow: require('./dialog-window'),
  DropDownIcon: require('./drop-down-icon'),
  DropDownMenu: require('./drop-down-menu'),
  EnhancedButton: require('./enhanced-button'),
  FlatButton: require('./flat-button'),
  FloatingActionButton: require('./floating-action-button'),
  FontIcon: require('./font-icon'),
  IconButton: require('./icon-button'),
  LeftNav: require('./left-nav'),
  Menu: require('./menu/menu'),
  MenuItem: require('./menu/menu-item'),
  Mixins: {
    Classable: require('./mixins/classable'),
    ClickAwayable: require('./mixins/click-awayable'),
    WindowListenable: require('./mixins/window-listenable'),
    StylePropable: require('./mixins/style-propable')
  },
  Paper: require('./paper'),
  RadioButton: require('./radio-button'),
  RadioButtonGroup: require('./radio-button-group'),
  RaisedButton: require('./raised-button'),
  Slider: require('./slider'),
  SvgIcon: require('./svg-icon'),
  Icons: {
    NavigationMenu: require('./svg-icons/navigation-menu'),
    NavigationChevronLeft: require('./svg-icons/navigation-chevron-left'),
    NavigationChevronRight: require('./svg-icons/navigation-chevron-right')
  },
  Styles: {
    AutoPrefix: require('./styles/auto-prefix'),
    Colors: require('./styles/colors'),
    Spacing: require('./styles/spacing'),
    ThemeManager: require('./styles/theme-manager'),
    Transitions: require('./styles/transitions'),
    Typography: require('./styles/typography')
  },
  Snackbar: require('./snackbar'),
  Tab: require('./tabs/tab'),
  Tabs: require('./tabs/tabs'),
  Toggle: require('./toggle'),
  TextField: require('./text-field'),
  Toolbar: require('./toolbar/toolbar'),
  ToolbarGroup: require('./toolbar/toolbar-group'),
  ToolbarSeparator: require('./toolbar/toolbar-separator'),
  ToolbarTitle: require('./toolbar/toolbar-title'),
  Tooltip: require('./tooltip'),
  Utils: {
    CssEvent: require('./utils/css-event'),
    Dom: require('./utils/dom'),
    Events: require('./utils/events'),
    KeyCode: require('./utils/key-code'),
    KeyLine: require('./utils/key-line'),
    ColorManipulator: require('./utils/color-manipulator'),
    Extend: require('./utils/extend'),
    UniqueId: require('./utils/unique-id')
  }
};
<commit_msg>Time Picker Included on components file<commit_after>module.exports = {
  AppBar: require('./app-bar'),
  AppCanvas: require('./app-canvas'),
  Checkbox: require('./checkbox'),
  DatePicker: require('./date-picker/date-picker'),
  Dialog: require('./dialog'),
  DialogWindow: require('./dialog-window'),
  DropDownIcon: require('./drop-down-icon'),
  DropDownMenu: require('./drop-down-menu'),
  EnhancedButton: require('./enhanced-button'),
  FlatButton: require('./flat-button'),
  FloatingActionButton: require('./floating-action-button'),
  FontIcon: require('./font-icon'),
  IconButton: require('./icon-button'),
  LeftNav: require('./left-nav'),
  Menu: require('./menu/menu'),
  MenuItem: require('./menu/menu-item'),
  Mixins: {
    Classable: require('./mixins/classable'),
    ClickAwayable: require('./mixins/click-awayable'),
    WindowListenable: require('./mixins/window-listenable'),
    StylePropable: require('./mixins/style-propable')
  },
  Paper: require('./paper'),
  RadioButton: require('./radio-button'),
  RadioButtonGroup: require('./radio-button-group'),
  RaisedButton: require('./raised-button'),
  Slider: require('./slider'),
  SvgIcon: require('./svg-icon'),
  Icons: {
    NavigationMenu: require('./svg-icons/navigation-menu'),
    NavigationChevronLeft: require('./svg-icons/navigation-chevron-left'),
    NavigationChevronRight: require('./svg-icons/navigation-chevron-right')
  },
  Styles: {
    AutoPrefix: require('./styles/auto-prefix'),
    Colors: require('./styles/colors'),
    Spacing: require('./styles/spacing'),
    ThemeManager: require('./styles/theme-manager'),
    Transitions: require('./styles/transitions'),
    Typography: require('./styles/typography')
  },
  Snackbar: require('./snackbar'),
  Tab: require('./tabs/tab'),
  Tabs: require('./tabs/tabs'),
  Toggle: require('./toggle'),
  TimePicker: require('./time-picker'),
  TextField: require('./text-field'),
  Toolbar: require('./toolbar/toolbar'),
  ToolbarGroup: require('./toolbar/toolbar-group'),
  ToolbarSeparator: require('./toolbar/toolbar-separator'),
  ToolbarTitle: require('./toolbar/toolbar-title'),
  Tooltip: require('./tooltip'),
  Utils: {
    CssEvent: require('./utils/css-event'),
    Dom: require('./utils/dom'),
    Events: require('./utils/events'),
    KeyCode: require('./utils/key-code'),
    KeyLine: require('./utils/key-line'),
    ColorManipulator: require('./utils/color-manipulator'),
    Extend: require('./utils/extend'),
    UniqueId: require('./utils/unique-id')
  }
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

const yargs = require('yargs');
const fs = require('fs');
const AWS = require('aws-sdk');

const logger = require('log4js').getLogger();

const argv = yargs
	.alias('s', 'server').describe('server', 'The address and port of the Kubernetes API server')
	.alias('cacert', 'certificate-authority').describe('certificate-authority', 'Path to a cert. file for the certificate authority')
	.alias('cert', 'client-certificate').describe('client-certificate', 'Path to a client certificate file for TLS')
	.alias('key', 'client-key').describe('client-key', 'Path to a client key file for TLS')
	.boolean('insecure-skip-tls-verify').describe('insecure-skip-tls-verify', 'If true, the server\'s certificate will not be checked for validity. This will make your HTTPS connections insecure')
	.describe('token', 'Bearer token for authentication to the API server')
	.describe('namespace', 'The namespace to watch')
	.help()
	.argv;

/** The basic configuration for accessing the API server */
let k8sConfig;
if (argv.server) {
	const fs = require('fs');

	k8sConfig = {
		url: argv.server,
		insecureSkipTlsVerify: argv.insecureSkipTlsVerify
	};
	if (argv.certificateAuthority) {
		k8sConfig.ca = fs.readFileSync(argv.certificateAuthority, 'utf8');
	}
	if (argv.token) {
		k8sConfig.auth = { bearer: argv.token };
	} else if (argv.username && argv.password) {
		k8sConfig.auth = { user: argv.username, pass: argv.password };
	} else if (argv.clientCertificate && argv.clientKey) {
		k8sConfig.cert = fs.readFileSync(argv.clientCertificate, 'utf8');
		k8sConfig.key = fs.readFileSync(argv.clientKey, 'utf8');
	}
} else if (process.env.KUBERNETES_SERVICE_HOST) {
	k8sConfig = {
		url: `https://${process.env.KUBERNETES_SERVICE_HOST}:${process.env.KUBERNETES_SERVICE_PORT}`,
		ca: fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt', 'utf8'),
		auth: { bearer: fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token', 'utf8') }
	}
} else {
	logger.error('Unknown Kubernetes API server');
	process.exit(1);
}

const k8s = require('auto-kubernetes-client');
const sqs = new AWS.SQS({
	endpoint: process.env.AWS_SQS_ENDPOINT_URL_OVERRIDE,
	region: process.env.AWS_REGION,
});

if (!argv.namespace) {
	// FIXME: How to do watching without namespace (i.e. "all namespaces")
	logger.error('Must provide a namespace using --namespace');
	process.exit(1);
}

k8s(k8sConfig).then(function(k8sClient) {
	const queues = k8sClient.group('aws.k8s.collaborne.com', 'v1').ns(argv.namespace).queues;

	/**
	 * Convert the queue.spec parts from camelCase to AWS CapitalCase.
	 *
	 * @param {Object} queue a queue definition
	 * @return {Object} the queue attributes
	 */
	function translateQueueAttributes(queue) {
		function capitalize(s) {
			return s[0].toUpperCase() + s.substring(1);
		}

		return Object.keys(queue.spec || {}).reduce((result, key) => {
			const value = queue.spec[key];
			let resultValue;
			switch (key) {
			case 'redrivePolicy':
			case 'policy':
				resultValue = JSON.stringify(value);
				break;
			default:
				// Convert to string
				resultValue = `${value}`;
				break;
			}
			logger.debug(`[${queue.metadata.name}]: Attribute ${key} = ${resultValue}`);

			result[capitalize(key)] = resultValue;
			return result;
		}, {});
	}

	function createQueue(queue) {
		return new Promise(function(resolve, reject) {
			function handleCreateQueueResponse(err, data) {
				if (err) {
					if (err.name === 'AWS.SimpleQueueService.QueueDeletedRecently') {
						// Schedule to retry the operation in 10s
						logger.info(`[${queue.metadata.name}]: Retrying for recently deleted queue`);
						return setTimeout(function() {
							return createQueue(queue).then(data => handleCreateQueueResponse(null, data), err => handleCreateQueueResponse(err, null));
						}, 10000);
					}
					return reject(err);
				}

				return resolve(data);
			}

			return sqs.createQueue({ QueueName: queue.metadata.name, Attributes: translateQueueAttributes(queue) }, handleCreateQueueResponse);
		});
	}

	function updateQueue(queue) {
		return new Promise(function(resolve, reject) {
			return sqs.getQueueUrl({ QueueName: queue.metadata.name }, function(err, data) {
				if (err) {
					return reject(err);
				}

				return sqs.setQueueAttributes({ QueueUrl: data.QueueUrl, Attributes: translateQueueAttributes(queue) }, function(err, data) {
					if (err) {
						return reject(err);
					}

					return resolve(data);
				});
			});
		});
	}

	function deleteQueue(queue) {
		return new Promise(function(resolve, reject) {
			return sqs.getQueueUrl({ QueueName: queue.metadata.name }, function(err, data) {
				if (err) {
					return reject(err);
				}

				return sqs.deleteQueue({ QueueUrl: data.QueueUrl }, function(err, data) {
					if (err) {
						return reject(err);
					}

					return resolve(data);
				});
			});
		});
	}

	function mainLoop() {
		// Highest version seen
		let resourceVersion = 0;

		// Known promises for queues, used to synchronize requests and avoid races between delayed creations and modifications.
		const queuePromises = {};

		logger.info(`Watching queues at ${resourceVersion}...`);
		const watch = queues.watch(resourceVersion)
			.on('data', function(item) {
				const queue = item.object;

				// Update the version: we've processed things until here now
				resourceVersion = queue.metadata.resourceVersion;
				const name = queue.metadata.name;

				// Enqueue the request to happen when the previous request is done.
				const previousPromise = queuePromises[name] || Promise.resolve();

				let result;

				switch (item.type) {
				case 'ADDED':
					result = previousPromise.then(function() {
						logger.info(`[${name}]: Creating queue`);
						return createQueue(queue);
					});
					break;
				case 'MODIFIED':
					result = previousPromise.then(function() {
						logger.info(`[${name}]: Updating queue attributes`);
						return updateQueue(queue);
					});
					break;
				case 'DELETED':
					result = previousPromise.then(function() {
						logger.info(`[${name}]: Deleting queue`);
						return deleteQueue(queue);
					});
					break;
				case 'ERROR':
					logger.error(`Error while watching: ${item.object.message}, restarting watch`);
					watch.close();
					return mainLoop();
				default:
					logger.warn(`Unkown watch event type ${item.type}, ignoring`);
					return;
				}

				result = result.then(function(data) {
					logger.info(`[${name}]: ${JSON.stringify(data)}`);
				}, function(err) {
					logger.error(`[${name}]: ${err.message} (${err.code})`);
				});

				// Note that we retain the 'rejected' state here: an existing queue that ended in a rejection
				// will effectively stay rejected.
				queuePromises[name] = result;

				return result;
			})
			.on('end', function() {
				// Restart the whole thing.
				logger.info('Watch ended, re-syncing everything');
				return mainLoop();
			});
	}

	// Start!
	mainLoop();
}).catch(function(err) {
	logger.error(`Uncaught error, aborting: ${err.message}`);
	process.exit(1);
});
<commit_msg>Ignore 'ERROR' updates<commit_after>#!/usr/bin/env node

'use strict';

const yargs = require('yargs');
const fs = require('fs');
const AWS = require('aws-sdk');

const logger = require('log4js').getLogger();

const argv = yargs
	.alias('s', 'server').describe('server', 'The address and port of the Kubernetes API server')
	.alias('cacert', 'certificate-authority').describe('certificate-authority', 'Path to a cert. file for the certificate authority')
	.alias('cert', 'client-certificate').describe('client-certificate', 'Path to a client certificate file for TLS')
	.alias('key', 'client-key').describe('client-key', 'Path to a client key file for TLS')
	.boolean('insecure-skip-tls-verify').describe('insecure-skip-tls-verify', 'If true, the server\'s certificate will not be checked for validity. This will make your HTTPS connections insecure')
	.describe('token', 'Bearer token for authentication to the API server')
	.describe('namespace', 'The namespace to watch')
	.help()
	.argv;

/** The basic configuration for accessing the API server */
let k8sConfig;
if (argv.server) {
	const fs = require('fs');

	k8sConfig = {
		url: argv.server,
		insecureSkipTlsVerify: argv.insecureSkipTlsVerify
	};
	if (argv.certificateAuthority) {
		k8sConfig.ca = fs.readFileSync(argv.certificateAuthority, 'utf8');
	}
	if (argv.token) {
		k8sConfig.auth = { bearer: argv.token };
	} else if (argv.username && argv.password) {
		k8sConfig.auth = { user: argv.username, pass: argv.password };
	} else if (argv.clientCertificate && argv.clientKey) {
		k8sConfig.cert = fs.readFileSync(argv.clientCertificate, 'utf8');
		k8sConfig.key = fs.readFileSync(argv.clientKey, 'utf8');
	}
} else if (process.env.KUBERNETES_SERVICE_HOST) {
	k8sConfig = {
		url: `https://${process.env.KUBERNETES_SERVICE_HOST}:${process.env.KUBERNETES_SERVICE_PORT}`,
		ca: fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt', 'utf8'),
		auth: { bearer: fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token', 'utf8') }
	}
} else {
	logger.error('Unknown Kubernetes API server');
	process.exit(1);
}

const k8s = require('auto-kubernetes-client');
const sqs = new AWS.SQS({
	endpoint: process.env.AWS_SQS_ENDPOINT_URL_OVERRIDE,
	region: process.env.AWS_REGION,
});

if (!argv.namespace) {
	// FIXME: How to do watching without namespace (i.e. "all namespaces")
	logger.error('Must provide a namespace using --namespace');
	process.exit(1);
}

k8s(k8sConfig).then(function(k8sClient) {
	const queues = k8sClient.group('aws.k8s.collaborne.com', 'v1').ns(argv.namespace).queues;

	/**
	 * Convert the queue.spec parts from camelCase to AWS CapitalCase.
	 *
	 * @param {Object} queue a queue definition
	 * @return {Object} the queue attributes
	 */
	function translateQueueAttributes(queue) {
		function capitalize(s) {
			return s[0].toUpperCase() + s.substring(1);
		}

		return Object.keys(queue.spec || {}).reduce((result, key) => {
			const value = queue.spec[key];
			let resultValue;
			switch (key) {
			case 'redrivePolicy':
			case 'policy':
				resultValue = JSON.stringify(value);
				break;
			default:
				// Convert to string
				resultValue = `${value}`;
				break;
			}
			logger.debug(`[${queue.metadata.name}]: Attribute ${key} = ${resultValue}`);

			result[capitalize(key)] = resultValue;
			return result;
		}, {});
	}

	function createQueue(queue) {
		return new Promise(function(resolve, reject) {
			function handleCreateQueueResponse(err, data) {
				if (err) {
					if (err.name === 'AWS.SimpleQueueService.QueueDeletedRecently') {
						// Schedule to retry the operation in 10s
						logger.info(`[${queue.metadata.name}]: Retrying for recently deleted queue`);
						return setTimeout(function() {
							return createQueue(queue).then(data => handleCreateQueueResponse(null, data), err => handleCreateQueueResponse(err, null));
						}, 10000);
					}
					return reject(err);
				}

				return resolve(data);
			}

			return sqs.createQueue({ QueueName: queue.metadata.name, Attributes: translateQueueAttributes(queue) }, handleCreateQueueResponse);
		});
	}

	function updateQueue(queue) {
		return new Promise(function(resolve, reject) {
			return sqs.getQueueUrl({ QueueName: queue.metadata.name }, function(err, data) {
				if (err) {
					return reject(err);
				}

				return sqs.setQueueAttributes({ QueueUrl: data.QueueUrl, Attributes: translateQueueAttributes(queue) }, function(err, data) {
					if (err) {
						return reject(err);
					}

					return resolve(data);
				});
			});
		});
	}

	function deleteQueue(queue) {
		return new Promise(function(resolve, reject) {
			return sqs.getQueueUrl({ QueueName: queue.metadata.name }, function(err, data) {
				if (err) {
					return reject(err);
				}

				return sqs.deleteQueue({ QueueUrl: data.QueueUrl }, function(err, data) {
					if (err) {
						return reject(err);
					}

					return resolve(data);
				});
			});
		});
	}

	function mainLoop() {
		// Highest version seen
		let resourceVersion = 0;

		// Known promises for queues, used to synchronize requests and avoid races between delayed creations and modifications.
		const queuePromises = {};

		logger.info(`Watching queues at ${resourceVersion}...`);
		const watch = queues.watch(resourceVersion)
			.on('data', function(item) {
				const queue = item.object;

				// Update the version: we've processed things until here now
				resourceVersion = queue.metadata.resourceVersion;
				const name = queue.metadata.name;

				// Enqueue the request to happen when the previous request is done.
				const previousPromise = queuePromises[name] || Promise.resolve();

				let result;

				switch (item.type) {
				case 'ADDED':
					result = previousPromise.then(function() {
						logger.info(`[${name}]: Creating queue`);
						return createQueue(queue);
					});
					break;
				case 'MODIFIED':
					result = previousPromise.then(function() {
						logger.info(`[${name}]: Updating queue attributes`);
						return updateQueue(queue);
					});
					break;
				case 'DELETED':
					result = previousPromise.then(function() {
						logger.info(`[${name}]: Deleting queue`);
						return deleteQueue(queue);
					});
					break;
				case 'ERROR':
					// Log the message, and continue: usually the stream would end now, but there might be more events
					// in it that we do want to consume.
					logger.warn(`Error while watching: ${item.object.message}, ignoring`);
					return;
				default:
					logger.warn(`Unkown watch event type ${item.type}, ignoring`);
					return;
				}

				result = result.then(function(data) {
					logger.info(`[${name}]: ${JSON.stringify(data)}`);
				}, function(err) {
					logger.error(`[${name}]: ${err.message} (${err.code})`);
				});

				// Note that we retain the 'rejected' state here: an existing queue that ended in a rejection
				// will effectively stay rejected.
				queuePromises[name] = result;

				return result;
			})
			.on('end', function() {
				// Restart the whole thing.
				logger.info('Watch ended, re-syncing everything');
				return mainLoop();
			});
	}

	// Start!
	mainLoop();
}).catch(function(err) {
	logger.error(`Uncaught error, aborting: ${err.message}`);
	process.exit(1);
});
<|endoftext|>


<commit_before>const got = require('got')
const cacheManager = require('cache-manager')
const querystring = require('querystring')
const pkg = require('../package.json')
const addSeconds = require('date-fns/add_seconds')
const isFuture = require('date-fns/is_future')
const deepAssign = require('deep-assign')

class Onionoo {

  // Constructor returns a new object so instance properties are private
  constructor (options = {}) {
    // Set default options
    this.options = Object.assign({}, {
      baseUrl: 'https://onionoo.torproject.org',
      endpoints: [
        'summary',
        'details',
        'bandwidth',
        'weights',
        'clients',
        'uptime'
      ]
    }, options)
    if (options.cache !== false) {
      this.options.cache = cacheManager.caching(Object.assign({}, {
        store: 'memory',
        max: 500
      }, options.cache))
    }

    // Return object containing endpoint methods
    return this.options.endpoints.reduce((onionoo, endpoint) => {
      onionoo[endpoint] = this.createEndpointMethod(endpoint)

      return onionoo
    }, {})
  }

  // Returns expirey date from response headers
  expires (headers) {
    const originDate = new Date(headers.date)

    // Get max age ms
    let maxAge = headers['cache-control'] && headers['cache-control'].match(/max-age=(\d+)/)
    maxAge = parseInt(maxAge ? maxAge[1] : 0)

    // Calculate expirey date
    return addSeconds(new Date(originDate), maxAge)
  }

  // Returns a function to make requests to a given endpoint
  createEndpointMethod (endpoint) {
    return options => {
      // Build query string (don't encode ':' for search filters)
      const qs = querystring.encode(options).replace(/%3A/g, ':')

      // Build url
      const url = `${this.options.baseUrl}/${endpoint}?${qs}`

      // If caching is enabled, check for url in cache
      if (this.options.cache) {
        return this.options.cache.get(url)
          .then(cachedResult => {
            let options = {}

            // If we have it cached
            if (cachedResult) {
              // Return the cached entry if it's still valid
              if (isFuture(this.expires(cachedResult.headers))) {
                return cachedResult

              // If it's stale, add last-modified date to headers
              } else {
                options.headers = {
                  'if-modified-since': cachedResult.headers['last-modified']
                }
              }
            }

            // Make a request
            return this.makeRequest(url, options)
              .then(response => {
                // If we get a 304, fill in the body
                if (response.statusCode === 304) {
                  response.body = cachedResult.body
                }

                //  If we get a 200 or 304, cache it
                if ([200, 304].includes(response.statusCode)) {
                  this.options.cache.set(url, response)
                }

                return response
              })
          })

      // If caching is disabled, just make the request
      } else {
        return this.makeRequest(url)
      }
    }
  }

  // Returns a promise for a request
  makeRequest (url, options = {}) {
    options = deepAssign({
      headers: {
        'user-agent': `onionoo-node-client v${pkg.version} (${pkg.homepage})`
      }
    }, options)

    return got(url, options)
      .catch(error => {
        // Don't throw 304 responses
        if (error.statusCode === 304) {
          return error.response
        } else {
          throw error
        }
      })
      .then(response => {
        // Format response
        response = {
          statusCode: response.statusCode,
          statusMessage: response.statusMessage,
          headers: response.headers,
          body: response.body && JSON.parse(response.body)
        }

        return response
      })
  }
}

module.exports = Onionoo
<commit_msg>Account for current age in cache calculations<commit_after>const got = require('got')
const cacheManager = require('cache-manager')
const querystring = require('querystring')
const pkg = require('../package.json')
const addSeconds = require('date-fns/add_seconds')
const isFuture = require('date-fns/is_future')
const deepAssign = require('deep-assign')

class Onionoo {

  // Constructor returns a new object so instance properties are private
  constructor (options = {}) {
    // Set default options
    this.options = Object.assign({}, {
      baseUrl: 'https://onionoo.torproject.org',
      endpoints: [
        'summary',
        'details',
        'bandwidth',
        'weights',
        'clients',
        'uptime'
      ]
    }, options)
    if (options.cache !== false) {
      this.options.cache = cacheManager.caching(Object.assign({}, {
        store: 'memory',
        max: 500
      }, options.cache))
    }

    // Return object containing endpoint methods
    return this.options.endpoints.reduce((onionoo, endpoint) => {
      onionoo[endpoint] = this.createEndpointMethod(endpoint)

      return onionoo
    }, {})
  }

  // Returns expirey date from response headers
  expires (headers) {
    const originDate = new Date(headers.date)

    // Get max age ms
    let maxAge = headers['cache-control'] && headers['cache-control'].match(/max-age=(\d+)/)
    maxAge = parseInt(maxAge ? maxAge[1] : 0)

    // Take current age into account
    if (headers.age) {
      maxAge -= headers.age
    }

    // Calculate expirey date
    return addSeconds(new Date(originDate), maxAge)
  }

  // Returns a function to make requests to a given endpoint
  createEndpointMethod (endpoint) {
    return options => {
      // Build query string (don't encode ':' for search filters)
      const qs = querystring.encode(options).replace(/%3A/g, ':')

      // Build url
      const url = `${this.options.baseUrl}/${endpoint}?${qs}`

      // If caching is enabled, check for url in cache
      if (this.options.cache) {
        return this.options.cache.get(url)
          .then(cachedResult => {
            let options = {}

            // If we have it cached
            if (cachedResult) {
              // Return the cached entry if it's still valid
              if (isFuture(this.expires(cachedResult.headers))) {
                return cachedResult

              // If it's stale, add last-modified date to headers
              } else {
                options.headers = {
                  'if-modified-since': cachedResult.headers['last-modified']
                }
              }
            }

            // Make a request
            return this.makeRequest(url, options)
              .then(response => {
                // If we get a 304, fill in the body
                if (response.statusCode === 304) {
                  response.body = cachedResult.body
                }

                //  If we get a 200 or 304, cache it
                if ([200, 304].includes(response.statusCode)) {
                  this.options.cache.set(url, response)
                }

                return response
              })
          })

      // If caching is disabled, just make the request
      } else {
        return this.makeRequest(url)
      }
    }
  }

  // Returns a promise for a request
  makeRequest (url, options = {}) {
    options = deepAssign({
      headers: {
        'user-agent': `onionoo-node-client v${pkg.version} (${pkg.homepage})`
      }
    }, options)

    return got(url, options)
      .catch(error => {
        // Don't throw 304 responses
        if (error.statusCode === 304) {
          return error.response
        } else {
          throw error
        }
      })
      .then(response => {
        // Format response
        response = {
          statusCode: response.statusCode,
          statusMessage: response.statusMessage,
          headers: response.headers,
          body: response.body && JSON.parse(response.body)
        }

        return response
      })
  }
}

module.exports = Onionoo
<|endoftext|>


<commit_before>const mailgun = require("mailgun-js");
const Attachment = require("mailgun-js/lib/attachment");
const consolidate = require("consolidate");
const packageData = require("../package.json");

const whitelist = [
  ["replyTo", "h:Reply-To"],
  ["messageId", "h:Message-Id"],
  [/^h:/],
  [/^v:/],
  ["from"],
  ["to"],
  ["cc"],
  ["bcc"],
  ["subject"],
  ["text"],
  ["template"],
  ["html"],
  ["attachment"],
  ["inline"],
  ["recipient-variables"],
  ["o:tag"],
  ["o:campaign"],
  ["o:dkim"],
  ["o:deliverytime"],
  ["o:testmode"],
  ["o:tracking"],
  ["o:tracking-clicks"],
  ["o:tracking-opens"],
  ["o:require-tls"],
  ["o:skip-verification"],
  ["X-Mailgun-Variables"]
];

const applyKeyWhitelist = mail =>
  Object.keys(mail).reduce((acc, key) => {
    const targetKey = whitelist.reduce((result, [cond, target]) => {
      if (result) {
        return result;
      }
      if ((cond.exec && cond.exec(key)) || cond === key) {
        return target || key;
      }
      return null;
    }, null);
    if (!targetKey || !mail[key]) {
      return acc;
    }
    return { ...acc, [targetKey]: mail[key] };
  }, {});

const renderTemplate = async template => {
  if (!template || !template.name || !template.engine) {
    return {};
  }
  const { engine, name, context = {} } = template;
  const html = await consolidate[engine](name, context);
  return { template: null, html };
};

const makeMailgunAttachments = (attachments = []) => {
  const [attachment, inline] = attachments.reduce(
    (results, item) => {
      const data =
        typeof item.content === "string"
          ? Buffer.from(item.content, item.encoding)
          : item.content || item.path || undefined;
      // mailgunjs does not encode content string to a buffer
      const attachment = new Attachment({
        data,
        filename: item.cid || item.filename || undefined,
        contentType: item.contentType || undefined,
        knownLength: item.knownLength || undefined
      });
      const [attachmentAttachments, inlineAttachments] = results;
      return [
        attachmentAttachments.concat(!item.cid ? attachment : []),
        inlineAttachments.concat(item.cid ? attachment : [])
      ];
    },
    [[], []]
  );
  return {
    ...(attachment.length ? { attachment } : {}),
    ...(inline.length ? { inline } : {})
  };
};

const makeAllTextAddresses = mail => {
  const keys = ["from", "to", "cc", "bcc", "replyTo"];
  const makeTextAddresses = addresses => {
    const validAddresses = [].concat(addresses).filter(Boolean);
    const textAddresses = validAddresses.map(item =>
      item.address
        ? item.name
          ? item.name + " <" + item.address + ">"
          : item.address
        : typeof item === "string"
        ? item
        : null
    );
    return textAddresses.filter(Boolean).join();
  };
  const result = keys.reduce((result, key) => {
    const textAddresses = makeTextAddresses(mail[key]);
    if (!textAddresses) {
      return result;
    }
    return { ...result, [key]: textAddresses };
  }, {});
  return result;
};

const send = mailgunSend => async ({ data: mail }, callback) => {
  try {
    const addresses = makeAllTextAddresses(mail);
    const attachments = makeMailgunAttachments(mail.attachments);
    const template = await renderTemplate(mail.template);
    const extendedMail = {
      ...mail,
      ...addresses,
      ...attachments,
      ...template
    };
    const whitelistedMail = applyKeyWhitelist(extendedMail);
    const result = await mailgunSend(whitelistedMail);
    callback(null, { ...result, messageId: result.id });
  } catch (error) {
    callback(error);
  }
};

const transport = (options = {}) => {
  const messages = mailgun({
    apiKey: options.auth.api_key,
    domain: options.auth.domain || "",
    proxy: options.proxy || false,
    host: options.host || "api.mailgun.net",
    protocol: options.protocol || "https:",
    port: options.port || 443
  }).messages();
  const mailgunSend = mail => messages.send(mail);
  return {
    name: "Mailgun",
    version: packageData.version,
    send: send(mailgunSend),
    messages,
    options
  };
};

transport._send = send;
transport._makeAllTextAddresses = makeAllTextAddresses;
transport._makeMailgunAttachments = makeMailgunAttachments;
transport._renderTemplate = renderTemplate;
transport._applyKeyWhitelist = applyKeyWhitelist;

module.exports = transport;
<commit_msg>support option auth.apiKey as alias of auth.api_key<commit_after>const mailgun = require("mailgun-js");
const Attachment = require("mailgun-js/lib/attachment");
const consolidate = require("consolidate");
const packageData = require("../package.json");

const whitelist = [
  ["replyTo", "h:Reply-To"],
  ["messageId", "h:Message-Id"],
  [/^h:/],
  [/^v:/],
  ["from"],
  ["to"],
  ["cc"],
  ["bcc"],
  ["subject"],
  ["text"],
  ["template"],
  ["html"],
  ["attachment"],
  ["inline"],
  ["recipient-variables"],
  ["o:tag"],
  ["o:campaign"],
  ["o:dkim"],
  ["o:deliverytime"],
  ["o:testmode"],
  ["o:tracking"],
  ["o:tracking-clicks"],
  ["o:tracking-opens"],
  ["o:require-tls"],
  ["o:skip-verification"],
  ["X-Mailgun-Variables"]
];

const applyKeyWhitelist = mail =>
  Object.keys(mail).reduce((acc, key) => {
    const targetKey = whitelist.reduce((result, [cond, target]) => {
      if (result) {
        return result;
      }
      if ((cond.exec && cond.exec(key)) || cond === key) {
        return target || key;
      }
      return null;
    }, null);
    if (!targetKey || !mail[key]) {
      return acc;
    }
    return { ...acc, [targetKey]: mail[key] };
  }, {});

const renderTemplate = async template => {
  if (!template || !template.name || !template.engine) {
    return {};
  }
  const { engine, name, context = {} } = template;
  const html = await consolidate[engine](name, context);
  return { template: null, html };
};

const makeMailgunAttachments = (attachments = []) => {
  const [attachment, inline] = attachments.reduce(
    (results, item) => {
      const data =
        typeof item.content === "string"
          ? Buffer.from(item.content, item.encoding)
          : item.content || item.path || undefined;
      // mailgunjs does not encode content string to a buffer
      const attachment = new Attachment({
        data,
        filename: item.cid || item.filename || undefined,
        contentType: item.contentType || undefined,
        knownLength: item.knownLength || undefined
      });
      const [attachmentAttachments, inlineAttachments] = results;
      return [
        attachmentAttachments.concat(!item.cid ? attachment : []),
        inlineAttachments.concat(item.cid ? attachment : [])
      ];
    },
    [[], []]
  );
  return {
    ...(attachment.length ? { attachment } : {}),
    ...(inline.length ? { inline } : {})
  };
};

const makeAllTextAddresses = mail => {
  const keys = ["from", "to", "cc", "bcc", "replyTo"];
  const makeTextAddresses = addresses => {
    const validAddresses = [].concat(addresses).filter(Boolean);
    const textAddresses = validAddresses.map(item =>
      item.address
        ? item.name
          ? item.name + " <" + item.address + ">"
          : item.address
        : typeof item === "string"
        ? item
        : null
    );
    return textAddresses.filter(Boolean).join();
  };
  const result = keys.reduce((result, key) => {
    const textAddresses = makeTextAddresses(mail[key]);
    if (!textAddresses) {
      return result;
    }
    return { ...result, [key]: textAddresses };
  }, {});
  return result;
};

const send = mailgunSend => async ({ data: mail }, callback) => {
  try {
    const addresses = makeAllTextAddresses(mail);
    const attachments = makeMailgunAttachments(mail.attachments);
    const template = await renderTemplate(mail.template);
    const extendedMail = {
      ...mail,
      ...addresses,
      ...attachments,
      ...template
    };
    const whitelistedMail = applyKeyWhitelist(extendedMail);
    const result = await mailgunSend(whitelistedMail);
    callback(null, { ...result, messageId: result.id });
  } catch (error) {
    callback(error);
  }
};

const transport = (options = {}) => {
  const messages = mailgun({
    apiKey: options.auth.api_key || options.auth.apiKey,
    domain: options.auth.domain || "",
    proxy: options.proxy || false,
    host: options.host || "api.mailgun.net",
    protocol: options.protocol || "https:",
    port: options.port || 443
  }).messages();
  const mailgunSend = mail => messages.send(mail);
  return {
    name: "Mailgun",
    version: packageData.version,
    send: send(mailgunSend),
    messages,
    options
  };
};

transport._send = send;
transport._makeAllTextAddresses = makeAllTextAddresses;
transport._makeMailgunAttachments = makeMailgunAttachments;
transport._renderTemplate = renderTemplate;
transport._applyKeyWhitelist = applyKeyWhitelist;

module.exports = transport;
<|endoftext|>


<commit_before>'use strict';

class Keyv {
	constructor(opts) {
		opts = opts || {};
		this.store = opts.store || new Map();
	}

	get(key) {
		return Promise.resolve(this.store.get(key)).then(data => {
			if (!data) {
				return undefined;
			}
			if (!this.store.ttlSupport && Date.now() > data.expires) {
				this.delete(key);
				return undefined;
			}
			return this.store.ttlSupport ? data : data.value;
		});
	}

	set(key, value, ttl) {
		let set;
		if (this.store.ttlSupport) {
			set = this.store.set(key, value, ttl);
		} else {
			const expires = (typeof ttl === 'number') ? (Date.now() + ttl) : undefined;
			const data = { value, expires };
			set = this.store.set(key, data);
		}
		return Promise.resolve(set).then(() => value);
	}

	delete(key) {
		return Promise.resolve(this.store.delete(key));
	}
}

module.exports = Keyv;
<commit_msg>Save all opts in this.opts<commit_after>'use strict';

class Keyv {
	constructor(opts) {
		this.opts = opts || {};
		this.opts.store = this.opts.store || new Map();
	}

	get(key) {
		return Promise.resolve(this.opts.store.get(key)).then(data => {
			if (!data) {
				return undefined;
			}
			if (!this.opts.store.ttlSupport && Date.now() > data.expires) {
				this.delete(key);
				return undefined;
			}
			return this.opts.store.ttlSupport ? data : data.value;
		});
	}

	set(key, value, ttl) {
		let set;
		if (this.opts.store.ttlSupport) {
			set = this.opts.store.set(key, value, ttl);
		} else {
			const expires = (typeof ttl === 'number') ? (Date.now() + ttl) : undefined;
			const data = { value, expires };
			set = this.opts.store.set(key, data);
		}
		return Promise.resolve(set).then(() => value);
	}

	delete(key) {
		return Promise.resolve(this.opts.store.delete(key));
	}
}

module.exports = Keyv;
<|endoftext|>


<commit_before>const Discord = require("discord.js");
const key = require("../key");
const botAllCommandRegister = require("./botAllCommandRegister");

const state = {
  commands: new Set()
};

const client = new Discord.Client();
client.on("ready", () => {
  console.log("I am ready!");
});

client.on("message", message => {
  for (const cmd of state.commands) {
    if (cmd.test(message.content, message)) {
      cmd.run(message, client);
    }
  }
});

client.on("guildMemberAdd", member => {
  const channel = member.guild.channels.find("name", "member-log");
  if (!channel) return;
  channel.send(`Welcome to the server, ${member}`);
});

botAllCommandRegister(state, client);
client.login(key);
<commit_msg>add update status<commit_after>const Discord = require("discord.js");
const key = require("../key");
const botAllCommandRegister = require("./botAllCommandRegister");

const state = {
  commands: new Set()
};

const client = new Discord.Client();
client.on("ready", () => {
  client.user.setGame("Бота");
  console.log("I am ready!");
});

client.on("message", message => {
  for (const cmd of state.commands) {
    if (cmd.test(message.content, message)) {
      cmd.run(message, client);
    }
  }
});

client.on("guildMemberAdd", member => {
  const channel = member.guild.channels.find("name", "member-log");
  if (!channel) return;
  channel.send(`Welcome to the server, ${member}`);
});

process.on("exit", () => {
  client.user.setGame("Обновляюсь");
});

botAllCommandRegister(state, client);
client.login(key);
<|endoftext|>