<commit_before>export { Base }; // Stage.BlockParamsCreator.Base

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
import * as ValueDesc from "../../../Unpacker/ValueDesc.js";
import * as Block from "../../Block.js";
import { Params } from "../Stage_Params.js";

/**
 * Base class for all Stage.BlockParamsCreator.Xxx classes.
 *
 *
 * @member {number} outChannels0
 *   The output0's channel count in current configuration.
 *
 * @member {number} outChannels1
 *   The output1's channel count in current configuration.
 *
 */
class Base extends Recyclable.Root {

  /**
   * Used as default Stage.BlockParamsCreator.Base provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Stage.BlockParamsCreator.Base.Pool", Base, Base.setAsConstructor );

  /**
   * @param {Params} stageParams
   *   The Stage.Params object which provides basic parameters. It will be owned and released by this Stage.BlockParamsCreator.Base onject.
   */
  constructor( stageParams ) {
    super();
    Base.setAsConstructor_self.call( this, stageParams );
  }

  /** @override */
  static setAsConstructor( stageParams ) {
    super.setAsConstructor();
    Base.setAsConstructor_self.call( this, stageParams );
    return this;
  }

  /** @override */
  static setAsConstructor_self( stageParams ) {
    this.stageParams = stageParams;
  }

  /** @override */
  disposeResources() {
    this.channelShuffler = undefined; // Note: channelShuffler is owned and released by Stage.Base (not here Stage.BlockParamsCreator.Base).

    this.blockCount = undefined; // How many block should be in the stage.
    this.depthwiseFilterHeight_Default = undefined;
    this.depthwiseFilterWidth_Default = undefined; // The default depthwise filter size.
    this.depthwiseFilterHeight_Last = undefined;
    this.depthwiseFilterWidth_Last = undefined;    // The last block's depthwise filter size.
    this.outChannels0 = undefined;
    this.outChannels1 = undefined;

    this.bKeepInputTensor = undefined;
    this.nActivationId = undefined;
    this.bSqueezeExcitationPrefix = undefined;
    this.nSqueezeExcitationChannelCountDivisor = undefined;
    this.pointwise20ActivationId = undefined;
    this.pointwise20ChannelCount = undefined;
    this.depthwiseActivationId = undefined;
    this.depthwiseStridesPad = undefined;
    this.depthwiseFilterWidth = undefined;
    this.depthwiseFilterHeight = undefined;
    this.depthwise_AvgMax_Or_ChannelMultiplier = undefined;
    this.pointwise1ChannelCount = undefined;
    this.nConvBlockTypeId = undefined;
    this.input0_channelCount = undefined;
    this.input0_width = undefined;
    this.input0_height = undefined;

    if ( this.stageParams ) {
      this.stageParams.disposeResources_and_recycleToPool();
      this.stageParams = undefined;
    }

    super.disposeResources();
  }

  /** Called to determine blockCount, depthwiseFilterHeight_Default, depthwiseFilterWidth_Default, depthwiseFilterHeight_Last,
    * depthwiseFilterWidth_Last.
    *
    * Sub-class could override this method to adjust data members.
    */
  determine_blockCount_depthwiseFilterHeightWidth_Default_Last() {
    let stageParams = this.stageParams;
    this.blockCount = stageParams.blockCountRequested; // By default, the block count is just the original block count.

    // By default, all blocks uses the original depthwise filter size.
    this.depthwiseFilterHeight_Default = this.depthwiseFilterHeight_Last = stageParams.depthwiseFilterHeight;
    this.depthwiseFilterWidth_Default = this.depthwiseFilterWidth_Last = stageParams.depthwiseFilterWidth;
  }

  /**
   * Called before block0 is about to be created. Sub-class should override this method to adjust data members.
   *
   * Block 0.
   *
   * The special points of a stage's block 0 are:
   *   - halve the height x width. (Both ShuffleNetV2 and MobileNetV2) (by depthwise convolution with strides = 2)
   *   - Double channels. (Please see explanation of class Stage.Base)
   */
  configTo_beforeBlock0() {
    let stageParams = this.stageParams;

    this.input0_height = stageParams.sourceHeight; // block0 inputs the source image size.
    this.input0_width = stageParams.sourceWidth;
    //this.input0_channelCount; // Sub-class should determine it.

    this.activation_setup_forBlock0(); // activation of depthwise1 and pointwise2.

    this.depthwiseFilterHeight = this.depthwiseFilterHeight_Default;
    this.depthwiseFilterWidth = this.depthwiseFilterWidth_Default;

    // block0 uses depthwise ( strides = 2, pad = "same" ) to halve ( height, width ).
    this.depthwiseStridesPad = ValueDesc.StridesPad.Singleton.Ids.STRIDES_2_PAD_SAME;

    this.nSqueezeExcitationChannelCountDivisor = stageParams.nSqueezeExcitationChannelCountDivisor;

    this.bKeepInputTensor = stageParams.bKeepInputTensor; // block0 may or may not keep input tensor according to caller's necessary.
  }

  /**
   * Called after block0 is created (i.e. before block1, 2, 3, ...). Sub-class should override this method to adjust data members.
   */
  configTo_afterBlock0() {
    let stageParams = this.stageParams;

    this.input0_height = stageParams.outputHeight; // all blocks (except block0) inputs half the source image size.
    this.input0_width = stageParams.outputWidth;
    //this.input0_channelCount; // Sub-class should determine it.

    // All blocks (except block0 in NoPointwise1) will not double the channel count by depthwise, because block0 has already double
    // output channel count.
    //
    this.depthwise_AvgMax_Or_ChannelMultiplier = 1;

    // All blocks (except block0) uses depthwise ( strides = 1, pad = "same" ) to keep ( height, width ).
    this.depthwiseStridesPad = ValueDesc.StridesPad.Singleton.Ids.STRIDES_1_PAD_SAME;

    this.bKeepInputTensor = false; // No matter bKeepInputTensor, all blocks (except block0) should not keep input tensor.
  }

  /**
   * Called before blockLast is about to be created. Sub-class could override this method to adjust data members.
   */
  configTo_beforeBlockLast() {

    // Besides, the blockLast may use a different depthwise filter size. This is especially true for NotShuffleNet_NotMobileNet.
    this.depthwiseFilterHeight = this.depthwiseFilterHeight_Last;
    this.depthwiseFilterWidth = this.depthwiseFilterWidth_Last;

    this.activation_setup_forBlockLast(); // activation of depthwise1 and pointwise2
  }

  /**
   * Config the activation of pointwise1, depthwise1, pointwise2 and squeeze-and-excitation for block0.
   */
  activation_setup_forBlock0() {
    let stageParams = this.stageParams;

    // 1. depthwise
    {
      // MobileNetV2_Xxx's depthwise has activation (before prefix squeeze-and-excitation and to remedy its pointwise2's no activation).
      //
      if ( ValueDesc.ConvStageType.isMobileNetV2( stageParams.nConvStageType ) ) {
        this.depthwiseActivationId = stageParams.nActivationId;

      // non-MobileNetV2_Xxx's depthwise has no activation. (since they will be done at pointwise2.)
      //
      } else {
        this.depthwiseActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;
      }
    }

    // 2. pointwise2
    {
      // MobileNetV2_Xxx's pointwise2 always does not have activation function.
      //
      // The reason is that MobileNetV2_Xxx's pointwise2 has add-input-to-output so its block's output is not affine transformation
      // (even if no activation function). It and the next block's pointwise1 is not continuous multiple affine transformation
      // and will not become just one affine transformation.
      //
      if ( ValueDesc.ConvStageType.isMobileNetV2( stageParams.nConvStageType ) ) {
        this.pointwise20ActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;

      // For all other ConvStageType, all non-blockLast's pointwise2 must have activation function (to become non-affine transformation).
      // The reason is to avoid the previous block's pointwise2 and the next block's pointwis1 become just one affine transformation.
      } else {
        this.pointwise20ActivationId = stageParams.nActivationId;
      }
    }

    // 3. pointwise1 and squeeze-and-excitation
    this.nActivationId = stageParams.nActivationId;

    // 4. squeeze-and-excitation prefix or postfix
    {
      // MobileNetV2_Xxx uses prefix squeeze-and-excitation.
      //
      if ( ValueDesc.ConvStageType.isMobileNetV2( stageParams.nConvStageType ) ) {
        this.bSqueezeExcitationPrefix = true;

      // non-MobileNetV2_Xxx uses postfix squeeze-and-excitation.
      //
      } else {
        this.bSqueezeExcitationPrefix = false;
      }
    }

  }

  /**
   * Config the activation of pointwise1, depthwise1, pointwise2 and squeeze-and-excitation for blockLast.
   */
  activation_setup_forBlockLast() {
    let stageParams = this.stageParams;

    // pointwise2
    {
      // MobileNetV2_Xxx's pointwise2 always does not have activation function.
      //
      // The reason is that MobileNetV2_Xxx's pointwise2 has add-input-to-output so its block's output is not affine transformation
      // (even if no activation function). It and the next block's pointwise1 is not continuous multiple affine transformation
      // and will not become just one affine transformation.
      //
      if ( ValueDesc.ConvStageType.isMobileNetV2( stageParams.nConvStageType ) ) {
        this.pointwise20ActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;

      // For all other ConvStageType, whether blockLast's pointwise2 has activation function is according to the specified flag.
      } else {
        if ( stageParams.bPointwise2ActivatedAtStageEnd == false ) {
          this.pointwise20ActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;
        } else {
          this.pointwise20ActivationId = stageParams.nActivationId;
        }
      }
    }
  }

  /**
   *
   * @return {Block.Params}
   *   Create and return a Block.Params according to this object's current state.
   */
  create_BlockParams() {
    let params = Block.Params.Pool.get_or_create_by(
      this.input0_height, this.input0_width, this.input0_channelCount,
      this.nConvBlockTypeId,
      this.pointwise1ChannelCount,
      this.depthwise_AvgMax_Or_ChannelMultiplier, this.depthwiseFilterHeight, this.depthwiseFilterWidth, this.depthwiseStridesPad,
      this.depthwiseActivationId,
      this.pointwise20ChannelCount, this.pointwise20ActivationId,
      this.nSqueezeExcitationChannelCountDivisor, this.bSqueezeExcitationPrefix,
      this.nActivationId,
      this.bKeepInputTensor
    );
    return params;
  }

}
<commit_msg>Update Base.js<commit_after>export { Base }; // Stage.BlockParamsCreator.Base

import * as Pool from "../../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
import * as ValueDesc from "../../../Unpacker/ValueDesc.js";
import * as Block from "../../Block.js";
import { Params } from "../Stage_Params.js";

/**
 * Base class for all Stage.BlockParamsCreator.Xxx classes.
 *
 *
 * @member {number} outChannels0
 *   The output0's channel count in current configuration.
 *
 * @member {number} outChannels1
 *   The output1's channel count in current configuration.
 *
 */
class Base extends Recyclable.Root {

  /**
   * Used as default Stage.BlockParamsCreator.Base provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Stage.BlockParamsCreator.Base.Pool", Base, Base.setAsConstructor );

  /**
   * @param {Params} stageParams
   *   The Stage.Params object which provides basic parameters. It will be owned and released by this Stage.BlockParamsCreator.Base onject.
   */
  constructor( stageParams ) {
    super();
    Base.setAsConstructor_self.call( this, stageParams );
  }

  /** @override */
  static setAsConstructor( stageParams ) {
    super.setAsConstructor();
    Base.setAsConstructor_self.call( this, stageParams );
    return this;
  }

  /** @override */
  static setAsConstructor_self( stageParams ) {
    this.stageParams = stageParams;
  }

  /** @override */
  disposeResources() {
    this.channelShuffler = undefined; // Note: channelShuffler is owned and released by Stage.Base (not here Stage.BlockParamsCreator.Base).

    this.blockCount = undefined; // How many block should be in the stage.
    this.depthwiseFilterHeight_Default = undefined;
    this.depthwiseFilterWidth_Default = undefined; // The default depthwise filter size.
    this.depthwiseFilterHeight_Last = undefined;
    this.depthwiseFilterWidth_Last = undefined;    // The last block's depthwise filter size.
    this.outChannels0 = undefined;
    this.outChannels1 = undefined;

    this.bKeepInputTensor = undefined;
    this.nActivationId = undefined;
    this.bSqueezeExcitationPrefix = undefined;
    this.nSqueezeExcitationChannelCountDivisor = undefined;
    this.pointwise20ActivationId = undefined;
    this.pointwise20ChannelCount = undefined;
    this.depthwiseActivationId = undefined;
    this.depthwiseStridesPad = undefined;
    this.depthwiseFilterWidth = undefined;
    this.depthwiseFilterHeight = undefined;
    this.depthwise_AvgMax_Or_ChannelMultiplier = undefined;
    this.pointwise1ChannelCount = undefined;
    this.nConvBlockTypeId = undefined;
    this.input0_channelCount = undefined;
    this.input0_width = undefined;
    this.input0_height = undefined;

    if ( this.stageParams ) {
      this.stageParams.disposeResources_and_recycleToPool();
      this.stageParams = undefined;
    }

    super.disposeResources();
  }

  /** Called to determine blockCount, depthwiseFilterHeight_Default, depthwiseFilterWidth_Default, depthwiseFilterHeight_Last,
    * depthwiseFilterWidth_Last.
    *
    * Sub-class could override this method to adjust data members.
    */
  determine_blockCount_depthwiseFilterHeightWidth_Default_Last() {
    let stageParams = this.stageParams;
    this.blockCount = stageParams.blockCountRequested; // By default, the block count is just the original block count.

    // By default, all blocks uses the original depthwise filter size.
    this.depthwiseFilterHeight_Default = this.depthwiseFilterHeight_Last = stageParams.depthwiseFilterHeight;
    this.depthwiseFilterWidth_Default = this.depthwiseFilterWidth_Last = stageParams.depthwiseFilterWidth;
  }

  /**
   * Called before block0 is about to be created. Sub-class should override this method to adjust data members.
   *
   * Block 0.
   *
   * The special points of a stage's block 0 are:
   *   - halve the height x width. (Both ShuffleNetV2 and MobileNetV2) (by depthwise convolution with strides = 2)
   *   - Double channels. (Please see explanation of class Stage.Base)
   */
  configTo_beforeBlock0() {
    let stageParams = this.stageParams;

    this.input0_height = stageParams.sourceHeight; // block0 inputs the source image size.
    this.input0_width = stageParams.sourceWidth;
    //this.input0_channelCount; // Sub-class should determine it.

    this.activation_setup_forBlock0(); // activation of depthwise1 and pointwise2.

    this.depthwiseFilterHeight = this.depthwiseFilterHeight_Default;
    this.depthwiseFilterWidth = this.depthwiseFilterWidth_Default;

    // block0 uses depthwise ( strides = 2, pad = "same" ) to halve ( height, width ).
    this.depthwiseStridesPad = ValueDesc.StridesPad.Singleton.Ids.STRIDES_2_PAD_SAME;

    this.nSqueezeExcitationChannelCountDivisor = stageParams.nSqueezeExcitationChannelCountDivisor;

    this.bKeepInputTensor = stageParams.bKeepInputTensor; // block0 may or may not keep input tensor according to caller's necessary.
  }

  /**
   * Called after block0 is created (i.e. before block1, 2, 3, ...). Sub-class should override this method to adjust data members.
   */
  configTo_afterBlock0() {
    let stageParams = this.stageParams;

    this.input0_height = stageParams.outputHeight; // all blocks (except block0) inputs half the source image size.
    this.input0_width = stageParams.outputWidth;
    //this.input0_channelCount; // Sub-class should determine it.

    // All blocks (except block0 in NoPointwise1) will not double the channel count by depthwise, because block0 has already double
    // output channel count.
    //
    this.depthwise_AvgMax_Or_ChannelMultiplier = 1;

    // All blocks (except block0) uses depthwise ( strides = 1, pad = "same" ) to keep ( height, width ).
    this.depthwiseStridesPad = ValueDesc.StridesPad.Singleton.Ids.STRIDES_1_PAD_SAME;

    this.bKeepInputTensor = false; // No matter bKeepInputTensor, all blocks (except block0) should not keep input tensor.
  }

  /**
   * Called before blockLast is about to be created. Sub-class could override this method to adjust data members.
   */
  configTo_beforeBlockLast() {

    // Besides, the blockLast may use a different depthwise filter size. This is especially true for NotShuffleNet_NotMobileNet.
    this.depthwiseFilterHeight = this.depthwiseFilterHeight_Last;
    this.depthwiseFilterWidth = this.depthwiseFilterWidth_Last;

    this.activation_setup_forBlockLast(); // activation of depthwise1 and pointwise2
  }

  /**
   * Config the activation of pointwise1, depthwise1, pointwise2 and squeeze-and-excitation for block0.
   */
  activation_setup_forBlock0() {
    let stageParams = this.stageParams;

    // 1. depthwise
    {
      // MobileNetV2_Xxx's depthwise has activation (before prefix squeeze-and-excitation and to remedy its pointwise2's no activation).
      //
      if ( ValueDesc.ConvStageType.isMobileNetV2( stageParams.nConvStageType ) ) {
        this.depthwiseActivationId = stageParams.nActivationId;

      // non-MobileNetV2_Xxx's depthwise has no activation. (since they will be done at pointwise2.)
      //
      } else {
        this.depthwiseActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;
      }
    }

    // 2. pointwise2
    {
      // MobileNetV2_Xxx's pointwise2 always does not have activation function.
      //
      // The reason is that MobileNetV2_Xxx's pointwise2 has add-input-to-output so its block's output is not affine transformation
      // (even if no activation function). It and the next block's pointwise1 is not continuous multiple affine transformation
      // and will not become just one affine transformation.
      //
      if ( ValueDesc.ConvStageType.isMobileNetV2( stageParams.nConvStageType ) ) {
        this.pointwise20ActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;

      // For all other ConvStageType, all non-blockLast's pointwise2 must have activation function (to become non-affine transformation).
      // The reason is to avoid the previous block's pointwise2 and the next block's pointwis1 become just one affine transformation.
      } else {
        this.pointwise20ActivationId = stageParams.nActivationId;
      }
    }

    // 3. pointwise1 and squeeze-and-excitation
    this.nActivationId = stageParams.nActivationId;

    // 4. squeeze-and-excitation prefix or postfix
    {
      // MobileNetV2_Xxx uses prefix squeeze-and-excitation.
      //
      if ( ValueDesc.ConvStageType.isMobileNetV2( stageParams.nConvStageType ) ) {
        this.bSqueezeExcitationPrefix = true;

      // non-MobileNetV2_Xxx uses postfix squeeze-and-excitation.
      //
      } else {
        this.bSqueezeExcitationPrefix = false;
      }
    }

  }

  /**
   * Config the activation of pointwise1, depthwise1, pointwise2 and squeeze-and-excitation for blockLast.
   */
  activation_setup_forBlockLast() {
    let stageParams = this.stageParams;

    // pointwise2
    {
      // MobileNetV2_Xxx's pointwise2 always does not have activation function.
      //
      // The reason is that MobileNetV2_Xxx's pointwise2 has add-input-to-output so its block's output is not affine transformation
      // (even if no activation function). It and the next block's pointwise1 is not continuous multiple affine transformation
      // and will not become just one affine transformation.
      //
      if ( ValueDesc.ConvStageType.isMobileNetV2( stageParams.nConvStageType ) ) {
        this.pointwise20ActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;

      // For all other ConvStageType, whether blockLast's pointwise2 has activation function is according to the specified flag.
      } else {
        if ( stageParams.bPointwise2ActivatedAtStageEnd == false ) {
          this.pointwise20ActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;
        } else {
          this.pointwise20ActivationId = stageParams.nActivationId;
        }
      }
    }
  }

  /**
   *
   * @return {Block.Params}
   *   Create and return a Block.Params according to this object's current state.
   */
  create_BlockParams() {
    let params = Block.Params.Pool.get_or_create_by(
      this.input0_height, this.input0_width, this.input0_channelCount,
      this.nConvBlockTypeId,
      this.pointwise1ChannelCount,
      this.depthwise_AvgMax_Or_ChannelMultiplier, this.depthwiseFilterHeight, this.depthwiseFilterWidth, this.depthwiseStridesPad,
      this.depthwiseActivationId,
      this.pointwise20ChannelCount, this.pointwise20ActivationId,
      this.nSqueezeExcitationChannelCountDivisor, this.bSqueezeExcitationPrefix,
      this.nActivationId,
      this.bKeepInputTensor
    );
    return params;
  }

}
<|endoftext|>


<commit_before>
module.exports = function(less) {

    var tree       = less.tree,
        Expression = tree.Expression,
        Anonymous  = tree.Anonymous,
        Value      = tree.Value,
        Node       = tree.Node,
        isArray    = Array.isArray;

    // ........................................................

    function newLessList(list, type) {
        var ReturnType = (type === "Expression")
            ? Expression : Value;
        return new ReturnType(list);
    }

    // ........................................................

    function toString(list, pre, post) {
        return !isArray(list.value) ? list.toCSS()
            : pre + list.value.map(function(a) {
                return toString(a, pre, post);
            }).join(list.type === "Expression"
                ? " " : ", ") + post;
    }

    // ........................................................

    function evalIndex(list, index, default_) {
        if (index && ((index.type !== "Dimension") ||
            !index.unit.isEmpty())) throw {
                type:    "Argument",
                message: "unexpected index `" + index.toCSS() + "`"
        };

        index = (index === undefined)
            ? default_ : index.value;
        return index + ((index < 1)
            ? list.value.length : -1);
    }

    // ........................................................

    function atKey(list, index) {
        if (!isArray(list.value))
            return;

        // see docs/impl-notes.md#at-1
        list = (!isArray(list.value[0].value) &&
            (list.type === "Expression"))
                ? [list] : list.value;

        var pair, type, key;
        for (var i = 0; i < list.length; i++) {
            pair = list[i];
            // return empty thing if value is missing but key matches:
            if (!isArray(pair) &&
                (Node.compare(index, pair) === 0))
                    return new Node();

            type = pair.type;
            pair = pair.value;
            key  = pair[0];
            if (Node.compare(index, key) === 0)
                return (pair.length < 2) ? pair[1]
                    : newLessList(pair.slice(1), type);
        }
    }

// ............................................................

    var functions = {

        // ....................................................

        at: function(list, index) {
            if ((index.type !== "Dimension") ||
                 !index.unit.isEmpty())
                    return atKey(list, index);

            list = isArray(list.value)
                ? list.value : [list];
            return list[index.value - 1];
        },

        /* Not yet.
        extract: function(list, index) {
            return functions.at(list, index);
        },
        */

        // ....................................................

        cat: function() {
            var returnType, list = [];
            for (var i = 0; i < arguments.length; i++) {
                var arg = arguments[i];
                if (isArray(arg.value)) {
                    returnType = returnType || arg.type;
                    arg = arg.value;
                }
                list = list.concat(arg);
            }

            return newLessList(list, returnType);
        },

        // ....................................................

        l: function() {
            if (arguments.length < 2)
                return;

            var list = new Array(arguments.length);
            for (var i = 0; i < arguments.length; i++)
                list[i] = arguments[i];
            return new Value(list);
        },

        // ....................................................

        slice: function(list, start, end) {
            if (list && isArray(list.value)) {
                start = evalIndex(list, start, 1);
                end   = evalIndex(list, end, 0);

                // see docs/impl-notes.md#slice-1
                return newLessList(list.value
                    .slice(start, end), list.type);
            }
        },

        // ....................................................

        splice: function(list, start, end, value) {
            if (list && isArray(list.value)) {
                start = evalIndex(list, start, 1);
                end   = evalIndex(list, end, start + 2) - start;

                var copy = list.value.slice();
                value // jshint expr: true
                    ? copy.splice(start, end, value)
                    : copy.splice(start, end);
                return newLessList(copy, list.type);
            }
        },

        // ....................................................

        flatten: function(list, type) {
            if (!isArray(list.value))
                return list;

            function flatten_(list) {
                return list.reduce(function(a, b) {
                    return a.concat(isArray(b.value)
                        ? flatten_(b.value) : b);
                }, []);
            }

            // TODO: should not it try to determine the default return type by the type
            // of the input list top dimension? (for consistency with `cat`?)

            var ReturnType = type ? {
                comma: Value,
                space: Expression,
                ",":   Value,
                " ":   Expression
            }[type.value] : Value;

            if (!ReturnType) throw {
                type:    "Argument",
                message: "invalid `" + type.toCSS()
                    + "` delimiter. Expected `comma`, `space`, `,` or ` `\n"
            };

            return new ReturnType(flatten_(list.value));
        },

        // ....................................................

        transpose: function(list) {
            if (!isArray(list.value))
                return list;

            var listType, row, rowType;
            rowType  = list.type;
            list     = list.value;
            listType = list[0].type;
            row      = list[0].value;

            list = (isArray(row) ? row : [row]).map(function(col, i) {
                return newLessList(list.map(function(row) {
                    return (isArray(row.value)
                        ? row.value : [row])[i]
                            || new Node();
                }), rowType);
            });

            return newLessList(list, listType);
        },

        // ....................................................

        join: function(list, delim) {
            return new Anonymous(!isArray(list.value)
                ? list.toCSS()
                : list.value.map(function(a) {
                    return toString(a, "", "");
                }).join(delim ? delim.value : ", "));
        },

        // ....................................................

        _inspect: function(list, prefix, postfix) {
            prefix  = prefix  ? prefix.value  : "[";
            postfix = postfix ? postfix.value : "]";
            return new Anonymous(toString(list, prefix, postfix));
        }

        // ....................................................

    };

    return functions;

// ............................................................

};
<commit_msg>`to-list` function skeleton<commit_after>
module.exports = function(less) {

    var tree       = less.tree,
        Expression = tree.Expression,
        Anonymous  = tree.Anonymous,
        Keyword    = tree.Keyword,
        Value      = tree.Value,
        Node       = tree.Node,
        mergeRules = less.visitors.ToCSSVisitor.prototype._mergeRules,
        isArray    = Array.isArray;

    // ........................................................

    function newLessList(list, type) {
        var ReturnType = (type === "Expression")
            ? Expression : Value;
        return new ReturnType(list);
    }

    // ........................................................

    function toString(list, pre, post) {
        return !isArray(list.value) ? list.toCSS()
            : pre + list.value.map(function(a) {
                return toString(a, pre, post);
            }).join(list.type === "Expression"
                ? " " : ", ") + post;
    }

    // ........................................................

    function evalIndex(list, index, default_) {
        if (index && ((index.type !== "Dimension") ||
            !index.unit.isEmpty())) throw {
                type:    "Argument",
                message: "unexpected index `" + index.toCSS() + "`"
        };

        index = (index === undefined)
            ? default_ : index.value;
        return index + ((index < 1)
            ? list.value.length : -1);
    }

    // ........................................................

    function atKey(list, index) {
        if (!isArray(list.value))
            return;

        // see docs/impl-notes.md#at-1
        list = (!isArray(list.value[0].value) &&
            (list.type === "Expression"))
                ? [list] : list.value;

        var pair, type, key;
        for (var i = 0; i < list.length; i++) {
            pair = list[i];
            // return empty thing if value is missing but key matches:
            if (!isArray(pair) &&
                (Node.compare(index, pair) === 0))
                    return new Node();

            type = pair.type;
            pair = pair.value;
            key  = pair[0];
            if (Node.compare(index, key) === 0)
                return (pair.length < 2) ? pair[1]
                    : newLessList(pair.slice(1), type);
        }
    }

// ............................................................

    var functions = {

        // ....................................................

        at: function(list, index) {
            if ((index.type !== "Dimension") ||
                 !index.unit.isEmpty())
                    return atKey(list, index);

            list = isArray(list.value)
                ? list.value : [list];
            return list[index.value - 1];
        },

        // ....................................................

        cat: function() {
            var returnType, list = [];
            for (var i = 0; i < arguments.length; i++) {
                var arg = arguments[i];
                if (isArray(arg.value)) {
                    returnType = returnType || arg.type;
                    arg = arg.value;
                }
                list = list.concat(arg);
            }

            return newLessList(list, returnType);
        },

        // ....................................................

        l: function() {
            if (arguments.length < 2)
                return;

            var list = new Array(arguments.length);
            for (var i = 0; i < arguments.length; i++)
                list[i] = arguments[i];
            return new Value(list);
        },

        // ....................................................

        slice: function(list, start, end) {
            if (list && isArray(list.value)) {
                start = evalIndex(list, start, 1);
                end   = evalIndex(list, end, 0);

                // see docs/impl-notes.md#slice-1
                return newLessList(list.value
                    .slice(start, end), list.type);
            }
        },

        // ....................................................

        splice: function(list, start, end, value) {
            if (list && isArray(list.value)) {
                start = evalIndex(list, start, 1);
                end   = evalIndex(list, end, start + 2) - start;

                var copy = list.value.slice();
                value // jshint expr: true
                    ? copy.splice(start, end, value)
                    : copy.splice(start, end);
                return newLessList(copy, list.type);
            }
        },

        // ....................................................

        flatten: function(list, type) {
            if (!isArray(list.value))
                return list;

            function flatten_(list) {
                return list.reduce(function(a, b) {
                    return a.concat(isArray(b.value)
                        ? flatten_(b.value) : b);
                }, []);
            }

            // TODO: should not it try to determine the default return type by the type
            // of the input list top dimension? (for consistency with `cat`?)

            var ReturnType = type ? {
                comma: Value,
                space: Expression,
                ",":   Value,
                " ":   Expression
            }[type.value] : Value;

            if (!ReturnType) throw {
                type:    "Argument",
                message: "invalid `" + type.toCSS()
                    + "` delimiter. Expected `comma`, `space`, `,` or ` `\n"
            };

            return new ReturnType(flatten_(list.value));
        },

        // ....................................................

        transpose: function(list) {
            if (!isArray(list.value))
                return list;

            var listType, row, rowType;
            rowType  = list.type;
            list     = list.value;
            listType = list[0].type;
            row      = list[0].value;

            list = (isArray(row) ? row : [row]).map(function(col, i) {
                return newLessList(list.map(function(row) {
                    return (isArray(row.value)
                        ? row.value : [row])[i]
                            || new Node();
                }), rowType);
            });

            return newLessList(list, listType);
        },

        // ....................................................

        join: function(list, delim) {
            return new Anonymous(!isArray(list.value)
                ? list.toCSS()
                : list.value.map(function(a) {
                    return toString(a, "", "");
                }).join(delim ? delim.value : ", "));
        },

        // ....................................................

        "to-list": function(obj) {
            // it's actually questionable if we should fully evaluate DR here at all
            // but we must evaluate (at least partially) and merge property names
            var list  = [],
                rules = obj.callEval(this.context).rules;
            mergeRules(rules);
            for (var i = 0; i < rules.length; i++) {
                var rule = rules[i];
                if (rule.type === "Rule") {
                    // console.log([rule.name, rule.value]);
                    list.push(new Expression([new Keyword(rule.name
                        .slice(rule.variable)), rule.value]));
                }
            }

            return new Value(list);
        },

        // ....................................................

        _inspect: function(list, prefix, postfix) {
            prefix  = prefix  ? prefix.value  : "[";
            postfix = postfix ? postfix.value : "]";
            return new Anonymous(toString(list, prefix, postfix));
        }

        // ....................................................

    };

    return functions;

// ............................................................

};
<|endoftext|>


<commit_before>#!/usr/bin/env node
var minimist = require('minimist')
var api = require('music163')
var Player = require('player')
var fs = require('fs')

var argv = minimist(process.argv.slice(2))

if (argv.h) usage(0)
else if (argv._[0] === 'search') {
  var keyword = argv._[1]
  api.search(keyword, function(err, res) {
    if(err) console.log(err)
    var data = res.result
    console.log('artists', data.artists)
    console.log()
    console.log('albums', data.albums)
    console.log()
    console.log('playlists', data.playlists)
    console.log()
    console.log('songs', data.songs)
  })
}
else if (argv._[0] === 'album') {
  var id = argv._[1]
  api.album(id, function(err, res) {
    if(err) console.log(err)
    console.log('Album "' + res.album.name + '" by "' + res.album.artist.name + '" list: ')
    res.album.songs.forEach(function(song) {
      console.log(song.name + ': ' + song.mp3Url)
    })
  })
}
else if (argv._[0] === 'playlist') {
  var id = argv._[1]
  api.playlist(id, function(err, res) {
    if(err) console.log(err)
    console.log('Playlist by "' + res.result.creator.nickname + '" List: ')
    res.result.tracks.forEach(function(song) {
        console.log(song.name + ': ' + song.mp3Url)
    })
  })
}
else if (argv._[0] === 'dj') {
  var id = argv._[1]
  api.dj(id, function(err, res) {
    if(err) console.log(err)
    console.log('DJ by "' + res.program.dj.nickname + '" List: ')
    res.program.songs.forEach(function(song) {
      console.log(song.name + ': ' + song.mp3Url)
    })
  })
}
else if (argv._[0] === 'detail') {
  var id = argv._[1]
  api.detail(id, function(err, res) {
    if(err) console.log(err)
    console.log('song info: ', res)
  })
}
else if (argv._[0] === 'play') {
  console.log('to be added...')
}
else if (argv._[0] === 'download') {
  console.log('to be added...')
}
else usage(1)

function usage (code) {
  var rs = fs.createReadStream(__dirname + '/usage.txt')
  rs.pipe(process.stdout)
  rs.on('close', function () {
    if (code) process.exit(code)
  })
}<commit_msg>add player code<commit_after>#!/usr/bin/env node

var minimist = require('minimist')
var api = require('music163')
var Player = require('player')
var fs = require('fs')

var argv = minimist(process.argv.slice(2))

if (argv.h) usage(0)
else if (argv._[0] === 'search') {
  var keyword = argv._[1]
  api.search(keyword, function(err, res) {
    if (err) console.log(err)
    var data = res.result
    console.log('artists', data.artists)
    console.log()
    console.log('albums')
    data.albums.forEach(function(album) {
      console.log(album.name + ' by ' + album.artist.name)
    })
    console.log()
    console.log('playlists')
    data.playlists.forEach(function(playlist) {
      console.log(playlist.name + ' created by ' + playlist.creator.nickname)
    })
    console.log()
    console.log('songs')
    data.songs.forEach(function(song) {
      console.log(song.name)
    })
  })
} else if (argv._[0] === 'album') {
  var id = argv._[1]
  api.album(id, function(err, res) {
    if (err) console.log(err)
    console.log('Album "' + res.album.name + '" by "' + res.album.artist.name + '" list: ')
    res.album.songs.forEach(function(song) {
      console.log(song.name + ': ' + song.mp3Url)
    })
  })
} else if (argv._[0] === 'playlist') {
  var id = argv._[1]
  api.playlist(id, function(err, res) {
    if (err) console.log(err)
    console.log('Playlist by "' + res.result.creator.nickname + '" List: ')
    res.result.tracks.forEach(function(song) {
      console.log(song.name + ': ' + song.mp3Url)
    })
  })
} else if (argv._[0] === 'dj') {
  var id = argv._[1]
  api.dj(id, function(err, res) {
    if (err) console.log(err)
    console.log('DJ by "' + res.program.dj.nickname + '" List: ')
    res.program.songs.forEach(function(song) {
      console.log(song.name + ': ' + song.mp3Url)
    })
  })
} else if (argv._[0] === 'detail') {
  var id = argv._[1]
  api.detail(id, function(err, res) {
    if (err) console.log(err)
    console.log('song info: ', res)
  })
} else if (argv._[0] === 'play') {
  var id = argv._[1]
  var type = argv.type || argv.t
  var songs = []

  if (type === 'album') {
    api.album(id, function(err, res) {
      if (err) console.log(err)
      res.album.songs.forEach(function(song) {
        songs.push(song.mp3Url)
      })
    })
  } else if (type === 'playlist') {
    api.playlist(id, function(err, res) {
      if (err) console.log(err)
      res.result.tracks.forEach(function(song) {
        songs.push(song.mp3Url)
      })
    })
  } else if (type === 'dj') {
    api.dj(id, function(err, res) {
      if (err) console.log(err)
      res.program.songs.forEach(function(song) {
        songs.push(song.mp3Url)
      })
    })
  } else if (type === 'detail') {
    api.detail(id, function(err, res) {
      if (err) console.log(err)
      console.log('song info: ', res)
    })
  }

  var player = new Player(songs)
  player.play()

  player.on('playing', function(item) {
    console.log('im playing... src:' + item)
  })

  player.on('playend', function(item) {
    console.log('src:' + item + ' play done, switching to next one ...')
  })

  player.on('error', function(err) {
    console.log(err)
  })
} else if (argv._[0] === 'download') {
  console.log('to be added...')
} else usage(1)

function usage(code) {
  var rs = fs.createReadStream(__dirname + '/usage.txt')
  rs.pipe(process.stdout)
  rs.on('close', function() {
    if (code) process.exit(code)
  })
}<|endoftext|>


<commit_before>/*
 * Copyright 2009-2011 Mozilla Foundation and contributors
 * Licensed under the New BSD license. See LICENSE.txt or:
 * http://opensource.org/licenses/BSD-3-Clause
 */

define(function(require, exports, module) {

/*
 * This module is a Pilot-Lite. It exports a number of objects that replicate
 * parts of the Pilot project. It aims to be mostly API compatible, while
 * removing the submodule complexity and helping us make things work inside
 * Firefox.
 * The Pilot compatible exports are: console/dom/event
 *
 * In addition it contains a small event library similar to EventEmitter but
 * which makes it harder to mistake the event in use.
 */

//------------------------------------------------------------------------------

/**
 * Create an event.
 * For use as follows:
 *
 *   function Hat() {
 *     this.putOn = createEvent();
 *     ...
 *   }
 *   Hat.prototype.adorn = function(person) {
 *     this.putOn({ hat: hat, person: person });
 *     ...
 *   }
 *
 *   var hat = new Hat();
 *   hat.putOn.add(function(ev) {
 *     console.log('The hat ', ev.hat, ' has is worn by ', ev.person);
 *   }, scope);
 *
 * @param name Optional name to help with debugging
 */
exports.createEvent = function(name) {
  var handlers = [];

  /**
   * This is how the event is triggered.
   * @param ev The event object to be passed to the event listeners
   */
  var event = function(ev) {
    // Use for rather than forEach because it step debugs better, which is
    // important for debugging events
    for (var i = 0; i < handlers.length; i++) {
      var handler = handlers[i];
      handler.func.call(handler.scope, ev);
    }
  };

  /**
   * Add a new handler function
   * @param func The function to call when this event is triggered
   * @param scope Optional 'this' object for the function call
   */
  event.add = function(func, scope) {
    handlers.push({ func: func, scope: scope });
  };

  /**
   * Remove a handler function added through add(). Both func and scope must
   * be strict equals (===) the values used in the call to add()
   * @param func The function to call when this event is triggered
   * @param scope Optional 'this' object for the function call
   */
  event.remove = function(func, scope) {
    handlers = handlers.filter(function(test) {
      return test.func !== func && test.scope !== scope;
    });
  };

  /**
   * Remove all handlers.
   * Reset the state of this event back to it's post create state
   */
  event.removeAll = function() {
    handlers = [];
  };

  return event;
};

//------------------------------------------------------------------------------

var dom = {};

var NS_XHTML = 'http://www.w3.org/1999/xhtml';

/**
 * Pass-through to createElement or createElementNS
 * @param doc The document in which to create the element
 * @param tag The name of the tag to create
 * @param ns Custom namespace, HTML/XHTML is assumed if this is missing
 * @returns The created element
 */
dom.createElement = function(doc, tag, ns) {
  // If we've not been given a namespace, but the document is XML, then we
  // use an XHTML namespace, otherwise we use HTML
  if (ns == null && doc.xmlVersion != null) {
    ns = NS_XHTML;
  }
  if (ns == null) {
    return doc.createElement(tag);
  }
  else {
    return doc.createElementNS(ns, tag);
  }
};

/**
 * Remove all the child nodes from this node
 * @param elem The element that should have it's children removed
 */
dom.clearElement = function(elem) {
  while (elem.hasChildNodes()) {
    elem.removeChild(elem.firstChild);
  }
};

/**
 * Add the named CSS class from the element if it is not already present or
 * remove it if is present.
 */
dom.toggleCssClass = function(elem, name) {
  return elem.classList.toggle(name);
};

/**
 * Add or remove a CSS class from the list of classes on the given node
 * depending on the value of <tt>include</tt>
 */
dom.setCssClass = function(node, className, include) {
  if (include) {
    node.classList.add(className);
  }
  else {
    node.classList.remove(className);
  }
};

/**
 * Create a style element in the document head, and add the given CSS text to
 * it.
 * @param cssText The CSS declarations to append
 * @param doc The document element to work from
 */
dom.importCss = function(cssText, doc) {
  doc = doc || document;

  var style = dom.createElement(doc, 'style');
  style.appendChild(doc.createTextNode(cssText));

  var head = doc.getElementsByTagName('head')[0] || doc.documentElement;
  head.appendChild(style);

  return style;
};

/**
 * Shim for window.getComputedStyle
 */
dom.computedStyle = function(element, style) {
  var win = element.ownerDocument.defaultView;
  if (win.getComputedStyle) {
    var styles = win.getComputedStyle(element, '') || {};
    return styles[style] || '';
  }
  else {
    return element.currentStyle[style];
  }
};

/**
 * Using setInnerHtml(foo) rather than innerHTML = foo allows us to enable
 * tweaks in XHTML documents.
 */
dom.setInnerHtml = function(elem, html) {
  if (!this.document || elem.namespaceURI === NS_XHTML) {
    try {
      dom.clearElement(elem);
      var range = elem.ownerDocument.createRange();
      html = '
' + html + '
';
      elem.appendChild(range.createContextualFragment(html));
    }
    catch (ex) {
      elem.innerHTML = html;
    }
  }
  else {
    elem.innerHTML = html;
  }
};

/**
 * Shim to textarea.selectionStart
 */
dom.getSelectionStart = function(textarea) {
  try {
    return textarea.selectionStart || 0;
  }
  catch (ex) {
    return 0;
  }
};

/**
 * Shim to textarea.selectionStart
 */
dom.setSelectionStart = function(textarea, start) {
  return textarea.selectionStart = start;
};

/**
 * Shim to textarea.selectionEnd
 */
dom.getSelectionEnd = function(textarea) {
  try {
    return textarea.selectionEnd || 0;
  }
  catch (ex) {
    return 0;
  }
};

/**
 * Shim to textarea.selectionEnd
 */
dom.setSelectionEnd = function(textarea, end) {
  return textarea.selectionEnd = end;
};

exports.dom = dom;

//------------------------------------------------------------------------------

/**
 * Various event utilities
 */
var event = {};

/**
 * Shim for lack of addEventListener on old IE.
 */
event.addListener = function(elem, type, callback) {
  if (elem.addEventListener) {
    return elem.addEventListener(type, callback, false);
  }
  if (elem.attachEvent) {
    var wrapper = function() {
      callback(window.event);
    };
    callback._wrapper = wrapper;
    elem.attachEvent('on' + type, wrapper);
  }
};

/**
 * Shim for lack of removeEventListener on old IE.
 */
event.removeListener = function(elem, type, callback) {
  if (elem.removeEventListener) {
    return elem.removeEventListener(type, callback, false);
  }
  if (elem.detachEvent) {
    elem.detachEvent('on' + type, callback._wrapper || callback);
  }
};

/**
 * Prevents propagation and clobbers the default action of the passed event
 */
event.stopEvent = function(e) {
  event.stopPropagation(e);
  if (e.preventDefault) {
    e.preventDefault();
  }
  return false;
};

/**
 * Prevents propagation of the event
 */
event.stopPropagation = function(ev) {
  if (ev.stopPropagation) {
    ev.stopPropagation();
  }
  else {
    ev.cancelBubble = true;
  }
};

/**
 * Keyboard handling is a mess. http://unixpapa.com/js/key.html
 * It would be good to use DOM L3 Keyboard events,
 * http://www.w3.org/TR/2010/WD-DOM-Level-3-Events-20100907/#events-keyboardevents
 * however only Webkit supports them, and there isn't a shim on Monernizr:
 * https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills
 * and when the code that uses this KeyEvent was written, nothing was clear,
 * so instead, we're using this unmodern shim:
 * http://stackoverflow.com/questions/5681146/chrome-10-keyevent-or-something-similar-to-firefoxs-keyevent
 * See BUG 664991: GCLI's keyboard handling should be updated to use DOM-L3
 * https://bugzilla.mozilla.org/show_bug.cgi?id=664991
 */
if ('KeyEvent' in this) {
  event.KeyEvent = this.KeyEvent;
}
else {
  event.KeyEvent = {
    DOM_VK_CANCEL: 3,
    DOM_VK_HELP: 6,
    DOM_VK_BACK_SPACE: 8,
    DOM_VK_TAB: 9,
    DOM_VK_CLEAR: 12,
    DOM_VK_RETURN: 13,
    DOM_VK_ENTER: 14,
    DOM_VK_SHIFT: 16,
    DOM_VK_CONTROL: 17,
    DOM_VK_ALT: 18,
    DOM_VK_PAUSE: 19,
    DOM_VK_CAPS_LOCK: 20,
    DOM_VK_ESCAPE: 27,
    DOM_VK_SPACE: 32,
    DOM_VK_PAGE_UP: 33,
    DOM_VK_PAGE_DOWN: 34,
    DOM_VK_END: 35,
    DOM_VK_HOME: 36,
    DOM_VK_LEFT: 37,
    DOM_VK_UP: 38,
    DOM_VK_RIGHT: 39,
    DOM_VK_DOWN: 40,
    DOM_VK_PRINTSCREEN: 44,
    DOM_VK_INSERT: 45,
    DOM_VK_DELETE: 46,
    DOM_VK_0: 48,
    DOM_VK_1: 49,
    DOM_VK_2: 50,
    DOM_VK_3: 51,
    DOM_VK_4: 52,
    DOM_VK_5: 53,
    DOM_VK_6: 54,
    DOM_VK_7: 55,
    DOM_VK_8: 56,
    DOM_VK_9: 57,
    DOM_VK_SEMICOLON: 59,
    DOM_VK_EQUALS: 61,
    DOM_VK_A: 65,
    DOM_VK_B: 66,
    DOM_VK_C: 67,
    DOM_VK_D: 68,
    DOM_VK_E: 69,
    DOM_VK_F: 70,
    DOM_VK_G: 71,
    DOM_VK_H: 72,
    DOM_VK_I: 73,
    DOM_VK_J: 74,
    DOM_VK_K: 75,
    DOM_VK_L: 76,
    DOM_VK_M: 77,
    DOM_VK_N: 78,
    DOM_VK_O: 79,
    DOM_VK_P: 80,
    DOM_VK_Q: 81,
    DOM_VK_R: 82,
    DOM_VK_S: 83,
    DOM_VK_T: 84,
    DOM_VK_U: 85,
    DOM_VK_V: 86,
    DOM_VK_W: 87,
    DOM_VK_X: 88,
    DOM_VK_Y: 89,
    DOM_VK_Z: 90,
    DOM_VK_CONTEXT_MENU: 93,
    DOM_VK_NUMPAD0: 96,
    DOM_VK_NUMPAD1: 97,
    DOM_VK_NUMPAD2: 98,
    DOM_VK_NUMPAD3: 99,
    DOM_VK_NUMPAD4: 100,
    DOM_VK_NUMPAD5: 101,
    DOM_VK_NUMPAD6: 102,
    DOM_VK_NUMPAD7: 103,
    DOM_VK_NUMPAD8: 104,
    DOM_VK_NUMPAD9: 105,
    DOM_VK_MULTIPLY: 106,
    DOM_VK_ADD: 107,
    DOM_VK_SEPARATOR: 108,
    DOM_VK_SUBTRACT: 109,
    DOM_VK_DECIMAL: 110,
    DOM_VK_DIVIDE: 111,
    DOM_VK_F1: 112,
    DOM_VK_F2: 113,
    DOM_VK_F3: 114,
    DOM_VK_F4: 115,
    DOM_VK_F5: 116,
    DOM_VK_F6: 117,
    DOM_VK_F7: 118,
    DOM_VK_F8: 119,
    DOM_VK_F9: 120,
    DOM_VK_F10: 121,
    DOM_VK_F11: 122,
    DOM_VK_F12: 123,
    DOM_VK_F13: 124,
    DOM_VK_F14: 125,
    DOM_VK_F15: 126,
    DOM_VK_F16: 127,
    DOM_VK_F17: 128,
    DOM_VK_F18: 129,
    DOM_VK_F19: 130,
    DOM_VK_F20: 131,
    DOM_VK_F21: 132,
    DOM_VK_F22: 133,
    DOM_VK_F23: 134,
    DOM_VK_F24: 135,
    DOM_VK_NUM_LOCK: 144,
    DOM_VK_SCROLL_LOCK: 145,
    DOM_VK_COMMA: 188,
    DOM_VK_PERIOD: 190,
    DOM_VK_SLASH: 191,
    DOM_VK_BACK_QUOTE: 192,
    DOM_VK_OPEN_BRACKET: 219,
    DOM_VK_BACK_SLASH: 220,
    DOM_VK_CLOSE_BRACKET: 221,
    DOM_VK_QUOTE: 222,
    DOM_VK_META: 224
  };
}

exports.event = event;

});
<commit_msg>Bug 697039 (no ie7): Get rid of dom.toggleCssClass<commit_after>/*
 * Copyright 2009-2011 Mozilla Foundation and contributors
 * Licensed under the New BSD license. See LICENSE.txt or:
 * http://opensource.org/licenses/BSD-3-Clause
 */

define(function(require, exports, module) {

/*
 * This module is a Pilot-Lite. It exports a number of objects that replicate
 * parts of the Pilot project. It aims to be mostly API compatible, while
 * removing the submodule complexity and helping us make things work inside
 * Firefox.
 * The Pilot compatible exports are: console/dom/event
 *
 * In addition it contains a small event library similar to EventEmitter but
 * which makes it harder to mistake the event in use.
 */

//------------------------------------------------------------------------------

/**
 * Create an event.
 * For use as follows:
 *
 *   function Hat() {
 *     this.putOn = createEvent();
 *     ...
 *   }
 *   Hat.prototype.adorn = function(person) {
 *     this.putOn({ hat: hat, person: person });
 *     ...
 *   }
 *
 *   var hat = new Hat();
 *   hat.putOn.add(function(ev) {
 *     console.log('The hat ', ev.hat, ' has is worn by ', ev.person);
 *   }, scope);
 *
 * @param name Optional name to help with debugging
 */
exports.createEvent = function(name) {
  var handlers = [];

  /**
   * This is how the event is triggered.
   * @param ev The event object to be passed to the event listeners
   */
  var event = function(ev) {
    // Use for rather than forEach because it step debugs better, which is
    // important for debugging events
    for (var i = 0; i < handlers.length; i++) {
      var handler = handlers[i];
      handler.func.call(handler.scope, ev);
    }
  };

  /**
   * Add a new handler function
   * @param func The function to call when this event is triggered
   * @param scope Optional 'this' object for the function call
   */
  event.add = function(func, scope) {
    handlers.push({ func: func, scope: scope });
  };

  /**
   * Remove a handler function added through add(). Both func and scope must
   * be strict equals (===) the values used in the call to add()
   * @param func The function to call when this event is triggered
   * @param scope Optional 'this' object for the function call
   */
  event.remove = function(func, scope) {
    handlers = handlers.filter(function(test) {
      return test.func !== func && test.scope !== scope;
    });
  };

  /**
   * Remove all handlers.
   * Reset the state of this event back to it's post create state
   */
  event.removeAll = function() {
    handlers = [];
  };

  return event;
};

//------------------------------------------------------------------------------

var dom = {};

var NS_XHTML = 'http://www.w3.org/1999/xhtml';

/**
 * Pass-through to createElement or createElementNS
 * @param doc The document in which to create the element
 * @param tag The name of the tag to create
 * @param ns Custom namespace, HTML/XHTML is assumed if this is missing
 * @returns The created element
 */
dom.createElement = function(doc, tag, ns) {
  // If we've not been given a namespace, but the document is XML, then we
  // use an XHTML namespace, otherwise we use HTML
  if (ns == null && doc.xmlVersion != null) {
    ns = NS_XHTML;
  }
  if (ns == null) {
    return doc.createElement(tag);
  }
  else {
    return doc.createElementNS(ns, tag);
  }
};

/**
 * Remove all the child nodes from this node
 * @param elem The element that should have it's children removed
 */
dom.clearElement = function(elem) {
  while (elem.hasChildNodes()) {
    elem.removeChild(elem.firstChild);
  }
};

/**
 * Add or remove a CSS class from the list of classes on the given node
 * depending on the value of <tt>include</tt>
 */
dom.setCssClass = function(node, className, include) {
  if (include) {
    node.classList.add(className);
  }
  else {
    node.classList.remove(className);
  }
};

/**
 * Create a style element in the document head, and add the given CSS text to
 * it.
 * @param cssText The CSS declarations to append
 * @param doc The document element to work from
 */
dom.importCss = function(cssText, doc) {
  doc = doc || document;

  var style = dom.createElement(doc, 'style');
  style.appendChild(doc.createTextNode(cssText));

  var head = doc.getElementsByTagName('head')[0] || doc.documentElement;
  head.appendChild(style);

  return style;
};

/**
 * Shim for window.getComputedStyle
 */
dom.computedStyle = function(element, style) {
  var win = element.ownerDocument.defaultView;
  if (win.getComputedStyle) {
    var styles = win.getComputedStyle(element, '') || {};
    return styles[style] || '';
  }
  else {
    return element.currentStyle[style];
  }
};

/**
 * Using setInnerHtml(foo) rather than innerHTML = foo allows us to enable
 * tweaks in XHTML documents.
 */
dom.setInnerHtml = function(elem, html) {
  if (!this.document || elem.namespaceURI === NS_XHTML) {
    try {
      dom.clearElement(elem);
      var range = elem.ownerDocument.createRange();
      html = '
' + html + '
';
      elem.appendChild(range.createContextualFragment(html));
    }
    catch (ex) {
      elem.innerHTML = html;
    }
  }
  else {
    elem.innerHTML = html;
  }
};

/**
 * Shim to textarea.selectionStart
 */
dom.getSelectionStart = function(textarea) {
  try {
    return textarea.selectionStart || 0;
  }
  catch (ex) {
    return 0;
  }
};

/**
 * Shim to textarea.selectionStart
 */
dom.setSelectionStart = function(textarea, start) {
  return textarea.selectionStart = start;
};

/**
 * Shim to textarea.selectionEnd
 */
dom.getSelectionEnd = function(textarea) {
  try {
    return textarea.selectionEnd || 0;
  }
  catch (ex) {
    return 0;
  }
};

/**
 * Shim to textarea.selectionEnd
 */
dom.setSelectionEnd = function(textarea, end) {
  return textarea.selectionEnd = end;
};

exports.dom = dom;

//------------------------------------------------------------------------------

/**
 * Various event utilities
 */
var event = {};

/**
 * Shim for lack of addEventListener on old IE.
 */
event.addListener = function(elem, type, callback) {
  if (elem.addEventListener) {
    return elem.addEventListener(type, callback, false);
  }
  if (elem.attachEvent) {
    var wrapper = function() {
      callback(window.event);
    };
    callback._wrapper = wrapper;
    elem.attachEvent('on' + type, wrapper);
  }
};

/**
 * Shim for lack of removeEventListener on old IE.
 */
event.removeListener = function(elem, type, callback) {
  if (elem.removeEventListener) {
    return elem.removeEventListener(type, callback, false);
  }
  if (elem.detachEvent) {
    elem.detachEvent('on' + type, callback._wrapper || callback);
  }
};

/**
 * Prevents propagation and clobbers the default action of the passed event
 */
event.stopEvent = function(e) {
  event.stopPropagation(e);
  if (e.preventDefault) {
    e.preventDefault();
  }
  return false;
};

/**
 * Prevents propagation of the event
 */
event.stopPropagation = function(ev) {
  if (ev.stopPropagation) {
    ev.stopPropagation();
  }
  else {
    ev.cancelBubble = true;
  }
};

/**
 * Keyboard handling is a mess. http://unixpapa.com/js/key.html
 * It would be good to use DOM L3 Keyboard events,
 * http://www.w3.org/TR/2010/WD-DOM-Level-3-Events-20100907/#events-keyboardevents
 * however only Webkit supports them, and there isn't a shim on Monernizr:
 * https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills
 * and when the code that uses this KeyEvent was written, nothing was clear,
 * so instead, we're using this unmodern shim:
 * http://stackoverflow.com/questions/5681146/chrome-10-keyevent-or-something-similar-to-firefoxs-keyevent
 * See BUG 664991: GCLI's keyboard handling should be updated to use DOM-L3
 * https://bugzilla.mozilla.org/show_bug.cgi?id=664991
 */
if ('KeyEvent' in this) {
  event.KeyEvent = this.KeyEvent;
}
else {
  event.KeyEvent = {
    DOM_VK_CANCEL: 3,
    DOM_VK_HELP: 6,
    DOM_VK_BACK_SPACE: 8,
    DOM_VK_TAB: 9,
    DOM_VK_CLEAR: 12,
    DOM_VK_RETURN: 13,
    DOM_VK_ENTER: 14,
    DOM_VK_SHIFT: 16,
    DOM_VK_CONTROL: 17,
    DOM_VK_ALT: 18,
    DOM_VK_PAUSE: 19,
    DOM_VK_CAPS_LOCK: 20,
    DOM_VK_ESCAPE: 27,
    DOM_VK_SPACE: 32,
    DOM_VK_PAGE_UP: 33,
    DOM_VK_PAGE_DOWN: 34,
    DOM_VK_END: 35,
    DOM_VK_HOME: 36,
    DOM_VK_LEFT: 37,
    DOM_VK_UP: 38,
    DOM_VK_RIGHT: 39,
    DOM_VK_DOWN: 40,
    DOM_VK_PRINTSCREEN: 44,
    DOM_VK_INSERT: 45,
    DOM_VK_DELETE: 46,
    DOM_VK_0: 48,
    DOM_VK_1: 49,
    DOM_VK_2: 50,
    DOM_VK_3: 51,
    DOM_VK_4: 52,
    DOM_VK_5: 53,
    DOM_VK_6: 54,
    DOM_VK_7: 55,
    DOM_VK_8: 56,
    DOM_VK_9: 57,
    DOM_VK_SEMICOLON: 59,
    DOM_VK_EQUALS: 61,
    DOM_VK_A: 65,
    DOM_VK_B: 66,
    DOM_VK_C: 67,
    DOM_VK_D: 68,
    DOM_VK_E: 69,
    DOM_VK_F: 70,
    DOM_VK_G: 71,
    DOM_VK_H: 72,
    DOM_VK_I: 73,
    DOM_VK_J: 74,
    DOM_VK_K: 75,
    DOM_VK_L: 76,
    DOM_VK_M: 77,
    DOM_VK_N: 78,
    DOM_VK_O: 79,
    DOM_VK_P: 80,
    DOM_VK_Q: 81,
    DOM_VK_R: 82,
    DOM_VK_S: 83,
    DOM_VK_T: 84,
    DOM_VK_U: 85,
    DOM_VK_V: 86,
    DOM_VK_W: 87,
    DOM_VK_X: 88,
    DOM_VK_Y: 89,
    DOM_VK_Z: 90,
    DOM_VK_CONTEXT_MENU: 93,
    DOM_VK_NUMPAD0: 96,
    DOM_VK_NUMPAD1: 97,
    DOM_VK_NUMPAD2: 98,
    DOM_VK_NUMPAD3: 99,
    DOM_VK_NUMPAD4: 100,
    DOM_VK_NUMPAD5: 101,
    DOM_VK_NUMPAD6: 102,
    DOM_VK_NUMPAD7: 103,
    DOM_VK_NUMPAD8: 104,
    DOM_VK_NUMPAD9: 105,
    DOM_VK_MULTIPLY: 106,
    DOM_VK_ADD: 107,
    DOM_VK_SEPARATOR: 108,
    DOM_VK_SUBTRACT: 109,
    DOM_VK_DECIMAL: 110,
    DOM_VK_DIVIDE: 111,
    DOM_VK_F1: 112,
    DOM_VK_F2: 113,
    DOM_VK_F3: 114,
    DOM_VK_F4: 115,
    DOM_VK_F5: 116,
    DOM_VK_F6: 117,
    DOM_VK_F7: 118,
    DOM_VK_F8: 119,
    DOM_VK_F9: 120,
    DOM_VK_F10: 121,
    DOM_VK_F11: 122,
    DOM_VK_F12: 123,
    DOM_VK_F13: 124,
    DOM_VK_F14: 125,
    DOM_VK_F15: 126,
    DOM_VK_F16: 127,
    DOM_VK_F17: 128,
    DOM_VK_F18: 129,
    DOM_VK_F19: 130,
    DOM_VK_F20: 131,
    DOM_VK_F21: 132,
    DOM_VK_F22: 133,
    DOM_VK_F23: 134,
    DOM_VK_F24: 135,
    DOM_VK_NUM_LOCK: 144,
    DOM_VK_SCROLL_LOCK: 145,
    DOM_VK_COMMA: 188,
    DOM_VK_PERIOD: 190,
    DOM_VK_SLASH: 191,
    DOM_VK_BACK_QUOTE: 192,
    DOM_VK_OPEN_BRACKET: 219,
    DOM_VK_BACK_SLASH: 220,
    DOM_VK_CLOSE_BRACKET: 221,
    DOM_VK_QUOTE: 222,
    DOM_VK_META: 224
  };
}

exports.event = event;

});
<|endoftext|>


<commit_before>/*
 * Copyright 2009-2011 Mozilla Foundation and contributors
 * Licensed under the New BSD license. See LICENSE.txt or:
 * http://opensource.org/licenses/BSD-3-Clause
 */

define(function(require, exports, module) {

/*
 * A number of DOM manipulation and event handling utilities.
 */

//------------------------------------------------------------------------------

/**
 * Create an event.
 * For use as follows:
 *
 *   function Hat() {
 *     this.putOn = createEvent();
 *     ...
 *   }
 *   Hat.prototype.adorn = function(person) {
 *     this.putOn({ hat: hat, person: person });
 *     ...
 *   }
 *
 *   var hat = new Hat();
 *   hat.putOn.add(function(ev) {
 *     console.log('The hat ', ev.hat, ' has is worn by ', ev.person);
 *   }, scope);
 *
 * @param name Optional name to help with debugging
 */
exports.createEvent = function(name) {
  var handlers = [];

  /**
   * This is how the event is triggered.
   * @param ev The event object to be passed to the event listeners
   */
  var event = function(ev) {
    // Use for rather than forEach because it step debugs better, which is
    // important for debugging events
    for (var i = 0; i < handlers.length; i++) {
      var handler = handlers[i];
      handler.func.call(handler.scope, ev);
    }
  };

  /**
   * Add a new handler function
   * @param func The function to call when this event is triggered
   * @param scope Optional 'this' object for the function call
   */
  event.add = function(func, scope) {
    handlers.push({ func: func, scope: scope });
  };

  /**
   * Remove a handler function added through add(). Both func and scope must
   * be strict equals (===) the values used in the call to add()
   * @param func The function to call when this event is triggered
   * @param scope Optional 'this' object for the function call
   */
  event.remove = function(func, scope) {
    handlers = handlers.filter(function(test) {
      return test.func !== func && test.scope !== scope;
    });
  };

  /**
   * Remove all handlers.
   * Reset the state of this event back to it's post create state
   */
  event.removeAll = function() {
    handlers = [];
  };

  return event;
};

//------------------------------------------------------------------------------

var dom = {};

dom.NS_XHTML = 'http://www.w3.org/1999/xhtml';

/**
 * Pass-through to createElement or createElementNS
 * @param doc The document in which to create the element
 * @param tag The name of the tag to create
 * @param ns Custom namespace, HTML/XHTML is assumed if this is missing
 * @returns The created element
 */
dom.createElement = function(doc, tag, ns) {
  // If we've not been given a namespace, but the document is XML, then we
  // use an XHTML namespace, otherwise we use HTML
  if (ns == null && doc.xmlVersion != null) {
    ns = dom.NS_XHTML;
  }
  if (ns == null) {
    return doc.createElement(tag);
  }
  else {
    return doc.createElementNS(ns, tag);
  }
};

/**
 * Remove all the child nodes from this node
 * @param elem The element that should have it's children removed
 */
dom.clearElement = function(elem) {
  while (elem.hasChildNodes()) {
    elem.removeChild(elem.firstChild);
  }
};

/**
 * Create a style element in the document head, and add the given CSS text to
 * it.
 * @param cssText The CSS declarations to append
 * @param doc The document element to work from
 */
dom.importCss = function(cssText, doc) {
  doc = doc || document;

  var style = dom.createElement(doc, 'style');
  style.appendChild(doc.createTextNode(cssText));

  var head = doc.getElementsByTagName('head')[0] || doc.documentElement;
  head.appendChild(style);

  return style;
};

/**
 * Using setInnerHtml(foo) rather than innerHTML = foo allows us to enable
 * tweaks in XHTML documents.
 */
dom.setInnerHtml = function(elem, html) {
  if (elem.ownerDocument.contentType !== 'text/html') {
    try {
      dom.clearElement(elem);
      html = '
' + html + '
';
      var range = elem.ownerDocument.createRange();
      var child = range.createContextualFragment(html).childNodes[0];
      while (child.hasChildNodes()) {
        elem.appendChild(child.firstChild);
      }
    }
    catch (ex) {
      elem.innerHTML = html;
    }
  }
  else {
    elem.innerHTML = html;
  }
};

/**
 * How to detect if we're in an XUL document (and therefore should create
 * elements in an XHTML namespace)
 * In a Mozilla XUL document, document.xmlVersion = null, however in Chrome
 * document.contentType = undefined.
 * @param doc The document element to work from (defaulted to the global
 * 'document' if missing
 */
dom.isXmlDocument = function(doc) {
  doc = doc || document;
  // Best test for Firefox
  if (doc.contentType && doc.contentType != 'text/html') {
    return true;
  }
  // Best test for Chrome
  if (doc.xmlVersion != null) {
    return true;
  }
  return false;
};

exports.dom = dom;

//------------------------------------------------------------------------------

/**
 * Various event utilities
 */
var event = {};

/**
 * Keyboard handling is a mess. http://unixpapa.com/js/key.html
 * It would be good to use DOM L3 Keyboard events,
 * http://www.w3.org/TR/2010/WD-DOM-Level-3-Events-20100907/#events-keyboardevents
 * however only Webkit supports them, and there isn't a shim on Monernizr:
 * https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills
 * and when the code that uses this KeyEvent was written, nothing was clear,
 * so instead, we're using this unmodern shim:
 * http://stackoverflow.com/questions/5681146/chrome-10-keyevent-or-something-similar-to-firefoxs-keyevent
 * See BUG 664991: GCLI's keyboard handling should be updated to use DOM-L3
 * https://bugzilla.mozilla.org/show_bug.cgi?id=664991
 */
if ('KeyEvent' in this) {
  event.KeyEvent = this.KeyEvent;
}
else {
  event.KeyEvent = {
    DOM_VK_CANCEL: 3,
    DOM_VK_HELP: 6,
    DOM_VK_BACK_SPACE: 8,
    DOM_VK_TAB: 9,
    DOM_VK_CLEAR: 12,
    DOM_VK_RETURN: 13,
    DOM_VK_ENTER: 14,
    DOM_VK_SHIFT: 16,
    DOM_VK_CONTROL: 17,
    DOM_VK_ALT: 18,
    DOM_VK_PAUSE: 19,
    DOM_VK_CAPS_LOCK: 20,
    DOM_VK_ESCAPE: 27,
    DOM_VK_SPACE: 32,
    DOM_VK_PAGE_UP: 33,
    DOM_VK_PAGE_DOWN: 34,
    DOM_VK_END: 35,
    DOM_VK_HOME: 36,
    DOM_VK_LEFT: 37,
    DOM_VK_UP: 38,
    DOM_VK_RIGHT: 39,
    DOM_VK_DOWN: 40,
    DOM_VK_PRINTSCREEN: 44,
    DOM_VK_INSERT: 45,
    DOM_VK_DELETE: 46,
    DOM_VK_0: 48,
    DOM_VK_1: 49,
    DOM_VK_2: 50,
    DOM_VK_3: 51,
    DOM_VK_4: 52,
    DOM_VK_5: 53,
    DOM_VK_6: 54,
    DOM_VK_7: 55,
    DOM_VK_8: 56,
    DOM_VK_9: 57,
    DOM_VK_SEMICOLON: 59,
    DOM_VK_EQUALS: 61,
    DOM_VK_A: 65,
    DOM_VK_B: 66,
    DOM_VK_C: 67,
    DOM_VK_D: 68,
    DOM_VK_E: 69,
    DOM_VK_F: 70,
    DOM_VK_G: 71,
    DOM_VK_H: 72,
    DOM_VK_I: 73,
    DOM_VK_J: 74,
    DOM_VK_K: 75,
    DOM_VK_L: 76,
    DOM_VK_M: 77,
    DOM_VK_N: 78,
    DOM_VK_O: 79,
    DOM_VK_P: 80,
    DOM_VK_Q: 81,
    DOM_VK_R: 82,
    DOM_VK_S: 83,
    DOM_VK_T: 84,
    DOM_VK_U: 85,
    DOM_VK_V: 86,
    DOM_VK_W: 87,
    DOM_VK_X: 88,
    DOM_VK_Y: 89,
    DOM_VK_Z: 90,
    DOM_VK_CONTEXT_MENU: 93,
    DOM_VK_NUMPAD0: 96,
    DOM_VK_NUMPAD1: 97,
    DOM_VK_NUMPAD2: 98,
    DOM_VK_NUMPAD3: 99,
    DOM_VK_NUMPAD4: 100,
    DOM_VK_NUMPAD5: 101,
    DOM_VK_NUMPAD6: 102,
    DOM_VK_NUMPAD7: 103,
    DOM_VK_NUMPAD8: 104,
    DOM_VK_NUMPAD9: 105,
    DOM_VK_MULTIPLY: 106,
    DOM_VK_ADD: 107,
    DOM_VK_SEPARATOR: 108,
    DOM_VK_SUBTRACT: 109,
    DOM_VK_DECIMAL: 110,
    DOM_VK_DIVIDE: 111,
    DOM_VK_F1: 112,
    DOM_VK_F2: 113,
    DOM_VK_F3: 114,
    DOM_VK_F4: 115,
    DOM_VK_F5: 116,
    DOM_VK_F6: 117,
    DOM_VK_F7: 118,
    DOM_VK_F8: 119,
    DOM_VK_F9: 120,
    DOM_VK_F10: 121,
    DOM_VK_F11: 122,
    DOM_VK_F12: 123,
    DOM_VK_F13: 124,
    DOM_VK_F14: 125,
    DOM_VK_F15: 126,
    DOM_VK_F16: 127,
    DOM_VK_F17: 128,
    DOM_VK_F18: 129,
    DOM_VK_F19: 130,
    DOM_VK_F20: 131,
    DOM_VK_F21: 132,
    DOM_VK_F22: 133,
    DOM_VK_F23: 134,
    DOM_VK_F24: 135,
    DOM_VK_NUM_LOCK: 144,
    DOM_VK_SCROLL_LOCK: 145,
    DOM_VK_COMMA: 188,
    DOM_VK_PERIOD: 190,
    DOM_VK_SLASH: 191,
    DOM_VK_BACK_QUOTE: 192,
    DOM_VK_OPEN_BRACKET: 219,
    DOM_VK_BACK_SLASH: 220,
    DOM_VK_CLOSE_BRACKET: 221,
    DOM_VK_QUOTE: 222,
    DOM_VK_META: 224
  };
}

exports.event = event;

});
<commit_msg>Bug 697140 (namespace): Convert createElement() to use isXmlDocument()<commit_after>/*
 * Copyright 2009-2011 Mozilla Foundation and contributors
 * Licensed under the New BSD license. See LICENSE.txt or:
 * http://opensource.org/licenses/BSD-3-Clause
 */

define(function(require, exports, module) {

/*
 * A number of DOM manipulation and event handling utilities.
 */

//------------------------------------------------------------------------------

/**
 * Create an event.
 * For use as follows:
 *
 *   function Hat() {
 *     this.putOn = createEvent();
 *     ...
 *   }
 *   Hat.prototype.adorn = function(person) {
 *     this.putOn({ hat: hat, person: person });
 *     ...
 *   }
 *
 *   var hat = new Hat();
 *   hat.putOn.add(function(ev) {
 *     console.log('The hat ', ev.hat, ' has is worn by ', ev.person);
 *   }, scope);
 *
 * @param name Optional name to help with debugging
 */
exports.createEvent = function(name) {
  var handlers = [];

  /**
   * This is how the event is triggered.
   * @param ev The event object to be passed to the event listeners
   */
  var event = function(ev) {
    // Use for rather than forEach because it step debugs better, which is
    // important for debugging events
    for (var i = 0; i < handlers.length; i++) {
      var handler = handlers[i];
      handler.func.call(handler.scope, ev);
    }
  };

  /**
   * Add a new handler function
   * @param func The function to call when this event is triggered
   * @param scope Optional 'this' object for the function call
   */
  event.add = function(func, scope) {
    handlers.push({ func: func, scope: scope });
  };

  /**
   * Remove a handler function added through add(). Both func and scope must
   * be strict equals (===) the values used in the call to add()
   * @param func The function to call when this event is triggered
   * @param scope Optional 'this' object for the function call
   */
  event.remove = function(func, scope) {
    handlers = handlers.filter(function(test) {
      return test.func !== func && test.scope !== scope;
    });
  };

  /**
   * Remove all handlers.
   * Reset the state of this event back to it's post create state
   */
  event.removeAll = function() {
    handlers = [];
  };

  return event;
};

//------------------------------------------------------------------------------

var dom = {};

dom.NS_XHTML = 'http://www.w3.org/1999/xhtml';

/**
 * Create an HTML or XHTML element depending on whether the document is HTML
 * or XML based. Where HTML/XHTML elements are distinguished by whether they
 * are created using doc.createElementNS('http://www.w3.org/1999/xhtml', tag)
 * or doc.createElement(tag)
 * If you want to create a XUL element then you don't have a problem knowing
 * what namespace you want.
 * @param doc The document in which to create the element
 * @param tag The name of the tag to create
 * @param ns Custom namespace, HTML/XHTML is assumed if this is missing
 * @returns The created element
 */
dom.createElement = function(doc, tag, ns) {
  if (dom.isXmlDocument(doc)) {
    return doc.createElementNS(dom.NS_XHTML, tag);
  }
  else {
    return doc.createElement(tag);
  }
};

/**
 * Remove all the child nodes from this node
 * @param elem The element that should have it's children removed
 */
dom.clearElement = function(elem) {
  while (elem.hasChildNodes()) {
    elem.removeChild(elem.firstChild);
  }
};

/**
 * Create a style element in the document head, and add the given CSS text to
 * it.
 * @param cssText The CSS declarations to append
 * @param doc The document element to work from
 */
dom.importCss = function(cssText, doc) {
  doc = doc || document;

  var style = dom.createElement(doc, 'style');
  style.appendChild(doc.createTextNode(cssText));

  var head = doc.getElementsByTagName('head')[0] || doc.documentElement;
  head.appendChild(style);

  return style;
};

/**
 * Using setInnerHtml(foo) rather than innerHTML = foo allows us to enable
 * tweaks in XHTML documents.
 */
dom.setInnerHtml = function(elem, html) {
  if (elem.ownerDocument.contentType !== 'text/html') {
    try {
      dom.clearElement(elem);
      html = '
' + html + '
';
      var range = elem.ownerDocument.createRange();
      var child = range.createContextualFragment(html).childNodes[0];
      while (child.hasChildNodes()) {
        elem.appendChild(child.firstChild);
      }
    }
    catch (ex) {
      elem.innerHTML = html;
    }
  }
  else {
    elem.innerHTML = html;
  }
};

/**
 * How to detect if we're in an XUL document (and therefore should create
 * elements in an XHTML namespace)
 * In a Mozilla XUL document, document.xmlVersion = null, however in Chrome
 * document.contentType = undefined.
 * @param doc The document element to work from (defaulted to the global
 * 'document' if missing
 */
dom.isXmlDocument = function(doc) {
  doc = doc || document;
  // Best test for Firefox
  if (doc.contentType && doc.contentType != 'text/html') {
    return true;
  }
  // Best test for Chrome
  if (doc.xmlVersion != null) {
    return true;
  }
  return false;
};

exports.dom = dom;

//------------------------------------------------------------------------------

/**
 * Various event utilities
 */
var event = {};

/**
 * Keyboard handling is a mess. http://unixpapa.com/js/key.html
 * It would be good to use DOM L3 Keyboard events,
 * http://www.w3.org/TR/2010/WD-DOM-Level-3-Events-20100907/#events-keyboardevents
 * however only Webkit supports them, and there isn't a shim on Monernizr:
 * https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills
 * and when the code that uses this KeyEvent was written, nothing was clear,
 * so instead, we're using this unmodern shim:
 * http://stackoverflow.com/questions/5681146/chrome-10-keyevent-or-something-similar-to-firefoxs-keyevent
 * See BUG 664991: GCLI's keyboard handling should be updated to use DOM-L3
 * https://bugzilla.mozilla.org/show_bug.cgi?id=664991
 */
if ('KeyEvent' in this) {
  event.KeyEvent = this.KeyEvent;
}
else {
  event.KeyEvent = {
    DOM_VK_CANCEL: 3,
    DOM_VK_HELP: 6,
    DOM_VK_BACK_SPACE: 8,
    DOM_VK_TAB: 9,
    DOM_VK_CLEAR: 12,
    DOM_VK_RETURN: 13,
    DOM_VK_ENTER: 14,
    DOM_VK_SHIFT: 16,
    DOM_VK_CONTROL: 17,
    DOM_VK_ALT: 18,
    DOM_VK_PAUSE: 19,
    DOM_VK_CAPS_LOCK: 20,
    DOM_VK_ESCAPE: 27,
    DOM_VK_SPACE: 32,
    DOM_VK_PAGE_UP: 33,
    DOM_VK_PAGE_DOWN: 34,
    DOM_VK_END: 35,
    DOM_VK_HOME: 36,
    DOM_VK_LEFT: 37,
    DOM_VK_UP: 38,
    DOM_VK_RIGHT: 39,
    DOM_VK_DOWN: 40,
    DOM_VK_PRINTSCREEN: 44,
    DOM_VK_INSERT: 45,
    DOM_VK_DELETE: 46,
    DOM_VK_0: 48,
    DOM_VK_1: 49,
    DOM_VK_2: 50,
    DOM_VK_3: 51,
    DOM_VK_4: 52,
    DOM_VK_5: 53,
    DOM_VK_6: 54,
    DOM_VK_7: 55,
    DOM_VK_8: 56,
    DOM_VK_9: 57,
    DOM_VK_SEMICOLON: 59,
    DOM_VK_EQUALS: 61,
    DOM_VK_A: 65,
    DOM_VK_B: 66,
    DOM_VK_C: 67,
    DOM_VK_D: 68,
    DOM_VK_E: 69,
    DOM_VK_F: 70,
    DOM_VK_G: 71,
    DOM_VK_H: 72,
    DOM_VK_I: 73,
    DOM_VK_J: 74,
    DOM_VK_K: 75,
    DOM_VK_L: 76,
    DOM_VK_M: 77,
    DOM_VK_N: 78,
    DOM_VK_O: 79,
    DOM_VK_P: 80,
    DOM_VK_Q: 81,
    DOM_VK_R: 82,
    DOM_VK_S: 83,
    DOM_VK_T: 84,
    DOM_VK_U: 85,
    DOM_VK_V: 86,
    DOM_VK_W: 87,
    DOM_VK_X: 88,
    DOM_VK_Y: 89,
    DOM_VK_Z: 90,
    DOM_VK_CONTEXT_MENU: 93,
    DOM_VK_NUMPAD0: 96,
    DOM_VK_NUMPAD1: 97,
    DOM_VK_NUMPAD2: 98,
    DOM_VK_NUMPAD3: 99,
    DOM_VK_NUMPAD4: 100,
    DOM_VK_NUMPAD5: 101,
    DOM_VK_NUMPAD6: 102,
    DOM_VK_NUMPAD7: 103,
    DOM_VK_NUMPAD8: 104,
    DOM_VK_NUMPAD9: 105,
    DOM_VK_MULTIPLY: 106,
    DOM_VK_ADD: 107,
    DOM_VK_SEPARATOR: 108,
    DOM_VK_SUBTRACT: 109,
    DOM_VK_DECIMAL: 110,
    DOM_VK_DIVIDE: 111,
    DOM_VK_F1: 112,
    DOM_VK_F2: 113,
    DOM_VK_F3: 114,
    DOM_VK_F4: 115,
    DOM_VK_F5: 116,
    DOM_VK_F6: 117,
    DOM_VK_F7: 118,
    DOM_VK_F8: 119,
    DOM_VK_F9: 120,
    DOM_VK_F10: 121,
    DOM_VK_F11: 122,
    DOM_VK_F12: 123,
    DOM_VK_F13: 124,
    DOM_VK_F14: 125,
    DOM_VK_F15: 126,
    DOM_VK_F16: 127,
    DOM_VK_F17: 128,
    DOM_VK_F18: 129,
    DOM_VK_F19: 130,
    DOM_VK_F20: 131,
    DOM_VK_F21: 132,
    DOM_VK_F22: 133,
    DOM_VK_F23: 134,
    DOM_VK_F24: 135,
    DOM_VK_NUM_LOCK: 144,
    DOM_VK_SCROLL_LOCK: 145,
    DOM_VK_COMMA: 188,
    DOM_VK_PERIOD: 190,
    DOM_VK_SLASH: 191,
    DOM_VK_BACK_QUOTE: 192,
    DOM_VK_OPEN_BRACKET: 219,
    DOM_VK_BACK_SLASH: 220,
    DOM_VK_CLOSE_BRACKET: 221,
    DOM_VK_QUOTE: 222,
    DOM_VK_META: 224
  };
}

exports.event = event;

});
<|endoftext|>