<commit_before>"use strict";
var when = require('when'),
    arrays = require('./arrays'),
    funcs = require('./funcs'),
    Consumer = require('./consumer'),
    push = arrays.push,
    has = funcs.has,
    isArray = funcs.isArray,
    isFunction = funcs.isFunction,
    isStream = funcs.isStream

module.exports = Producer
function Producer(onSubscribe){
  this.onSubscribe = onSubscribe
}
var P = Producer.prototype

Producer.isProducer = isProducer
function isProducer(producer){
 return  producer instanceof Producer
}

Producer.wrap = wrap
function wrap(delegate){
  return isProducer(delegate) ? delegate
    : new Producer(
        isStream(delegate) ? Consumer.stream(delegate)
      : isArray(delegate) ? Consumer.seqNextResolve(delegate)
      : Consumer.resolveValue({value:delegate}))
}

P.subscribe = subscribe
function subscribe(next, complete, error){
  /*jshint validthis:true*/
  var consumer = Consumer.wrap(next, complete, error)
    , producer = this._unwrap()

  if(producer.onSubscribe){
    producer.onSubscribe(consumer)
  }

  return consumer
}

P._unwrap = _unwrap
function _unwrap(){
  /*jshint validthis:true*/
  return this
}

P.then = then
function then(resolve, error, progress){
  /*jshint validthis:true*/
  var deferred = when.defer()
    , resolver = deferred.resolver
    , self = this._unwrap()
    // no need to buffer if no resolve function
    , collectResults = isFunction(resolve)
    , results = []
    , consumer = new Consumer(
        function(result){
          if(collectResults){
            if(consumer.resolveSingleValue){
              results = [result]
            } else {
              push.call(results, result)
            }
          }
          resolver.notify(result)
        }
      , function(){
          var result = collectResults &&
                  has(self, 'resolvedValue')
                ? self.resolvedValue
                : consumer.resolveSingleValue
                  ? results[results.length - 1]
                  : results
          resolver.resolve(result)
        }
      , function(err){
          resolver.reject(err)
        })
  self.subscribe(consumer)

  return deferred.promise
    .then(resolve, error, progress)
}

<commit_msg>Remove check for resolvedValue in producer then, artifact of old deferred<commit_after>"use strict";
var when = require('when'),
    arrays = require('./arrays'),
    funcs = require('./funcs'),
    Consumer = require('./consumer'),
    push = arrays.push,
    has = funcs.has,
    isArray = funcs.isArray,
    isFunction = funcs.isFunction,
    isStream = funcs.isStream

module.exports = Producer
function Producer(onSubscribe){
  this.onSubscribe = onSubscribe
}
var P = Producer.prototype

Producer.isProducer = isProducer
function isProducer(producer){
 return  producer instanceof Producer
}

Producer.wrap = wrap
function wrap(delegate){
  return isProducer(delegate) ? delegate
    : new Producer(
        isStream(delegate) ? Consumer.stream(delegate)
      : isArray(delegate) ? Consumer.seqNextResolve(delegate)
      : Consumer.resolveValue({value:delegate}))
}

P.subscribe = subscribe
function subscribe(next, complete, error){
  /*jshint validthis:true*/
  var consumer = Consumer.wrap(next, complete, error)
    , producer = this._unwrap()

  if(producer.onSubscribe){
    producer.onSubscribe(consumer)
  }

  return consumer
}

P._unwrap = _unwrap
function _unwrap(){
  /*jshint validthis:true*/
  return this
}

P.then = then
function then(resolve, error, progress){
  /*jshint validthis:true*/
  var deferred = when.defer()
    , resolver = deferred.resolver
    , self = this._unwrap()
    // no need to buffer if no resolve function
    , collectResults = isFunction(resolve)
    , results = []
    , consumer = new Consumer(
        function(result){
          if(collectResults){
            if(consumer.resolveSingleValue){
              results = [result]
            } else {
              push.call(results, result)
            }
          }
          resolver.notify(result)
        }
      , function(){
          var result = collectResults &&
                consumer.resolveSingleValue
                ? results[results.length - 1]
                : results
          resolver.resolve(result)
        }
      , function(err){
          resolver.reject(err)
        })
  self.subscribe(consumer)

  return deferred.promise
    .then(resolve, error, progress)
}

<|endoftext|>


<commit_before>/* Gyppo - optional client library
 * simple logger to send client errors to the Gyppo server
 *
 * example usage:
 *   var logger = new Gyppo({ url: "/gyppo_log_url"});
 *   logger.log.error("Oh noes");
 *
 * NOTE: logs all errors to the server by default. if you don't want
 * it to, pass log_errors: false in the options param object
 */
(function(){
    window.Gyppo = function(options){
        // allow our defaults to be overridden
        this.options = $.extend(this.options, options);

        if (this.options.log_errors) this.bindErrorLogger();

        this.initLevels();
    };

    $.extend(Gyppo.prototype, {
        options: {
            url:           "/log",
            success:       $.noop,
            error:         $.noop,
            default_level: "info",

            // make sure these map to the backend
            log_levels:    [
                "info",
                "debug",
                "warn",
                "error"
            ],

            // log all errors to the server?
            log_errors: true,

            // you can define a custom method for choosing what
            // metadata you want to include in the report to the
            // server
            meta_data: function(){
                return {
                    ua:    navigator.userAgent,
                    href:  window.location.href
                }
            }
        },

        // makes all errors log to the server
        bindErrorLogger: function(){
            var instance = this;
            window.onerror = function(message, file, line) {
                instance.log.error(file + ':' + line + '\n\n' + message);
            };
        },

        // build out instance.log.debug, instance.log.error, etc
        initLevels: function(){
            var instance = this;
            var logger = this.log = {};

            $.each(this.options.log_levels, function(i, level){
                logger[level] = function(message){
                    instance.logToServer(level, message, instance.options.success, instance.options.error);
                };

                // index the levels for easy lookup
                instance.log_levels_map[level] = i;
            });
        },

        logToServer: function(level, message, success, error){
            if (this.log_levels_map[level] < this.log_levels_map[this.options.default_level]) return;

            return $.ajax({
                type: "POST",
                url:  this.options.url,
                data: {
                    level:     level,
                    message:   message,
                    meta_data: $.isFunction(this.options.meta_data) ? this.options.meta_data() : {}
                },
                success:  $.isFunction(success) ? success : $.noop,
                error:    $.isFunction(error)   ? error   : $.noop
            });
        }
    });
})();
<commit_msg>fixing log_level_map undefined<commit_after>/* Gyppo - optional client library
 * simple logger to send client errors to the Gyppo server
 *
 * example usage:
 *   var logger = new Gyppo({ url: "/gyppo_log_url"});
 *   logger.log.error("Oh noes");
 *
 * NOTE: logs all errors to the server by default. if you don't want
 * it to, pass log_errors: false in the options param object
 */
(function(){
    window.Gyppo = function(options){
        // allow our defaults to be overridden
        this.options = $.extend(this.options, options);

        if (this.options.log_errors) this.bindErrorLogger();

        this.initLevels();
    };

    $.extend(Gyppo.prototype, {
        options: {
            url:           "/log",
            success:       $.noop,
            error:         $.noop,
            default_level: "info",

            // make sure these map to the backend
            log_levels:    [
                "info",
                "debug",
                "warn",
                "error"
            ],

            // log all errors to the server?
            log_errors: true,

            // you can define a custom method for choosing what
            // metadata you want to include in the report to the
            // server
            meta_data: function(){
                return {
                    ua:    navigator.userAgent,
                    href:  window.location.href
                }
            }
        },

        // makes all errors log to the server
        bindErrorLogger: function(){
            var instance = this;
            window.onerror = function(message, file, line) {
                instance.log.error(file + ':' + line + '\n\n' + message);
            };
        },

        // build out instance.log.debug, instance.log.error, etc
        initLevels: function(){
            var instance = this;
            var logger = this.log = {};
            this.log_levels_map   = {};

            $.each(this.options.log_levels, function(i, level){
                logger[level] = function(message){
                    instance.logToServer(level, message, instance.options.success, instance.options.error);
                };

                // index the levels for easy lookup
                instance.log_levels_map[level] = i;
            });
        },

        logToServer: function(level, message, success, error){
            if (this.log_levels_map[level] < this.log_levels_map[this.options.default_level]) return;

            return $.ajax({
                type: "POST",
                url:  this.options.url,
                data: {
                    level:     level,
                    message:   message,
                    meta_data: $.isFunction(this.options.meta_data) ? this.options.meta_data() : {}
                },
                success:  $.isFunction(success) ? success : $.noop,
                error:    $.isFunction(error)   ? error   : $.noop
            });
        }
    });
})();
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost:27017/ang');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
db.on('error', console.error.bind(console, 'connection error'));
db.once('open', function(){

});<commit_msg>Removed old db file<commit_after><|endoftext|>


<commit_before>export { TwinArray };

import * as TensorPlaceholder from "../TensorPlaceholder.js";
import { Root } from "./Operation_Base.js";

/**
 * An array of operations. Every time appending operation, one or parallel twin operations could be appended.
 *
 * No matter how many sub operations (even no sub operation) are appended, this TwinArray's .output0 and .output1 (tensor
 * placeholder) are always .endingDummyOperation.output0 and .endingDummyOperation.output1 in fact. The .endingInput0
 * and endingInput1 are always .endingDummyOperation.input0 and .endingDummyOperation.input1 in fact. This could
 * simplify the decision of what tensor placeholders should be used as the next (appended) operation's input.
 *
 *
 * Note: The .outputTensorCount is determined when constructor is called. No matter what kind of operation is appended
 * (even if the is no operation is appended), the outputTensorCount will not be changed.
 *
 *
 *
 * @member {TensorPlaceholder.Base} endingInput0
 *   The last sub operation's output0 (also .endingDummyOperation.input0). It could be used as input of next appended sub operation.
 *
 * @member {TensorPlaceholder.Base} endingInput1
 *   The last sub operation's output1 (also .endingDummyOperation.input1). It could be used as input of next appended sub operation.
 *
 * @member {number} tensorWeightCountExtracted
 *   The sum of all sub operations' tensorWeightCountExtracted.
 *
 * @member {number} tensorWeightCountTotal
 *   The sum of all sub operations' tensorWeightCountTotal.
 *
 * @member {function} apply
 *   This is a data member pointer to a function. It processes this.input0.realTensor (and this.input1.realTensor) as inputTensors. It
 * puts to this.output0.realTensor (and this.output1.realTensor) as outputTensor. In fact, its calls .apply of every sub operation
 * and .endingDummyOperation.
 *
 * @see Operation.Root
 */
class TwinArray extends Root {

  /**
   *
   */
  constructor( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount, ...restArgs ) {

    // Note: The real output TensorPlacehoder will be created later as final operation outputs.
    super( inputTensorPlaceholder0, inputTensorPlaceholder1, 0, ...restArgs );

//!!! (2022/06/10 Remarked) Not so good solution.
// //!!! ...untested... (2022/06/10)
//     // When ValueDesc.channelCount1_pointwise1Before.Singleton.Ids.ONE_INPUT_TWO_DEPTHWISE but depthwise does not exist,
//     // in order to handle concat1 operation correctly (i.e. avoid got an undefined .endInput1), an beginning dummy operation
//     // is necessary.
//     {
//       this.beginningDummyOperation = new Root( inputTensorPlaceholder0, inputTensorPlaceholder1, 2 ); // Always has .output0 and .output1
//     }

    // In order to handle keep-input-flag correctly (even if no sub operation at all), an ending dummy operation is used.
    {
//!!! (2022/06/10 Remarked) Not so good solution.
//      this.endingDummyOperation = new Root( this.beginningDummyOperation.output0, this.beginningDummyOperation.output1, outputTensorCount );
      this.endingDummyOperation = new Root( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount );

      // The ending dummy operation's output will be the output of this operation array.
      {
        if ( this.endingDummyOperation.output0 )
          this.output0 = this.endingDummyOperation.output0;
        if ( this.endingDummyOperation.output1 )
          this.output1 = this.endingDummyOperation.output1;
      }
    }

    this.operationArray = new Array();

//!!! (2022/06/10 Remarked) Call TwinArray.setKeepInput() after all operation_append() done.
//     this.bKeepInputTensor0 = false; // Default is destroy0 and destroy1;
//     this.bKeepInputTensor1 = false;
//     TwinArray.alwaysKeepSet_collect.call( this ); // Re-collect TensorPlaceholders which are requested to keep their tensors.
//     TwinArray.setKeepInputTensor_by_this_operationArray_endingDummyOperation_alwaysKeepSet.call( this );

    TwinArray.setup_apply_loop.call( this );

    // For reducing memory re-allocation.
    //
    // When one or twin operations are appended, the newly appende operations' output tensor placeholders will be collected here
    // temporarily. And then they will be assigned as endingDummyOperation's input tensor placeholder.
    //
    this.tempLastOutputTensorPlaceholderArray = new Array();
  }

  /**
   * @override
   */
  disposeTensors() {

    {
      for ( let i = 0; i < this.operationArray.length; ++i ) {
        let operation = this.operationArray[ i ];
        operation.disposeTensors();
      }
      this.operationArray.length = 0;
    }

    // Since there is no sub operation, short-circuit to the original inputs.
//!!! (2022/06/10 Remarked) Not so good solution.
//    TwinArray.set_endingInput0_endingInput1.call( this, this.beginningDummyOperation.output0, this.beginningDummyOperation.output1 );
    TwinArray.set_endingInput0_endingInput1.call( this, this.input0, this.input1 );

    super.disposeTensors();
  }

  /**
   * Release all ScaleBoundsArray (inside tensor placeholder) except this.input0, this.input1, this.output0, this.output1
   *
   * This could reduce memory footprint by releasing unused scale bounds array.
   */
  dispose_intermediate_ScaleBoundsArray() {
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      if ( ( operation.input0 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.input0 ) ) )
        operation.input0.scaleBoundsArray = null;
      if ( ( operation.input1 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.input1 ) ) )
        operation.input1.scaleBoundsArray = null;
      if ( ( operation.output0 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.output0 ) ) )
        operation.output0.scaleBoundsArray = null;
      if ( ( operation.output1 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.output1 ) ) )
        operation.output1.scaleBoundsArray = null;
    }
  }

  /**
//!!! (2022/06/10 Remarked) Not so good solution.
//   * Call .beginningDummyOperation's, every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()

   * Call every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()
   * according to bKeepInputTensor0 and bKeepInputTensor1.
   *
   * Note: After all .operation_append() are called and  before .apply() is called, this .setKeepInputTensor() should be called to
   *       configure all sub operation's .apply correctly.
   *
   * @override
   */
  setKeepInputTensor( bKeepInputTensor0, bKeepInputTensor1 ) {

//!!! (2022/06/10 Remarked) Call TwinArray.setKeepInput() after all operation_add() done.
//     if ( ( this.bKeepInputTensor0 == bKeepInputTensor0 ) && ( this.bKeepInputTensor1 == bKeepInputTensor1 ) )
//       return; // Do nothing because no changed.
//
//     this.bKeepInputTensor0 = bKeepInputTensor0;
//     this.bKeepInputTensor1 = bKeepInputTensor1;

    // Q: Why not recorded bKeepInputTensor0 and bKeepInputTensor1 as data members.
    // A: The operation appending is complex so that the keep-input state will be changed in complicated way. Recording
    //    them is not helpful.

    TwinArray.alwaysKeepSet_collect.call( this, bKeepInputTensor0, bKeepInputTensor1 );

//!!! (2022/06/10 Remarked) Not so good solution.
//    TwinArray.setKeepInputTensor_by_beginningDummyOperation_operationArray_endingDummyOperation_alwaysKeepSet.call( this );

    TwinArray.setKeepInputTensor_by_operationArray_endingDummyOperation_alwaysKeepSet.call( this );
  }

  /**
//!!! (2022/06/10 Remarked) Not so good solution.
//   * Call .beginningDummyOperation's, every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()

   * Call every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()
   * according to this.alwaysKeepSet.
   */
//!!! (2022/06/10 Remarked) Not so good solution.
//  static setKeepInputTensor_by_beginningDummyOperation_operationArray_endingDummyOperation_alwaysKeepSet() {
  static setKeepInputTensor_by_operationArray_endingDummyOperation_alwaysKeepSet() {

//!!! (2022/06/10 Remarked) Not so good solution.
//     // 1.
//     this.beginningDummyOperation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );

    // 2. Every input tensors' final operation is responsible for releasing the tensor (except the input tensors which are requested
    //    to be kept (i.e. inside alwaysKeepSet)).
    //
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      operation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );
    }

    // 3.
    this.endingDummyOperation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );
  }

  /**
   * Append one or twin (i.e. two operation in parallel) operation(s) into this.operationArray[].
   *
   * All of the newly appended operations' .outputX TensorPlaceholders will be assigned as .endingDummyOperation.inputX (i.e.
   * .endingInputX) with some rules:
   *
   *   - If a .endingDummyOperation is no longer the final operation of .endingDummyOperation.inputX, the .endingDummyOperation.inputX
   *       will be viewed as empty solt which could be assigned by newly appended operations' .outputX.
   *
   *   - However, because there are only two slots (i.e. .endingDummyOperation.input0 and .endingDummyOperation.input1) at most,
   *       there are only two operationX.outputY could be assigned to them.
   *
   *   - If there too many operationX.outputY needs to be handled, it will be asserted failed.
   *
   *
   * Note: After all .operation_append() are called, the .setKeepInputTensor() should be called to configure correctly before
   *       .apply() is called.
   *
   *
   * @param {Operation.Base} operation0  The 1st operation object to be appended into this.operationArray[].
   * @param {Operation.Base} operation1  The 2nd operation object. If null, there will be no 2nd operation.
   */
  operation_append( operation0, operation1 ) {

//!!! (2022/06/10 Remarked) Call TwinArray.setKeepInput() after all operation_append() done.
//     // 1. Adjust keep-input-tensor flags, and put into queue.
//     //
//     // The previous final operation (of input tensor placeholders) is no longer its final operation.
//     // The newly created operation becomes the final operation of its input.
//     //
//     if ( operation0 ) {
//       operation0.setKeepInputTensor__input0_finalOperationOld__input1_finalOperationOld__this__IfNotFinalOperation_Or_In( this.alwaysKeepSet );
//       this.operationArray.push( operation0 );
//     }
//
//     if ( operation1 ) {
//       operation1.setKeepInputTensor__input0_finalOperationOld__input1_finalOperationOld__this__IfNotFinalOperation_Or_In( this.alwaysKeepSet );
//       this.operationArray.push( operation1 );
//     }

    // 1. Put into queue.
    if ( operation0 ) {
      this.operationArray.push( operation0 );
    }

    if ( operation1 ) {
      this.operationArray.push( operation1 );
    }

    // 2. Determine whether give up or keep current .endingInputX
    //
    // No matter ( .endingInputX does not exist ) or ( .endingInputX exists but .endingDummyOperation is no longer its final
    // operation ), .endingInputX will become an empty slot which could handle newly generated output tensor placeholders from
    // newly appended operations.
    //
    // Q: Why .endingDummyOperation should give it up when .endingDummyOperation is no longer its input tensor placeholder's
    //    final operation (i.e. the newly created and appended operation becomes its final operation)?
    // A: So that .endingDummyOperation will not use a disposed tensor.
    //
    let endingInput0_new, endingInput1_new;
    {
      if ( this.endingDummyOperation.input0?.finalOperation == this.endingDummyOperation )
        endingInput0_new = this.endingDummyOperation.input0; // Continue to handle it Since it still is its final operation.
      else
        endingInput0_new = null;

      if ( this.endingDummyOperation.input1?.finalOperation == this.endingDummyOperation )
        endingInput1_new = this.endingDummyOperation.input1; // Continue to handle it Since it still is its final operation.
      else
        endingInput1_new = null;
    }

    // 3. Adjust .endingInputX

    // 3.1 Collect output tensor placeholders in reverse order (so that they will be popped in forward order).
    {
      this.tempLastOutputTensorPlaceholderArray.length = 0;

      if ( operation1 ) {
        if ( operation1.output1 )
          this.tempLastOutputTensorPlaceholderArray.push( operation1.output1 );
        if ( operation1.output0 )
          this.tempLastOutputTensorPlaceholderArray.push( operation1.output0 );
      }

      if ( operation0 ) {
        if ( operation0.output1 )
          this.tempLastOutputTensorPlaceholderArray.push( operation0.output1 );
        if ( operation0.output0 )
          this.tempLastOutputTensorPlaceholderArray.push( operation0.output0 );
      }
    }

    // 3.2 Assign newly generated output tensor placeholders (from newly appended operations) to empty input slot of .endingDummyOperation.
    {
      if ( ( this.tempLastOutputTensorPlaceholderArray.length > 0 ) && ( endingInput0_new == null ) )
        endingInput0_new = this.tempLastOutputTensorPlaceholderArray.pop();

      if ( ( this.tempLastOutputTensorPlaceholderArray.length > 0 ) && ( endingInput1_new == null ) )
        endingInput1_new = this.tempLastOutputTensorPlaceholderArray.pop();

      // At most, two outputs could be handled.
      tf.util.assert( ( this.tempLastOutputTensorPlaceholderArray.length == 0 ),
        `Operation.TwinArray.operation_append(): `
          + `The appended operations have too many output TensorPlaceholders. There are not enough .endingInputX could be used.`
      );
    }

    // 3.3 Confirm the new endingInputX.
    TwinArray.set_endingInput0_endingInput1.call( this, endingInput0_new, endingInput1_new );
  }

  get endingInput0() {
    return this.endingDummyOperation.input0;
  }

  get endingInput1() {
    return this.endingDummyOperation.input1;
  }

  get tensorWeightCountExtracted() {
    let sum = 0;
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      sum += operation.tensorWeightCountExtracted;
    }
    return sum;
  }

  get tensorWeightCountTotal() {
    let sum = 0;
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      sum += operation.tensorWeightCountTotal;
    }
    return sum;
  }

  /** Re-collect TensorPlaceholders into this.alwaysKeepSet if some input tensors are requested to be kept after .apply(). */
  static alwaysKeepSet_collect( bKeepInputTensor0, bKeepInputTensor1 ) {
    let bShouldbKeepInputTensor0 = ( this.input0 && bKeepInputTensor0 );
    let bShouldbKeepInputTensor1 = ( this.input1 && bKeepInputTensor1 );
    let bShouldbKeepInputTensor = ( bShouldbKeepInputTensor0 || bShouldbKeepInputTensor1 );

    if ( bShouldbKeepInputTensor ) { // 1. Some inputs should be kept.

      // 1.1
      if ( this.alwaysKeepSet )
        this.alwaysKeepSet.clear();
      else
        this.alwaysKeepSet = new Set(); // Create container only if it is indeed necessary.

      if ( bShouldbKeepInputTensor0 ) // 1.2
        this.alwaysKeepSet.add( this.input0 );

      if ( bShouldbKeepInputTensor1 ) // 1.3
        this.alwaysKeepSet.add( this.input1 );

    } else { // 2. No inputs should be kept.

      // 2.1 Empty the container if the container exists.
      if ( this.alwaysKeepSet )
        this.alwaysKeepSet.clear();

      // 2.2 If the container does not exist, do nothing instead.
    }
  }

  /**
   *
   * @param {TensorPlaceholder.Base} endingInput0  The tensor placeholder to become .endingDummyOperation.input0.
   * @param {TensorPlaceholder.Base} endingInput1  The tensor placeholder to become .endingDummyOperation.input1.
   */
  static set_endingInput0_endingInput1( endingInput0, endingInput1 ) {
    TwinArray.set_inputTensorPlaceholder0_inputTensorPlaceholder1.call( this.endingDummyOperation, endingInput0, endingInput1 );

//!!! (2022/06/10 Remarked) Call TwinArray.setKeepInput() after all operation_append() done.
//    this.endingDummyOperation.setKeepInputTensor__input0_finalOperationOld__input1_finalOperationOld__this__IfNotFinalOperation_Or_In( this.alwaysKeepSet );
  }

  /**
   * Adjust .apply data member according to calling .apply_operationArray_endingDummyOperation().
   */
  static setup_apply_loop() {
//!!! (2022/06/10 Remarked) Not so good solution.
//    this.apply = TwinArray.apply_beginningDummyOperation_operationArray_endingDummyOperation;
    this.apply = TwinArray.apply_operationArray_endingDummyOperation;
  }

  /**
//!!! (2022/06/10 Remarked) Not so good solution.
//   * Calling .beginningDummyOperation's, every sub operations', and .endingDummyOperation's .apply()

   * Calling every sub operations', and .endingDummyOperation's .apply()
   */
//!!! (2022/06/10 Remarked) Not so good solution.
//   static apply_beginningDummyOperation_operationArray_endingDummyOperation() {
//     this.beginningDummyOperation.apply();

  static apply_operationArray_endingDummyOperation() {
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      operation.apply();
    }
    this.endingDummyOperation.apply();
  }

}
<commit_msg>Update Operation_TwinArray.js<commit_after>export { TwinArray };

import * as TensorPlaceholder from "../TensorPlaceholder.js";
import { Root } from "./Operation_Base.js";

/**
 * An array of operations. Every time appending operation, one or parallel twin operations could be appended.
 *
 * No matter how many sub operations (even no sub operation) are appended, this TwinArray's .output0 and .output1 (tensor
 * placeholder) are always .endingDummyOperation.output0 and .endingDummyOperation.output1 in fact. The .endingInput0
 * and endingInput1 are always .endingDummyOperation.input0 and .endingDummyOperation.input1 in fact. This could
 * simplify the decision of what tensor placeholders should be used as the next (appended) operation's input.
 *
 *
 * Note: The .outputTensorCount is determined when constructor is called. No matter what kind of operation is appended
 * (even if the is no operation is appended), the outputTensorCount will not be changed.
 *
 *
 *
 * @member {TensorPlaceholder.Base} endingInput0
 *   The last sub operation's output0 (also .endingDummyOperation.input0). It could be used as input of next appended sub operation.
 *
 * @member {TensorPlaceholder.Base} endingInput1
 *   The last sub operation's output1 (also .endingDummyOperation.input1). It could be used as input of next appended sub operation.
 *
 * @member {number} tensorWeightCountExtracted
 *   The sum of all sub operations' tensorWeightCountExtracted.
 *
 * @member {number} tensorWeightCountTotal
 *   The sum of all sub operations' tensorWeightCountTotal.
 *
 * @member {function} apply
 *   This is a data member pointer to a function. It processes this.input0.realTensor (and this.input1.realTensor) as inputTensors. It
 * puts to this.output0.realTensor (and this.output1.realTensor) as outputTensor. In fact, its calls .apply of every sub operation
 * and .endingDummyOperation.
 *
 * @see Operation.Root
 */
class TwinArray extends Root {

  /**
   *
   */
  constructor( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount, ...restArgs ) {

    // Note: The real output TensorPlacehoder will be created later as final operation outputs.
    super( inputTensorPlaceholder0, inputTensorPlaceholder1, 0, ...restArgs );

    // In order to handle keep-input-flag correctly (even if no sub operation at all), an ending dummy operation is used.
    {
      this.endingDummyOperation = new Root( inputTensorPlaceholder0, inputTensorPlaceholder1, outputTensorCount );

      // The ending dummy operation's output will be the output of this operation array.
      {
        if ( this.endingDummyOperation.output0 )
          this.output0 = this.endingDummyOperation.output0;
        if ( this.endingDummyOperation.output1 )
          this.output1 = this.endingDummyOperation.output1;
      }
    }

    this.operationArray = new Array();

    TwinArray.setup_apply_loop.call( this );

    // For reducing memory re-allocation.
    //
    // When one or twin operations are appended, the newly appende operations' output tensor placeholders will be collected here
    // temporarily. And then they will be assigned as endingDummyOperation's input tensor placeholder.
    //
    this.tempLastOutputTensorPlaceholderArray = new Array();
  }

  /**
   * @override
   */
  disposeTensors() {
    {
      for ( let i = 0; i < this.operationArray.length; ++i ) {
        let operation = this.operationArray[ i ];
        operation.disposeTensors();
      }
      this.operationArray.length = 0;
    }

    // Since there is no sub operation, short-circuit to the original inputs.
    TwinArray.set_endingInput0_endingInput1.call( this, this.input0, this.input1 );

    super.disposeTensors();
  }

  /**
   * Release all ScaleBoundsArray (inside tensor placeholder) except this.input0, this.input1, this.output0, this.output1
   *
   * This could reduce memory footprint by releasing unused scale bounds array.
   */
  dispose_intermediate_ScaleBoundsArray() {
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      if ( ( operation.input0 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.input0 ) ) )
        operation.input0.scaleBoundsArray = null;
      if ( ( operation.input1 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.input1 ) ) )
        operation.input1.scaleBoundsArray = null;
      if ( ( operation.output0 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.output0 ) ) )
        operation.output0.scaleBoundsArray = null;
      if ( ( operation.output1 ) && !( this.is_inputs_outputs_byTensorPlaceholder( operation.output1 ) ) )
        operation.output1.scaleBoundsArray = null;
    }
  }

  /**
   * Call every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()
   * according to bKeepInputTensor0 and bKeepInputTensor1.
   *
   * Note: After all .operation_append() are called and  before .apply() is called, this .setKeepInputTensor() should be called to
   *       configure all sub operation's .apply correctly.
   *
   * @override
   */
  setKeepInputTensor( bKeepInputTensor0, bKeepInputTensor1 ) {

    // Q: Why not recorded bKeepInputTensor0 and bKeepInputTensor1 as data members.
    // A: The operation appending is complex so that the keep-input state will be changed in complicated way. Recording
    //    them is not helpful.

    TwinArray.alwaysKeepSet_collect.call( this, bKeepInputTensor0, bKeepInputTensor1 );
    TwinArray.setKeepInputTensor_by_operationArray_endingDummyOperation_alwaysKeepSet.call( this );
  }

  /**
   * Call every sub operation's, and endingDummyOperation's setKeepInputTensor_IfNotFinalOperation_Or_In()
   * according to this.alwaysKeepSet.
   */
  static setKeepInputTensor_by_operationArray_endingDummyOperation_alwaysKeepSet() {

    // 2. Every input tensors' final operation is responsible for releasing the tensor (except the input tensors which are requested
    //    to be kept (i.e. inside alwaysKeepSet)).
    //
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      operation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );
    }

    // 3.
    this.endingDummyOperation.setKeepInputTensor_IfNotFinalOperation_Or_In( this.alwaysKeepSet );
  }

  /**
   * Append one or twin (i.e. two operation in parallel) operation(s) into this.operationArray[].
   *
   * All of the newly appended operations' .outputX TensorPlaceholders will be assigned as .endingDummyOperation.inputX (i.e.
   * .endingInputX) with some rules:
   *
   *   - If a .endingDummyOperation is no longer the final operation of .endingDummyOperation.inputX, the .endingDummyOperation.inputX
   *       will be viewed as empty solt which could be assigned by newly appended operations' .outputX.
   *
   *   - However, because there are only two slots (i.e. .endingDummyOperation.input0 and .endingDummyOperation.input1) at most,
   *       there are only two operationX.outputY could be assigned to them.
   *
   *   - If there too many operationX.outputY needs to be handled, it will be asserted failed.
   *
   *
   * Note: After all .operation_append() are called, the .setKeepInputTensor() should be called to configure correctly before
   *       .apply() is called.
   *
   *
   * @param {Operation.Base} operation0  The 1st operation object to be appended into this.operationArray[].
   * @param {Operation.Base} operation1  The 2nd operation object. If null, there will be no 2nd operation.
   */
  operation_append( operation0, operation1 ) {

    // 1. Put into queue.
    if ( operation0 ) {
      this.operationArray.push( operation0 );
    }

    if ( operation1 ) {
      this.operationArray.push( operation1 );
    }

    // 2. Determine whether give up or keep current .endingInputX
    //
    // No matter ( .endingInputX does not exist ) or ( .endingInputX exists but .endingDummyOperation is no longer its final
    // operation ), .endingInputX will become an empty slot which could handle newly generated output tensor placeholders from
    // newly appended operations.
    //
    // Q: Why .endingDummyOperation should give it up when .endingDummyOperation is no longer its input tensor placeholder's
    //    final operation (i.e. the newly created and appended operation becomes its final operation)?
    // A: So that .endingDummyOperation will not use a disposed tensor.
    //
    let endingInput0_new, endingInput1_new;
    {
      if ( this.endingDummyOperation.input0?.finalOperation == this.endingDummyOperation )
        endingInput0_new = this.endingDummyOperation.input0; // Continue to handle it Since it still is its final operation.
      else
        endingInput0_new = null;

      if ( this.endingDummyOperation.input1?.finalOperation == this.endingDummyOperation )
        endingInput1_new = this.endingDummyOperation.input1; // Continue to handle it Since it still is its final operation.
      else
        endingInput1_new = null;
    }

    // 3. Adjust .endingInputX

    // 3.1 Collect output tensor placeholders in reverse order (so that they will be popped in forward order).
    {
      this.tempLastOutputTensorPlaceholderArray.length = 0;

      if ( operation1 ) {
        if ( operation1.output1 )
          this.tempLastOutputTensorPlaceholderArray.push( operation1.output1 );
        if ( operation1.output0 )
          this.tempLastOutputTensorPlaceholderArray.push( operation1.output0 );
      }

      if ( operation0 ) {
        if ( operation0.output1 )
          this.tempLastOutputTensorPlaceholderArray.push( operation0.output1 );
        if ( operation0.output0 )
          this.tempLastOutputTensorPlaceholderArray.push( operation0.output0 );
      }
    }

    // 3.2 Assign newly generated output tensor placeholders (from newly appended operations) to empty input slot of .endingDummyOperation.
    {
      if ( ( this.tempLastOutputTensorPlaceholderArray.length > 0 ) && ( endingInput0_new == null ) )
        endingInput0_new = this.tempLastOutputTensorPlaceholderArray.pop();

      if ( ( this.tempLastOutputTensorPlaceholderArray.length > 0 ) && ( endingInput1_new == null ) )
        endingInput1_new = this.tempLastOutputTensorPlaceholderArray.pop();

      // At most, two outputs could be handled.
      tf.util.assert( ( this.tempLastOutputTensorPlaceholderArray.length == 0 ),
        `Operation.TwinArray.operation_append(): `
          + `The appended operations have too many output TensorPlaceholders. There are not enough .endingInputX could be used.`
      );
    }

    // 3.3 Confirm the new endingInputX.
    TwinArray.set_endingInput0_endingInput1.call( this, endingInput0_new, endingInput1_new );
  }

  get endingInput0() {
    return this.endingDummyOperation.input0;
  }

  get endingInput1() {
    return this.endingDummyOperation.input1;
  }

  get tensorWeightCountExtracted() {
    let sum = 0;
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      sum += operation.tensorWeightCountExtracted;
    }
    return sum;
  }

  get tensorWeightCountTotal() {
    let sum = 0;
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      sum += operation.tensorWeightCountTotal;
    }
    return sum;
  }

  /** Re-collect TensorPlaceholders into this.alwaysKeepSet if some input tensors are requested to be kept after .apply(). */
  static alwaysKeepSet_collect( bKeepInputTensor0, bKeepInputTensor1 ) {
    let bShouldbKeepInputTensor0 = ( this.input0 && bKeepInputTensor0 );
    let bShouldbKeepInputTensor1 = ( this.input1 && bKeepInputTensor1 );
    let bShouldbKeepInputTensor = ( bShouldbKeepInputTensor0 || bShouldbKeepInputTensor1 );

    if ( bShouldbKeepInputTensor ) { // 1. Some inputs should be kept.

      // 1.1
      if ( this.alwaysKeepSet )
        this.alwaysKeepSet.clear();
      else
        this.alwaysKeepSet = new Set(); // Create container only if it is indeed necessary.

      if ( bShouldbKeepInputTensor0 ) // 1.2
        this.alwaysKeepSet.add( this.input0 );

      if ( bShouldbKeepInputTensor1 ) // 1.3
        this.alwaysKeepSet.add( this.input1 );

    } else { // 2. No inputs should be kept.

      // 2.1 Empty the container if the container exists.
      if ( this.alwaysKeepSet )
        this.alwaysKeepSet.clear();

      // 2.2 If the container does not exist, do nothing instead.
    }
  }

  /**
   *
   * @param {TensorPlaceholder.Base} endingInput0  The tensor placeholder to become .endingDummyOperation.input0.
   * @param {TensorPlaceholder.Base} endingInput1  The tensor placeholder to become .endingDummyOperation.input1.
   */
  static set_endingInput0_endingInput1( endingInput0, endingInput1 ) {
    TwinArray.set_inputTensorPlaceholder0_inputTensorPlaceholder1.call( this.endingDummyOperation, endingInput0, endingInput1 );
  }

  /**
   * Adjust .apply data member according to calling .apply_operationArray_endingDummyOperation().
   */
  static setup_apply_loop() {
    this.apply = TwinArray.apply_operationArray_endingDummyOperation;
  }

  /**
   * Calling every sub operations', and .endingDummyOperation's .apply()
   */
  static apply_operationArray_endingDummyOperation() {
    for ( let i = 0; i < this.operationArray.length; ++i ) {
      let operation = this.operationArray[ i ];
      operation.apply();
    }
    this.endingDummyOperation.apply();
  }

}
<|endoftext|>


<commit_before>var Scarlet = require('scarlet')

var scarlet = Scarlet()

exports.profile = function(klass) {
  for (fn in klass) {
    klass[fn] = function(f) {
      return scarlet.intercept(klass[f]).
        using(function(invocation, proceed) {
          var args = invocation.args.filter(function(e) { return typeof(e) != 'function' }).map(function(e) { return "'" + e + "'" })
          console.log(klass.name + "." + f + "( " + args.join(", ") + " )")
          proceed()
        }).
        proxy()
    }(fn)
  }

  for (fn in klass.prototype) {
    klass.prototype[fn] = function(f) {
      return scarlet.intercept(klass.prototype[fn]).
        using(function(invocation, proceed) {
          var args = invocation.args.filter(function(e) { return typeof(e) != 'function' }).map(function(e) { return "'" + e + "'" })
          console.log(klass.name + "." + f + "( " + args.join(", ") + " )")
          proceed()
        }).
        proxy()
    }(fn)
  }
}
<commit_msg>Improves profiler and prints function arguments in json.<commit_after>var Scarlet = require('scarlet')

var scarlet = Scarlet()

exports.profile = function(klass) {
  for (fn in klass) {
    klass[fn] = function(f) {
      return scarlet.intercept(klass[f]).
        using(function(invocation, proceed) {
          var args = invocation.args.filter(function(e) { return typeof(e) != 'function' }).map(function(e) { return JSON.stringify(e) })
          console.log(klass.name + "." + f + "( " + args.join(", ") + " )")
          proceed()
        }).
        proxy()
    }(fn)
  }

  for (fn in klass.prototype) {
    klass.prototype[fn] = function(f) {
      return scarlet.intercept(klass.prototype[fn]).
        using(function(invocation, proceed) {
          var args = invocation.args.filter(function(e) { return typeof(e) != 'function' }).map(function(e) { return JSON.stringify(e) })
          console.log(klass.name + "." + f + "( " + args.join(", ") + " )")
          proceed()
        }).
        proxy()
    }(fn)
  }
}
<|endoftext|>


<commit_before>/*
Copyright (c) Lightstreamer Srl

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

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

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

// Module imports
var globals = require('./consts').globals,
	types = require('./consts').types,
	values = require('./consts').values,
	modeValues = require('./consts').modeValues,
	exceptions = require('./consts').exceptions;

/**
 * Concatenates the arguments in a pipe-delimited string
 *
 * @return {String} the pipe-delimited string
 * @private
 */
function implodeMessage() {
	return implodeArray(arguments) + globals.EOM;
}

/**
 * Concatenates the array in a pipe-delimited string
 *
 * @param {Array} tokens to be concatenated
 * @return {String} the pipe-delimited string
 * @private
 */
function implodeArray(tokens) {
	var message = "", i, l;
	l = tokens.length;
	for (i = 0; i < l; i++) {
        message += (i > 0 ? globals.SEP : "") + tokens[i];
    }
	return message;
}

/**
 * Concatenates the associative array in a pipe-delimited string
 * in the following form FIELD_TYPE_STRING|key|FIELD_TYPE_STRING|value.
 * Values are encoded as strings.
 *
 * @param {Array} data an associative array
 * @return {String} the pipe-delimited string
 * @private
 */
function implodeData(data) {
	var dataArray = [], field;
	for(field in data) {
		dataArray.push(types.STRING);
		dataArray.push(encodeString(field));
		dataArray.push(types.STRING);
		dataArray.push(encodeString(data[field]));
	}
	return implodeArray(dataArray);
}

/**
 * Concatenates the array values in a pipe-delimited string
 * in the following form FIELD_TYPE_STRING|value.
 * Values are encoded as strings.
 *
 * @param {Array} data fields to be encoded
 * @return {String} the pipe-delimited string
 * @private
 */
function implodeDataArray(data) {
	var dataArray = [], i, l;
	l = data.length;
	for(i = 0; i < l; i++) {
		dataArray.push(types.STRING);
		dataArray.push(encodeString(data[i]));
	}
	return implodeArray(dataArray);
}

/**
 * Splits the pipe-delimited string in an array.
 *
 * @param {String} message pipe-delimited string
 * @return {Array} the fields contained in the string
 * @private
 */
function explode(message) {
	return message.split(globals.SEP);
}

/**
 * Decodes a string as a publish mode associative array.
 * eg. "M|R" = {raw: true, merge: true, distinct: false, command: false}.
 *
 * @param {String} string pipe-delimited string
 * @return {Array} publish mode flags
 * @private
 */
function decodePubModes(string) {
	var decStr, mode, i, l;
	decStr = decodeString(string);
	mode = {raw : false, merge : false,	distinct : false, command : false};

	if (decStr) {
		l = decStr.length;
		for(i = 0; i < l; i++) {
			if (decStr.charAt(i) === modeValues.RAW) {
				mode.raw = true;
			} else if (decStr.charAt(i) === modeValues.MERGE) {
				mode.merge = true;
			} else if (decStr.charAt(i) === modeValues.DISTINCT) {
				mode.distinct = true;
			} else if (decStr.charAt(i) === modeValues.COMMAND) {
				mode.command = true;
			} else {
				throw new Error('Invalid mode "' + decStr.charAt(i) + '"');
			}

		}
	}
	return mode;
}

/**
 * Encodes a publish mode associative array in a ARI protocol string form.
 * eg. {raw: true, merge: true, distinct: false, command: false} = "R|M".
 *
 * @param {Array} modes publish mode flags
 * @return {String} pipe-delimited string
 * @private
 */
function encodePubModes(modes) {
	var string = "";
	if(modes.raw) {
		string = string + modeValues.RAW;
	};
	if(modes.merge) {
		string = string + modeValues.MERGE;
	};
	if(modes.distinct) {
		string = string + modeValues.DISTINCT;
	};
	if(modes.command) {
		string = string + modeValues.COMMAND;
	};
	if (!string) {
		throw new Error("No modes are specified");
	}
	return string;
}

/**
 * Encodes a string according to the ARI protocol.
 *
 * @param {String} string input
 * @return {String} output
 * @private
 */
function encodeString(string) {
  //it actually accepts any kind of object as input
  if (string === null) {
    return values.NULL;
  } else if (string === "") {
    return values.EMPTY;
  } else {//0 false undefined NaN will pass from here
    return encodeURIComponent(string)
    .replace(/%20/g, "+");
  }
}

/**
 * Decodes a string according to the ARI protocol.
 *
 * @param {String} string input
 * @return {String} output
 * @private
 */
function decodeString (string) {
	if (string === values.EMPTY) {
		return "";
	} else if (string === values.NULL) {
		return null;
	} else {
		return decodeURIComponent(
			string.replace(/\+/g,"%20"));
	}
}

/**
 * Decodes an integer according to the ARI protocol.
 *
 * @param {String} string input
 * @return {Number} output
 * @private
 */
function decodeInteger(string) {
	if (string === values.NULL) {
		return null;
	} else {
		return parseInt(string);
	}
}

/**
 * Encodes an integer according to the ARI protocol.
 *
 * @param {Number} value input
 * @return {String} output
 * @private
 */
function encodeInteger(value) {
	if (value === null) {
		return values.NULL;
	} else if (!isNaN(value) && parseInt(value)==value) {
		return value + "";
	} else {
		throw new Error('Invalid integer value "' + value + '"');
	}
}

/**
 * Encodes a float according to the ARI protocol.
 *
 * @param {Number} value input
 * @return {String} output
 * @private
 */
function encodeDouble(value) {
	if (value === null) {
		return values.NULL;
	} else if (!isNaN(value)) {
		return value + "";
	} else {
		throw new Error('Invalid double value "' + value + '"');
	}
}

/**
 * Encodes a boolean according to the ARI protocol.
 *
 * @param {Boolean} bool input
 * @return {String} output
 * @private
 */
function encodeBoolean(bool) {
	return bool ? values.TRUE : values.FALSE;
}

/**
 * Encodes a metadata exception type.
 *
 * @param {Boolean} type input
 * @return {String} output
 * @private
 */
function encodeMetadataException(type) {
	if (type === "metadata") {
		return exceptions.METADATA;
	} else if (type === "access") {
		return exceptions.ACCESS;
	} else if (type === "credits") {
		return exceptions.CREDITS;
	} else if (type === "conflictingSession") {
		return exceptions.CONFLICTING_SESSION;
	} else if (type === "items") {
		return exceptions.ITEMS;
	} else if (type === "schema") {
		return exceptions.SCHEMA;
	} else if (type === "notification") {
		return exceptions.NOTIFICATION;
	} else {
		return exceptions.GENERIC;
	}
}

/**
 * Generates a timestamp.
 *
 * @return {String} time millis
 * @private
 */
function timestamp() {
	return new Date().getTime() + "";
}

/**
 *
StreamReader constructor.

 *
 * @class
 * @param {Function} read the function to parse the message
 * @private
 */
function StreamReader(read) {

	var tail = '', messages = new Array();

	/**
	 * Parsa new data.
	 * @param {String} data New data from the stream
	 */
	function parse(data, initExpected) {
		var lines, i, last;
		data = tail + data;
		data = data.replace(/\r*\n+/, "\n");
		lines = data.split("\n");
		last = lines.length - 1;
		for (i = 0; i < last; i++) {
			messages.push(read(lines[i], initExpected));
		}
		tail = lines[lines.length - 1];
	}

	/**
	 * Pop the next message
	 */
	function pop() {
    	return messages.shift();
  	}

	/**
	 * Return if it has no more messages
	 */
	function isEmpty() {
    	return messages.length == 0;
  	}

	// Public methods
	that = {
		parse: parse,
		pop: pop,
		isEmpty: isEmpty
	};

	return that;
}

// Module exports
exports.implodeMessage = implodeMessage;
exports.implodeArray = implodeArray;
exports.implodeData = implodeData;
exports.implodeDataArray = implodeDataArray;
exports.explode = explode;
exports.decodePubModes = decodePubModes;
exports.encodePubModes = encodePubModes;
exports.encodeString = encodeString;
exports.decodeString = decodeString;
exports.decodeInteger = decodeInteger;
exports.encodeInteger = encodeInteger;
exports.encodeDouble = encodeDouble;
exports.encodeBoolean = encodeBoolean;
exports.encodeMetadataException = encodeMetadataException;
exports.timestamp = timestamp;
exports.StreamReader = StreamReader;
<commit_msg>Replace all "\r\n"<commit_after>/*
Copyright (c) Lightstreamer Srl

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

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

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

// Module imports
var globals = require('./consts').globals,
	types = require('./consts').types,
	values = require('./consts').values,
	modeValues = require('./consts').modeValues,
	exceptions = require('./consts').exceptions;

/**
 * Concatenates the arguments in a pipe-delimited string
 *
 * @return {String} the pipe-delimited string
 * @private
 */
function implodeMessage() {
	return implodeArray(arguments) + globals.EOM;
}

/**
 * Concatenates the array in a pipe-delimited string
 *
 * @param {Array} tokens to be concatenated
 * @return {String} the pipe-delimited string
 * @private
 */
function implodeArray(tokens) {
	var message = "", i, l;
	l = tokens.length;
	for (i = 0; i < l; i++) {
        message += (i > 0 ? globals.SEP : "") + tokens[i];
    }
	return message;
}

/**
 * Concatenates the associative array in a pipe-delimited string
 * in the following form FIELD_TYPE_STRING|key|FIELD_TYPE_STRING|value.
 * Values are encoded as strings.
 *
 * @param {Array} data an associative array
 * @return {String} the pipe-delimited string
 * @private
 */
function implodeData(data) {
	var dataArray = [], field;
	for(field in data) {
		dataArray.push(types.STRING);
		dataArray.push(encodeString(field));
		dataArray.push(types.STRING);
		dataArray.push(encodeString(data[field]));
	}
	return implodeArray(dataArray);
}

/**
 * Concatenates the array values in a pipe-delimited string
 * in the following form FIELD_TYPE_STRING|value.
 * Values are encoded as strings.
 *
 * @param {Array} data fields to be encoded
 * @return {String} the pipe-delimited string
 * @private
 */
function implodeDataArray(data) {
	var dataArray = [], i, l;
	l = data.length;
	for(i = 0; i < l; i++) {
		dataArray.push(types.STRING);
		dataArray.push(encodeString(data[i]));
	}
	return implodeArray(dataArray);
}

/**
 * Splits the pipe-delimited string in an array.
 *
 * @param {String} message pipe-delimited string
 * @return {Array} the fields contained in the string
 * @private
 */
function explode(message) {
	return message.split(globals.SEP);
}

/**
 * Decodes a string as a publish mode associative array.
 * eg. "M|R" = {raw: true, merge: true, distinct: false, command: false}.
 *
 * @param {String} string pipe-delimited string
 * @return {Array} publish mode flags
 * @private
 */
function decodePubModes(string) {
	var decStr, mode, i, l;
	decStr = decodeString(string);
	mode = {raw : false, merge : false,	distinct : false, command : false};

	if (decStr) {
		l = decStr.length;
		for(i = 0; i < l; i++) {
			if (decStr.charAt(i) === modeValues.RAW) {
				mode.raw = true;
			} else if (decStr.charAt(i) === modeValues.MERGE) {
				mode.merge = true;
			} else if (decStr.charAt(i) === modeValues.DISTINCT) {
				mode.distinct = true;
			} else if (decStr.charAt(i) === modeValues.COMMAND) {
				mode.command = true;
			} else {
				throw new Error('Invalid mode "' + decStr.charAt(i) + '"');
			}

		}
	}
	return mode;
}

/**
 * Encodes a publish mode associative array in a ARI protocol string form.
 * eg. {raw: true, merge: true, distinct: false, command: false} = "R|M".
 *
 * @param {Array} modes publish mode flags
 * @return {String} pipe-delimited string
 * @private
 */
function encodePubModes(modes) {
	var string = "";
	if(modes.raw) {
		string = string + modeValues.RAW;
	};
	if(modes.merge) {
		string = string + modeValues.MERGE;
	};
	if(modes.distinct) {
		string = string + modeValues.DISTINCT;
	};
	if(modes.command) {
		string = string + modeValues.COMMAND;
	};
	if (!string) {
		throw new Error("No modes are specified");
	}
	return string;
}

/**
 * Encodes a string according to the ARI protocol.
 *
 * @param {String} string input
 * @return {String} output
 * @private
 */
function encodeString(string) {
  //it actually accepts any kind of object as input
  if (string === null) {
    return values.NULL;
  } else if (string === "") {
    return values.EMPTY;
  } else {//0 false undefined NaN will pass from here
    return encodeURIComponent(string)
    .replace(/%20/g, "+");
  }
}

/**
 * Decodes a string according to the ARI protocol.
 *
 * @param {String} string input
 * @return {String} output
 * @private
 */
function decodeString (string) {
	if (string === values.EMPTY) {
		return "";
	} else if (string === values.NULL) {
		return null;
	} else {
		return decodeURIComponent(
			string.replace(/\+/g,"%20"));
	}
}

/**
 * Decodes an integer according to the ARI protocol.
 *
 * @param {String} string input
 * @return {Number} output
 * @private
 */
function decodeInteger(string) {
	if (string === values.NULL) {
		return null;
	} else {
		return parseInt(string);
	}
}

/**
 * Encodes an integer according to the ARI protocol.
 *
 * @param {Number} value input
 * @return {String} output
 * @private
 */
function encodeInteger(value) {
	if (value === null) {
		return values.NULL;
	} else if (!isNaN(value) && parseInt(value)==value) {
		return value + "";
	} else {
		throw new Error('Invalid integer value "' + value + '"');
	}
}

/**
 * Encodes a float according to the ARI protocol.
 *
 * @param {Number} value input
 * @return {String} output
 * @private
 */
function encodeDouble(value) {
	if (value === null) {
		return values.NULL;
	} else if (!isNaN(value)) {
		return value + "";
	} else {
		throw new Error('Invalid double value "' + value + '"');
	}
}

/**
 * Encodes a boolean according to the ARI protocol.
 *
 * @param {Boolean} bool input
 * @return {String} output
 * @private
 */
function encodeBoolean(bool) {
	return bool ? values.TRUE : values.FALSE;
}

/**
 * Encodes a metadata exception type.
 *
 * @param {Boolean} type input
 * @return {String} output
 * @private
 */
function encodeMetadataException(type) {
	if (type === "metadata") {
		return exceptions.METADATA;
	} else if (type === "access") {
		return exceptions.ACCESS;
	} else if (type === "credits") {
		return exceptions.CREDITS;
	} else if (type === "conflictingSession") {
		return exceptions.CONFLICTING_SESSION;
	} else if (type === "items") {
		return exceptions.ITEMS;
	} else if (type === "schema") {
		return exceptions.SCHEMA;
	} else if (type === "notification") {
		return exceptions.NOTIFICATION;
	} else {
		return exceptions.GENERIC;
	}
}

/**
 * Generates a timestamp.
 *
 * @return {String} time millis
 * @private
 */
function timestamp() {
	return new Date().getTime() + "";
}

/**
 *
StreamReader constructor.

 *
 * @class
 * @param {Function} read the function to parse the message
 * @private
 */
function StreamReader(read) {

	var tail = '', messages = new Array();

	/**
	 * Parsa new data.
	 * @param {String} data New data from the stream
	 */
	function parse(data, initExpected) {
		var lines, i, last;
		data = tail + data;
		data = data.replace(/\r*\n+/g, "\n");
		lines = data.split("\n");
		last = lines.length - 1;
		for (i = 0; i < last; i++) {
			messages.push(read(lines[i], initExpected));
		}
		tail = lines[lines.length - 1];
	}

	/**
	 * Pop the next message
	 */
	function pop() {
    	return messages.shift();
  	}

	/**
	 * Return if it has no more messages
	 */
	function isEmpty() {
    	return messages.length == 0;
  	}

	// Public methods
	that = {
		parse: parse,
		pop: pop,
		isEmpty: isEmpty
	};

	return that;
}

// Module exports
exports.implodeMessage = implodeMessage;
exports.implodeArray = implodeArray;
exports.implodeData = implodeData;
exports.implodeDataArray = implodeDataArray;
exports.explode = explode;
exports.decodePubModes = decodePubModes;
exports.encodePubModes = encodePubModes;
exports.encodeString = encodeString;
exports.decodeString = decodeString;
exports.decodeInteger = decodeInteger;
exports.encodeInteger = encodeInteger;
exports.encodeDouble = encodeDouble;
exports.encodeBoolean = encodeBoolean;
exports.encodeMetadataException = encodeMetadataException;
exports.timestamp = timestamp;
exports.StreamReader = StreamReader;
<|endoftext|>


<commit_before>/*
 * loquat-prim test / prim.bind()
 * copyright (c) 2016 Susisu
 */

"use strict";

const chai = require("chai");
const expect = chai.expect;

const _core = require("loquat-core");
const SourcePos        = _core.SourcePos;
const ErrorMessageType = _core.ErrorMessageType;
const ErrorMessage     = _core.ErrorMessage;
const ParseError       = _core.ParseError;
const Config           = _core.Config;
const State            = _core.State;
const Result           = _core.Result;
const Parser           = _core.Parser;
const assertParser     = _core.assertParser;

const _prim = require("prim.js")(_core);
const pure = _prim.pure;
const bind = _prim.bind;

describe(".bind(parser, func)", () => {
    it("should return a parser that runs `parser', maps `func' to the result, and flattens its return value", () => {
        let initState = new State(
            new Config({ tabWidth: 8 }),
            "input",
            new SourcePos("foobar", 1, 1),
            "none"
        );
        let stateA = new State(
            new Config({ tabWidth: 4 }),
            "restA",
            new SourcePos("foobar", 1, 2),
            "someA"
        );
        let errA = new ParseError(
            new SourcePos("foobar", 1, 2),
            [new ErrorMessage(ErrorMessageType.MESSAGE, "testA")]
        );
        let stateB = new State(
            new Config({ tabWidth: 2 }),
            "restB",
            new SourcePos("foobar", 1, 2),
            "someB"
        );
        let errB = new ParseError(
            new SourcePos("foobar", 1, 2),
            [new ErrorMessage(ErrorMessageType.MESSAGE, "testB")]
        );
        // csuc, csuc
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.csuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.csuc(errB, "cat", stateB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.csuc(errB, "cat", stateB))).to.be.true;
        }
        // csuc, cerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.csuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.cerr(errB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.cerr(errB))).to.be.true;
        }
        // csuc, esuc
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.csuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.esuc(errB, "cat", stateB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.csuc(ParseError.merge(errA, errB), "cat", stateB))).to.be.true;
        }
        // csuc, eerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.csuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.eerr(errB);
                });
            };
            let mapped = bind(parser, func);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.cerr(ParseError.merge(errA, errB)))).to.be.true;
        }
        // cerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.cerr(errA);
            });
            let func = () => { throw new Error("unexpected call"); };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.cerr(errA))).to.be.true;
        }
        // esuc, csuc
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.esuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.csuc(errB, "cat", stateB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.csuc(errB, "cat", stateB))).to.be.true;
        }
        // esuc, cerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.esuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.cerr(errB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.cerr(errB))).to.be.true;
        }
        // esuc, esuc
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.esuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.esuc(errB, "cat", stateB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.esuc(ParseError.merge(errA, errB), "cat", stateB))).to.be.true;
        }
        // esuc, eerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.esuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.eerr(errB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.eerr(ParseError.merge(errA, errB)))).to.be.true;
        }
        // eerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.eerr(errA);
            });
            let func = () => { throw new Error("unexpected call"); };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.eerr(errA))).to.be.true;
        }
    });

    it("should obey the monad laws", () => {
        let initState = new State(
            new Config({ tabWidth: 8 }),
            "input",
            new SourcePos("foobar", 1, 1),
            "none"
        );
        // pure x >>= func = func x
        {
            let finalState = new State(
                new Config({ tabWidth: 4 }),
                "rest",
                new SourcePos("foobar", 1, 1),
                "some"
            );
            let err = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "test")]
            );
            let funcs = [
                () => new Parser(() => Result.csuc(err, "cat", finalState)),
                () => new Parser(() => Result.cerr(err)),
                () => new Parser(() => Result.esuc(err, "cat", finalState)),
                () => new Parser(() => Result.eerr(err))
            ];
            for (let func of funcs) {
                expect(Result.equal(
                    bind(pure("nyan"), func).run(initState),
                    func("nyan").run(initState)
                )).to.be.true;
            }
        }
        // parser >>= pure = parser
        {
            let finalState = new State(
                new Config({ tabWidth: 4 }),
                "rest",
                new SourcePos("foobar", 1, 1),
                "some"
            );
            let err = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "test")]
            );
            let parsers = [
                new Parser(() => Result.csuc(err, "nyancat", finalState)),
                new Parser(() => Result.cerr(err)),
                new Parser(() => Result.esuc(err, "nyancat", finalState)),
                new Parser(() => Result.eerr(err))
            ];
            for (let parser of parsers) {
                expect(Result.equal(
                    bind(parser, pure).run(initState),
                    parser.run(initState)
                )).to.be.true;
            }
        }
        // (parser >>= f) >>= g = parser >>= (\x -> f x >>= g)
        {
            let stateP = new State(
                new Config({ tabWidth: 4 }),
                "restP",
                new SourcePos("foobar", 1, 1),
                "someP"
            );
            let errP = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "testP")]
            );
            let parsers = [
                new Parser(() => Result.csuc(errP, "p", stateP)),
                new Parser(() => Result.cerr(errP)),
                new Parser(() => Result.esuc(errP, "p", stateP)),
                new Parser(() => Result.eerr(errP))
            ];

            let stateF = new State(
                new Config({ tabWidth: 2 }),
                "restF",
                new SourcePos("foobar", 1, 1),
                "someF"
            );
            let errF = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "testF")]
            );
            let fs = [
                () => new Parser(() => Result.csuc(errF, "f", stateF)),
                () => new Parser(() => Result.cerr(errF)),
                () => new Parser(() => Result.esuc(errF, "f", stateF)),
                () => new Parser(() => Result.eerr(errF))
            ];

            let stateG = new State(
                new Config({ tabWidth: 1 }),
                "restG",
                new SourcePos("foobar", 1, 1),
                "someG"
            );
            let errG = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "testG")]
            );
            let gs = [
                () => new Parser(() => Result.csuc(errG, "g", stateG)),
                () => new Parser(() => Result.cerr(errG)),
                () => new Parser(() => Result.esuc(errG, "g", stateG)),
                () => new Parser(() => Result.eerr(errG))
            ];

            for (let parser of parsers) {
                for (let f of fs) {
                    for (let g of gs) {
                        expect(Result.equal(
                            bind(bind(parser, f), g).run(initState),
                            bind(parser, x => bind(f(x), g)).run(initState)
                        )).to.be.true;
                    }
                }
            }
        }
    });
});
<commit_msg>[prim] Fix lacking test<commit_after>/*
 * loquat-prim test / prim.bind()
 * copyright (c) 2016 Susisu
 */

"use strict";

const chai = require("chai");
const expect = chai.expect;

const _core = require("loquat-core");
const SourcePos        = _core.SourcePos;
const ErrorMessageType = _core.ErrorMessageType;
const ErrorMessage     = _core.ErrorMessage;
const ParseError       = _core.ParseError;
const Config           = _core.Config;
const State            = _core.State;
const Result           = _core.Result;
const Parser           = _core.Parser;
const assertParser     = _core.assertParser;

const _prim = require("prim.js")(_core);
const pure = _prim.pure;
const bind = _prim.bind;

describe(".bind(parser, func)", () => {
    it("should return a parser that runs `parser', maps `func' to the result, and flattens its return value", () => {
        let initState = new State(
            new Config({ tabWidth: 8 }),
            "input",
            new SourcePos("foobar", 1, 1),
            "none"
        );
        let stateA = new State(
            new Config({ tabWidth: 4 }),
            "restA",
            new SourcePos("foobar", 1, 2),
            "someA"
        );
        let errA = new ParseError(
            new SourcePos("foobar", 1, 2),
            [new ErrorMessage(ErrorMessageType.MESSAGE, "testA")]
        );
        let stateB = new State(
            new Config({ tabWidth: 2 }),
            "restB",
            new SourcePos("foobar", 1, 2),
            "someB"
        );
        let errB = new ParseError(
            new SourcePos("foobar", 1, 2),
            [new ErrorMessage(ErrorMessageType.MESSAGE, "testB")]
        );
        // csuc, csuc
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.csuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.csuc(errB, "cat", stateB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.csuc(errB, "cat", stateB))).to.be.true;
        }
        // csuc, cerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.csuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.cerr(errB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.cerr(errB))).to.be.true;
        }
        // csuc, esuc
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.csuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.esuc(errB, "cat", stateB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.csuc(ParseError.merge(errA, errB), "cat", stateB))).to.be.true;
        }
        // csuc, eerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.csuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.eerr(errB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.cerr(ParseError.merge(errA, errB)))).to.be.true;
        }
        // cerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.cerr(errA);
            });
            let func = () => { throw new Error("unexpected call"); };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.cerr(errA))).to.be.true;
        }
        // esuc, csuc
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.esuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.csuc(errB, "cat", stateB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.csuc(errB, "cat", stateB))).to.be.true;
        }
        // esuc, cerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.esuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.cerr(errB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.cerr(errB))).to.be.true;
        }
        // esuc, esuc
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.esuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.esuc(errB, "cat", stateB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.esuc(ParseError.merge(errA, errB), "cat", stateB))).to.be.true;
        }
        // esuc, eerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.esuc(errA, "nyan", stateA);
            });
            let func = val => {
                expect(val).to.equal("nyan");
                return new Parser(state => {
                    expect(state).to.equal(stateA);
                    return Result.eerr(errB);
                });
            };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.eerr(ParseError.merge(errA, errB)))).to.be.true;
        }
        // eerr
        {
            let parser = new Parser(state => {
                expect(State.equal(state, initState)).to.be.true;
                return Result.eerr(errA);
            });
            let func = () => { throw new Error("unexpected call"); };
            let mapped = bind(parser, func);
            assertParser(mapped);
            let res = mapped.run(initState);
            expect(Result.equal(res, Result.eerr(errA))).to.be.true;
        }
    });

    it("should obey the monad laws", () => {
        let initState = new State(
            new Config({ tabWidth: 8 }),
            "input",
            new SourcePos("foobar", 1, 1),
            "none"
        );
        // pure x >>= func = func x
        {
            let finalState = new State(
                new Config({ tabWidth: 4 }),
                "rest",
                new SourcePos("foobar", 1, 1),
                "some"
            );
            let err = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "test")]
            );
            let funcs = [
                () => new Parser(() => Result.csuc(err, "cat", finalState)),
                () => new Parser(() => Result.cerr(err)),
                () => new Parser(() => Result.esuc(err, "cat", finalState)),
                () => new Parser(() => Result.eerr(err))
            ];
            for (let func of funcs) {
                expect(Result.equal(
                    bind(pure("nyan"), func).run(initState),
                    func("nyan").run(initState)
                )).to.be.true;
            }
        }
        // parser >>= pure = parser
        {
            let finalState = new State(
                new Config({ tabWidth: 4 }),
                "rest",
                new SourcePos("foobar", 1, 1),
                "some"
            );
            let err = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "test")]
            );
            let parsers = [
                new Parser(() => Result.csuc(err, "nyancat", finalState)),
                new Parser(() => Result.cerr(err)),
                new Parser(() => Result.esuc(err, "nyancat", finalState)),
                new Parser(() => Result.eerr(err))
            ];
            for (let parser of parsers) {
                expect(Result.equal(
                    bind(parser, pure).run(initState),
                    parser.run(initState)
                )).to.be.true;
            }
        }
        // (parser >>= f) >>= g = parser >>= (\x -> f x >>= g)
        {
            let stateP = new State(
                new Config({ tabWidth: 4 }),
                "restP",
                new SourcePos("foobar", 1, 1),
                "someP"
            );
            let errP = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "testP")]
            );
            let parsers = [
                new Parser(() => Result.csuc(errP, "p", stateP)),
                new Parser(() => Result.cerr(errP)),
                new Parser(() => Result.esuc(errP, "p", stateP)),
                new Parser(() => Result.eerr(errP))
            ];

            let stateF = new State(
                new Config({ tabWidth: 2 }),
                "restF",
                new SourcePos("foobar", 1, 1),
                "someF"
            );
            let errF = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "testF")]
            );
            let fs = [
                () => new Parser(() => Result.csuc(errF, "f", stateF)),
                () => new Parser(() => Result.cerr(errF)),
                () => new Parser(() => Result.esuc(errF, "f", stateF)),
                () => new Parser(() => Result.eerr(errF))
            ];

            let stateG = new State(
                new Config({ tabWidth: 1 }),
                "restG",
                new SourcePos("foobar", 1, 1),
                "someG"
            );
            let errG = new ParseError(
                new SourcePos("foobar", 1, 1),
                [new ErrorMessage(ErrorMessageType.MESSAGE, "testG")]
            );
            let gs = [
                () => new Parser(() => Result.csuc(errG, "g", stateG)),
                () => new Parser(() => Result.cerr(errG)),
                () => new Parser(() => Result.esuc(errG, "g", stateG)),
                () => new Parser(() => Result.eerr(errG))
            ];

            for (let parser of parsers) {
                for (let f of fs) {
                    for (let g of gs) {
                        expect(Result.equal(
                            bind(bind(parser, f), g).run(initState),
                            bind(parser, x => bind(f(x), g)).run(initState)
                        )).to.be.true;
                    }
                }
            }
        }
    });
});
<|endoftext|>