<commit_before>(function(Backbone) {
    var init = function(trigger, triggerEvents) {

    // backbone-events-promises
    // ========================
    //
    // This plugin to [backbone.js](http://backbonejs.org/) can add
    // promise functionality to Backbone.Events (and any Backbone
    // object which extends Backbone.Events - which is pretty much
    // all of them).
    //
    // Why?
    // ----
    //
    // You fire an event and need to make sure all event listeners
    // have finished their async calls before you do something destructive
    // like change the browser location.
    //
    // Dependencies
    // ------------
    // It implements promises by using `$.Deferred` and `$.when` either. This can be
    // provided via [jQuery](http://jquery.org) or [Zepto](http://zeptojs.com/) (requires
    // including Zepto's deferred plugin). Potentially, other
    // sources such as when.js could be used if a shim was provided to
    // apply it's functions to `$.Deferred` and `$.when`.
    //
    // It also depends on `_.extend()`. Underscore is already a hard dependency of Backbone,
    // so no harm done there.
    //
    // Backwards Breaking Changes
    // --------------------------
    // The only thing that happens by default here is setting
    // `Backbone.Events.promises()`.
    //
    // Backbone.Events.promises(enable, [context], [options]);
    // --------------------------------------------
    // Enables the backbone-promises functionality for events.

        Backbone.Events.promises = function(enable, context, options) {

            // The biggest change that happens after enabling backbone-promises
            // is that `Backbone.Events.trigger()` will return a promise. This means if
            // you are chaining a method after calling `trigger()` in your code
            // (ex. `.trigger(event).somethingElse()`), it will cause a fatal error and break.
            // However, backbone-promises can be configured to use a different method name
            // than `.trigger()` if you can think of a better name that won't cause
            // conflicts in your application.

            var method;
            if (enable === undefined) {
                enable = true;
            }
            options = options || {};
            options = _.extend({
                method: "trigger"
            }, options);
            method = options.method;

            // You can pass a context in the second parameter which will
            // apply the backbone-promises functionality to that object.
            // By default, the context is `Backbone.Events`.

            if (!context) {
                context = Backbone.Events;
            }

            // Additionally, the original functionality can
            // be restored by using `Backbone.Events.promises(false, [context])`.
            // backbone-promises also reserves use of `context._promises` to store configuration data.
            // Currently, it is used to store the original version of the trigger function.

            if (!enable) {
                if (!context._promises) {
                    return;
                }
                if (!context._promises.original) {
                    return;
                }
                method = context._promises.method;
                context[method] = context._promises.original;
                delete context._promises;
                return context;
            }

            if (enable) {
                if (context._promises) {
                    return;
                }
                context._promises = _.extend(options, {
                    original: context[method]
                });
                context[method] = trigger;
            }
        };
    },

    // Usage
    // -----

    // To enable on all Backbone objects, use the following code before creating
    // any Backbone objects in your application.
    //     var objs = ['Model', 'Collection', 'Router', 'View', 'History'];
    //     Backbone.Events.promises(true);
    //     for (var i = 0, l = objs.length; i < l; i++) {
    //         Backbone.Events.promises(true, Backbone[objs[i]].prototype);
    //     }

    // // Backbone.Events.trigger now returns a promise
    // var promise = Backbone.Events.trigger( "event name", arg1, arg2 );

    // // Each callback assigned to the event *can* return a promise.
    // // If a promise is returned, it will be added to the list of promises to resolve.
    // http://api.jquery.com/jQuery.when/

    // Under The Hood
    // --------------

    // Here we are modifying the `Backbone.Event.trigger()` method and we also
    // have to copy several private functions and aliases from the Backbone source
    // code. See annotated source over here: http://backbonejs.org/docs/backbone.html.
    // It should be exactly the same as the original version except it returns
    // a promise.
    // The promise object is the result of a `$.when()` call. The arguments to
    // `$.when are callbacks returning the results of each event listener.
    // See [api.jquery.com/jQuery.when/](http://api.jquery.com/jQuery.when/).

    array = [],
    push = array.push,
    slice = array.slice,
    splice = array.splice,
    eventSplitter = /\s+/,
    eventsApi = function(obj, action, name, rest) {
        if (!name) {
            return true;
        }
        if (typeof name === 'object') {
            for (var key in name) {
                obj[action].apply(obj, [key, name[key]].concat(rest));
            }
            return false;
        }
        if (eventSplitter.test(name)) {
            var names = name.split(eventSplitter);
            for (var i = 0, l = names.length; i < l; i++) {
                obj[action].apply(obj, [names[i]].concat(rest));
            }
            return false;
        }
        return true;
    },
    trigger = function(name) {
        if (!this._events) {
            return $.when();
        }
        var args = slice.call(arguments, 1);
        if (!eventsApi(this, 'trigger', name, args)) {
            return $.when();
        }
        var events = this._events[name];
        var allEvents = this._events.all;
        if (events) {
            return triggerEvents(events, args);
        }
        if (allEvents) {
            return triggerEvents(allEvents, arguments);
        }
        return $.when();
    },

    // We attempted to follow Backbone's lead here with
    // optimizing the manner to call event listeners. The idea is that
    // javascript's `call()` method is faster
    // than `apply` and most events are called with only a few arguments.
    //
    // This is where we differ from Backbone and create an
    // array of callback which is sent to `$.when()`.

    triggerEvents = function(events, args) {
        var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2], cbs = [];
        switch (args.length) {
        case 0:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx));
            }
            break;
        case 1:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1));
            }
            break;
        case 2:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1, a2));
            }
            break;
        case 3:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1, a2, a3));
            }
            break;
        default:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.apply(ev.ctx, args));
            }
            break;
        }
        return $.when.apply($, cbs);
    };

    init(trigger, triggerEvents);

})(Backbone);
<commit_msg>More documentation updates<commit_after>(function(Backbone) {
    var init = function(trigger, triggerEvents) {

    // backbone-events-promises
    // ========================
    //
    // This plugin to [backbone.js](http://backbonejs.org/) can add
    // promise functionality to Backbone.Events (and any Backbone
    // object which extends Backbone.Events - which is pretty much
    // all of them).
    //
    // Why?
    // ----
    //
    // You trigger an event and need to make sure all event listeners
    // have finished their async calls before you do something destructive
    // like change the browser location.
    //
    // Dependencies
    // ------------
    // It implements promises by using `$.Deferred` and `$.when` either. This can be
    // provided via [jQuery](http://jquery.org) or [Zepto](http://zeptojs.com/) (requires
    // including Zepto's deferred plugin). Potentially, other
    // sources such as when.js could be used if a shim was provided to
    // apply it's functions to `$.Deferred` and `$.when`.
    //
    // It also depends on `_.extend()`. Underscore is already a hard dependency of Backbone,
    // so no harm done there.
    //
    // Backwards Breaking Changes
    // --------------------------
    // The only thing that happens by default here is setting
    // `Backbone.Events.promises()`.
    //
    // Backbone.Events.promises(enable, [context], [options]);
    // --------------------------------------------
    // Enables the backbone-promises functionality for events.

        Backbone.Events.promises = function(enable, context, options) {

            // The biggest change that happens after enabling backbone-promises
            // is that `Backbone.Events.trigger()` will return a promise. This means if
            // you are chaining a method after calling `trigger()` in your code
            // (ex. `.trigger(event).somethingElse()`), it will cause a fatal error and break.
            // However, backbone-promises can be configured to use a different method name
            // than `.trigger()` if you can think of a better name that won't cause
            // conflicts in your application.

            var method;
            if (enable === undefined) {
                enable = true;
            }
            options = options || {};
            options = _.extend({
                method: "trigger"
            }, options);
            method = options.method;

            // You can pass a context in the second parameter which will
            // apply the backbone-promises functionality to that object.
            // By default, the context is `Backbone.Events`.

            if (!context) {
                context = Backbone.Events;
            }

            // Additionally, the original functionality can
            // be restored by using `Backbone.Events.promises(false, [context])`.
            // backbone-promises also reserves use of `context._promises` to store configuration data.
            // Currently, it is used to store the original version of the trigger function.

            if (!enable) {
                if (!context._promises) {
                    return;
                }
                if (!context._promises.original) {
                    return;
                }
                method = context._promises.method;
                context[method] = context._promises.original;
                delete context._promises;
                return context;
            }

            if (enable) {
                if (context._promises) {
                    return;
                }
                context._promises = _.extend(options, {
                    original: context[method]
                });
                context[method] = trigger;
            }
        };
    },

    // Usage
    // -----
    //
    // To enable on all Backbone objects, use the following code before creating
    // any Backbone objects in your application.
    //
    //     var objs = ['Model', 'Collection', 'Router', 'View', 'History'];
    //     Backbone.Events.promises(true);
    //     for (var i = 0, l = objs.length; i < l; i++) {
    //         Backbone.Events.promises(true, Backbone[objs[i]].prototype);
    //     }
    //
    // Backbone.Events.trigger() now returns a promise
    //
    //     var promise = Backbone.Events.trigger( "event name", arg1, arg2, ... );
    ///
    // Each event listener *can* return a promise. It is optional.
    // If a promise is returned from the event listener's callback,
    // it will be added to the list of promises to resolve before
    // resolving the promise returned by Backbone.Events.trigger.
    //
    // If your event listener has multiple async calls to make,
    // you can use http://api.jquery.com/jQuery.when/ to coordinate them.

    // Under The Hood
    // --------------
    //
    // Here we are modifying the `Backbone.Event.trigger()` method and we also
    // have to copy several private functions and aliases from the Backbone source
    // code. See annotated source over here: http://backbonejs.org/docs/backbone.html.
    // It should be exactly the same as the original version except it returns
    // a promise.
    // The promise object is the result of a `$.when()` call. The arguments to
    // `$.when are callbacks returning the results of each event listener.
    // See [api.jquery.com/jQuery.when/](http://api.jquery.com/jQuery.when/).

    array = [],
    push = array.push,
    slice = array.slice,
    splice = array.splice,
    eventSplitter = /\s+/,
    eventsApi = function(obj, action, name, rest) {
        if (!name) {
            return true;
        }
        if (typeof name === 'object') {
            for (var key in name) {
                obj[action].apply(obj, [key, name[key]].concat(rest));
            }
            return false;
        }
        if (eventSplitter.test(name)) {
            var names = name.split(eventSplitter);
            for (var i = 0, l = names.length; i < l; i++) {
                obj[action].apply(obj, [names[i]].concat(rest));
            }
            return false;
        }
        return true;
    },
    trigger = function(name) {
        if (!this._events) {
            return $.when();
        }
        var args = slice.call(arguments, 1);
        if (!eventsApi(this, 'trigger', name, args)) {
            return $.when();
        }
        var events = this._events[name];
        var allEvents = this._events.all;
        if (events) {
            return triggerEvents(events, args);
        }
        if (allEvents) {
            return triggerEvents(allEvents, arguments);
        }
        return $.when();
    },

    // We attempted to follow Backbone's lead here with
    // optimizing the manner to call event listeners. The idea is that
    // javascript's `call()` method is faster
    // than `apply` and most events are called with only a few arguments.
    //
    // This is where we differ from Backbone and create an
    // array of callback which is sent to `$.when()`.

    triggerEvents = function(events, args) {
        var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2], cbs = [];
        switch (args.length) {
        case 0:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx));
            }
            break;
        case 1:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1));
            }
            break;
        case 2:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1, a2));
            }
            break;
        case 3:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.call(ev.ctx, a1, a2, a3));
            }
            break;
        default:
            while (++i < l) {
                cbs.push((ev = events[i]).callback.apply(ev.ctx, args));
            }
            break;
        }
        return $.when.apply($, cbs);
    };

    init(trigger, triggerEvents);

})(Backbone);
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 */
'use strict';

const blacklist = require('metro-bundler/src/blacklist');
const findSymlinksPaths = require('./findSymlinksPaths');
const fs = require('fs');
const getPolyfills = require('../../rn-get-polyfills');
const invariant = require('fbjs/lib/invariant');
const path = require('path');

const {providesModuleNodeModules} = require('metro-bundler/src/defaults');

const RN_CLI_CONFIG = 'rn-cli.config.js';

import type {
  GetTransformOptions,
  PostMinifyProcess,
  PostProcessModules,
  PostProcessBundleSourcemap
} from 'metro-bundler/src/Bundler';
import type {HasteImpl} from 'metro-bundler/src/node-haste/Module';
import type {TransformVariants} from 'metro-bundler/src/ModuleGraph/types.flow';
import type {PostProcessModules as PostProcessModulesForBuck} from 'metro-bundler/src/ModuleGraph/types.flow.js';

/**
 * Configuration file of the CLI.
 */
export type ConfigT = {
  extraNodeModules: {[id: string]: string},
  /**
   * Specify any additional asset file extensions to be used by the packager.
   * For example, if you want to include a .ttf file, you would return ['ttf']
   * from here and use `require('./fonts/example.ttf')` inside your app.
   */
  getAssetExts: () => Array<string>,

  /**
   * Returns a regular expression for modules that should be ignored by the
   * packager on a given platform.
   */
  getBlacklistRE(): RegExp,

  /**
   * Specify whether or not to enable Babel's behavior for looking up .babelrc
   * files. If false, only the .babelrc file (if one exists) in the main project
   * root is used.
   */
  getEnableBabelRCLookup(): boolean,

  /**
   * Specify any additional polyfill modules that should be processed
   * before regular module loading.
   */
  getPolyfillModuleNames: () => Array<string>,

  /**
   * Specify any additional platforms to be used by the packager.
   * For example, if you want to add a "custom" platform, and use modules
   * ending in .custom.js, you would return ['custom'] here.
   */
  getPlatforms: () => Array<string>,

  getProjectRoots(): Array<string>,

  /**
   * Specify any additional node modules that should be processed for
   * providesModule declarations.
   */
  getProvidesModuleNodeModules?: () => Array<string>,

  /**
   * Specify any additional source file extensions to be used by the packager.
   * For example, if you want to include a .ts file, you would return ['ts']
   * from here and use `require('./module/example')` to require the file with
   * path 'module/example.ts' inside your app.
   */
  getSourceExts: () => Array<string>,

  /**
   * Returns the path to a custom transformer. This can also be overridden
   * with the --transformer commandline argument.
   */
  getTransformModulePath: () => string,
  getTransformOptions: GetTransformOptions,

  /**
   * Returns the path to the worker that is used for transformation.
   */
  getWorkerPath: () => ?string,

  /**
   * An optional list of polyfills to include in the bundle. The list defaults
   * to a set of common polyfills for Number, String, Array, Object...
   */
  getPolyfills: ({platform: ?string}) => $ReadOnlyArray<string>,

  /**
   * An optional function that can modify the code and source map of bundle
   * after the minifaction took place. (Function applied per module).
   */
  postMinifyProcess: PostMinifyProcess,

  /**
   * An optional function that can modify the module array before the bundle is
   * finalized.
   */
  postProcessModules: PostProcessModules,

  /**
   * An optional function that can modify the code and source map of the bundle
   * before it is written. Applied once for the entire bundle, only works if
   * output is a plainBundle.
   */
  postProcessBundleSourcemap: PostProcessBundleSourcemap,

  /**
   * Same as `postProcessModules` but for the Buck worker. Eventually we do want
   * to unify both variants.
   */
  postProcessModulesForBuck: PostProcessModulesForBuck,

  /**
   * A module that exports:
   * - a `getHasteName(filePath)` method that returns `hasteName` for module at
   *  `filePath`, or undefined if `filePath` is not a haste module.
   */
  hasteImpl?: HasteImpl,

  transformVariants: () => TransformVariants,
};

function getProjectPath() {
  if (__dirname.match(/node_modules[\/\\]react-native[\/\\]local-cli[\/\\]util$/)) {
    // Packager is running from node_modules.
    // This is the default case for all projects created using 'react-native init'.
    return path.resolve(__dirname, '../../../..');
  } else if (__dirname.match(/Pods[\/\\]React[\/\\]packager$/)) {
    // React Native was installed using CocoaPods.
    return path.resolve(__dirname, '../../../..');
  }
  return path.resolve(__dirname, '../..');
}

const resolveSymlink = (roots) =>
  roots.concat(
    findSymlinksPaths(
      path.join(getProjectPath(), 'node_modules'),
      roots
    )
  );

/**
 * Module capable of getting the configuration out of a given file.
 *
 * The function will return all the default configuration, as specified by the
 * `DEFAULTS` param overriden by those found on `rn-cli.config.js` files, if any. If no
 * default config is provided and no configuration can be found in the directory
 * hierarchy, an error will be thrown.
 */
const Config = {
  DEFAULTS: ({
    extraNodeModules: Object.create(null),
    getAssetExts: () => [],
    getBlacklistRE: () => blacklist(),
    getEnableBabelRCLookup: () => true,
    getPlatforms: () => [],
    getPolyfillModuleNames: () => [],
    getProjectRoots: () => {
      const root = process.env.REACT_NATIVE_APP_ROOT;
      if (root) {
        return resolveSymlink([path.resolve(root)]);
      }
      return resolveSymlink([getProjectPath()]);
    },
    getProvidesModuleNodeModules: () => providesModuleNodeModules.slice(),
    getSourceExts: () => [],
    getTransformModulePath: () => require.resolve('metro-bundler/src/transformer.js'),
    getTransformOptions: async () => ({}),
    getPolyfills,
    postMinifyProcess: x => x,
    postProcessModules: modules => modules,
    postProcessModulesForBuck: modules => modules,
    postProcessBundleSourcemap: ({code, map, outFileName}) => ({code, map}),
    transformVariants: () => ({default: {}}),
    getWorkerPath: () => null,
  }: ConfigT),

  find(startDir: string): ConfigT {
    return Config.findCustom(startDir, Config.DEFAULTS);
  },

  /**
   * This allows a callsite to grab a config that may have custom fields or
   * a different version of the config. In that case the defaults have to be
   * specified explicitely.
   */
  findCustom<TConfig: {}>(startDir: string, defaults: TConfig): TConfig {
    return Config.findWithPathCustom(startDir, defaults).config;
  },

  findWithPath(startDir: string): {config: ConfigT, projectPath: string} {
    return Config.findWithPathCustom(startDir, Config.DEFAULTS);
  },

  findWithPathCustom<TConfig: {}>(startDir: string, defaults: TConfig): {config: TConfig, projectPath: string} {
    const configPath = findConfigPath(startDir);
    invariant(
      configPath,
      `Can't find "${RN_CLI_CONFIG}" file in any parent folder of "${startDir}"`,
    );
    const projectPath = path.dirname(configPath);
    return {config: Config.loadFileCustom(configPath, defaults), projectPath};
  },

  findOptional(startDir: string): ConfigT {
    return Config.findOptionalCustom(startDir, Config.DEFAULTS);
  },

  findOptionalCustom<TConfig: {}>(startDir: string, defaults: TConfig): TConfig {
    const configPath = findConfigPath(startDir);
    return configPath
      ? Config.loadFileCustom(configPath, defaults)
      : {...defaults};
  },

  loadFile(pathToConfig: string): ConfigT {
    return Config.loadFileCustom(pathToConfig, Config.DEFAULTS);
  },

  loadFileCustom<TConfig: {}>(pathToConfig: string, defaults: TConfig): TConfig {
    // $FlowFixMe: necessary dynamic require
    const config: {} = require(pathToConfig);
    return {...defaults, ...config};
  },
};

function findConfigPath(cwd: string): ?string {
  const parentDir = findParentDirectory(cwd, RN_CLI_CONFIG);
  return parentDir ? path.join(parentDir, RN_CLI_CONFIG) : null;
}

// Finds the most near ancestor starting at `currentFullPath` that has
// a file named `filename`
function findParentDirectory(currentFullPath, filename) {
  const root = path.parse(currentFullPath).root;
  const testDir = (parts) => {
    if (parts.length === 0) {
      return null;
    }

    const fullPath = path.join(root, parts.join(path.sep));

    var exists = fs.existsSync(path.join(fullPath, filename));
    return exists ? fullPath : testDir(parts.slice(0, -1));
  };

  return testDir(currentFullPath.substring(root.length).split(path.sep));
}

module.exports = Config;
<commit_msg>Remove typed option loading<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 */
'use strict';

const blacklist = require('metro-bundler/src/blacklist');
const findSymlinksPaths = require('./findSymlinksPaths');
const fs = require('fs');
const getPolyfills = require('../../rn-get-polyfills');
const invariant = require('fbjs/lib/invariant');
const path = require('path');

const {providesModuleNodeModules} = require('metro-bundler/src/defaults');

const RN_CLI_CONFIG = 'rn-cli.config.js';

import type {
  GetTransformOptions,
  PostMinifyProcess,
  PostProcessModules,
  PostProcessBundleSourcemap
} from 'metro-bundler/src/Bundler';
import type {HasteImpl} from 'metro-bundler/src/node-haste/Module';
import type {TransformVariants} from 'metro-bundler/src/ModuleGraph/types.flow';
import type {PostProcessModules as PostProcessModulesForBuck} from 'metro-bundler/src/ModuleGraph/types.flow.js';

/**
 * Configuration file of the CLI.
 */
export type ConfigT = {
  extraNodeModules: {[id: string]: string},
  /**
   * Specify any additional asset file extensions to be used by the packager.
   * For example, if you want to include a .ttf file, you would return ['ttf']
   * from here and use `require('./fonts/example.ttf')` inside your app.
   */
  getAssetExts: () => Array<string>,

  /**
   * Returns a regular expression for modules that should be ignored by the
   * packager on a given platform.
   */
  getBlacklistRE(): RegExp,

  /**
   * Specify whether or not to enable Babel's behavior for looking up .babelrc
   * files. If false, only the .babelrc file (if one exists) in the main project
   * root is used.
   */
  getEnableBabelRCLookup(): boolean,

  /**
   * Specify any additional polyfill modules that should be processed
   * before regular module loading.
   */
  getPolyfillModuleNames: () => Array<string>,

  /**
   * Specify any additional platforms to be used by the packager.
   * For example, if you want to add a "custom" platform, and use modules
   * ending in .custom.js, you would return ['custom'] here.
   */
  getPlatforms: () => Array<string>,

  getProjectRoots(): Array<string>,

  /**
   * Specify any additional node modules that should be processed for
   * providesModule declarations.
   */
  getProvidesModuleNodeModules?: () => Array<string>,

  /**
   * Specify any additional source file extensions to be used by the packager.
   * For example, if you want to include a .ts file, you would return ['ts']
   * from here and use `require('./module/example')` to require the file with
   * path 'module/example.ts' inside your app.
   */
  getSourceExts: () => Array<string>,

  /**
   * Returns the path to a custom transformer. This can also be overridden
   * with the --transformer commandline argument.
   */
  getTransformModulePath: () => string,
  getTransformOptions: GetTransformOptions,

  /**
   * Returns the path to the worker that is used for transformation.
   */
  getWorkerPath: () => ?string,

  /**
   * An optional list of polyfills to include in the bundle. The list defaults
   * to a set of common polyfills for Number, String, Array, Object...
   */
  getPolyfills: ({platform: ?string}) => $ReadOnlyArray<string>,

  /**
   * An optional function that can modify the code and source map of bundle
   * after the minifaction took place. (Function applied per module).
   */
  postMinifyProcess: PostMinifyProcess,

  /**
   * An optional function that can modify the module array before the bundle is
   * finalized.
   */
  postProcessModules: PostProcessModules,

  /**
   * An optional function that can modify the code and source map of the bundle
   * before it is written. Applied once for the entire bundle, only works if
   * output is a plainBundle.
   */
  postProcessBundleSourcemap: PostProcessBundleSourcemap,

  /**
   * Same as `postProcessModules` but for the Buck worker. Eventually we do want
   * to unify both variants.
   */
  postProcessModulesForBuck: PostProcessModulesForBuck,

  /**
   * A module that exports:
   * - a `getHasteName(filePath)` method that returns `hasteName` for module at
   *  `filePath`, or undefined if `filePath` is not a haste module.
   */
  hasteImpl?: HasteImpl,

  transformVariants: () => TransformVariants,
};

function getProjectPath() {
  if (__dirname.match(/node_modules[\/\\]react-native[\/\\]local-cli[\/\\]util$/)) {
    // Packager is running from node_modules.
    // This is the default case for all projects created using 'react-native init'.
    return path.resolve(__dirname, '../../../..');
  } else if (__dirname.match(/Pods[\/\\]React[\/\\]packager$/)) {
    // React Native was installed using CocoaPods.
    return path.resolve(__dirname, '../../../..');
  }
  return path.resolve(__dirname, '../..');
}

const resolveSymlink = (roots) =>
  roots.concat(
    findSymlinksPaths(
      path.join(getProjectPath(), 'node_modules'),
      roots
    )
  );

/**
 * Module capable of getting the configuration out of a given file.
 *
 * The function will return all the default configuration, as specified by the
 * `DEFAULTS` param overriden by those found on `rn-cli.config.js` files, if any. If no
 * default config is provided and no configuration can be found in the directory
 * hierarchy, an error will be thrown.
 */
const Config = {
  DEFAULTS: ({
    extraNodeModules: Object.create(null),
    getAssetExts: () => [],
    getBlacklistRE: () => blacklist(),
    getEnableBabelRCLookup: () => true,
    getPlatforms: () => [],
    getPolyfillModuleNames: () => [],
    getProjectRoots: () => {
      const root = process.env.REACT_NATIVE_APP_ROOT;
      if (root) {
        return resolveSymlink([path.resolve(root)]);
      }
      return resolveSymlink([getProjectPath()]);
    },
    getProvidesModuleNodeModules: () => providesModuleNodeModules.slice(),
    getSourceExts: () => [],
    getTransformModulePath: () => require.resolve('metro-bundler/src/transformer.js'),
    getTransformOptions: async () => ({}),
    getPolyfills,
    postMinifyProcess: x => x,
    postProcessModules: modules => modules,
    postProcessModulesForBuck: modules => modules,
    postProcessBundleSourcemap: ({code, map, outFileName}) => ({code, map}),
    transformVariants: () => ({default: {}}),
    getWorkerPath: () => null,
  }: ConfigT),

  find(startDir: string): ConfigT {
    return this.findWithPath(startDir).config;
  },

  findWithPath(startDir: string): {config: ConfigT, projectPath: string} {
    const configPath = findConfigPath(startDir);
    invariant(
      configPath,
      `Can't find "${RN_CLI_CONFIG}" file in any parent folder of "${startDir}"`,
    );
    const projectPath = path.dirname(configPath);
    return {config: this.loadFile(configPath, startDir), projectPath};
  },

  findOptional(startDir: string): ConfigT {
    const configPath = findConfigPath(startDir);
    return configPath
      ? this.loadFile(configPath, startDir)
      : {...Config.DEFAULTS};
  },

  loadFile(pathToConfig: string): ConfigT {
    //$FlowFixMe: necessary dynamic require
    const config: {} = require(pathToConfig);
    return {...Config.DEFAULTS, ...config};
  },
};

function findConfigPath(cwd: string): ?string {
  const parentDir = findParentDirectory(cwd, RN_CLI_CONFIG);
  return parentDir ? path.join(parentDir, RN_CLI_CONFIG) : null;
}

// Finds the most near ancestor starting at `currentFullPath` that has
// a file named `filename`
function findParentDirectory(currentFullPath, filename) {
  const root = path.parse(currentFullPath).root;
  const testDir = (parts) => {
    if (parts.length === 0) {
      return null;
    }

    const fullPath = path.join(root, parts.join(path.sep));

    var exists = fs.existsSync(path.join(fullPath, filename));
    return exists ? fullPath : testDir(parts.slice(0, -1));
  };

  return testDir(currentFullPath.substring(root.length).split(path.sep));
}

module.exports = Config;
<|endoftext|>


<commit_before>/**
 * Clock Window
 */
var WARNING_IMAGE_WIDTH = 19;

// UI components
var _window, _imageViews, _clockLabel, _emergencyView, _emergencyClockLabel;

var _helper;
var _imageSwitchCounter;
var _isEmergencyMode;

function ClockWindow() {
	_imageSwitchCounter = 0;
	_isEmergencyMode = false;

	// build view
	_buildView();

	// Add event listener to view components and etc...
	_window.addEventListener('swipe', _toggleEmergencyMode);
	Ti.Gesture.addEventListener('orientationchange', _adjustEmergencyModeWhenRotate);

	// create helper
	var toHelper = {
		setClock: _setClock,
		setImage: _setImage,
	};
	_helper = new (require('/app/views/helpers/ClockWindowHelper'))(toHelper);

	return _window;
}

function _buildView() {
	// Window
	_window = Ti.UI.createWindow({
		fullscreen: true,
		orientationModes: [Ti.UI.PORTRAIT, Ti.UI.UPSIDE_PORTRAIT, Ti.UI.LANDSCAPE_LEFT, Ti.UI.LANDSCAPE_RIGHT],
	});

	// Image container
	var imageViewContainer = Ti.UI.createView({
		top: 0,
		left: 0,
		width: '100%',
		height: '100%',
	});

	// Image views
	_imageViews = [];
	for (var i = 0; i < 2; i++) {
		_imageViews.push(Ti.UI.createImageView({
			width: '100%',
			height: '100%',
			backgroundColor: '#000000',
			opacity: 0,
		}));
	}
	imageViewContainer.add(_imageViews[0]);
	imageViewContainer.add(_imageViews[1]);

	// Header
	var header = Ti.UI.createView({
		width: '100%',
		height: 'auto',
		top: 0,
		backgroundColor: '#000000',
		opacity: 0.45,
	});
	_clockLabel = Ti.UI.createLabel({
		text: '',
		textAlign: 'center',
		width: '100%',
		height: 'auto',
		color: '#FFFFFF',
		font: { fontWeight: 'bold', fontSize: 32 },
		opacity: 1,
	});
	header.add(_clockLabel);
	imageViewContainer.add(header);

	_window.add(imageViewContainer);

	// Emergency view
	_emergencyView = Ti.UI.createView({
		top: 0,
		left: -9999,
		width: Ti.Platform.displayCaps.getPlatformWidth() + WARNING_IMAGE_WIDTH * 2,
		height: Ti.Platform.displayCaps.getPlatformHeight(),
		backgroundColor: '#000000',
	});
	_emergencyClockLabel = Ti.UI.createLabel({
		text: '',
		textAlign: 'center',
		top: 0,
		width: Ti.Platform.displayCaps.getPlatformWidth(),
		height: Ti.Platform.displayCaps.getPlatformHeight(),
		color: '#FFFFFF',
		font: { fontWeight: 'bold', fontSize: 72 },
		opacity: 0.35,
	});
	var warningImage1 = Ti.UI.createImageView({
		image: '/images/warning.png',
		width: WARNING_IMAGE_WIDTH,
		height: 1024,
		left: 0,
	});
	var warningImage2 = Ti.UI.createImageView({
		image: '/images/warning.png',
		width: WARNING_IMAGE_WIDTH,
		height: 1024,
		right: 0,
	});
	_emergencyView.add(_emergencyClockLabel);
	_emergencyView.add(warningImage1);
	_emergencyView.add(warningImage2);

	_window.add(_emergencyView);
}

// Call by helper
function _setClock(clockString) {
	_clockLabel.setText(clockString);
	_emergencyClockLabel.setText(clockString);
}

// Call by helper
function _setImage(imageFilePath) {
	// Detect which image view is currently showing
	var currentImageView = _imageViews[_imageSwitchCounter % 2];
	_imageSwitchCounter++;
	var nextImageView = _imageViews[_imageSwitchCounter % 2];

	nextImageView.setImage(imageFilePath);

	// Change image animation
	currentImageView.animate({ opacity: 0, duration: 750 });
	nextImageView.animate({ opacity: 1, duration: 750 });
}

function _toggleEmergencyMode(event) {
	// Stop animation
	_emergencyView.animate();

	if (_isEmergencyMode) {
		// To normal mode
		if (event.direction === 'left') {
			_emergencyView.animate({ left: 0 - (Ti.Platform.displayCaps.getPlatformWidth() + WARNING_IMAGE_WIDTH * 2), duration: 200 });
		} else {
			_emergencyView.animate({ left: Ti.Platform.displayCaps.getPlatformWidth(), duration: 200 });
		}
	} else {
		// To emergency mode
		if (event.direction === 'left') {
			_emergencyView.left = Ti.Platform.displayCaps.getPlatformWidth();
		} else {
			_emergencyView.left = 0 - (Ti.Platform.displayCaps.getPlatformWidth() + WARNING_IMAGE_WIDTH * 2);
		}
		_emergencyView.animate({ left: 0 - WARNING_IMAGE_WIDTH, duration: 200 });
	}
	_isEmergencyMode = !_isEmergencyMode;
}

function _adjustEmergencyModeWhenRotate(event) {
	_emergencyView.width = Ti.Platform.displayCaps.getPlatformWidth() + WARNING_IMAGE_WIDTH * 2;
	_emergencyView.height = Ti.Platform.displayCaps.getPlatformHeight();
	_emergencyClockLabel.height = Ti.Platform.displayCaps.getPlatformHeight();
	if (!_isEmergencyMode) {
		_emergencyView.left = -9999;
	}
}

// Export
module.exports = ClockWindow;
<commit_msg>Add toolbar<commit_after>/**
 * Clock Window
 */
var WARNING_IMAGE_WIDTH = 19;

// UI components
var _window, _imageViews, _clockLabel, _hooter, _emergencyView, _emergencyClockLabel;

var _helper;
var _imageSwitchCounter;
var _isEmergencyMode;
var _isShowingToolbar;

function ClockWindow() {
	_imageSwitchCounter = 0;
	_isEmergencyMode = false;
	_isShowingToolbar = false;

	// build view
	_buildView();

	// Add event listener to view components and etc...
	_window.addEventListener('swipe', _toggleEmergencyMode);
	_window.addEventListener('singletap', _toggleToolBar);
	Ti.Gesture.addEventListener('orientationchange', _adjustEmergencyModeWhenRotate);

	// create helper
	var toHelper = {
		setClock: _setClock,
		setImage: _setImage,
	};
	_helper = new (require('/app/views/helpers/ClockWindowHelper'))(toHelper);

	return _window;
}

function _buildView() {
	// Window
	_window = Ti.UI.createWindow({
		fullscreen: true,
		orientationModes: [Ti.UI.PORTRAIT, Ti.UI.UPSIDE_PORTRAIT, Ti.UI.LANDSCAPE_LEFT, Ti.UI.LANDSCAPE_RIGHT],
	});

	// Image container
	var imageViewContainer = Ti.UI.createView({
		top: 0,
		left: 0,
		width: '100%',
		height: '100%',
	});

	// Image views
	_imageViews = [];
	for (var i = 0; i < 2; i++) {
		_imageViews.push(Ti.UI.createImageView({
			width: '100%',
			height: '100%',
			backgroundColor: '#000000',
			opacity: 0,
		}));
	}
	imageViewContainer.add(_imageViews[0]);
	imageViewContainer.add(_imageViews[1]);

	// Header
	var header = Ti.UI.createView({
		width: '100%',
		height: 'auto',
		top: 0,
		backgroundColor: '#000000',
		opacity: 0.45,
	});
	_clockLabel = Ti.UI.createLabel({
		text: '',
		textAlign: 'center',
		width: '100%',
		height: 'auto',
		color: '#FFFFFF',
		font: { fontWeight: 'bold', fontSize: 32 },
		opacity: 1,
	});
	header.add(_clockLabel);
	imageViewContainer.add(header);

	_window.add(imageViewContainer);

	// Hooter
	var actionButton = Ti.UI.createButton({
		systemButton: Ti.UI.iPhone.SystemButton.ACTION,
	});
	var spacer = Ti.UI.createButton({
		systemButton: Ti.UI.iPhone.SystemButton.FLEXIBLE_SPACE,
	});
	var infoButton = Ti.UI.createButton({
		systemButton: Ti.UI.iPhone.SystemButton.INFO_LIGHT,
	});

	_hooter = Ti.UI.iOS.createToolbar({
		items: [actionButton, spacer, infoButton],
		bottom: -9999,
		borderTop: false,
		borderBottom: false,
		translucent: true,
		opacity: 0.6,
		barColor: '#000000',
    });
	_hooter.bottom = 0 - _hooter.height;

	_window.add(_hooter);

	// Emergency view
	_emergencyView = Ti.UI.createView({
		top: 0,
		left: -9999,
		width: Ti.Platform.displayCaps.getPlatformWidth() + WARNING_IMAGE_WIDTH * 2,
		height: Ti.Platform.displayCaps.getPlatformHeight(),
		backgroundColor: '#000000',
	});
	_emergencyClockLabel = Ti.UI.createLabel({
		text: '',
		textAlign: 'center',
		top: 0,
		width: Ti.Platform.displayCaps.getPlatformWidth(),
		height: Ti.Platform.displayCaps.getPlatformHeight(),
		color: '#FFFFFF',
		font: { fontWeight: 'bold', fontSize: 72 },
		opacity: 0.35,
	});
	var warningImage1 = Ti.UI.createImageView({
		image: '/images/warning.png',
		width: WARNING_IMAGE_WIDTH,
		height: 1024,
		left: 0,
	});
	var warningImage2 = Ti.UI.createImageView({
		image: '/images/warning.png',
		width: WARNING_IMAGE_WIDTH,
		height: 1024,
		right: 0,
	});
	_emergencyView.add(_emergencyClockLabel);
	_emergencyView.add(warningImage1);
	_emergencyView.add(warningImage2);

	_window.add(_emergencyView);
}

// Call by helper
function _setClock(clockString) {
	_clockLabel.setText(clockString);
	_emergencyClockLabel.setText(clockString);
}

// Call by helper
function _setImage(imageFilePath) {
	// Detect which image view is currently showing
	var currentImageView = _imageViews[_imageSwitchCounter % 2];
	_imageSwitchCounter++;
	var nextImageView = _imageViews[_imageSwitchCounter % 2];

	nextImageView.setImage(imageFilePath);

	// Change image animation
	currentImageView.animate({ opacity: 0, duration: 750 });
	nextImageView.animate({ opacity: 1, duration: 750 });
}

function _toggleEmergencyMode(event) {
	// Stop animation
	_emergencyView.animate();

	if (_isEmergencyMode) {
		// To normal mode
		if (event.direction === 'left') {
			_emergencyView.animate({ left: 0 - (Ti.Platform.displayCaps.getPlatformWidth() + WARNING_IMAGE_WIDTH * 2), duration: 200 });
		} else {
			_emergencyView.animate({ left: Ti.Platform.displayCaps.getPlatformWidth(), duration: 200 });
		}
	} else {
		// To emergency mode
		if (event.direction === 'left') {
			_emergencyView.left = Ti.Platform.displayCaps.getPlatformWidth();
		} else {
			_emergencyView.left = 0 - (Ti.Platform.displayCaps.getPlatformWidth() + WARNING_IMAGE_WIDTH * 2);
		}
		_emergencyView.animate({ left: 0 - WARNING_IMAGE_WIDTH, duration: 200 });
	}
	_isEmergencyMode = !_isEmergencyMode;
}

function _toggleToolBar(event) {
	if (_isShowingToolbar) {
		_hooter.animate({ bottom: 0 - _hooter.height, duration: 500 });
	} else {
		_hooter.animate({ bottom: 0, duration: 500 });
	}
	_isShowingToolbar = !_isShowingToolbar;
}

function _adjustEmergencyModeWhenRotate(event) {
	_emergencyView.width = Ti.Platform.displayCaps.getPlatformWidth() + WARNING_IMAGE_WIDTH * 2;
	_emergencyView.height = Ti.Platform.displayCaps.getPlatformHeight();
	_emergencyClockLabel.height = Ti.Platform.displayCaps.getPlatformHeight();
	if (!_isEmergencyMode) {
		_emergencyView.left = -9999;
	}
}

// Export
module.exports = ClockWindow;
<|endoftext|>


<commit_before>$(function () {
  'use strict'

  $('[data-toggle="offcanvas"]').on('click', function () {
    $('.offcanvas-collapse').toggleClass('open')
  })
})
<commit_msg>Convert offcanvas.js to vanilla JS.<commit_after>(function () {
  'use strict'

  document.querySelector('[data-toggle="offcanvas"]').addEventListener('click', function () {
    document.querySelector('.offcanvas-collapse').classList.toggle('open')
  })
}())
<|endoftext|>


<commit_before>class GameOfLife {

    constructor () {
        this.grid = {}
        this.offsets = [-1, 0, 1]
    }

    setAlive (coords) {
       this.grid[coords] = true
    }

    isAlive (coords) {
        return Boolean(this.grid[coords])
    }

    nextFrame () {

        let newGrid = {}

        for (let coords of this.getAliveCoords()) {
            newGrid[coords] = this.getNextState(coords)
        }

        this.grid = newGrid

    }

    *getAliveCoords () {
        for (let coordsStr of Object.keys(this.grid)) {
            yield this.getCoordsFromStr(coordsStr)
        }
    }

    getCoordsFromStr (str) {
        return str.split(',').map(coord => parseInt(coord))
    }

    getNextState (coords) {
        if (this.getAmountAliveNeighbours(coords) > 2) {
            return true
        }
    }

    getAmountAliveNeighbours (coords) {

        let amount = 0

        for (let neighbourCoords of this.getNeighbourCoords(coords)) {
            amount += +this.isAlive(neighbourCoords)
        }

        return amount

    }

    *getNeighbourCoords (coords) {
        for (let [xOffset, yOffset] of this.getAllOffsets()) {
            yield [
                coords[0] + xOffset,
                coords[1] + yOffset
            ]
        }
    }

    *getAllOffsets () {
        for (let xOffset of this.offsets) {
            for (let yOffset of this.offsets) {
                yield [xOffset, yOffset]
            }
        }
    }

}
<commit_msg>refactored<commit_after>class GameOfLife {

    constructor () {
        this.grid = {}
        this.offsets = [-1, 0, 1]
    }

    setAlive (coords) {
       this.grid[coords] = true
    }

    isAlive (coords) {
        return Boolean(this.grid[coords])
    }

    nextFrame () {

        let newGrid = {}

        for (let coords of this.getAliveCoords()) {
            newGrid[coords] = this.getNextState(coords)
        }

        this.grid = newGrid

    }

    *getAliveCoords () {
        for (let coordsStr of Object.keys(this.grid)) {
            yield this.getCoordsFromStr(coordsStr)
        }
    }

    getCoordsFromStr (str) {
        return str.split(',').map(coord => parseInt(coord))
    }

    getNextState (coords) {
        if (this.getAmountAliveNeighbours(coords) > 2) {
            return true
        }
    }

    getAmountAliveNeighbours (coords) {

        let amount = 0

        for (let neighbourCoords of this.getNeighbourCoords(coords)) {
            amount += +this.isAlive(neighbourCoords)
        }

        return amount

    }

    *getNeighbourCoords (coords) {
        for (let [xOffset, yOffset] of this.getNeighbourOffsets()) {
            yield [
                coords[0] + xOffset,
                coords[1] + yOffset
            ]
        }
    }

    *getNeighbourOffsets () {
        for (let xOffset of this.offsets) {
            for (let yOffset of this.offsets) {
                yield [xOffset, yOffset]
            }
        }
    }

}
<|endoftext|>


<commit_before>// @flow
import * as React from 'react'
import {Box2, Icon, Text, FloatingPicker} from '../../../../common-adapters/mobile.native'
import {globalColors, globalMargins, styleSheetCreate} from '../../../../styles'
import type {Props} from '.'

const Announcement = () => (
  <Box2 direction="vertical" fullWidth={true} style={styles.announcementContainer}>
    <Icon
      type="iconfont-boom"
      color={globalColors.white}
      fontSize={64}
      style={{marginTop: -10, marginBottom: -10}}
    />
    <Text type="BodySmallSemibold" backgroundMode="Announcements" style={styles.headline}>
      Set a timeout on your messages and watch them
    </Text>
    <Text type="BodySmallSemibold" backgroundMode="Announcements" style={styles.headline}>
      E   X   P   L   O   D   E.
    </Text>
    <Text
      type="BodySmallSemiboldPrimaryLink"
      backgroundMode="Announcements"
      className="underline"
      onClickURL="https://keybase.io/blog/keybase-exploding-messages"
    >
      Learn more
    </Text>
  </Box2>
)

const styles = styleSheetCreate({
  announcementContainer: {
    alignItems: 'center',
    backgroundColor: globalColors.blue,
    padding: globalMargins.small,
    paddingBottom: globalMargins.small,
  },
  headline: {
    paddingLeft: globalMargins.medium,
    paddingRight: globalMargins.medium,
    flexGrow: 1,
    textAlign: 'center',
  },
})

const Prompt = () => (
  <Box2 direction="horizontal" fullWidth={true} gap="xtiny" style={promptContainerStyle}>
    <Text type="BodySmallSemibold">Explode messages after:</Text>
  </Box2>
)

const promptContainerStyle = {
  alignItems: 'center',
  justifyContent: 'center',
}

type State = {selected: number}
class SetExplodePopup extends React.Component<Props, State> {
  state = {selected: 0}

  static getDerivedStateFromProps(nextProps: Props, prevState: State) {
    return {selected: nextProps.selected || 0}
  }

  setSelected = (value: number | string) => {
    if (typeof value === 'string') {
      // never happens. makes flow happy.
      return
    }
    this.setState({selected: value})
  }

  onDone = () => {
    this.props.onSelect(this.state.selected)
    this.props.onHidden()
  }

  render() {
    const items = this.props.items.map(item => ({label: item.text, value: item.seconds}))
    return (
      <FloatingPicker
        header={this.props.isNew ? <Announcement /> : null}
        items={items}
        onSelect={this.setSelected}
        onHidden={this.props.onHidden}
        onCancel={this.props.onHidden}
        onDone={this.onDone}
        prompt={<Prompt />}
        promptString="Pick a timeout"
        visible={this.props.visible}
        selectedValue={this.state.selected}
      />
    )
  }
}

export default SetExplodePopup
<commit_msg>fix getDerivedState (#12560)<commit_after>// @flow
import * as React from 'react'
import {Box2, Icon, Text, FloatingPicker} from '../../../../common-adapters/mobile.native'
import {globalColors, globalMargins, styleSheetCreate} from '../../../../styles'
import type {Props} from '.'

const Announcement = () => (
  <Box2 direction="vertical" fullWidth={true} style={styles.announcementContainer}>
    <Icon
      type="iconfont-boom"
      color={globalColors.white}
      fontSize={64}
      style={{marginTop: -10, marginBottom: -10}}
    />
    <Text type="BodySmallSemibold" backgroundMode="Announcements" style={styles.headline}>
      Set a timeout on your messages and watch them
    </Text>
    <Text type="BodySmallSemibold" backgroundMode="Announcements" style={styles.headline}>
      E   X   P   L   O   D   E.
    </Text>
    <Text
      type="BodySmallSemiboldPrimaryLink"
      backgroundMode="Announcements"
      className="underline"
      onClickURL="https://keybase.io/blog/keybase-exploding-messages"
    >
      Learn more
    </Text>
  </Box2>
)

const styles = styleSheetCreate({
  announcementContainer: {
    alignItems: 'center',
    backgroundColor: globalColors.blue,
    padding: globalMargins.small,
    paddingBottom: globalMargins.small,
  },
  headline: {
    paddingLeft: globalMargins.medium,
    paddingRight: globalMargins.medium,
    flexGrow: 1,
    textAlign: 'center',
  },
})

const Prompt = () => (
  <Box2 direction="horizontal" fullWidth={true} gap="xtiny" style={promptContainerStyle}>
    <Text type="BodySmallSemibold">Explode messages after:</Text>
  </Box2>
)

const promptContainerStyle = {
  alignItems: 'center',
  justifyContent: 'center',
}

type State = {selected: number}
class SetExplodePopup extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props)
    this.state = {selected: props.selected || 0}
  }

  componentDidUpdate(prevProps: Props) {
    if (this.props.selected !== prevProps.selected) {
      this.setState({selected: this.props.selected || 0})
    }
  }

  setSelected = (value: number | string) => {
    if (typeof value === 'string') {
      // never happens. makes flow happy.
      return
    }
    this.setState({selected: value})
  }

  onDone = () => {
    this.props.onSelect(this.state.selected)
    this.props.onHidden()
  }

  render() {
    const items = this.props.items.map(item => ({label: item.text, value: item.seconds}))
    return (
      <FloatingPicker
        header={this.props.isNew ? <Announcement /> : null}
        items={items}
        onSelect={this.setSelected}
        onHidden={this.props.onHidden}
        onCancel={this.props.onHidden}
        onDone={this.onDone}
        prompt={<Prompt />}
        promptString="Pick a timeout"
        visible={this.props.visible}
        selectedValue={this.state.selected}
      />
    )
  }
}

export default SetExplodePopup
<|endoftext|>


<commit_before>/*
 Uninstallation Listener Library

 Usage:
   new window['piro.sakura.ne.jp'].UninstallationListener({
     id : 'test@exmaple.com',
     onuninstalled : function() { ... },
     ondisabled : function() { ... }
   });

 license: The MIT License, Copyright (c) 2009-2011 YUKI "Piro" Hiroshi
 original:
   http://github.com/piroor/fxaddonlib-uninstallation-listener
*/

/* To work as a JS Code Module  */
if (typeof window == 'undefined' ||
	(window && typeof window.constructor == 'function')) {
	this.EXPORTED_SYMBOLS = ['UninstallationListener'];

	// If namespace.jsm is available, export symbols to the shared namespace.
	// See: http://github.com/piroor/fxaddonlibs/blob/master/namespace.jsm
	try {
		let ns = {};
		Components.utils.import('resource://my-modules/namespace.jsm', ns);
		/* var */ window = ns.getNamespaceFor('piro.sakura.ne.jp');
	}
	catch(e) {
		window = {};
	}
}

(function() {
	const currentRevision = 2;

	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};

	var loadedRevision = 'UninstallationListener' in window['piro.sakura.ne.jp'] ?
			window['piro.sakura.ne.jp'].UninstallationListener.prototype.revision :
			0 ;
	if (loadedRevision && loadedRevision > currentRevision) {
		return;
	}

	const Cc = Components.classes;
	const Ci = Components.interfaces;

	const ObserverService = Cc['@mozilla.org/observer-service;1']
							.getService(Ci.nsIObserverService);

	var AddonManager;
	try {
		let ns = {};
		Components.utils.import('resource://gre/modules/AddonManager.jsm', ns);
		AddonManager = ns.AddonManager;
	}
	catch(e) {
	}

	window['piro.sakura.ne.jp'].UninstallationListener = function(aArguments) {
		this.init(aArguments);
	};
	window['piro.sakura.ne.jp'].UninstallationListener.prototype = {
		revision : currentRevision,

		// for Firefox 3.6 or older
		observe : function(aSubject, aTopic, aData)
		{
			switch (aTopic)
			{
				case 'em-action-requested':
					switch (aData)
					{
						case 'item-uninstalled':
							if (this.isTargetExtension(aSubject))
								this.toBeUninstalled = true;
							break;
						case 'item-cancel-action':
							if (this.isTargetExtension(aSubject)) {
								this.toBeUninstalled = false;
								this.toBeDisabled = false;
							}
							break;
						case 'item-disabled':
							if (this.isTargetExtension(aSubject))
								this.toBeDisabled = true;
							break;
						case 'item-enabled':
							if (this.isTargetExtension(aSubject))
								this.toBeDisabled = false;
							break;
					}
					return;

				case 'quit-application-granted':
					this.destroy();
					return;
			}
		},
		isTargetExtension : function(aSubject)
		{
			return (aSubject instanceof Ci.nsIUpdateItem) && (aSubject.id == this.id);
		},

		// for Firefox 4 or later
		onEnabling : function(aAddon, aRestartRequired) {},
		onEnabled : function(aAddon) {},
		onDisabling : function(aAddon, aRestartRequired) {
			if (aAddon.id == this.id) {
				this.toBeDisabled = true;
			}
		},
		onDisabled : function(aAddon)
		{
			if (aAddon.id == this.id) {
				if (this.ondisabled) this.ondisabled();
				delete this.ondisabled;
			}
		},
		onInstalling : function(aAddon, aRestartRequired) {},
		onInstalled : function(aAddon) {},
		onUninstalling : function(aAddon, aRestartRequired) {
			if (aAddon.id == this.id) {
				this.toBeUninstalled = true;
			}
		},
		onUninstalled : function(aAddon)
		{
			if (aAddon.id == this.id) {
				if (this.onuninstalled) this.onuninstalled();
				delete this.onuninstalled;
			}
		},
		onOperationCancelled : function(aAddon)
		{
			if (aAddon.id == this.id) {
				this.toBeDisabled = false;
				this.toBeUninstalled = false;
			}
		},
		onPropertyChanged : function(aAddon, aProperties) {},

		init : function(aArguments)
		{
			if (!aArguments) return;

			this.id = (typeof aArguments == 'string') ? aArguments : aArguments.id ;

			this.toBeUninstalled = false;
			this.toBeDisabled = false;
			if (typeof aArguments == 'object') {
				this.onuninstalled = aArguments.onuninstalled;
				this.ondisabled = aArguments.ondisabled;
			}

			if (AddonManager) { // Firefox 4 or later
				AddonManager.addAddonListener(this);
			}
			else {
				ObserverService.addObserver(this, 'em-action-requested', false);
			}
			ObserverService.addObserver(this, 'quit-application-granted', false);
		},

		destroy : function()
		{
			if (this.toBeUninstalled && this.onuninstalled)
				this.onuninstalled();
			delete this.onuninstalled;

			if (this.toBeDisabled && this.ondisabled)
				this.ondisabled();
			delete this.ondisabled;

			if (AddonManager) { // Firefox 4 or later
				AddonManager.removeAddonListener(this);
			}
			else {
				ObserverService.removeObserver(this, 'em-action-requested');
			}
			ObserverService.removeObserver(this, 'quit-application-granted');
		}
	};
})();

if (window != this) { // work as a JS Code Module
	this.UninstallationListener = window['piro.sakura.ne.jp'].UninstallationListener;
}
<commit_msg>Simplify: drop support for too old Firefox/Thunderbird<commit_after>/**
 * @fileOverview Uninstallation Listener Library
 * @author       YUKI "Piro" Hiroshi
 * @version      3
 *
 * @license
 *   The MIT License, Copyright (c) 2009-2016 YUKI "Piro" Hiroshi.
 *   https://github.com/piroor/fxaddonlib-uninstallation-listener/blob/master/license.txt
 * @url https://github.com/piroor/fxaddonlib-uninstallation-listener
 *
 * Usage:
 *   new UninstallationListener({
 *     id : 'test@exmaple.com',
 *    onuninstalled : function() { ... },
 *     ondisabled : function() { ... }
 *   });
 */

var EXPORTED_SYMBOLS = ['UninstallationListener'];

	const Cc = Components.classes;
	const Ci = Components.interfaces;

	const ObserverService = Cc['@mozilla.org/observer-service;1']
							.getService(Ci.nsIObserverService);

	var { AddonManager } = Components.utils.import('resource://gre/modules/AddonManager.jsm', {});

	var UninstallationListener = function(aArguments) {
		this.init(aArguments);
	};
	UninstallationListener.prototype = {
		onEnabling : function(aAddon, aRestartRequired) {},
		onEnabled : function(aAddon) {},
		onDisabling : function(aAddon, aRestartRequired) {
			if (aAddon.id == this.id) {
				this.toBeDisabled = true;
			}
		},
		onDisabled : function(aAddon)
		{
			if (aAddon.id == this.id) {
				if (this.ondisabled) this.ondisabled();
				delete this.ondisabled;
			}
		},
		onInstalling : function(aAddon, aRestartRequired) {},
		onInstalled : function(aAddon) {},
		onUninstalling : function(aAddon, aRestartRequired) {
			if (aAddon.id == this.id) {
				this.toBeUninstalled = true;
			}
		},
		onUninstalled : function(aAddon)
		{
			if (aAddon.id == this.id) {
				if (this.onuninstalled) this.onuninstalled();
				delete this.onuninstalled;
			}
		},
		onOperationCancelled : function(aAddon)
		{
			if (aAddon.id == this.id) {
				this.toBeDisabled = false;
				this.toBeUninstalled = false;
			}
		},
		onPropertyChanged : function(aAddon, aProperties) {},

		init : function(aArguments)
		{
			if (!aArguments) return;

			this.id = (typeof aArguments == 'string') ? aArguments : aArguments.id ;

			this.toBeUninstalled = false;
			this.toBeDisabled = false;
			if (typeof aArguments == 'object') {
				this.onuninstalled = aArguments.onuninstalled;
				this.ondisabled = aArguments.ondisabled;
			}

			AddonManager.addAddonListener(this);
			ObserverService.addObserver(this, 'quit-application-granted', false);
		},

		destroy : function()
		{
			if (this.toBeUninstalled && this.onuninstalled)
				this.onuninstalled();
			delete this.onuninstalled;

			if (this.toBeDisabled && this.ondisabled)
				this.ondisabled();
			delete this.ondisabled;

			AddonManager.removeAddonListener(this);
			ObserverService.removeObserver(this, 'quit-application-granted');
		}
	};
<|endoftext|>


<commit_before>/*
 Copyright 2019 - 2019 by Jan Dockx

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

/* eslint-env mocha */

'use strict'

const Contract = require('../lib/IV/Contract')
const cases = require('./_cases')

const contract = new Contract({ pre: [cases.intentionallyFailingFunction] })

describe('mocha this', function () {
  before(function () {
    this.subject = contract.implementation(function () {})
  })

  it('works when a precondition violation occurs when a function is called with a mocha fixture as this', function () {
    this.subject()
  })
})
<commit_msg>note observations<commit_after>/*
 Copyright 2019 - 2019 by Jan Dockx

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

/* eslint-env mocha */

'use strict'

const Contract = require('../lib/IV/Contract')
const cases = require('./_cases')

const contract = new Contract({ pre: [cases.intentionallyFailingFunction] })

describe('mocha this', function () {
  before(function () {
    this.subject = contract.implementation(function () {})
  })

  it('works when a precondition violation occurs when a function is called with a mocha fixture as this', function () {
    this.subject()
  })
})

/* Mocha Context has ctx.customInspect = true
 * The problem is in
 * node_modules/mocha/lib/runnable.js, line 231:
 *
 * /**
 *  * Inspect the runnable void of private properties.
 *  *
 *  * @private
 *  * @return {string}
 *  *-
 *  Runnable.prototype.inspect = function() {
 *    return JSON.stringify(
 *      this,
 *      function(key, val) {
 *        if (key[0] === '_') {
 *          return;
 *        }
 *        if (key === 'parent') {
 *          return '#<Suite>';
 *        }
 *        if (key === 'ctx') {
 *          return '#<Context>';
 *        }
 *        return val;
 *      },
 *      2
 *    );
 *  };
 *
 * `this ` still contains circular structures, apart from what the replacer handles.
 * this.ctx.test === this, but that should be handled by the replacer
 * this.parent.ctx.test === this, but that should be handled by the replacer
 *
 * There seems to be nothing else that can make this happen, except for `this.intellij_test_node`. This seems to be
 * added on by IntelliJ. It is obviously not handled by Mocha itself. This structure has internal loops:
 * this.intellij_test_node.parent.children[0] === this.intellij_test_node
 *
 * This means the bug is in IntelliJ
 */

/* But then, why does npm test fails too?
 * [mocha this]
 *
 *   1) works when a precondition violation occurs when a function is called with a mocha fixture as this
 *
 *      >>> logs: Error: TypeError: Converting circular structure to JSON
 *      >>> logs:     at JSON.stringify (<anonymous>)
 *      >>> logs:     at makeSimple (node_modules/format-error/index.js:36:28)
 *      >>> logs:     at format (node_modules/format-error/index.js:39:21)
 *      >>> logs:     at Runner.<anonymous> (node_modules/mocha-reporter/index.js:283:18)
 *
 * This is an error in mocha-reporter!
 *
 * But without mocha-reporter, it is even weirder:

(node:18037) UnhandledPromiseRejectionWarning: Error: This condition intentionally fails.
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/test/_cases.js:51:26)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/test/99.mochaBugTest.js:22:15)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at /Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:330:36
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:327:14)
    at Mocha.run (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:804:10)
    at Object.exports.singleRun (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run-helpers.js:207:16)
    at exports.runMocha (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run-helpers.js:300:13)
    at Object.exports.handler.argv [as handler] (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run.js:296:3)
    at Object.runCommand (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/lib/command.js:242:26)
    at Object.parseArgs [as _parseArgs] (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/yargs.js:1087:28)
    at Object.parse (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/yargs.js:566:25)
    at Object.exports.main (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/cli.js:63:6)
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/bin/_mocha:10:23)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)
    at bootstrap_node.js:625:3
(node:18037) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:18037) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
  mocha this
    1) works when a precondition violation occurs when a function is called with a mocha fixture as this
    *
 * Why is there an 'UnhandledPromiseRejectionWarning:'? There is nothing async here?!?!
 */
<|endoftext|>


<commit_before>var express = require('express'),
	bodyParser = require('body-parser'),
    authenticate = require('azure-mobile-apps/src/express/middleware/authenticate'),
    authorize = require('azure-mobile-apps/src/express/middleware/authorize');

var sql = require('mssql');
var util = require('../util');

const queryTertulias = 'SELECT' +
' tr_id         AS id,' +
' tr_name       AS name,' +
' tr_subject    AS subject,' +
' ev_targetdate AS nextEventDate,' +
' lo_name       AS nextEventLocation,' +
' no_count      AS messages,' +
' nv_name       AS role ' +
' FROM Tertulias' +
' INNER JOIN Members ON mb_tertulia = tr_id' +
' INNER JOIN Enumvalues ON mb_role = nv_id' +
' INNER JOIN Users ON mb_user = us_id' +
' LEFT JOIN' +
' (SELECT * FROM' +
' (SELECT RANK() OVER(PARTITION BY ev_tertulia ORDER BY ev_targetdate DESC) AS "rank", * FROM Events' +
'  INNER JOIN Locations on ev_location = lo_id WHERE ev_targetdate > GETDATE()) AS a WHERE a.rank = 1) AS b' +
' ON ev_tertulia = tr_id' +
' LEFT JOIN (SELECT no_tertulia, count(*) AS no_count FROM Notifications WHERE no_id NOT IN' +
' (SELECT no_id FROM Notifications INNER JOIN Readnotifications ON rn_notification = no_id' +
' INNER JOIN Users ON rn_user = us_id WHERE us_sid = @sid)' +
' GROUP BY no_tertulia) AS c ON no_tertulia = tr_id' +
' WHERE tr_is_cancelled = 0 AND us_sid = @sid';

const queryTertuliaDetails = 'SELECT DISTINCT' +
	' tr_id                    AS id,' + // Tertulia
	' tr_name                  AS name,' +
	' tr_subject               AS subject,' +
	' lo_name                  AS location,' + // Location
	' lo_address               AS address,' +
	' lo_zip                   AS zip,' +
	' lo_city                  AS city,' +
	' lo_country               AS country,' +
	' lo_latitude              AS latitude,' +
	' lo_longitude             AS longitude,' +
	' sc_type                  AS scheduleId,' + // Schedule
	' _Schedule.nv_name        AS scheduleName,' +
	' _Schedule.nv_description AS scheduleDescription,' +
	' tr_is_private            AS private, ' +  // Private
	' _Member.nv_name          AS role' + // Role
' FROM Tertulias' +
' INNER JOIN Locations  ON tr_location = lo_id' +
' INNER JOIN Schedules  ON tr_schedule = sc_id' +
' INNER JOIN Members    ON mb_tertulia = tr_id' +
' INNER JOIN Users      ON mb_user = us_id' +
' INNER JOIN EnumValues AS _Member ON mb_role = _Member.nv_id' +
' INNER JOIN EnumValues AS _Schedule ON sc_type = _Schedule.nv_id' +
' WHERE tr_is_cancelled = 0 AND us_sid = @sid' +
' AND tr_id = @tertulia';

/* { 'SQL types': {
	'String': 'sql.NVarChar', 'Number': 'sql.Int', 'Boolean': 'sql.Bit', 'Date': 'sql.DateTime', 'Buffer': 'sql.VarBinary', 'sql.Table': 'sql.TVP'
} } */
module.exports = function (configuration) {
    var router = express.Router();

    router.get('/', (req, res, next) => {
		var route = '/tertulias';
		req['tertulias'] = {};
		req.tertulias['resultsTag'] = 'tertulias';
		req.tertulias['query'] = queryTertulias;
	    req.tertulias['paramsTypes'] = { 'sid': sql.NVarChar };
	    req.tertulias['paramsValues'] = { 'sid': req.azureMobile.user.id };
	    req.tertulias['jsonType'] = "array";
	    req.tertulias['links'] = '[ ' +
			'{ "rel": "self", "method": "GET", "href": "' + route + '" }, ' +
			'{ "rel": "create", "method": "POST", "href": "' + route + '" }, ' +
			'{ "rel": "searchPublic", "method": "GET", "href": "' + route + '/publicsearch" } ' +
		']';
	    req.tertulias['itemLinks'] = '[ ' +
			'{ "rel": "self", "method": "GET", "href": "' + route + '/:id" }, ' +
			'{ "rel": "update", "method": "PUT", "href": "' + route + '/:id" }, ' +
			'{ "rel": "delete", "method": "DELETE", "href": "' + route + '/:id" } ' +
		']';
	    goGet(req, res, next);
	});

	router.get('/:tr_id', (req, res, next) => {
		var tr_id = req.params.tr_id;
		var route = '/tertulias/' + tr_id;
		req['tertulias'] = {};
		req.tertulias['resultsTag'] = 'tertulia';
		req.tertulias['query'] = queryTertuliaDetails;
	    req.tertulias['paramsTypes'] = { 'sid': sql.NVarChar, 'tertulia': sql.Int };
	    req.tertulias['paramsValues'] = { 'sid': req.azureMobile.user.id, 'tertulia': tr_id };
	    req.tertulias['jsonType'] = "object";
	    req.tertulias['links'] = '[ ' +
			'{ "rel": "self", "method": "GET", "href": "' + route + '" }, ' +
			'{ "rel": "update", "method": "PATCH", "href": "' + route + '" }, ' +
			'{ "rel": "delete", "method": "DELETE", "href": "' + route + '" } ' +
		']';
	    goGet(req, res, next);
	});

	router.post('/', (req, res, next) => {
	    sql.connect(util.sqlConfiguration)
	    .then(function() {
			new sql.Request()
			.input('name', sql.NVarChar(40), req.body.name)
			.input('subject', sql.NVarChar(80), req.body.subject)
			.input('locationName', sql.NVarChar(40), req.body.location)
			.input('locationAddress', sql.NVarChar(80), req.body.address)
			.input('locationZip', sql.NVarChar(40), req.body.zip)
			.input('locationCity', sql.NVarChar(40), req.body.city)
			.input('locationCountry', sql.NVarChar(40), req.body.country)
			.input('locationLatitude', sql.NVarChar(12), req.body.latitude)
			.input('locationLongitude', sql.NVarChar(12), req.body.longitude)
			.input('weekDay', sql.NVarChar(20), 'Tuesday')
			.input('weekNr', sql.Int, 1)
			.input('fromStart', sql.BIT, 1)
			.input('skip', sql.Int, 0)
			.input('isPrivate', sql.Int, req.body.isPrivate ? 1 : 0)
			.input('userSid', sql.NVarChar(40), req.azureMobile.user.id)
			.execute('sp_insertTertulia_MonthlyW_sid')
			.then((recordsets) => {
				console.log(recordsets);
				console.log('len: ' + recordsets.length);
				//console.log('r1: ' + recordsets[0][0][ErrorNumber]);
				//console.log('r2: ' + recordsets[0][ErrorNumber]);
				//console.log('r2: ' + recordsets[0]);
				if (recordsets.length == 0) {
					console.log('sending 201');
					res.status(201)	// 201: Created
						.type('application/json')
						.json( { result: 'Ok' } );
					return;
				} else {
					console.log('sending 409');
					res.status(409)	// 409: Conflict, 422: Unprocessable Entity (WebDAV; RFC 4918)
						.type('application/json')
						.json( { result: 'Duplicate' } );
					return;
				}
				next();
			})
			.catch(function(err) {
				console.log('catch 1');
				console.log(err);
				next();
			});
		})
		.catch(function(err) {
			console.log('catch 2');
			console.log(err);
			next();
		});
	});

	var completeError = function(err, res) {
	    if (err) {
	        console.error(err);
	        if (res) res.sendStatus(500);
	    }
	};

	var goGet = function(req, res, next) {
		var query = req.tertulias.query;
		var resultsTag = req.tertulias.resultsTag;
	    var paramsTypes = req.tertulias.paramsTypes;
	    var paramsValues = req.tertulias.paramsValues;
	    var links = req.tertulias.links;
	    var itemLinks = req.tertulias.itemLinks;

		var connection = new sql.Connection(util.sqlConfiguration);
	    connection.connect(function(err) {
	        var preparedStatement = new sql.PreparedStatement(connection);
	        for (var key in paramsTypes)
	        	preparedStatement.input(key, paramsTypes[key]);
	        preparedStatement.prepare(query, function(err) {
	            if (err) {
	            	completeError(err, res);
	            	return;
	            }
	            preparedStatement.execute(paramsValues,
	                function(err, recordset, affected) {
	                    if (err) {
	                    	completeError(err, res);
	                    	return;
	                    }
	                    res.type('application/json');
                    	if (typeof itemLinks !== typeof undefined) {
		                    recordset.forEach(function(elem) {
		                    	elem['links'] = JSON.parse(itemLinks.replace(/:id/g, elem.id));
                    		});
	                    };
	                    preparedStatement.unprepare();
	                    var results = {};
	                    if (req.tertulias.jsonType == "array")
	                    	results[resultsTag] = recordset;
	                    else
	                    	results[resultsTag] = recordset[0];
	                    results['links'] = JSON.parse(links);
	                    console.log(results);
	                    res.json(results);
	                    next();
	                }
	            );
	        });
	    });
	};

    return router;

}
<commit_msg>wip save<commit_after>var express = require('express'),
	bodyParser = require('body-parser'),
    authenticate = require('azure-mobile-apps/src/express/middleware/authenticate'),
    authorize = require('azure-mobile-apps/src/express/middleware/authorize');

var sql = require('mssql');
var util = require('../util');

const queryTertulias = 'SELECT' +
' tr_id         AS id,' +
' tr_name       AS name,' +
' tr_subject    AS subject,' +
' ev_targetdate AS nextEventDate,' +
' lo_name       AS nextEventLocation,' +
' no_count      AS messages,' +
' nv_name       AS role ' +
' FROM Tertulias' +
' INNER JOIN Members ON mb_tertulia = tr_id' +
' INNER JOIN Enumvalues ON mb_role = nv_id' +
' INNER JOIN Users ON mb_user = us_id' +
' LEFT JOIN' +
' (SELECT * FROM' +
' (SELECT RANK() OVER(PARTITION BY ev_tertulia ORDER BY ev_targetdate DESC) AS "rank", * FROM Events' +
'  INNER JOIN Locations on ev_location = lo_id WHERE ev_targetdate > GETDATE()) AS a WHERE a.rank = 1) AS b' +
' ON ev_tertulia = tr_id' +
' LEFT JOIN (SELECT no_tertulia, count(*) AS no_count FROM Notifications WHERE no_id NOT IN' +
' (SELECT no_id FROM Notifications INNER JOIN Readnotifications ON rn_notification = no_id' +
' INNER JOIN Users ON rn_user = us_id WHERE us_sid = @sid)' +
' GROUP BY no_tertulia) AS c ON no_tertulia = tr_id' +
' WHERE tr_is_cancelled = 0 AND us_sid = @sid';

const queryTertuliaDetails = 'SELECT DISTINCT' +
	' tr_id                    AS id,' + // Tertulia
	' tr_name                  AS name,' +
	' tr_subject               AS subject,' +
	' lo_name                  AS location,' + // Location
	' lo_address               AS address,' +
	' lo_zip                   AS zip,' +
	' lo_city                  AS city,' +
	' lo_country               AS country,' +
	' lo_latitude              AS latitude,' +
	' lo_longitude             AS longitude,' +
	' sc_type                  AS scheduleId,' + // Schedule
	' _Schedule.nv_name        AS scheduleName,' +
	' _Schedule.nv_description AS scheduleDescription,' +
	' tr_is_private            AS private, ' +  // Private
	' _Member.nv_name          AS role' + // Role
' FROM Tertulias' +
' INNER JOIN Locations  ON tr_location = lo_id' +
' INNER JOIN Schedules  ON tr_schedule = sc_id' +
' INNER JOIN Members    ON mb_tertulia = tr_id' +
' INNER JOIN Users      ON mb_user = us_id' +
' INNER JOIN EnumValues AS _Member ON mb_role = _Member.nv_id' +
' INNER JOIN EnumValues AS _Schedule ON sc_type = _Schedule.nv_id' +
' WHERE tr_is_cancelled = 0 AND us_sid = @sid' +
' AND tr_id = @tertulia';

/* { 'SQL types': {
	'String': 'sql.NVarChar', 'Number': 'sql.Int', 'Boolean': 'sql.Bit', 'Date': 'sql.DateTime', 'Buffer': 'sql.VarBinary', 'sql.Table': 'sql.TVP'
} } */
module.exports = function (configuration) {
    var router = express.Router();

    router.get('/', (req, res, next) => {
		var route = '/tertulias';
		req['tertulias'] = {};
		req.tertulias['resultsTag'] = 'tertulias';
		req.tertulias['query'] = queryTertulias;
	    req.tertulias['paramsTypes'] = { 'sid': sql.NVarChar };
	    req.tertulias['paramsValues'] = { 'sid': req.azureMobile.user.id };
	    req.tertulias['jsonType'] = "array";
	    req.tertulias['links'] = '[ ' +
			'{ "rel": "self", "method": "GET", "href": "' + route + '" }, ' +
			'{ "rel": "create", "method": "POST", "href": "' + route + '" }, ' +
			'{ "rel": "searchPublic", "method": "GET", "href": "' + route + '/publicsearch" } ' +
		']';
	    req.tertulias['itemLinks'] = '[ ' +
			'{ "rel": "self", "method": "GET", "href": "' + route + '/:id" }, ' +
			'{ "rel": "update", "method": "PUT", "href": "' + route + '/:id" }, ' +
			'{ "rel": "delete", "method": "DELETE", "href": "' + route + '/:id" }, ' +
			'{ "rel": "unsubscribe", "method": "DELETE", "href": "' + route + '/:id/unsubscribe" } ' +
		']';
	    goGet(req, res, next);
	});

    router.get('/publicSearch', (req, res, next) => {
		var route = '/tertulias';
		req['tertulias'] = {};
		req.tertulias['resultsTag'] = 'tertulias';
		req.tertulias['query'] = queryTertulias;
	    req.tertulias['paramsTypes'] = { 'sid': sql.NVarChar, 'latitude': sql.Int, 'longitude': sql.Int };
	    req.tertulias['paramsValues'] = { 'sid': req.azureMobile.user.id, 'latitude': req.body.latitude, 'longitude': req.body.longitude };
	    req.tertulias['jsonType'] = "array";
	    req.tertulias['links'] = '[ ' +
			'{ "rel": "self", "method": "GET", "href": "' + route + '" }' +
		']';
	    req.tertulias['itemLinks'] = '[ ' +
			'{ "rel": "self", "method": "GET", "href": "' + route + '/:id" }, ' +
			'{ "rel": "subscribe", "method": "POST", "href": "' + route + '/:id/subscribe" }' +
		']';
	    goGet(req, res, next);
	});

	router.get('/:tr_id', (req, res, next) => {
		var tr_id = req.params.tr_id;
		var route = '/tertulias/' + tr_id;
		req['tertulias'] = {};
		req.tertulias['resultsTag'] = 'tertulia';
		req.tertulias['query'] = queryTertuliaDetails;
	    req.tertulias['paramsTypes'] = { 'sid': sql.NVarChar, 'tertulia': sql.Int };
	    req.tertulias['paramsValues'] = { 'sid': req.azureMobile.user.id, 'tertulia': tr_id };
	    req.tertulias['jsonType'] = "object";
	    req.tertulias['links'] = '[ ' +
			'{ "rel": "self", "method": "GET", "href": "' + route + '" }, ' +
			'{ "rel": "update", "method": "PATCH", "href": "' + route + '" }, ' +
			'{ "rel": "delete", "method": "DELETE", "href": "' + route + '" }, ' +
			'{ "rel": "subscribe", "method": "POST", "href": "' + route + '/subscribe" } ' +
			'{ "rel": "unsubscribe", "method": "DELETE", "href": "' + route + '/unsubscribe" } ' +
		']';
	    goGet(req, res, next);
	});

	router.post('/', (req, res, next) => {
	    sql.connect(util.sqlConfiguration)
	    .then(function() {
			new sql.Request()
			.input('name', sql.NVarChar(40), req.body.name)
			.input('subject', sql.NVarChar(80), req.body.subject)
			.input('locationName', sql.NVarChar(40), req.body.location)
			.input('locationAddress', sql.NVarChar(80), req.body.address)
			.input('locationZip', sql.NVarChar(40), req.body.zip)
			.input('locationCity', sql.NVarChar(40), req.body.city)
			.input('locationCountry', sql.NVarChar(40), req.body.country)
			.input('locationLatitude', sql.NVarChar(12), req.body.latitude)
			.input('locationLongitude', sql.NVarChar(12), req.body.longitude)
			.input('weekDay', sql.NVarChar(20), 'Tuesday')
			.input('weekNr', sql.Int, 1)
			.input('fromStart', sql.BIT, 1)
			.input('skip', sql.Int, 0)
			.input('isPrivate', sql.Int, req.body.isPrivate ? 1 : 0)
			.input('userSid', sql.NVarChar(40), req.azureMobile.user.id)
			.execute('sp_insertTertulia_MonthlyW_sid')
			.then((recordsets) => {
				console.log(recordsets);
				console.log('len: ' + recordsets.length);
				//console.log('r1: ' + recordsets[0][0][ErrorNumber]);
				//console.log('r2: ' + recordsets[0][ErrorNumber]);
				//console.log('r2: ' + recordsets[0]);
				if (recordsets.length == 0) {
					console.log('sending 201');
					res.status(201)	// 201: Created
						.type('application/json')
						.json( { result: 'Ok' } );
					return;
				} else {
					console.log('sending 409');
					res.status(409)	// 409: Conflict, 422: Unprocessable Entity (WebDAV; RFC 4918)
						.type('application/json')
						.json( { result: 'Duplicate' } );
					return;
				}
				next();
			})
			.catch(function(err) {
				console.log('catch 1');
				console.log(err);
				next();
			});
		})
		.catch(function(err) {
			console.log('catch 2');
			console.log(err);
			next();
		});
	});

	var completeError = function(err, res) {
	    if (err) {
	        console.error(err);
	        if (res) res.sendStatus(500);
	    }
	};

	var goGet = function(req, res, next) {
		var query = req.tertulias.query;
		var resultsTag = req.tertulias.resultsTag;
	    var paramsTypes = req.tertulias.paramsTypes;
	    var paramsValues = req.tertulias.paramsValues;
	    var links = req.tertulias.links;
	    var itemLinks = req.tertulias.itemLinks;

		var connection = new sql.Connection(util.sqlConfiguration);
	    connection.connect(function(err) {
	        var preparedStatement = new sql.PreparedStatement(connection);
	        for (var key in paramsTypes)
	        	preparedStatement.input(key, paramsTypes[key]);
	        preparedStatement.prepare(query, function(err) {
	            if (err) {
	            	completeError(err, res);
	            	return;
	            }
	            preparedStatement.execute(paramsValues,
	                function(err, recordset, affected) {
	                    if (err) {
	                    	completeError(err, res);
	                    	return;
	                    }
	                    res.type('application/json');
                    	if (typeof itemLinks !== typeof undefined) {
		                    recordset.forEach(function(elem) {
		                    	elem['links'] = JSON.parse(itemLinks.replace(/:id/g, elem.id));
                    		});
	                    };
	                    preparedStatement.unprepare();
	                    var results = {};
	                    if (req.tertulias.jsonType == "array")
	                    	results[resultsTag] = recordset;
	                    else
	                    	results[resultsTag] = recordset[0];
	                    results['links'] = JSON.parse(links);
	                    console.log(results);
	                    res.json(results);
	                    next();
	                }
	            );
	        });
	    });
	};

    return router;

}
<|endoftext|>