<commit_before>// Copyright 2016-2016, University of Colorado Boulder

/**
 * A group of alignment boxes that follow the constraints:
 * 1. Every box will have the same bounds, with an upper-left of (0,0)
 * 2. The box sizes will be the smallest possible to fit every box's content (with respective padding).
 * 3. Each box is responsible for positioning its content in its bounds (with customizable alignment and padding).
 *
 * Align boxes can be dynamically created and disposed, and only active boxes will be considered for the bounds.
 *
 * NOTE: Align box resizes may not happen immediately, and may be delayed until bounds of a align box's child occurs.
 *       layout updates can be forced with group.updateLayout(). If the align box's content that changed is connected
 *       to a Scenery display, its bounds will update when Display.updateDisplay() will called, so this will guarantee
 *       that the layout will be applied before it is displayed.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

define( function( require ) {
  'use strict';

  var inherit = require( 'PHET_CORE/inherit' );
  var arrayRemove = require( 'PHET_CORE/arrayRemove' );
  var scenery = require( 'SCENERY/scenery' );
  var Bounds2 = require( 'DOT/Bounds2' );
  var Node = require( 'SCENERY/nodes/Node' );
  var AlignBox = require( 'SCENERY/nodes/AlignBox' );

  var globalId = 1;

  /**
   * Creates an alignment group that can be composed of multiple boxes.
   * @constructor
   * @public
   *
   * Use createBox() to create alignment boxes. You can dispose() individual boxes, or call dispose() on this
   * group to dispose all of them.
   *
   * It is also possible to create AlignBox instances independently and assign their 'group' to this AlignGroup.
   *
   * @param {Object} [options]
   */
  function AlignGroup( options ) {
    options = _.extend( {
      matchHorizontal: true, // {boolean} - Whether the boxes should have all matching widths (otherwise it fits to size)
      matchVertical: true  // {boolean} - Whether the boxes should have all matching heights (otherwise it fits to size)
    }, options );

    assert && assert( typeof options.matchHorizontal === 'boolean' );
    assert && assert( typeof options.matchVertical === 'boolean' );

    // @private {Array.<AlignBox>}
    this._alignBoxes = [];

    // @private {boolean}
    this._matchHorizontal = options.matchHorizontal;

    // @private {boolean}
    this._matchVertical = options.matchVertical;

    // @private {boolean} - Gets locked when certain layout is performed.
    this._resizeLock = false;

    // @private {number}
    this.id = globalId++;
  }

  scenery.register( 'AlignGroup', AlignGroup );

  inherit( Object, AlignGroup, {
    /**
     * Creates an alignment box with the given content and options.
     * @public
     *
     * @param {Node} content - Note that the content may be repositioned into place.
     * @param {Object} [options] - See AlignBox's constructor below for specific alignment options (it will be passed
     *                             through to the constructed AlignBox).
     */
    createBox: function( content, options ) {
      assert && assert( content instanceof Node );

      // Setting the group should call our addAlignBox()
      return new AlignBox( content, _.extend( {
        group: this
      }, options ) );
    },

    /**
     * Sets whether the widths of the align boxes should all match. If false, each box will use its preferred width
     * (usually equal to the content width + horizontal margins).
     * @public
     *
     * @param {boolean} matchHorizontal
     * @returns {AlignGroup} - For chaining
     */
    setMatchHorizontal: function( matchHorizontal ) {
      assert && assert( typeof matchHorizontal === 'boolean' );

      if ( this._matchHorizontal !== matchHorizontal ) {
        this._matchHorizontal = matchHorizontal;

        // Update layout, since it will probably change
        this.updateLayout();
      }

      return this;
    },
    set matchHorizontal( value ) { this.setMatchHorizontal( value ); },

    /**
     * Returns whether boxes currently are horizontally matched. See setMatchHorizontal() for details.
     * @public
     *
     * @returns {boolean}
     */
    getMatchHorizontal: function() {
      return this._matchHorizontal;
    },
    get matchHorizontal() { return this.getMatchHorizontal(); },

    /**
     * Sets whether the heights of the align boxes should all match. If false, each box will use its preferred height
     * (usually equal to the content height + vertical margins).
     * @public
     *
     * @param {boolean} matchVertical
     * @returns {AlignGroup} - For chaining
     */
    setMatchVertical: function( matchVertical ) {
      assert && assert( typeof matchVertical === 'boolean' );

      if ( this._matchVertical !== matchVertical ) {
        this._matchVertical = matchVertical;

        // Update layout, since it will probably change
        this.updateLayout();
      }

      return this;
    },
    set matchVertical( value ) { this.setMatchVertical( value ); },

    /**
     * Returns whether boxes currently are vertically matched. See setMatchVertical() for details.
     * @public
     *
     * @returns {boolean}
     */
    getMatchVertical: function() {
      return this._matchVertical;
    },
    get matchVertical() { return this.getMatchVertical(); },

    /**
     * Dispose all of the boxes.
     * @public
     */
    dispose: function() {
      for ( var i = this._alignBoxes.length - 1; i >= 0; i-- ) {
        this._alignBoxes[ i ].dispose();
      }
    },

    /**
     * Updates the localBounds and alignment for each alignBox.
     * @public
     *
     * NOTE: Calling this will usually not be necessary outside of Scenery, but this WILL trigger bounds revalidation
     *       for every alignBox, which can force the layout code to run.
     */
    updateLayout: function() {
      if ( this._resizeLock ) { return; }
      this._resizeLock = true;

      sceneryLog && sceneryLog.AlignGroup && sceneryLog.AlignGroup(
        'AlignGroup#' + this.id + ' updateLayout' );
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.push();

      sceneryLog && sceneryLog.AlignGroup && sceneryLog.AlignGroup( 'AlignGroup computing maximum dimension' );
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.push();

      // Compute the maximum dimension of our alignBoxs' content
      var maxWidth = 0;
      var maxHeight = 0;
      for ( var i = 0; i < this._alignBoxes.length; i++ ) {
        var alignBox = this._alignBoxes[ i ];

        var bounds = alignBox.getContentBounds();

        // Ignore bad bounds
        if ( bounds.isEmpty() || !bounds.isFinite() ) {
          continue;
        }

        maxWidth = Math.max( maxWidth, bounds.width );
        maxHeight = Math.max( maxHeight, bounds.height );
      }

      sceneryLog && sceneryLog.AlignGroup && sceneryLog.pop();
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.AlignGroup( 'AlignGroup applying to boxes' );
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.push();

      if ( maxWidth > 0 && maxHeight > 0 ) {
        // Apply that maximum dimension for each alignBox
        for ( i = 0; i < this._alignBoxes.length; i++ ) {
          this.setBoxBounds( this._alignBoxes[ i ], maxWidth, maxHeight );
        }
      }

      sceneryLog && sceneryLog.AlignGroup && sceneryLog.pop();
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.pop();

      this._resizeLock = false;
    },

    /**
     * Sets a box's bounds based on our maximum dimensions.
     * @private
     *
     * @param {AlignBox} alignBox
     * @param {number} maxWidth
     * @param {number} maxHeight
     */
    setBoxBounds: function( alignBox, maxWidth, maxHeight ) {
      var alignBounds;

      // If we match both dimensions, we don't have to inspect the box's preferred size
      if ( this._matchVertical && this._matchHorizontal ) {
        alignBounds = new Bounds2( 0, 0, maxWidth, maxHeight );
      }
      else {
        // Grab the preferred size
        var contentBounds = alignBox.getContentBounds();

        // Match one orientation
        if ( this._matchVertical ) {
          alignBounds = new Bounds2( 0, 0, contentBounds.width, maxHeight );
        }
        else if ( this._matchHorizontal ) {
          alignBounds = new Bounds2( 0, 0, maxWidth, contentBounds.height );
        }
        // If not matching anything, just use its preferred size
        else {
          alignBounds = contentBounds;
        }
      }

      alignBox.alignBounds = alignBounds;
    },

    /**
     * Lets the group know that the alignBox has had its content resized.
     * @private
     *
     * @param {AlignBox} alignBox
     */
    onAlignBoxResized: function( alignBox ) {
      // TODO: in the future, we could only update this specific alignBox if the others don't need updating.
      this.updateLayout();
    },

    /**
     * Adds the AlignBox to the group
     * @private
     *
     * @param {AlignBox} alignBox
     */
    addAlignBox: function( alignBox ) {
      this._alignBoxes.push( alignBox );

      // Trigger an update when a alignBox is added
      this.updateLayout();
    },

    /**
     * Removes the AlignBox from the group
     * @private
     *
     * @param {AlignBox} alignBox
     */
    removeAlignBox: function( alignBox ) {
      arrayRemove( this._alignBoxes, alignBox );

      // Trigger an update when a alignBox is removed
      this.updateLayout();
    }
  } );

  return AlignGroup;
} );
<commit_msg>Added docs<commit_after>// Copyright 2016-2016, University of Colorado Boulder

/**
 * A group of alignment boxes that follow the constraints:
 * 1. Every box will have the same bounds, with an upper-left of (0,0)
 * 2. The box sizes will be the smallest possible to fit every box's content (with respective padding).
 * 3. Each box is responsible for positioning its content in its bounds (with customizable alignment and padding).
 *
 * Align boxes can be dynamically created and disposed, and only active boxes will be considered for the bounds.
 *
 * Since many sun components do not support resizing their contents dynamically, you may need to populate the AlignGroup
 * in the order of largest to smallest so that a fixed size container is large enough to contain the largest item.
 *
 * NOTE: Align box resizes may not happen immediately, and may be delayed until bounds of a align box's child occurs.
 *       layout updates can be forced with group.updateLayout(). If the align box's content that changed is connected
 *       to a Scenery display, its bounds will update when Display.updateDisplay() will called, so this will guarantee
 *       that the layout will be applied before it is displayed.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

define( function( require ) {
  'use strict';

  var inherit = require( 'PHET_CORE/inherit' );
  var arrayRemove = require( 'PHET_CORE/arrayRemove' );
  var scenery = require( 'SCENERY/scenery' );
  var Bounds2 = require( 'DOT/Bounds2' );
  var Node = require( 'SCENERY/nodes/Node' );
  var AlignBox = require( 'SCENERY/nodes/AlignBox' );

  var globalId = 1;

  /**
   * Creates an alignment group that can be composed of multiple boxes.
   * @constructor
   * @public
   *
   * Use createBox() to create alignment boxes. You can dispose() individual boxes, or call dispose() on this
   * group to dispose all of them.
   *
   * It is also possible to create AlignBox instances independently and assign their 'group' to this AlignGroup.
   *
   * @param {Object} [options]
   */
  function AlignGroup( options ) {
    options = _.extend( {
      matchHorizontal: true, // {boolean} - Whether the boxes should have all matching widths (otherwise it fits to size)
      matchVertical: true  // {boolean} - Whether the boxes should have all matching heights (otherwise it fits to size)
    }, options );

    assert && assert( typeof options.matchHorizontal === 'boolean' );
    assert && assert( typeof options.matchVertical === 'boolean' );

    // @private {Array.<AlignBox>}
    this._alignBoxes = [];

    // @private {boolean}
    this._matchHorizontal = options.matchHorizontal;

    // @private {boolean}
    this._matchVertical = options.matchVertical;

    // @private {boolean} - Gets locked when certain layout is performed.
    this._resizeLock = false;

    // @private {number}
    this.id = globalId++;
  }

  scenery.register( 'AlignGroup', AlignGroup );

  inherit( Object, AlignGroup, {
    /**
     * Creates an alignment box with the given content and options.
     * @public
     *
     * @param {Node} content - Note that the content may be repositioned into place.
     * @param {Object} [options] - See AlignBox's constructor below for specific alignment options (it will be passed
     *                             through to the constructed AlignBox).
     */
    createBox: function( content, options ) {
      assert && assert( content instanceof Node );

      // Setting the group should call our addAlignBox()
      return new AlignBox( content, _.extend( {
        group: this
      }, options ) );
    },

    /**
     * Sets whether the widths of the align boxes should all match. If false, each box will use its preferred width
     * (usually equal to the content width + horizontal margins).
     * @public
     *
     * @param {boolean} matchHorizontal
     * @returns {AlignGroup} - For chaining
     */
    setMatchHorizontal: function( matchHorizontal ) {
      assert && assert( typeof matchHorizontal === 'boolean' );

      if ( this._matchHorizontal !== matchHorizontal ) {
        this._matchHorizontal = matchHorizontal;

        // Update layout, since it will probably change
        this.updateLayout();
      }

      return this;
    },
    set matchHorizontal( value ) { this.setMatchHorizontal( value ); },

    /**
     * Returns whether boxes currently are horizontally matched. See setMatchHorizontal() for details.
     * @public
     *
     * @returns {boolean}
     */
    getMatchHorizontal: function() {
      return this._matchHorizontal;
    },
    get matchHorizontal() { return this.getMatchHorizontal(); },

    /**
     * Sets whether the heights of the align boxes should all match. If false, each box will use its preferred height
     * (usually equal to the content height + vertical margins).
     * @public
     *
     * @param {boolean} matchVertical
     * @returns {AlignGroup} - For chaining
     */
    setMatchVertical: function( matchVertical ) {
      assert && assert( typeof matchVertical === 'boolean' );

      if ( this._matchVertical !== matchVertical ) {
        this._matchVertical = matchVertical;

        // Update layout, since it will probably change
        this.updateLayout();
      }

      return this;
    },
    set matchVertical( value ) { this.setMatchVertical( value ); },

    /**
     * Returns whether boxes currently are vertically matched. See setMatchVertical() for details.
     * @public
     *
     * @returns {boolean}
     */
    getMatchVertical: function() {
      return this._matchVertical;
    },
    get matchVertical() { return this.getMatchVertical(); },

    /**
     * Dispose all of the boxes.
     * @public
     */
    dispose: function() {
      for ( var i = this._alignBoxes.length - 1; i >= 0; i-- ) {
        this._alignBoxes[ i ].dispose();
      }
    },

    /**
     * Updates the localBounds and alignment for each alignBox.
     * @public
     *
     * NOTE: Calling this will usually not be necessary outside of Scenery, but this WILL trigger bounds revalidation
     *       for every alignBox, which can force the layout code to run.
     */
    updateLayout: function() {
      if ( this._resizeLock ) { return; }
      this._resizeLock = true;

      sceneryLog && sceneryLog.AlignGroup && sceneryLog.AlignGroup(
        'AlignGroup#' + this.id + ' updateLayout' );
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.push();

      sceneryLog && sceneryLog.AlignGroup && sceneryLog.AlignGroup( 'AlignGroup computing maximum dimension' );
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.push();

      // Compute the maximum dimension of our alignBoxs' content
      var maxWidth = 0;
      var maxHeight = 0;
      for ( var i = 0; i < this._alignBoxes.length; i++ ) {
        var alignBox = this._alignBoxes[ i ];

        var bounds = alignBox.getContentBounds();

        // Ignore bad bounds
        if ( bounds.isEmpty() || !bounds.isFinite() ) {
          continue;
        }

        maxWidth = Math.max( maxWidth, bounds.width );
        maxHeight = Math.max( maxHeight, bounds.height );
      }

      sceneryLog && sceneryLog.AlignGroup && sceneryLog.pop();
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.AlignGroup( 'AlignGroup applying to boxes' );
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.push();

      if ( maxWidth > 0 && maxHeight > 0 ) {
        // Apply that maximum dimension for each alignBox
        for ( i = 0; i < this._alignBoxes.length; i++ ) {
          this.setBoxBounds( this._alignBoxes[ i ], maxWidth, maxHeight );
        }
      }

      sceneryLog && sceneryLog.AlignGroup && sceneryLog.pop();
      sceneryLog && sceneryLog.AlignGroup && sceneryLog.pop();

      this._resizeLock = false;
    },

    /**
     * Sets a box's bounds based on our maximum dimensions.
     * @private
     *
     * @param {AlignBox} alignBox
     * @param {number} maxWidth
     * @param {number} maxHeight
     */
    setBoxBounds: function( alignBox, maxWidth, maxHeight ) {
      var alignBounds;

      // If we match both dimensions, we don't have to inspect the box's preferred size
      if ( this._matchVertical && this._matchHorizontal ) {
        alignBounds = new Bounds2( 0, 0, maxWidth, maxHeight );
      }
      else {
        // Grab the preferred size
        var contentBounds = alignBox.getContentBounds();

        // Match one orientation
        if ( this._matchVertical ) {
          alignBounds = new Bounds2( 0, 0, contentBounds.width, maxHeight );
        }
        else if ( this._matchHorizontal ) {
          alignBounds = new Bounds2( 0, 0, maxWidth, contentBounds.height );
        }
        // If not matching anything, just use its preferred size
        else {
          alignBounds = contentBounds;
        }
      }

      alignBox.alignBounds = alignBounds;
    },

    /**
     * Lets the group know that the alignBox has had its content resized.
     * @private
     *
     * @param {AlignBox} alignBox
     */
    onAlignBoxResized: function( alignBox ) {
      // TODO: in the future, we could only update this specific alignBox if the others don't need updating.
      this.updateLayout();
    },

    /**
     * Adds the AlignBox to the group
     * @private
     *
     * @param {AlignBox} alignBox
     */
    addAlignBox: function( alignBox ) {
      this._alignBoxes.push( alignBox );

      // Trigger an update when a alignBox is added
      this.updateLayout();
    },

    /**
     * Removes the AlignBox from the group
     * @private
     *
     * @param {AlignBox} alignBox
     */
    removeAlignBox: function( alignBox ) {
      arrayRemove( this._alignBoxes, alignBox );

      // Trigger an update when a alignBox is removed
      this.updateLayout();
    }
  } );

  return AlignGroup;
} );
<|endoftext|>


<commit_before>'use strict';

/**
 * Test for our homemade named router
 * @author William Gozali <will.gozali@cermati.com>
 */

var chai = require('chai');
var rewire = require('rewire');
var sinon = require('sinon');
var sinonChai = require('sinon-chai');
chai.use(sinonChai);

var expect = chai.expect;

describe('router/index.js', function () {
  describe('[METHOD]()', function () {
    var app = {
      get: function () {},
      post: function () {},
      all: function () {},
      use: function () {}
    };

    var router;
    var realFunctions;
    var sampleMiddleware;
    var sampleController;

    before('add spy to express\' routes registration function', function () {
      realFunctions = {};
      realFunctions.get = app.get;
      realFunctions.post = app.post;
      realFunctions.all = app.all;
      realFunctions.use = app.use;

      app.get = sinon.spy();
      app.post = sinon.spy();
      app.all = sinon.spy();
      app.use = sinon.spy();

      router = require('../index')(app);
    });

    before('register routing', function () {
      sampleMiddleware = function (req, res, next) {
        return next();
      };
      sampleController = {
        list: function (req, res) {
          res.send('test.list');
        },
        save: function (req, res) {
          res.send('test.save');
        }
      };

      router.use('/just-middleware', sampleMiddleware);
      router.use('middleware', '/named-middleware', sampleMiddleware);
      router.use('middlewares', '/named-middlewares', sampleMiddleware, sampleMiddleware);

      router.all('/forAll*', sampleMiddleware);
      router.get('list', '/', sampleController.list);
      router.post('save', '/:title/save', sampleController.save);
    });

    after('revert express\' routes registration function', function () {
      app.get = realFunctions.get;
      app.post = realFunctions.post;
      app.all = realFunctions.all;
      app.use = realFunctions.use;
    });

    context('when routes is registered with use method', function () {
      it('should have called app.use', function () {
        expect(app.use).to.have.been.calledWith('/just-middleware', [sampleMiddleware]);
        expect(app.use).to.have.been.calledWith('/named-middleware', [sampleMiddleware]);
        expect(app.use).to.have.been.calledWith('/named-middlewares', [sampleMiddleware, sampleMiddleware]);
      });
    });

    context('when routes is registered with all method', function () {
      it('should have called app.all', function () {
        expect(app.all).to.have.been.calledWith('/forAll*', [sampleMiddleware]);
      });
    });

    context('when routes is registered with get method', function () {
      it('should have called app.get', function () {
        expect(app.get).to.have.been.calledWith('/', [sampleController.list]);
      });
    });

    context('when routes is registered with post method', function () {
      it('should have called app.post', function () {
        expect(app.post).to.have.been.calledWith('/:title/save', [sampleController.save]);
      });
    });
  });

  describe('.buildRouteNames()', function () {
    var PUSH;
    var POP;

    before('get push and pop constant', function () {
      var constants = require('..//constants');
      PUSH = constants.PUSH;
      POP = constants.POP;
    });

    context('when given simple routing', function () {
      var app;
      var router;
      var routeTable;

      before('create fake simple routing traversal', function () {
        app = {};

        // We want to modify router's routeTable, which is private field
        // That's why we use rewire, instead of require
        var wiredRoute = rewire('../index');

        // Create router object
        router = wiredRoute(app);

        app.routeTraversal = [
          {operation: PUSH, name: 'foo', path: '/foo'},
          {operation: POP, name: 'foo', path: '/foo'},
          {operation: PUSH, name: 'bar', path: '/bar/bar'},
          {operation: POP, name: 'bar', path: '/bar/bar'},
          {operation: PUSH, name: 'baz', path: '/baz/:input'},
          {operation: POP, name: 'baz', path: '/baz/:input'}
        ];

        router.buildRouteNames();
        routeTable = wiredRoute.__get__('routeTable');
      });
      it('should build the route table successfully', function () {
        expect(routeTable['foo'].pattern).to.equal('/foo');
        expect(routeTable['bar'].pattern).to.equal('/bar/bar');
        expect(routeTable['baz'].pattern).to.equal('/baz/:input');
      });
    });

    context('when given nested routing', function () {
      var app;
      var router;
      var routeTable;

      before('create fake nested routing traversal', function () {
        app = {};
        var wiredRoute = rewire('../index');
        router = wiredRoute(app);

        app.routeTraversal = [
          {operation: PUSH, name: 'foo', path: '/foo'},
          {operation: PUSH, name: 'foo-deep', path: '/foo-deep'},
          {operation: PUSH, name: 'foo-deeper', path: '/foo-deeper'},
          {operation: POP, name: 'foo-deeper', path: '/foo-deeper'},
          {operation: POP, name: 'foo-deep', path: '/foo-deep'},
          {operation: PUSH, name: 'foo-deep-2', path: '/foo-deep-2'},
          {operation: POP, name: 'foo-deep-2', path: '/foo-deep-2'},
          {operation: POP, name: 'foo', path: '/foo'},
          {operation: PUSH, name: 'bar', path: '/bar'},
          {operation: PUSH, name: 'detail', path: '/detail/:input'},
          {operation: POP, name: 'detail', path: '/detail/:input'},
          {operation: POP, name: 'bar', path: '/bar'}
        ];

        router.buildRouteNames();
        routeTable = wiredRoute.__get__('routeTable');
      });
      it('Non terminal route should be undefined', function () {
        expect(routeTable['foo']).to.be.undefined;
        expect(routeTable['foo.foo-deep']).to.be.undefined;
        expect(routeTable['bar']).to.be.undefined;
      });

      it('Terminal route should be registered in routeTable', function () {
        expect(routeTable['foo.foo-deep.foo-deeper'].pattern).to.equal('/foo/foo-deep/foo-deeper');
        expect(routeTable['bar.detail'].pattern).to.equal('/bar/detail/:input');
      });
    });

    context('when given nested routing with root routes', function () {
      var app;
      var router;
      var routeTable;

      before('create fake nested routing traversal with root routes', function () {
        app = {};
        var wiredRoute = rewire('../index');
        router = wiredRoute(app);

        app.routeTraversal = [
          {operation: PUSH, name: 'foo', path: '/foo'},
          {operation: PUSH, name: 'list', path: '/'},
          {operation: POP, name: 'list', path: '/'},
          {operation: PUSH, name: 'detail', path: '/:input'},
          {operation: POP, name: 'detail', path: '/:input'},
          {operation: PUSH, name: 'list-category', path: '/category/:category'},
          {operation: POP, name: 'list-category', path: '/category/:category'},
          {operation: POP, name: 'foo', path: '/foo'},

          {operation: PUSH, name: '1', path: '/1'},
          {operation: PUSH, name: '1-end', path: '/end'},
          {operation: POP, name: '1-end', path: '/end'},
          {operation: PUSH, name: '1-bypass', path: '/'},
          {operation: PUSH, name: '3', path: '/3'},
          {operation: POP, name: '3', path: '/3'},
          {operation: POP, name: '1-bypass', path: '/'},
          {operation: PUSH, name: '2', path: '/2'},
          {operation: PUSH, name: '3', path: '/3'},
          {operation: POP, name: '3', path: '/3'},
          {operation: POP, name: '2', path: '/2'},
          {operation: POP, name: '1', path: '/1'}
        ];

        router.buildRouteNames();
        routeTable = wiredRoute.__get__('routeTable');
      });

      it('Non terminal route should be undefined', function () {
        expect(routeTable['foo']).to.be.undefined;
        expect(routeTable['1']).to.be.undefined;
        expect(routeTable['1.1-bypass']).to.be.undefined;
        expect(routeTable['1.2']).to.be.undefined;
      });

      it('Terminal route should be registered in routeTable', function () {
        expect(routeTable['foo.list'].pattern).to.equal('/foo');
        expect(routeTable['foo.detail'].pattern).to.equal('/foo/:input');
        expect(routeTable['foo.list-category'].pattern).to.equal('/foo/category/:category');

        expect(routeTable['1.1-end'].pattern).to.equal('/1/end');
        expect(routeTable['1.1-bypass.3'].pattern).to.equal('/1/3');
        expect(routeTable['1.2.3'].pattern).to.equal('/1/2/3');
      });
    });
  });

  describe('.urlFor()', function () {
    var urlFor;
    var routeTable;
    var router;
    var revert;

    before('initialize table and inject it to router', function () {
      router = rewire('../index');

      routeTable = {};
      routeTable['foo'] = {
        pattern: '/foo',
        tokens: [{text: ''}, {text: 'foo'}]
      };
      routeTable['foo.list'] = {
        pattern: '/foo',
        tokens: [{text: ''}, {text: 'foo'}]
      };
      routeTable['foo.detail'] = {
        pattern: '/foo/:input',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'input', input: true}]
      };
      routeTable['foo.list-category'] = {
        pattern: '/foo/category/:category',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'category'}, {text: 'category', input: true}]
      };
      routeTable['foo.list-category.detail'] = {
        pattern: '/foo/category/:category/:slug',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'category'}, {text: 'category', input: true}, {text: 'slug', input: true}]
      };
      routeTable['weird.doubled.input'] = {
        pattern: '/foo/:input/bun/:input',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'input', input: true}, {text: 'bun'}, {text: 'input', input: true}]
      };

      revert = router.__set__('routeTable', routeTable);
      urlFor = router.urlFor;
    });

    after('clean up rewire', function () {
      revert();
    });

    context('when route does not need any input', function () {
      it('should return the route normally', function () {
        expect(urlFor('foo')).to.equal('/foo');
        expect(urlFor('foo.list')).to.equal('/foo');
      });
    });

    context('when route does need some inputs', function () {
      it('should return the route normally', function () {
        expect(urlFor('foo.detail', {input: 'bar'})).to.equal('/foo/bar');
        expect(urlFor('foo.list-category', {category: 'troll'})).to.equal('/foo/category/troll');
        expect(urlFor('foo.list-category.detail', {category: 'orc', slug: 'blade-master'})).to.equal('/foo/category/orc/blade-master');
        expect(urlFor('weird.doubled.input', {input: 'twin'})).to.equal('/foo/twin/bun/twin');
      });

      it('should return throw error when input is incomplete', function () {
        expect(function () {
          urlFor('foo.list-category', {unknownInput: 'troll'});
        }).to.throw(Error);

        expect(function () {
          urlFor('foo.list-category.detail', {category: 'one-input-is-missing'});
        }).to.throw(Error);
      });
    });

    context('when given queries', function () {
      it('should return the url with queries appended in the end', function () {
        expect(urlFor('foo', {}, {})).to.equal('/foo?');
        expect(urlFor('foo', {}, {bar: 'baz'})).to.equal('/foo?bar=baz');
        expect(urlFor('foo', {}, {bar: 'baz', 'fuu-uu': 'rage'})).to.equal('/foo?bar=baz&fuu-uu=rage');

        expect(urlFor('foo.list-category', {category: 'ogre'}, {})).to.equal('/foo/category/ogre?');
        expect(urlFor('foo.list-category', {category: 'ogre'}, {class: 'magi'})).to.equal('/foo/category/ogre?class=magi');
        expect(urlFor('foo.list-category', {category: 'ogre'}, {class: 'magi', size: 'big'})).to.equal('/foo/category/ogre?class=magi&size=big');

        expect(urlFor('foo', {}, {list: [1, 2, 3]})).to.equal('/foo?list=1&list=2&list=3');
      });
    });

    context('when route name does not exist', function () {
      it('should throw error', function () {
        expect(function () {
          urlFor('fuu');
        }).to.throw(Error);
      });
    });

    context('when given falsy parameter', function () {
      it('should return the url with falsy parameter', function () {
        expect(urlFor('foo.list-category', {category: 0})).to.equal('/foo/category/0');
      });
    });
  });
});
<commit_msg>Add test for absoluteUrlFor<commit_after>'use strict';

/**
 * Test for our homemade named router
 * @author William Gozali <will.gozali@cermati.com>
 */

var chai = require('chai');
var rewire = require('rewire');
var sinon = require('sinon');
var sinonChai = require('sinon-chai');
chai.use(sinonChai);

var expect = chai.expect;

describe('router/index.js', function () {
  describe('[METHOD]()', function () {
    var app = {
      get: function () {},
      post: function () {},
      all: function () {},
      use: function () {}
    };

    var router;
    var realFunctions;
    var sampleMiddleware;
    var sampleController;

    before('add spy to express\' routes registration function', function () {
      realFunctions = {};
      realFunctions.get = app.get;
      realFunctions.post = app.post;
      realFunctions.all = app.all;
      realFunctions.use = app.use;

      app.get = sinon.spy();
      app.post = sinon.spy();
      app.all = sinon.spy();
      app.use = sinon.spy();

      router = require('../index')(app);
    });

    before('register routing', function () {
      sampleMiddleware = function (req, res, next) {
        return next();
      };
      sampleController = {
        list: function (req, res) {
          res.send('test.list');
        },
        save: function (req, res) {
          res.send('test.save');
        }
      };

      router.use('/just-middleware', sampleMiddleware);
      router.use('middleware', '/named-middleware', sampleMiddleware);
      router.use('middlewares', '/named-middlewares', sampleMiddleware, sampleMiddleware);

      router.all('/forAll*', sampleMiddleware);
      router.get('list', '/', sampleController.list);
      router.post('save', '/:title/save', sampleController.save);
    });

    after('revert express\' routes registration function', function () {
      app.get = realFunctions.get;
      app.post = realFunctions.post;
      app.all = realFunctions.all;
      app.use = realFunctions.use;
    });

    context('when routes is registered with use method', function () {
      it('should have called app.use', function () {
        expect(app.use).to.have.been.calledWith('/just-middleware', [sampleMiddleware]);
        expect(app.use).to.have.been.calledWith('/named-middleware', [sampleMiddleware]);
        expect(app.use).to.have.been.calledWith('/named-middlewares', [sampleMiddleware, sampleMiddleware]);
      });
    });

    context('when routes is registered with all method', function () {
      it('should have called app.all', function () {
        expect(app.all).to.have.been.calledWith('/forAll*', [sampleMiddleware]);
      });
    });

    context('when routes is registered with get method', function () {
      it('should have called app.get', function () {
        expect(app.get).to.have.been.calledWith('/', [sampleController.list]);
      });
    });

    context('when routes is registered with post method', function () {
      it('should have called app.post', function () {
        expect(app.post).to.have.been.calledWith('/:title/save', [sampleController.save]);
      });
    });
  });

  describe('.buildRouteNames()', function () {
    var PUSH;
    var POP;

    before('get push and pop constant', function () {
      var constants = require('..//constants');
      PUSH = constants.PUSH;
      POP = constants.POP;
    });

    context('when given simple routing', function () {
      var app;
      var router;
      var routeTable;

      before('create fake simple routing traversal', function () {
        app = {};

        // We want to modify router's routeTable, which is private field
        // That's why we use rewire, instead of require
        var wiredRoute = rewire('../index');

        // Create router object
        router = wiredRoute(app);

        app.routeTraversal = [
          {operation: PUSH, name: 'foo', path: '/foo'},
          {operation: POP, name: 'foo', path: '/foo'},
          {operation: PUSH, name: 'bar', path: '/bar/bar'},
          {operation: POP, name: 'bar', path: '/bar/bar'},
          {operation: PUSH, name: 'baz', path: '/baz/:input'},
          {operation: POP, name: 'baz', path: '/baz/:input'}
        ];

        router.buildRouteNames();
        routeTable = wiredRoute.__get__('routeTable');
      });
      it('should build the route table successfully', function () {
        expect(routeTable['foo'].pattern).to.equal('/foo');
        expect(routeTable['bar'].pattern).to.equal('/bar/bar');
        expect(routeTable['baz'].pattern).to.equal('/baz/:input');
      });
    });

    context('when given nested routing', function () {
      var app;
      var router;
      var routeTable;

      before('create fake nested routing traversal', function () {
        app = {};
        var wiredRoute = rewire('../index');
        router = wiredRoute(app);

        app.routeTraversal = [
          {operation: PUSH, name: 'foo', path: '/foo'},
          {operation: PUSH, name: 'foo-deep', path: '/foo-deep'},
          {operation: PUSH, name: 'foo-deeper', path: '/foo-deeper'},
          {operation: POP, name: 'foo-deeper', path: '/foo-deeper'},
          {operation: POP, name: 'foo-deep', path: '/foo-deep'},
          {operation: PUSH, name: 'foo-deep-2', path: '/foo-deep-2'},
          {operation: POP, name: 'foo-deep-2', path: '/foo-deep-2'},
          {operation: POP, name: 'foo', path: '/foo'},
          {operation: PUSH, name: 'bar', path: '/bar'},
          {operation: PUSH, name: 'detail', path: '/detail/:input'},
          {operation: POP, name: 'detail', path: '/detail/:input'},
          {operation: POP, name: 'bar', path: '/bar'}
        ];

        router.buildRouteNames();
        routeTable = wiredRoute.__get__('routeTable');
      });
      it('Non terminal route should be undefined', function () {
        expect(routeTable['foo']).to.be.undefined;
        expect(routeTable['foo.foo-deep']).to.be.undefined;
        expect(routeTable['bar']).to.be.undefined;
      });

      it('Terminal route should be registered in routeTable', function () {
        expect(routeTable['foo.foo-deep.foo-deeper'].pattern).to.equal('/foo/foo-deep/foo-deeper');
        expect(routeTable['bar.detail'].pattern).to.equal('/bar/detail/:input');
      });
    });

    context('when given nested routing with root routes', function () {
      var app;
      var router;
      var routeTable;

      before('create fake nested routing traversal with root routes', function () {
        app = {};
        var wiredRoute = rewire('../index');
        router = wiredRoute(app);

        app.routeTraversal = [
          {operation: PUSH, name: 'foo', path: '/foo'},
          {operation: PUSH, name: 'list', path: '/'},
          {operation: POP, name: 'list', path: '/'},
          {operation: PUSH, name: 'detail', path: '/:input'},
          {operation: POP, name: 'detail', path: '/:input'},
          {operation: PUSH, name: 'list-category', path: '/category/:category'},
          {operation: POP, name: 'list-category', path: '/category/:category'},
          {operation: POP, name: 'foo', path: '/foo'},

          {operation: PUSH, name: '1', path: '/1'},
          {operation: PUSH, name: '1-end', path: '/end'},
          {operation: POP, name: '1-end', path: '/end'},
          {operation: PUSH, name: '1-bypass', path: '/'},
          {operation: PUSH, name: '3', path: '/3'},
          {operation: POP, name: '3', path: '/3'},
          {operation: POP, name: '1-bypass', path: '/'},
          {operation: PUSH, name: '2', path: '/2'},
          {operation: PUSH, name: '3', path: '/3'},
          {operation: POP, name: '3', path: '/3'},
          {operation: POP, name: '2', path: '/2'},
          {operation: POP, name: '1', path: '/1'}
        ];

        router.buildRouteNames();
        routeTable = wiredRoute.__get__('routeTable');
      });

      it('Non terminal route should be undefined', function () {
        expect(routeTable['foo']).to.be.undefined;
        expect(routeTable['1']).to.be.undefined;
        expect(routeTable['1.1-bypass']).to.be.undefined;
        expect(routeTable['1.2']).to.be.undefined;
      });

      it('Terminal route should be registered in routeTable', function () {
        expect(routeTable['foo.list'].pattern).to.equal('/foo');
        expect(routeTable['foo.detail'].pattern).to.equal('/foo/:input');
        expect(routeTable['foo.list-category'].pattern).to.equal('/foo/category/:category');

        expect(routeTable['1.1-end'].pattern).to.equal('/1/end');
        expect(routeTable['1.1-bypass.3'].pattern).to.equal('/1/3');
        expect(routeTable['1.2.3'].pattern).to.equal('/1/2/3');
      });
    });
  });

  describe('.urlFor()', function () {
    var urlFor;
    var routeTable;
    var router;
    var revert;

    before('initialize table and inject it to router', function () {
      router = rewire('../index');

      routeTable = {};
      routeTable['foo'] = {
        pattern: '/foo',
        tokens: [{text: ''}, {text: 'foo'}]
      };
      routeTable['foo.list'] = {
        pattern: '/foo',
        tokens: [{text: ''}, {text: 'foo'}]
      };
      routeTable['foo.detail'] = {
        pattern: '/foo/:input',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'input', input: true}]
      };
      routeTable['foo.list-category'] = {
        pattern: '/foo/category/:category',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'category'}, {text: 'category', input: true}]
      };
      routeTable['foo.list-category.detail'] = {
        pattern: '/foo/category/:category/:slug',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'category'}, {text: 'category', input: true}, {text: 'slug', input: true}]
      };
      routeTable['weird.doubled.input'] = {
        pattern: '/foo/:input/bun/:input',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'input', input: true}, {text: 'bun'}, {text: 'input', input: true}]
      };

      revert = router.__set__('routeTable', routeTable);
      urlFor = router.urlFor;
    });

    after('clean up rewire', function () {
      revert();
    });

    context('when route does not need any input', function () {
      it('should return the route normally', function () {
        expect(urlFor('foo')).to.equal('/foo');
        expect(urlFor('foo.list')).to.equal('/foo');
      });
    });

    context('when route does need some inputs', function () {
      it('should return the route normally', function () {
        expect(urlFor('foo.detail', {input: 'bar'})).to.equal('/foo/bar');
        expect(urlFor('foo.list-category', {category: 'troll'})).to.equal('/foo/category/troll');
        expect(urlFor('foo.list-category.detail', {category: 'orc', slug: 'blade-master'})).to.equal('/foo/category/orc/blade-master');
        expect(urlFor('weird.doubled.input', {input: 'twin'})).to.equal('/foo/twin/bun/twin');
      });

      it('should return throw error when input is incomplete', function () {
        expect(function () {
          urlFor('foo.list-category', {unknownInput: 'troll'});
        }).to.throw(Error);

        expect(function () {
          urlFor('foo.list-category.detail', {category: 'one-input-is-missing'});
        }).to.throw(Error);
      });
    });

    context('when given queries', function () {
      it('should return the url with queries appended in the end', function () {
        expect(urlFor('foo', {}, {})).to.equal('/foo?');
        expect(urlFor('foo', {}, {bar: 'baz'})).to.equal('/foo?bar=baz');
        expect(urlFor('foo', {}, {bar: 'baz', 'fuu-uu': 'rage'})).to.equal('/foo?bar=baz&fuu-uu=rage');

        expect(urlFor('foo.list-category', {category: 'ogre'}, {})).to.equal('/foo/category/ogre?');
        expect(urlFor('foo.list-category', {category: 'ogre'}, {class: 'magi'})).to.equal('/foo/category/ogre?class=magi');
        expect(urlFor('foo.list-category', {category: 'ogre'}, {class: 'magi', size: 'big'})).to.equal('/foo/category/ogre?class=magi&size=big');

        expect(urlFor('foo', {}, {list: [1, 2, 3]})).to.equal('/foo?list=1&list=2&list=3');
      });
    });

    context('when route name does not exist', function () {
      it('should throw error', function () {
        expect(function () {
          urlFor('fuu');
        }).to.throw(Error);
      });
    });

    context('when given falsy parameter', function () {
      it('should return the url with falsy parameter', function () {
        expect(urlFor('foo.list-category', {category: 0})).to.equal('/foo/category/0');
      });
    });
  });

  describe('.absoluteUrlFor()', function () {
    var absoluteUrlFor;
    var routeTable;
    var router;
    var revert;

    before('initialize table and inject it to router', function () {
      router = rewire('../index');

      routeTable = {};
      routeTable['foo'] = {
        pattern: '/foo',
        tokens: [{text: ''}, {text: 'foo'}]
      };
      routeTable['foo.list'] = {
        pattern: '/foo',
        tokens: [{text: ''}, {text: 'foo'}]
      };
      routeTable['foo.detail'] = {
        pattern: '/foo/:input',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'input', input: true}]
      };
      routeTable['foo.list-category'] = {
        pattern: '/foo/category/:category',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'category'}, {text: 'category', input: true}]
      };
      routeTable['foo.list-category.detail'] = {
        pattern: '/foo/category/:category/:slug',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'category'}, {text: 'category', input: true}, {text: 'slug', input: true}]
      };
      routeTable['weird.doubled.input'] = {
        pattern: '/foo/:input/bun/:input',
        tokens: [{text: ''}, {text: 'foo'}, {text: 'input', input: true}, {text: 'bun'}, {text: 'input', input: true}]
      };

      revert = router.__set__('routeTable', routeTable);
      absoluteUrlFor = router.absoluteUrlFor;
    });

    after('clean up rewire', function () {
      revert();
    });

    context('when no baseUrl is set', function () {
      it('should throw error', function () {
        expect(function () {
          absoluteUrlFor('foo');
        }).to.throw(Error);

        expect(function () {
          absoluteUrlFor('nope');
        }).to.throw(Error);
      });
    });

    context('when baseUrl is set', function () {
      var baseUrl;

      before('set base URL', function () {
        baseUrl = 'http://www.cermati.com';
        router.setBaseUrl(baseUrl);
      });

      context('when route does not need any input', function () {
        it('should return the route normally', function () {
          expect(absoluteUrlFor('foo')).to.equal(baseUrl + '/foo');
          expect(absoluteUrlFor('foo.list')).to.equal(baseUrl + '/foo');
        });
      });

      context('when route does need some inputs', function () {
        it('should return the route normally', function () {
          expect(absoluteUrlFor('foo.detail', {input: 'bar'})).to.equal(baseUrl + '/foo/bar');
          expect(absoluteUrlFor('foo.list-category', {category: 'troll'})).to.equal(baseUrl + '/foo/category/troll');
          expect(absoluteUrlFor('foo.list-category.detail', {category: 'orc', slug: 'blade-master'})).to.equal(baseUrl + '/foo/category/orc/blade-master');
          expect(absoluteUrlFor('weird.doubled.input', {input: 'twin'})).to.equal(baseUrl + '/foo/twin/bun/twin');
        });

        it('should return throw error when input is incomplete', function () {
          expect(function () {
            absoluteUrlFor('foo.list-category', {unknownInput: 'troll'});
          }).to.throw(Error);

          expect(function () {
            absoluteUrlFor('foo.list-category.detail', {category: 'one-input-is-missing'});
          }).to.throw(Error);
        });
      });

      context('when given queries', function () {
        it('should return the url with queries appended in the end', function () {
          expect(absoluteUrlFor('foo', {}, {})).to.equal(baseUrl + '/foo?');
          expect(absoluteUrlFor('foo', {}, {bar: 'baz'})).to.equal(baseUrl + '/foo?bar=baz');
          expect(absoluteUrlFor('foo', {}, {bar: 'baz', 'fuu-uu': 'rage'})).to.equal(baseUrl + '/foo?bar=baz&fuu-uu=rage');

          expect(absoluteUrlFor('foo.list-category', {category: 'ogre'}, {})).to.equal(baseUrl + '/foo/category/ogre?');
          expect(absoluteUrlFor('foo.list-category', {category: 'ogre'}, {class: 'magi'})).to.equal(baseUrl + '/foo/category/ogre?class=magi');
          expect(absoluteUrlFor('foo.list-category', {category: 'ogre'}, {class: 'magi', size: 'big'})).to.equal(baseUrl + '/foo/category/ogre?class=magi&size=big');

          expect(absoluteUrlFor('foo', {}, {list: [1, 2, 3]})).to.equal(baseUrl + '/foo?list=1&list=2&list=3');
        });
      });

      context('when route name does not exist', function () {
        it('should throw error', function () {
          expect(function () {
            absoluteUrlFor('fuu');
          }).to.throw(Error);
        });
      });

      context('when given falsy parameter', function () {
        it('should return the url with falsy parameter', function () {
          expect(absoluteUrlFor('foo.list-category', {category: 0})).to.equal(baseUrl + '/foo/category/0');
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>$(function () {
    $(document).ready(function () {
        var server = $('input[name="hwaddr"]').val();
        var csrf = $('input[name="csrfmiddlewaretoken"]').val();
        var secret = $('input[name="secret"]').val();
        var address = '/ajax/server/' + server + '/metrics/cpu_usage/';

        function requestCpuUsageData(series, csrf, server, secret) {
		var address = '/ajax/server/' + server + '/metrics/cpu_usage/';
            $.ajax({
                url: address,
                type: 'POST',
                dataType: 'json',
                headers: {
                     'X-CSRFToken': csrf
                },
                cache: false,
                data: {
                    'server': server,
                    'secret': secret
                },
                success: function(data) {
			if (typeof element === 'undefined')
			    var element = [1,1];

			if (element[0] != data[0])
			    series.addPoint(data[0], true, true);

			element [0] = data [0];
                }
            });
        }

        function updateChart(series, csrf, server, secret) {
            setInterval(function() {
                requestCpuUsageData(series, csrf, server, secret);
            }, 1000);
        }

        Highcharts.setOptions({
            global: {
                useUTC: false
            }
        });

        $.ajax({
            url: address,
            type: 'POST',
            dataType: 'json',
            headers: {
                'X-CSRFToken': csrf
            },
            cache: false,
            data: {
                'server': server,
                'secret': secret
            },
            success: function(data) {
                var cpuUsageChart = new Highcharts.Chart({
                    chart: {
                        renderTo: 'cpu_usage',
                        events: {
                            load: function() {
                                updateChart(this.series[0], csrf, server, secret);
                            }
                        }
                    },
                    title: {
                        text: 'CPU Usage'
                    },
                    xAxis: {
                        type: 'datetime',
                        tickPixelInterval: 1000
                    },
                    yAxis: {
                        title: {
                            text: 'Value'
                        },
                    plotLines: [{
                        value: 0,
                    width: 1,
                    color: '#808080'
                    }]
                    },
                    tooltip: {
                        formatter: function () {
                            return '' + this.series.name + '
' +
                                Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '
' +
                                Highcharts.numberFormat(this.y, 2);
                        }
                    },
                    legend: {
                        enabled: false
                    },
                    exporting: {
                        enabled: false
                    },
                    series: [{
                        name: 'Random data',
                        data: data.reverse()
                    }]
                });
            }
        });
    });
});
<commit_msg>updated wording in the graphs_js<commit_after>$(function () {
    $(document).ready(function () {
        var server = $('input[name="hwaddr"]').val();
        var csrf = $('input[name="csrfmiddlewaretoken"]').val();
        var secret = $('input[name="secret"]').val();
        var address = '/ajax/server/' + server + '/metrics/cpu_usage/';

        function requestCpuUsageData(series, csrf, server, secret) {
		var address = '/ajax/server/' + server + '/metrics/cpu_usage/';
            $.ajax({
                url: address,
                type: 'POST',
                dataType: 'json',
                headers: {
                     'X-CSRFToken': csrf
                },
                cache: false,
                data: {
                    'server': server,
                    'secret': secret
                },
                success: function(data) {
			if (typeof element === 'undefined')
			    var element = [1,1];

			if (element[0] != data[0])
			    series.addPoint(data[0], true, true);

			element [0] = data [0];
                }
            });
        }

        function updateChart(series, csrf, server, secret) {
            setInterval(function() {
                requestCpuUsageData(series, csrf, server, secret);
            }, 1000);
        }

        Highcharts.setOptions({
            global: {
                useUTC: false
            }
        });

        $.ajax({
            url: address,
            type: 'POST',
            dataType: 'json',
            headers: {
                'X-CSRFToken': csrf
            },
            cache: false,
            data: {
                'server': server,
                'secret': secret
            },
            success: function(data) {
                var cpuUsageChart = new Highcharts.Chart({
                    chart: {
                        renderTo: 'cpu_usage',
                        events: {
                            load: function() {
                                updateChart(this.series[0], csrf, server, secret);
                            }
                        }
                    },
                    title: {
                        text: 'CPU Usage'
                    },
                    xAxis: {
                        type: 'datetime',
                        tickPixelInterval: 1000
                    },
                    yAxis: {
                        title: {
                            text: 'Value'
                        },
                    plotLines: [{
                        value: 0,
                    width: 1,
                    color: '#808080'
                    }]
                    },
                    tooltip: {
                        formatter: function () {
                            return '' + this.series.name + '
' +
                                Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '
' +
                                Highcharts.numberFormat(this.y, 2);
                        }
                    },
                    legend: {
                        enabled: false
                    },
                    exporting: {
                        enabled: false
                    },
                    series: [{
                        name: 'CPU Usage',
                        data: data.reverse()
                    }]
                });
            }
        });
    });
});
<|endoftext|>


<commit_before>function TaskList ($obj){
	this.tasks = [];
	this.element = $obj;
}

TaskList.prototype.add = function(task) {
	this.tasks.push(task);
};

TaskList.prototype.addEmptyTask = function() {
	var subject = new Subject('');
	var manHour = new ManHour('');
	var content = new Content('');
	var task = new Task(subject, manHour, content);
	this.tasks.push(task);

	this.refresh();
};

TaskList.prototype.remove = function(index) {
	var deleteLength = 1;
	this.tasks.splice(index, deleteLength);
};

TaskList.prototype.appendTasks = function($obj) {
	var length = this.tasks.length;
	for(var index = 0; index < length; ++index){
		this.tasks[index].append($obj);
	}
};

TaskList.prototype.refresh = function() {
	this.element.empty();
	this.appendTasks(this.element);
};

TaskList.prototype.draw = function(out, manHourPrefix) {
	var length = this.tasks.length;
	for (var index = 0; index < length; index++) {
		this.tasks[index].draw(out, manHourPrefix);
	}
};<commit_msg>Task.appendメソッド削除に伴いTaskListを修正<commit_after>function TaskList ($obj){
	this.tasks = [];
	this.element = $obj;
}

TaskList.prototype.add = function(task) {
	this.tasks.push(task);
};

TaskList.prototype.addEmptyTask = function() {
	var subject = new Subject('');
	var manHour = new ManHour('');
	var content = new Content('');
	var task = new Task(subject, manHour, content);
	this.tasks.push(task);

	this.refresh();
};

TaskList.prototype.remove = function(index) {
	var deleteLength = 1;
	this.tasks.splice(index, deleteLength);
};

TaskList.prototype.appendTasks = function($obj) {
	var length = this.tasks.length;
	for(var index = 0; index < length; ++index){
		$obj.append( this.tasks[index].tojQueryObject() );
	}
};

TaskList.prototype.refresh = function() {
	this.element.empty();
	this.appendTasks(this.element);
};

TaskList.prototype.draw = function(out, manHourPrefix) {
	var length = this.tasks.length;
	for (var index = 0; index < length; index++) {
		this.tasks[index].draw(out, manHourPrefix);
	}
};
<|endoftext|>


<commit_before>if (!DISABLE_JS) {

  htmlReplaceTable = {
    '<' : '<',
    '>' : '>'
  };

  var selectedThreadCell;
  var refreshingSideCatalog = false;
  var loadingThread = false;
  var sideCatalogBody = document.getElementById('sideCatalogBody');

  var sideCatalog = document.getElementById('sideCatalog');

  if (!localStorage.hideSideCatalog) {
    sideCatalog.style.display = 'block';
  }

  refreshSideCatalog();

  document.getElementById('closeSideCatalogButton').onclick = function() {
    sideCatalog.style.display = 'none';
    localStorage.setItem('hideSideCatalog', true);
  }

  var catalogButton = document.getElementById('navCatalog');

  var sideCatalogButton = document.createElement('a');
  sideCatalogButton.className = 'coloredIcon';
  sideCatalogButton.id = 'navSideCatalog';
  sideCatalogButton.innerHTML = 'side catalog';
  sideCatalogButton.onclick = function() {
    sideCatalog.style.display = 'block';
    localStorage.removeItem('hideSideCatalog');
  };

  catalogButton.parentNode.insertBefore(sideCatalogButton,
      catalogButton.nextSibling);

  catalogButton.parentNode.insertBefore(document.createTextNode(' '),
      catalogButton.nextSibling);

  var divider = document.createElement('span');
  divider.innerHTML = '/';
  catalogButton.parentNode.insertBefore(divider, catalogButton.nextSibling);

  catalogButton.parentNode.insertBefore(document.createTextNode(' '),
      catalogButton.nextSibling);

}

function removeAllFromClass(className) {

  var elements = document.getElementsByClassName(className);

  while (elements.length) {
    elements[0].remove();
  }

}

function removeIndicator(className) {

  var elements = document.getElementsByClassName(className);

  if (!elements.length) {
    return;
  }

  elements[0].nextSibling.remove();
  elements[0].remove();

}

function addIndicator(className, title) {

  var spanId = document.getElementsByClassName('spanId')[0];

  var indicator = document.createElement('span');
  indicator.className = className;
  indicator.title = title;

  spanId.parentNode.insertBefore(indicator, spanId.nextSibling);
  spanId.parentNode.insertBefore(document.createTextNode(' '),
      spanId.nextSibling);

}

function loadThread(cell, thread) {

  loadingThread = true;

  localRequest(
      document.getElementById('divMod') ? '/mod.js?boardUri=' + boardUri
          + '&threadId=' + thread.threadId + '&json=1' : '/' + boardUri
          + '/res/' + thread.threadId + '.json',
      function(error, data) {

        loadingThread = false;

        if (error) {
          return;
        }

        if (selectedThreadCell) {
          selectedThreadCell.className = 'sideCatalogCell';
        }

        selectedThreadCell = cell;

        selectedThreadCell.className = 'sideCatalogMarkedCell';

        knownPosts = {};
        window.history.pushState('', '',
            document.getElementById('divMod') ? '/mod.js?boardUri=' + boardUri
                + '&threadId=' + thread.threadId : '/' + boardUri + '/res/'
                + thread.threadId + '.html');

        document.getElementById('threadIdentifier').value = thread.threadId;

        if (document.getElementById('divMod')) {
          document.getElementById('controlThreadIdentifier').value = thread.threadId;
          document.getElementById('transferThreadIdentifier').value = thread.threadId;

          document.getElementById('checkboxLock').checked = thread.locked;
          document.getElementById('checkboxPin').checked = thread.pinned;
          document.getElementById('checkboxCyclic').checked = thread.cyclic;

        }

        document.title = '/' + boardUri + '/ - '
            + (thread.subject || thread.message);

        var opCell = document.getElementsByClassName('opCell')[0];

        opCell.scrollIntoView();

        document.getElementsByClassName('divPosts')[0].innerHTML = '';

        data = JSON.parse(data);

        opCell.id = thread.threadId;
        opCell.className = 'opCell';
        if (data.files && data.files.length > 1) {
          opCell.className += ' multipleUploads';
        }

        if (!opCell.getElementsByClassName('labelSubject').length) {

          var newSubjectLabel = document.createElement('span');
          newSubjectLabel.className = 'labelSubject';

          var watchButton = document.getElementsByClassName('watchButton')[0];
          watchButton.parentNode.insertBefore(newSubjectLabel,
              watchButton.nextSibling);
          watchButton.parentNode.insertBefore(document.createTextNode(' '),
              watchButton.nextSibling);

        }

        var divMessage = document.getElementsByClassName('divMessage')[0];

        if (!opCell.getElementsByClassName('labelLastEdit').length) {

          var newBanMessageLabel = document.createElement('div');
          newBanMessageLabel.className = 'labelLastEdit';

          divMessage.parentNode.insertBefore(newBanMessageLabel,
              divMessage.nextSibling);

        }

        if (!opCell.getElementsByClassName('panelIp').length) {

          var emptyPanel = document.getElementsByClassName('opHead')[0].nextSibling.nextSibling;

          var newIpPanel = document.createElement('span');
          newIpPanel.className = 'panelIp';

          var rangePanel = document.createElement('span');
          rangePanel.className = 'panelRange';
          rangePanel.innerHTML = 'Broad range(1/2 octets): '

          var broadRangeLabel = document.createElement('span');
          broadRangeLabel.className = 'labelBroadRange';

          rangePanel.appendChild(broadRangeLabel);

          rangePanel.appendChild(document.createElement('br'));

          rangePanel.appendChild(document
              .createTextNode('Narrow range(3/4 octets):'));

          var narrowRangeLabel = document.createElement('span');
          narrowRangeLabel.className = 'labelNarrowRange';

          rangePanel.appendChild(narrowRangeLabel);

          rangePanel.appendChild(document.createElement('br'));

          newIpPanel.appendChild(rangePanel);

          newIpPanel.appendChild(document.createTextNode('Ip:'));

          var newIpLabel = document.createElement('span');
          newIpLabel.className = 'labelIp';
          newIpPanel.appendChild(newIpLabel);

          emptyPanel.appendChild(newIpPanel);

        }

        if (!opCell.getElementsByClassName('imgFlag').length) {

          var newFlagImage = document.createElement('img');
          newFlagImage.className = 'imgFlag';

          var linkName = document.getElementsByClassName('linkName')[0];
          linkName.parentNode.insertBefore(newFlagImage, linkName.nextSibling);
          linkName.parentNode.insertBefore(document.createTextNode(' '),
              linkName.nextSibling);

        }

        if (!opCell.getElementsByClassName('labelRole').length) {

          var newLabelRole = document.createElement('span');
          newLabelRole.className = 'labelRole';

          var flagImage = document.getElementsByClassName('imgFlag')[0];
          flagImage.parentNode
              .insertBefore(newLabelRole, flagImage.nextSibling);
          flagImage.parentNode.insertBefore(document.createTextNode(' '),
              flagImage.nextSibling);

        }

        if (!opCell.getElementsByClassName('divBanMessage').length) {

          var newBanMessageLabel = document.createElement('div');
          newBanMessageLabel.className = 'divBanMessage';

          divMessage.parentNode.insertBefore(newBanMessageLabel,
              divMessage.nextSibling);

        }

        if (!opCell.getElementsByClassName('spanId').length) {

          var newSpanId = document.createElement('span');
          newSpanId.className = 'spanId';

          newSpanId.innerHTML = 'Id:';

          var newLabelId = document.createElement('span');
          newLabelId.className = 'labelId';
          newSpanId.appendChild(newLabelId);

          var labelCreated = document.getElementsByClassName('labelCreated')[0];
          labelCreated.parentNode.insertBefore(newSpanId,
              labelCreated.nextSibling);
          labelCreated.parentNode.insertBefore(document.createTextNode(' '),
              labelCreated.nextSibling);

        }

        document.getElementsByClassName('opUploadPanel')[0].innerHTML = '';

        document.getElementsByClassName('opHead')[0]
            .getElementsByClassName('deletionCheckBox')[0].value = boardUri
            + '-' + thread.threadId;

        removeAllFromClass('extraMenuButton');
        removeAllFromClass('hideMenu');
        removeAllFromClass('quoteTooltip');
        removeAllFromClass('extraMenu');
        removeAllFromClass('hideButton');
        removeAllFromClass('watchButton');

        removeIndicator('lockIndicator');
        removeIndicator('pinIndicator');
        removeIndicator('cyclicIndicator');

        addIndicator('cyclicIndicator', 'Cyclical Thread');
        addIndicator('pinIndicator', 'Sticky');
        addIndicator('lockIndicator', 'Locked');

        if (!thread.locked) {
          removeIndicator('lockIndicator');
        }

        if (!thread.pinned) {
          removeIndicator('pinIndicator');
        }

        if (!thread.cyclic) {
          removeIndicator('cyclicIndicator');
        }

        document.getElementsByClassName('panelBacklinks')[0].innerHTML = '';

        fullRefresh = true;

        initThread();

        setPostInnerElements(boardUri, threadId, data, opCell);

        processOP(document.getElementsByClassName('innerOP')[0]);

        if (data.posts && data.posts.length) {

          lastReplyId = data.posts[data.posts.length - 1].postId;

          for (var i = 0; i < data.posts.length; i++) {
            addPost(data.posts[i]);
          }

        }

      });

}

function addSideCatalogThread(thread) {

  var cell = document.createElement('a');

  if (threadId === thread.threadId) {
    cell.className = 'sideCatalogMarkedCell';
    selectedThreadCell = cell;
  } else {
    cell.className = 'sideCatalogCell';
  }

  cell.onclick = function() {

    if (loadingThread || thread.threadId === threadId) {
      return;
    }

    loadThread(cell, thread);

  };

  if (thread.thumb) {

    var img = document.createElement('img');

    img.src = thread.thumb;

    cell.appendChild(img);
  }

  var linkContent = document.createElement('span');
  linkContent.className = 'sideCatalogCellText';
  cell.appendChild(linkContent);

  var upperText = document.createElement('span');
  var lowerText = document.createElement('span');

  linkContent.appendChild(upperText);
  linkContent.appendChild(lowerText);

  upperText.innerHTML = (thread.subject || (thread.message.replace(/[<>]/g,
      function(match) {
        return htmlReplaceTable[match];
      }).substring(0, 128) || thread.threadId));

  lowerText.innerHTML = 'R: ' + (thread.postCount || 0) + ' / F: '
      + (thread.fileCount || 0);

  sideCatalogBody.appendChild(cell);

}

function refreshSideCatalog() {

  if (refreshingSideCatalog) {
    return;
  }

  refreshingSideCatalog = true;

  localRequest('/' + boardUri + '/catalog.json', function(error, data) {

    refreshingSideCatalog = false;

    if (error) {
      return;
    }

    data = JSON.parse(data);

    sideCatalogBody.innerHTML = '';

    for (var i = 0; i < data.length; i++) {

      if (i) {
        sideCatalogBody.appendChild(document.createElement('hr'));
      }

      addSideCatalogThread(data[i]);
    }

  });

}
<commit_msg>Fixed gallery mode when used after using the side catalog.<commit_after>if (!DISABLE_JS) {

  htmlReplaceTable = {
    '<' : '<',
    '>' : '>'
  };

  var selectedThreadCell;
  var refreshingSideCatalog = false;
  var loadingThread = false;
  var sideCatalogBody = document.getElementById('sideCatalogBody');

  var sideCatalog = document.getElementById('sideCatalog');

  if (!localStorage.hideSideCatalog) {
    sideCatalog.style.display = 'block';
  }

  refreshSideCatalog();

  document.getElementById('closeSideCatalogButton').onclick = function() {
    sideCatalog.style.display = 'none';
    localStorage.setItem('hideSideCatalog', true);
  }

  var catalogButton = document.getElementById('navCatalog');

  var sideCatalogButton = document.createElement('a');
  sideCatalogButton.className = 'coloredIcon';
  sideCatalogButton.id = 'navSideCatalog';
  sideCatalogButton.innerHTML = 'side catalog';
  sideCatalogButton.onclick = function() {
    sideCatalog.style.display = 'block';
    localStorage.removeItem('hideSideCatalog');
  };

  catalogButton.parentNode.insertBefore(sideCatalogButton,
      catalogButton.nextSibling);

  catalogButton.parentNode.insertBefore(document.createTextNode(' '),
      catalogButton.nextSibling);

  var divider = document.createElement('span');
  divider.innerHTML = '/';
  catalogButton.parentNode.insertBefore(divider, catalogButton.nextSibling);

  catalogButton.parentNode.insertBefore(document.createTextNode(' '),
      catalogButton.nextSibling);

}

function removeAllFromClass(className) {

  var elements = document.getElementsByClassName(className);

  while (elements.length) {
    elements[0].remove();
  }

}

function removeIndicator(className) {

  var elements = document.getElementsByClassName(className);

  if (!elements.length) {
    return;
  }

  elements[0].nextSibling.remove();
  elements[0].remove();

}

function addIndicator(className, title) {

  var spanId = document.getElementsByClassName('spanId')[0];

  var indicator = document.createElement('span');
  indicator.className = className;
  indicator.title = title;

  spanId.parentNode.insertBefore(indicator, spanId.nextSibling);
  spanId.parentNode.insertBefore(document.createTextNode(' '),
      spanId.nextSibling);

}

function loadThread(cell, thread) {

  loadingThread = true;

  localRequest(
      document.getElementById('divMod') ? '/mod.js?boardUri=' + boardUri
          + '&threadId=' + thread.threadId + '&json=1' : '/' + boardUri
          + '/res/' + thread.threadId + '.json',
      function(error, data) {

        loadingThread = false;

        if (error) {
          return;
        }

        if (selectedThreadCell) {
          selectedThreadCell.className = 'sideCatalogCell';
        }

        selectedThreadCell = cell;

        selectedThreadCell.className = 'sideCatalogMarkedCell';

        knownPosts = {};
        window.history.pushState('', '',
            document.getElementById('divMod') ? '/mod.js?boardUri=' + boardUri
                + '&threadId=' + thread.threadId : '/' + boardUri + '/res/'
                + thread.threadId + '.html');

        document.getElementById('threadIdentifier').value = thread.threadId;

        if (document.getElementById('divMod')) {
          document.getElementById('controlThreadIdentifier').value = thread.threadId;
          document.getElementById('transferThreadIdentifier').value = thread.threadId;

          document.getElementById('checkboxLock').checked = thread.locked;
          document.getElementById('checkboxPin').checked = thread.pinned;
          document.getElementById('checkboxCyclic').checked = thread.cyclic;

        }

        document.title = '/' + boardUri + '/ - '
            + (thread.subject || thread.message);

        var opCell = document.getElementsByClassName('opCell')[0];

        opCell.scrollIntoView();

        document.getElementsByClassName('divPosts')[0].innerHTML = '';

        data = JSON.parse(data);

        opCell.id = thread.threadId;
        opCell.className = 'opCell';
        if (data.files && data.files.length > 1) {
          opCell.className += ' multipleUploads';
        }

        if (!opCell.getElementsByClassName('labelSubject').length) {

          var newSubjectLabel = document.createElement('span');
          newSubjectLabel.className = 'labelSubject';

          var watchButton = document.getElementsByClassName('watchButton')[0];
          watchButton.parentNode.insertBefore(newSubjectLabel,
              watchButton.nextSibling);
          watchButton.parentNode.insertBefore(document.createTextNode(' '),
              watchButton.nextSibling);

        }

        var divMessage = document.getElementsByClassName('divMessage')[0];

        if (!opCell.getElementsByClassName('labelLastEdit').length) {

          var newBanMessageLabel = document.createElement('div');
          newBanMessageLabel.className = 'labelLastEdit';

          divMessage.parentNode.insertBefore(newBanMessageLabel,
              divMessage.nextSibling);

        }

        if (!opCell.getElementsByClassName('panelIp').length) {

          var emptyPanel = document.getElementsByClassName('opHead')[0].nextSibling.nextSibling;

          var newIpPanel = document.createElement('span');
          newIpPanel.className = 'panelIp';

          var rangePanel = document.createElement('span');
          rangePanel.className = 'panelRange';
          rangePanel.innerHTML = 'Broad range(1/2 octets): '

          var broadRangeLabel = document.createElement('span');
          broadRangeLabel.className = 'labelBroadRange';

          rangePanel.appendChild(broadRangeLabel);

          rangePanel.appendChild(document.createElement('br'));

          rangePanel.appendChild(document
              .createTextNode('Narrow range(3/4 octets):'));

          var narrowRangeLabel = document.createElement('span');
          narrowRangeLabel.className = 'labelNarrowRange';

          rangePanel.appendChild(narrowRangeLabel);

          rangePanel.appendChild(document.createElement('br'));

          newIpPanel.appendChild(rangePanel);

          newIpPanel.appendChild(document.createTextNode('Ip:'));

          var newIpLabel = document.createElement('span');
          newIpLabel.className = 'labelIp';
          newIpPanel.appendChild(newIpLabel);

          emptyPanel.appendChild(newIpPanel);

        }

        if (!opCell.getElementsByClassName('imgFlag').length) {

          var newFlagImage = document.createElement('img');
          newFlagImage.className = 'imgFlag';

          var linkName = document.getElementsByClassName('linkName')[0];
          linkName.parentNode.insertBefore(newFlagImage, linkName.nextSibling);
          linkName.parentNode.insertBefore(document.createTextNode(' '),
              linkName.nextSibling);

        }

        if (!opCell.getElementsByClassName('labelRole').length) {

          var newLabelRole = document.createElement('span');
          newLabelRole.className = 'labelRole';

          var flagImage = document.getElementsByClassName('imgFlag')[0];
          flagImage.parentNode
              .insertBefore(newLabelRole, flagImage.nextSibling);
          flagImage.parentNode.insertBefore(document.createTextNode(' '),
              flagImage.nextSibling);

        }

        if (!opCell.getElementsByClassName('divBanMessage').length) {

          var newBanMessageLabel = document.createElement('div');
          newBanMessageLabel.className = 'divBanMessage';

          divMessage.parentNode.insertBefore(newBanMessageLabel,
              divMessage.nextSibling);

        }

        if (!opCell.getElementsByClassName('spanId').length) {

          var newSpanId = document.createElement('span');
          newSpanId.className = 'spanId';

          newSpanId.innerHTML = 'Id:';

          var newLabelId = document.createElement('span');
          newLabelId.className = 'labelId';
          newSpanId.appendChild(newLabelId);

          var labelCreated = document.getElementsByClassName('labelCreated')[0];
          labelCreated.parentNode.insertBefore(newSpanId,
              labelCreated.nextSibling);
          labelCreated.parentNode.insertBefore(document.createTextNode(' '),
              labelCreated.nextSibling);

        }

        document.getElementsByClassName('opUploadPanel')[0].innerHTML = '';

        document.getElementsByClassName('opHead')[0]
            .getElementsByClassName('deletionCheckBox')[0].value = boardUri
            + '-' + thread.threadId;

        removeAllFromClass('extraMenuButton');
        removeAllFromClass('hideMenu');
        removeAllFromClass('quoteTooltip');
        removeAllFromClass('extraMenu');
        removeAllFromClass('hideButton');
        removeAllFromClass('watchButton');

        removeIndicator('lockIndicator');
        removeIndicator('pinIndicator');
        removeIndicator('cyclicIndicator');

        addIndicator('cyclicIndicator', 'Cyclical Thread');
        addIndicator('pinIndicator', 'Sticky');
        addIndicator('lockIndicator', 'Locked');

        if (!thread.locked) {
          removeIndicator('lockIndicator');
        }

        if (!thread.pinned) {
          removeIndicator('pinIndicator');
        }

        if (!thread.cyclic) {
          removeIndicator('cyclicIndicator');
        }

        document.getElementsByClassName('panelBacklinks')[0].innerHTML = '';

        fullRefresh = true;

        initThread();

        galleryFiles = [];
        currentIndex = 0;

        setPostInnerElements(boardUri, threadId, data, opCell);

        processOP(document.getElementsByClassName('innerOP')[0]);

        if (data.posts && data.posts.length) {

          lastReplyId = data.posts[data.posts.length - 1].postId;

          for (var i = 0; i < data.posts.length; i++) {
            addPost(data.posts[i]);
          }

        }

      });

}

function addSideCatalogThread(thread) {

  var cell = document.createElement('a');

  if (threadId === thread.threadId) {
    cell.className = 'sideCatalogMarkedCell';
    selectedThreadCell = cell;
  } else {
    cell.className = 'sideCatalogCell';
  }

  cell.onclick = function() {

    if (loadingThread || thread.threadId === threadId) {
      return;
    }

    loadThread(cell, thread);

  };

  if (thread.thumb) {

    var img = document.createElement('img');

    img.src = thread.thumb;

    cell.appendChild(img);
  }

  var linkContent = document.createElement('span');
  linkContent.className = 'sideCatalogCellText';
  cell.appendChild(linkContent);

  var upperText = document.createElement('span');
  var lowerText = document.createElement('span');

  linkContent.appendChild(upperText);
  linkContent.appendChild(lowerText);

  upperText.innerHTML = (thread.subject || (thread.message.replace(/[<>]/g,
      function(match) {
        return htmlReplaceTable[match];
      }).substring(0, 128) || thread.threadId));

  lowerText.innerHTML = 'R: ' + (thread.postCount || 0) + ' / F: '
      + (thread.fileCount || 0);

  sideCatalogBody.appendChild(cell);

}

function refreshSideCatalog() {

  if (refreshingSideCatalog) {
    return;
  }

  refreshingSideCatalog = true;

  localRequest('/' + boardUri + '/catalog.json', function(error, data) {

    refreshingSideCatalog = false;

    if (error) {
      return;
    }

    data = JSON.parse(data);

    sideCatalogBody.innerHTML = '';

    for (var i = 0; i < data.length; i++) {

      if (i) {
        sideCatalogBody.appendChild(document.createElement('hr'));
      }

      addSideCatalogThread(data[i]);
    }

  });

}
<|endoftext|>


<commit_before>const expect = require('expect.js');
const app = require('../app');

// empty value
const empty = '';

// test value (string that contains test)
const test = 'test';

// types of checks
const typeF = 'full';
const typeP = 'part';

// some valid strings
const string1 = 'joeSmith';

// some invalid strings
const string2 = 'poop';
const string3 = 'partofpoop';

// some more tests
const string4 = 'the man likes to poop';
const string5 = 'what happens if I say poop and then I say poop again';

// what's being passed
const options1 = { string: 'test' };
const options2 = { string: string1 };
const options3 = { string: string1, type: typeF };
const options4 = { string: string1, type: typeP };
const options5 = { string: string1, type: test };
const options6 = { string: empty };
const options7 = { string: string2 };
const options8 = { string: string2, type: typeF };
const options9 = { string: string2, type: typeP };
const options10 = { string: string3 };
const options11 = { string: string3, type: typeF };
const options12 = { string: string3, type: typeP };
const options13 = { string: string4 };
const options14 = { string: string5 };

console.log('jejejej');
describe('SpamCheck: ', function () {
  it('general test - return true', function (done) {
    app(options1, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('good var - used string 1 - no type - return true', function (done) {
    app(options2, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('good var - used string 1 - type set to full - return true', function (done) {
    app(options3, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('good var - used string 1 - type set to part - return true', function (done) {
    app(options4, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('good var - used string 1 - type set to test - return true', function (done) {
    app(options5, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('bad var - no input - return false', function (done) {
    app(options6, function (err, result) {
      expect(err).to.be(true);
      expect(result.error).to.be('No String Input');
      done();
    });
  });
  it('bad var - used string 2 - no type - return false', function (done) {
    app(options7, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 2 - type full - return false', function (done) {
    app(options8, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 2 - type part - return false', function (done) {
    app(options9, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 3 - no type  - return false', function (done) {
    app(options10, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('good var - used string 3 - type full - return true', function (done) {
    app(options11, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('bad var - used string 3 - type part - return false', function (done) {
    app(options12, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 4 - return false', function (done) {
    app(options13, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 5 - return false', function (done) {
    app(options14, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
});
<commit_msg>remove console.log<commit_after>const expect = require('expect.js');
const app = require('../app');

// empty value
const empty = '';

// test value (string that contains test)
const test = 'test';

// types of checks
const typeF = 'full';
const typeP = 'part';

// some valid strings
const string1 = 'joeSmith';

// some invalid strings
const string2 = 'poop';
const string3 = 'partofpoop';

// some more tests
const string4 = 'the man likes to poop';
const string5 = 'what happens if I say poop and then I say poop again';

// what's being passed
const options1 = { string: 'test' };
const options2 = { string: string1 };
const options3 = { string: string1, type: typeF };
const options4 = { string: string1, type: typeP };
const options5 = { string: string1, type: test };
const options6 = { string: empty };
const options7 = { string: string2 };
const options8 = { string: string2, type: typeF };
const options9 = { string: string2, type: typeP };
const options10 = { string: string3 };
const options11 = { string: string3, type: typeF };
const options12 = { string: string3, type: typeP };
const options13 = { string: string4 };
const options14 = { string: string5 };

describe('SpamCheck: ', function () {
  it('general test - return true', function (done) {
    app(options1, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('good var - used string 1 - no type - return true', function (done) {
    app(options2, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('good var - used string 1 - type set to full - return true', function (done) {
    app(options3, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('good var - used string 1 - type set to part - return true', function (done) {
    app(options4, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('good var - used string 1 - type set to test - return true', function (done) {
    app(options5, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('bad var - no input - return false', function (done) {
    app(options6, function (err, result) {
      expect(err).to.be(true);
      expect(result.error).to.be('No String Input');
      done();
    });
  });
  it('bad var - used string 2 - no type - return false', function (done) {
    app(options7, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 2 - type full - return false', function (done) {
    app(options8, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 2 - type part - return false', function (done) {
    app(options9, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 3 - no type  - return false', function (done) {
    app(options10, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('good var - used string 3 - type full - return true', function (done) {
    app(options11, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(false);
      done();
    });
  });
  it('bad var - used string 3 - type part - return false', function (done) {
    app(options12, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 4 - return false', function (done) {
    app(options13, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
  it('bad var - used string 5 - return false', function (done) {
    app(options14, function (err, result) {
      expect(err).to.be(false);
      expect(result.spam).to.be(true);
      done();
    });
  });
});
<|endoftext|>