<commit_before>import Service from '@ember/service';

import { get, getWithDefault, set } from '@ember/object';
import { isPresent, isNone, isEmpty } from '@ember/utils';
import { getOwner } from '@ember/application';
import { resolve, Promise, reject } from 'rsvp';
import { assign } from '@ember/polyfills';
import { KJUR, KEYUTIL } from 'jsrsasign';
import { inject as service } from '@ember/service';

import AccessToken from "../-lib/access-token";
import TempSession from '../-lib/temp-session';

import { DefaultConfigurator } from "../-lib/configurator";
import { tracked } from "@glimmer/tracking";

/**
 * @class GatekeeperService
 *
 * The service for the gatekeeper framework.
 */
export default class GatekeeperService extends Service {
  constructor () {
    super (...arguments);

    this.configurator = this.defaultConfigurator;
  }

  @service
  router;

  @service
  storage;

  @tracked
  configurator;

  /**
   * Create a new instance of a DefaultConfigurator for the service.
   *
   * @returns {DefaultConfigurator}
   */
  get defaultConfigurator () {
    let ENV = getOwner (this).resolveRegistration ('config:environment');
    let config = get (ENV, 'gatekeeper');

    return new DefaultConfigurator (config);
  }

  get storageLocation () {
    return this.configurator.storageLocation;
  }

  storageKey (key) {
    return `storage.${this.storageLocation}.${key}`;
  }

  get _tokenString () {
    return get (this, this.storageKey ('gatekeeper_ct'));
  }

  set _tokenString (value) {
    return set (this, this.storageKey ('gatekeeper_ct'), value);
  }

  /// The singleton access token for the gatekeeper.
  get accessToken () {
    return AccessToken.fromString (this._tokenString);
  }

  /**
   * Test if the client has been authenticated.
   *
   * @returns {boolean}
   */
  get isAuthenticated () {
    return this.accessToken.isValid && !this.accessToken.isExpired;
  }

  get isUnauthenticated () {
    return !this.isAuthenticated;
  }

  get baseUrl () {
    return this.configurator.baseUrl;
  }

  get tokenOptions () {
    return this.configurator.tokenOptions;
  }

  get authenticateUrl () {
    return this.configurator.authenticateUrl;
  }

  computeUrl (relativeUrl) {
    return `${this.baseUrl}${relativeUrl}`;
  }

  /**
   * Authenticate the client.
   *
   * @param opts
   * @param force
   */
  authenticate (opts, force = false) {
    if (this.isAuthenticated && !force) {
      return Promise.resolve ();
    }

    return this._requestClientToken (opts).then (token => {
      this._tokenString = token.access_token;

      // Notify all observers that our token has changed.
      this.notifyPropertyChange ('_tokenString');
    });
  }

  /**
   * Unauthenticate the client on the platform.
   */
  unauthenticate () {
    return this.signOut (this.accessToken.toString());
  }

  /**
   * Sign out a token on the system.
   */
  signOut (token) {
    const url = this.computeUrl ('/oauth2/logout');

    const options = {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${token}`
      }
    };

    return fetch (url, options).then ((response) => {
      if (response.ok) {
        return response.json ();
      }
      else {
        return response.json ().then (result => Promise.reject (result));
      }
    });
  }

  /**
   * Initiate the forgot password process.
   */
  forgotPassword (email, opts) {
    return this.authenticate (opts)
      .then (() => {
        let url = this.computeUrl ('/password/forgot');

        let opts = {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${this.accessToken.toString ()}`
          },
          body: JSON.stringify ({ email })
        };

        return fetch (url, opts);
      })
      .then (response => response.ok ? response.json () : this._handleErrorResponse (response));
  }

  /**
   * Reset the password for the user.
   */
  resetPassword (token, password) {
    let url = this.computeUrl ('/password/reset');

    let options = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify ({'reset-password': {token, password}})
    };

    return fetch (url, options).then (response => response.ok ? response.json () : this._handleErrorResponse (response));
  }

  get publicKey () {
    const { publicCert } = this.configurator;

    return isPresent (publicCert) ? KEYUTIL.getKey (publicCert) : null;
  }

  get secretOrPublicKey () {
    return this.configurator.secretOrPublicKey;
  }

  get verifyOptions () {
    return this.configurator.verifyOptions;
  }

  /**
   * Create a temporary session for the current client.
   *
   * @param payload
   * @param options
   * @returns {*}
   */
  createTempSession (payload, options) {
    const tokenOptions = Object.assign ({grant_type: 'temp'}, {
      payload,
      options,
      access_token: this.accessToken.toString ()
    });

    return this._requestToken (this.authenticateUrl, tokenOptions)
      .then (({access_token}) => Object.assign ({}, { accessToken: access_token, gatekeeper: this}))
      .then (opts => TempSession.create (opts));
  }

  /**
   * Verify a token. If there is no secret or public key, then the token is assumed
   * to be valid.
   *
   * @param token
   */
  verifyToken (token) {
    if (isNone (token)) {
      return resolve (true);
    }

    return new Promise ((resolve, reject) => {
      const { secretOrPublicKey, verifyOptions } = this;

      if (isEmpty (secretOrPublicKey)) {
        return resolve (true);
      }

      const verified = KJUR.jws.JWS.verifyJWT (token, secretOrPublicKey, verifyOptions);
      return verified ? resolve (true) : reject (new Error ('The access token could not be verified.'));
    });
  }

  /**
   * Perform the redirect to for the user. This will either take the user to the original
   * page they accessed before being redirected to the sign-in page, or the start route
   * if no redirect is present.
   */
  redirect (redirectTo = this.redirectTo) {
    if (isNone (redirectTo)) {
      // There is no redirect url. So, we either transition to the default route, or we
      // transition to the index.
      let ENV = getOwner (this).resolveRegistration ('config:environment');
      redirectTo = getWithDefault (ENV, 'gatekeeper.startRoute', 'index');
    }

    this.router.replaceWith (redirectTo);
  }

  get redirectTo () {
    let currentURL = this.router.currentURL;
    let [, query] = currentURL.split ('?');

    if (isNone (query)) {
      return null;
    }

    let params = query.split ('&');
    return params.reduce ((accum, param) => {
      let [name, value] = param.split ('=');
      return name === 'redirect' ? decodeURIComponent (value) : accum;
    }, null);
  }

  /**
   * Requesting an access token from the server.
   *
   * @param opts
   * @returns {RSVP.Promise}
   * @private
   */
  _requestClientToken (opts) {
    const url = this.computeUrl ('/oauth2/token');
    const tokenOptions = this.tokenOptions;
    const data = assign ({grant_type: 'client_credentials'}, tokenOptions, opts);

    const options = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify (data)
    };

    return fetch (url, options)
      .then ((response) => response.ok ? response.json () : this._handleErrorResponse (response));
  }

  _handleErrorResponse (response) {
    return response.json ().then (reject);
  }
}
<commit_msg>chore: refactored code<commit_after>import Service from '@ember/service';

import { get, getWithDefault, set } from '@ember/object';
import { isPresent, isNone, isEmpty } from '@ember/utils';
import { getOwner } from '@ember/application';
import { resolve, Promise, reject, all } from 'rsvp';
import { assign } from '@ember/polyfills';
import { KJUR, KEYUTIL } from 'jsrsasign';
import { inject as service } from '@ember/service';

import AccessToken from "../-lib/access-token";
import TempSession from '../-lib/temp-session';

import { DefaultConfigurator } from "../-lib/configurator";
import { tracked } from "@glimmer/tracking";

/**
 * @class GatekeeperService
 *
 * The service for the gatekeeper framework.
 */
export default class GatekeeperService extends Service {
  constructor () {
    super (...arguments);

    this.configurator = this.defaultConfigurator;
  }

  @service
  router;

  @service
  storage;

  @tracked
  configurator;

  /**
   * Create a new instance of a DefaultConfigurator for the service.
   *
   * @returns {DefaultConfigurator}
   */
  get defaultConfigurator () {
    let ENV = getOwner (this).resolveRegistration ('config:environment');
    let config = get (ENV, 'gatekeeper');

    return new DefaultConfigurator (config);
  }

  get storageLocation () {
    return this.configurator.storageLocation;
  }

  storageKey (key) {
    return `storage.${this.storageLocation}.${key}`;
  }

  get _tokenString () {
    return get (this, this.storageKey ('gatekeeper_ct'));
  }

  set _tokenString (value) {
    return set (this, this.storageKey ('gatekeeper_ct'), value);
  }

  /// The singleton access token for the gatekeeper.
  get accessToken () {
    return AccessToken.fromString (this._tokenString);
  }

  /**
   * Test if the client has been authenticated.
   *
   * @returns {boolean}
   */
  get isAuthenticated () {
    return this.accessToken.isValid && !this.accessToken.isExpired;
  }

  get isUnauthenticated () {
    return !this.isAuthenticated;
  }

  get baseUrl () {
    return this.configurator.baseUrl;
  }

  get tokenOptions () {
    return this.configurator.tokenOptions;
  }

  get authenticateUrl () {
    return this.configurator.authenticateUrl;
  }

  computeUrl (relativeUrl) {
    return `${this.baseUrl}${relativeUrl}`;
  }

  /**
   * Authenticate the client.
   *
   * @param opts
   * @param force
   */
  authenticate (opts, force = false) {
    if (this.isAuthenticated && !force) {
      return Promise.resolve ();
    }

    return this._requestClientToken (opts).then (token => {
      this._tokenString = token.access_token;

      // Notify all observers that our token has changed.
      this.notifyPropertyChange ('_tokenString');
    });
  }

  /**
   * Unauthenticate the client on the platform.
   */
  unauthenticate () {
    return this.signOut (this.accessToken.toString());
  }

  /**
   * Sign out a token on the system.
   */
  signOut (token) {
    const url = this.computeUrl ('/oauth2/logout');

    const options = {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${token}`
      }
    };

    return fetch (url, options).then ((response) => {
      if (response.ok) {
        return response.json ();
      }
      else {
        return response.json ().then (result => Promise.reject (result));
      }
    });
  }

  /**
   * Initiate the forgot password process.
   */
  forgotPassword (email, opts) {
    return this.authenticate (opts)
      .then (() => {
        let url = this.computeUrl ('/password/forgot');

        let opts = {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${this.accessToken.toString ()}`
          },
          body: JSON.stringify ({ email })
        };

        return fetch (url, opts);
      })
      .then (response => response.ok ? response.json () : this._handleErrorResponse (response));
  }

  /**
   * Reset the password for the user.
   */
  resetPassword (token, password) {
    let url = this.computeUrl ('/password/reset');

    let options = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify ({'reset-password': {token, password}})
    };

    return fetch (url, options).then (response => response.ok ? response.json () : this._handleErrorResponse (response));
  }

  get publicKey () {
    const { publicCert } = this.configurator;

    return isPresent (publicCert) ? KEYUTIL.getKey (publicCert) : null;
  }

  get secretOrPublicKey () {
    return this.configurator.secretOrPublicKey;
  }

  get verifyOptions () {
    return this.configurator.verifyOptions;
  }

  /**
   * Create a temporary session for the current client.
   *
   * @param payload
   * @param options
   * @returns {*}
   */
  createTempSession (payload, options) {
    const tokenOptions = Object.assign ({grant_type: 'temp'}, {
      payload,
      options,
      access_token: this.accessToken.toString ()
    });

    return this._requestToken (this.authenticateUrl, tokenOptions)
      .then (res => Object.assign ({}, { accessToken: res.access_token, gatekeeper: this}))
      .then (opts => TempSession.create (opts));
  }

  /**
   * Verify a token. If there is no secret or public key, then the token is assumed
   * to be valid.
   *
   * @param token
   */
  verifyToken (token) {
    if (isNone (token)) {
      return resolve (true);
    }

    return new Promise ((resolve, reject) => {
      const { secretOrPublicKey, verifyOptions } = this;

      if (isEmpty (secretOrPublicKey)) {
        return resolve (true);
      }

      const verified = KJUR.jws.JWS.verifyJWT (token, secretOrPublicKey, verifyOptions);
      return verified ? resolve (true) : reject (new Error ('The access token could not be verified.'));
    });
  }

  /**
   * Perform the redirect to for the user. This will either take the user to the original
   * page they accessed before being redirected to the sign-in page, or the start route
   * if no redirect is present.
   */
  redirect (redirectTo = this.redirectTo) {
    if (isNone (redirectTo)) {
      // There is no redirect url. So, we either transition to the default route, or we
      // transition to the index.
      let ENV = getOwner (this).resolveRegistration ('config:environment');
      redirectTo = getWithDefault (ENV, 'gatekeeper.startRoute', 'index');
    }

    this.router.replaceWith (redirectTo);
  }

  get redirectTo () {
    let currentURL = this.router.currentURL;
    let [, query] = currentURL.split ('?');

    if (isNone (query)) {
      return null;
    }

    let params = query.split ('&');
    return params.reduce ((accum, param) => {
      let [name, value] = param.split ('=');
      return name === 'redirect' ? decodeURIComponent (value) : accum;
    }, null);
  }

  /**
   * Requesting an access token from the server.
   *
   * @param opts
   * @returns {RSVP.Promise}
   * @private
   */
  _requestClientToken (opts) {
    const url = this.computeUrl ('/oauth2/token');
    const options = Object.assign ({}, opts, { grant_type: 'client_credentials' });

    return this._requestToken (url, options);
  }

  _handleErrorResponse (response) {
    return response.json ().then (reject);
  }

  _requestToken (url, opts) {
    const data = Object.assign ({}, this.tokenOptions, opts);

    const options = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify (data)
    };

    return fetch (url, options)
      .then (response => {
        return response.json ().then (res => {
          if (response.ok) {
            let checks = [];

            if (isPresent (res.access_token)) {
              checks.push (this.verifyToken (res.access_token))
            }

            if (isPresent (res.refresh_token)) {
              checks.push (this.verifyToken (res.refresh_token))
            }

            return all (checks).then (() => res);
          }
          else {
            return Promise.reject (res);
          }
        });
      });
  }

}
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

/**
 * Update only expired packages (those with nextUpdate previous to current date)
 * (C) 2015 Diego Lafuente.
 */

// requires
require('prototypes');
var update = require('../lib/update.js');
var config = require('../config.js');
var Log = require('log');

// globals
var log = new Log(config.logLevel);

function update()
{
	var offset = process.argv[2] || 0;
	var all;
	// read all.json and apply offset
	log.info('loading all.json...');
	try
	{
		all = require('../all.json');
		delete all._updated;
	}
	catch(exception)
	{
		log.error('Could not parse all.json: ' + exception);
		process.exit(1);
	}
	log.info('all.json loaded');
	var names = Object.keys(all);
	log.info('All packages: ' + names.length);
	if (offset)
	{
		log.info('Offset ' + offset);
		for (var i=0; i<offset; i++)
		{
			delete all[names.shift()];
		}
	}
	log.info('All packages after offset: ' + names.length);
	update.goOver(all, function(error, result)
	{
		if (error)
		{
			log.error('Could not evaluate all: %s', error);
			process.exit(1);
		}
		log.info('Processed ' + result + ' chunks of approx ' + config.limit + ' elements each.');
		process.exit(0);
	});
}

update();

<commit_msg>all.json no longer needed. Simplifying class<commit_after>#!/usr/bin/env node
'use strict';

/**
 * Update only expired packages (those with nextUpdate previous to current date)
 * (C) 2015 Diego Lafuente.
 */

// requires
require('prototypes');
var update = require('../lib/update.js');
var config = require('../config.js');
var Log = require('log');

// globals
var log = new Log(config.logLevel);

function update()
{
	update.goOver(function(error, result)
	{
		if (error)
		{
			log.error('Could not evaluate all: %s', error);
			process.exit(1);
		}
		log.info('Processed ' + result + ' chunks of approx ' + config.limit + ' elements each.');
		process.exit(0);
	});
}

update();

<|endoftext|>


<commit_before>import React, {Component} from 'react';

/**
 * Default class for Image webp
 */
class Image extends Component {
    componentDidMount() {
        if (sessionStorage.getItem('react-webp') === null) {
            this.testWebP(this.setToSession());
        }
    }

    setToSession(support) {
        sessionStorage.setItem('react-webp', support ? '1' : '0');
    }

    testWebP(callback) {
        const webP = new Image();
        webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
        webP.onload = webP.onerror = function () {
            callback(webP.height === 2);
        };
    };

    /**
     * Render jsx to html
     * @returns {XML}
     */
    render() {
        const {src, webp} = this.props;
        const webpSupport = sessionStorage.getItem('react-webp');
        let image = null;

        if (webpSupport === '1') {
            image = ;
        } else if (webpSupport === '0') {
            image = ;
        }

        return image;
    }
}

export default Image;<commit_msg>add new property<commit_after>import React, {Component} from 'react';

/**
 * Default class for Image webp
 */
class Image extends Component {
    componentDidMount() {
        if (sessionStorage.getItem('react-webp') === null) {
            this.testWebP(this.setToSession());
        }
    }

    setToSession(support) {
        sessionStorage.setItem('react-webp', support ? '1' : '0');
    }

    testWebP(callback) {
        const webP = new Image();
        webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
        webP.onload = webP.onerror = function () {
            callback(webP.height === 2);
        };
    };

    /**
     * Render jsx to html
     * @returns {XML}
     */
    render() {
        const {src, webp, alt, title} = this.props;
        const webpSupport = sessionStorage.getItem('react-webp');
        let image = null;

        if (webpSupport === '1') {
            image = ;
        } else if (webpSupport === '0') {
            image = ;
        }

        return image;
    }
}

export default Image;<|endoftext|>


<commit_before>/**
 * if, unless, else-if, else-unless, else
 * A binder init function that creates a binder that shows or hides the element if the value is truthy or falsey.
 * Actually removes the element from the DOM when hidden, replacing it with a non-visible placeholder and not needlessly
 * executing bindings inside. Pass in the configuration values for the corresponding partner attributes for unless and
 * else, etc.
 */
module.exports = function(elseIfAttrName, elseAttrName, unlessAttrName, elseUnlessAttrName) {
  return {
    animated: true,
    priority: 150,

    compiled: function() {
      var element = this.element;
      var expressions = [ wrapIfExp(this.expression, this.name === unlessAttrName) ];
      var placeholder = document.createTextNode('');
      var node = element.nextElementSibling;
      this.element = placeholder;
      element.parentNode.replaceChild(placeholder, element);

      // Stores a template for all the elements that can go into this spot
      this.templates = [ this.fragments.createTemplate(element) ];

      // Pull out any other elements that are chained with this one
      while (node) {
        var next = node.nextElementSibling;
        var expression;
        if (node.hasAttribute(elseIfAttrName)) {
          expression = this.fragments.codifyExpression('attribute', node.getAttribute(elseIfAttrName), true);
          expressions.push(wrapIfExp(expression, false));
          node.removeAttribute(elseIfAttrName);
        } else if (node.hasAttribute(elseUnlessAttrName)) {
          expression = this.fragments.codifyExpression('attribute', node.getAttribute(elseUnlessAttrName), true);
          expressions.push(wrapIfExp(expression, true));
          node.removeAttribute(elseUnlessAttrName);
        } else if (node.hasAttribute(elseAttrName)) {
          node.removeAttribute(elseAttrName);
          next = null;
        } else {
          break;
        }

        node.remove();
        this.templates.push(this.fragments.createTemplate(node));
        node = next;
      }

      // An expression that will return an index. Something like this `expr ? 0 : expr2 ? 1 : expr3 ? 2 : 3`. This will
      // be used to know which section to show in the if/else-if/else grouping.
      this.expression = expressions.map(function(expr, index) {
        return expr + ' ? ' + index + ' : ';
      }).join('') + expressions.length;
    },

    updated: function(index) {
      // For performance provide an alternate code path for animation
      if (this.animate && this.context && !this.firstUpdate) {
        this.updatedAnimated(index);
      } else {
        this.updatedRegular(index);
      }
      this.firstUpdate = false;
    },

    attached: function() {
      if (this.showing) {
        this.showing.attached();
      }
    },

    detached: function() {
      if (this.showing) {
        this.showing.detached();
      }
    },

    add: function(view) {
      view.bind(this.context);
      this.element.parentNode.insertBefore(view, this.element.nextSibling);
      view.attached();
    },

    // Doesn't do much, but allows sub-classes to alter the functionality.
    remove: function(view) {
      view.dispose();
    },

    updatedRegular: function(index) {
      if (this.showing) {
        this.remove(this.showing);
        this.showing = null;
      }
      var template = this.templates[index];
      if (template) {
        this.showing = template.createView();
        this.add(this.showing);
      }
    },

    updatedAnimated: function(index) {
      this.lastValue = index;
      if (this.animating) {
        // Obsoleted, will change after animation is finished.
        this.showing.unbind();
        return;
      }

      if (this.showing) {
        this.animating = true;
        this.showing.unbind();
        this.animateOut(this.showing, function() {
          if (this.animating) {
            this.animating = false;

            if (this.showing) {
              // Make sure this wasn't unbound while we were animating (e.g. by a parent `if` that doesn't animate)
              this.remove(this.showing);
              this.showing = null;
            }

            if (this.context) {
              // finish by animating the new element in (if any), unless no longer bound
              this.updatedAnimated(this.lastValue);
            }
          }
        });
        return;
      }

      var template = this.templates[index];
      if (template) {
        this.showing = template.createView();
        this.add(this.showing);
        this.animating = true;
        this.animateIn(this.showing, function() {
          if (this.animating) {
            this.animating = false;
            // if the value changed while this was animating run it again
            if (this.lastValue !== index) {
              this.updatedAnimated(this.lastValue);
            }
          }
        });
      }
    },

    bound: function() {
      this.firstUpdate = true;
    },

    unbound: function() {
      if (this.showing) {
        this.showing.unbind();
      }
      this.lastValue = null;
      this.animating = false;
    }
  };
};

function wrapIfExp(expr, isUnless) {
  if (isUnless) {
    return '!(' + expr + ')';
  } else {
    return expr;
  }
}
<commit_msg>Fix if-animation when stacked up<commit_after>/**
 * if, unless, else-if, else-unless, else
 * A binder init function that creates a binder that shows or hides the element if the value is truthy or falsey.
 * Actually removes the element from the DOM when hidden, replacing it with a non-visible placeholder and not needlessly
 * executing bindings inside. Pass in the configuration values for the corresponding partner attributes for unless and
 * else, etc.
 */
module.exports = function(elseIfAttrName, elseAttrName, unlessAttrName, elseUnlessAttrName) {
  return {
    animated: true,
    priority: 150,

    compiled: function() {
      var element = this.element;
      var expressions = [ wrapIfExp(this.expression, this.name === unlessAttrName) ];
      var placeholder = document.createTextNode('');
      var node = element.nextElementSibling;
      this.element = placeholder;
      element.parentNode.replaceChild(placeholder, element);

      // Stores a template for all the elements that can go into this spot
      this.templates = [ this.fragments.createTemplate(element) ];

      // Pull out any other elements that are chained with this one
      while (node) {
        var next = node.nextElementSibling;
        var expression;
        if (node.hasAttribute(elseIfAttrName)) {
          expression = this.fragments.codifyExpression('attribute', node.getAttribute(elseIfAttrName), true);
          expressions.push(wrapIfExp(expression, false));
          node.removeAttribute(elseIfAttrName);
        } else if (node.hasAttribute(elseUnlessAttrName)) {
          expression = this.fragments.codifyExpression('attribute', node.getAttribute(elseUnlessAttrName), true);
          expressions.push(wrapIfExp(expression, true));
          node.removeAttribute(elseUnlessAttrName);
        } else if (node.hasAttribute(elseAttrName)) {
          node.removeAttribute(elseAttrName);
          next = null;
        } else {
          break;
        }

        node.remove();
        this.templates.push(this.fragments.createTemplate(node));
        node = next;
      }

      // An expression that will return an index. Something like this `expr ? 0 : expr2 ? 1 : expr3 ? 2 : 3`. This will
      // be used to know which section to show in the if/else-if/else grouping.
      this.expression = expressions.map(function(expr, index) {
        return expr + ' ? ' + index + ' : ';
      }).join('') + expressions.length;
    },

    updated: function(index) {
      // For performance provide an alternate code path for animation
      if (this.animate && this.context && !this.firstUpdate) {
        this.updatedAnimated(index);
      } else {
        this.updatedRegular(index);
      }
      this.firstUpdate = false;
    },

    attached: function() {
      if (this.showing) {
        this.showing.attached();
      }
    },

    detached: function() {
      if (this.showing) {
        this.showing.detached();
      }
    },

    add: function(view) {
      view.bind(this.context);
      this.element.parentNode.insertBefore(view, this.element.nextSibling);
      view.attached();
    },

    // Doesn't do much, but allows sub-classes to alter the functionality.
    remove: function(view) {
      view.dispose();
    },

    updatedRegular: function(index) {
      if (this.showing) {
        this.remove(this.showing);
        this.showing = null;
      }
      var template = this.templates[index];
      if (template) {
        this.showing = template.createView();
        this.add(this.showing);
      }
    },

    updatedAnimated: function(index) {
      this.lastValue = index;
      if (this.animating) {
        // Obsoleted, will change after animation is finished.
        this.showing.unbind();
        return;
      }

      if (this.showing) {
        this.animating = true;
        this.showing.unbind();
        this.animateOut(this.showing, function() {
          if (this.animating) {
            this.animating = false;

            if (this.showing) {
              // Make sure this wasn't unbound while we were animating (e.g. by a parent `if` that doesn't animate)
              this.remove(this.showing);
              this.showing = null;
            }

            if (this.context) {
              // finish by animating the new element in (if any), unless no longer bound
              this.updatedAnimated(this.lastValue);
            }
          }
        });
        return;
      }

      var template = this.templates[index];
      if (template) {
        this.showing = template.createView();
        this.add(this.showing);
        this.animating = true;
        this.animateIn(this.showing, function() {
          if (this.animating) {
            setTimeout(function() {
              this.animating = false;
              // if the value changed while this was animating run it again
              if (this.lastValue !== index) {
                  this.updatedAnimated(this.lastValue);
              }
            }.bind(this));
          }
        });
      }
    },

    bound: function() {
      this.firstUpdate = true;
    },

    unbound: function() {
      if (this.showing) {
        this.showing.unbind();
      }
      this.lastValue = null;
      this.animating = false;
    }
  };
};

function wrapIfExp(expr, isUnless) {
  if (isUnless) {
    return '!(' + expr + ')';
  } else {
    return expr;
  }
}
<|endoftext|>


<commit_before>"use strict";

function gsuiKeys() {
	var root = document.createElement( "div" );

	this._init();
	this.rootElement = root;
	this.rowElements = [];
	this._nlKeys = root.childNodes;
	this._nbOct = 0;
	root.className = "gsuiKeys";
	root.onmousedown = this._evmdRoot.bind( this );
}

gsuiKeys.prototype = {
	remove() {
		this.rootElement.remove();
		this.rowElements.length = 0;
	},
	octaves( start, nbOct ) {
		var root = this.rootElement,
			nbDiff = nbOct - this._nbOct;

		if ( nbDiff || this._octStart !== start ) {
			this._octStart = start;
			root.style.counterReset = "octave " + ( start + nbOct );
		}
		if ( nbDiff ) {
			this._nbOct = nbOct;
			if ( nbDiff > 0 ) {
				while ( nbDiff-- > 0 ) {
					root.append( document.importNode( gsuiKeys.octaveTemplate.content, true ) );
				}
				this.newRowElements = root.querySelectorAll( ".gsui-row" );
				this.newRowElements.forEach( function( el ) {
					el.remove();
				} );
				Array.prototype.push.apply( this.rowElements, this.newRowElements );
			} else {
				for ( nbDiff *= 12; nbDiff < 0; ++nbDiff ) {
					root.lastChild.remove();
					this.rowElements[ this.rowElements.length - 1 ].remove();
					this.rowElements.pop();
				}
			}
		}
	},

	// private:
	_init() {
		if ( !gsuiKeys.octaveTemplate ) {
			gsuiKeys.octaveTemplate = document.getElementById( "gsuiKeys-octave" );
			document.body.addEventListener( "mousemove", function( e ) {
				gsuiKeys._focused && gsuiKeys._focused._evmmRoot( e );
			} );
			document.body.addEventListener( "mouseup", function( e ) {
				gsuiKeys._focused && gsuiKeys._focused._evmuRoot( e );
			} );
		}
	},
	_isBlack( keyInd ) {
		return keyInd === 1 || keyInd === 3 || keyInd === 5 || keyInd === 8 || keyInd === 10;
	},
	_keydown( keyInd ) {
		var elKey = this._nlKeys[ keyInd ];

		if ( elKey ) {
			this._keyup();
			this._keyInd = keyInd;
			this._elKey = elKey;
			this._octNum = this._octStart + this._nbOct - 1 - ~~( keyInd / 12 );
			elKey.classList.add( "gsui-active" );
			this.onkeydown && this.onkeydown( elKey.dataset.key, this._octNum, this._gain );
		}
	},
	_keyup() {
		if ( this._elKey ) {
			this._elKey.classList.remove( "gsui-active" );
			this.onkeyup && this.onkeyup( this._elKey.dataset.key, this._octNum, this._gain );
		}
	},

	// events:
	_evmdRoot( e ) {
		if ( this._nbOct ) {
			var blackKeyBCR = this.rootElement.childNodes[ 1 ].getBoundingClientRect();

			this._rootTop = this.rootElement.getBoundingClientRect().top;
			this._blackKeyR = blackKeyBCR.right;
			this._blackKeyH = blackKeyBCR.height;
			this._gain = Math.min( e.layerX / ( e.target.clientWidth - 1 ), 1 );
			gsuiKeys._focused = this;
			this._evmmRoot( e );
		}
	},
	_evmuRoot( e ) {
		this._keyup();
		delete this._elKey;
		delete this._keyInd;
		delete gsuiKeys._focused;
	},
	_evmmRoot( e ) {
		var fKeyInd = ( e.clientY - this._rootTop ) / this._blackKeyH,
			iKeyInd = ~~fKeyInd;

		if ( e.clientX > this._blackKeyR && this._isBlack( ~~( iKeyInd % 12 ) ) ) {
			iKeyInd += fKeyInd - iKeyInd < .5 ? -1 : 1;
		}
		if ( this._keyInd !== iKeyInd ) {
			this._keydown( iKeyInd );
		}
	}
};
<commit_msg>gsuiKeys: remove the rowElements<commit_after>"use strict";

function gsuiKeys() {
	var root = document.createElement( "div" );

	this._init();
	this.rootElement = root;
	this.rowElements = [];
	this._nlKeys = root.childNodes;
	this._nbOct = 0;
	root.className = "gsuiKeys";
	root.onmousedown = this._evmdRoot.bind( this );
}

gsuiKeys.prototype = {
	remove() {
		this.rootElement.remove();
		this.rootElement.forEach( function( el ) {
			el.remove();
		} );
		this.rowElements.length = 0;
	},
	octaves( start, nbOct ) {
		var root = this.rootElement,
			nbDiff = nbOct - this._nbOct;

		if ( nbDiff || this._octStart !== start ) {
			this._octStart = start;
			root.style.counterReset = "octave " + ( start + nbOct );
		}
		if ( nbDiff ) {
			this._nbOct = nbOct;
			if ( nbDiff > 0 ) {
				while ( nbDiff-- > 0 ) {
					root.append( document.importNode( gsuiKeys.octaveTemplate.content, true ) );
				}
				this.newRowElements = root.querySelectorAll( ".gsui-row" );
				this.newRowElements.forEach( function( el ) {
					el.remove();
				} );
				Array.prototype.push.apply( this.rowElements, this.newRowElements );
			} else {
				for ( nbDiff *= 12; nbDiff < 0; ++nbDiff ) {
					root.lastChild.remove();
					this.rowElements[ this.rowElements.length - 1 ].remove();
					this.rowElements.pop();
				}
			}
		}
	},

	// private:
	_init() {
		if ( !gsuiKeys.octaveTemplate ) {
			gsuiKeys.octaveTemplate = document.getElementById( "gsuiKeys-octave" );
			document.body.addEventListener( "mousemove", function( e ) {
				gsuiKeys._focused && gsuiKeys._focused._evmmRoot( e );
			} );
			document.body.addEventListener( "mouseup", function( e ) {
				gsuiKeys._focused && gsuiKeys._focused._evmuRoot( e );
			} );
		}
	},
	_isBlack( keyInd ) {
		return keyInd === 1 || keyInd === 3 || keyInd === 5 || keyInd === 8 || keyInd === 10;
	},
	_keydown( keyInd ) {
		var elKey = this._nlKeys[ keyInd ];

		if ( elKey ) {
			this._keyup();
			this._keyInd = keyInd;
			this._elKey = elKey;
			this._octNum = this._octStart + this._nbOct - 1 - ~~( keyInd / 12 );
			elKey.classList.add( "gsui-active" );
			this.onkeydown && this.onkeydown( elKey.dataset.key, this._octNum, this._gain );
		}
	},
	_keyup() {
		if ( this._elKey ) {
			this._elKey.classList.remove( "gsui-active" );
			this.onkeyup && this.onkeyup( this._elKey.dataset.key, this._octNum, this._gain );
		}
	},

	// events:
	_evmdRoot( e ) {
		if ( this._nbOct ) {
			var blackKeyBCR = this.rootElement.childNodes[ 1 ].getBoundingClientRect();

			this._rootTop = this.rootElement.getBoundingClientRect().top;
			this._blackKeyR = blackKeyBCR.right;
			this._blackKeyH = blackKeyBCR.height;
			this._gain = Math.min( e.layerX / ( e.target.clientWidth - 1 ), 1 );
			gsuiKeys._focused = this;
			this._evmmRoot( e );
		}
	},
	_evmuRoot( e ) {
		this._keyup();
		delete this._elKey;
		delete this._keyInd;
		delete gsuiKeys._focused;
	},
	_evmmRoot( e ) {
		var fKeyInd = ( e.clientY - this._rootTop ) / this._blackKeyH,
			iKeyInd = ~~fKeyInd;

		if ( e.clientX > this._blackKeyR && this._isBlack( ~~( iKeyInd % 12 ) ) ) {
			iKeyInd += fKeyInd - iKeyInd < .5 ? -1 : 1;
		}
		if ( this._keyInd !== iKeyInd ) {
			this._keydown( iKeyInd );
		}
	}
};
<|endoftext|>


<commit_before>'use strict';
// 1.0.0

angular.module('amChartsDirective', []).directive('amChart', function() {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      options: '=',
      height: '=',
      width: '='
    },
    template: '

',
    link: function($scope, $el) {

      // use existing outer id to create new id
      var id = $el[0].id;
      $el.attr('id', id);
      var chart;

      // we can't render a chart without any data
      if ($scope.options.data) {
        var renderChart = function(amChartOptions) {
          var o = amChartOptions || $scope.options;

          // set height and width
          var height = $scope.height || '400px';
          var width = $scope.width || '600px';

          $el.css({
            'height': height,
            'width': width
          });

          // instantiate new chart object
          if (o.type === 'xy') {
            chart = o.theme ? new AmCharts.AmXYChart(AmCharts.themes[o.theme]) : new AmCharts.AmXYChart();
          } else {
            chart = o.theme ? new AmCharts.AmSerialChart(AmCharts.themes[o.theme]) : new AmCharts.AmSerialChart();
          }

          /** set some default values that amCharts doesnt provide **/
          chart.dataProvider = o.data;
          // if a category field is not specified, attempt to use the first field from an object in the array
          chart.categoryField = o.categoryField || Object.keys(o.data[0])[0];
          chart.startDuration = 0.5; // default animation length, because everyone loves a little pizazz

          // AutoMargin is on by default, but the default 20px all around seems to create unnecessary white space around the control
          chart.autoMargins = true;
          chart.marginTop = 0;
          chart.marginLeft = 0;
          chart.marginBottom = 0;
          chart.marginRight = 0;

          // modify default creditsPosition
          chart.creditsPosition = o.creditsPosition || 'top-right';

          var chartKeys = Object.keys(o);
          for (var i = 0; i < chartKeys.length; i++) {
            if (typeof o[chartKeys[i]] !== 'object' && typeof o[chartKeys[i]] !== 'function') {
              chart[chartKeys[i]] = o[chartKeys[i]];
            }
          }

          // Assign Category Axis Properties
          if (o.categoryAxis) {
            var categoryAxis = chart.categoryAxis;

            if (categoryAxis) {
              /* if we need to create any default values, we should assign them here */
              categoryAxis.parseDates = true;

              var keys = Object.keys(o.categoryAxis);
              for (var i = 0; i < keys.length; i++) {
                if (!angular.isObject(o.categoryAxis[keys[i]]) || angular.isArray(o.categoryAxis[keys[i]])) {
                  categoryAxis[keys[i]] = o.categoryAxis[keys[i]];
                } else {
                  console.log('Stripped categoryAxis obj ' + keys[i]);
                }
              }
              chart.categoryAxis = categoryAxis;
            }
          }

          // Create value axis

          /* if we need to create any default values, we should assign them here */

          var addValueAxis = function (a) {
            var valueAxis = new AmCharts.ValueAxis();

            var keys = Object.keys(a);
            for (var i = 0; i < keys.length; i++) {
              if (typeof a[keys[i]] !== 'object') {
                valueAxis[keys[i]] = a[keys[i]];
              }
            }
            chart.addValueAxis(valueAxis);
          };

          if (o.valueAxes && o.valueAxes.length > 0) {
            for (var i = 0; i < o.valueAxes.length; i++) {
              addValueAxis(o.valueAxes[i])
            }
          }

          //reusable function to create graph
          var addGraph = function (g) {
            var graph = new AmCharts.AmGraph();
            /** set some default values that amCharts doesnt provide **/
              // if a category field is not specified, attempt to use the second field from an object in the array as a default value
            graph.valueField = g.valueField || Object.keys(o.data[0])[1];
            graph.balloonText = '[[category]]: [[value]]';
            if (g) {
              var keys = Object.keys(g);
              // iterate over all of the properties in the graph object and apply them to the new AmGraph
              for (var i = 0; i < keys.length; i++) {
                graph[keys[i]] = g[keys[i]];
              }
            }
            chart.addGraph(graph);
          };

          // create the graphs
          if (o.graphs && o.graphs.length > 0) {
            for (var i = 0; i < o.graphs.length; i++) {
              addGraph(o.graphs[i]);
            }
          } else {
            addGraph();
          }

          var chartCursor = new AmCharts.ChartCursor();
          if (o.chartCursor) {
            var keys = Object.keys(o.chartCursor);
            for (var i = 0; i < keys.length; i++) {
              if (typeof o.chartCursor[keys[i]] !== 'object') {
                chartCursor[keys[i]] = o.chartCursor[keys[i]];
              }
            }
          }
          chart.addChartCursor(chartCursor);

          // WRITE
          chart.write(id);
        };

        // Render the chart
        renderChart();

        // EVENTS =========================================================================

        $scope.$on('amCharts.triggerChartAnimate', function(event, id){
          if (id === $el[0].id || !id) {
            chart.animateAgain();
          }
        });

        $scope.$on('amCharts.updateData', function(event, data, id){
          if (id === $el[0].id || !id){
            chart.dataProvider = data;
            chart.validateData();
          }

        });

        $scope.$on('amCharts.validateNow', function(event, validateData, skipEvents, id){
          if (id === $el[0].id || !id){
            chart.validateNow(validateData === undefined ? true : validateData,
              skipEvents === undefined ? false : skipEvents)
          }
        });

        $scope.$on('amCharts.renderChart', function(event, amChartOptions,  id){
          if (id === $el[0].id || !id) {
            renderChart(amChartOptions);
          }
        });

      }

    }
  };
});

<commit_msg>Add support for legend and chartScrollbar<commit_after>'use strict';
// 1.0.0

angular.module('amChartsDirective', []).directive('amChart', function() {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      options: '=',
      height: '=',
      width: '='
    },
    template: '

',
    link: function($scope, $el) {

      // use existing outer id to create new id
      var id = $el[0].id;
      $el.attr('id', id);
      var chart;

      // we can't render a chart without any data
      if ($scope.options.data) {
        var renderChart = function(amChartOptions) {
          var o = amChartOptions || $scope.options;

          // set height and width
          var height = $scope.height || '400px';
          var width = $scope.width || '600px';

          $el.css({
            'height': height,
            'width': width
          });

          // instantiate new chart object
          if (o.type === 'xy') {
            chart = o.theme ? new AmCharts.AmXYChart(AmCharts.themes[o.theme]) : new AmCharts.AmXYChart();
          } else {
            chart = o.theme ? new AmCharts.AmSerialChart(AmCharts.themes[o.theme]) : new AmCharts.AmSerialChart();
          }

          /** set some default values that amCharts doesnt provide **/
          chart.dataProvider = o.data;
          // if a category field is not specified, attempt to use the first field from an object in the array
          chart.categoryField = o.categoryField || Object.keys(o.data[0])[0];
          chart.startDuration = 0.5; // default animation length, because everyone loves a little pizazz

          // AutoMargin is on by default, but the default 20px all around seems to create unnecessary white space around the control
          chart.autoMargins = true;
          chart.marginTop = 0;
          chart.marginLeft = 0;
          chart.marginBottom = 0;
          chart.marginRight = 0;

          // modify default creditsPosition
          chart.creditsPosition = o.creditsPosition || 'top-right';

          var chartKeys = Object.keys(o);
          for (var i = 0; i < chartKeys.length; i++) {
            if (typeof o[chartKeys[i]] !== 'object' && typeof o[chartKeys[i]] !== 'function') {
              chart[chartKeys[i]] = o[chartKeys[i]];
            }
          }

          // Assign Category Axis Properties
          if (o.categoryAxis) {
            var categoryAxis = chart.categoryAxis;

            if (categoryAxis) {
              /* if we need to create any default values, we should assign them here */
              categoryAxis.parseDates = true;

              var keys = Object.keys(o.categoryAxis);
              for (var i = 0; i < keys.length; i++) {
                if (!angular.isObject(o.categoryAxis[keys[i]]) || angular.isArray(o.categoryAxis[keys[i]])) {
                  categoryAxis[keys[i]] = o.categoryAxis[keys[i]];
                } else {
                  console.log('Stripped categoryAxis obj ' + keys[i]);
                }
              }
              chart.categoryAxis = categoryAxis;
            }
          }

          // Create value axis

          /* if we need to create any default values, we should assign them here */

          var addValueAxis = function (a) {
            var valueAxis = new AmCharts.ValueAxis();

            var keys = Object.keys(a);
            for (var i = 0; i < keys.length; i++) {
              if (typeof a[keys[i]] !== 'object') {
                valueAxis[keys[i]] = a[keys[i]];
              }
            }
            chart.addValueAxis(valueAxis);
          };

          if (o.valueAxes && o.valueAxes.length > 0) {
            for (var i = 0; i < o.valueAxes.length; i++) {
              addValueAxis(o.valueAxes[i])
            }
          }

          //reusable function to create graph
          var addGraph = function (g) {
            var graph = new AmCharts.AmGraph();
            /** set some default values that amCharts doesnt provide **/
              // if a category field is not specified, attempt to use the second field from an object in the array as a default value
            graph.valueField = g.valueField || Object.keys(o.data[0])[1];
            graph.balloonText = '[[category]]: [[value]]';
            if (g) {
              var keys = Object.keys(g);
              // iterate over all of the properties in the graph object and apply them to the new AmGraph
              for (var i = 0; i < keys.length; i++) {
                graph[keys[i]] = g[keys[i]];
              }
            }
            chart.addGraph(graph);
          };

          // create the graphs
          if (o.graphs && o.graphs.length > 0) {
            for (var i = 0; i < o.graphs.length; i++) {
              addGraph(o.graphs[i]);
            }
          } else {
            addGraph();
          }

          var chartCursor = new AmCharts.ChartCursor();
          if (o.chartCursor) {
            var keys = Object.keys(o.chartCursor);
            for (var i = 0; i < keys.length; i++) {
              if (typeof o.chartCursor[keys[i]] !== 'object') {
                chartCursor[keys[i]] = o.chartCursor[keys[i]];
              }
            }
          }
          chart.addChartCursor(chartCursor);

          if (o.legend){
              var legend = new AmCharts.AmLegend();
              var keys = Object.keys(o.legend);
              for (var i = 0; i < keys.length; i++) {
                  legend[keys[i]] = o.legend[keys[i]];
              }
              chart.legend = legend;
          }

          if (o.chartScrollbar){
            var scrollbar = new AmCharts.ChartScrollbar();
            var keys = Object.keys(o.chartScrollbar);
            for (var i = 0; i < keys.length; i++) {
              scrollbar[keys[i]] = o.chartScrollbar[keys[i]];
            }
            chart.chartScrollbar = scrollbar;
          }

          // WRITE
          chart.write(id);
        };

        // Render the chart
        renderChart();

        // EVENTS =========================================================================

        $scope.$on('amCharts.triggerChartAnimate', function(event, id){
          if (id === $el[0].id || !id) {
            chart.animateAgain();
          }
        });

        $scope.$on('amCharts.updateData', function(event, data, id){
          if (id === $el[0].id || !id){
            chart.dataProvider = data;
            chart.validateData();
          }

        });

        $scope.$on('amCharts.validateNow', function(event, validateData, skipEvents, id){
          if (id === $el[0].id || !id){
            chart.validateNow(validateData === undefined ? true : validateData,
              skipEvents === undefined ? false : skipEvents)
          }
        });

        $scope.$on('amCharts.renderChart', function(event, amChartOptions,  id){
          if (id === $el[0].id || !id) {
            renderChart(amChartOptions);
          }
        });

      }

    }
  };
});
<|endoftext|>


<commit_before>import assert from "assert";

import {
  getEditorTankName,
  clickCreateTank,
  clickEditTank,
  editTankName,
  clickEditorClose,
  getTankTableNames,
  writeCode,
  getCode,
  isSavingEnabled,
  clickFight,
  clickSave
} from "../helper/EditorHelper.js"
import {
  clickNavLink,
  getActiveNavLink
} from "../helper/NaviHelper.js"
import {
  waitForBattlefield
} from "../helper/BattleHelper.js"
module.exports = function() {

  describe('Editor', () => {

    beforeEach(async () => {
      await this.createNewPage();
      let url = this.config.BASE_URL + "#stateless";
      this.mlog.log(`Opening ${url}`);
      await this.page.goto(url);
      await clickNavLink(this.page, "editor");
      await clickCreateTank(this.page);
      await clickEditTank(this.page, 0);
    });

    it('should rename the script when confirmed', async () => {
      let oldName = await getEditorTankName(this.page);
      await editTankName(this.page, "blablabla", true);
      let newName = await getEditorTankName(this.page);

      assert.equal("blablabla", newName);
      assert(newName != oldName, "name has changed");

    });

    it('should not rename the script when canceled', async () => {
      let oldName = await getEditorTankName(this.page);
      await editTankName(this.page, "blablabla", false);
      let newName = await getEditorTankName(this.page);

      assert.equal(oldName, newName);
    });

    it('should exit editor', async () => {
      await clickEditorClose(this.page);
      let names = await getTankTableNames(this.page);
      assert.equal(1, names.length);
    });

    it.only('should start a quick fight', async () => {
      await clickFight(this.page);
      await waitForBattlefield(this.page);
      let navLink = await getActiveNavLink(this.page);
      assert.equal('Battlefield', navLink)
    });

    it('should allow code editing', async () => {
      await writeCode(this.page, "blabla");
      let code = await getCode(this.page);
      assert.equal("blabla", code);
    });

    it('should allow saving when code changed', async () => {
      let oldCode = await getCode(this.page);
      let saving = await isSavingEnabled(this.page);
      assert(!saving, "saving disabled");

      await writeCode(this.page, "blabla");
      saving = await isSavingEnabled(this.page);
      assert(saving, "saving enabled");

      await writeCode(this.page, oldCode);
      saving = await isSavingEnabled(this.page);
      assert(!saving, "saving disabled");
    });

    it('should save changes', async () => {
      await writeCode(this.page, "blabla");
      await clickSave(this.page);
      await clickEditorClose(this.page);
      await clickEditTank(this.page, 0);
      let code = await getCode(this.page);
      assert.equal("blabla", code);
    });

  });

}
<commit_msg>test(jsbattle): enable full test suite<commit_after>import assert from "assert";

import {
  getEditorTankName,
  clickCreateTank,
  clickEditTank,
  editTankName,
  clickEditorClose,
  getTankTableNames,
  writeCode,
  getCode,
  isSavingEnabled,
  clickFight,
  clickSave
} from "../helper/EditorHelper.js"
import {
  clickNavLink,
  getActiveNavLink
} from "../helper/NaviHelper.js"
import {
  waitForBattlefield
} from "../helper/BattleHelper.js"
module.exports = function() {

  describe('Editor', () => {

    beforeEach(async () => {
      await this.createNewPage();
      let url = this.config.BASE_URL + "#stateless";
      this.mlog.log(`Opening ${url}`);
      await this.page.goto(url);
      await clickNavLink(this.page, "editor");
      await clickCreateTank(this.page);
      await clickEditTank(this.page, 0);
    });

    it('should rename the script when confirmed', async () => {
      let oldName = await getEditorTankName(this.page);
      await editTankName(this.page, "blablabla", true);
      let newName = await getEditorTankName(this.page);

      assert.equal("blablabla", newName);
      assert(newName != oldName, "name has changed");

    });

    it('should not rename the script when canceled', async () => {
      let oldName = await getEditorTankName(this.page);
      await editTankName(this.page, "blablabla", false);
      let newName = await getEditorTankName(this.page);

      assert.equal(oldName, newName);
    });

    it('should exit editor', async () => {
      await clickEditorClose(this.page);
      let names = await getTankTableNames(this.page);
      assert.equal(1, names.length);
    });

    it('should start a quick fight', async () => {
      await clickFight(this.page);
      await waitForBattlefield(this.page);
      let navLink = await getActiveNavLink(this.page);
      assert.equal('Battlefield', navLink)
    });

    it('should allow code editing', async () => {
      await writeCode(this.page, "blabla");
      let code = await getCode(this.page);
      assert.equal("blabla", code);
    });

    it('should allow saving when code changed', async () => {
      let oldCode = await getCode(this.page);
      let saving = await isSavingEnabled(this.page);
      assert(!saving, "saving disabled");

      await writeCode(this.page, "blabla");
      saving = await isSavingEnabled(this.page);
      assert(saving, "saving enabled");

      await writeCode(this.page, oldCode);
      saving = await isSavingEnabled(this.page);
      assert(!saving, "saving disabled");
    });

    it('should save changes', async () => {
      await writeCode(this.page, "blabla");
      await clickSave(this.page);
      await clickEditorClose(this.page);
      await clickEditTank(this.page, 0);
      let code = await getCode(this.page);
      assert.equal("blabla", code);
    });

  });

}
<|endoftext|>


<commit_before>/* global moment */
{
  'use strict';

  class GuiderSchedulesCalendar {
    constructor(el, config = {}) {
      const defaultConfig = {
        gridColumns: 12,
        windowStartMonthsAgo: 1,
        windowLengthInMonths: 12,
        scheduleHeight: 30,
        scheduleMarginTop: 5,
        readOnlyPeriodInWeeks: 6,
        monthFormat: 'MMM',
        classes: {
          months: 'guider-schedules__months',
          readyOnlyWindow: 'guider-schedules__readonly-window',
          schedules: 'guider-schedules__schedules',
          schedule: 'guider-schedules__schedule'
        }
      };

      this.config = $.extend(true, defaultConfig, config);
      this.$el = el;
      this.today = moment().startOf('day');

      this.displayMonths();
      this.setupScheduleData();
      this.displayReadyOnlyWindow();
      this.displaySchedules();
    }

    displayMonths() {
      this.startWindowDate = moment(this.today).subtract(this.config.windowStartMonthsAgo, 'months').startOf('month');
      this.endWindowDate = moment(this.startWindowDate).add(this.config.windowLengthInMonths, 'months');

      for (let currentMonth = this.startWindowDate; currentMonth < this.endWindowDate; currentMonth = moment(currentMonth).add(1, 'months')) {
        this.$el.find(`.${this.config.classes.months}`).append(`

          ${currentMonth.format(this.config.monthFormat)}

        `);
      }
    }

    setupScheduleData() {
      this.schedules = [];

      $(`#${this.config.guiderScheduleDataSourceElementId}`).find('[data-schedule-start]').each((scheduleIndex, schedule) => {
        this.schedules.push({
          'start': $(schedule).data('schedule-start'),
          'end': $(schedule).data('schedule-end')
        });
      });
    }

    displayReadyOnlyWindow() {
      let blockConfig = this.getReadOnlyWindowBlockConfig(),
      height = (this.config.scheduleHeight * this.schedules.length) - this.config.scheduleMarginTop + 'px';

      this.$el.find(`.${this.config.classes.readyOnlyWindow}`).css({
        'margin-left': `${blockConfig.offsetPercentage}%`,
        'width': `${blockConfig.lengthPercentage}%`,
        'height': height
      });
    }

    getReadOnlyWindowBlockConfig() {
      return this.getPercentagesForBlock(
        moment(this.today),
        moment(this.today).add(this.config.readOnlyPeriodInWeeks, 'weeks')
      );
    }

    getPercentagesForBlock(start, end) {
      const percentageWindowMonthLength = 100 / this.config.windowLengthInMonths,
      monthsGoneStart = start.diff(this.startWindowDate, 'months'),
      percentageThroughMonthStart = ((start.date() - 1) / start.daysInMonth()),
      percentageStart = (monthsGoneStart * percentageWindowMonthLength) + (percentageThroughMonthStart * percentageWindowMonthLength),
      monthsGoneEnd = end.diff(this.startWindowDate, 'months'),
      percentageThroughMonthEnd = (end.date() / end.daysInMonth());

      let blockWidth = (monthsGoneEnd * percentageWindowMonthLength) + (percentageThroughMonthEnd * percentageWindowMonthLength) - percentageStart;

      if (!blockWidth) {
        blockWidth = 100;
      }

      return {
        'offsetPercentage': percentageStart,
        'lengthPercentage': blockWidth,
        'endPercentage': percentageStart + blockWidth
      };
    }

    displaySchedules() {
      for (let schedule in this.schedules) {
        let status = 'editable',
        currentSchedule = this.schedules[schedule],
        startDate = moment(currentSchedule.start),
        endDate = moment(currentSchedule.end),
        blockConfig = this.getPercentagesForBlock(startDate, endDate);

        if (blockConfig.offsetPercentage < this.getReadOnlyWindowBlockConfig().endPercentage) {
          status = 'readonly';
        }

        this.$el.find(`.${this.config.classes.schedules}`).append(
          $(`<div class="${this.config.classes.schedule} ${this.config.classes.schedule}--${status}">`
        ).css({
          'margin-left': `${blockConfig.offsetPercentage}%`,
          'width': `${blockConfig.lengthPercentage}%`
        }));
      }
    }
  }

  window.PWTAP = window.PWTAP || {};
  window.PWTAP.GuiderSchedulesCalendar = GuiderSchedulesCalendar;
}
<commit_msg>Fix bug where schedule starts before the display window and there is no end date<commit_after>/* global moment */
{
  'use strict';

  class GuiderSchedulesCalendar {
    constructor(el, config = {}) {
      const defaultConfig = {
        gridColumns: 12,
        windowStartMonthsAgo: 1,
        windowLengthInMonths: 12,
        scheduleHeight: 30,
        scheduleMarginTop: 5,
        readOnlyPeriodInWeeks: 6,
        monthFormat: 'MMM',
        classes: {
          months: 'guider-schedules__months',
          readyOnlyWindow: 'guider-schedules__readonly-window',
          schedules: 'guider-schedules__schedules',
          schedule: 'guider-schedules__schedule'
        }
      };

      this.config = $.extend(true, defaultConfig, config);
      this.$el = el;
      this.today = moment().startOf('day');

      this.displayMonths();
      this.setupScheduleData();
      this.displayReadyOnlyWindow();
      this.displaySchedules();
    }

    displayMonths() {
      this.startWindowDate = moment(this.today).subtract(this.config.windowStartMonthsAgo, 'months').startOf('month');
      this.endWindowDate = moment(this.startWindowDate).add(this.config.windowLengthInMonths, 'months');

      for (let currentMonth = this.startWindowDate; currentMonth < this.endWindowDate; currentMonth = moment(currentMonth).add(1, 'months')) {
        this.$el.find(`.${this.config.classes.months}`).append(`

          ${currentMonth.format(this.config.monthFormat)}

        `);
      }
    }

    setupScheduleData() {
      this.schedules = [];

      $(`#${this.config.guiderScheduleDataSourceElementId}`).find('[data-schedule-start]').each((scheduleIndex, schedule) => {
        this.schedules.push({
          'start': $(schedule).data('schedule-start'),
          'end': $(schedule).data('schedule-end')
        });
      });
    }

    displayReadyOnlyWindow() {
      let blockConfig = this.getReadOnlyWindowBlockConfig(),
      height = (this.config.scheduleHeight * this.schedules.length) - this.config.scheduleMarginTop + 'px';

      this.$el.find(`.${this.config.classes.readyOnlyWindow}`).css({
        'margin-left': `${blockConfig.offsetPercentage}%`,
        'width': `${blockConfig.lengthPercentage}%`,
        'height': height
      });
    }

    getReadOnlyWindowBlockConfig() {
      return this.getPercentagesForBlock(
        moment(this.today),
        moment(this.today).add(this.config.readOnlyPeriodInWeeks, 'weeks')
      );
    }

    getPercentagesForBlock(start, end) {
      const percentageWindowMonthLength = 100 / this.config.windowLengthInMonths,
      monthsGoneStart = start.diff(this.startWindowDate, 'months'),
      percentageThroughMonthStart = ((start.date() - 1) / start.daysInMonth()),
      percentageStart = (monthsGoneStart * percentageWindowMonthLength) + (percentageThroughMonthStart * percentageWindowMonthLength),
      monthsGoneEnd = end.diff(this.startWindowDate, 'months'),
      percentageThroughMonthEnd = (end.date() / end.daysInMonth());

      let blockWidth = (monthsGoneEnd * percentageWindowMonthLength) + (percentageThroughMonthEnd * percentageWindowMonthLength) - percentageStart;

      if (!blockWidth) {
        blockWidth = 100 - percentageStart;
      }

      return {
        'offsetPercentage': percentageStart,
        'lengthPercentage': blockWidth,
        'endPercentage': percentageStart + blockWidth
      };
    }

    displaySchedules() {
      for (let schedule in this.schedules) {
        let status = 'editable',
        currentSchedule = this.schedules[schedule],
        startDate = moment(currentSchedule.start),
        endDate = moment(currentSchedule.end),
        blockConfig = this.getPercentagesForBlock(startDate, endDate);

        if (blockConfig.offsetPercentage < this.getReadOnlyWindowBlockConfig().endPercentage) {
          status = 'readonly';
        }

        this.$el.find(`.${this.config.classes.schedules}`).append(
          $(`<div class="${this.config.classes.schedule} ${this.config.classes.schedule}--${status}">`
        ).css({
          'margin-left': `${blockConfig.offsetPercentage}%`,
          'width': `${blockConfig.lengthPercentage}%`
        }));
      }
    }
  }

  window.PWTAP = window.PWTAP || {};
  window.PWTAP.GuiderSchedulesCalendar = GuiderSchedulesCalendar;
}
<|endoftext|>


<commit_before>/*
 * grunt-assets-wp
 * https://github.com/hariadi/grunt-assets-wp
 *
 * Base from:
 * https://github.com/roots/roots/blob/master/tasks/version.js
 * https://github.com/yeoman/grunt-filerev
 *
 * Copyright (c) 2013 Hariadi Hinta
 * Licensed under the MIT license.
 */
'use strict';

var fs = require('fs');
var path = require('path');
var crypto = require('crypto');

module.exports = function(grunt) {

  grunt.registerMultiTask('wprev', 'WordPress assets revving', function() {

    var done = this.async();
    var dest = this.data.dest;
    var options = this.options({
      encoding: 'utf8',
      algorithm: 'md5',
      format: true,
      length: 8,
      rename: false
    });

    this.files.forEach(function(files) {

      files.src.forEach(function (file) {

        if (file.length === 0) {
          grunt.log.warn('src does not exists');
          return false;
        }
        var name = path.basename(file);
        var content = grunt.file.read(file);
        var hash = crypto.createHash(options.algorithm).update(content, options.encoding).digest('hex');
        var suffix = hash.slice(0, options.length);
        var ext = path.extname(file);
        var newName = options.format ? [suffix, path.basename(file, ext), ext.slice(1)].join('.') : [path.basename(file, ext), suffix, ext.slice(1)].join('.');

        // Copy/rename file base on hash and format
        var resultPath = path.resolve(path.dirname(file), newName);
        if (options.rename) {
          fs.renameSync(file, resultPath);
        } else {
          grunt.file.copy(file, resultPath);
        }

        // Get target, find and change references assets to new hashed.
        var wpcontent = grunt.file.read(dest);
        var match = new RegExp('[a-z0-9]{'+ options.length +'}.' + name, "g");
        var re = ( match.test(wpcontent) ) ? match : new RegExp(name, "g");
        wpcontent = wpcontent.replace(re, newName);

        grunt.file.write(dest, wpcontent);
        grunt.log.writeln('  ' + file.grey + (' changed to ') + newName.green);

      });

    });

    done();
  });
};<commit_msg>Remove async<commit_after>/*
 * grunt-assets-wp
 * https://github.com/hariadi/grunt-assets-wp
 *
 * Base from:
 * https://github.com/roots/roots/blob/master/tasks/version.js
 * https://github.com/yeoman/grunt-filerev
 *
 * Copyright (c) 2013 Hariadi Hinta
 * Licensed under the MIT license.
 */
'use strict';

var fs = require('fs');
var path = require('path');
var crypto = require('crypto');

module.exports = function(grunt) {

  grunt.registerMultiTask('wprev', 'WordPress assets revving', function() {
    var dest = this.data.dest;
    var options = this.options({
      encoding: 'utf8',
      algorithm: 'md5',
      format: true,
      length: 8,
      rename: false
    });

    this.files.forEach(function(files) {

      files.src.forEach(function (file) {

        if (file.length === 0) {
          grunt.log.warn('src does not exists');
          return false;
        }
        var name = path.basename(file);
        var content = grunt.file.read(file);
        var hash = crypto.createHash(options.algorithm).update(content, options.encoding).digest('hex');
        var suffix = hash.slice(0, options.length);
        var ext = path.extname(file);
        var newName = options.format ? [suffix, path.basename(file, ext), ext.slice(1)].join('.') : [path.basename(file, ext), suffix, ext.slice(1)].join('.');

        // Copy/rename file base on hash and format
        var resultPath = path.resolve(path.dirname(file), newName);
        if (options.rename) {
          fs.renameSync(file, resultPath);
        } else {
          grunt.file.copy(file, resultPath);
        }

        // Get target, find and change references assets to new hashed.
        var wpcontent = grunt.file.read(dest);
        var match = new RegExp('[a-z0-9]{'+ options.length +'}.' + name, "g");
        var re = ( match.test(wpcontent) ) ? match : new RegExp(name, "g");
        wpcontent = wpcontent.replace(re, newName);

        grunt.file.write(dest, wpcontent);
        grunt.log.writeln('  ' + file.grey + (' changed to ') + newName.green);

      });

    });
  });
};<|endoftext|>


<commit_before>var awssum = require('awssum');
var amazon = awssum.load('amazon/amazon');
var CloudSearch = awssum.load('amazon/cloudsearch').CloudSearch;
var DocumentService = awssum.load('amazon/cloudsearch').DocumentService;

var OPTIONAL_PARAM = { required : false, type : 'param' };

function sendRawDocumentRequest() {
}

function Client(options) {
  this.domainName = options.domainName;
  this.host = options.host;
  this.port = options.port;
  this.docEndpoint = options.docEndpoint;
  this.isACS = options.isACS;

  this.accessKeyId     = options.accessKeyId;
  this.secretAccessKey = options.secretAccessKey;
}
Client.prototype = {
  get configurationAPI() {
    if (!this._configurationAPI) {
      this._configurationAPI = new CloudSearch({
        accessKeyId:     this.accessKeyId,
        secretAccessKey: this.secretAccessKey
      });
      if (!this.isACS) {
        var self = this;
        this._configurationAPI.host = function() {
          return self.host;
        };
        this._configurationAPI.addExtras = function(options, args) {
          options.protocol = self.protocol || 'http';
          options.port = self.port;
        };
      }
    }
    return this._configurationAPI;
  },

  setupDocumentsAPI: function(callback) {
    if (this.documentsAPI)
      return callback(this.documentsAPI);

    var self = this;
    if (this.docEndpoint) {
      var parsedEndpoint = this.docEndpoint.match(/^(doc-([^-]+)-([^\.]+)[^:]+)(?::(\d+))?$/);
      this._documentsAPI = this.createDocumentService({
        domainName: parsedEndpoint[2],
        domainId: parsedEndpoint[3],
        host: parsedEndpoint[1],
        port: parsedEndpoint[4] || 80
      });
      return callback(this.documentsAPI);
    }

    this.getDomainStatus(function(error, domain) {
      if (error)
        self.raiseFatalError(error);

      try {
        var endpoint = domain.DocService.Endpoint.split(':');
        self._documentsAPI = self.createDocumentService({
          domainName: domain.DomainName,
          domainId: domain.DomainId.replace(new RegExp('/' + domain.DomainName + '$'), ''),
          host: endpoint[0],
          port: endpoint[1] || 80
        });
        callback(self.documentsAPI);
      } catch(error) {
        self.raiseFatalError(error);
      }
    });
  },
  createDocumentService: function(options) {
    var service = new DocumentService({
      accessKeyId: this.accessKeyId,
      secretAccessKey: this.secretAccessKey,
      domainName: options.domainName,
      domainId: options.domainId,
      region: amazon.US_EAST_1
    });
    var self = this;
    if (!this.isACS) {
      var host = options.host;
      service.host = function() {
        return host;
      };
      var port = options.port;
      service.addExtras = function(options, args) {
        options.protocol = self.protocol || 'http';
        options.port = port;
      };
    }
    service.extractBody = function(options, args) {
      return 'json';
    };
    service.addCommonOptions = function(options, args) {
      options.headers['content-type'] = 'application/json';
      options.headers['content-length'] = self.countBytes(JSON.stringify(args.Docs));
    };
    return service;
  },
  countBytes: function(string) {
    string = encodeURIComponent(string);
    var escapedPartsMatcher = /\%[0-9a-f][0-9a-f]/gi;
    var escapedParts = string.match(escapedPartsMatcher);
    var notEscapedParts = string.replace(escapedPartsMatcher, '');
    return notEscapedParts.length + (escapedParts ? escapedParts.length : 0);
  },
  get documentsAPI() {
    return this._documentsAPI;
  },

  raiseFatalError: function(error) {
    if (typeof error != 'string') {
      error = error.message ?
        error.message + '\n' + error.stack : JSON.stringify(error);
      error = 'Unexpected error: ' + error;
    }
    console.log(error);
    process.exit(1);
  },

  rawConfigurationRequest: function(action, params, callback) {
    var extractBody = this.configurationAPI.extractBody;
    this.configurationAPI.extractBody = function() {
      return 'blob';
    };

    var operation = {
          defaults: {
            Action: action
          },
          args: {}
        };
    Object.keys(params).forEach(function(name) {
      operation.args[name] = OPTIONAL_PARAM;
    });

    var self = this;
    this.configurationAPI.send(operation, params, null, function(error, result) {
      self.configurationAPI.extractBody = extractBody;
      callback(error, result);
    });
  },

  assertHaveDomainName: function() {
    if (!this.domainName)
      this.raiseFatalError('You must specify the domain name.');
    return this;
  },

  getDomainStatus: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.getDomainStatuses(
      { DomainNames: [domainName] },
      function(error, domainStatuses) {
        if (error)
          self.raiseFatalError(error);
        if (domainStatuses.length && domainStatuses[0]) {
          callback(null, domainStatuses[0]);
        } else {
          callback(domainName + ' does not exist. You must specify an existing domain name.', null);
        }
      }
    );
  },

  getDomainStatuses: function(options, callback) {
    try {
      var self = this;
      if (!callback) callback = options;
      var domainStatusesCallback = function(error, response) {
          if (error)
            self.raiseFatalError(error);
          var domainStatuses = response.Body
               .DescribeDomainsResponse
               .DescribeDomainsResult
               .DomainStatusList
               .member;
          if (!Array.isArray(domainStatuses))
            domainStatuses = [domainStatuses];
          callback(null, domainStatuses);
        };
      if (arguments.length > 1)
        this.configurationAPI.DescribeDomains(options, domainStatusesCallback);
      else
        this.configurationAPI.DescribeDomains(domainStatusesCallback);
    } catch(error) {
      this.raiseFatalError(error);
    }
  },

  getIndexFieldStatus: function(options, callback) {
    var domainName;
    var fieldName;
    if (typeof options == 'string') {
      domainName = this.domainName;
      fieldName = options;
    } else {
      domainName = options.domainName;
      fieldName = options.fieldName;
    }

    var self = this;
    this.configurationAPI.DescribeIndexFields(
      {
        DomainName: domainName,
        FieldNames: [fieldName]
      },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);

        var indexFields = response.Body
             .DescribeIndexFieldsResponse
             .DescribeIndexFieldsResult
             .IndexFields
             .member;
        indexFields = !indexFields ? [] :
                      !Array.isArray(indexFields) ? [indexFields] :
                      indexFields;
        if (indexFields.length && indexFields[0])
          callback(null, indexFields[0]);
        else
          callback(fieldName + ' does not exist.', null);
      }
    );
  },

  getIndexFieldStatuses: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.configurationAPI.DescribeIndexFields(
      { DomainName: domainName },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);

        var indexFields = response.Body
             .DescribeIndexFieldsResponse
             .DescribeIndexFieldsResult
             .IndexFields
             .member;
        indexFields = !indexFields ? [] :
                      !Array.isArray(indexFields) ? [indexFields] :
                      indexFields;
        callback(null, indexFields);
      }
    );
  },

  getDefaultSearchField: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.configurationAPI.DescribeDefaultSearchField(
      { DomainName: domainName },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);
        try {
          var defaultSearchField = response.Body
                .DescribeDefaultSearchFieldResponse
                .DescribeDefaultSearchFieldResult
                .DefaultSearchField
                .Options;
          if (typeof defaultSearchField != 'string') defaultSearchField = '';
          callback(null, defaultSearchField);
        } catch(error) {
          commandLine.raiseFatalError(error);
        }
      }
    );
  },

  summarizeIndexFieldStatus: function(status) {
    var type = status.Options.TextOptions ? 'text' :
               status.Options.UIntOptions ? 'uint' :
               status.Options.LiteralOptions ? 'literal' :
               null;

    var options = status.Options.TextOptions ||
                  status.Options.UIntOptions ||
                  status.Options.LiteralOptions;
    var summarizedOptions = [];
    if (type == 'text' || type == 'uint' || options.SearchEnabled == 'true')
      summarizedOptions.push('Search');
    if (type != 'uint' && options.FacetEnabled == 'true')
      summarizedOptions.push('Facet');
    if (type == 'uint' || options.ResultEnabled == 'true')
      summarizedOptions.push('Result');

    return status.Options.IndexFieldName + ' ' +
             status.Status.State + ' ' +
             type + ' (' + summarizedOptions.join(' ') + ')';
  },

  assertDomainExists: function(callback) {
    var domainName = this.domainName;
    var self = this;
    this.getDomainStatus(domainName, function(error, domain) {
      if (error || !domain)
        self.raiseFatalError(domainName + ' does not exist. You must specify an existing domain name.');
      callback();
    });
  },

  assertNoDomain: function(callback) {
    this.getDomainStatuses(function(error, domains) {
      if (!error && domains.length)
        error = new Error(domains.length + ' domains exist unexpectedly.');
      callback(error);
    });
  }
};
exports.Client = Client;
<commit_msg>Don't return [undefined] as the result of Cliet#getDomainStatuses if there is no domain<commit_after>var awssum = require('awssum');
var amazon = awssum.load('amazon/amazon');
var CloudSearch = awssum.load('amazon/cloudsearch').CloudSearch;
var DocumentService = awssum.load('amazon/cloudsearch').DocumentService;

var OPTIONAL_PARAM = { required : false, type : 'param' };

function sendRawDocumentRequest() {
}

function Client(options) {
  this.domainName = options.domainName;
  this.host = options.host;
  this.port = options.port;
  this.docEndpoint = options.docEndpoint;
  this.isACS = options.isACS;

  this.accessKeyId     = options.accessKeyId;
  this.secretAccessKey = options.secretAccessKey;
}
Client.prototype = {
  get configurationAPI() {
    if (!this._configurationAPI) {
      this._configurationAPI = new CloudSearch({
        accessKeyId:     this.accessKeyId,
        secretAccessKey: this.secretAccessKey
      });
      if (!this.isACS) {
        var self = this;
        this._configurationAPI.host = function() {
          return self.host;
        };
        this._configurationAPI.addExtras = function(options, args) {
          options.protocol = self.protocol || 'http';
          options.port = self.port;
        };
      }
    }
    return this._configurationAPI;
  },

  setupDocumentsAPI: function(callback) {
    if (this.documentsAPI)
      return callback(this.documentsAPI);

    var self = this;
    if (this.docEndpoint) {
      var parsedEndpoint = this.docEndpoint.match(/^(doc-([^-]+)-([^\.]+)[^:]+)(?::(\d+))?$/);
      this._documentsAPI = this.createDocumentService({
        domainName: parsedEndpoint[2],
        domainId: parsedEndpoint[3],
        host: parsedEndpoint[1],
        port: parsedEndpoint[4] || 80
      });
      return callback(this.documentsAPI);
    }

    this.getDomainStatus(function(error, domain) {
      if (error)
        self.raiseFatalError(error);

      try {
        var endpoint = domain.DocService.Endpoint.split(':');
        self._documentsAPI = self.createDocumentService({
          domainName: domain.DomainName,
          domainId: domain.DomainId.replace(new RegExp('/' + domain.DomainName + '$'), ''),
          host: endpoint[0],
          port: endpoint[1] || 80
        });
        callback(self.documentsAPI);
      } catch(error) {
        self.raiseFatalError(error);
      }
    });
  },
  createDocumentService: function(options) {
    var service = new DocumentService({
      accessKeyId: this.accessKeyId,
      secretAccessKey: this.secretAccessKey,
      domainName: options.domainName,
      domainId: options.domainId,
      region: amazon.US_EAST_1
    });
    var self = this;
    if (!this.isACS) {
      var host = options.host;
      service.host = function() {
        return host;
      };
      var port = options.port;
      service.addExtras = function(options, args) {
        options.protocol = self.protocol || 'http';
        options.port = port;
      };
    }
    service.extractBody = function(options, args) {
      return 'json';
    };
    service.addCommonOptions = function(options, args) {
      options.headers['content-type'] = 'application/json';
      options.headers['content-length'] = self.countBytes(JSON.stringify(args.Docs));
    };
    return service;
  },
  countBytes: function(string) {
    string = encodeURIComponent(string);
    var escapedPartsMatcher = /\%[0-9a-f][0-9a-f]/gi;
    var escapedParts = string.match(escapedPartsMatcher);
    var notEscapedParts = string.replace(escapedPartsMatcher, '');
    return notEscapedParts.length + (escapedParts ? escapedParts.length : 0);
  },
  get documentsAPI() {
    return this._documentsAPI;
  },

  raiseFatalError: function(error) {
    if (typeof error != 'string') {
      error = error.message ?
        error.message + '\n' + error.stack : JSON.stringify(error);
      error = 'Unexpected error: ' + error;
    }
    console.log(error);
    process.exit(1);
  },

  rawConfigurationRequest: function(action, params, callback) {
    var extractBody = this.configurationAPI.extractBody;
    this.configurationAPI.extractBody = function() {
      return 'blob';
    };

    var operation = {
          defaults: {
            Action: action
          },
          args: {}
        };
    Object.keys(params).forEach(function(name) {
      operation.args[name] = OPTIONAL_PARAM;
    });

    var self = this;
    this.configurationAPI.send(operation, params, null, function(error, result) {
      self.configurationAPI.extractBody = extractBody;
      callback(error, result);
    });
  },

  assertHaveDomainName: function() {
    if (!this.domainName)
      this.raiseFatalError('You must specify the domain name.');
    return this;
  },

  getDomainStatus: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.getDomainStatuses(
      { DomainNames: [domainName] },
      function(error, domainStatuses) {
        if (error)
          self.raiseFatalError(error);
        if (domainStatuses.length && domainStatuses[0]) {
          callback(null, domainStatuses[0]);
        } else {
          callback(domainName + ' does not exist. You must specify an existing domain name.', null);
        }
      }
    );
  },

  getDomainStatuses: function(options, callback) {
    try {
      var self = this;
      if (!callback) callback = options;
      var domainStatusesCallback = function(error, response) {
          if (error)
            self.raiseFatalError(error);
          var domainStatuseList = response.Body
               .DescribeDomainsResponse
               .DescribeDomainsResult
               .DomainStatusList;
          var domainStatuses = domainStatuseList ?
                                 domainStatuseList.member : [];
          if (!Array.isArray(domainStatuses))
            domainStatuses = [domainStatuses];
          callback(null, domainStatuses);
        };
      if (arguments.length > 1)
        this.configurationAPI.DescribeDomains(options, domainStatusesCallback);
      else
        this.configurationAPI.DescribeDomains(domainStatusesCallback);
    } catch(error) {
      this.raiseFatalError(error);
    }
  },

  getIndexFieldStatus: function(options, callback) {
    var domainName;
    var fieldName;
    if (typeof options == 'string') {
      domainName = this.domainName;
      fieldName = options;
    } else {
      domainName = options.domainName;
      fieldName = options.fieldName;
    }

    var self = this;
    this.configurationAPI.DescribeIndexFields(
      {
        DomainName: domainName,
        FieldNames: [fieldName]
      },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);

        var indexFields = response.Body
             .DescribeIndexFieldsResponse
             .DescribeIndexFieldsResult
             .IndexFields
             .member;
        indexFields = !indexFields ? [] :
                      !Array.isArray(indexFields) ? [indexFields] :
                      indexFields;
        if (indexFields.length && indexFields[0])
          callback(null, indexFields[0]);
        else
          callback(fieldName + ' does not exist.', null);
      }
    );
  },

  getIndexFieldStatuses: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.configurationAPI.DescribeIndexFields(
      { DomainName: domainName },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);

        var indexFields = response.Body
             .DescribeIndexFieldsResponse
             .DescribeIndexFieldsResult
             .IndexFields
             .member;
        indexFields = !indexFields ? [] :
                      !Array.isArray(indexFields) ? [indexFields] :
                      indexFields;
        callback(null, indexFields);
      }
    );
  },

  getDefaultSearchField: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.configurationAPI.DescribeDefaultSearchField(
      { DomainName: domainName },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);
        try {
          var defaultSearchField = response.Body
                .DescribeDefaultSearchFieldResponse
                .DescribeDefaultSearchFieldResult
                .DefaultSearchField
                .Options;
          if (typeof defaultSearchField != 'string') defaultSearchField = '';
          callback(null, defaultSearchField);
        } catch(error) {
          commandLine.raiseFatalError(error);
        }
      }
    );
  },

  summarizeIndexFieldStatus: function(status) {
    var type = status.Options.TextOptions ? 'text' :
               status.Options.UIntOptions ? 'uint' :
               status.Options.LiteralOptions ? 'literal' :
               null;

    var options = status.Options.TextOptions ||
                  status.Options.UIntOptions ||
                  status.Options.LiteralOptions;
    var summarizedOptions = [];
    if (type == 'text' || type == 'uint' || options.SearchEnabled == 'true')
      summarizedOptions.push('Search');
    if (type != 'uint' && options.FacetEnabled == 'true')
      summarizedOptions.push('Facet');
    if (type == 'uint' || options.ResultEnabled == 'true')
      summarizedOptions.push('Result');

    return status.Options.IndexFieldName + ' ' +
             status.Status.State + ' ' +
             type + ' (' + summarizedOptions.join(' ') + ')';
  },

  assertDomainExists: function(callback) {
    var domainName = this.domainName;
    var self = this;
    this.getDomainStatus(domainName, function(error, domain) {
      if (error || !domain)
        self.raiseFatalError(domainName + ' does not exist. You must specify an existing domain name.');
      callback();
    });
  },

  assertNoDomain: function(callback) {
    this.getDomainStatuses(function(error, domains) {
      if (!error && domains.length)
        error = new Error(domains.length + ' domains exist unexpectedly.');
      callback(error);
    });
  }
};
exports.Client = Client;
<|endoftext|>