<commit_before>/**
 * Copyright 2011-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You
 * may not use this file except in compliance with the License. A copy of
 * the License is located at
 *
 *     http://aws.amazon.com/apache2.0/
 *
 * or in the "license" file accompanying this file. This file is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
 * ANY KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */

var AWS = require('./core');
var inherit = AWS.util.inherit;

/**
 * == Asynchronous Promise Objects
 *
 * All requests made through the SDK are asynchronous and use an
 * event-based promise callback interface. Each service method
 * that kicks off a request returns an +AWS.AWSRequest+ promise
 * object that you can use to register callbacks.
 *
 * For example, the following service method returns the request
 * object as "request", which can be used to register callbacks:
 *
 *   // request is an AWS.AWSRequest object
 *   var request = ec2.client.describeInstances();
 *
 *   // register callbacks on request to retrieve response data
 *   request.done(function(response) {
 *     console.log(resp.data);
 *   });
 *
 * == Multiple Callbacks and Chaining
 *
 * You can register multiple callbacks on any request object. The
 * callbacks can be registered for different events, or all for the
 * same event. In addition, you can chain callback registration, for
 * example:
 *
 *   request.
 *     done(function(response) {
 *       console.log("Success!");
 *     }).
 *     fail(function(response) {
 *       console.log("Error!");
 *     }).
 *     always(function(response) {
 *       console.log("Always!");
 *     });
 *
 * The above example will print either "Success! Always!", or "Error! Always!",
 * depending on whether the request succeeded or not.
 *
 * == Binding Custom Context Data on a Callback
 *
 * By default, the +this+ context of a callback function registered on an
 * event will be the {AWS.AWSResponse} object returned from the service.
 * In some cases, it may be necessary to pass extra custom context to these
 * functions; in these cases, you can bind a custom value to be used as the
 * +this+ context object when the callbacks are executed. To do so, pass
 * the +bind+ option to the asynchronous registration method:
 *
 *   var myContext = new Object();
 *   request.always(function(response) {
 *     console.log(this === myContext);
 *   }, {bind: myContext});
 *
 * The above callback will print +true+ when the callback function is executed.
 */
AWS.AWSRequest = inherit({
  /**
   * @api private
   */
  constructor: function AWSRequest(awsResponse) {
    this.state = null;
    this.awsResponse = awsResponse;
    this.callbacks = { data: [], done: [], fail: [], always: [] };

    AWS.util.each.call(this, this.callbacks, function (name) {
      this.addConfigCallback(name);
    });
  },

  /**
   * This event is used to stream response data from the
   * service packet-by-packet. This event is mostly used for large responses,
   * when it is inefficient (or impossible) to load the entire response into
   * memory.
   *
   * === Example: Registering a +data+ callback
   *
   *   s3.client.getObject({Bucket: b, Key: k}).data(function(resp) {
   *     console.log(resp.data);
   *   });
   *
   * Prints:
   *
   *   <Buffer 50 4b 03 04 0a 00 00 00 ...>
   *   <Buffer 2c 70 96 ac 92 2e ca e7 ...>
   *   ...
   *
   * @note If you register a +data+ callback,
   *   +response.data+ will not contain serialized output
   *   for the entire request. Instead, it will be your responsibility
   *   to stream the output and de-serialize the result on your own.
   * @callback callback function(response)
   *   @param response [AWS.AWSResponse] the response object containing the
   *     current packet in the +data+ property.
   * @option options bind [Object] (response object) an object to bind
   *   the callback function to. Defaults to the response object.
   * @return [AWS.AWSRequest] The same object, for chaining.
   */
  data: function data(callback, options) {
    if (this.awsResponse.data !== null) {
      this.call(callback, options);
    }
    this.callbacks.data.push([callback, options]);
    return this;
  },

  /**
   * This event registers a callback to be called when a successful response
   * from the server is returned. The response contains a
   * {AWS.AWSResponse.data data} field with the serialized response data
   * from the service.
   *
   * === Example: Registering a +done+ callback
   *
   *   s3.client.listBuckets().done(function(response) {
   *     console.log(response.data);
   *   });
   *
   * Prints:
   *
   *   { Owner: { ID: '...', DisplayName: '...' },
   *     Buckets:
   *      [ { Name: 'someBucketName', CreationDate: someCreationDate },
   *        { Name: 'otherBucketName', CreationDate: otherCreationDate } ],
   *     RequestId: '...' }
   *
   * @option options bind [Object] (response object) an object to bind
   *   the callback function to. Defaults to the response object.
   * @callback callback function(response)
   *   @param response [AWS.AWSResponse] the response object containing the
   *     de-serialized response contents in the +data+ property.
   *   @note The +response.error+ property will be +null+ when this callback
   *     is called.
   * @return [AWS.AWSRequest] The same object, for chaining.
   */
  done: function done(callback, options) {
    if (this.state === 'done') {
      this.call(callback, options);
    } else if (this.state === null) {
      this.callbacks.done.push([callback, options]);
    }
    return this;
  },

  /**
   * This event registers a callback to be called when a failure response
   * from the server is returned, or if a networking error occurs.
   * The response contains a {AWS.AWSResponse.error data} field with the
   * error data from the service.
   *
   * === Example: Registering a +fail+ callback
   *
   *   s3.config.credentials.accessKeyId = 'invalid';
   *   s3.client.listBuckets().fail(function(response) {
   *     console.log(response.error);
   *   });
   *
   * Prints:
   *
   *   { code: 'Forbidden', message: 403 }
   *
   * @option options bind [Object] (response object) an object to bind
   *   the callback function to. Defaults to the response object.
   * @callback callback function(response)
   *   @param response [AWS.AWSResponse] the response object containing the
   *     service error details in the +error+ property.
   *   @note The +response.data+ property will be +null+ when this callback
   *     is called.
   * @return [AWS.AWSRequest] The same object, for chaining.
   */
  fail: function fail(callback, options) {
    if (this.state === 'fail') {
      this.call(callback, options);
    } else if (this.state === null) {
      this.callbacks.fail.push([callback, options]);
    }
    return this;
  },

  /**
   * This event registers a callback to be called in any final state of a
   * request, i.e., both {done} and {fail}. Use this callback to handle any
   * request cleanup that must be executed regardless of the success state.
   *
   * Note that if you do intend to use response data inside of this callback,
   * you must check for the presence of +response.data+ or +response.error+
   * before attempting to access either property. For example:
   *
   *   request.always(function(response) {
   *     if (response.error) {
   *       // an error occurred, handle it
   *     } else {
   *       // we can use response.data here
   *     }
   *   });
   *
   * @option options bind [Object] (response object) an object to bind
   *   the callback function to. Defaults to the response object.
   * @callback callback function(response)
   *   @param response [AWS.AWSResponse] the response object containing the
   *     de-serialized response contents in the +data+ property or the
   *     error information in the +error+ property, depending on the result.
   * @return [AWS.AWSRequest] The same object, for chaining.
   */
  always: function always(callback, options) {
    if (this.state) {
      this.call(callback, options);
    } else {
      this.callbacks.always.push([callback, options]);
    }
    return this;
  },

  /**
   * @api private
   */
  notifyData: function notifyData(data) {
    this.awsResponse.data = data;
    this.notify('data', this.callbacks.data);
  },

  /**
   * @api private
   */
  notifyDone: function notifyDone(data) {
    this.awsResponse.data = data;
    this.notify('done', this.callbacks.done.concat(this.callbacks.always));
  },

  /**
   * @api private
   */
  notifyFail: function notifyFail(error) {
    this.awsResponse.error = error;
    this.notify('fail', this.callbacks.fail.concat(this.callbacks.always));
  },

  /**
   * @api private
   */
  notify: function notify(state, callbacks) {
    AWS.util.arrayEach.call(this, callbacks, function iterator(cb) {
      this.call(cb[0], cb[1]);
    });
    this.state = state;
  },

  /**
   * @api private
   */
  call: function call(callback, options) {
    var binding = this.awsResponse;
    if (options && options.bind) {
      binding = options.bind;
    }
    callback.call(binding, this.awsResponse);
  },

  /**
   * @api private
   */
  addConfigCallback: function addConfigCallback(cbMethod, configName) {
    if (!this.awsResponse.client) return;

    if (configName === undefined) {
      configName = 'on' + cbMethod.charAt(0).toUpperCase() + cbMethod.slice(1);
    }

    var callbacks = this.awsResponse.client.config[configName];
    if (!(callbacks instanceof Array) && callbacks !== undefined) {
      callbacks = [callbacks];
    }

    AWS.util.arrayEach.call(this, callbacks, function (callback) {
      if (callback instanceof Function) {
        this[cbMethod].call(this, callback);
      }
    });
  }

});

AWS.AWSResponse = inherit({

  constructor: function AWSResponse(options) {

    // the request "context"
    this.client = options.client;
    this.method = options.method;
    this.params = options.params;

    this.data = null;
    this.error = null;
    this.retryCount = 0;

    this.httpRequest = null;
    this.httpResponse = null;

  }

});
<commit_msg>Document AWS.AWSResponse<commit_after>/**
 * Copyright 2011-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You
 * may not use this file except in compliance with the License. A copy of
 * the License is located at
 *
 *     http://aws.amazon.com/apache2.0/
 *
 * or in the "license" file accompanying this file. This file is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
 * ANY KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */

var AWS = require('./core');
var inherit = AWS.util.inherit;

/**
 * == Asynchronous Promise Objects
 *
 * All requests made through the SDK are asynchronous and use an
 * event-based promise callback interface. Each service method
 * that kicks off a request returns an +AWS.AWSRequest+ promise
 * object that you can use to register callbacks.
 *
 * For example, the following service method returns the request
 * object as "request", which can be used to register callbacks:
 *
 *   // request is an AWS.AWSRequest object
 *   var request = ec2.client.describeInstances();
 *
 *   // register callbacks on request to retrieve response data
 *   request.done(function(response) {
 *     console.log(resp.data);
 *   });
 *
 * == Multiple Callbacks and Chaining
 *
 * You can register multiple callbacks on any request object. The
 * callbacks can be registered for different events, or all for the
 * same event. In addition, you can chain callback registration, for
 * example:
 *
 *   request.
 *     done(function(response) {
 *       console.log("Success!");
 *     }).
 *     fail(function(response) {
 *       console.log("Error!");
 *     }).
 *     always(function(response) {
 *       console.log("Always!");
 *     });
 *
 * The above example will print either "Success! Always!", or "Error! Always!",
 * depending on whether the request succeeded or not.
 *
 * == Binding Custom Context Data on a Callback
 *
 * By default, the +this+ context of a callback function registered on an
 * event will be the {AWS.AWSResponse} object returned from the service.
 * In some cases, it may be necessary to pass extra custom context to these
 * functions; in these cases, you can bind a custom value to be used as the
 * +this+ context object when the callbacks are executed. To do so, pass
 * the +bind+ option to the asynchronous registration method:
 *
 *   var myContext = new Object();
 *   request.always(function(response) {
 *     console.log(this === myContext);
 *   }, {bind: myContext});
 *
 * The above callback will print +true+ when the callback function is executed.
 *
 * @see AWS.AWSResponse
 */
AWS.AWSRequest = inherit({
  /**
   * @api private
   */
  constructor: function AWSRequest(awsResponse) {
    this.state = null;
    this.awsResponse = awsResponse;
    this.callbacks = { data: [], done: [], fail: [], always: [] };

    AWS.util.each.call(this, this.callbacks, function (name) {
      this.addConfigCallback(name);
    });
  },

  /**
   * This event is used to stream response data from the
   * service packet-by-packet. This event is mostly used for large responses,
   * when it is inefficient (or impossible) to load the entire response into
   * memory.
   *
   * === Example: Registering a +data+ callback
   *
   *   s3.client.getObject({Bucket: b, Key: k}).data(function(resp) {
   *     console.log(resp.data);
   *   });
   *
   * Prints:
   *
   *   <Buffer 50 4b 03 04 0a 00 00 00 ...>
   *   <Buffer 2c 70 96 ac 92 2e ca e7 ...>
   *   ...
   *
   * @note If you register a +data+ callback,
   *   +response.data+ will not contain serialized output
   *   for the entire request. Instead, it will be your responsibility
   *   to stream the output and de-serialize the result on your own.
   * @callback callback function(response)
   *   @param response [AWS.AWSResponse] the response object containing the
   *     current packet in the +data+ property.
   * @option options bind [Object] (response object) an object to bind
   *   the callback function to. Defaults to the response object.
   * @return [AWS.AWSRequest] The same object, for chaining.
   */
  data: function data(callback, options) {
    if (this.awsResponse.data !== null) {
      this.call(callback, options);
    }
    this.callbacks.data.push([callback, options]);
    return this;
  },

  /**
   * This event registers a callback to be called when a successful response
   * from the server is returned. The response contains a
   * {AWS.AWSResponse.data data} field with the serialized response data
   * from the service.
   *
   * === Example: Registering a +done+ callback
   *
   *   s3.client.listBuckets().done(function(response) {
   *     console.log(response.data);
   *   });
   *
   * Prints:
   *
   *   { Owner: { ID: '...', DisplayName: '...' },
   *     Buckets:
   *      [ { Name: 'someBucketName', CreationDate: someCreationDate },
   *        { Name: 'otherBucketName', CreationDate: otherCreationDate } ],
   *     RequestId: '...' }
   *
   * @option options bind [Object] (response object) an object to bind
   *   the callback function to. Defaults to the response object.
   * @callback callback function(response)
   *   @param response [AWS.AWSResponse] the response object containing the
   *     de-serialized response contents in the +data+ property.
   *   @note The +response.error+ property will be +null+ when this callback
   *     is called.
   * @return [AWS.AWSRequest] The same object, for chaining.
   */
  done: function done(callback, options) {
    if (this.state === 'done') {
      this.call(callback, options);
    } else if (this.state === null) {
      this.callbacks.done.push([callback, options]);
    }
    return this;
  },

  /**
   * This event registers a callback to be called when a failure response
   * from the server is returned, or if a networking error occurs.
   * The response contains a {AWS.AWSResponse.error data} field with the
   * error data from the service.
   *
   * === Example: Registering a +fail+ callback
   *
   *   s3.config.credentials.accessKeyId = 'invalid';
   *   s3.client.listBuckets().fail(function(response) {
   *     console.log(response.error);
   *   });
   *
   * Prints:
   *
   *   { code: 'Forbidden', message: 403 }
   *
   * @option options bind [Object] (response object) an object to bind
   *   the callback function to. Defaults to the response object.
   * @callback callback function(response)
   *   @param response [AWS.AWSResponse] the response object containing the
   *     service error details in the +error+ property.
   *   @note The +response.data+ property will be +null+ when this callback
   *     is called.
   * @return [AWS.AWSRequest] The same object, for chaining.
   */
  fail: function fail(callback, options) {
    if (this.state === 'fail') {
      this.call(callback, options);
    } else if (this.state === null) {
      this.callbacks.fail.push([callback, options]);
    }
    return this;
  },

  /**
   * This event registers a callback to be called in any final state of a
   * request, i.e., both {done} and {fail}. Use this callback to handle any
   * request cleanup that must be executed regardless of the success state.
   *
   * Note that if you do intend to use response data inside of this callback,
   * you must check for the presence of +response.data+ or +response.error+
   * before attempting to access either property. For example:
   *
   *   request.always(function(response) {
   *     if (response.error) {
   *       // an error occurred, handle it
   *     } else {
   *       // we can use response.data here
   *     }
   *   });
   *
   * @option options bind [Object] (response object) an object to bind
   *   the callback function to. Defaults to the response object.
   * @callback callback function(response)
   *   @param response [AWS.AWSResponse] the response object containing the
   *     de-serialized response contents in the +data+ property or the
   *     error information in the +error+ property, depending on the result.
   * @return [AWS.AWSRequest] The same object, for chaining.
   */
  always: function always(callback, options) {
    if (this.state) {
      this.call(callback, options);
    } else {
      this.callbacks.always.push([callback, options]);
    }
    return this;
  },

  /**
   * @api private
   */
  notifyData: function notifyData(data) {
    this.awsResponse.data = data;
    this.notify('data', this.callbacks.data);
  },

  /**
   * @api private
   */
  notifyDone: function notifyDone(data) {
    this.awsResponse.data = data;
    this.notify('done', this.callbacks.done.concat(this.callbacks.always));
  },

  /**
   * @api private
   */
  notifyFail: function notifyFail(error) {
    this.awsResponse.error = error;
    this.notify('fail', this.callbacks.fail.concat(this.callbacks.always));
  },

  /**
   * @api private
   */
  notify: function notify(state, callbacks) {
    AWS.util.arrayEach.call(this, callbacks, function iterator(cb) {
      this.call(cb[0], cb[1]);
    });
    this.state = state;
  },

  /**
   * @api private
   */
  call: function call(callback, options) {
    var binding = this.awsResponse;
    if (options && options.bind) {
      binding = options.bind;
    }
    callback.call(binding, this.awsResponse);
  },

  /**
   * @api private
   */
  addConfigCallback: function addConfigCallback(cbMethod, configName) {
    if (!this.awsResponse.client) return;

    if (configName === undefined) {
      configName = 'on' + cbMethod.charAt(0).toUpperCase() + cbMethod.slice(1);
    }

    var callbacks = this.awsResponse.client.config[configName];
    if (!(callbacks instanceof Array) && callbacks !== undefined) {
      callbacks = [callbacks];
    }

    AWS.util.arrayEach.call(this, callbacks, function (callback) {
      if (callback instanceof Function) {
        this[cbMethod].call(this, callback);
      }
    });
  }

});

/**
 * This class encapsulates the the response information
 * from a service request operation sent through {AWS.AWSRequest}.
 * The response object has two main properties for getting information
 * back from a request:
 *
 * == The +data+ property
 *
 * The +response.data+ property contains the serialized object data
 * retrieved from the service request. For instance, for an
 * Amazon DynamoDB +listTables+ method call, the response data might
 * look like:
 *
 *   > resp.data
 *   { TableNames:
 *      [ 'table1', 'table2', ... ] }
 *
 * The +data+ property can be null if an error occurs (see below).
 *
 * == The +error+ property
 *
 * In the event of a service error (or transfer error), the
 * +response.error+ property will be filled with the given
 * error data in the form:
 *
 *   { code: 'SHORT_UNIQUE_ERROR_CODE',
 *     message: 'Some human readable error message' }
 *
 * In the case of an error, the +data+ property will be +null+.
 * Note that if you handle events that can be in a failure state,
 * you should always check whether +response.error+ is set
 * before attempting to access the +response.data+ property.
 *
 * @!attribute data
 *   @readonly
 *   @group Data Properties
 *   @note Inside of a {AWS.AWSRequest.data} event, this
 *     property contains a single raw packet instead of the
 *     full de-serialized service response.
 *   @return [Object] the de-serialized response data
 *     from the service.
 *
 * @!attribute error
 *   An structure containing information about a service
 *   or networking error.
 *   @readonly
 *   @group Data Properties
 *   @note This attribute is only filled if a service or
 *     networking error occurs.
 *   @return [Object]
 *     * code [String] a unique short code representing the
 *       error that was emitted.
 *     * message [String] a longer human readable error message
 *     * retryable [Boolean] whether the error message is
 *       retryable.
 *
 * @!attribute client
 *   @readonly
 *   @group Operation Properties
 *   @return [AWS.Client] The low-level service client object
 *     that initiated the request.
 *
 * @!attribute method
 *   @readonly
 *   @group Operation Properties
 *   @return [String] the name of the operation executed on
 *     the service.
 *
 * @!attribute params
 *   @readonly
 *   @group Operation Properties
 *   @return [Object] the parameters sent in the request to
 *     the service.
 *
 * @!attribute retryCount
 *   @readonly
 *   @group Operation Properties
 *   @return [Integer] the number of retries that have were
 *     attempted before the request was completed.
 *
 * @!attribute httpRequest
 *   @readonly
 *   @group HTTP Properties
 *   @return [AWS.HttpRequest] the raw HTTP request object
 *     containing request headers and body information
 *     sent by the client.
 *
 * @!attribute httpResponse
 *   @readonly
 *   @group HTTP Properties
 *   @return [AWS.HttpResponse] the raw HTTP response object
 *     containing the response headers and body information
 *     from the server.
 *
 * @see AWS.AWSRequest
 */
AWS.AWSResponse = inherit({

  /**
   * @api private
   */
  constructor: function AWSResponse(options) {

    // the request "context"
    this.client = options.client;
    this.method = options.method;
    this.params = options.params;

    this.data = null;
    this.error = null;
    this.retryCount = 0;

    this.httpRequest = null;
    this.httpResponse = null;

  }

});
<|endoftext|>


<commit_before>(function (exports) {

    var // a handy re-useable object
        _empty = {},
        // short-cut scope lookup
        O = Object,
        OP = O.prototype,
        hasOwnProp = OP.hasOwnProperty,
        // a re-useable property definition to create 'open' properties. By
        // default, Object.defineProperty creates closed properties (i.e: not
        // enumerable, writable, or configurable)
        openSpec = {
            enumerable: true,
            configurable: true
        },
        // property definition for plain properties
        // (strings, numbers, booleans, etc...)
        // defined further down...
        plainSpec,
        callProto
    ;

    /**
     * Extend one object with the properties of another.
     *
     * If the extending object, 'xtndr', has a function named 'extended', it
     * will be called with one argument, the object that was extended.
     *
     * @param xtnd {object} object to extend
     * @param xtndr1 ... xtndrN {object} one, or more objects to extend with
     * @returns {object} the extended object
     */
    function extend (xtnd /*, xtndr1, ..., xtndrN */) {
        var hasOwn = hasOwnProp,
            len = arguments.length,
            i = 1,
            xtndr, name, getter, setter
        ;

        for (; i < len; i++) {
            xtndr = arguments[i];
            for (name in xtndr) {
                if (hasOwn.call(xtndr, name) && name !== "self") {
                    getter = xtndr.__lookupGetter__(name);
                    setter = xtndr.__lookupSetter__(name);

                    if (getter || setter) {
                        // use assignment to avoid jshint error
                        getter = getter && xtnd.__defineGetter__(name, getter);
                        setter = setter && xtnd.__defineSetter__(name, setter);
                    }
                    else {
                        xtnd[name] = xtndr[name];
                    }
                }
            }

            if (typeof xtndr.extended === "function") {
                xtndr.extended(xtnd);
            }
        }

        return xtnd;
    }

    /**
     * Include properties onto the prototype of 'self' from another Constructor
     * function or a plain object. If the 'props' has a property named 'self',
     * the properties of 'self' will be merged into 'self' directly.
     *
     * If the supplying object, 'props', has a function named 'included' it will
     * be called with one argument, the 'self' Constructor function that was
     * just modified.
     *
     * @param self {function} Constructor function
     * @param props {function|object} either a Constructor function, or an
     *      object of properties to include
     * @returns {function} self
     */
    function include (self /*, props1, ..., propsN */) {
        var hasOwn = hasOwnProp,
            proto = self.prototype,
            len = arguments.length,
            i = 1,
            props, name
        ;

        for (; i < len; i++) {
            props = arguments[i];

            if (typeof props === "function") {
                extend(proto, props.prototype);
            }
            else {
                if (hasOwn.call(props, "self")) {
                    extend(self, props.self);
                }

                extend(proto, props);
            }

            if (typeof props.included === "function") {
                props.included(self);
            }
        }

        return self;
    }

    /**
     * Create a Constructor function, optionally setting its prototype to the
     * supplied object.
     *
     * When the Constructor function is called by 'new' it will attempt to
     * initialize the instance. First by calling the Constructor's "initialize"
     * method, passing the new instance and the arguments object. Then it will
     * attempt to apply the instances "init" method passing all arguments
     * as they were passed to the constructor function.
     *
     * @param proto {object} optional, object to use as the prototype
     * @returns {function} the new constructor function
     */
    function makeCtor (proto) {
        var Ctor = function Proteus () {
                var fn;

                if (arguments[0] !== _empty) {
                    if (typeof this.constructor.initialize === "function") {
                        this.constructor.initialize(this, arguments);
                    }

                    if (typeof (fn = this.init) === "function") {
                        fn.apply(this, arguments);
                    }
                }
            }
        ;

        if (proto) {
            Ctor.prototype = proto;
        }

        Ctor.prototype.constructor = Ctor;

        return Ctor;
    }

    /**
     * Dervie a new Constructor function from another, optionally adding the
     * supplied properties to its prototype.
     *
     * If the parent Constructor has a function named 'inherited' it will be
     * called with one argument, the new Constructor function.
     *
     * @param parent {function} a constructor object to derive from
     * @param props {object} optional, properties to add to the constructors prototype
     * @returns {function} a constructor function
     */
    function derive (parent, props) {
        var Ctor = makeCtor(new parent(_empty));

        O.defineProperty(Ctor, "__super__", {
            value: parent.prototype
        });

        extend(Ctor, parent);

        if (props) {
            include(Ctor, props);
        }

        if (typeof parent.inherited === "function") {
            parent.inherited(Ctor);
        }

        return Ctor;
    }

    /**
     * Interface to Object.create, however, the props argument is a plain
     * object of properties to copy over to the newly created object.
     * Getters and setters will be preserved.
     *
     * The "init" method on the object, and all of the objects prototypes,
     * will be called scoped to the new object and without any additional
     * arguments.
     *
     * @param proto {object} optional, prototype to use for the new object
     * @param props {object} properties to merge onto the new object
     * @returns {object}
     */
    function create (proto, props) {
        var hasOwn = hasOwnProp,
            obj, p;

        if (!props) {
            props = proto;
            proto = OP;
        }

        obj = extend(O.create(proto), props);

        return obj;
    }

    plainSpec = extend({writable: true}, openSpec);

    /**
     * Utility method for creating 'plain' properties on an object. Plain
     * being {enumerable: true, writable: true, configurable: true}, the
     * passed spec can override these defaults.
     *
     * @param obj {object} object to define property on
     * @param name {string} property name
     * @param val {mixed} the value for the property
     * @param spec {object} optional, property specification
     * @returns {object} obj
     */
    function defineProperty(obj, name, val, spec) {
        spec = extend({value: val}, plainSpec, spec || _empty);
        return O.defineProperty(obj, name, spec);
    }

    /**
     * Utility method for creating a getter on an object. The property
     * definition will default to {enumerable: true, configurable: true}
     * unless overridden with the spec object.
     *
     * @param obj {object} object to define property on
     * @param name {string} property name
     * @param fn {function} the getter function
     * @param spec {object} optional, property specification
     * @returns {object} obj
     */
    function defineGetter (obj, name, fn, spec) {
        spec = extend({get: fn}, openSpec, spec || _empty);
        return O.defineProperty(obj, name, spec);
    }

    /**
     * Utility method for creating a setter on an object. The property
     * definition will default to {enumerable: true, configurable: true}
     * unless overridden with the spec object.
     *
     * @param obj {object} object to define property on
     * @param name {string} property name
     * @param fn {function} the setter function
     * @param spec {object} optional, property specification
     * @returns {object} obj
     */
    function defineSetter (obj, name, fn, spec) {
        spec = extend({set: fn}, openSpec, spec || _empty);
        return O.defineProperty(obj, name, spec);
    }

    /**
     * Utility method for creating both a getter and a setter on an object.
     * The property definition will default to {enumerable: true,
     * configurable: true} unless overridden with the spec object.
     *
     * @param obj {object} object to define property on
     * @param name {string} property name
     * @param getter {function} the getter function, or if 'setter' is not
     *      given, then the function will be used for both getting and
     *      setting.
     * @param setter {function} optional, the setter function
     * @param spec {object} optional, property specification
     * @returns {object} obj
     */
    function defineGetSet (obj, name, getter, setter, spec) {
        if (typeof setter !== "function") {
            spec = setter;
            setter = getter;
        }
        spec = extend({get: getter, set: setter}, openSpec, spec || _empty);
        return O.defineProperty(obj, name, spec);
    }

    /**
     * Apply a method from the objects prototype.
     *
     * @param self {object} the scope object
     * @param name {string} name of the method to call, optional if the calling
     *      function is named i.e:
     *          {
     *              init: function init () {...}
     *          }
     * @param args {array-like} arguments to pass to the method
     * @returns {mixed} whatever the prototype method would return
     */
    function applyProto (self, name, args) {
        var hasOwn = hasOwnProp,
            caller = applyProto.caller === callProto ?
                        callProto.caller :
                        applyProto.caller,
            callerFound, p
        ;

        if (typeof name !== "string") {
            args = name;
            name = caller.name;
        }

        if (!name) {
            throw new Error("Can not call prototype method without a name");
        }

        p = self;
        do {
            if (p[name] === caller) {
                callerFound = true;
                p = Object.getPrototypeOf(p);
            }

            if (p && callerFound && hasOwn.call(p, name)) {
                return p[name].apply(self, args);
            }

        }
        while ((p = Object.getPrototypeOf(p)));

        throw new Error("Can not call '" + name + "' on undefined.");
    }

    /**
     * Call a method from an objects prototype.
     *
     * @param self {object} the scope object
     * @param name {string} name of the method to call
     * @returns {mixed}
     */
    callProto = function callProto (self, name) {
        return applyProto(
            self,
            name,
            Array.prototype.slice.call(arguments, 2));
    };

    extend(exports, {

        create:  create,

        defineProperty: defineProperty,
        defineGetter:   defineGetter,
        defineSetter:   defineSetter,
        defineGetSet:   defineGetSet,

        applyProto:     applyProto,
        callProto:      callProto,

        extend:     extend,
        include:    include,
        derive:     derive,

        Class: derive(O, {
            self: {
                /**
                 * 'include' scoped to the current object
                 * @param props {object} properties to include
                 * @returns {object}
                 */
                include: function () {
                    return include.apply(
                        this,
                        [this].concat(Array.prototype.slice.call(arguments))
                    );
                },
                /**
                 * 'extend' scoped to the current object
                 * @param xtnd {object} object to extend
                 * @returns {object} the extended object
                 */
                extend:  function (xtnd) {
                    return extend(xtnd, this);
                },
                /**
                 * 'derive' scoped to the current constructor function
                 * @param props {object}
                 * @returns {function}
                 */
                derive:  function (props) {
                    return derive(this, props);
                }
            }
        })
    });

}(exports || (window.Proteus = {})));
<commit_msg>Require a prototype object for Proteus.create<commit_after>(function (exports) {

    var // a handy re-useable object
        _empty = {},
        // short-cut scope lookup
        O = Object,
        OP = O.prototype,
        hasOwnProp = OP.hasOwnProperty,
        // a re-useable property definition to create 'open' properties. By
        // default, Object.defineProperty creates closed properties (i.e: not
        // enumerable, writable, or configurable)
        openSpec = {
            enumerable: true,
            configurable: true
        },
        // property definition for plain properties
        // (strings, numbers, booleans, etc...)
        // defined further down...
        plainSpec,
        callProto
    ;

    /**
     * Extend one object with the properties of another.
     *
     * If the extending object, 'xtndr', has a function named 'extended', it
     * will be called with one argument, the object that was extended.
     *
     * @param xtnd {object} object to extend
     * @param xtndr1 ... xtndrN {object} one, or more objects to extend with
     * @returns {object} the extended object
     */
    function extend (xtnd /*, xtndr1, ..., xtndrN */) {
        var hasOwn = hasOwnProp,
            len = arguments.length,
            i = 1,
            xtndr, name, getter, setter
        ;

        for (; i < len; i++) {
            xtndr = arguments[i];
            for (name in xtndr) {
                if (hasOwn.call(xtndr, name) && name !== "self") {
                    getter = xtndr.__lookupGetter__(name);
                    setter = xtndr.__lookupSetter__(name);

                    if (getter || setter) {
                        // use assignment to avoid jshint error
                        getter = getter && xtnd.__defineGetter__(name, getter);
                        setter = setter && xtnd.__defineSetter__(name, setter);
                    }
                    else {
                        xtnd[name] = xtndr[name];
                    }
                }
            }

            if (typeof xtndr.extended === "function") {
                xtndr.extended(xtnd);
            }
        }

        return xtnd;
    }

    /**
     * Include properties onto the prototype of 'self' from another Constructor
     * function or a plain object. If the 'props' has a property named 'self',
     * the properties of 'self' will be merged into 'self' directly.
     *
     * If the supplying object, 'props', has a function named 'included' it will
     * be called with one argument, the 'self' Constructor function that was
     * just modified.
     *
     * @param self {function} Constructor function
     * @param props {function|object} either a Constructor function, or an
     *      object of properties to include
     * @returns {function} self
     */
    function include (self /*, props1, ..., propsN */) {
        var hasOwn = hasOwnProp,
            proto = self.prototype,
            len = arguments.length,
            i = 1,
            props, name
        ;

        for (; i < len; i++) {
            props = arguments[i];

            if (typeof props === "function") {
                extend(proto, props.prototype);
            }
            else {
                if (hasOwn.call(props, "self")) {
                    extend(self, props.self);
                }

                extend(proto, props);
            }

            if (typeof props.included === "function") {
                props.included(self);
            }
        }

        return self;
    }

    /**
     * Create a Constructor function, optionally setting its prototype to the
     * supplied object.
     *
     * When the Constructor function is called by 'new' it will attempt to
     * initialize the instance. First by calling the Constructor's "initialize"
     * method, passing the new instance and the arguments object. Then it will
     * attempt to apply the instances "init" method passing all arguments
     * as they were passed to the constructor function.
     *
     * @param proto {object} optional, object to use as the prototype
     * @returns {function} the new constructor function
     */
    function makeCtor (proto) {
        var Ctor = function Proteus () {
                var fn;

                if (arguments[0] !== _empty) {
                    if (typeof this.constructor.initialize === "function") {
                        this.constructor.initialize(this, arguments);
                    }

                    if (typeof (fn = this.init) === "function") {
                        fn.apply(this, arguments);
                    }
                }
            }
        ;

        if (proto) {
            Ctor.prototype = proto;
        }

        Ctor.prototype.constructor = Ctor;

        return Ctor;
    }

    /**
     * Dervie a new Constructor function from another, optionally adding the
     * supplied properties to its prototype.
     *
     * If the parent Constructor has a function named 'inherited' it will be
     * called with one argument, the new Constructor function.
     *
     * @param parent {function} a constructor object to derive from
     * @param props {object} optional, properties to add to the constructors prototype
     * @returns {function} a constructor function
     */
    function derive (parent, props) {
        var Ctor = makeCtor(new parent(_empty));

        O.defineProperty(Ctor, "__super__", {
            value: parent.prototype
        });

        extend(Ctor, parent);

        if (props) {
            include(Ctor, props);
        }

        if (typeof parent.inherited === "function") {
            parent.inherited(Ctor);
        }

        return Ctor;
    }

    /**
     * Interface to Object.create, however, the props argument is a plain
     * object of properties to copy over to the newly created object.
     * Getters and setters will be preserved.
     *
     * The "init" method on the object, and all of the objects prototypes,
     * will be called scoped to the new object and without any additional
     * arguments.
     *
     * @param proto {object} optional, prototype to use for the new object
     * @param props {object} properties to merge onto the new object
     * @returns {object}
     */
    function create (proto, props) {
        var obj, p;

        obj = O.create(proto || OP);

        if (props) {
            obj = extend(obj, props);
        }

        return obj;
    }

    plainSpec = extend({writable: true}, openSpec);

    /**
     * Utility method for creating 'plain' properties on an object. Plain
     * being {enumerable: true, writable: true, configurable: true}, the
     * passed spec can override these defaults.
     *
     * @param obj {object} object to define property on
     * @param name {string} property name
     * @param val {mixed} the value for the property
     * @param spec {object} optional, property specification
     * @returns {object} obj
     */
    function defineProperty(obj, name, val, spec) {
        spec = extend({value: val}, plainSpec, spec || _empty);
        return O.defineProperty(obj, name, spec);
    }

    /**
     * Utility method for creating a getter on an object. The property
     * definition will default to {enumerable: true, configurable: true}
     * unless overridden with the spec object.
     *
     * @param obj {object} object to define property on
     * @param name {string} property name
     * @param fn {function} the getter function
     * @param spec {object} optional, property specification
     * @returns {object} obj
     */
    function defineGetter (obj, name, fn, spec) {
        spec = extend({get: fn}, openSpec, spec || _empty);
        return O.defineProperty(obj, name, spec);
    }

    /**
     * Utility method for creating a setter on an object. The property
     * definition will default to {enumerable: true, configurable: true}
     * unless overridden with the spec object.
     *
     * @param obj {object} object to define property on
     * @param name {string} property name
     * @param fn {function} the setter function
     * @param spec {object} optional, property specification
     * @returns {object} obj
     */
    function defineSetter (obj, name, fn, spec) {
        spec = extend({set: fn}, openSpec, spec || _empty);
        return O.defineProperty(obj, name, spec);
    }

    /**
     * Utility method for creating both a getter and a setter on an object.
     * The property definition will default to {enumerable: true,
     * configurable: true} unless overridden with the spec object.
     *
     * @param obj {object} object to define property on
     * @param name {string} property name
     * @param getter {function} the getter function, or if 'setter' is not
     *      given, then the function will be used for both getting and
     *      setting.
     * @param setter {function} optional, the setter function
     * @param spec {object} optional, property specification
     * @returns {object} obj
     */
    function defineGetSet (obj, name, getter, setter, spec) {
        if (typeof setter !== "function") {
            spec = setter;
            setter = getter;
        }
        spec = extend({get: getter, set: setter}, openSpec, spec || _empty);
        return O.defineProperty(obj, name, spec);
    }

    /**
     * Apply a method from the objects prototype.
     *
     * @param self {object} the scope object
     * @param name {string} name of the method to call, optional if the calling
     *      function is named i.e:
     *          {
     *              init: function init () {...}
     *          }
     * @param args {array-like} arguments to pass to the method
     * @returns {mixed} whatever the prototype method would return
     */
    function applyProto (self, name, args) {
        var hasOwn = hasOwnProp,
            caller = applyProto.caller === callProto ?
                        callProto.caller :
                        applyProto.caller,
            callerFound, p
        ;

        if (typeof name !== "string") {
            args = name;
            name = caller.name;
        }

        if (!name) {
            throw new Error("Can not call prototype method without a name");
        }

        p = self;
        do {
            if (p[name] === caller) {
                callerFound = true;
                p = Object.getPrototypeOf(p);
            }

            if (p && callerFound && hasOwn.call(p, name)) {
                return p[name].apply(self, args);
            }

        }
        while ((p = Object.getPrototypeOf(p)));

        throw new Error("Can not call '" + name + "' on undefined.");
    }

    /**
     * Call a method from an objects prototype.
     *
     * @param self {object} the scope object
     * @param name {string} name of the method to call
     * @returns {mixed}
     */
    callProto = function callProto (self, name) {
        return applyProto(
            self,
            name,
            Array.prototype.slice.call(arguments, 2));
    };

    extend(exports, {

        create:  create,

        defineProperty: defineProperty,
        defineGetter:   defineGetter,
        defineSetter:   defineSetter,
        defineGetSet:   defineGetSet,

        applyProto:     applyProto,
        callProto:      callProto,

        extend:     extend,
        include:    include,
        derive:     derive,

        Class: derive(O, {
            self: {
                /**
                 * 'include' scoped to the current object
                 * @param props {object} properties to include
                 * @returns {object}
                 */
                include: function () {
                    return include.apply(
                        this,
                        [this].concat(Array.prototype.slice.call(arguments))
                    );
                },
                /**
                 * 'extend' scoped to the current object
                 * @param xtnd {object} object to extend
                 * @returns {object} the extended object
                 */
                extend:  function (xtnd) {
                    return extend(xtnd, this);
                },
                /**
                 * 'derive' scoped to the current constructor function
                 * @param props {object}
                 * @returns {function}
                 */
                derive:  function (props) {
                    return derive(this, props);
                }
            }
        })
    });

}(exports || (window.Proteus = {})));
<|endoftext|>


<commit_before>var fs = require('fs'),
    Promise = require('node-promise').Promise;

var outputFile = exports.outputFile = function outputFile(str, filepath, callback) {
    // console.log('rageout#outputFile');
    if ((!str || typeof str !== 'string') ||
        (!filepath || typeof filepath !== 'string') ||
        (!callback || typeof callback !== 'function')) throw new Error();

    fs.writeFile(filepath, str, callback);
};

var serializeData = exports.serializeData = function serializeData(obj) {
    // console.log('rageout#serializeData');
    if (typeof obj === 'undefined') throw new Error();
    return JSON.stringify(obj);
};

var generate = exports.generate = function generate(result) {
    console.log('rageout#generate');
    var promise = new Promise();
    outputFile(serializeData(result), 'imgges-'+((new Date()).toISOString()).replace(/[\-\.:a-z]/gi, '')+'.json', function (err) {
        if (err) {
            return promise.reject(err);
        }
        promise.resolve(result);
    });
    return promise;
};
<commit_msg>Comment out log statement<commit_after>var fs = require('fs'),
    Promise = require('node-promise').Promise;

var outputFile = exports.outputFile = function outputFile(str, filepath, callback) {
    // console.log('rageout#outputFile');
    if ((!str || typeof str !== 'string') ||
        (!filepath || typeof filepath !== 'string') ||
        (!callback || typeof callback !== 'function')) throw new Error();

    fs.writeFile(filepath, str, callback);
};

var serializeData = exports.serializeData = function serializeData(obj) {
    // console.log('rageout#serializeData');
    if (typeof obj === 'undefined') throw new Error();
    return JSON.stringify(obj);
};

var generate = exports.generate = function generate(result) {
    // console.log('rageout#generate');
    var promise = new Promise();
    outputFile(serializeData(result), 'imgges-'+((new Date()).toISOString()).replace(/[\-\.:a-z]/gi, '')+'.json', function (err) {
        if (err) {
            return promise.reject(err);
        }
        promise.resolve(result);
    });
    return promise;
};
<|endoftext|>


<commit_before>/*!
 *
 * Copyright (c) 2013 Sebastian Golasch
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

// Ext. libs
var _ = require('lodash');
var Q = require('q');

// Int. libs
var actions = require('dalek-internal-actions');
var assertions = require('dalek-internal-assertions');

/**
 * Prepares the test instance values
 *
 * @param {object} opts Options like the tests name, etc.
 * @constructor
 */

var Test = function (opts) {
  // prepare meta queue data
  this.actionPromiseQueue = [];

  // prepare assertion data
  this.expactation = null;
  this.runnedExpactations = 0;
  this.failedAssertions = 0;

  // prepare test specific data
  this.name = opts.name;
  this.lastChain = [];
  this.uuids = {};
  this.contextVars = {};

  if (this.name) {
    this.timeoutForDone = setTimeout(function () {
      this.done();
      this.reporter.emit('warning', 'done not called!');
    }.bind(this), 2000);
  }
};

/**
 * Generates an test instance
 *
 * @module DalekJS
 * @class Test
 * @namespace Dalek
 * @part test
 * @api
 */

Test.prototype = {

  /**
   * Specify how many assertions are expected to run within a test.
   * Very useful for ensuring that all your callbacks and assertions are run.
   *
   * @method expect
   * @param {Integer} expecatation Number of assertions that should be run
   * @chainable
   */

  expect: function (expectation) {
    this.expectation = parseInt(expectation, 10);
    return this;
  },

  /**
   * Global data store (works between the node & browser envs)
   *
   * @method expect
   * @param {string|number} key Key to store or fetch data
   * @param {mixed} value *optional* Data that should be stored
   * @return {mixed} Data that has been stored
   * @chainable
   */

  data: function (key, value) {
    if (value) {
      this.contextVars[key] = value;
      return this;
    }

    return this.contextVars[key];
  },

  /**
   * Increment the number of executed assertions
   *
   * @method incrementExpectations
   * @chainable
   */

  incrementExpectations: function () {
    this.runnedExpactations++;
    return this;
  },

  /**
   * Increment the number of failed assertions
   *
   * @method incrementFailedAssertions
   * @chainable
   */

  incrementFailedAssertions: function () {
    this.failedAssertions++;
    return this;
  },

  /**
   * Checks if the runned tests fullfill the set expectations
   * or if no expectations were raised
   *
   * @method checkExpectations
   * @return {bool} checkedExpectations Expectations match
   */

  checkExpectations: function () {
    return (this.expectation === null || !this.expectation || (this.runnedExpactations === this.expectation));
  },

  /**
   * Checks if all runned assertions passed
   *
   * @method checkAssertions
   * @return {bool} assertiosnFailed Any expectation failed
   */

  checkAssertions: function () {
    return this.failedAssertions === 0;
  },

  /**
   * Sets up all the bindings needed for a test to run
   *
   * @method done
   * @return {object} result A promise
   * @private
   */

  done: function () {
    var result = Q.resolve();
    // clear the done error timeout
    clearTimeout(this.timeoutForDone);
    // remove all previously attached event listeners to clear the message queue
    this.driver.events.removeAllListeners('driver:message');
    // resolve the deferred when the test is finished
    Test.testStarted.fin(this._testFinished.bind(this, result));
    return result;
  },

  /**
   * Emits the test finished events & resolves all promises
   * when its done
   *
   * @method _testFinished
   * @param {object} result Promised result var
   * @return {object} result Promised result var
   * @private
   */

  _testFinished: function (result) {
    // add a last deferred function on the end of the action queue,
    // to tell that this test is finished
    this.actionPromiseQueue.push(this._testFin.bind(this));

    // initialize all of the event receiver functions,
    // that later take the driver result
    this.actionPromiseQueue.forEach(function (f) {
      result = result.then(f).fail(function () {
        console.error(arguments);
        process.exit(0);
      });
    }.bind(this));

    // run the driver when all actions are stored in the queue
    Q.allSettled(this.actionPromiseQueue)
      .then(this.driver.run.bind(this.driver));

    return result;
  },

  /**
   * Emits the test started event
   *
   * @method _reportTestStarted
   * @param {string} name Name of the test
   * @chainable
   * @private
   */

  _reportTestStarted: function (name) {
    this.reporter.emit('report:test:started', {name: name});
    return this;
  },

  /**
   * Checks if the test run is complete & emits/resolves
   * all the needed events/promises when the run is complete
   *
   * @method _onDriverMessage
   * @param {object} data Data that is returned by the driver:message event
   * @chainable
   * @private
   */

  _onDriverMessage: function (data) {
    // check if the test run is complete
    if (data && data.key === 'run.complete') {
      // emit the test finish events & resolve the deferred
      this._emitConcreteTestFinished();
      this._emitAssertionStatus();
      this._emitTestFinished();
      this.deferred.resolve();
    }

    return this;
  },

  /**
   * Emits an event, that the current test run has been finished
   *
   * @method _emitConcreteTestFinished
   * @chainable
   * @private
   */

  _emitConcreteTestFinished: function () {
    this.events.emit('test:' + this._uid + ':finished', 'test:finished', this);
    return this;
  },

  /**
   * Emits an event that describes the current state of all assertions
   *
   * @method _emitAssertionStatus
   * @chainable
   * @private
   */

  _emitAssertionStatus: function () {
    this.reporter.emit('report:assertion:status', {
      expected: (this.expectation ? this.expectation : this.runnedExpactations),
      run: this.runnedExpactations,
      status: this._testStatus()
    });
    return this;
  },

  /**
   * Get the overall test status (assertions & expectation)
   *
   * @method _testStatus
   * @return {bool} status The test status
   * @chainable
   * @private
   */

  _testStatus: function () {
    return this.checkExpectations() && this.checkAssertions();
  },

  /**
   * Emits an event that describes the current state of all assertions.
   * The event should be fired when a test is finished
   *
   * @method _emitTestFinished
   * @chainable
   * @private
   */

  _emitTestFinished: function () {
    this.reporter.emit('report:test:finished', {
      name: this.name,
      id: this._uid,
      passedAssertions: this.runnedExpactations - this.failedAssertions,
      failedAssertions: this.failedAssertions,
      runnedExpactations: this.runnedExpactations,
      status: this._testStatus(),
      nl: true
    });

    return this;
  },

  /**
   * Kicks off the test & binds all promises/events
   *
   * @method _testFin
   * @return {object} promise A promise
   * @private
   */

  _testFin: function () {
    this.deferred = Q.defer();

    if (_.isFunction(this.driver.end)) {
      this.driver.end();
    }

    // emit report startet event
    this._reportTestStarted(this.name);

    // listen to all the messages from the driver
    this.driver.events.on('driver:message', this._onDriverMessage.bind(this));
    return this.deferred.promise;
  },

  /**
   * Copies assertion methods
   *
   * @method _inheritAssertions
   * @param {Test} test Instacne of test
   * @chainable
   * @private
   */

  _inheritAssertions: function (test) {
    ['is'].forEach(function (method) {
      test[method] = test.assert[method].bind(test.assert);
    });
    return test;
  },

  /**
   * Copies assertion helper methods
   *
   * @method _inheritAssertions
   * @param {Test} test Instacne of test
   * @chainable
   * @private
   */

  _inheritAssertionHelpers: function (test) {
    ['not', 'between', 'gt', 'gte', 'lt', 'lte'].forEach(function (method) {
      test.is[method] = test.assert[method].bind(test.assert);
      test.assert.is[method] = test.assert[method].bind(test.assert);
    });
    ['contain'].forEach(function (method) {
      test.to = {};
      test.assert.to = {};

      test.to[method] = test.assert[method].bind(test.assert);
      test.assert.to[method] = test.assert[method].bind(test.assert);
    });
    return test;
  },

  /**
   * Set up the instance
   *
   * @method _inheritAssertions
   * @param {Test} test Instacne of test
   * @param {object} opts Options
   * @chainable
   * @private
   */

  _initialize: function (test, opts) {
    test._uid = _.uniqueId('test');
    test.events = opts.events;
    test.driver = opts.driver;
    test.reporter = opts.reporter;
    return test;
  }

};

// export a function that generates a new test instance
module.exports = function (opts) {
  // mixin assertions, actions & getters
  Test.prototype = _.extend(Test.prototype, actions({reporter: opts.reporter}).prototype);
  var test = new Test(opts);
  test.assert = new (assertions())({test: test});
  test.assert.done = test.done.bind(this);
  test.assert.query = test.query.bind(test.assert);
  test.assert.$ = test.query.bind(test.assert);
  test.end = test.assert.end.bind(test.assert);

  // copy log methods
  test.log = {};
  test.log.dom = test.logger.dom.bind(test);
  test.log.message = test.logger.message.bind(test);

  // copy assertions methods
  test = test._inheritAssertions(test);

  // copy assertion helper methods
  test = test._inheritAssertionHelpers(test);

  // initialize the instance
  test = test._initialize(test, opts);

  // TODO: Promise driver start
  // so that we can reexecute them and clean the env between tests
  Test.testStarted = test.driver.start(Q);
  return test;
};
<commit_msg>fix(test) fixed paths to internal modules<commit_after>/*!
 *
 * Copyright (c) 2013 Sebastian Golasch
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

// Ext. libs
var _ = require('lodash');
var Q = require('q');

// Int. libs
var actions = require('./actions');
var assertions = require('./assertions');

/**
 * Prepares the test instance values
 *
 * @param {object} opts Options like the tests name, etc.
 * @constructor
 */

var Test = function (opts) {
  // prepare meta queue data
  this.actionPromiseQueue = [];

  // prepare assertion data
  this.expactation = null;
  this.runnedExpactations = 0;
  this.failedAssertions = 0;

  // prepare test specific data
  this.name = opts.name;
  this.lastChain = [];
  this.uuids = {};
  this.contextVars = {};

  if (this.name) {
    this.timeoutForDone = setTimeout(function () {
      this.done();
      this.reporter.emit('warning', 'done not called!');
    }.bind(this), 2000);
  }
};

/**
 * Generates an test instance
 *
 * @module DalekJS
 * @class Test
 * @namespace Dalek
 * @part test
 * @api
 */

Test.prototype = {

  /**
   * Specify how many assertions are expected to run within a test.
   * Very useful for ensuring that all your callbacks and assertions are run.
   *
   * @method expect
   * @param {Integer} expecatation Number of assertions that should be run
   * @chainable
   */

  expect: function (expectation) {
    this.expectation = parseInt(expectation, 10);
    return this;
  },

  /**
   * Global data store (works between the node & browser envs)
   *
   * @method expect
   * @param {string|number} key Key to store or fetch data
   * @param {mixed} value *optional* Data that should be stored
   * @return {mixed} Data that has been stored
   * @chainable
   */

  data: function (key, value) {
    if (value) {
      this.contextVars[key] = value;
      return this;
    }

    return this.contextVars[key];
  },

  /**
   * Increment the number of executed assertions
   *
   * @method incrementExpectations
   * @chainable
   */

  incrementExpectations: function () {
    this.runnedExpactations++;
    return this;
  },

  /**
   * Increment the number of failed assertions
   *
   * @method incrementFailedAssertions
   * @chainable
   */

  incrementFailedAssertions: function () {
    this.failedAssertions++;
    return this;
  },

  /**
   * Checks if the runned tests fullfill the set expectations
   * or if no expectations were raised
   *
   * @method checkExpectations
   * @return {bool} checkedExpectations Expectations match
   */

  checkExpectations: function () {
    return (this.expectation === null || !this.expectation || (this.runnedExpactations === this.expectation));
  },

  /**
   * Checks if all runned assertions passed
   *
   * @method checkAssertions
   * @return {bool} assertiosnFailed Any expectation failed
   */

  checkAssertions: function () {
    return this.failedAssertions === 0;
  },

  /**
   * Sets up all the bindings needed for a test to run
   *
   * @method done
   * @return {object} result A promise
   * @private
   */

  done: function () {
    var result = Q.resolve();
    // clear the done error timeout
    clearTimeout(this.timeoutForDone);
    // remove all previously attached event listeners to clear the message queue
    this.driver.events.removeAllListeners('driver:message');
    // resolve the deferred when the test is finished
    Test.testStarted.fin(this._testFinished.bind(this, result));
    return result;
  },

  /**
   * Emits the test finished events & resolves all promises
   * when its done
   *
   * @method _testFinished
   * @param {object} result Promised result var
   * @return {object} result Promised result var
   * @private
   */

  _testFinished: function (result) {
    // add a last deferred function on the end of the action queue,
    // to tell that this test is finished
    this.actionPromiseQueue.push(this._testFin.bind(this));

    // initialize all of the event receiver functions,
    // that later take the driver result
    this.actionPromiseQueue.forEach(function (f) {
      result = result.then(f).fail(function () {
        console.error(arguments);
        process.exit(0);
      });
    }.bind(this));

    // run the driver when all actions are stored in the queue
    Q.allSettled(this.actionPromiseQueue)
      .then(this.driver.run.bind(this.driver));

    return result;
  },

  /**
   * Emits the test started event
   *
   * @method _reportTestStarted
   * @param {string} name Name of the test
   * @chainable
   * @private
   */

  _reportTestStarted: function (name) {
    this.reporter.emit('report:test:started', {name: name});
    return this;
  },

  /**
   * Checks if the test run is complete & emits/resolves
   * all the needed events/promises when the run is complete
   *
   * @method _onDriverMessage
   * @param {object} data Data that is returned by the driver:message event
   * @chainable
   * @private
   */

  _onDriverMessage: function (data) {
    // check if the test run is complete
    if (data && data.key === 'run.complete') {
      // emit the test finish events & resolve the deferred
      this._emitConcreteTestFinished();
      this._emitAssertionStatus();
      this._emitTestFinished();
      this.deferred.resolve();
    }

    return this;
  },

  /**
   * Emits an event, that the current test run has been finished
   *
   * @method _emitConcreteTestFinished
   * @chainable
   * @private
   */

  _emitConcreteTestFinished: function () {
    this.events.emit('test:' + this._uid + ':finished', 'test:finished', this);
    return this;
  },

  /**
   * Emits an event that describes the current state of all assertions
   *
   * @method _emitAssertionStatus
   * @chainable
   * @private
   */

  _emitAssertionStatus: function () {
    this.reporter.emit('report:assertion:status', {
      expected: (this.expectation ? this.expectation : this.runnedExpactations),
      run: this.runnedExpactations,
      status: this._testStatus()
    });
    return this;
  },

  /**
   * Get the overall test status (assertions & expectation)
   *
   * @method _testStatus
   * @return {bool} status The test status
   * @chainable
   * @private
   */

  _testStatus: function () {
    return this.checkExpectations() && this.checkAssertions();
  },

  /**
   * Emits an event that describes the current state of all assertions.
   * The event should be fired when a test is finished
   *
   * @method _emitTestFinished
   * @chainable
   * @private
   */

  _emitTestFinished: function () {
    this.reporter.emit('report:test:finished', {
      name: this.name,
      id: this._uid,
      passedAssertions: this.runnedExpactations - this.failedAssertions,
      failedAssertions: this.failedAssertions,
      runnedExpactations: this.runnedExpactations,
      status: this._testStatus(),
      nl: true
    });

    return this;
  },

  /**
   * Kicks off the test & binds all promises/events
   *
   * @method _testFin
   * @return {object} promise A promise
   * @private
   */

  _testFin: function () {
    this.deferred = Q.defer();

    if (_.isFunction(this.driver.end)) {
      this.driver.end();
    }

    // emit report startet event
    this._reportTestStarted(this.name);

    // listen to all the messages from the driver
    this.driver.events.on('driver:message', this._onDriverMessage.bind(this));
    return this.deferred.promise;
  },

  /**
   * Copies assertion methods
   *
   * @method _inheritAssertions
   * @param {Test} test Instacne of test
   * @chainable
   * @private
   */

  _inheritAssertions: function (test) {
    ['is'].forEach(function (method) {
      test[method] = test.assert[method].bind(test.assert);
    });
    return test;
  },

  /**
   * Copies assertion helper methods
   *
   * @method _inheritAssertions
   * @param {Test} test Instacne of test
   * @chainable
   * @private
   */

  _inheritAssertionHelpers: function (test) {
    ['not', 'between', 'gt', 'gte', 'lt', 'lte'].forEach(function (method) {
      test.is[method] = test.assert[method].bind(test.assert);
      test.assert.is[method] = test.assert[method].bind(test.assert);
    });
    ['contain'].forEach(function (method) {
      test.to = {};
      test.assert.to = {};

      test.to[method] = test.assert[method].bind(test.assert);
      test.assert.to[method] = test.assert[method].bind(test.assert);
    });
    return test;
  },

  /**
   * Set up the instance
   *
   * @method _inheritAssertions
   * @param {Test} test Instacne of test
   * @param {object} opts Options
   * @chainable
   * @private
   */

  _initialize: function (test, opts) {
    test._uid = _.uniqueId('test');
    test.events = opts.events;
    test.driver = opts.driver;
    test.reporter = opts.reporter;
    return test;
  }

};

// export a function that generates a new test instance
module.exports = function (opts) {
  // mixin assertions, actions & getters
  Test.prototype = _.extend(Test.prototype, actions({reporter: opts.reporter}).prototype);
  var test = new Test(opts);
  test.assert = new (assertions())({test: test});
  test.assert.done = test.done.bind(this);
  test.assert.query = test.query.bind(test.assert);
  test.assert.$ = test.query.bind(test.assert);
  test.end = test.assert.end.bind(test.assert);

  // copy log methods
  test.log = {};
  test.log.dom = test.logger.dom.bind(test);
  test.log.message = test.logger.message.bind(test);

  // copy assertions methods
  test = test._inheritAssertions(test);

  // copy assertion helper methods
  test = test._inheritAssertionHelpers(test);

  // initialize the instance
  test = test._initialize(test, opts);

  // TODO: Promise driver start
  // so that we can reexecute them and clean the env between tests
  Test.testStarted = test.driver.start(Q);
  return test;
};
<|endoftext|>


<commit_before>const deepMerge = (base, override) => {
  if (override === undefined) {
    return base || {};
  }

  let mergedObj = Object.assign({}, base);

  Object.keys(override).forEach((key) => {
    if (isObject(override[key])) {
      if (!base.hasOwnProperty(key)) {
        Object.assign(mergedObj, {
          [key]: override[key]
        });
      } else {
        mergedObj[key] = deepMerge(base[key], override[key]);
      }
    } else {
      Object.assign(mergedObj, {
        [key]: override[key]
      });
    }
  });

  return mergedObj;
};

const isObject = (item) => {
  return typeof item === 'object' && !Array.isArray(item) && item !== null;
};

module.exports = deepMerge
<commit_msg>Adjust merge function per @developit's suggestion<commit_after>const deepMerge = (base, override) => {
  if (override === undefined) {
    return base || {};
  }

  let mergedObj = Object.assign({}, base);

  Object.keys(override).forEach((key) => {
    if (isObject(override[key])) {
      if (!base.hasOwnProperty(key)) {
        mergedObj[key] = override[key];
      } else {
        mergedObj[key] = deepMerge(base[key], override[key]);
      }
    } else {
      mergedObj[key] = override[key];
    }
  });

  return mergedObj;
};

const isObject = (item) => {
  return typeof item === 'object' && !Array.isArray(item) && item !== null;
};

module.exports = deepMerge
<|endoftext|>


<commit_before>'use strict'
const fs = require('fs')
const path = require('path')

module.exports = class Deployment {
  constructor (inspectData, name, boundMounts) {
    this.inspectData = inspectData
    this.name = name
    this.ports = inspectData.Config.ExposedPorts
    this.envs = inspectData.Config.Env
    this.image = inspectData.Config.Image
    this.command = inspectData.Config.Entrypoint
    this.args = inspectData.Config.Cmd
    this.boundMounts = boundMounts
  }

  getJsonDeployment () {
    const out = {}
    const jsonConfig = this._createRootConfig()
    this._addVolumesToSpecIfNeeded(jsonConfig.spec.template.spec)
    this._addCommandIfNeeded(jsonConfig.spec.template.spec)
    this._addPortsIfNeeded(jsonConfig.spec.template.spec)

    out[this.name] = jsonConfig
    return out
  }

  _addVolumesToSpecIfNeeded (spec) {
    if (this._isMountsBound()) {
      spec.volumes = this._getVolumesConfig()
      spec.containers[0].volumeMounts = this._getVolumesMountConfig()
    }
  }

  _addCommandIfNeeded (spec) {
    if (this.command) {
      spec.containers[0].command = this.command
    }
  }

  _addPortsIfNeeded (spec) {
    if (this.ports) {
      spec.containers[0].ports = this._getPorts()
    }
  }

  _getVolumesConfig () {
    return this.boundMounts.map(this._getVolumeConfig.bind(this))
  }

  _getVolumeConfig (mount) {
    const mountName = this._getMountName(mount)

    return {
      name: mountName,
      configMap: {
        name: mountName
      }
    }
  }

  _getVolumesMountConfig () {
    const boundMounts = this.boundMounts

    return boundMounts.map(this._getVolumeMountConfig.bind(this))
  }

  _getVolumeMountConfig (mount) {
    let mountPath = mount.Destination
    const mountName = this._getMountName(mount)
    const isFile = fs.lstatSync(mount.Source).isFile()

    if (isFile) {
      mountPath = path.dirname(mountPath)
    }
    return {
      name: mountName,
      mountPath
    }
  }

  _createRootConfig () {
    const name = this.name
    const image = this.image
    const args = this.args

    return {
      apiVersion: 'extensions/v1beta1',
      kind: 'Deployment',
      metadata: {
        name
      },
      spec: {
        replicas: 1,
        template: {
          metadata: {
            labels: {
              app: name
            }
          },
          spec: {
            containers: [{
              image,
              name,
              args,
              env: this._getEnvs()
            }]
          }
        }
      }
    }
  }

  _getEnvs () {
    return this.envs.map(this._parseEnv)
  }

  _parseEnv (env) {
    const split = env.split('=')
    const name = split[0]
    const value = split[1]
    return {
      name,
      value
    }
  }

  _getPorts () {
    return Object
      .keys(this.ports)
      .map(this._getContainerPort)
  }

  _getContainerPort (portAndProtocol) {
    return {
      containerPort: parseInt(portAndProtocol.split('/')[0], 10)
    }
  }

  // TODO merge with other
  _isMountsBound () {
    return !!this.boundMounts.length
  }
  // TODO merge with other
  _getMountName (mount) {
    return `${this.name}${mount.Destination}`.replace(/\//g, '-').replace(/\./g, '-')
  }
}
<commit_msg>fix spacing<commit_after>'use strict'
const fs = require('fs')
const path = require('path')

module.exports = class Deployment {
  constructor (inspectData, name, boundMounts) {
    this.inspectData = inspectData
    this.name = name
    this.ports = inspectData.Config.ExposedPorts
    this.envs = inspectData.Config.Env
    this.image = inspectData.Config.Image
    this.command = inspectData.Config.Entrypoint
    this.args = inspectData.Config.Cmd
    this.boundMounts = boundMounts
  }

  getJsonDeployment () {
    const out = {}
    const jsonConfig = this._createRootConfig()

    this._addVolumesToSpecIfNeeded(jsonConfig.spec.template.spec)
    this._addCommandIfNeeded(jsonConfig.spec.template.spec)
    this._addPortsIfNeeded(jsonConfig.spec.template.spec)

    out[this.name] = jsonConfig
    return out
  }

  _addVolumesToSpecIfNeeded (spec) {
    if (this._isMountsBound()) {
      spec.volumes = this._getVolumesConfig()
      spec.containers[0].volumeMounts = this._getVolumesMountConfig()
    }
  }

  _addCommandIfNeeded (spec) {
    if (this.command) {
      spec.containers[0].command = this.command
    }
  }

  _addPortsIfNeeded (spec) {
    if (this.ports) {
      spec.containers[0].ports = this._getPorts()
    }
  }

  _getVolumesConfig () {
    return this.boundMounts.map(this._getVolumeConfig.bind(this))
  }

  _getVolumeConfig (mount) {
    const mountName = this._getMountName(mount)

    return {
      name: mountName,
      configMap: {
        name: mountName
      }
    }
  }

  _getVolumesMountConfig () {
    const boundMounts = this.boundMounts

    return boundMounts.map(this._getVolumeMountConfig.bind(this))
  }

  _getVolumeMountConfig (mount) {
    let mountPath = mount.Destination
    const mountName = this._getMountName(mount)
    const isFile = fs.lstatSync(mount.Source).isFile()

    if (isFile) {
      mountPath = path.dirname(mountPath)
    }
    return {
      name: mountName,
      mountPath
    }
  }

  _createRootConfig () {
    const name = this.name
    const image = this.image
    const args = this.args

    return {
      apiVersion: 'extensions/v1beta1',
      kind: 'Deployment',
      metadata: {
        name
      },
      spec: {
        replicas: 1,
        template: {
          metadata: {
            labels: {
              app: name
            }
          },
          spec: {
            containers: [{
              image,
              name,
              args,
              env: this._getEnvs()
            }]
          }
        }
      }
    }
  }

  _getEnvs () {
    return this.envs.map(this._parseEnv)
  }

  _parseEnv (env) {
    const split = env.split('=')
    const name = split[0]
    const value = split[1]
    return {
      name,
      value
    }
  }

  _getPorts () {
    return Object
      .keys(this.ports)
      .map(this._getContainerPort)
  }

  _getContainerPort (portAndProtocol) {
    return {
      containerPort: parseInt(portAndProtocol.split('/')[0], 10)
    }
  }

  // TODO merge with other
  _isMountsBound () {
    return !!this.boundMounts.length
  }
  // TODO merge with other
  _getMountName (mount) {
    return `${this.name}${mount.Destination}`.replace(/\//g, '-').replace(/\./g, '-')
  }
}
<|endoftext|>


<commit_before>/** @jsx React.DOM */
'use strict';
var React = require('react');
var globals = require('./globals');
var parseError = require('./mixins').parseError;
var FetchedData = require('./fetched').FetchedData;
var _ = require('underscore');

var ItemEdit = module.exports.ItemEdit = React.createClass({
    render: function() {
        var context = this.props.context;
        var itemClass = globals.itemClass(context, 'view-item');
        var title = globals.listing_titles.lookup(context)({context: context});
        var url = this.props.context['@id'] + '?frame=edit'
        return (

Edit {title}

                {this.transferPropsTo(
                    <FetchedData Component={EditForm} url={url} />
                )}

        );
    }
});

var EditForm = module.exports.EditForm = React.createClass({
    render: function () {
        var error = this.state.error;
        return (

                    Cancel
                    {' '}
                    <button onClick={this.save} className="btn btn-success" disabled={this.communicating}>Save</button>

                    {error && error.code === 422 ? error.errors.map(function (error) {
                        return
{'/' + error.name.join('/') + ': '}{error.description}
;
                    }) : error ?
{JSON.stringify(error)}
 : null}

        );
    },

    componentDidMount: function () {
        var ace = require('brace');
        require('brace/mode/json');
        require('brace/theme/solarized_light');
        var value = JSON.stringify(this.props.data, null, 4)
        var editor = ace.edit(this.refs.editor.getDOMNode());
        editor.getSession().setMode('ace/mode/json');
        editor.setValue(value);
        // These options will take effect with the next brace release
        editor.setOptions({
            maxLines: 1000,
            minLines: 24
        })
        editor.clearSelection();
        this.setState({editor: editor});
    },

    getInitialState: function () {
        return {
            communicating: false,
            data: undefined,
            putRequest: undefined,
            erred: false
        };
    },

    save: function (event) {
        var value = this.state.editor.getValue();
        try {
            var parsed = JSON.parse(value);
        } catch (e) {
            this.setState({error: 'Invalid JSON'});
            return;
        }
        var url = this.props.context['@id'];

        var xhr = $.ajax({
            url: url,
            type: 'PUT',
            contentType: "application/json",
            data: value,
            dataType: 'json'
        }).fail(this.fail)
        .done(this.receive);
        xhr.href = url;
        this.setState({
            communicating: true,
            putRequest: xhr
        });
        xhr.done(this.finish);

    },

    finish: function () {
        window.location.assign('');
    },

    fail: function (xhr, status, error) {
        if (status == 'abort') return;
        var ga = window.ga;
        var data = parseError(xhr, status);
        ga('send', 'exception', {
            'exDescription': 'putRequest:' + status + ':' + xhr.statusText,
            'location': window.location.href
        });
        this.receive(data, status, xhr, true);
    },

    receive: function (data, status, xhr, erred) {
        this.setState({
            data: data,
            communicating: false,
            erred: erred,
            error: erred ? data : undefined
        });
    }
});

globals.content_views.register(ItemEdit, 'item', 'edit');
<commit_msg>Editor tweaks.<commit_after>/** @jsx React.DOM */
'use strict';
var React = require('react');
var globals = require('./globals');
var parseError = require('./mixins').parseError;
var FetchedData = require('./fetched').FetchedData;
var _ = require('underscore');

var ItemEdit = module.exports.ItemEdit = React.createClass({
    render: function() {
        var context = this.props.context;
        var itemClass = globals.itemClass(context, 'view-item');
        var title = globals.listing_titles.lookup(context)({context: context});
        var url = this.props.context['@id'] + '?frame=edit'
        return (

Edit {title}

                {this.transferPropsTo(
                    <FetchedData Component={EditForm} url={url} />
                )}

        );
    }
});

var EditForm = module.exports.EditForm = React.createClass({
    render: function () {
        var error = this.state.error;
        return (

                    Cancel
                    {' '}
                    <button onClick={this.save} className="btn btn-success" disabled={this.communicating || this.state.editor_error}>Save</button>

                    {error && error.code === 422 ? error.errors.map(function (error) {
                        return
{'/' + error.name.join('/') + ': '}{error.description}
;
                    }) : error ?
{JSON.stringify(error)}
 : null}

        );
    },

    componentDidMount: function () {
        var ace = require('brace');
        require('brace/mode/json');
        require('brace/theme/solarized_light');
        var value = JSON.stringify(this.props.data, null, 4)
        var editor = ace.edit(this.refs.editor.getDOMNode());
        var session = editor.getSession()
        session.setMode('ace/mode/json');
        editor.setValue(value);
        // These options will take effect with the next brace release
        editor.setOptions({
            maxLines: 1000,
            minLines: 24
        })
        editor.clearSelection();
        this.setState({editor: editor});
        session.on("changeAnnotation", this.hasErrors);
    },

    hasErrors: function () {
        var annotations = this.state.editor.getSession().getAnnotations();
        var has_error = annotations.reduce(function (value, anno) {
            return value || (anno.type === "error");
        }, false);
        this.setState({editor_error: has_error});
    },

    getInitialState: function () {
        return {
            communicating: false,
            data: undefined,
            putRequest: undefined,
            erred: false
        };
    },

    save: function (event) {
        var value = this.state.editor.getValue();
        var url = this.props.context['@id'];
        var xhr = $.ajax({
            url: url,
            type: 'PUT',
            contentType: "application/json",
            data: value,
            dataType: 'json'
        }).fail(this.fail)
        .done(this.receive);
        xhr.href = url;
        this.setState({
            communicating: true,
            putRequest: xhr
        });
        xhr.done(this.finish);
    },

    finish: function () {
        window.location.assign('');
    },

    fail: function (xhr, status, error) {
        if (status == 'abort') return;
        var ga = window.ga;
        var data = parseError(xhr, status);
        ga('send', 'exception', {
            'exDescription': 'putRequest:' + status + ':' + xhr.statusText,
            'location': window.location.href
        });
        this.receive(data, status, xhr, true);
    },

    receive: function (data, status, xhr, erred) {
        this.setState({
            data: data,
            communicating: false,
            erred: erred,
            error: erred ? data : undefined
        });
    }
});

globals.content_views.register(ItemEdit, 'item', 'edit');
<|endoftext|>