<commit_before>export { Pointwise };

import * as Pool from "../../util/Pool.js";
import * as TwoTensors from "../../util/TwoTensors.js";
import * as ValueDesc from "../../Unpacker/ValueDesc.js";
import * as ReturnOrClone from "../ReturnOrClone.js";
import * as TensorPlaceholder from "../TensorPlaceholder.js";
import { FiltersArray_BiasesArray } from "../Pointwise/Pointwise_FiltersArray_BiasesArray.js";
import { Base } from "./Operation_Base.js";

/**
 * Handle pointwise convolution (1x1 conv2d), bias and activation.
 *
 *
 * @member {boolean} bExisted
 *   If true, this pointwise convolution exists. The same as this.bPointwise.
 *
 * @member {boolean} bPointwise
 *   If true, this pointwise convolution exists. The same as this.bExisted.
 *
 * @member {boolean} bInitOk
 *   If true, the init() is successful.
 *
 * @member {function} pfnConv
 *   This is a method. It has one parameter inputTensor and return a outputTensor. The inputTensor (tf.tensor3d) represents the image
 * ( height x width x channel ) which will be processed. The outputTensor (tf.tensor3d) represents the result.
 * All intermediate tensors will be disposed. The inputTensor may or may not be disposed. In fact, this method calls one of
 * return_input_directly(), keep_input_return_copy(), Conv_and_destroy(), Conv_and_keep() according to the parameters.
 *
 * @member {function} apply
 *   This is a method. It processes this.input0.realTensor as inputTensor and puts to this.output0.realTensor as outputTensor. The
 * inputTensor (tf.tensor3d) represents the image ( height x width x channel ) which will be processed. The outputTensor (tf.tensor3d)
 * represents the result. All intermediate tensors will be disposed. The inputTensor may or may not be disposed. In fact, this method
 * calls one of output0_return_input0_directly(), output0_return_input0_cloned(), Conv_and_destroy_or_keep(),
 * ConvBias_and_destroy_or_keep(), ConvActivation_and_destroy_or_keep(), ConvBiasActivation_and_destroy_or_keep()
 * according to the parameters.
 *
 * @see Operration.Base
 * @see Pointwise.FiltersArray_BiasesArray
 */
class Pointwise extends Base( FiltersArray_BiasesArray( TwoTensors.filtersTensor4d_biasesTensor3d( ReturnOrClone.Root ) ) ) {

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

  /**
   */
  constructor(
    inputTensorPlaceholder0,
    outputChannelCount, bBias, nActivationId, nPassThroughStyleId,
    nHigherHalfDifferent, outputChannelCount_lowerHalf,
    channelShuffler_inputGroupCount, channelShuffler_outputGroupCount ) {

    super(
      inputTensorPlaceholder0, null, 1,
      inputTensorPlaceholder0.channelCount, outputChannelCount, bBias, nActivationId, nPassThroughStyleId,
      nHigherHalfDifferent, inputTensorPlaceholder0.channelCount_lowerHalf, outputChannelCount_lowerHalf,
      channelShuffler_inputGroupCount, channelShuffler_outputGroupCount );

    Pointwise.setAsConstructor_self.call( this );
  }

  /** @override */
  static setAsConstructor(
    inputTensorPlaceholder0,
    outputChannelCount, bBias, nActivationId, nPassThroughStyleId,
    nHigherHalfDifferent, outputChannelCount_lowerHalf,
    channelShuffler_inputGroupCount, channelShuffler_outputGroupCount ) {

    super.setAsConstructor(
      inputTensorPlaceholder0, null, 1,
      inputTensorPlaceholder0.channelCount, outputChannelCount, bBias, nActivationId, nPassThroughStyleId,
      nHigherHalfDifferent, inputTensorPlaceholder0.channelCount_lowerHalf, outputChannelCount_lowerHalf,
      channelShuffler_inputGroupCount, channelShuffler_outputGroupCount );

    Pointwise.setAsConstructor_self.call( this );
    return this;
  }

  /** @override */
  static setAsConstructor_self() {
    // Do nothing.
  }

  /**
   * @param {number[]|Float32Array} inputWeightArray
   *   A number array whose values will be interpreted as weights.
   *
   * @param {Array} arrayTemp_forInterleave_asGrouptTwo
   *   A temporary array for placing the original elements temporarily. Providing this array could reduce memory re-allocation
   * and improve performance when doing Interleave_asGrouptTwo.
   *
   * @return {boolean} Return true, if succeeded.
   */
  init( inputWeightArray, weightElementOffsetBegin, arrayTemp_forInterleave_asGrouptTwo ) {

    // Q1: Why is the inputWeightArray not a parameter of constructor?
    // A1: The reason is to avoid keeping it as this.inputWeightArray so that it could be released by memory garbage collector.
    //
    // Q2: Why not keep filtersWeights and biasesWeights in data members of this?
    // A2: Their underlying ArrayBuffer is inputWeightArray.buffer. If this.filtersWeights and this.biasesWeights are kept,
    //     the inputWeightArray.buffer could not be released by memory garbage collector.

    // 1. Determine operation functions.
    Pointwise.setup_bPointwise_pfn.call( this );

    let bExtractOk;
    if ( !this.bPointwise ) {
      bExtractOk = true; // 2. no operation at all.

      this.weightElementOffsetBegin = this.weightElementOffsetEnd = weightElementOffsetBegin;
      this.weightElementExtractedCount = 0;

      // Bypass previous to next.
      //
      // Note: The .outputX and .inputX should always be different object (but can have the same content).
      //       Otherwise, the apply() will destroy the content of .inputX (especially when keep-input-tensor).
      this.output0.set_height_width_channelCount_scaleBoundsArray_byTensorPlaceholder( this.input0 );

    } else { // 3.

      bExtractOk = super.init( inputWeightArray, weightElementOffsetBegin, this.input0.scaleBoundsArray, arrayTemp_forInterleave_asGrouptTwo );
      if ( bExtractOk ) {
        try {

          if ( this.filtersShape && this.filtersArray ) {
            this.filtersTensor4d = tf.tensor( this.filtersArray, this.filtersShape );
            this.filtersArray.disposeResources_and_recycleToPool(); this.filtersArray = null; // Release for reducing memory usage.

            // Note: Because .filtersShape will be kept by .filtersTensor4d internally, it can not be released here.

//!!! (2022/07/05 Remarked) Because .filtersShape will be kept by .filtersTensor4d internally, it can not be released here.
//            this.filtersShape.disposeResources_and_recycleToPool(); this.filtersShape = null;
          }

          if ( this.biasesShape && this.biasesArray ) {
            this.biasesTensor3d = tf.tensor( this.biasesArray, this.biasesShape );
            this.biasesArray.disposeResources_and_recycleToPool(); this.biasesArray = null; // Release for reducing memory usage.

            // Note: Because .biasesShape will be kept by .biasesTensor3d internally, it can not be released here.

//!!! (2022/07/05 Remarked) Because .biasesShape will be kept by .biasesTensor3d internally, it can not be released here.
//            this.biasesShape.disposeResources_and_recycleToPool(); this.biasesShape = null;
          }

          this.output0.set_height_width_channelCount_scaleBoundsArray(
            this.input0.height, // (Pointwise convolution does not change height.)
            this.input0.width,  // (Pointwise convolution does not change width.)
            this.outputChannelCount,
            this.outputChannelCount_lowerHalf,
            this.outputChannelCount_higherHalf,
            this.boundsArraySet.output0
          );

          // Release for reducing memory usage. (Since it has been inside the output tensor placeholder.)
          {
            this.boundsArraySet.output0 = null; // Because it has already been transferred to TensorPlaceholder this.output0
            this.boundsArraySet.disposeResources_and_recycleToPool();
            this.boundsArraySet = null;
          }

        } catch ( e ) {  // If failed (e.g. memory not enough), return false.
          bExtractOk = false;
        }
      }

    }

    this.bInitOk = bExtractOk;
    return this.bInitOk;
  }

  /** @override */
  disposeResources() {
    this.pfnActivation = null;
    this.pfnConv = null;

    this.bPointwise = undefined;
    this.bKeepInputTensor = undefined;

    super.disposeResources(); // Release filtersTensor4d and biasesTensor3d.
  }

  /**
   * Adjust this.pfnConv (and this.apply if need) so that this.pfnConv() and this.apply() will or will not
   * dispose its inputTensor.
   */
  setKeepInputTensor( bKeepInputTensor ) {
    if ( bKeepInputTensor == this.bKeepInputTensor )
      return;

    this.bKeepInputTensor = bKeepInputTensor;

    if ( this.bExisted ) {
      if ( bKeepInputTensor ) {
        this.pfnConv = Pointwise.Conv_and_keep;
      } else {
        this.pfnConv = Pointwise.Conv_and_destroy;
      }
    } else {
      // Since there is no operation at all, let apply ignore pfnConv completely.
      if ( bKeepInputTensor ) {
        this.pfnConv = Pointwise.keep_input_return_copy;
        this.apply = Pointwise.output0_return_input0_cloned;
      } else {
        this.pfnConv = Pointwise.return_input_directly;
        this.apply = Pointwise.output0_return_input0_directly;
      }
    }
  }

  get bExisted() {
    return this.bPointwise;
  }

  /**
   * @override
   */
  get tensorWeightCountExtracted() {
    return this.weightElementExtractedCount;
  }

  /**
   * @override
   */
  get tensorWeightCountTotal() {
    return this.tensorWeightCountTotal_internal;
  }

  /** Determine this.bPointwise and this.pfnXxx data members.
   *
   * @param {Base} this
   *   The Base object to be determined and modified.
   */
  static setup_bPointwise_pfn() {
    this.bKeepInputTensor = false; // (Because this method will arrange function pointer as not-keep-input-tensor.)

    // 0. Determine whether pointwise operation should exist.
    if ( this.outputChannelCount > 0 ) {
      this.bPointwise = true;
    } else {  // ( outputChannelCount <= 0 )
      this.bPointwise = false;
    }

    // 1.
    this.pfnConv = Pointwise.Conv_and_destroy; // will dispose inputTensor.

    // 2.
    this.pfnActivation = Pointwise.ActivationFunction_getById( this.nActivationId );

    // 3.
    if ( this.bPointwise ) {
      if ( this.bBias ) {
        if ( this.pfnActivation )
          this.apply = Pointwise.ConvBiasActivation_and_destroy_or_keep;
        else
          this.apply = Pointwise.ConvBias_and_destroy_or_keep;
      } else {
        if ( this.pfnActivation )
          this.apply = Pointwise.ConvActivation_and_destroy_or_keep;
         else
          this.apply = Pointwise.Conv_and_destroy_or_keep;
      }
    } else {
      // Since there is no operation at all, let apply ignore pfnConv completely.
      this.pfnConv = Pointwise.return_input_directly;
      this.apply = Pointwise.output0_return_input0_directly;
    }
  }

  /** Pointwise Convolution (1x1). (The inputTensor will not be disposed so that it can be used for achieving skip connection.) */
  static Conv_and_keep( inputTensor ) {
    return tf.conv2d( inputTensor, this.filtersTensor4d, 1, "valid" ); // 1x1, Stride = 1
  }

  static Conv_and_destroy( inputTensor ) {
    let t = tf.conv2d( inputTensor, this.filtersTensor4d, 1, "valid" );
    inputTensor.dispose();
    return t;
  }

  /** Pointwise Convolution, Bias and Activation. */
  static Conv_and_destroy_or_keep() {
    this.output0.realTensor = this.pfnConv( this.input0.realTensor );
  }

  static ConvBias_and_destroy_or_keep() {
    let t0 = this.pfnConv( this.input0.realTensor );

    let t1 = tf.add( t0, this.biasesTensor3d );
    t0.dispose();

    this.output0.realTensor = t1;
  }

  static ConvActivation_and_destroy_or_keep() {
    let t0 = this.pfnConv( this.input0.realTensor );

    let t1 = this.pfnActivation( t0 );
    t0.dispose();

    this.output0.realTensor = t1;
  }

  static ConvBiasActivation_and_destroy_or_keep() {
    let t0 = this.pfnConv( this.input0.realTensor );

    let t1 = tf.add( t0, this.biasesTensor3d );
    t0.dispose();

    t0 = this.pfnActivation( t1 );
    t1.dispose();

    this.output0.realTensor = t0;
  }

}

<commit_msg>Update Operation_Pointwise.js<commit_after>export { Pointwise };

import * as Pool from "../../util/Pool.js";
import * as TwoTensors from "../../util/TwoTensors.js";
import * as ValueDesc from "../../Unpacker/ValueDesc.js";
import * as ReturnOrClone from "../ReturnOrClone.js";
import * as TensorPlaceholder from "../TensorPlaceholder.js";
import { FiltersArray_BiasesArray } from "../Pointwise/Pointwise_FiltersArray_BiasesArray.js";
import { Base } from "./Operation_Base.js";

/**
 * Handle pointwise convolution (1x1 conv2d), bias and activation.
 *
 *
 * @member {boolean} bExisted
 *   If true, this pointwise convolution exists. The same as this.bPointwise.
 *
 * @member {boolean} bPointwise
 *   If true, this pointwise convolution exists. The same as this.bExisted.
 *
 * @member {boolean} bInitOk
 *   If true, the init() is successful.
 *
 * @member {function} pfnConv
 *   This is a method. It has one parameter inputTensor and return a outputTensor. The inputTensor (tf.tensor3d) represents the image
 * ( height x width x channel ) which will be processed. The outputTensor (tf.tensor3d) represents the result.
 * All intermediate tensors will be disposed. The inputTensor may or may not be disposed. In fact, this method calls one of
 * return_input_directly(), keep_input_return_copy(), Conv_and_destroy(), Conv_and_keep() according to the parameters.
 *
 * @member {function} apply
 *   This is a method. It processes this.input0.realTensor as inputTensor and puts to this.output0.realTensor as outputTensor. The
 * inputTensor (tf.tensor3d) represents the image ( height x width x channel ) which will be processed. The outputTensor (tf.tensor3d)
 * represents the result. All intermediate tensors will be disposed. The inputTensor may or may not be disposed. In fact, this method
 * calls one of output0_return_input0_directly(), output0_return_input0_cloned(), Conv_and_destroy_or_keep(),
 * ConvBias_and_destroy_or_keep(), ConvActivation_and_destroy_or_keep(), ConvBiasActivation_and_destroy_or_keep()
 * according to the parameters.
 *
 * @see Operration.Base
 * @see Pointwise.FiltersArray_BiasesArray
 */
class Pointwise extends Base( FiltersArray_BiasesArray( TwoTensors.filtersTensor4d_biasesTensor3d( ReturnOrClone.Root ) ) ) {

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

  /**
   */
  constructor(
    inputTensorPlaceholder0,
    outputChannelCount, bBias, nActivationId, nPassThroughStyleId,
    nHigherHalfDifferent, outputChannelCount_lowerHalf,
    channelShuffler_inputGroupCount, channelShuffler_outputGroupCount ) {

    super(
      inputTensorPlaceholder0, null, 1,
      inputTensorPlaceholder0.channelCount, outputChannelCount, bBias, nActivationId, nPassThroughStyleId,
      nHigherHalfDifferent, inputTensorPlaceholder0.channelCount_lowerHalf, outputChannelCount_lowerHalf,
      channelShuffler_inputGroupCount, channelShuffler_outputGroupCount );

    Pointwise.setAsConstructor_self.call( this );
  }

  /** @override */
  static setAsConstructor(
    inputTensorPlaceholder0,
    outputChannelCount, bBias, nActivationId, nPassThroughStyleId,
    nHigherHalfDifferent, outputChannelCount_lowerHalf,
    channelShuffler_inputGroupCount, channelShuffler_outputGroupCount ) {

    super.setAsConstructor(
      inputTensorPlaceholder0, null, 1,
      inputTensorPlaceholder0.channelCount, outputChannelCount, bBias, nActivationId, nPassThroughStyleId,
      nHigherHalfDifferent, inputTensorPlaceholder0.channelCount_lowerHalf, outputChannelCount_lowerHalf,
      channelShuffler_inputGroupCount, channelShuffler_outputGroupCount );

    Pointwise.setAsConstructor_self.call( this );
    return this;
  }

  /** @override */
  static setAsConstructor_self() {
    // Do nothing.
  }

  /**
   * @param {number[]|Float32Array} inputWeightArray
   *   A number array whose values will be interpreted as weights.
   *
   * @return {boolean} Return true, if succeeded.
   */
  init( inputWeightArray, weightElementOffsetBegin ) {

    // Q1: Why is the inputWeightArray not a parameter of constructor?
    // A1: The reason is to avoid keeping it as this.inputWeightArray so that it could be released by memory garbage collector.
    //
    // Q2: Why not keep filtersWeights and biasesWeights in data members of this?
    // A2: Their underlying ArrayBuffer is inputWeightArray.buffer. If this.filtersWeights and this.biasesWeights are kept,
    //     the inputWeightArray.buffer could not be released by memory garbage collector.

    // 1. Determine operation functions.
    Pointwise.setup_bPointwise_pfn.call( this );

    let bExtractOk;
    if ( !this.bPointwise ) {
      bExtractOk = true; // 2. no operation at all.

      this.weightElementOffsetBegin = this.weightElementOffsetEnd = weightElementOffsetBegin;
      this.weightElementExtractedCount = 0;

      // Bypass previous to next.
      //
      // Note: The .outputX and .inputX should always be different object (but can have the same content).
      //       Otherwise, the apply() will destroy the content of .inputX (especially when keep-input-tensor).
      this.output0.set_height_width_channelCount_scaleBoundsArray_byTensorPlaceholder( this.input0 );

    } else { // 3.

      bExtractOk = super.init( inputWeightArray, weightElementOffsetBegin, this.input0.scaleBoundsArray );
      if ( bExtractOk ) {
        try {

          if ( this.filtersShape && this.filtersArray ) {
            this.filtersTensor4d = tf.tensor( this.filtersArray, this.filtersShape );
            this.filtersArray.disposeResources_and_recycleToPool(); this.filtersArray = null; // Release for reducing memory usage.

            // Note: Because .filtersShape will be kept by .filtersTensor4d internally, it can not be released here.
          }

          if ( this.biasesShape && this.biasesArray ) {
            this.biasesTensor3d = tf.tensor( this.biasesArray, this.biasesShape );
            this.biasesArray.disposeResources_and_recycleToPool(); this.biasesArray = null; // Release for reducing memory usage.

            // Note: Because .biasesShape will be kept by .biasesTensor3d internally, it can not be released here.
          }

          this.output0.set_height_width_channelCount_scaleBoundsArray(
            this.input0.height, // (Pointwise convolution does not change height.)
            this.input0.width,  // (Pointwise convolution does not change width.)
            this.outputChannelCount,
            this.outputChannelCount_lowerHalf,
            this.outputChannelCount_higherHalf,
            this.boundsArraySet.output0
          );

          // Release for reducing memory usage. (Since it has been inside the output tensor placeholder.)
          {
            this.boundsArraySet.output0 = null; // Because it has already been transferred to TensorPlaceholder this.output0
            this.boundsArraySet.disposeResources_and_recycleToPool();
            this.boundsArraySet = null;
          }

        } catch ( e ) {  // If failed (e.g. memory not enough), return false.
          bExtractOk = false;
        }
      }

    }

    this.bInitOk = bExtractOk;
    return this.bInitOk;
  }

  /** @override */
  disposeResources() {
    this.pfnActivation = null;
    this.pfnConv = null;

    this.bPointwise = undefined;
    this.bKeepInputTensor = undefined;

    super.disposeResources(); // Release filtersTensor4d and biasesTensor3d.
  }

  /**
   * Adjust this.pfnConv (and this.apply if need) so that this.pfnConv() and this.apply() will or will not
   * dispose its inputTensor.
   */
  setKeepInputTensor( bKeepInputTensor ) {
    if ( bKeepInputTensor == this.bKeepInputTensor )
      return;

    this.bKeepInputTensor = bKeepInputTensor;

    if ( this.bExisted ) {
      if ( bKeepInputTensor ) {
        this.pfnConv = Pointwise.Conv_and_keep;
      } else {
        this.pfnConv = Pointwise.Conv_and_destroy;
      }
    } else {
      // Since there is no operation at all, let apply ignore pfnConv completely.
      if ( bKeepInputTensor ) {
        this.pfnConv = Pointwise.keep_input_return_copy;
        this.apply = Pointwise.output0_return_input0_cloned;
      } else {
        this.pfnConv = Pointwise.return_input_directly;
        this.apply = Pointwise.output0_return_input0_directly;
      }
    }
  }

  get bExisted() {
    return this.bPointwise;
  }

  /**
   * @override
   */
  get tensorWeightCountExtracted() {
    return this.weightElementExtractedCount;
  }

  /**
   * @override
   */
  get tensorWeightCountTotal() {
    return this.tensorWeightCountTotal_internal;
  }

  /** Determine this.bPointwise and this.pfnXxx data members.
   *
   * @param {Base} this
   *   The Base object to be determined and modified.
   */
  static setup_bPointwise_pfn() {
    this.bKeepInputTensor = false; // (Because this method will arrange function pointer as not-keep-input-tensor.)

    // 0. Determine whether pointwise operation should exist.
    if ( this.outputChannelCount > 0 ) {
      this.bPointwise = true;
    } else {  // ( outputChannelCount <= 0 )
      this.bPointwise = false;
    }

    // 1.
    this.pfnConv = Pointwise.Conv_and_destroy; // will dispose inputTensor.

    // 2.
    this.pfnActivation = Pointwise.ActivationFunction_getById( this.nActivationId );

    // 3.
    if ( this.bPointwise ) {
      if ( this.bBias ) {
        if ( this.pfnActivation )
          this.apply = Pointwise.ConvBiasActivation_and_destroy_or_keep;
        else
          this.apply = Pointwise.ConvBias_and_destroy_or_keep;
      } else {
        if ( this.pfnActivation )
          this.apply = Pointwise.ConvActivation_and_destroy_or_keep;
         else
          this.apply = Pointwise.Conv_and_destroy_or_keep;
      }
    } else {
      // Since there is no operation at all, let apply ignore pfnConv completely.
      this.pfnConv = Pointwise.return_input_directly;
      this.apply = Pointwise.output0_return_input0_directly;
    }
  }

  /** Pointwise Convolution (1x1). (The inputTensor will not be disposed so that it can be used for achieving skip connection.) */
  static Conv_and_keep( inputTensor ) {
    return tf.conv2d( inputTensor, this.filtersTensor4d, 1, "valid" ); // 1x1, Stride = 1
  }

  static Conv_and_destroy( inputTensor ) {
    let t = tf.conv2d( inputTensor, this.filtersTensor4d, 1, "valid" );
    inputTensor.dispose();
    return t;
  }

  /** Pointwise Convolution, Bias and Activation. */
  static Conv_and_destroy_or_keep() {
    this.output0.realTensor = this.pfnConv( this.input0.realTensor );
  }

  static ConvBias_and_destroy_or_keep() {
    let t0 = this.pfnConv( this.input0.realTensor );

    let t1 = tf.add( t0, this.biasesTensor3d );
    t0.dispose();

    this.output0.realTensor = t1;
  }

  static ConvActivation_and_destroy_or_keep() {
    let t0 = this.pfnConv( this.input0.realTensor );

    let t1 = this.pfnActivation( t0 );
    t0.dispose();

    this.output0.realTensor = t1;
  }

  static ConvBiasActivation_and_destroy_or_keep() {
    let t0 = this.pfnConv( this.input0.realTensor );

    let t1 = tf.add( t0, this.biasesTensor3d );
    t0.dispose();

    t0 = this.pfnActivation( t1 );
    t1.dispose();

    this.output0.realTensor = t0;
  }

}

<|endoftext|>


<commit_before>/*
 Copyright (c) 2013-2017 by Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL

 Permission to use this software for any purpose without fee is hereby granted, provided
 that the above copyright notice and this permission notice appear in all copies.

 Permission to copy and/or edit this software or parts of it for any purpose is permitted,
 provided that the following points are followed.
 - The above copyright notice and this permission notice appear in all copies
 - Within two (2) days after modification is proven working, any modifications are send back
   to the original authors to be inspected with the goal of inclusion in the official software
 - Any edited version are only test versions and not permitted to be run as a final product
 - Any edited version aren't to be distributed
 - Any edited version have the prerelease version set to something that can be distinguished
   from a version used in the original software

 TERMS OF REPRODUCTION USE

 Failure to follow these terms will result in me getting very angry at you
 and having your software tweaked or removed if possible. Either way, you're
 still an idiot for not following such a basic rule.
 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS
 BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

 * NOTE:  PLEASE CONTACT DJ-NEON FOR THIS SCRIPT (DO NOT CHANGE ANYTHING ON THIS SCRIPT OR USE AND EDIT THIS SCRIPT WHICH
 * WAS WRITTEN BY IT'S RIGHTFUL OWNER: DJ NOEN)
 *
 * @Author:    Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL (Member. on Plug.dj)
 *
 */

var path = 'http://pastebin.com/raw.php?i=';

function message(contents) {
        var msg = '
PlugWoot_Alpha ' + contents + '
';
        $('#chat-messages').append(msg);
}

var scriptFail = window.setTimeout(function() {
    message('Oops! An Error Occurred');
  }, 2000);

$.getScript(path + 'd114cGtJ', function() {
 message("version "+ pwa.version +" is now available!");
 setTimeout(function(){
 API.chatLog("Type /commands to see the commands!", alert);
 }, 1000);
  window.clearTimeout(scriptFail);
});
<commit_msg>Update Alpha.js<commit_after>/*
 Copyright (c) 2013-2017 by Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL

 Permission to use this software for any purpose without fee is hereby granted, provided
 that the above copyright notice and this permission notice appear in all copies.

 Permission to copy and/or edit this software or parts of it for any purpose is permitted,
 provided that the following points are followed.
 - The above copyright notice and this permission notice appear in all copies
 - Within two (2) days after modification is proven working, any modifications are send back
   to the original authors to be inspected with the goal of inclusion in the official software
 - Any edited version are only test versions and not permitted to be run as a final product
 - Any edited version aren't to be distributed
 - Any edited version have the prerelease version set to something that can be distinguished
   from a version used in the original software

 TERMS OF REPRODUCTION USE

 Failure to follow these terms will result in me getting very angry at you
 and having your software tweaked or removed if possible. Either way, you're
 still an idiot for not following such a basic rule.
 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS
 BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

 * NOTE:  PLEASE CONTACT DJ-NEON FOR THIS SCRIPT (DO NOT CHANGE ANYTHING ON THIS SCRIPT OR USE AND EDIT THIS SCRIPT WHICH
 * WAS WRITTEN BY IT'S RIGHTFUL OWNER: DJ NOEN)
 *
 * @Author:    Tawi Jordan - ๖ۣۜĐJ - ɴᴇᴏɴ - TFL (Member. on Plug.dj)
 *
 */

var path = 'http://pastebin.com/raw.php?i=';

function message(contents) {
        var msg = '
PlugWoot_Alpha ' + contents + '
';
        $('#chat-messages').append(msg);
}

var scriptFail = window.setTimeout(function() {
    admin('Oops! An Error Occurred');
  }, 2000);

$.getScript(path + 'd114cGtJ', function() {
 message("version "+ pwa.version +" is now available!");
 API.chatLog("Type /commands to see the commands!", alert);
  window.clearTimeout(scriptFail);
});
<|endoftext|>


<commit_before>//META{"name":"imageback"}*//

/*@cc_on
@if (@_jscript)
    var shell = WScript.CreateObject("WScript.Shell");
    var fs = new ActiveXObject("Scripting.FileSystemObject");
    var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins");
    var pathSelf = WScript.ScriptFullName;
    if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
        shell.Popup("Plugin is already in the folder.\nReload Discord.", 0, "Error", 0x40);
    } else if (!fs.FolderExists(pathPlugins)) {
        shell.Popup("BetterDiscord plugins folder missing.\nMake sure its installed?", 0, "Error add", 0x10);
    } else if (shell.Popup("Adding the local Plugin, want to?", 0, "Request", 0x34) === 6) {
        fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
        // Show the user where to put plugins in the future
        shell.Exec("explorer " + pathPlugins);
    }
    WScript.Quit();
@else @*/

var imageback = function () {};
var apps = document.getElementsByClassName("app");
var newDiv = document.createElement("div");
var controlsContainer = document.createElement("div");
var next = document.createElement("button");
var prev = document.createElement("button");
//var url = "https://bunniesmcgee.tk/rand/";
var localurl = "C:\\Users\\YOUR-USERNAME\\AppData\\Roaming\\BetterDiscord\\plugins\\img\\";
var localarray = [];
var dontstart = false;
var index = 0;
var incooldown = false;
var fs = require('fs');

var setBackground = function(number) {
	if (number == null) {
		console.log("Error: No number entered");
		return;
	}
	if (number >= localarray.length) {
		index = (localarray.length - 1);
		console.log("Error: Number entered is too high, setting to last image " + index);
	} else {
		index = number;
	}
	$(newDiv).fadeOut(1000);
	setTimeout(function() {
		//newDiv.style.backgroundImage = "url('"+ url + localarray[index] + "')";
		newDiv.style.backgroundImage = "url(data:image/png;base64," + localarray[index] + ")";
	}, 800);
	$(newDiv).fadeIn(1000);
	//console.log("Current background image: Index = " + index + ", URL = " + url + localarray[index]);
}

imageback.prototype.convert = function () {
	var elementExists = document.getElementById("bgImgContainer");
	//$(function(){
        //$.get('https://bunniesmcgee.tk/res/22 07 2016 v1.txt', function(data){
			// fs.realpath((url), function(err, path) {
				// if (err) {
					// console.log(err);
				 // return;
				// }
			// });

			var files = fs.readdirSync(localurl);
			for (var i in files) {
				var name = localurl + files[i];
				var bitmap = fs.readFileSync(name);
				localarray.push(Buffer(bitmap).toString('base64'));
			}
			//function(err, files) {
			//	if (err) return;
			//	files.forEach(function(f) {
			//		var name = url+f;
			//		var bitmap = fs.readFileSync(name);
			//		//console.log(Buffer(bitmap).toString('base64'));//this broke it kek
			//		localarray[index++] = Buffer(bitmap).toString('base64');
			//		//console.log(f);
			//	});
			//	//console.log(localarray[0]);
			//	//logging any of these crashes it
			//	console.log(index);
			//});
            //localarray = data.split('\n');
			if (elementExists == null) {
				dontstart = false;
			} else {
				dontstart = true;
			}
			if (dontstart == false) {
				document.body.appendChild(newDiv);
				newDiv.style.width = "100%";
				newDiv.style.height = "100%";
				newDiv.style.position = "absolute";
				newDiv.style.left = "0";
				newDiv.style.top = "0";
				newDiv.style.zIndex = "-1";
				newDiv.style.backgroundSize = "cover";
				newDiv.id = "bgImgContainer";

				var links = document.getElementsByClassName("channels-3g2vYe");
				$(links).append(controlsContainer);
				controlsContainer.style.flex = "0 0 auto";
				controlsContainer.style.flexFlow = "row";
				controlsContainer.id = "controlsContainer";
				$(controlsContainer).append(prev);
				$(controlsContainer).append(next);
				prev.innerHTML = "Prev";
				prev.style.backgroundColor = "#282b30";
				prev.id = "previousButton";
				next.innerHTML = "Next";
				next.style.backgroundColor = "#282b30";
				next.id = "nextButton";

				console.log("Number of background images; " + (localarray.length - 1));
				var randint = Math.floor(Math.random() * (localarray.length - 1));
				index = randint;
				$(newDiv).fadeOut(1000);
				setTimeout(function() {
					//newDiv.style.backgroundImage = "url('"+ url + localarray[index] + "')";
					newDiv.style.backgroundImage = "url(data:image/png;base64," + localarray[index] + ")";
				}, 1000);
				setTimeout(function() {
					$(newDiv).fadeIn(1000);
				}, 1300);
				//console.log("Current background image: Index = " + index + ", URL = " + url + localarray[index]);
			}

			$(next).on("click", function() {
				if (incooldown == true) {
					return;
				}

				incooldown = true;
				setTimeout(() => {
					incooldown = false;
				}, 1750);

				index = index + 1;
				if (index == localarray.length) {
					index = 0;
				}

				$(newDiv).fadeOut(1000);
				setTimeout(function() {
					//newDiv.style.backgroundImage = "url('"+ url + localarray[index] + "')";
					newDiv.style.backgroundImage = "url(data:image/png;base64," + localarray[index] + ")";
					//console.log("Current background image: Index = " + index + ", URL = " + url + localarray[index]);
				}, 1000);
				setTimeout(function() {
					$(newDiv).fadeIn(1000);
				}, 1300);
			});

			$(prev).on("click", function() {
				if (incooldown == true) {
					return;
				}
				incooldown = true;
				setTimeout(() => {
					incooldown = false;
				}, 1750);

				index = index - 1;
				if (index == -1) {
					index = (localarray.length-1);
				}

				$(newDiv).fadeOut(1000);
				setTimeout(function() {
					//newDiv.style.backgroundImage = "url('"+ url + localarray[index] + "')";
					newDiv.style.backgroundImage = "url(data:image/png;base64," + localarray[index] + ")";
					//console.log("Current background image: Index = " + index + ", URL = " + url + localarray[index]);
				}, 1000);
				setTimeout(function() {
					$(newDiv).fadeIn(1000);
				}, 1300);
			});
		//});
	//});
};

imageback.prototype.start = function () {
    this.convert();
};

imageback.prototype.load = function () {};
imageback.prototype.unload = function () {};
imageback.prototype.stop = function () {};
imageback.prototype.getSettingsPanel = function () {
    return "";
};

imageback.prototype.getName = function () {
    return "Bunny Plugin Local Edition";
};
imageback.prototype.getDescription = function () {
    return "Must use Bunny theme in conjunction, allows for changing of background image using buttons. Uses local files";
};
imageback.prototype.getVersion = function () {
    return "1.2";
};
imageback.prototype.getAuthor = function () {
    return "Bunnies McGee";
};
/*@end @*/
<commit_msg>jQuery though<commit_after>//META{"name":"imageback"}*//

/*@cc_on
@if (@_jscript)
    var shell = WScript.CreateObject("WScript.Shell");
    var fs = new ActiveXObject("Scripting.FileSystemObject");
    var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins");
    var pathSelf = WScript.ScriptFullName;
    if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
        shell.Popup("Plugin is already in the folder.\nReload Discord.", 0, "Error", 0x40);
    } else if (!fs.FolderExists(pathPlugins)) {
        shell.Popup("BetterDiscord plugins folder missing.\nMake sure its installed?", 0, "Error add", 0x10);
    } else if (shell.Popup("Adding the local Plugin, want to?", 0, "Request", 0x34) === 6) {
        fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
        // Show the user where to put plugins in the future
        shell.Exec("explorer " + pathPlugins);
    }
    WScript.Quit();
@else @*/

var imageback = function () {};
var apps = document.getElementsByClassName("app");
var newDiv = document.createElement("div");
var controlsContainer = document.createElement("div");
var next = document.createElement("button");
var prev = document.createElement("button");
//var url = "https://bunniesmcgee.tk/rand/";
var localurl = "C:\\Users\\YOUR-USERNAME\\AppData\\Roaming\\BetterDiscord\\plugins\\img\\";
var localarray = [];
var dontstart = false;
var index = 0;
var incooldown = false;
var fs = require('fs');

var setBackground = function(number) {
	if (number == null) {
		console.log("Error: No number entered");
		return;
	}
	if (number >= localarray.length) {
		index = (localarray.length - 1);
		console.log("Error: Number entered is too high, setting to last image " + index);
	} else {
		index = number;
	}
	$(newDiv).fadeOut(1000);
	setTimeout(function() {
		//newDiv.style.backgroundImage = "url('"+ url + localarray[index] + "')";
		newDiv.style.backgroundImage = "url(data:image/png;base64," + localarray[index] + ")";
	}, 800);
	$(newDiv).fadeIn(1000);
	//console.log("Current background image: Index = " + index + ", URL = " + url + localarray[index]);
}

imageback.prototype.convert = function () {
	var elementExists = document.getElementById("bgImgContainer");
	//$(function(){
        //$.get('https://bunniesmcgee.tk/res/22 07 2016 v1.txt', function(data){
			// fs.realpath((url), function(err, path) {
				// if (err) {
					// console.log(err);
				 // return;
				// }
			// });

			var files = fs.readdirSync(localurl);
			for (var i in files) {
				var name = localurl + files[i];
				var bitmap = fs.readFileSync(name);
				localarray.push(Buffer(bitmap).toString('base64'));
			}
			//function(err, files) {
			//	if (err) return;
			//	files.forEach(function(f) {
			//		var name = url+f;
			//		var bitmap = fs.readFileSync(name);
			//		//console.log(Buffer(bitmap).toString('base64'));//this broke it kek
			//		localarray[index++] = Buffer(bitmap).toString('base64');
			//		//console.log(f);
			//	});
			//	//console.log(localarray[0]);
			//	//logging any of these crashes it
			//	console.log(index);
			//});
            //localarray = data.split('\n');
			if (elementExists == null) {
				dontstart = false;
			} else {
				dontstart = true;
			}
			if (dontstart == false) {
				document.body.appendChild(newDiv);
				newDiv.style.width = "100%";
				newDiv.style.height = "100%";
				newDiv.style.position = "absolute";
				newDiv.style.left = "0";
				newDiv.style.top = "0";
				newDiv.style.zIndex = "-1";
				newDiv.style.backgroundSize = "cover";
				newDiv.id = "bgImgContainer";

				var links = $('div[class^="channels-"]');
				$(links).append(controlsContainer);
				controlsContainer.style.flex = "0 0 auto";
				controlsContainer.style.flexFlow = "row";
				controlsContainer.id = "controlsContainer";
				$(controlsContainer).append(prev);
				$(controlsContainer).append(next);
				prev.innerHTML = "Prev";
				prev.style.backgroundColor = "#282b30";
				prev.id = "previousButton";
				next.innerHTML = "Next";
				next.style.backgroundColor = "#282b30";
				next.id = "nextButton";

				console.log("Number of background images; " + (localarray.length - 1));
				var randint = Math.floor(Math.random() * (localarray.length - 1));
				index = randint;
				$(newDiv).fadeOut(1000);
				setTimeout(function() {
					//newDiv.style.backgroundImage = "url('"+ url + localarray[index] + "')";
					newDiv.style.backgroundImage = "url(data:image/png;base64," + localarray[index] + ")";
				}, 1000);
				setTimeout(function() {
					$(newDiv).fadeIn(1000);
				}, 1300);
				//console.log("Current background image: Index = " + index + ", URL = " + url + localarray[index]);
			}

			$(next).on("click", function() {
				if (incooldown == true) {
					return;
				}

				incooldown = true;
				setTimeout(() => {
					incooldown = false;
				}, 1750);

				index = index + 1;
				if (index == localarray.length) {
					index = 0;
				}

				$(newDiv).fadeOut(1000);
				setTimeout(function() {
					//newDiv.style.backgroundImage = "url('"+ url + localarray[index] + "')";
					newDiv.style.backgroundImage = "url(data:image/png;base64," + localarray[index] + ")";
					//console.log("Current background image: Index = " + index + ", URL = " + url + localarray[index]);
				}, 1000);
				setTimeout(function() {
					$(newDiv).fadeIn(1000);
				}, 1300);
			});

			$(prev).on("click", function() {
				if (incooldown == true) {
					return;
				}
				incooldown = true;
				setTimeout(() => {
					incooldown = false;
				}, 1750);

				index = index - 1;
				if (index == -1) {
					index = (localarray.length-1);
				}

				$(newDiv).fadeOut(1000);
				setTimeout(function() {
					//newDiv.style.backgroundImage = "url('"+ url + localarray[index] + "')";
					newDiv.style.backgroundImage = "url(data:image/png;base64," + localarray[index] + ")";
					//console.log("Current background image: Index = " + index + ", URL = " + url + localarray[index]);
				}, 1000);
				setTimeout(function() {
					$(newDiv).fadeIn(1000);
				}, 1300);
			});
		//});
	//});
};

imageback.prototype.start = function () {
    this.convert();
};

imageback.prototype.load = function () {};
imageback.prototype.unload = function () {};
imageback.prototype.stop = function () {};
imageback.prototype.getSettingsPanel = function () {
    return "";
};

imageback.prototype.getName = function () {
    return "Bunny Plugin Local Edition";
};
imageback.prototype.getDescription = function () {
    return "Must use Bunny theme in conjunction, allows for changing of background image using buttons. Uses local files";
};
imageback.prototype.getVersion = function () {
    return "1.2";
};
imageback.prototype.getAuthor = function () {
    return "Bunnies McGee";
};
/*@end @*/
<|endoftext|>


<commit_before>export default class CancelablePromise {
  static all(iterable) {
    return Promise.all(iterable);
  }
  static race(iterable) {
    return Promise.race(iterable);
  }
  static reject(iterable) {
    return Promise.reject(iterable);
  }
  static resolve(iterable) {
    return Promise.resolve(iterable);
  }
  constructor(executor) {
    let superResolve, superReject;
    this._promise = new Promise(executor);

    this._canceled = false;
  }

  then(success, error) {
    const p = new CancelablePromise((resolve, reject) => {
      this._promise.then((r) => {
        if (this._canceled) {
          p.cancel();
        }
        if (success && !this._canceled) {
          resolve(success(r));
        } else {
          resolve(r);
        }
      }, (r) => {
        if (this._canceled) {
          p.cancel();
        }
        if (error && !this._canceled) {
          resolve(error(r));
        } else {
          resolve(r);
        }
      });
    });
    return p;
  }

  catch(error) {
    return this.then(undefined, error);
  }

  cancel() {
    this._canceled = true;
    return this;
  }
}
<commit_msg>Remove useless code<commit_after>export default class CancelablePromise {
  static all(iterable) {
    return Promise.all(iterable);
  }
  static race(iterable) {
    return Promise.race(iterable);
  }
  static reject(iterable) {
    return Promise.reject(iterable);
  }
  static resolve(iterable) {
    return Promise.resolve(iterable);
  }
  constructor(executor) {
    this._promise = new Promise(executor);

    this._canceled = false;
  }

  then(success, error) {
    const p = new CancelablePromise((resolve, reject) => {
      this._promise.then((r) => {
        if (this._canceled) {
          p.cancel();
        }
        if (success && !this._canceled) {
          resolve(success(r));
        } else {
          resolve(r);
        }
      }, (r) => {
        if (this._canceled) {
          p.cancel();
        }
        if (error && !this._canceled) {
          resolve(error(r));
        } else {
          resolve(r);
        }
      });
    });
    return p;
  }

  catch(error) {
    return this.then(undefined, error);
  }

  cancel() {
    this._canceled = true;
    return this;
  }
}
<|endoftext|>


<commit_before>
var DOMAIN = 'https://heka.house';
var ACCOUNT_ENDPOINT = ',system/newAccount';
var CERT_ENDPOINT = ',system/newCert';

var accURL = {};

function init() {
	var parser = document.createElement('a');
	parser.href = DOMAIN;
	accURL.host = parser.host + '/'; // => "example.com"
	accURL.path = parser.pathname; // => "/pathname/"
	accURL.schema = parser.protocol + '//';
}

init();

var makeURI = function(username) {
  if (username.length > 0) {
    return accURL.schema + username + '.' + accURL.host;
  }
  return null;
}

var makeHost = function(username) {
  if (username.length > 0) {
    return username + '.' + accURL.host;
  }
  return null;
}

var requestPersona = function(persona,cb) {

	if (persona.indexOf('-') === 0) {
		persona = persona.slice(1);
	}
	if (persona.lastIndexOf('-') === persona.length - 1) {
		persona = persona.slice(0, -1)
	}

	if (persona.length > 0) {
		// var mrp = require('minimal-request-promise');
		// options = {
		//     method: 'HEAD',
		//     hostname: makeURI(persona),
		//     path: '/',
		//     port: 443,
		//     headers: {},
		//     body: ''
		// };
		// return mrp(options).then(
		//   function (response) {
		//     return response.statusCode;
		//   },
		//   function (response) {
		//   	if (response.statusCode === undefined) {
		//   		return '999';
		//   	}
		//     return response.statusCode;
		//   }
		// );
		var url = makeURI(persona,function(status){
			console.log('status',status);
		});
		var http = new XMLHttpRequest();
		http.open('HEAD', makeURI(persona));
		http.onreadystatechange = function() {
		  console.log(this.status)
		    if (this.readyState == this.DONE) {
		      if (this.status === 0) {
		      	console.log('not connected');
		        cb('999');
		      } else if (this.status === 404) {
		        cb('404');
		      } else {
		        cb(this.status);
		      }
		    }
		};
		http.send();
	}

};

var createAccount = function(account,email,cb) {
	if (account.length > 0) {
		generateRSAKeyPair()
		.then(function(keyPair){
			storeKeys(keyPair);
			return generateCSR(keyPair,db,definePersonaCSR(account));
		})
		.then(function(csr){
			storeKeyValue(db,'csr',csr);
			certified.verifyCSR(csr)
			.then(function(verified){
				console.log(verified);
				if (verified) {
					certified.parseCSR(csr)
					.then(function(csrStruct){
						return JSON.stringify(csrStruct);
					})
					.then(function(csrStr){
						var url = makeURI(account) + ACCOUNT_ENDPOINT;
						var data = "username="+account+"&email="+email+"&csr="+csr;
						var http = new XMLHttpRequest();
						http.open('POST', url);
						http.withCredentials = true;
						http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
						http.onreadystatechange = function() {
						    if (this.readyState == this.DONE) {
						      if (this.status === 200) {
								console.log('Account created at '+url);
						      } else {
						        console.log('Error creating account at '+url);
						      }
						    }
						};
						http.send(data);
						//document.querySelector("#spkacWebID").value = csrStr;
					});
				}
			});
		});

	}
};

window.requestPersona = requestPersona;

window.createAccount = createAccount;<commit_msg>completing registration<commit_after>
var DOMAIN = 'https://heka.house';
var ACCOUNT_ENDPOINT = ',system/newAccount';
var CERT_ENDPOINT = ',system/newCert';

var accURL = {};

function init() {
	var parser = document.createElement('a');
	parser.href = DOMAIN;
	accURL.host = parser.host + '/'; // => "example.com"
	accURL.path = parser.pathname; // => "/pathname/"
	accURL.schema = parser.protocol + '//';
}

init();

var makeURI = function(username) {
  if (username.length > 0) {
    return accURL.schema + username + '.' + accURL.host;
  }
  return null;
}

var makeHost = function(username) {
  if (username.length > 0) {
    return username + '.' + accURL.host;
  }
  return null;
}

var requestPersona = function(persona,cb) {

	if (persona.indexOf('-') === 0) {
		persona = persona.slice(1);
	}
	if (persona.lastIndexOf('-') === persona.length - 1) {
		persona = persona.slice(0, -1)
	}

	if (persona.length > 0) {
		// var mrp = require('minimal-request-promise');
		// options = {
		//     method: 'HEAD',
		//     hostname: makeURI(persona),
		//     path: '/',
		//     port: 443,
		//     headers: {},
		//     body: ''
		// };
		// return mrp(options).then(
		//   function (response) {
		//     return response.statusCode;
		//   },
		//   function (response) {
		//   	if (response.statusCode === undefined) {
		//   		return '999';
		//   	}
		//     return response.statusCode;
		//   }
		// );
		var url = makeURI(persona,function(status){
			console.log('status',status);
		});
		var http = new XMLHttpRequest();
		http.open('HEAD', makeURI(persona));
		http.onreadystatechange = function() {
		  console.log(this.status)
		    if (this.readyState == this.DONE) {
		      if (this.status === 0) {
		      	console.log('not connected');
		        cb('999');
		      } else if (this.status === 404) {
		        cb('404');
		      } else {
		        cb(this.status);
		      }
		    }
		};
		http.send();
	}

};

var createAccount = function(account,email,cb) {
	if (account.length > 0) {
		generateRSAKeyPair()
		.then(function(keyPair){
			storeKeys(keyPair);
			return generateCSR(keyPair,db,definePersonaCSR(account));
		})
		.then(function(csr){
			storeKeyValue(db,'csr',csr);
			certified.verifyCSR(csr)
			.then(function(verified){
				console.log(verified);
				if (verified) {
					certified.parseCSR(csr)
					.then(function(csrStruct){
						return JSON.stringify(csrStruct);
					})
					.then(function(csrStr){
						var url = makeURI(account) + ACCOUNT_ENDPOINT;
						var data = {"username":account,"email":email,"csr":csr};
						var http = new XMLHttpRequest();
						http.open('POST', url);
						http.withCredentials = true;
						http.setRequestHeader("Content-Type", "application/json");
						http.onreadystatechange = function() {
						    if (this.readyState == this.DONE) {
						      if (this.status === 200) {
								console.log('Account created at '+url);
						      } else {
						        console.log('Error creating account at '+url);
						      }
						    }
						};
						http.send(data);
						//document.querySelector("#spkacWebID").value = csrStr;
					});
				}
			});
		});

	}
};

window.requestPersona = requestPersona;

window.createAccount = createAccount;<|endoftext|>


<commit_before>
export default function route ($stateProvider) {
  $stateProvider
    .state('home', {
      url: '/',
      template: require('./app/home/home.html'),
      controller: 'HomeCtrl'
    })
    .state('login', {
      url: '/login',
      template: require('./app/authentication/login.html'),
      controller: 'LoginCtrl'
    })
    .state('register', {
      url: '/register',
      template: require('./app/authentication/register.html'),
      controller: 'RegisterCtrl'
    })
    .state('disconnect', {
      url: '/disconnect',
      controller: ['AuthService', function (AuthService) {
        AuthService.logout()
      }]
    })
    /*******************************/
    /* ---------- ADMIN ---------- */
    /*******************************/
    .state('admin', {
      url: '/admin',
      template: require('./app/admin/admin.html')
    })
    .state('admin.questions', {
      abstract: true,
      url: '/questions'
    })
    .state('admin.questions.all', {
      url: '',
      template: require('./app/admin/questions.html'),
      controller: 'AdminQuestionsCtrl'
    })
    .state('admin.questions.add', {
      url: '/add',
      template: require('./app/admin/questions.add.html'),
      controller: 'AdminAddQuestionCtrl'
    })
    .state('admin.questions.edit', {
      url: '/{id}/edit',
      template: require('./app/admin/questions.edit.html'),
      controller: 'AdminEditQuestionCtrl'
    })
    .state('games', {
      url: '/games/{id}',
      template: require('./app/game/game.html'),
      controller: 'GameCtrl'
    })
}
<commit_msg>Renamed game route<commit_after>
export default function route ($stateProvider) {
  $stateProvider
    .state('home', {
      url: '/',
      template: require('./app/home/home.html'),
      controller: 'HomeCtrl'
    })
    .state('login', {
      url: '/login',
      template: require('./app/authentication/login.html'),
      controller: 'LoginCtrl'
    })
    .state('register', {
      url: '/register',
      template: require('./app/authentication/register.html'),
      controller: 'RegisterCtrl'
    })
    .state('disconnect', {
      url: '/disconnect',
      controller: ['AuthService', function (AuthService) {
        AuthService.logout()
      }]
    })
    /*******************************/
    /* ---------- ADMIN ---------- */
    /*******************************/
    .state('admin', {
      url: '/admin',
      template: require('./app/admin/admin.html')
    })
    .state('admin.questions', {
      abstract: true,
      url: '/questions'
    })
    .state('admin.questions.all', {
      url: '',
      template: require('./app/admin/questions.html'),
      controller: 'AdminQuestionsCtrl'
    })
    .state('admin.questions.add', {
      url: '/add',
      template: require('./app/admin/questions.add.html'),
      controller: 'AdminAddQuestionCtrl'
    })
    .state('admin.questions.edit', {
      url: '/{id}/edit',
      template: require('./app/admin/questions.edit.html'),
      controller: 'AdminEditQuestionCtrl'
    })
    .state('game', {
      url: '/games/{id}',
      template: require('./app/game/game.html'),
      controller: 'GameCtrl'
    })
}
<|endoftext|>


<commit_before>/*

HumanizeDuration.js
http://git.io/j0HgmQ

*/

;(function() {

  // What are the languages?
  var LANGUAGES = {
    en: {
      year: function(c) { return "year" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "month" + ((c !== 1) ? "s" : ""); },
      week: function(c) { return "week" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "day" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hour" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "second" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "millisecond" + ((c !== 1) ? "s" : ""); }
    },
    ca: {
      year: function(c) { return "any" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "mes" + ((c !== 1) ? "os" : ""); },
      week: function(c) { return "setman" + ((c !== 1) ? "es" :"a"); },
      day: function(c) { return "di" + ((c !== 1) ? "es" :"a"); },
      hour: function(c) { return "hor" + ((c !== 1) ? "es" :"a"); },
      minute: function(c) { return "minut" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segon" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milisegon" + ((c !== 1) ? "s" : "" ); }
    },
    es: {
      year: function(c) { return "año" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "mes" + ((c !== 1) ? "es" : ""); },
      week: function(c) { return "semana" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "día" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hora" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minuto" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segundo" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milisegundo" + ((c !== 1) ? "s" : "" ); }
    },
    fr: {
      year: function(c) { return "an" + ((c !== 1) ? "s" : ""); },
      month: function() { return "mois"; },
      week: function(c) { return "semaine" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "jour" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "heure" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "seconde" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milliseconde" + ((c !== 1) ? "s" : ""); }
    },
    pt: {
      year: function(c) { return "ano" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return (c !== 1) ? "meses" : "mês"; },
      week: function(c) { return "semana" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "dia" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hora" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minuto" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segundo" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milissegundo" + ((c !== 1) ? "s" : ""); }
    },
    ko: {
      year: function() { return "년"; },
      month: function() { return "개월"; },
      week: function() { return "주일"; },
      day: function() { return "일"; },
      hour: function() { return "시간"; },
      minute: function() { return "분"; },
      second: function() { return "초"; },
      millisecond: function() { return "밀리 초"; }
    },
    nob: {
      year: function() { return "år"; },
      month: function(c) { return "måned" + ((c !== 1) ? "er" : ""); },
      week: function(c) { return "uke" + ((c !== 1) ? "r" : ""); },
      day: function(c) { return "dag" + ((c !== 1) ? "er" : ""); },
      hour: function(c) { return "time" + ((c !== 1) ? "r" : ""); },
      minute: function(c) { return "minutt" + ((c !== 1) ? "er" : ""); },
      second: function(c) { return "sekund" + ((c !== 1) ? "er" : ""); },
      millisecond: function(c) { return "millisekund" + ((c !== 1) ? "er" : ""); }
    },
    de: {
      year: function(c) { return "jahr" + ((c !== 1) ? "e" : ""); },
      month: function(c) { return "monat" + ((c !== 1) ? "e" : ""); },
      week: function(c) { return "woche" + ((c !== 1) ? "n" : ""); },
      day: function(c) { return "tag" + ((c !== 1) ? "e" : ""); },
      hour: function(c) { return "stunde" + ((c !== 1) ? "n" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "n" : ""); },
      second: function(c) { return "sekunde" + ((c !== 1) ? "n" : ""); },
      millisecond: function(c) { return "millisekunde" + ((c !== 1) ? "n" : ""); }
    },
    pl: {
      year: function(c) { return ["rok", "roku", "lata", "lat"][getPolishForm(c)]; },
      month: function(c) { return ["miesiąc", "miesiąca", "miesiące", "miesięcy"][getPolishForm(c)]; },
      week: function(c) { return ["tydzień", "tygodnia", "tygodnie", "tygodni"][getPolishForm(c)]; },
      day: function(c) { return ["dzień", "dnia", "dni", "dni"][getPolishForm(c)]; },
      hour: function(c) { return ["godzina", "godziny", "godziny", "godzin"][getPolishForm(c)]; },
      minute: function(c) { return ["minuta", "minuty", "minuty", "minut"][getPolishForm(c)]; },
      second: function(c) { return ["sekunda", "sekundy", "sekundy", "sekund"][getPolishForm(c)]; },
      millisecond: function(c) { return ["milisekunda", "milisekundy", "milisekundy", "milisekund"][getPolishForm(c)]; }
    }
  };

  // Start by defining the units and how many ms is in each.
  var UNITS = [
    { name: "year", milliseconds: 31557600000 },
    { name: "month", milliseconds: 2629800000 },
    { name: "week", milliseconds: 604800000 },
    { name: "day", milliseconds: 86400000 },
    { name: "hour", milliseconds: 3600000 },
    { name: "minute", milliseconds: 60000 },
    { name: "second", milliseconds: 1000 },
    { name: "millisecond", milliseconds: 1 }
  ];

  // Internal utility function for rendering the strings.
  // render(1, "minute") == "1 minute"
  // render(12, "hour") == "12 hours"
  // render(2, "hour", "es") == "2 horas"
  function render(count, word, language) {
    var dictionary = LANGUAGES[language || humanizeDuration.language];
    if (!dictionary) {
      throw new Error("Language " + language + " not defined");
    }
    return count + " " + dictionary[word](count);
  }

  // Internal helper function for Polish language.
  function getPolishForm(c) {
    if (c === 1) {
      return 0;
    } else if (Math.floor(c) !== c) {
      return 1;
    } else if (2 <= c % 10 && c % 10 <= 4 && !(10 < c % 100 && c % 100 < 20)) {
      return 2;
    } else {
      return 3;
    }
  }

  // Grab the components.
  function componentsOf(total, language) {

    var result = { total: {} };

    // Make sure we have positive numbers.
    // Has the nice sideffect of turning Number objects into primitives.
    total = Math.abs(total);
    var ms = total;

    var unit, unitName, unitTotal, unitCount;
    for (var i = 0, len = UNITS.length; i < len; i ++) {

      // Store the current unit.
      unit = UNITS[i];
      unitName = unit.name + "s";

      // What are the totals and the rest?
      if (unit.name === "millisecond") {
        unitCount = ms / unit.milliseconds;
        unitTotal = total / unit.milliseconds;
      } else {
        unitCount = Math.floor(ms / unit.milliseconds);
        unitTotal = Math.floor(total / unit.milliseconds);
      }

      // Put them in the result.
      result[unitName] = render(unitCount, unit.name, language);
      result.total[unitName] = render(unitTotal, unit.name, language);

      // Lower the number of milliseconds.
      ms -= unitCount * unit.milliseconds;

    }

    return result;

  }

  // The main function.
  function humanizeDuration(ms, language) {

    // Make sure we have a positive number.
    // Has the nice sideffect of turning Number objects into primitives.
    ms = Math.abs(ms);

    // Humanizing zero, I see.
    if (ms === 0)
      return "0";

    // We'll put everything in an array and turn that into a string at the end.
    var result = [];

    // Start at the top and keep removing units, bit by bit.
    var unit, unitCount, mightBeHalfUnit;
    for (var i = 0, len = UNITS.length; i < len; i ++) {

      // Store the current unit.
      unit = UNITS[i];

      // If it's a half-unit interval, we're done.
      if (result.length === 0) {
        mightBeHalfUnit = (ms / unit.milliseconds) * 2;
        if (mightBeHalfUnit === Math.floor(mightBeHalfUnit))
          return render(mightBeHalfUnit / 2, unit.name, language);
      }

      // What's the number of full units we can fit?
      if (unit.name === "millisecond") {
        unitCount = ms / unit.milliseconds;
      } else {
        unitCount = Math.floor(ms / unit.milliseconds);
      }

      // Add the string.
      if (unitCount)
        result.push(render(unitCount, unit.name, language));

      // Remove what we just figured out.
      ms -= unitCount * unit.milliseconds;

    }

    // All done! Turn the array into a string.
    return result.join(", ");

  }

  // What's the default language?
  humanizeDuration.language = "en";

  // Export this baby.
  humanizeDuration.componentsOf = componentsOf;
  if ((typeof module !== "undefined") && (module.exports))
    module.exports = humanizeDuration;
  else
    this.humanizeDuration = humanizeDuration;

})();
<commit_msg>Added Danish language support.<commit_after>/*

HumanizeDuration.js
http://git.io/j0HgmQ

*/

;(function() {

  // What are the languages?
  var LANGUAGES = {
    en: {
      year: function(c) { return "year" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "month" + ((c !== 1) ? "s" : ""); },
      week: function(c) { return "week" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "day" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hour" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "second" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "millisecond" + ((c !== 1) ? "s" : ""); }
    },
    ca: {
      year: function(c) { return "any" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "mes" + ((c !== 1) ? "os" : ""); },
      week: function(c) { return "setman" + ((c !== 1) ? "es" :"a"); },
      day: function(c) { return "di" + ((c !== 1) ? "es" :"a"); },
      hour: function(c) { return "hor" + ((c !== 1) ? "es" :"a"); },
      minute: function(c) { return "minut" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segon" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milisegon" + ((c !== 1) ? "s" : "" ); }
    },
    es: {
      year: function(c) { return "año" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "mes" + ((c !== 1) ? "es" : ""); },
      week: function(c) { return "semana" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "día" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hora" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minuto" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segundo" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milisegundo" + ((c !== 1) ? "s" : "" ); }
    },
    fr: {
      year: function(c) { return "an" + ((c !== 1) ? "s" : ""); },
      month: function() { return "mois"; },
      week: function(c) { return "semaine" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "jour" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "heure" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "seconde" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milliseconde" + ((c !== 1) ? "s" : ""); }
    },
    pt: {
      year: function(c) { return "ano" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return (c !== 1) ? "meses" : "mês"; },
      week: function(c) { return "semana" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "dia" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hora" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minuto" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segundo" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milissegundo" + ((c !== 1) ? "s" : ""); }
    },
    ko: {
      year: function() { return "년"; },
      month: function() { return "개월"; },
      week: function() { return "주일"; },
      day: function() { return "일"; },
      hour: function() { return "시간"; },
      minute: function() { return "분"; },
      second: function() { return "초"; },
      millisecond: function() { return "밀리 초"; }
    },
    nob: {
      year: function() { return "år"; },
      month: function(c) { return "måned" + ((c !== 1) ? "er" : ""); },
      week: function(c) { return "uke" + ((c !== 1) ? "r" : ""); },
      day: function(c) { return "dag" + ((c !== 1) ? "er" : ""); },
      hour: function(c) { return "time" + ((c !== 1) ? "r" : ""); },
      minute: function(c) { return "minutt" + ((c !== 1) ? "er" : ""); },
      second: function(c) { return "sekund" + ((c !== 1) ? "er" : ""); },
      millisecond: function(c) { return "millisekund" + ((c !== 1) ? "er" : ""); }
    },
    de: {
      year: function(c) { return "jahr" + ((c !== 1) ? "e" : ""); },
      month: function(c) { return "monat" + ((c !== 1) ? "e" : ""); },
      week: function(c) { return "woche" + ((c !== 1) ? "n" : ""); },
      day: function(c) { return "tag" + ((c !== 1) ? "e" : ""); },
      hour: function(c) { return "stunde" + ((c !== 1) ? "n" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "n" : ""); },
      second: function(c) { return "sekunde" + ((c !== 1) ? "n" : ""); },
      millisecond: function(c) { return "millisekunde" + ((c !== 1) ? "n" : ""); }
    },
    pl: {
      year: function(c) { return ["rok", "roku", "lata", "lat"][getPolishForm(c)]; },
      month: function(c) { return ["miesiąc", "miesiąca", "miesiące", "miesięcy"][getPolishForm(c)]; },
      week: function(c) { return ["tydzień", "tygodnia", "tygodnie", "tygodni"][getPolishForm(c)]; },
      day: function(c) { return ["dzień", "dnia", "dni", "dni"][getPolishForm(c)]; },
      hour: function(c) { return ["godzina", "godziny", "godziny", "godzin"][getPolishForm(c)]; },
      minute: function(c) { return ["minuta", "minuty", "minuty", "minut"][getPolishForm(c)]; },
      second: function(c) { return ["sekunda", "sekundy", "sekundy", "sekund"][getPolishForm(c)]; },
      millisecond: function(c) { return ["milisekunda", "milisekundy", "milisekundy", "milisekund"][getPolishForm(c)]; }
    },
    da: {
      year: function(c) { return "år" + ((c !== 1) ? "" : ""); },
      month: function(c) { return "måned" + ((c !== 1) ? "er" : ""); },
      week: function(c) { return "uge" + ((c !== 1) ? "r" : ""); },
      day: function(c) { return "dag" + ((c !== 1) ? "e" : ""); },
      hour: function(c) { return "time" + ((c !== 1) ? "r" : ""); },
      minute: function(c) { return "minut" + ((c !== 1) ? "ter" : ""); },
      second: function(c) { return "sekund" + ((c !== 1) ? "er" : ""); },
      millisecond: function(c) { return "millisekund" + ((c !== 1) ? "er" : ""); }
    }
  };

  // Start by defining the units and how many ms is in each.
  var UNITS = [
    { name: "year", milliseconds: 31557600000 },
    { name: "month", milliseconds: 2629800000 },
    { name: "week", milliseconds: 604800000 },
    { name: "day", milliseconds: 86400000 },
    { name: "hour", milliseconds: 3600000 },
    { name: "minute", milliseconds: 60000 },
    { name: "second", milliseconds: 1000 },
    { name: "millisecond", milliseconds: 1 }
  ];

  // Internal utility function for rendering the strings.
  // render(1, "minute") == "1 minute"
  // render(12, "hour") == "12 hours"
  // render(2, "hour", "es") == "2 horas"
  function render(count, word, language) {
    var dictionary = LANGUAGES[language || humanizeDuration.language];
    if (!dictionary) {
      throw new Error("Language " + language + " not defined");
    }
    return count + " " + dictionary[word](count);
  }

  // Internal helper function for Polish language.
  function getPolishForm(c) {
    if (c === 1) {
      return 0;
    } else if (Math.floor(c) !== c) {
      return 1;
    } else if (2 <= c % 10 && c % 10 <= 4 && !(10 < c % 100 && c % 100 < 20)) {
      return 2;
    } else {
      return 3;
    }
  }

  // Grab the components.
  function componentsOf(total, language) {

    var result = { total: {} };

    // Make sure we have positive numbers.
    // Has the nice sideffect of turning Number objects into primitives.
    total = Math.abs(total);
    var ms = total;

    var unit, unitName, unitTotal, unitCount;
    for (var i = 0, len = UNITS.length; i < len; i ++) {

      // Store the current unit.
      unit = UNITS[i];
      unitName = unit.name + "s";

      // What are the totals and the rest?
      if (unit.name === "millisecond") {
        unitCount = ms / unit.milliseconds;
        unitTotal = total / unit.milliseconds;
      } else {
        unitCount = Math.floor(ms / unit.milliseconds);
        unitTotal = Math.floor(total / unit.milliseconds);
      }

      // Put them in the result.
      result[unitName] = render(unitCount, unit.name, language);
      result.total[unitName] = render(unitTotal, unit.name, language);

      // Lower the number of milliseconds.
      ms -= unitCount * unit.milliseconds;

    }

    return result;

  }

  // The main function.
  function humanizeDuration(ms, language) {

    // Make sure we have a positive number.
    // Has the nice sideffect of turning Number objects into primitives.
    ms = Math.abs(ms);

    // Humanizing zero, I see.
    if (ms === 0)
      return "0";

    // We'll put everything in an array and turn that into a string at the end.
    var result = [];

    // Start at the top and keep removing units, bit by bit.
    var unit, unitCount, mightBeHalfUnit;
    for (var i = 0, len = UNITS.length; i < len; i ++) {

      // Store the current unit.
      unit = UNITS[i];

      // If it's a half-unit interval, we're done.
      if (result.length === 0) {
        mightBeHalfUnit = (ms / unit.milliseconds) * 2;
        if (mightBeHalfUnit === Math.floor(mightBeHalfUnit))
          return render(mightBeHalfUnit / 2, unit.name, language);
      }

      // What's the number of full units we can fit?
      if (unit.name === "millisecond") {
        unitCount = ms / unit.milliseconds;
      } else {
        unitCount = Math.floor(ms / unit.milliseconds);
      }

      // Add the string.
      if (unitCount)
        result.push(render(unitCount, unit.name, language));

      // Remove what we just figured out.
      ms -= unitCount * unit.milliseconds;

    }

    // All done! Turn the array into a string.
    return result.join(", ");

  }

  // What's the default language?
  humanizeDuration.language = "en";

  // Export this baby.
  humanizeDuration.componentsOf = componentsOf;
  if ((typeof module !== "undefined") && (module.exports))
    module.exports = humanizeDuration;
  else
    this.humanizeDuration = humanizeDuration;

})();
<|endoftext|>


<commit_before>var ProfileStatsView = function(_parentWindow, _userProfile, _status){
	var PointModel = require('model/point');
	var LevelModel = require('model/level');
	var FriendModel = require('model/friend');

	var ProfileMainWindow = require('ui/common/Pf_ProfileMainWindow');
	var curId = _userProfile.id;

	var profileStats = Ti.UI.createView({
		backgroundColor: 'transparent',
		bottom: 10,
		height: 'auto',
	});

	var expSec = Ti.UI.createView({
		top: 5
	});

	var leaderSec = Ti.UI.createView({
			top:50
	});

	//experience point
	var expLabel = Ti.UI.createLabel({
		font: {fontSize: 14, fontWeight: 'bold'},
		color: '#fff',
		textAlign: 'right',
		top: 0,
		height:30,
		right: 10
	});

	var myLevelLabel = Ti.UI.createLabel({
		text: '',
		font: {fontSize: 16, fontWeight: 'bold'},
		color: '#53b4df',
		textAlign: 'left',
		height:30,
		top: 0,
		left: 10,
	});

    var expBar = Ti.UI.createSlider({
		top:25,
		width:300,
		min:0,
		thumbImage: 'images/slider/thumb_bar.png',
		leftTrackImage:'images/slider/slider_bar.png',
		rightTrackImage:'images/slider/slider_emptybar.png',
		touchEnabled: false,
		backgroundColor: 'transparent',
    });

	var expBar_light = Ti.UI.createSlider({
		top:25,
		width:300,
		min:0,
		thumbImage: 'images/slider/thumb_nextbar.png',
		leftTrackImage:'images/slider/slider_nextbar.png',
		rightTrackImage:'images/slider/slider_lightbar.png',
		touchEnabled: false,
    });

	//sort from max totalPoint
	function totalPointSort(a,b) {
		return b.totalPoint - a.totalPoint;
	}

	var updateExpBar = function() {
		var totalPoints = PointModel.pointModel_fetchMyPoint(curId);
		var profileDataLevelUp = LevelModel.level_nextLevel(totalPoints);
		expLabel.text = totalPoints + '/' + profileDataLevelUp;
		expBar.max = profileDataLevelUp;
		expBar_light.max = profileDataLevelUp;
		expBar.value = totalPoints;

		if(expBar.value === 0) expBar.thumbImage = 'images/empty_thumb.png';
		else expBar.thumbImage = 'images/slider/thumb_bar.png';

		myLevel = LevelModel.level_checkLevel(totalPoints);
		myLevelLabel.text = myLevel;
		expBar_light.value = (totalPoints+5);

	}

	var leaderLabel = Ti.UI.createLabel({
		text:'LEADERBOARD',
		font: {fontSize: 14, fontWeight: 'bold'},
		color: '#eeeeee',
		height:30,
		textAlign: 'left',
		left: 10,
		top:10
	});

	var leaderTable = Ti.UI.createTableView({
		top: 40,
		borderRadius: 10,
		scrollable:false,
		disableBounce: true,
		width: 290,
		height: 'auto',
		zIndex: 10,
		separatorColor: 'transparent'
	});

	var createLeaderBoardView = function(leaderBoardData) {
		var myIndex = 0;
		userRankInfo = [];
		for(i=0; i<leaderBoardData.length; i++) {
			if(leaderBoardData[i].user_id===curId) {
				myIndex=i;
				break;
			}
		};
		for(var i=0; i<leaderBoardData.length; i++) {
			if(leaderBoardData[i].totalPoint <= 0) break; //not including people who get 0

			var userRank = Ti.UI.createTableViewRow({
				backgroundColor: '#eeeeee',
				height: 45,
				selectedBackgroundColor: '#53b4df',
				color: '#666'
			});

			var userRankNo = Ti.UI.createLabel({
				text: '#' + (i+1),
				left: 15,
				height:30,
				font: { fontWeight: 'bold', fontSize: 14},
				color: '#666'
			});

			var userRankPicture = Ti.UI.createImageView({
				height: 36,
				width: 36,
				borderRadius: 5,
				left: 40
			});

			userRank.user_id = leaderBoardData[i].user_id;

			if(leaderBoardData[i].fb_id) {
				userRankPicture.image = acs.getUserImageSquareOfFbId(leaderBoardData[i].fb_id);
			}
			else userRankPicture.image = "images/kuma100x100.png";

			var userRankName = Ti.UI.createLabel({
				text: leaderBoardData[i].name,
				left: 90,
				width: 150,
				height: 20,
				font: {fontWeight: 'bold', fontSize: 14},
				color: '#666'
			});

			var userRankScore = Ti.UI.createLabel({
				text: leaderBoardData[i].totalPoint,
				//top: 10,
				right: 5,
				width: 'auto',
				textAlign: 'right',
				height: 30,
				font: {fontWeight: 'bold', fontSize: 26},
				color: '#666'
			});

			if(i===myIndex) {
				userRank.selectedBackgroundColor = '#eeeeee';
				userRankNo.color = '#000';
				userRankName.color = '#000';
				userRankScore.color = '#000';
			};

			userRank.add(userRankNo);
			userRank.add(userRankPicture);
			userRank.add(userRankName);
			userRank.add(userRankScore);
			userRankInfo.push(userRank);
		}

		leaderTable.height = (userRankInfo.length)*45;
		leaderTable.data = userRankInfo;
		leaderTable.bottom = 10;
		profileStats.height = expSec.height + leaderSec.height;
	} //end of function: createLeaderBoardView

	expSec.add(expLabel);
	expSec.add(myLevelLabel);
	expSec.add(expBar_light);
	expSec.add(expBar);
	profileStats.add(expSec);

	if(_status==="me") {
		var friendLoadedCallBack = function(e){
			FriendModel.friendModel_updateFriendsFromACS(e.fetchedFriends);
		}

		var leaderBoardLoadedCallBack = function(e) {
			PointModel.pointModel_updateLeadersFromACS(e.fetchedLeader);
		}

		var friendsDbUpdatedCallBack = function() {
			var rankList = [];
			rankList[0] = _userProfile.id;
			var myFriends = FriendModel.friendModel_fetchFriend(rankList[0]);
			for(var i = 0; i< myFriends.length;i++) {
				var curUser = myFriends[i].friend_id;
				rankList.push(curUser);
			};
			var LeaderACS = require('acs/leaderBoardACS');
			LeaderACS.leaderACS_fetchedRank(rankList);
		}

		var leaderDbUpdatedCallBack = function() {
			var leaderBoardData = PointModel.pointModel_fetchRank();
			leaderBoardData.sort(totalPointSort);
	    	createLeaderBoardView(leaderBoardData);
	    	addMoreFriend(leaderBoardData);
	    	updateExpBar();

		    if(_status==="me") {
				Ti.API.info("cache");
				var totalPoints = PointModel.pointModel_fetchMyPoint(curId);
				myLevel = LevelModel.level_checkLevel(totalPoints);
				var CacheHelper = require('helpers/cacheHelper');
				CacheHelper.levelUpCache("level"+acs.getUserId(),myLevel);
			}
		}
		var addMoreFriend = function(_data) {
			if(_data.length<=10 &&_data.length>=0) {
				var addFriendLabel = Ti.UI.createLabel({
					text: ' + add friends...',
					top: 0,
					font: {fontSize: 14, fontWeight: 'bold'},
					color: '#fff',
					height: 30, width: 110,
					zIndex: 2
				});
				var addFriendView = Ti.UI.createView({
					backgroundColor: '#53b4df',
					right: 11, top: 15,
					width: 120, height: 50,
					borderRadius: 10,
					zIndex: 1
				});
			addFriendView.add(addFriendLabel);
			leaderSec.add(addFriendView);
			addFriendLabel.addEventListener('click',function() {
				var AddFriendMainWindow = require('ui/common/Pf_AddFriendMainWindow');
				var addFriendMainWindow = new AddFriendMainWindow(_parentWindow);
				_parentWindow.containingTab.open(addFriendMainWindow);
			});
			}
		}

		Ti.App.addEventListener('levelDbUpdated', function(){
			updateExpBar();
		});
		Ti.App.addEventListener('friendsLoaded',friendLoadedCallBack);
		Ti.App.addEventListener('leaderBoardLoaded',leaderBoardLoadedCallBack);
		Ti.App.addEventListener('friendsDbUpdated',friendsDbUpdatedCallBack);
		Ti.App.addEventListener('leaderDbUpdated',leaderDbUpdatedCallBack);

		leaderTable.addEventListener('click',function(e){
			if(e.rowData.user_id!==curId) _parentWindow.containingTab.open(new ProfileMainWindow(e.rowData.user_id,"friend"));
		});

		leaderSec.add(leaderLabel);
		leaderSec.add(leaderTable);
		profileStats.add(leaderSec);

   } else updateExpBar();
    //end of condition: "me"

	return profileStats;
}

module.exports = ProfileStatsView;<commit_msg>clean<commit_after>var ProfileStatsView = function(_parentWindow, _userProfile, _status){
	var PointModel = require('model/point');
	var LevelModel = require('model/level');
	var FriendModel = require('model/friend');

	var ProfileMainWindow = require('ui/common/Pf_ProfileMainWindow');
	var curId = _userProfile.id;

	var profileStats = Ti.UI.createView({
		backgroundColor: 'transparent',
		bottom: 10,
		height: 'auto',
	});

	var expSec = Ti.UI.createView({
		top: 5
	});

	var leaderSec = Ti.UI.createView({
			top:50
	});

	//experience point
	var expLabel = Ti.UI.createLabel({
		font: {fontSize: 14, fontWeight: 'bold'},
		color: '#fff',
		textAlign: 'right',
		top: 0,
		height:30,
		right: 10
	});

	var myLevelLabel = Ti.UI.createLabel({
		text: '',
		font: {fontSize: 16, fontWeight: 'bold'},
		color: '#53b4df',
		textAlign: 'left',
		height:30,
		top: 0,
		left: 10,
	});

    var expBar = Ti.UI.createSlider({
		top:25,
		width:300,
		min:0,
		thumbImage: 'images/slider/thumb_bar.png',
		leftTrackImage:'images/slider/slider_bar.png',
		rightTrackImage:'images/slider/slider_emptybar.png',
		touchEnabled: false,
		backgroundColor: 'transparent',
    });

	var expBar_light = Ti.UI.createSlider({
		top:25,
		width:300,
		min:0,
		thumbImage: 'images/slider/thumb_nextbar.png',
		leftTrackImage:'images/slider/slider_nextbar.png',
		rightTrackImage:'images/slider/slider_lightbar.png',
		touchEnabled: false,
    });

	//sort from max totalPoint
	function totalPointSort(a,b) {
		return b.totalPoint - a.totalPoint;
	}

	var updateExpBar = function() {
		var totalPoints = PointModel.pointModel_fetchMyPoint(curId);
		var profileDataLevelUp = LevelModel.level_nextLevel(totalPoints);
		expLabel.text = totalPoints + '/' + profileDataLevelUp;
		expBar.max = profileDataLevelUp;
		expBar_light.max = profileDataLevelUp;
		expBar.value = totalPoints;

		if(expBar.value === 0) expBar.thumbImage = 'images/empty_thumb.png';
		else expBar.thumbImage = 'images/slider/thumb_bar.png';

		myLevel = LevelModel.level_checkLevel(totalPoints);
		myLevelLabel.text = myLevel;
		expBar_light.value = (totalPoints+5);

	}

	var leaderLabel = Ti.UI.createLabel({
		text:'LEADERBOARD',
		font: {fontSize: 14, fontWeight: 'bold'},
		color: '#eeeeee',
		height:30,
		textAlign: 'left',
		left: 10,
		top:10
	});

	var leaderTable = Ti.UI.createTableView({
		top: 40,
		borderRadius: 10,
		scrollable:false,
		disableBounce: true,
		width: 290,
		height: 'auto',
		zIndex: 10,
		separatorColor: 'transparent'
	});

	var createLeaderBoardView = function(leaderBoardData) {
		var myIndex = 0;
		userRankInfo = [];
		for(i=0; i<leaderBoardData.length; i++) {
			if(leaderBoardData[i].user_id===curId) {
				myIndex=i;
				break;
			}
		};
		for(var i=0; i<leaderBoardData.length; i++) {
			if(leaderBoardData[i].totalPoint <= 0) break; //not including people who get 0

			var userRank = Ti.UI.createTableViewRow({
				backgroundColor: '#eeeeee',
				height: 45,
				selectedBackgroundColor: '#53b4df',
				color: '#666'
			});

			var userRankNo = Ti.UI.createLabel({
				text: '#' + (i+1),
				left: 15,
				height:30,
				font: { fontWeight: 'bold', fontSize: 14},
				color: '#666'
			});

			var userRankPicture = Ti.UI.createImageView({
				height: 36,
				width: 36,
				borderRadius: 5,
				left: 40
			});

			userRank.user_id = leaderBoardData[i].user_id;

			if(leaderBoardData[i].fb_id) {
				userRankPicture.image = acs.getUserImageSquareOfFbId(leaderBoardData[i].fb_id);
			}
			else userRankPicture.image = "images/kuma100x100.png";

			var userRankName = Ti.UI.createLabel({
				text: leaderBoardData[i].name,
				left: 90,
				width: 150,
				height: 20,
				font: {fontWeight: 'bold', fontSize: 14},
				color: '#666'
			});

			var userRankScore = Ti.UI.createLabel({
				text: leaderBoardData[i].totalPoint,
				//top: 10,
				right: 5,
				width: 'auto',
				textAlign: 'right',
				height: 30,
				font: {fontWeight: 'bold', fontSize: 26},
				color: '#666'
			});

			if(i===myIndex) {
				userRank.selectedBackgroundColor = '#eeeeee';
				userRankNo.color = '#000';
				userRankName.color = '#000';
				userRankScore.color = '#000';
			};

			userRank.add(userRankNo);
			userRank.add(userRankPicture);
			userRank.add(userRankName);
			userRank.add(userRankScore);
			userRankInfo.push(userRank);
		}

		leaderTable.height = (userRankInfo.length)*45;
		leaderTable.data = userRankInfo;
		leaderTable.bottom = 10;
		profileStats.height = expSec.height + leaderSec.height;
	} //end of function: createLeaderBoardView

	expSec.add(expLabel);
	expSec.add(myLevelLabel);
	expSec.add(expBar_light);
	expSec.add(expBar);
	profileStats.add(expSec);

	if(_status==="me") {
		var friendLoadedCallBack = function(e){
			FriendModel.friendModel_updateFriendsFromACS(e.fetchedFriends);
		};

		var leaderBoardLoadedCallBack = function(e) {
			PointModel.pointModel_updateLeadersFromACS(e.fetchedLeader);
		};

		var friendsDbUpdatedCallBack = function() {
			var rankList = [];
			rankList[0] = _userProfile.id;
			var myFriends = FriendModel.friendModel_fetchFriend(rankList[0]);
			for(var i = 0; i< myFriends.length;i++) {
				var curUser = myFriends[i].friend_id;
				rankList.push(curUser);
			};
			var LeaderACS = require('acs/leaderBoardACS');
			LeaderACS.leaderACS_fetchedRank(rankList);
		};

		var leaderDbUpdatedCallBack = function() {
			var leaderBoardData = PointModel.pointModel_fetchRank();
			leaderBoardData.sort(totalPointSort);
	    	createLeaderBoardView(leaderBoardData);
	    	addMoreFriend(leaderBoardData);
	    	updateExpBar();

		    if(_status==="me") {
				Ti.API.info("cache");
				var totalPoints = PointModel.pointModel_fetchMyPoint(curId);
				myLevel = LevelModel.level_checkLevel(totalPoints);
				var CacheHelper = require('helpers/cacheHelper');
				CacheHelper.levelUpCache("level"+acs.getUserId(),myLevel);
			}
		};

		var addMoreFriend = function(_data) {
			if(_data.length<=10 &&_data.length>=0) {
				var addFriendLabel = Ti.UI.createLabel({
					text: ' + add friends...',
					top: 0,
					font: {fontSize: 14, fontWeight: 'bold'},
					color: '#fff',
					height: 30, width: 110,
					zIndex: 2
				});
				var addFriendView = Ti.UI.createView({
					backgroundColor: '#53b4df',
					right: 11, top: 15,
					width: 120, height: 50,
					borderRadius: 10,
					zIndex: 1
				});
				addFriendView.add(addFriendLabel);
				leaderSec.add(addFriendView);
				addFriendLabel.addEventListener('click',function() {
					var AddFriendMainWindow = require('ui/common/Pf_AddFriendMainWindow');
					var addFriendMainWindow = new AddFriendMainWindow(_parentWindow);
					_parentWindow.containingTab.open(addFriendMainWindow);
				});
			}
		};

		Ti.App.addEventListener('levelDbUpdated', function(){
			updateExpBar();
		});
		Ti.App.addEventListener('friendsLoaded',friendLoadedCallBack);
		Ti.App.addEventListener('leaderBoardLoaded',leaderBoardLoadedCallBack);
		Ti.App.addEventListener('friendsDbUpdated',friendsDbUpdatedCallBack);
		Ti.App.addEventListener('leaderDbUpdated',leaderDbUpdatedCallBack);

		leaderTable.addEventListener('click',function(e){
			if(e.rowData.user_id!==curId)
				_parentWindow.containingTab.open(new ProfileMainWindow(e.rowData.user_id,"friend"));
		});

		leaderSec.add(leaderLabel);
		leaderSec.add(leaderTable);
		profileStats.add(leaderSec);

   } else updateExpBar();
    //end of condition: "me"

	return profileStats;
}

module.exports = ProfileStatsView;<|endoftext|>


<commit_before>window.onresize = doLayout;

onload = function() {
  var browser = document.querySelector('browser');
  doLayout();

  document.querySelector('#back').onclick = function() {
    browser.back();
  };

  document.querySelector('#forward').onclick = function() {
    browser.forward();
  };

  document.querySelector('#home').onclick = function() {
    navigateTo('http://www.google.com/');
  };

  document.querySelector('#reload').onclick = function() {
    browser.reload();
  };
  document.querySelector('#reload').addEventListener(
    'webkitAnimationIteration',
    function() {
      if (!isLoading) {
        document.body.classList.remove('loading');
      }
    });

  document.querySelector('#terminate').onclick = function() {
    browser.terminate();
  };

  document.querySelector('#location-form').onsubmit = function(e) {
    e.preventDefault();
    navigateTo(document.querySelector('#location').value);
  };

  browser.addEventListener('exit', handleExit);
  browser.addEventListener('loadstart', handleLoadStart);
  browser.addEventListener('loadstop', handleLoadStop);
  browser.addEventListener('loadabort', handleLoadAbort);
  browser.addEventListener('loadredirect', handleLoadRedirect);
  browser.addEventListener('loadcommit', handleLoadCommit);
};

function navigateTo(url) {
  resetExitedState();
  document.querySelector('browser').src = url;
}

function doLayout() {
  var browser = document.querySelector('browser');
  var controls = document.querySelector('#controls');
  var controlsHeight = controls.offsetHeight;
  var windowWidth = document.documentElement.clientWidth;
  var windowHeight = document.documentElement.clientHeight;
  browser.width = windowWidth;
  browser.height = windowHeight - controlsHeight;

  var sadBrowser = document.querySelector('#sad-browser');
  sadBrowser.style.width = browser.width + 'px';
  sadBrowser.style.height = browser.height * 2/3 + 'px';
  sadBrowser.style.paddingTop = browser.height/3 + 'px';
}

function handleExit(event) {
  console.log(event.type);
  document.body.classList.add('exited');
  if (event.type == 'abnormal') {
    document.body.classList.add('crashed');
  } else if (event.type == 'killed') {
    document.body.classList.add('killed');
  }
}

function resetExitedState() {
  document.body.classList.remove('exited');
  document.body.classList.remove('crashed');
  document.body.classList.remove('killed');
}

function handleLoadCommit(event) {
  resetExitedState();
  if (!event.isTopLevel) {
    return;
  }

  document.querySelector('#location').value = event.url;

  var browser = document.querySelector('browser');
  document.querySelector('#back').disabled = !browser.canGoBack();
  document.querySelector('#forward').disabled = !browser.canGoForward();
}

function handleLoadStart(event) {
  document.body.classList.add('loading');
  isLoading = true;

  resetExitedState();
  if (!event.isTopLevel) {
    return;
  }

  document.querySelector('#location').value = event.url;
}

function handleLoadStop(event) {
  // We don't remove the loading class immediately, instead we let the animation
  // finish, so that the spinner doesn't jerkily reset back to the 0 position.
  isLoading = false;
}

function handleLoadAbort(event) {
  console.log('oadAbort');
  console.log('  url: ' + event.url);
  console.log('  isTopLevel: ' + event.isTopLevel);
  console.log('  type: ' + event.type);
}

function handleLoadRedirect(event) {
  resetExitedState();
  if (!event.isTopLevel) {
    return;
  }

  document.querySelector('#location').value = event.newUrl;
}
<commit_msg>Reload button becomes a stop button while the page is loading<commit_after>window.onresize = doLayout;
var isLoading = false;

onload = function() {
  var browser = document.querySelector('browser');
  doLayout();

  document.querySelector('#back').onclick = function() {
    browser.back();
  };

  document.querySelector('#forward').onclick = function() {
    browser.forward();
  };

  document.querySelector('#home').onclick = function() {
    navigateTo('http://www.google.com/');
  };

  document.querySelector('#reload').onclick = function() {
    if (isLoading) {
      browser.stop();
    } else {
      browser.reload();
    }
  };
  document.querySelector('#reload').addEventListener(
    'webkitAnimationIteration',
    function() {
      if (!isLoading) {
        document.body.classList.remove('loading');
      }
    });

  document.querySelector('#terminate').onclick = function() {
    browser.terminate();
  };

  document.querySelector('#location-form').onsubmit = function(e) {
    e.preventDefault();
    navigateTo(document.querySelector('#location').value);
  };

  browser.addEventListener('exit', handleExit);
  browser.addEventListener('loadstart', handleLoadStart);
  browser.addEventListener('loadstop', handleLoadStop);
  browser.addEventListener('loadabort', handleLoadAbort);
  browser.addEventListener('loadredirect', handleLoadRedirect);
  browser.addEventListener('loadcommit', handleLoadCommit);
};

function navigateTo(url) {
  resetExitedState();
  document.querySelector('browser').src = url;
}

function doLayout() {
  var browser = document.querySelector('browser');
  var controls = document.querySelector('#controls');
  var controlsHeight = controls.offsetHeight;
  var windowWidth = document.documentElement.clientWidth;
  var windowHeight = document.documentElement.clientHeight;
  browser.width = windowWidth;
  browser.height = windowHeight - controlsHeight;

  var sadBrowser = document.querySelector('#sad-browser');
  sadBrowser.style.width = browser.width + 'px';
  sadBrowser.style.height = browser.height * 2/3 + 'px';
  sadBrowser.style.paddingTop = browser.height/3 + 'px';
}

function handleExit(event) {
  console.log(event.type);
  document.body.classList.add('exited');
  if (event.type == 'abnormal') {
    document.body.classList.add('crashed');
  } else if (event.type == 'killed') {
    document.body.classList.add('killed');
  }
}

function resetExitedState() {
  document.body.classList.remove('exited');
  document.body.classList.remove('crashed');
  document.body.classList.remove('killed');
}

function handleLoadCommit(event) {
  resetExitedState();
  if (!event.isTopLevel) {
    return;
  }

  document.querySelector('#location').value = event.url;

  var browser = document.querySelector('browser');
  document.querySelector('#back').disabled = !browser.canGoBack();
  document.querySelector('#forward').disabled = !browser.canGoForward();
}

function handleLoadStart(event) {
  document.body.classList.add('loading');
  isLoading = true;

  resetExitedState();
  if (!event.isTopLevel) {
    return;
  }

  document.querySelector('#location').value = event.url;
}

function handleLoadStop(event) {
  // We don't remove the loading class immediately, instead we let the animation
  // finish, so that the spinner doesn't jerkily reset back to the 0 position.
  isLoading = false;
}

function handleLoadAbort(event) {
  console.log('oadAbort');
  console.log('  url: ' + event.url);
  console.log('  isTopLevel: ' + event.isTopLevel);
  console.log('  type: ' + event.type);
}

function handleLoadRedirect(event) {
  resetExitedState();
  if (!event.isTopLevel) {
    return;
  }

  document.querySelector('#location').value = event.newUrl;
}
<|endoftext|>