<commit_before>var passport = require('passport')
  , path     = require('path')
  , url      = require('url');

/**
 * Passport Service
 *
 * A painless Passport.js service for your Sails app that is guaranteed to
 * Rock Your Socks™. It takes all the hassle out of setting up Passport.js by
 * encapsulating all the boring stuff in two functions:
 *
 *   passport.endpoint()
 *   passport.callback()
 *
 * The former sets up an endpoint (/auth/:provider) for redirecting a user to a
 * third-party provider for authentication, while the latter sets up a callback
 * endpoint (/auth/:provider/callback) for receiving the response from the
 * third-party provider. All you have to do is define in the configuration which
 * third-party providers you'd like to support. It's that easy!
 *
 * Behind the scenes, the service stores all the data it needs within "Pass-
 * ports". These contain all the information required to associate a local user
 * with a profile from a third-party provider. This even holds true for the good
 * ol' password authentication scheme – the Authentication Service takes care of
 * encrypting passwords and storing them in Passports, allowing you to keep your
 * User model free of bloat.
 */

// Load authentication protocols
passport.protocols = require('./protocols');

/**
 * Connect a third-party profile to a local user
 *
 * This is where most of the magic happens when a user is authenticating with a
 * third-party provider. What it does, is the following:
 *
 *   1. Given a provider and an identifier, find a mathcing Passport.
 *   2. From here, the logic branches into two paths.
 *
 *     - A user is not currently logged in:
 *       1. If a Passport wassn't found, create a new user as well as a new
 *          Passport that will be assigned to the user.
 *       2. If a Passport was found, get the user associated with the passport.
 *
 *     - A user is currently logged in:
 *       1. If a Passport wasn't found, create a new Passport and associate it
 *          with the already logged in user (ie. "Connect")
 *       2. If a Passport was found, nothing needs to happen.
 *
 * As you can see, this function handles both "authentication" and "authori-
 * zation" at the same time. This is due to the fact that we pass in
 * `passReqToCallback: true` when loading the strategies, allowing us to look
 * for an existing session in the request and taking action based on that.
 *
 * For more information on auth(entication|rization) in Passport.js, check out:
 * http://passportjs.org/guide/authenticate/
 * http://passportjs.org/guide/authorize/
 *
 * @param {Object}   req
 * @param {Object}   query
 * @param {Object}   profile
 * @param {Function} next
 */
passport.connect = function (req, query, profile, next) {
  var strategies = sails.config.passport
    , config     = strategies[profile.provider]
    , user       = {};

  // Set the authentication provider.
  query.provider = req.param('provider');

  // If the profile object contains a list of emails, grab the first one and
  // add it to the user.
  if (profile.hasOwnProperty('emails')) {
    user.email = profile.emails[0].value;
  }
  // If the profile object contains a username, add it to the user.
  if (profile.hasOwnProperty('username')) {
    user.username = profile.username;
  }

  // If neither an email or a username was available in the profile, we don't
  // have a way of identifying the user in the future. Throw an error and let
  // whoever's next in the line take care of it.
  if (!Object.keys(user).length) {
    return next(new Error('Neither a username or email was available', null));
  }

  Passport.findOne({
    provider   : profile.provider
  , identifier : query.identifier
  })
  .populate('user')
  .done(function (err, passport) {
    if (err) return next(err);

    if (!req.user) {
      // Scenario: A new user is attempting to sign up using a third-party
      //           authentication provider.
      // Action:   Create a new user and assign them a passport.
      if (!passport) {
        User.create(user).done(function (err, user) {
          if (err) return next(err);

          query.user = user.id;

          Passport.create(query).done(function (err, passport) {
            // If a passport wasn't created, bail out
            if (err) return next(err);

            next(err, user);
          });
        });
      }
      // Scenario: An existing user is trying to log in using an already
      //           connected passport.
      // Action:   Get the user associated with the passport.
      else {
        next(null, passport.user);
      }
    } else {
      // Scenario: A user is currently logged in and trying to connect a new
      //           passport.
      // Action:   Create and assign a new passport to the user.
      if (!passport) {
        query.user = req.user.id;

        Passport.create(query).done(function (err, passport) {
          // If a passport wasn't created, bail out
          if (err) return next(err);

          next(err, req.user);
        });
      }
      // Scenario: The user is a nutjob or spammed the back-button.
      // Action:   Simply pass along the already established session.
      else {
        next(null, req.user);
      }
    }
  });
};

/**
 * Create an authentication endpoint
 *
 * For more information on authentication in Passport.js, check out:
 * http://passportjs.org/guide/authenticate/
 *
 * @param  {Object} req
 * @param  {Object} res
 */
passport.endpoint = function (req, res) {
  var strategies = sails.config.passport
    , provider   = req.param('provider')
    , options    = {};

  // Attach scope if it has been set in the config
  if (strategies[provider].hasOwnProperty('scope')) {
    options.scope = strategies[provider].scope;
  }

  // Load authentication strategies
  this.loadStrategies(req);

  // Redirect the user to the provider for authentication. When complete,
  // the provider will redirect the user back to the application at
  //     /auth/:provider/callback
  this.authenticate(provider, options)(req, res, req.next);
};

/**
 * Create an authentication callback endpoint
 *
 * For more information on authentication in Passport.js, check out:
 * http://passportjs.org/guide/authenticate/
 *
 * @param {Object}   req
 * @param {Object}   res
 * @param {Function} next
 */
passport.callback = function (req, res, next) {
  var provider = req.param('provider', 'local')
    , action   = req.param('action');

  // Passport.js wasn't really built for local user registration, but it's nice
  // having it tied into everything else.
  if (provider === 'local' && action !== undefined) {
    if (action === 'register' && !req.user) {
      this.protocols.local.register(req, res, next);
    }
    else if (action === 'connect' && req.user) {
      this.protocols.local.connect(req, res, next);
    }
    else {
      next(new Error('Invalid action'));
    }
  } else {
    // Load authentication strategies
    this.loadStrategies(req);

    // The provider will redirect the user to this URL after approval. Finish
    // the authentication process by attempting to obtain an access token. If
    // access was granted, the user will be logged in. Otherwise, authentication
    // has failed.
    this.authenticate(provider, next)(req, res, req.next);
  }
};

/**
 * Load all strategies defined in the Passport configuration
 *
 * For example, we could add this to our config to use the GitHub strategy
 * with permission to access a users email address (even if it's marked as
 * private) as well as permission to add and update a user's Gists:
 *
    github: {
      name: 'GitHub',
      protocol: 'oauth2',
      scope: [ 'user', 'gist' ]
      options: {
        clientID: 'CLIENT_ID',
        clientSecret: 'CLIENT_SECRET'
      }
    }
 *
 * For more information on the providers supported by Passport.js, check out:
 * http://passportjs.org/guide/providers/
 *
 * @param {Object} req
 */
passport.loadStrategies = function (req) {
  var self       = this
    , strategies = sails.config.passport;

  Object.keys(strategies).forEach(function (key) {
    var Strategy = require('passport-' + key).Strategy
      , options  = { passReqToCallback: true };

    if (key === 'local') {
      // Since we need to allow users to login using both usernames as well as
      // emails, we'll set the username field to something more generic.
      _.extend(options, { usernameField: 'identifier' });

      // Only load the local strategy if it's enabled in the config
      if (strategies[key]) {
        self.use(new Strategy(options, self.protocols.local.login));
      }
    } else {
      var protocol   = strategies[key].protocol
        , callback   = path.join('auth', key, 'callback');

      switch (protocol) {
        case 'oauth':
        case 'oauth2':
          options.callbackURL = url.resolve(req.baseUrl, callback);
          break;

        case 'openid':
          options.returnURL = url.resolve(req.baseUrl, callback);
          options.realm     = req.baseUrl;
          options.profile   = true;
          break;
      }

      // Merge the default options with any options defined in the config. All
      // defaults can be overriden, but I don't see a reason why you'd want to
      // do that.
      _.extend(options, strategies[key].options);

      self.use(new Strategy(options, self.protocols[protocol]));
    }
  });
};

module.exports = passport;
<commit_msg>Better handling of non-existing endpoints<commit_after>var passport = require('passport')
  , path     = require('path')
  , url      = require('url');

/**
 * Passport Service
 *
 * A painless Passport.js service for your Sails app that is guaranteed to
 * Rock Your Socks™. It takes all the hassle out of setting up Passport.js by
 * encapsulating all the boring stuff in two functions:
 *
 *   passport.endpoint()
 *   passport.callback()
 *
 * The former sets up an endpoint (/auth/:provider) for redirecting a user to a
 * third-party provider for authentication, while the latter sets up a callback
 * endpoint (/auth/:provider/callback) for receiving the response from the
 * third-party provider. All you have to do is define in the configuration which
 * third-party providers you'd like to support. It's that easy!
 *
 * Behind the scenes, the service stores all the data it needs within "Pass-
 * ports". These contain all the information required to associate a local user
 * with a profile from a third-party provider. This even holds true for the good
 * ol' password authentication scheme – the Authentication Service takes care of
 * encrypting passwords and storing them in Passports, allowing you to keep your
 * User model free of bloat.
 */

// Load authentication protocols
passport.protocols = require('./protocols');

/**
 * Connect a third-party profile to a local user
 *
 * This is where most of the magic happens when a user is authenticating with a
 * third-party provider. What it does, is the following:
 *
 *   1. Given a provider and an identifier, find a mathcing Passport.
 *   2. From here, the logic branches into two paths.
 *
 *     - A user is not currently logged in:
 *       1. If a Passport wassn't found, create a new user as well as a new
 *          Passport that will be assigned to the user.
 *       2. If a Passport was found, get the user associated with the passport.
 *
 *     - A user is currently logged in:
 *       1. If a Passport wasn't found, create a new Passport and associate it
 *          with the already logged in user (ie. "Connect")
 *       2. If a Passport was found, nothing needs to happen.
 *
 * As you can see, this function handles both "authentication" and "authori-
 * zation" at the same time. This is due to the fact that we pass in
 * `passReqToCallback: true` when loading the strategies, allowing us to look
 * for an existing session in the request and taking action based on that.
 *
 * For more information on auth(entication|rization) in Passport.js, check out:
 * http://passportjs.org/guide/authenticate/
 * http://passportjs.org/guide/authorize/
 *
 * @param {Object}   req
 * @param {Object}   query
 * @param {Object}   profile
 * @param {Function} next
 */
passport.connect = function (req, query, profile, next) {
  var strategies = sails.config.passport
    , config     = strategies[profile.provider]
    , user       = {};

  // Set the authentication provider.
  query.provider = req.param('provider');

  // If the profile object contains a list of emails, grab the first one and
  // add it to the user.
  if (profile.hasOwnProperty('emails')) {
    user.email = profile.emails[0].value;
  }
  // If the profile object contains a username, add it to the user.
  if (profile.hasOwnProperty('username')) {
    user.username = profile.username;
  }

  // If neither an email or a username was available in the profile, we don't
  // have a way of identifying the user in the future. Throw an error and let
  // whoever's next in the line take care of it.
  if (!Object.keys(user).length) {
    return next(new Error('Neither a username or email was available', null));
  }

  Passport.findOne({
    provider   : profile.provider
  , identifier : query.identifier
  })
  .populate('user')
  .done(function (err, passport) {
    if (err) return next(err);

    if (!req.user) {
      // Scenario: A new user is attempting to sign up using a third-party
      //           authentication provider.
      // Action:   Create a new user and assign them a passport.
      if (!passport) {
        User.create(user).done(function (err, user) {
          if (err) return next(err);

          query.user = user.id;

          Passport.create(query).done(function (err, passport) {
            // If a passport wasn't created, bail out
            if (err) return next(err);

            next(err, user);
          });
        });
      }
      // Scenario: An existing user is trying to log in using an already
      //           connected passport.
      // Action:   Get the user associated with the passport.
      else {
        next(null, passport.user);
      }
    } else {
      // Scenario: A user is currently logged in and trying to connect a new
      //           passport.
      // Action:   Create and assign a new passport to the user.
      if (!passport) {
        query.user = req.user.id;

        Passport.create(query).done(function (err, passport) {
          // If a passport wasn't created, bail out
          if (err) return next(err);

          next(err, req.user);
        });
      }
      // Scenario: The user is a nutjob or spammed the back-button.
      // Action:   Simply pass along the already established session.
      else {
        next(null, req.user);
      }
    }
  });
};

/**
 * Create an authentication endpoint
 *
 * For more information on authentication in Passport.js, check out:
 * http://passportjs.org/guide/authenticate/
 *
 * @param  {Object} req
 * @param  {Object} res
 */
passport.endpoint = function (req, res) {
  var strategies = sails.config.passport
    , provider   = req.param('provider')
    , options    = {};

  // If a provider doesn't exist for this endpoint, send the user back to the
  // login page
  if (!strategies.hasOwnProperty(provider)) {
    return res.redirect('/login');
  }

  // Attach scope if it has been set in the config
  if (strategies[provider].hasOwnProperty('scope')) {
    options.scope = strategies[provider].scope;
  }

  // Load authentication strategies
  this.loadStrategies(req);

  // Redirect the user to the provider for authentication. When complete,
  // the provider will redirect the user back to the application at
  //     /auth/:provider/callback
  this.authenticate(provider, options)(req, res, req.next);
};

/**
 * Create an authentication callback endpoint
 *
 * For more information on authentication in Passport.js, check out:
 * http://passportjs.org/guide/authenticate/
 *
 * @param {Object}   req
 * @param {Object}   res
 * @param {Function} next
 */
passport.callback = function (req, res, next) {
  var provider = req.param('provider', 'local')
    , action   = req.param('action');

  // Passport.js wasn't really built for local user registration, but it's nice
  // having it tied into everything else.
  if (provider === 'local' && action !== undefined) {
    if (action === 'register' && !req.user) {
      this.protocols.local.register(req, res, next);
    }
    else if (action === 'connect' && req.user) {
      this.protocols.local.connect(req, res, next);
    }
    else {
      next(new Error('Invalid action'));
    }
  } else {
    // Load authentication strategies
    this.loadStrategies(req);

    // The provider will redirect the user to this URL after approval. Finish
    // the authentication process by attempting to obtain an access token. If
    // access was granted, the user will be logged in. Otherwise, authentication
    // has failed.
    this.authenticate(provider, next)(req, res, req.next);
  }
};

/**
 * Load all strategies defined in the Passport configuration
 *
 * For example, we could add this to our config to use the GitHub strategy
 * with permission to access a users email address (even if it's marked as
 * private) as well as permission to add and update a user's Gists:
 *
    github: {
      name: 'GitHub',
      protocol: 'oauth2',
      scope: [ 'user', 'gist' ]
      options: {
        clientID: 'CLIENT_ID',
        clientSecret: 'CLIENT_SECRET'
      }
    }
 *
 * For more information on the providers supported by Passport.js, check out:
 * http://passportjs.org/guide/providers/
 *
 * @param {Object} req
 */
passport.loadStrategies = function (req) {
  var self       = this
    , strategies = sails.config.passport;

  Object.keys(strategies).forEach(function (key) {
    var Strategy = require('passport-' + key).Strategy
      , options  = { passReqToCallback: true };

    if (key === 'local') {
      // Since we need to allow users to login using both usernames as well as
      // emails, we'll set the username field to something more generic.
      _.extend(options, { usernameField: 'identifier' });

      // Only load the local strategy if it's enabled in the config
      if (strategies[key]) {
        self.use(new Strategy(options, self.protocols.local.login));
      }
    } else {
      var protocol   = strategies[key].protocol
        , callback   = path.join('auth', key, 'callback');

      switch (protocol) {
        case 'oauth':
        case 'oauth2':
          options.callbackURL = url.resolve(req.baseUrl, callback);
          break;

        case 'openid':
          options.returnURL = url.resolve(req.baseUrl, callback);
          options.realm     = req.baseUrl;
          options.profile   = true;
          break;
      }

      // Merge the default options with any options defined in the config. All
      // defaults can be overriden, but I don't see a reason why you'd want to
      // do that.
      _.extend(options, strategies[key].options);

      self.use(new Strategy(options, self.protocols[protocol]));
    }
  });
};

module.exports = passport;
<|endoftext|>


<commit_before><commit_msg>error redirecciona en search de compara/escuelas<commit_after><|endoftext|>


<commit_before>//import * as NetProgress from "./NetProgress.js";
import * as ConvBlock from "../Conv/Block.js";

export { Config, Base };

/**
 * A neural network's configuration.
 *
 * A special recommended configuration is 3x3 ShuffleNetV2 without explicit bias (but with implicit bias by cosine activation)
 * and without activation at the end of every block:
 *   - bChannelShuffler: true
 *   - pointwise1ChannelCountRate: 1
 *   - strAvgMaxConv: "Conv"
 *   - depthwiseFilterHeight: 3
 *   - depthwiseChannelMultiplierBlock0Step0: 1
 *   - bBias: false
 *   - nActivationId: ConvBlock.PointDepthPoint.Params.Activation.Ids.COS
 *   - nActivationIdAtBlockEnd: ConvBlock.PointDepthPoint.Params.Activation.Ids.NONE
 *
 * The cosine activation function can achieve impilcit bias. This is because depthwise and pointwise convolution can easily achieve zero
 * and ( cos( 0 ) == 1 ). A constant value (e.g. 1) becomes the bias of the next convolution. So there is not necessary to use explicit bias
 * which has worse performance (than without it).
 *
 * The recommended sourceChannelCount is 4. This is because source image is usually generated by tf.browser.fromPixels() and it handles
 * RGBA 4 channels faster than RGB 3 channels.
 *
 * The last PointDepthPoint's pointwise2 of every block without activation function
 * (i.e. nActivationIdAtBlockEnd == ConvBlock.PointDepthPoint.Params.Activation.Ids.NONE) could let the output of neural network be any
 * arbitrary value because it will not be restricted by the range of the activation function.
 */
class Config {
  /**
   * @param {number} depthwiseChannelMultiplierBlock0Step0
   *   The depthwise convolution of the first step (Step 0) of the first block (Block 0) will expand input channel by this factor.
   *
   * @see ConvBlock.Base.init
   */
  constructor(
    sourceHeight, sourceWidth, sourceChannelCount = 4,
    stepCountPerBlock,
    bChannelShuffler = true,
    pointwise1ChannelCountRate = 1,
    strAvgMaxConv = "Conv", depthwiseFilterHeight = 3, depthwiseChannelMultiplierBlock0Step0 = 1, bBias = false,
    nActivationId = ConvBlock.PointDepthPoint.Params.Activation.Ids.COS,
    nActivationIdAtBlockEnd = ConvBlock.PointDepthPoint.Params.Activation.Ids.NONE )
  {
    this.sourceHeight = sourceHeight;
    this.sourceWidth = sourceWidth;
    this.sourceChannelCount = sourceChannelCount;
    this.stepCountPerBlock = stepCountPerBlock;
    this.bChannelShuffler = bChannelShuffler;
    this.pointwise1ChannelCountRate = pointwise1ChannelCountRate;
    this.strAvgMaxConv = strAvgMaxConv;
    this.depthwiseFilterHeight = depthwiseFilterHeight;
    this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
    this.bBias = bBias;
    this.nActivationId = nActivationId;
    this.nActivationIdAtBlockEnd = nActivationIdAtBlockEnd;

    this.sourceHeightWidth = [ this.sourceHeight, this.sourceWidth ];
  }

  /**
   * @param {ImageData|HTMLCanvasElement} source_ImageData_or_Canvas
   *   The image or canvas which provides image.
   *
   * @param {boolean} bForceInt32
   *   If true, the dtype of the returned tf.tensor3d will guaranteed to be int32. Otherwise, the dtype of the returned tf.tensor3d
   * may be int32 or float32 (if resized). This is useful if the result will be used by an embedding layer (which only accepts
   * integer input).
   *
   * @return {tf.tensor3d}
   *   Return the tensor3d which is the scaled image from canvas. Its size will be this.sourceImageHeightWidth. Its channel count
   * will be this.config.sourceChannelCount.
   */
  create_ScaledSourceTensor_from_ImageData_or_Canvas( source_ImageData_or_Canvas, bForceInt32 ) {

    let sourceTensor = tf.browser.fromPixels( source_ImageData_or_Canvas, this.sourceChannelCount ); // dtype will be int32.

    // If the size (height x width) is as expected, use it directly. (dtype will still be int32.)
    if (   ( sourceTensor.shape[ 0 ] == this.sourceHeight )
        && ( sourceTensor.shape[ 1 ] == this.sourceWidth  ) )
      return sourceTensor;

    // Otherwise, resize to the default size (height x width) which is the input image size used for training the neural network.
    //
    // ( alignCorners = true ) for visual image resizing.
    let scaledSourceTensorFloat32;
    try {
      scaledSourceTensorFloat32 = tf.image.resizeBilinear( sourceTensor, this.sourceHeightWidth, true );
    } catch ( e ) {
      throw e; // e.g. out of (GPU) memory.
    } finally {
      sourceTensor.dispose();
    }

    if ( !bForceInt32 ) {
      return scaledSourceTensorFloat32;

    // Convert to int32 if necessary. (Because the tf.resize() result's dtype is float32.)
    try {
      let scaledSourceTensorInt32 = scaledSourceTensorFloat32.cast( 'int32' );
      return scaledSourceTensorInt32;
    } catch ( e ) {
      throw e; // e.g. out of (GPU) memory.
    } finally {
      scaledSourceTensorFloat32.dispose();
    }
  }

  /** The channel count of the first block (Block 0). */
  get channelCountBlock0() {
    return this.sourceChannelCount * this.depthwiseChannelMultiplierBlock0Step0;
  }

}

/**
 * A neural network composes of multiple blocks.
 *
 *
 *
 * @member {Config} config
 *   This neural network's configuration.
 *
 * @member {string} structure
 *   A string denote this neural network's structure (configuration).
 *
 * @member {number} totalChannelExpansionFactor
 *   The final output of this neural network will have ( totalChannelExpansionFactor * sourceChannelCount ) channel count.
 *
 * @member {number[]} sourceImageHeightWidth
 *   The size (i.e. [ height, width ]) of the source image. When apply_and_destroy_or_keep() is called, the input tensor should be this size.
 */
class Base {

  /**
   * @param {Config} config
   *   The configuration of this neural network.
   *
   * @param {boolean} bKeepInputTensor
   *   If true, apply_and_destroy_or_keep() will not dispose inputTensor (i.e. keep).
   *
   * @see ConvBlock.Base.init
   */
  init( config, bKeepInputTensor ) {

    this.disposeTensors();

    this.config = config;
    this.bKeepInputTensor = bKeepInputTensor;

    let targetHeight = 1; // The final output always has ( height x width ) = ( 1 x 1 ), i.e. only one pixel per channel.

    let differenceHeight = config.sourceHeight - targetHeight;
//    let filterWidth = depthwiseFilterHeight;

//  this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
//    this.channelCountBlock0 = config.sourceChannelCount * config.depthwiseChannelMultiplierBlock0Step0;  // the channel count of the first block (Block 0).

    if ( config.stepCountPerBlock <= 0 ) { // Not ShuffleNetV2, Not MobileNetV2.

      // The height of processed image will be reduced a little for any depthwise filter larger than 1x1.
      let heightReducedPerBlock = config.depthwiseFilterHeight - 1;

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 1, pad = "valid" ).
      this.blockCount = Math.floor( differenceHeight / heightReducedPerBlock );

      // Channel count only be expanded by channel multiplier of depthwise convolution of step 0 of block 0.
      this.totalChannelExpansionFactor = config.depthwiseChannelMultiplierBlock0Step0;

    } else {  // ShuffleNetV2 or MobileNetV2. Halven per block.

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 2, pad = "same" ).
//      this.blockCount = Math.floor( Math.log2( sourceHeight ) );
      this.blockCount = Math.ceil( Math.log2( config.sourceHeight ) );

//!!! wrong
//       // Channel count is expanded both by channel multiplier of depthwise convolution of step 0 of block 0
//       // and by every block (half height x width and double channel count).
//       this.totalChannelExpansionFactor = depthwiseChannelMultiplierBlock0Step0 * Math.pow( 2, this.blockCount );

      // Channel count is expanded by every block (half height x width and double channel count).
      this.totalChannelExpansionFactor = Math.pow( 2, this.blockCount );
    }

    let nextBlockInputChannelCount = config.sourceChannelCount;
    let nextBlockDepthwiseChannelMultiplier = config.depthwiseChannelMultiplierBlock0Step0; // Only block 0 can have ( depthwise channel multiplier > 1 ).

    let nextKeepInputTensor = bKeepInputTensor; // Only step 0 may or may not keep the input tensor according to caller's necessary.

    this.blocks = new Array( this.blockCount );
    for ( let i = 0; i < this.blockCount; ++i )
    {
      let block = new ConvBlock.Base();
      block.init(
        config.sourceHeight, config.sourceWidth, nextBlockInputChannelCount,
        config.stepCountPerBlock,
        config.bChannelShuffler,
        config.pointwise1ChannelCountRate,
        config.strAvgMaxConv, config.depthwiseFilterHeight, nextBlockDepthwiseChannelMultiplier, config.bBias, config.nActivationId,
        config.nActivationIdAtBlockEnd,
        nextKeepInputTensor
      );

      this.blocks[ i ] = block;
      nextBlockInputChannelCount = block.outputChannelCount; // Using previous block's output channel count as next block's input channel count.
      nextBlockDepthwiseChannelMultiplier = 1;               // Except block 0, all other blocks' depthwise channel multiplier should be 1.
      nextKeepInputTensor = false;                           // All blocks (except block 0) should not keep (and should dispose) the input tensor.
    }

    let block0 = this.blocks[ 0 ];
    {
      let step0 = block0.step0;
      let stepLast = block0.stepLast;

      // e.g. "C24_24__DConv_101x101_DBias_RELU__PConv_PBias_RELU__Block_1__Step_1"
      this.structure = `C${config.sourceChannelCount}_${config.channelCountBlock0}`

        + `${ ( step0.bPointwise1 ) ? "__PConv1(x" + config.pointwise1ChannelCountRate + ")" : "" }`
        + `${ ( step0.bPointwise1 && step0.bPointwise1Bias ) ? ( "_PBias1" ) : "" }`
        + `${ ( step0.bPointwise1 && step0.pointwise1ActivationFunction ) ? ( "_" + step0.pointwise1ActivationName ) : "" }`

        + `${ ( step0.bDepthwise ) ? `__D${config.strAvgMaxConv}_${config.depthwiseFilterHeight}x${config.depthwiseFilterHeight}` : "" }`
        + `${ ( step0.bDepthwise && step0.bDepthwiseBias ) ? ( "_DBias" ) : "" }`
//!!! (2021/03/10 Remarked)
//        + `${ ( step0.bDepthwise && step0.depthwiseActivationFunction ) ? ( "_" + config.strActivationName ) : "" }`
        + `${ ( step0.bDepthwise && step0.depthwiseActivationFunction ) ? ( "_" + step0.depthwiseActivationName ) : "" }`

        + `${ ( step0.bPointwise2 ) ? "__PConv2" : "" }`
        + `${ ( step0.bPointwise2 && step0.bPointwise2Bias ) ? ( "_PBias2" ) : "" }`
        + `${ ( step0.bPointwise2 && step0.pointwise2ActivationFunction ) ? ( "_" + step0.pointwise2ActivationName ) : "" }`

        // If there are more (than 1) steps, show the activation function name (if exists) of the last step.
        //
        // Note: Is it possible that a step does not have the pointwise2 convolution?
        // Although the Conv/PointDepthPoint.js might have no pointwise2 convolution, the Conv/Block.js always has pointwise2 convolution.
        // So, the last activation function always is the activation function of the last step's pointwise2 convolution.
        + `${ ( config.stepCountPerBlock > 1 )
                ? ( ( stepLast.bPointwise2 && stepLast.pointwise2ActivationFunction )
                     ? ( "_" + stepLast.pointwise2ActivationName )
                     : "_NoLastActivation" )
                : "" }`

        + `__${this.blockCount}_Block`
        + `__${config.stepCountPerBlock}_Step`
        + `${ ( config.bChannelShuffler ) ? "__Shuffle" : ( ( config.stepCountPerBlock > 0 ) ? "__AddInput" : "" ) }`
        //+ `${ ( bKeepInputTensor ) ? "__KeepInput" : "" }`
      ;
    }

    this.sourceImageHeightWidth = [ block0.sourceHeight, block0.sourceWidth ];
  }

  disposeTensors() {
    if ( this.blocks ) {
      for ( let i = 0; i < this.blocks.length; ++i ) {
        let block = this.blocks[ i ];
        block.disposeTensors();
      }
      this.blocks = null;
    }
  }

  /**
   *
   * @param {tf.tensor3d} inputTensor
   *   The image which will be processed. This inputTensor may or may not be disposed according to init()'s bKeepInputTensor.
   * Its size should be this.sourceImageHeightWidth.
   *
   * @param {boolean} bReturn
   *   If true, the result tensor will be returned. Otherwise, the result tensor will be disposed.
   *
   * @return {tf.tensor3d}
   *   If ( bReturn == true ), return the result (new) tensor. If ( bReturn == false ), the result tensor will be disposed and nothing
   * will be returned. No matter in which case, all other intermediate tensors were disposed.
   */
  apply_and_destroy_or_keep( inputTensor, bReturn ) {
    let t = inputTensor;

    let block;
    for ( let i = 0; i < this.blocks.length; ++i ) {
      block = this.blocks[ i ];
      t = block.apply_and_destroy_or_keep( t );
    }

    if ( bReturn )
      return t;
    else
      t.dispose();
  }

}
<commit_msg>Update Net.js<commit_after>//import * as NetProgress from "./NetProgress.js";
import * as ConvBlock from "../Conv/Block.js";

export { Config, Base };

/**
 * A neural network's configuration.
 *
 * A special recommended configuration is 3x3 ShuffleNetV2 without explicit bias (but with implicit bias by cosine activation)
 * and without activation at the end of every block:
 *   - bChannelShuffler: true
 *   - pointwise1ChannelCountRate: 1
 *   - strAvgMaxConv: "Conv"
 *   - depthwiseFilterHeight: 3
 *   - depthwiseChannelMultiplierBlock0Step0: 1
 *   - bBias: false
 *   - nActivationId: ParamDesc.ActivationFunction.Ids.COS
 *   - nActivationIdAtBlockEnd: ParamDesc.ActivationFunction.Ids.NONE
 *
 * The cosine activation function can achieve impilcit bias. This is because depthwise and pointwise convolution can easily achieve zero
 * and ( cos( 0 ) == 1 ). A constant value (e.g. 1) becomes the bias of the next convolution. So there is not necessary to use explicit bias
 * which has worse performance (than without it).
 *
 * The recommended sourceChannelCount is 4. This is because source image is usually generated by tf.browser.fromPixels() and it handles
 * RGBA 4 channels faster than RGB 3 channels.
 *
 * The last PointDepthPoint's pointwise2 of every block without activation function
 * (i.e. nActivationIdAtBlockEnd == ParamDesc.ActivationFunction.Ids.NONE) could let the output of neural network be any
 * arbitrary value because it will not be restricted by the range of the activation function.
 */
class Config {
  /**
   * @param {number} depthwiseChannelMultiplierBlock0Step0
   *   The depthwise convolution of the first step (Step 0) of the first block (Block 0) will expand input channel by this factor.
   *
   * @see ConvBlock.Base.init
   */
  constructor(
    sourceHeight, sourceWidth, sourceChannelCount = 4,
    stepCountPerBlock,
    bChannelShuffler = true,
    pointwise1ChannelCountRate = 1,
    strAvgMaxConv = "Conv", depthwiseFilterHeight = 3, depthwiseChannelMultiplierBlock0Step0 = 1, bBias = false,
    nActivationId = ParamDesc.ActivationFunction.Ids.COS,
    nActivationIdAtBlockEnd = ParamDesc.ActivationFunction.Ids.NONE )
  {
    this.sourceHeight = sourceHeight;
    this.sourceWidth = sourceWidth;
    this.sourceChannelCount = sourceChannelCount;
    this.stepCountPerBlock = stepCountPerBlock;
    this.bChannelShuffler = bChannelShuffler;
    this.pointwise1ChannelCountRate = pointwise1ChannelCountRate;
    this.strAvgMaxConv = strAvgMaxConv;
    this.depthwiseFilterHeight = depthwiseFilterHeight;
    this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
    this.bBias = bBias;
    this.nActivationId = nActivationId;
    this.nActivationIdAtBlockEnd = nActivationIdAtBlockEnd;

    this.sourceHeightWidth = [ this.sourceHeight, this.sourceWidth ];
  }

  /**
   * @param {ImageData|HTMLCanvasElement} source_ImageData_or_Canvas
   *   The image or canvas which provides image.
   *
   * @param {boolean} bForceInt32
   *   If true, the dtype of the returned tf.tensor3d will guaranteed to be int32. Otherwise, the dtype of the returned tf.tensor3d
   * may be int32 or float32 (if resized). This is useful if the result will be used by an embedding layer (which only accepts
   * integer input).
   *
   * @return {tf.tensor3d}
   *   Return the tensor3d which is the scaled image from canvas. Its size will be this.sourceImageHeightWidth. Its channel count
   * will be this.config.sourceChannelCount.
   */
  create_ScaledSourceTensor_from_ImageData_or_Canvas( source_ImageData_or_Canvas, bForceInt32 ) {

    let sourceTensor = tf.browser.fromPixels( source_ImageData_or_Canvas, this.sourceChannelCount ); // dtype will be int32.

    // If the size (height x width) is as expected, use it directly. (dtype will still be int32.)
    if (   ( sourceTensor.shape[ 0 ] == this.sourceHeight )
        && ( sourceTensor.shape[ 1 ] == this.sourceWidth  ) )
      return sourceTensor;

    // Otherwise, resize to the default size (height x width) which is the input image size used for training the neural network.
    //
    // ( alignCorners = true ) for visual image resizing.
    let scaledSourceTensorFloat32;
    try {
      scaledSourceTensorFloat32 = tf.image.resizeBilinear( sourceTensor, this.sourceHeightWidth, true );
    } catch ( e ) {
      throw e; // e.g. out of (GPU) memory.
    } finally {
      sourceTensor.dispose();
    }

    if ( !bForceInt32 ) {
      return scaledSourceTensorFloat32;

    // Convert to int32 if necessary. (Because the tf.resize() result's dtype is float32.)
    try {
      let scaledSourceTensorInt32 = scaledSourceTensorFloat32.cast( 'int32' );
      return scaledSourceTensorInt32;
    } catch ( e ) {
      throw e; // e.g. out of (GPU) memory.
    } finally {
      scaledSourceTensorFloat32.dispose();
    }
  }

  /** The channel count of the first block (Block 0). */
  get channelCountBlock0() {
    return this.sourceChannelCount * this.depthwiseChannelMultiplierBlock0Step0;
  }

}

/**
 * A neural network composes of multiple blocks.
 *
 *
 *
 * @member {Config} config
 *   This neural network's configuration.
 *
 * @member {string} structure
 *   A string denote this neural network's structure (configuration).
 *
 * @member {number} totalChannelExpansionFactor
 *   The final output of this neural network will have ( totalChannelExpansionFactor * sourceChannelCount ) channel count.
 *
 * @member {number[]} sourceImageHeightWidth
 *   The size (i.e. [ height, width ]) of the source image. When apply_and_destroy_or_keep() is called, the input tensor should be this size.
 */
class Base {

  /**
   * @param {Config} config
   *   The configuration of this neural network.
   *
   * @param {boolean} bKeepInputTensor
   *   If true, apply_and_destroy_or_keep() will not dispose inputTensor (i.e. keep).
   *
   * @see ConvBlock.Base.init
   */
  init( config, bKeepInputTensor ) {

    this.disposeTensors();

    this.config = config;
    this.bKeepInputTensor = bKeepInputTensor;

    let targetHeight = 1; // The final output always has ( height x width ) = ( 1 x 1 ), i.e. only one pixel per channel.

    let differenceHeight = config.sourceHeight - targetHeight;
//    let filterWidth = depthwiseFilterHeight;

//  this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
//    this.channelCountBlock0 = config.sourceChannelCount * config.depthwiseChannelMultiplierBlock0Step0;  // the channel count of the first block (Block 0).

    if ( config.stepCountPerBlock <= 0 ) { // Not ShuffleNetV2, Not MobileNetV2.

      // The height of processed image will be reduced a little for any depthwise filter larger than 1x1.
      let heightReducedPerBlock = config.depthwiseFilterHeight - 1;

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 1, pad = "valid" ).
      this.blockCount = Math.floor( differenceHeight / heightReducedPerBlock );

      // Channel count only be expanded by channel multiplier of depthwise convolution of step 0 of block 0.
      this.totalChannelExpansionFactor = config.depthwiseChannelMultiplierBlock0Step0;

    } else {  // ShuffleNetV2 or MobileNetV2. Halven per block.

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 2, pad = "same" ).
//      this.blockCount = Math.floor( Math.log2( sourceHeight ) );
      this.blockCount = Math.ceil( Math.log2( config.sourceHeight ) );

//!!! wrong
//       // Channel count is expanded both by channel multiplier of depthwise convolution of step 0 of block 0
//       // and by every block (half height x width and double channel count).
//       this.totalChannelExpansionFactor = depthwiseChannelMultiplierBlock0Step0 * Math.pow( 2, this.blockCount );

      // Channel count is expanded by every block (half height x width and double channel count).
      this.totalChannelExpansionFactor = Math.pow( 2, this.blockCount );
    }

    let nextBlockInputChannelCount = config.sourceChannelCount;
    let nextBlockDepthwiseChannelMultiplier = config.depthwiseChannelMultiplierBlock0Step0; // Only block 0 can have ( depthwise channel multiplier > 1 ).

    let nextKeepInputTensor = bKeepInputTensor; // Only step 0 may or may not keep the input tensor according to caller's necessary.

    this.blocks = new Array( this.blockCount );
    for ( let i = 0; i < this.blockCount; ++i )
    {
      let block = new ConvBlock.Base();
      block.init(
        config.sourceHeight, config.sourceWidth, nextBlockInputChannelCount,
        config.stepCountPerBlock,
        config.bChannelShuffler,
        config.pointwise1ChannelCountRate,
        config.strAvgMaxConv, config.depthwiseFilterHeight, nextBlockDepthwiseChannelMultiplier, config.bBias, config.nActivationId,
        config.nActivationIdAtBlockEnd,
        nextKeepInputTensor
      );

      this.blocks[ i ] = block;
      nextBlockInputChannelCount = block.outputChannelCount; // Using previous block's output channel count as next block's input channel count.
      nextBlockDepthwiseChannelMultiplier = 1;               // Except block 0, all other blocks' depthwise channel multiplier should be 1.
      nextKeepInputTensor = false;                           // All blocks (except block 0) should not keep (and should dispose) the input tensor.
    }

    let block0 = this.blocks[ 0 ];
    {
      let step0 = block0.step0;
      let stepLast = block0.stepLast;

      // e.g. "C24_24__DConv_101x101_DBias_RELU__PConv_PBias_RELU__Block_1__Step_1"
      this.structure = `C${config.sourceChannelCount}_${config.channelCountBlock0}`

        + `${ ( step0.bPointwise1 ) ? "__PConv1(x" + config.pointwise1ChannelCountRate + ")" : "" }`
        + `${ ( step0.bPointwise1 && step0.bPointwise1Bias ) ? ( "_PBias1" ) : "" }`
        + `${ ( step0.bPointwise1 && step0.pointwise1ActivationFunction ) ? ( "_" + step0.pointwise1ActivationName ) : "" }`

        + `${ ( step0.bDepthwise ) ? `__D${config.strAvgMaxConv}_${config.depthwiseFilterHeight}x${config.depthwiseFilterHeight}` : "" }`
        + `${ ( step0.bDepthwise && step0.bDepthwiseBias ) ? ( "_DBias" ) : "" }`
//!!! (2021/03/10 Remarked)
//        + `${ ( step0.bDepthwise && step0.depthwiseActivationFunction ) ? ( "_" + config.strActivationName ) : "" }`
        + `${ ( step0.bDepthwise && step0.depthwiseActivationFunction ) ? ( "_" + step0.depthwiseActivationName ) : "" }`

        + `${ ( step0.bPointwise2 ) ? "__PConv2" : "" }`
        + `${ ( step0.bPointwise2 && step0.bPointwise2Bias ) ? ( "_PBias2" ) : "" }`
        + `${ ( step0.bPointwise2 && step0.pointwise2ActivationFunction ) ? ( "_" + step0.pointwise2ActivationName ) : "" }`

        // If there are more (than 1) steps, show the activation function name (if exists) of the last step.
        //
        // Note: Is it possible that a step does not have the pointwise2 convolution?
        // Although the Conv/PointDepthPoint.js might have no pointwise2 convolution, the Conv/Block.js always has pointwise2 convolution.
        // So, the last activation function always is the activation function of the last step's pointwise2 convolution.
        + `${ ( config.stepCountPerBlock > 1 )
                ? ( ( stepLast.bPointwise2 && stepLast.pointwise2ActivationFunction )
                     ? ( "_" + stepLast.pointwise2ActivationName )
                     : "_NoLastActivation" )
                : "" }`

        + `__${this.blockCount}_Block`
        + `__${config.stepCountPerBlock}_Step`
        + `${ ( config.bChannelShuffler ) ? "__Shuffle" : ( ( config.stepCountPerBlock > 0 ) ? "__AddInput" : "" ) }`
        //+ `${ ( bKeepInputTensor ) ? "__KeepInput" : "" }`
      ;
    }

    this.sourceImageHeightWidth = [ block0.sourceHeight, block0.sourceWidth ];
  }

  disposeTensors() {
    if ( this.blocks ) {
      for ( let i = 0; i < this.blocks.length; ++i ) {
        let block = this.blocks[ i ];
        block.disposeTensors();
      }
      this.blocks = null;
    }
  }

  /**
   *
   * @param {tf.tensor3d} inputTensor
   *   The image which will be processed. This inputTensor may or may not be disposed according to init()'s bKeepInputTensor.
   * Its size should be this.sourceImageHeightWidth.
   *
   * @param {boolean} bReturn
   *   If true, the result tensor will be returned. Otherwise, the result tensor will be disposed.
   *
   * @return {tf.tensor3d}
   *   If ( bReturn == true ), return the result (new) tensor. If ( bReturn == false ), the result tensor will be disposed and nothing
   * will be returned. No matter in which case, all other intermediate tensors were disposed.
   */
  apply_and_destroy_or_keep( inputTensor, bReturn ) {
    let t = inputTensor;

    let block;
    for ( let i = 0; i < this.blocks.length; ++i ) {
      block = this.blocks[ i ];
      t = block.apply_and_destroy_or_keep( t );
    }

    if ( bReturn )
      return t;
    else
      t.dispose();
  }

}
<|endoftext|>


<commit_before>'use strict';
(function(){
<% if(hasFilter('es6')) { %>
class <%= classedName %>Component {
  constructor() {
    this.message = 'Hello';
  }
}<% } else { %>
function <%= classedName %>Component() {
  this.message = 'Hello';
}<% } %>

angular.module('<%= scriptAppName %>')
  .component('<%= cameledName %>', {
    templateUrl: '<%= htmlUrl %>',
    controller: <%= classedName %>Component,
    controllerAs: <%= classedName %>
  });

})();
<commit_msg>style(template): adding newline (#41)<commit_after>'use strict';

(function(){
<% if(hasFilter('es6')) { %>
class <%= classedName %>Component {
  constructor() {
    this.message = 'Hello';
  }
}<% } else { %>
function <%= classedName %>Component() {
  this.message = 'Hello';
}<% } %>

angular.module('<%= scriptAppName %>')
  .component('<%= cameledName %>', {
    templateUrl: '<%= htmlUrl %>',
    controller: <%= classedName %>Component,
    controllerAs: <%= classedName %>
  });

})();
<|endoftext|>


<commit_before>import path from 'path';
import del from 'del';
import webpack from 'webpack';
import MemoryFS from 'memory-fs';

const modules = (config) => {
  return {
    rules: config.rules
      ? config.rules
      : config.loader
        ? [
            {
              test: config.loader.test || /\.js$/,
              use: {
                loader: path.resolve(__dirname, '../../src'),
                options: config.loader.options || {},
              },
            },
          ]
        : [],
  };
};

const plugins = (config) =>
  [
    new webpack.optimize.CommonsChunkPlugin({
      names: ['runtime'],
      minChunks: Infinity,
    }),
  ].concat(config.plugins || []);

const output = (config) => {
  return {
    path: path.resolve(
      __dirname,
      `../outputs/${config.output ? config.output : ''}`
    ),
    filename: '[name].js',
    chunkFilename: '[name].chunk.js',
  };
};

export default function(fixture, config, options) {
  config = {
    devtool: config.devtool || 'sourcemap',
    context: path.resolve(__dirname, '..', 'fixtures'),
    entry: `./${fixture}`,
    output: output(config),
    module: modules(config),
    plugins: plugins(config),
  };

  options = Object.assign({ output: false }, options);

  if (options.output) del.sync(config.output.path);

  const compiler = webpack(config);

  if (!options.output) compiler.outputFileSystem = new MemoryFS();

  return new Promise((resolve, reject) =>
    compiler.run((err, stats) => {
      if (err) reject(err);

      resolve(stats);
    })
  );
}
<commit_msg>refactor: default test helper<commit_after>import path from 'path';
import del from 'del';
import webpack from 'webpack';
import MemoryFS from 'memory-fs';

const modules = (config) => {
  return {
    rules: config.rules
      ? config.rules
      : config.loader
        ? [
            {
              test: config.loader.test || /\.js$/,
              use: {
                loader: path.resolve(__dirname, '../../src'),
                options: config.loader.options || {},
              },
            },
          ]
        : [],
  };
};

const plugins = (config) => [].concat(config.plugins || []);

const output = (config) => {
  return {
    path: path.resolve(
      __dirname,
      `../outputs/${config.output ? config.output : ''}`
    ),
    filename: '[name].js',
    chunkFilename: '[name].chunk.js',
  };
};

export default function(fixture, config, options) {
  config = {
    mode: 'development',
    devtool: config.devtool || 'sourcemap',
    context: path.resolve(__dirname, '..', 'fixtures'),
    entry: `./${fixture}`,
    output: output(config),
    module: modules(config),
    plugins: plugins(config),
  };

  options = Object.assign({ output: false }, options);

  if (options.output) {
    del.sync(config.output.path);
  }

  const compiler = webpack(config);

  if (!options.output) {
    compiler.outputFileSystem = new MemoryFS();
  }

  return new Promise((resolve, reject) =>
    compiler.run((error, stats) => {
      if (error) {
        reject(error);
      }

      return resolve(stats);
    })
  );
}
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

let TARGET = process.env.npm_lifecycle_event;

let common = {

  entry: path.join(__dirname, 'src/app/app.js'),

  module: {
    preLoaders: [],
    loaders: [{
      test: /\.js$/,
      loaders: ['ng-annotate', 'babel'],
      exclude: /node_modules/
    },
    {
      test: /\.html$/,
      loader: 'raw'
    }<% if (cssPreprocessor === 'sass') { %>,
    {
      test: /\.scss$/,
      loaders: ['style', 'css', 'sass']
    }<% } else if (cssPreprocessor === 'less') { %>,
    {
      test: /\.less$/,
      loaders: ['style', 'css', 'less']
    }<% } else { %>,
    {
      test: /\.css$/,
      loaders: ['style', 'css']
    }<% } %>]
  },

  plugins: [
    new HtmlWebpackPlugin({
      template: './src/public/index.html',
      inject: 'body'
    })
  ],

  devServer: {
    contentBase: './src/public',
    stats: 'minimal'
  }
};

// Development
if (TARGET === 'start') {
  module.exports = merge(common, {

  });
}

// Production
if (TARGET === 'build') {
  module.exports = merge(common, {
    output: {
      path: __dirname + '/dist',
      publicPath: '/',
      filename: '[name].[hash].js',
      chunkFilename: '[name].[hash].js'
    },

    plugins: [
      new webpack.NoErrorsPlugin(),
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.UglifyJsPlugin(),
      new CopyWebpackPlugin([{
        from: __dirname + '/src/public'
      }])
    ],
  });
}

// Test
if (TARGET === 'test') {
  module.exports = merge(common, {

  });
}
<commit_msg>feat(styles): Add extract-text-plugin in webpack conf<commit_after>'use strict';

const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

let TARGET = process.env.npm_lifecycle_event;

let common = {

  entry: path.join(__dirname, 'src/app/app.js'),

  module: {
    preLoaders: [],
    loaders: [{
      test: /\.js$/,
      loaders: ['ng-annotate', 'babel'],
      exclude: /node_modules/
    },
    {
      test: /\.html$/,
      loader: 'raw'
    }]
  },

  plugins: [
    new HtmlWebpackPlugin({
      template: './src/public/index.html',
      inject: 'body'
    })
  ],

  devServer: {
    contentBase: './src/public',
    stats: 'minimal'
  }
};

// Development
if (TARGET === 'start') {
  module.exports = merge.smart(common, {
    module: {
      loaders: [{
        test: /\.js$/,
        loaders: ['ng-annotate', 'babel'],
        exclude: /node_modules/
      },
      {
        test: /\.html$/,
        loader: 'raw'
      }<% if (cssPreprocessor === 'sass') { %>,
      {
        test: /\.scss$/,
        loaders: ['style-loader', 'css-loader', 'sass-loader']
      }<% } else if (cssPreprocessor === 'less') { %>,
      {
        test: /\.less$/,
        loaders: ['style-loader', 'css-loader', 'less-loader']
      }<% } else { %>,
      {
        test: /\.css$/,
        loaders: ['style-loader', 'css-loader']
      }<% } %>]
    }
  });
}

// Production
if (TARGET === 'build') {
  module.exports = merge.smart(common, {
    output: {
      path: __dirname + '/dist',
      publicPath: '/',
      filename: '[name].[hash].js',
      chunkFilename: '[name].[hash].js'
    },

    module: {
      loaders: [<% if (cssPreprocessor === 'sass') { %>
        {
          test: /\.scss$/,
          loader: ExtractTextPlugin.extract('style-loader', 'css-loader!sass-loader')
        }<% } else if (cssPreprocessor === 'less') { %>
        {
          test: /\.less$/,
          loader: ExtractTextPlugin.extract('style-loader', 'css-loader!less-loader')
        }<% } else { %>
        {
          test: /\.css$/,
          loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
        }<% } %>
      ]
    },

    plugins: [
      new webpack.NoErrorsPlugin(),
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.UglifyJsPlugin(),
      new CopyWebpackPlugin([{
        from: __dirname + '/src/public'
      }]),
      new ExtractTextPlugin('[name].[hash].css')
    ],
  });
}

// Test
if (TARGET === 'test') {
  module.exports = merge.smart(common, {

  });
}
<|endoftext|>


<commit_before>require('../helper');

const server = require('../../app/server')();
const assert = require('../support/assert');

describe('query-multipart', function() {
    it('multipart form select', function(done){
        assert.response(server, {
            url: '/api/v1/sql',
            formData: {
                q: 'SELECT 2 as n'
            },
            headers: {host: 'vizzuality.cartodb.com'},
            method: 'POST'
        },{}, function(err, res) {
            assert.ifError(err);
            const response = JSON.parse(res.body);
            assert.equal(!!response.time, true);
            assert.strictEqual(response.total_rows, 1);
            assert.deepStrictEqual(response.rows, [{n:2}]);
            done();
        });
    });
});
<commit_msg>improve test message<commit_after>require('../helper');

const server = require('../../app/server')();
const assert = require('../support/assert');

describe('query-multipart', function() {
    it('make query from a multipart form', function(done){
        assert.response(server, {
            url: '/api/v1/sql',
            formData: {
                q: 'SELECT 2 as n'
            },
            headers: {host: 'vizzuality.cartodb.com'},
            method: 'POST'
        },{}, function(err, res) {
            assert.ifError(err);
            const response = JSON.parse(res.body);
            assert.equal(!!response.time, true);
            assert.strictEqual(response.total_rows, 1);
            assert.deepStrictEqual(response.rows, [{n:2}]);
            done();
        });
    });
});
<|endoftext|>


<commit_before>require('../support/test_helper');

const assert = require('../support/assert');
const redis = require('redis');
const RedisPool = require('redis-mpool');
const cartodbRedis = require('cartodb-redis');
const TestClient = require('../support/test-client');
const UserLimitsApi = require('../../lib/cartodb/api/user_limits_api');
const rateLimitMiddleware = require('../../lib/cartodb/middleware/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimitMiddleware;

let userLimitsApi;
let rateLimit;
let redisClient;
let testClient;
let keysToDelete = ['user:localhost:mapviews:global'];
const user = 'localhost';

const query = `
    SELECT
        ST_Transform('SRID=4326;POINT(-180 85.05112877)'::geometry, 3857) the_geom_webmercator,
        1 cartodb_id,
        2 val
`;

const createMapConfig = ({
    version = '1.6.0',
    type = 'cartodb',
    sql = query,
    cartocss = TestClient.CARTOCSS.POINTS,
    cartocss_version = '2.3.0',
    interactivity = 'cartodb_id',
    countBy = 'cartodb_id'
} = {}) => ({
    version,
    layers: [{
        type,
        options: {
            source: {
                id: 'a0'
            },
            cartocss,
            cartocss_version,
            interactivity
        }
    }],
    analyses: [
        {
            id: 'a0',
            type: 'source',
            params: {
                query: sql
            }
        }
    ],
    dataviews: {
        count: {
            source: {
                id: 'a0'
            },
            type: 'formula',
            options: {
                column: countBy,
                operation: 'count'
            }
        }
    }
});

function setLimit(count, period, burst) {
    redisClient.SELECT(8, err => {
        if (err) {
            return;
        }

        const key = `limits:rate:store:${user}:maps:${RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS}`;
        redisClient.rpush(key, burst);
        redisClient.rpush(key, count);
        redisClient.rpush(key, period);
        keysToDelete.push(key);
    });
}

function getReqAndRes() {
    return {
        req: {},
        res: {
            headers: {},
            set(headers) {
                this.headers = headers;
            },
            locals: {
                user: 'localhost'
            }
        }
    };
}

function assertGetLayergroupRequest (status, limit, remaining, reset, retry, done = null) {
    const response = {
        status,
        headers: {
            'Content-Type': 'application/json; charset=utf-8',
            'X-Rate-Limit-Limit': limit,
            'X-Rate-Limit-Remaining': remaining,
            'X-Rate-Limit-Reset': reset,
            'X-Rate-Limit-Retry-After': retry
        }
    };

    testClient.getLayergroup({ response }, err => {
        assert.ifError(err);
        if (done) {
            setTimeout(done, 1000);
        }
    });
}

function assertRateLimitRequest (status, limit, remaining, reset, retry, done = null) {
    const { req, res } = getReqAndRes();
    rateLimit(req, res, function (err) {
        assert.deepEqual(res.headers, {
            "X-Rate-Limit-Limit": limit,
            "X-Rate-Limit-Remaining": remaining,
            "X-Rate-Limit-Reset": reset,
            "X-Rate-Limit-Retry-After": retry
        });

        if(status === 200) {
            assert.ifError(err);
        } else {
            assert.ok(err);
            assert.equal(err.message, 'You are over the limits.');
            assert.equal(err.http_status, 429);
        }

        if (done) {
            setTimeout(done, 1000);
        }
    });
}

describe('rate limit', function() {
    before(function() {
        global.environment.enabledFeatures.rateLimitsEnabled = true;
        global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = true;

        redisClient = redis.createClient(global.environment.redis.port);
        testClient = new TestClient(createMapConfig(), 1234);
    });

    after(function() {
        global.environment.enabledFeatures.rateLimitsEnabled = false;
        global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = false;
    });

    afterEach(function(done) {
        keysToDelete.forEach( key => {
            redisClient.del(key);
        });

        redisClient.SELECT(0, () => {
            redisClient.del('user:localhost:mapviews:global');

            redisClient.SELECT(5, () => {
                redisClient.del('user:localhost:mapviews:global');
                done();
            });
        });
    });

    it('should not be rate limited', function (done) {
        const count = 1;
        const period = 1;
        const burst = 1;
        setLimit(count, period, burst);

        assertGetLayergroupRequest(200, '2', '1', '1', '-1', done);
    });

    it("1 req/sec: 2 req/seg should be limited", function(done) {
        const count = 1;
        const period = 1;
        const burst = 1;
        setLimit(count, period, burst);

        assertGetLayergroupRequest(200, '2', '1', '1', '-1');
        setTimeout( () => assertGetLayergroupRequest(200, '2', '0', '1', '-1'), 250);
        setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '0'),  500);
        setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '0'),  750);
        setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '0'),  950);
        setTimeout( () => assertGetLayergroupRequest(200, '2', '0', '1', '-1', done), 1050);
    });

});

describe('rate limit middleware', function () {
    before(function (done) {
        global.environment.enabledFeatures.rateLimitsEnabled = true;
        global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = true;

        const redisPool = new RedisPool(global.environment.redis);
        const metadataBackend = cartodbRedis({ pool: redisPool });
        userLimitsApi = new UserLimitsApi(metadataBackend, {
            limits: {
                rateLimitsEnabled: global.environment.enabledFeatures.rateLimitsEnabled
            }
        });
        rateLimit = rateLimitMiddleware(userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS);

        redisClient = redis.createClient(global.environment.redis.port);
        testClient = new TestClient(createMapConfig(), 1234);

        const count = 1;
        const period = 1;
        const burst = 0;
        setLimit(count, period, burst);

        setTimeout(done, 1000);
    });

    after(function () {
        global.environment.enabledFeatures.rateLimitsEnabled = false;
        global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = false;

        keysToDelete.forEach(key => {
            redisClient.del(key);
        });
    });

    it("1 req/sec: 2 req/seg should be limited", function (done) {
        assertRateLimitRequest(200, 1, 0, 1, -1);
        setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 250);
        setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 500);
        setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 750);
        setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 950);
        setTimeout( () => assertRateLimitRequest(200, 1, 0, 1, -1, done), 1050);
    });

    it("1 req/sec: 2 req/seg should be limited, removing SHA script from Redis", function (done) {
        userLimitsApi.metadataBackend.redisCmd(
            8,
            'SCRIPT',
            ['FLUSH'],
            function () {
                assertRateLimitRequest(200, 1, 0, 1, -1);
                setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 500);
                setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 500);
                setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 750);
                setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 950);
                setTimeout( () => assertRateLimitRequest(200, 1, 0, 1, -1, done), 1050);
            }
        );
    });
});
<commit_msg>Updating headers on tests<commit_after>require('../support/test_helper');

const assert = require('../support/assert');
const redis = require('redis');
const RedisPool = require('redis-mpool');
const cartodbRedis = require('cartodb-redis');
const TestClient = require('../support/test-client');
const UserLimitsApi = require('../../lib/cartodb/api/user_limits_api');
const rateLimitMiddleware = require('../../lib/cartodb/middleware/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimitMiddleware;

let userLimitsApi;
let rateLimit;
let redisClient;
let testClient;
let keysToDelete = ['user:localhost:mapviews:global'];
const user = 'localhost';

const query = `
    SELECT
        ST_Transform('SRID=4326;POINT(-180 85.05112877)'::geometry, 3857) the_geom_webmercator,
        1 cartodb_id,
        2 val
`;

const createMapConfig = ({
    version = '1.6.0',
    type = 'cartodb',
    sql = query,
    cartocss = TestClient.CARTOCSS.POINTS,
    cartocss_version = '2.3.0',
    interactivity = 'cartodb_id',
    countBy = 'cartodb_id'
} = {}) => ({
    version,
    layers: [{
        type,
        options: {
            source: {
                id: 'a0'
            },
            cartocss,
            cartocss_version,
            interactivity
        }
    }],
    analyses: [
        {
            id: 'a0',
            type: 'source',
            params: {
                query: sql
            }
        }
    ],
    dataviews: {
        count: {
            source: {
                id: 'a0'
            },
            type: 'formula',
            options: {
                column: countBy,
                operation: 'count'
            }
        }
    }
});

function setLimit(count, period, burst) {
    redisClient.SELECT(8, err => {
        if (err) {
            return;
        }

        const key = `limits:rate:store:${user}:maps:${RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS}`;
        redisClient.rpush(key, burst);
        redisClient.rpush(key, count);
        redisClient.rpush(key, period);
        keysToDelete.push(key);
    });
}

function getReqAndRes() {
    return {
        req: {},
        res: {
            headers: {},
            set(headers) {
                this.headers = headers;
            },
            locals: {
                user: 'localhost'
            }
        }
    };
}

function assertGetLayergroupRequest (status, limit, remaining, reset, retry, done = null) {
    const response = {
        status,
        headers: {
            'Content-Type': 'application/json; charset=utf-8',
            'Carto-Rate-Limit-Limit': limit,
            'Carto-Rate-Limit-Remaining': remaining,
            'Carto-Rate-Limit-Reset': reset,
            'Retry-After': retry
        }
    };

    testClient.getLayergroup({ response }, err => {
        assert.ifError(err);
        if (done) {
            setTimeout(done, 1000);
        }
    });
}

function assertRateLimitRequest (status, limit, remaining, reset, retry, done = null) {
    const { req, res } = getReqAndRes();
    rateLimit(req, res, function (err) {
        assert.deepEqual(res.headers, {
            "Carto-Rate-Limit-Limit": limit,
            "Carto-Rate-Limit-Remaining": remaining,
            "Carto-Rate-Limit-Reset": reset,
            "Retry-After": retry
        });

        if(status === 200) {
            assert.ifError(err);
        } else {
            assert.ok(err);
            assert.equal(err.message, 'You are over the limits.');
            assert.equal(err.http_status, 429);
        }

        if (done) {
            setTimeout(done, 1000);
        }
    });
}

describe('rate limit', function() {
    before(function() {
        global.environment.enabledFeatures.rateLimitsEnabled = true;
        global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = true;

        redisClient = redis.createClient(global.environment.redis.port);
        testClient = new TestClient(createMapConfig(), 1234);
    });

    after(function() {
        global.environment.enabledFeatures.rateLimitsEnabled = false;
        global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = false;
    });

    afterEach(function(done) {
        keysToDelete.forEach( key => {
            redisClient.del(key);
        });

        redisClient.SELECT(0, () => {
            redisClient.del('user:localhost:mapviews:global');

            redisClient.SELECT(5, () => {
                redisClient.del('user:localhost:mapviews:global');
                done();
            });
        });
    });

    it('should not be rate limited', function (done) {
        const count = 1;
        const period = 1;
        const burst = 1;
        setLimit(count, period, burst);

        assertGetLayergroupRequest(200, '2', '1', '1', '-1', done);
    });

    it("1 req/sec: 2 req/seg should be limited", function(done) {
        const count = 1;
        const period = 1;
        const burst = 1;
        setLimit(count, period, burst);

        assertGetLayergroupRequest(200, '2', '1', '1', '-1');
        setTimeout( () => assertGetLayergroupRequest(200, '2', '0', '1', '-1'), 250);
        setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '0'),  500);
        setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '0'),  750);
        setTimeout( () => assertGetLayergroupRequest(429, '2', '0', '1', '0'),  950);
        setTimeout( () => assertGetLayergroupRequest(200, '2', '0', '1', '-1', done), 1050);
    });

});

describe('rate limit middleware', function () {
    before(function (done) {
        global.environment.enabledFeatures.rateLimitsEnabled = true;
        global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = true;

        const redisPool = new RedisPool(global.environment.redis);
        const metadataBackend = cartodbRedis({ pool: redisPool });
        userLimitsApi = new UserLimitsApi(metadataBackend, {
            limits: {
                rateLimitsEnabled: global.environment.enabledFeatures.rateLimitsEnabled
            }
        });
        rateLimit = rateLimitMiddleware(userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS);

        redisClient = redis.createClient(global.environment.redis.port);
        testClient = new TestClient(createMapConfig(), 1234);

        const count = 1;
        const period = 1;
        const burst = 0;
        setLimit(count, period, burst);

        setTimeout(done, 1000);
    });

    after(function () {
        global.environment.enabledFeatures.rateLimitsEnabled = false;
        global.environment.enabledFeatures.rateLimitsByEndpoint.anonymous = false;

        keysToDelete.forEach(key => {
            redisClient.del(key);
        });
    });

    it("1 req/sec: 2 req/seg should be limited", function (done) {
        assertRateLimitRequest(200, 1, 0, 1, -1);
        setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 250);
        setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 500);
        setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 750);
        setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 950);
        setTimeout( () => assertRateLimitRequest(200, 1, 0, 1, -1, done), 1050);
    });

    it("1 req/sec: 2 req/seg should be limited, removing SHA script from Redis", function (done) {
        userLimitsApi.metadataBackend.redisCmd(
            8,
            'SCRIPT',
            ['FLUSH'],
            function () {
                assertRateLimitRequest(200, 1, 0, 1, -1);
                setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 500);
                setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 500);
                setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 750);
                setTimeout( () => assertRateLimitRequest(429, 1, 0, 0, 0), 950);
                setTimeout( () => assertRateLimitRequest(200, 1, 0, 1, -1, done), 1050);
            }
        );
    });
});
<|endoftext|>


<commit_before>'use strict';

// mocha defines to avoid JSHint breakage
/* global describe, it, before, beforeEach, after, afterEach */

var assert = require('../../utils/assert.js');
var server = require('../../utils/server.js');
var preq   = require('preq');

var testPage = {
    title: 'User:GWicke%2F_restbase_test',
    revision: '646859921',
    html: "<!DOCTYPE html>\n<meta property=\"mw:articleNamespace\" content=\"2\"/><link rel=\"dc:replaces\" resource=\"mwr:revision/0\"/><meta property=\"dc:modified\" content=\"2015-02-12T22:30:30.000Z\"/><meta about=\"mwr:user/11429869\" property=\"dc:title\" content=\"GWicke\"/><link rel=\"dc:contributor\" resource=\"mwr:user/11429869\"/><meta property=\"mw:revisionSHA1\" content=\"6417e5e59b2975e65eebb5104ea572913a61db7e\"/><meta property=\"dc:description\" content=\"selser test page\"/><meta property=\"mw:parsoidVersion\" content=\"0\"/><link rel=\"dc:isVersionOf\" href=\"//en.wikipedia.org/wiki/User%3AGWicke/_restbase_test\"/><title>User:GWicke/_restbase_test</title><base href=\"//en.wikipedia.org/wiki/\"/><link rel=\"stylesheet\" href=\"//en.wikipedia.org/w/load.php?modules=mediawiki.legacy.commonPrint,shared|mediawiki.skinning.elements|mediawiki.skinning.content|mediawiki.skinning.interface|skins.vector.styles|site|mediawiki.skinning.content.parsoid&only=styles&skin=vector\"/>
Selser test
",
    wikitext: '
Selser test'
};

describe('transform api', function() {
    this.timeout(20000);

    before(function () { return server.start(); });

    it('html2html', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/html/to/html/' + testPage.title
                + '/' + testPage.revision,
            body: {
                html: testPage.html
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            var pattern = /
Selser test<\/div>/;
            if (!pattern.test(res.body)) {
                throw new Error('Expected pattern in response: ' + pattern
                        + '\nSaw: ' + JSON.stringify(res, null, 2));
            }
            assert.deepEqual(res.headers['content-type'],
                    'text/html;profile=mediawiki.org/specs/html/1.0.0');
        });
    });

    it('html2html with bodyOnly', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/html/to/html/' + testPage.title
                + '/' + testPage.revision,
            body: {
                html: testPage.html,
                bodyOnly: true
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            var pattern = /
Selser test<\/div>/;
            if (!pattern.test(res.body)) {
                throw new Error('Expected pattern in response: ' + pattern
                        + '\nSaw: ' + JSON.stringify(res, null, 2));
            }
            assert.deepEqual(res.headers['content-type'],
                    'text/html;profile=mediawiki.org/specs/html/1.0.0');
        });
    });

    it('wt2html', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/wikitext/to/html/User:GWicke%2F_restbase_test',
            body: {
                wikitext: '== Heading =='
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            assert.deepEqual(res.headers['content-type'],
                    'text/html;profile=mediawiki.org/specs/html/1.0.0');
            var pattern = /
 Heading <\/h2>/;
            if (!pattern.test(res.body)) {
                throw new Error('Expected pattern in response: ' + pattern
                        + '\nSaw: ' + res.body);
            }
        });
    });

    it('wt2html with bodyOnly', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/wikitext/to/html/User:GWicke%2F_restbase_test',
            body: {
                wikitext: '== Heading ==',
                bodyOnly: true
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            assert.deepEqual(res.headers['content-type'],
                    'text/html;profile=mediawiki.org/specs/html/1.0.0');
            var pattern = /^
 Heading <\/h2>$/;
            if (!pattern.test(res.body)) {
                throw new Error('Expected pattern in response: ' + pattern
                        + '\nSaw: ' + res.body);
            }
        });
    });

    it('html2wt, no-selser', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/html/to/wikitext/User:GWicke%2F_restbase_test',
            body: {
                html: 'The modified HTML'
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            assert.deepEqual(res.body, 'The modified HTML');
            assert.deepEqual(res.headers['content-type'],
                    'text/plain;profile=mediawiki.org/specs/wikitext/1.0.0');
        });
    });

//    it('html2wt, selser', function () {
//        return preq.post({
//            uri: server.config.baseURL
//                + '/transform/html/to/wikitext/' + testPage.title
//                + '/' + testPage.revision,
//            body: {
//                html: testPage.html
//            }
//        })
//        .then(function (res) {
//            assert.deepEqual(res.status, 200);
//            assert.deepEqual(res.body, testPage.wikitext);
//            assert.deepEqual(res.headers['content-type'],
//                    'text/plain;profile=mediawiki.org/specs/wikitext/1.0.0');
//        });
//    });

});

/* TODO: actually implement wikitext fetching
describe('storage-backed transform api', function() {
    this.timeout(20000);

    before(function () { return server.start(); });

    it('should load a specific title/revision from storage to send as the "original"', function () {
        return preq.post({
            uri: server.config.baseURL + '/transform/html/to/wikitext/Main_Page/1',
            headers: { 'content-type': 'application/json' },
            body: {
                headers: {
                  'content-type': 'text/html;profile=mediawiki.org/specs/html/1.0.0'
                },
                body: 'The modified HTML'
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            assert.deepEqual(res.body, {
                wikitext: {
                    headers: {
                        'content-type': 'text/plain;profile=mediawiki.org/specs/wikitext/1.0.0'
                    },
                    body: 'The modified HTML'
                }
            });
        });
    });

});
*/
<commit_msg>Use assert.contentType in tests<commit_after>'use strict';

// mocha defines to avoid JSHint breakage
/* global describe, it, before, beforeEach, after, afterEach */

var assert = require('../../utils/assert.js');
var server = require('../../utils/server.js');
var preq   = require('preq');

var testPage = {
    title: 'User:GWicke%2F_restbase_test',
    revision: '646859921',
    html: "<!DOCTYPE html>\n<meta property=\"mw:articleNamespace\" content=\"2\"/><link rel=\"dc:replaces\" resource=\"mwr:revision/0\"/><meta property=\"dc:modified\" content=\"2015-02-12T22:30:30.000Z\"/><meta about=\"mwr:user/11429869\" property=\"dc:title\" content=\"GWicke\"/><link rel=\"dc:contributor\" resource=\"mwr:user/11429869\"/><meta property=\"mw:revisionSHA1\" content=\"6417e5e59b2975e65eebb5104ea572913a61db7e\"/><meta property=\"dc:description\" content=\"selser test page\"/><meta property=\"mw:parsoidVersion\" content=\"0\"/><link rel=\"dc:isVersionOf\" href=\"//en.wikipedia.org/wiki/User%3AGWicke/_restbase_test\"/><title>User:GWicke/_restbase_test</title><base href=\"//en.wikipedia.org/wiki/\"/><link rel=\"stylesheet\" href=\"//en.wikipedia.org/w/load.php?modules=mediawiki.legacy.commonPrint,shared|mediawiki.skinning.elements|mediawiki.skinning.content|mediawiki.skinning.interface|skins.vector.styles|site|mediawiki.skinning.content.parsoid&only=styles&skin=vector\"/>
Selser test
",
    wikitext: '
Selser test'
};

describe('transform api', function() {
    this.timeout(20000);

    before(function () { return server.start(); });

    it('html2html', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/html/to/html/' + testPage.title
                + '/' + testPage.revision,
            body: {
                html: testPage.html
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            var pattern = /
Selser test<\/div>/;
            if (!pattern.test(res.body)) {
                throw new Error('Expected pattern in response: ' + pattern
                        + '\nSaw: ' + JSON.stringify(res, null, 2));
            }
            assert.contentType(res, 'text/html;profile=mediawiki.org/specs/html/1.0.0');
        });
    });

    it('html2html with bodyOnly', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/html/to/html/' + testPage.title
                + '/' + testPage.revision,
            body: {
                html: testPage.html,
                bodyOnly: true
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            var pattern = /
Selser test<\/div>/;
            if (!pattern.test(res.body)) {
                throw new Error('Expected pattern in response: ' + pattern
                        + '\nSaw: ' + JSON.stringify(res, null, 2));
            }
            assert.contentType(res, 'text/html;profile=mediawiki.org/specs/html/1.0.0');
        });
    });

    it('wt2html', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/wikitext/to/html/User:GWicke%2F_restbase_test',
            body: {
                wikitext: '== Heading =='
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            assert.contentType(res, 'text/html;profile=mediawiki.org/specs/html/1.0.0');
            var pattern = /
 Heading <\/h2>/;
            if (!pattern.test(res.body)) {
                throw new Error('Expected pattern in response: ' + pattern
                        + '\nSaw: ' + res.body);
            }
        });
    });

    it('wt2html with bodyOnly', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/wikitext/to/html/User:GWicke%2F_restbase_test',
            body: {
                wikitext: '== Heading ==',
                bodyOnly: true
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            assert.contentType(res, 'text/html;profile=mediawiki.org/specs/html/1.0.0');
            var pattern = /^
 Heading <\/h2>$/;
            if (!pattern.test(res.body)) {
                throw new Error('Expected pattern in response: ' + pattern
                        + '\nSaw: ' + res.body);
            }
        });
    });

    it('html2wt, no-selser', function () {
        return preq.post({
            uri: server.config.baseURL
                + '/transform/html/to/wikitext/User:GWicke%2F_restbase_test',
            body: {
                html: 'The modified HTML'
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            assert.deepEqual(res.body, 'The modified HTML');
            assert.contentType(res, 'text/plain;profile=mediawiki.org/specs/wikitext/1.0.0');
        });
    });

//    it('html2wt, selser', function () {
//        return preq.post({
//            uri: server.config.baseURL
//                + '/transform/html/to/wikitext/' + testPage.title
//                + '/' + testPage.revision,
//            body: {
//                html: testPage.html
//            }
//        })
//        .then(function (res) {
//            assert.deepEqual(res.status, 200);
//            assert.deepEqual(res.body, testPage.wikitext);
//            assert.contentType(res, 'text/plain;profile=mediawiki.org/specs/wikitext/1.0.0');
//        });
//    });

});

/* TODO: actually implement wikitext fetching
describe('storage-backed transform api', function() {
    this.timeout(20000);

    before(function () { return server.start(); });

    it('should load a specific title/revision from storage to send as the "original"', function () {
        return preq.post({
            uri: server.config.baseURL + '/transform/html/to/wikitext/Main_Page/1',
            headers: { 'content-type': 'application/json' },
            body: {
                headers: {
                  'content-type': 'text/html;profile=mediawiki.org/specs/html/1.0.0'
                },
                body: 'The modified HTML'
            }
        })
        .then(function (res) {
            assert.deepEqual(res.status, 200);
            assert.deepEqual(res.body, {
                wikitext: {
                    headers: {
                        'content-type': 'text/plain;profile=mediawiki.org/specs/wikitext/1.0.0'
                    },
                    body: 'The modified HTML'
                }
            });
        });
    });

});
*/
<|endoftext|>


<commit_before>'use strict';

describe('Middleware/Navigation', function () {

    var path = require('path');
    var rootPath = path.resolve(path.join(__dirname, '../../'));
    var appMock = require(path.resolve(path.join(rootPath, 'test', 'mocks', 'appMock')));
    var navigation = require(path.resolve(path.join(rootPath, 'lib', 'middleware', 'navigation')));
    var navigationFilePath = path.resolve(path.join(rootPath, 'test', 'mocks', '.dist', 'navigation'));
    var sut, req, res, mock;

    beforeEach(function () {
        mock = appMock();
        sut = navigation(navigationFilePath);
    });

    it('should be defined', function () {
        expect(sut).toBeDefined();
        expect(sut.getTree).toBeDefined();
        expect(sut.getList).toBeDefined();
        expect(sut.getTopList).toBeDefined();
        expect(sut.getSubTree).toBeDefined();
        expect(sut.getSubList).toBeDefined();
    });

    describe('.getTree()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should return a navigation', function () {
            var navArr = sut.getTree(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[0];
            expect(nav.title).toBe('HOME');
            expect(nav.children).toBeDefined();
            expect(nav.children.length).toBe(3);
            expect(nav.children[0].title).toBe('LOCALE');

            nav = nav.children[2];
            expect(nav.title).toBe('CONTACT');
            expect(nav.children).toBeDefined();
            expect(nav.children.length).toBe(1);
            expect(nav.children[0].title).toBe('EDIT');
        });

        it('should return a navigation with param "req.body.current" = null', function () {
            req.body.current = null;

            var navArr = sut.getTree(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[0];
            expect(nav.title).toBe('HOME');
            expect(nav.children).toBeDefined();
            expect(nav.children.length).toBe(3);
            expect(nav.children[0].title).toBe('LOCALE');
        });
    });

    describe('.getList()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should return a flat navigation', function () {
            var navArr = sut.getList(req, res);
            expect(navArr.length).toBe(7);

            var nav = navArr[1];
            expect(nav.title).toBe('LOCALE');
        });

        it('should return a flat navigation with param "req.body.current" = null', function () {
            req.body.current = null;

            var navArr = sut.getList(req, res);
            expect(navArr.length).toBe(7);

            var nav = navArr[1];
            expect(nav.title).toBe('LOCALE');
        });
    });

    describe('.getTopList()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should return a navigation only from top level', function () {
            var navArr = sut.getTopList(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[1];
            expect(nav.title).toBe('PROJECT1');
        });

        it('should return a navigation only from top level with param "req.body.current" = null', function () {
            req.body.current = null;

            var navArr = sut.getTopList(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[1];
            expect(nav.title).toBe('PROJECT1');
        });
    });

    describe('.getSubTree()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should throw an error if param "req.body.top" = null', function () {
            req.body.top = null;

            var func = function () {sut.getSubTree(req, res);};
            expect(func).toThrow();
        });

        it('should return a sub navigation from a top level', function () {
            req.body.top = 'HOME';

            var navArr = sut.getSubTree(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[1];
            expect(nav.title).toBe('ABOUT');
        });

        it('should return an empty navigation from a top level which does not exists', function () {
            req.body.top = 'ABC';

            var navArr = sut.getSubTree(req, res);
            expect(navArr.length).toBe(0);
        });

        it('should return the main sub navigation from a top level with param "req.body.current" = null', function () {
            req.body.current = null;
            req.body.top = 'HOME';

            var navArr = sut.getSubTree(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[1];
            expect(nav.title).toBe('ABOUT');
        });
    });

    describe('.getSubList()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should throw an error if param "req.body.top" = null', function () {
            req.body.top = null;

            var func = function () {sut.getSubList(req, res);};
            expect(func).toThrow();
        });

        it('should return a sub navigation from a top level', function () {
            req.body.top = 'HOME';

            var navArr = sut.getSubList(req, res);
            expect(navArr.length).toBe(4);

            var nav = navArr[1];
            expect(nav.title).toBe('ABOUT');

            nav = navArr[3];
            expect(nav.title).toBe('EDIT');
        });

        it('should return an undefined from a top level which does not exists', function () {
            req.body.top = 'ABC';

            var navArr = sut.getSubList(req, res);
            expect(navArr).toBeUndefined();
        });

        it('should return an undefined from a top level with param "req.body.current" = null', function () {
            req.body.current = null;
            req.body.top = 'HOME';

            var navArr = sut.getSubList(req, res);
            expect(navArr.length).toBe(4);

            var nav = navArr[1];
            expect(nav.title).toBe('ABOUT');

            nav = navArr[3];
            expect(nav.title).toBe('EDIT');
        });
    });
});
<commit_msg>feat(middleware/navigation.js): feature 700 - navigation.js - unit tests angepasst<commit_after>'use strict';

describe('Middleware/Navigation', function () {

    var path = require('path');
    var rootPath = path.resolve(path.join(__dirname, '../../'));
    var appMock = require(path.resolve(path.join(rootPath, 'test', 'mocks', 'appMock')));
    var navigation = require(path.resolve(path.join(rootPath, 'lib', 'middleware', 'navigation')));
    var navigationFilePath = path.resolve(path.join(rootPath, 'test', 'mocks', '.dist', 'navigation'));
    var sut, req, res, mock;

    beforeEach(function () {
        mock = appMock();
        sut = navigation(navigationFilePath);
    });

    it('should be defined', function () {
        expect(sut).toBeDefined();
        expect(sut.getTree).toBeDefined();
        expect(sut.getList).toBeDefined();
        expect(sut.getTopList).toBeDefined();
        expect(sut.getSubTree).toBeDefined();
        expect(sut.getSubList).toBeDefined();
    });

    describe('.getTree()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should return a navigation', function () {
            var navArr = sut.getTree(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[0];
            expect(nav.title).toBe('HOME');
            expect(nav.children).toBeDefined();
            expect(nav.children.length).toBe(3);
            expect(nav.children[0].title).toBe('LOCALE');

            nav = nav.children[2];
            expect(nav.title).toBe('CONTACT');
            expect(nav.children).toBeDefined();
            expect(nav.children.length).toBe(1);
            expect(nav.children[0].title).toBe('EDIT');
        });

        it('should return a navigation with param "req.body.current" = null', function () {
            req.body.current = null;

            var navArr = sut.getTree(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[0];
            expect(nav.title).toBe('HOME');
            expect(nav.children).toBeDefined();
            expect(nav.children.length).toBe(3);
            expect(nav.children[0].title).toBe('LOCALE');
        });
    });

    describe('.getList()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should return a flat navigation', function () {
            var navArr = sut.getList(req, res);
            expect(navArr.length).toBe(7);

            var nav = navArr[1];
            expect(nav.title).toBe('LOCALE');
        });

        it('should return a flat navigation with param "req.body.current" = null', function () {
            req.body.current = null;

            var navArr = sut.getList(req, res);
            expect(navArr.length).toBe(7);

            var nav = navArr[1];
            expect(nav.title).toBe('LOCALE');
        });
    });

    describe('.getTopList()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should return a navigation only from top level', function () {
            var navArr = sut.getTopList(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[1];
            expect(nav.title).toBe('PROJECT1');
        });

        it('should return a navigation only from top level with param "req.body.current" = null', function () {
            req.body.current = null;

            var navArr = sut.getTopList(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[1];
            expect(nav.title).toBe('PROJECT1');
        });
    });

    describe('.getSubTree()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should throw an error if param "req.body.top" = null', function () {
            req.body.top = null;

            var func = function () {sut.getSubTree(req, res);};
            expect(func).toThrow();
        });

        it('should return a sub navigation from a top level', function () {
            req.body.top = 'HOME';

            var navArr = sut.getSubTree(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[1];
            expect(nav.title).toBe('ABOUT');
        });

        it('should return an empty navigation from a top level which does not exists', function () {
            req.body.top = 'ABC';

            var navArr = sut.getSubTree(req, res);
            expect(navArr.length).toBe(0);
        });

        it('should return the main sub navigation from a top level with param "req.body.current" = null', function () {
            req.body.current = null;
            req.body.top = 'HOME';

            var navArr = sut.getSubTree(req, res);
            expect(navArr.length).toBe(3);

            var nav = navArr[1];
            expect(nav.title).toBe('ABOUT');
        });
    });

    describe('.getSubList()', function () {
        beforeEach(function () {
            req = mock.req;
            res = mock.res;
        });

        it('should throw an error if param "req.body.top" = null', function () {
            req.body.top = null;

            var func = function () {sut.getSubList(req, res);};
            expect(func).toThrow();
        });

        it('should return a sub navigation from a top level', function () {
            req.body.top = 'HOME';

            var navArr = sut.getSubList(req, res);
            expect(navArr.length).toBe(4);

            var nav = navArr[1];
            expect(nav.title).toBe('ABOUT');

            nav = navArr[3];
            expect(nav.title).toBe('EDIT');
        });

        it('should return an undefined from a top level which does not exists', function () {
            req.body.top = 'ABC';

            var navArr = sut.getSubList(req, res);
            expect(navArr).toBeUndefined();
        });

        it('should return the main top level including sublist with param "req.body.current" = null', function () {
            req.body.current = null;
            req.body.top = 'HOME';

            var navArr = sut.getSubList(req, res);
            expect(navArr.length).toBe(4);

            var nav = navArr[1];
            expect(nav.title).toBe('ABOUT');

            nav = navArr[3];
            expect(nav.title).toBe('EDIT');
        });
    });
});
<|endoftext|>