<commit_before>var vows = require('vows'),
    assert = require('assert'),
    zeromq = require('zeromq');

vows.describe('ZeroMQ')
.addBatch({
    'A socket': {
        topic: function() {
            var s = zeromq.createSocket('req');
            this.callback(null, s);
        },
        'after successful open': {
            topic: function(s) {
                this.callback(null, s);
            },
            'can connect': function(s) {
                assert.doesNotThrow(function() {
                    s.connect('tcp://127.0.0.1:5554');
                });
            },
            'dies on bad host': function(s) {
                //TODO: this just hangs, need to fix that behavior
                //assert.throws(function() {s.connect('tcp://127.0.0.1:8398'); });
            },
            'after successful connect': {
                topic: function(s) {
                    this.callback(null, s);
                },
                'can send': function(s) {
                    assert.doesNotThrow(function() {
                        s.send("hey there!");
                    });
                },
                'can set highwater mark': function(s) {
                    assert.doesNotThrow(function() {
                        s.highWaterMark = 10;
                    });
                    assert.equal(s.highWaterMark, 10);
                },
                'after successful `send`': {
                    topic: function(s) {
                        var self = this;
                        s.on('message', function(data) {
                            self.callback(null, data.toString('utf8'));
                        });
                    },
                    'does receive data': function(data) {
                        assert.isString(data);
                    },
                    'after receive': {
                        topic: function(data, s) {
                            this.callback(null, s);
                        },
                        'can be closed': function(s) {
                            assert.doesNotThrow(function() {
                                s.close();
                            });
                        }
                    }
                }
            }
        }
    }
}).export(module);
<commit_msg>A working test!<commit_after>var vows = require('vows'),
    assert = require('assert'),
    zeromq = require('zeromq');

var suite = vows.describe('ZeroMQ');
suite.options.error = false;
suite.addBatch({
  'A reply socket': {
    topic: function() {
      return zeromq.createSocket('reply');
    },
    'can set the high water mark': function(rep) {
      rep.highWaterMark = 10;
      assert.equal(rep.highWaterMark, 10);
    },
    'after a successful open': {
      topic: function(rep) {
        rep.bind('inproc://1-1', this.callback);
      },
      'can be bound to an inproc address': function(bindErr) {
        assert.ifError(bindErr);
      },
      'and a request socket': {
        topic: function(bindErr, rep) {
          return zeromq.createSocket('request');
        },
        'can connect to the reply socket': function(req) {
          req.connect('inproc://1-1');
        },
        'after a successful connect': {
          topic: function(req, bindErr, rep) {
            rep.on('message', this.callback);
            req.send('foo');
          },
          'can send a request': function(reqMsg) {
            assert.equal(reqMsg, 'foo');
          },
          'after a successful request': {
            topic: function(reqMsg, req, bindErr, rep) {
              req.on('message', this.callback);
              rep.send('bar');
            },
            'can send a reply': function(repMsg) {
              assert.equal(repMsg, 'bar');
            },
            'after a successful reply': {
              topic: function(repMsg, reqMsg, req, bindErr, rep) {
                req.close();
                rep.close();
                this.callback(null);
              },
              'can close both sockets': function() {}
            }
          }
        }
      }
    }
  }
});
suite.export(module);
<|endoftext|>


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

  /*
    ---------------
    Variables
    ---------------
  */

  // cache document.documentElement
  var docElem = document.documentElement;

  // last used input type
  var currentInput = 'initial';

  // last used input intent
  var currentIntent = null;

  // form input types
  var formInputs = [
    'input',
    'select',
    'textarea'
  ];

  // list of modifier keys commonly used with the mouse and
  // can be safely ignored to prevent false keyboard detection
  var ignoreMap = [
    16, // shift
    17, // control
    18, // alt
    91, // Windows key / left Apple cmd
    93  // Windows menu / right Apple cmd
  ];

  // mapping of events to input types
  var inputMap = {
    'keyup': 'keyboard',
    'mousedown': 'mouse',
    'mousemove': 'mouse',
    'MSPointerDown': 'pointer',
    'MSPointerMove': 'pointer',
    'pointerdown': 'pointer',
    'pointermove': 'pointer',
    'touchstart': 'touch'
  };

  // array of all used input types
  var inputTypes = [];

  // boolean: true if touch buffer timer is running
  var isBuffering = false;

  // map of IE 10 pointer events
  var pointerMap = {
    2: 'touch',
    3: 'touch', // treat pen like touch
    4: 'mouse'
  };

  // touch buffer timer
  var touchTimer = null;

  /*
    ---------------
    Set up
    ---------------
  */

  var setUp = function() {

    // add correct mouse wheel event mapping to `inputMap`
    inputMap[detectWheel()] = 'mouse';

    addListeners();
    setInput();
  };

  /*
    ---------------
    Events
    ---------------
  */

  var addListeners = function() {

    // `pointermove`, `MSPointerMove`, `mousemove` and mouse wheel event binding
    // can only demonstrate potential, but not actual, interaction
    // and are treated separately

    // pointer events (mouse, pen, touch)
    if (window.PointerEvent) {
      docElem.addEventListener('pointerdown', updateInput);
      docElem.addEventListener('pointermove', setIntent);
    } else if (window.MSPointerEvent) {
      docElem.addEventListener('MSPointerDown', updateInput);
      docElem.addEventListener('MSPointerMove', setIntent);
    } else {

      // mouse events
      docElem.addEventListener('mousedown', updateInput);
      docElem.addEventListener('mousemove', setIntent);

      // touch events
      if ('ontouchstart' in window) {
        docElem.addEventListener('touchstart', touchBuffer);
      }
    }

    // mouse wheel
    docElem.addEventListener(detectWheel(), setIntent);

    // keyboard events
    docElem.addEventListener('keydown', updateInput);
    docElem.addEventListener('keyup', updateInput);
  };

  // checks conditions before updating new input
  var updateInput = function(event) {

    // only execute if the touch buffer timer isn't running
    if (!isBuffering) {
      var eventKey = event.which;
      var value = inputMap[event.type];
      if (value === 'pointer') value = pointerType(event);

      if (
        currentInput !== value ||
        currentIntent !== value
      ) {

        var activeInput = (
          document.activeElement &&
          formInputs.indexOf(document.activeElement.nodeName.toLowerCase()) === -1
        ) ? true : false;

        if (
          value === 'touch' ||

          // ignore mouse modifier keys
          (value === 'mouse' && ignoreMap.indexOf(eventKey) === -1) ||

          // don't switch if the current element is a form input
          (value === 'keyboard' && activeInput)
        ) {

          // set the current and catch-all variable
          currentInput = currentIntent = value;

          setInput();
        }
      }
    }
  };

  // updates the doc and `inputTypes` array with new input
  var setInput = function() {
    docElem.setAttribute('data-whatinput', currentInput);
    docElem.setAttribute('data-whatintent', currentInput);

    if (inputTypes.indexOf(currentInput) === -1) {
      inputTypes.push(currentInput);
      docElem.classList.add('whatinput-types-' + currentInput);
    }
  };

  // updates input intent for `mousemove` and `pointermove`
  var setIntent = function(event) {

    // only execute if the touch buffer timer isn't running
    if (!isBuffering) {
      var value = inputMap[event.type];
      if (value === 'pointer') value = pointerType(event);

      if (currentIntent !== value) {
        currentIntent = value;

        docElem.setAttribute('data-whatintent', currentIntent);
      }
    }
  };

  // buffers touch events because they frequently also fire mouse events
  var touchBuffer = function(event) {

    // clear the timer if it happens to be running
    window.clearTimeout(touchTimer);

    // set the current input
    updateInput(event);

    // set the isBuffering to `true`
    isBuffering = true;

    // run the timer
    touchTimer = window.setTimeout(function() {

      // if the timer runs out, set isBuffering back to `false`
      isBuffering = false;
    }, 200);
  };

  /*
    ---------------
    Utilities
    ---------------
  */

  var pointerType = function(event) {
   if (typeof event.pointerType === 'number') {
      return pointerMap[event.pointerType];
   } else {
      return (event.pointerType === 'pen') ? 'touch' : event.pointerType; // treat pen like touch
   }
  };

  // detect version of mouse wheel event to use
  // via https://developer.mozilla.org/en-US/docs/Web/Events/wheel
  var detectWheel = function() {
    return 'onwheel' in document.createElement('div') ?
      'wheel' : // Modern browsers support "wheel"

      document.onmousewheel !== undefined ?
        'mousewheel' : // Webkit and IE support at least "mousewheel"
        'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
  };

  /*
    ---------------
    Init

    don't start script unless browser cuts the mustard
    (also passes if polyfills are used)
    ---------------
  */

  if (
    'addEventListener' in window &&
    Array.prototype.indexOf
  ) {
    setUp();
  }

  /*
    ---------------
    API
    ---------------
  */

  return {

    // returns string: the current input type
    // opt: 'loose'|'strict'
    // 'strict' (default): returns the same value as the `data-whatinput` attribute
    // 'loose': includes `data-whatintent` value if it's more current than `data-whatinput`
    ask: function(opt) { return (opt === 'loose') ? currentIntent : currentInput; },

    // returns array: all the detected input types
    types: function() { return inputTypes; }

  };

}());
<commit_msg>className is universally available.. classList is only available in newer browsers<commit_after>module.exports = (function() {

  /*
    ---------------
    Variables
    ---------------
  */

  // cache document.documentElement
  var docElem = document.documentElement;

  // last used input type
  var currentInput = 'initial';

  // last used input intent
  var currentIntent = null;

  // form input types
  var formInputs = [
    'input',
    'select',
    'textarea'
  ];

  // list of modifier keys commonly used with the mouse and
  // can be safely ignored to prevent false keyboard detection
  var ignoreMap = [
    16, // shift
    17, // control
    18, // alt
    91, // Windows key / left Apple cmd
    93  // Windows menu / right Apple cmd
  ];

  // mapping of events to input types
  var inputMap = {
    'keyup': 'keyboard',
    'mousedown': 'mouse',
    'mousemove': 'mouse',
    'MSPointerDown': 'pointer',
    'MSPointerMove': 'pointer',
    'pointerdown': 'pointer',
    'pointermove': 'pointer',
    'touchstart': 'touch'
  };

  // array of all used input types
  var inputTypes = [];

  // boolean: true if touch buffer timer is running
  var isBuffering = false;

  // map of IE 10 pointer events
  var pointerMap = {
    2: 'touch',
    3: 'touch', // treat pen like touch
    4: 'mouse'
  };

  // touch buffer timer
  var touchTimer = null;

  /*
    ---------------
    Set up
    ---------------
  */

  var setUp = function() {

    // add correct mouse wheel event mapping to `inputMap`
    inputMap[detectWheel()] = 'mouse';

    addListeners();
    setInput();
  };

  /*
    ---------------
    Events
    ---------------
  */

  var addListeners = function() {

    // `pointermove`, `MSPointerMove`, `mousemove` and mouse wheel event binding
    // can only demonstrate potential, but not actual, interaction
    // and are treated separately

    // pointer events (mouse, pen, touch)
    if (window.PointerEvent) {
      docElem.addEventListener('pointerdown', updateInput);
      docElem.addEventListener('pointermove', setIntent);
    } else if (window.MSPointerEvent) {
      docElem.addEventListener('MSPointerDown', updateInput);
      docElem.addEventListener('MSPointerMove', setIntent);
    } else {

      // mouse events
      docElem.addEventListener('mousedown', updateInput);
      docElem.addEventListener('mousemove', setIntent);

      // touch events
      if ('ontouchstart' in window) {
        docElem.addEventListener('touchstart', touchBuffer);
      }
    }

    // mouse wheel
    docElem.addEventListener(detectWheel(), setIntent);

    // keyboard events
    docElem.addEventListener('keydown', updateInput);
    docElem.addEventListener('keyup', updateInput);
  };

  // checks conditions before updating new input
  var updateInput = function(event) {

    // only execute if the touch buffer timer isn't running
    if (!isBuffering) {
      var eventKey = event.which;
      var value = inputMap[event.type];
      if (value === 'pointer') value = pointerType(event);

      if (
        currentInput !== value ||
        currentIntent !== value
      ) {

        var activeInput = (
          document.activeElement &&
          formInputs.indexOf(document.activeElement.nodeName.toLowerCase()) === -1
        ) ? true : false;

        if (
          value === 'touch' ||

          // ignore mouse modifier keys
          (value === 'mouse' && ignoreMap.indexOf(eventKey) === -1) ||

          // don't switch if the current element is a form input
          (value === 'keyboard' && activeInput)
        ) {

          // set the current and catch-all variable
          currentInput = currentIntent = value;

          setInput();
        }
      }
    }
  };

  // updates the doc and `inputTypes` array with new input
  var setInput = function() {
    docElem.setAttribute('data-whatinput', currentInput);
    docElem.setAttribute('data-whatintent', currentInput);

    if (inputTypes.indexOf(currentInput) === -1) {
      inputTypes.push(currentInput);
      docElem.className += ' whatinput-types-' + currentInput;
    }
  };

  // updates input intent for `mousemove` and `pointermove`
  var setIntent = function(event) {

    // only execute if the touch buffer timer isn't running
    if (!isBuffering) {
      var value = inputMap[event.type];
      if (value === 'pointer') value = pointerType(event);

      if (currentIntent !== value) {
        currentIntent = value;

        docElem.setAttribute('data-whatintent', currentIntent);
      }
    }
  };

  // buffers touch events because they frequently also fire mouse events
  var touchBuffer = function(event) {

    // clear the timer if it happens to be running
    window.clearTimeout(touchTimer);

    // set the current input
    updateInput(event);

    // set the isBuffering to `true`
    isBuffering = true;

    // run the timer
    touchTimer = window.setTimeout(function() {

      // if the timer runs out, set isBuffering back to `false`
      isBuffering = false;
    }, 200);
  };

  /*
    ---------------
    Utilities
    ---------------
  */

  var pointerType = function(event) {
   if (typeof event.pointerType === 'number') {
      return pointerMap[event.pointerType];
   } else {
      return (event.pointerType === 'pen') ? 'touch' : event.pointerType; // treat pen like touch
   }
  };

  // detect version of mouse wheel event to use
  // via https://developer.mozilla.org/en-US/docs/Web/Events/wheel
  var detectWheel = function() {
    return 'onwheel' in document.createElement('div') ?
      'wheel' : // Modern browsers support "wheel"

      document.onmousewheel !== undefined ?
        'mousewheel' : // Webkit and IE support at least "mousewheel"
        'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
  };

  /*
    ---------------
    Init

    don't start script unless browser cuts the mustard
    (also passes if polyfills are used)
    ---------------
  */

  if (
    'addEventListener' in window &&
    Array.prototype.indexOf
  ) {
    setUp();
  }

  /*
    ---------------
    API
    ---------------
  */

  return {

    // returns string: the current input type
    // opt: 'loose'|'strict'
    // 'strict' (default): returns the same value as the `data-whatinput` attribute
    // 'loose': includes `data-whatintent` value if it's more current than `data-whatinput`
    ask: function(opt) { return (opt === 'loose') ? currentIntent : currentInput; },

    // returns array: all the detected input types
    types: function() { return inputTypes; }

  };

}());
<|endoftext|>


<commit_before>'use strict';

// Report overall code coverage from Istanbul coverage files.

const _ = require('underscore');
const istanbul = require('istanbul-harmony');
const fs = require('fs');

const bind = _.bind;

const coverage = require('..');

/* eslint handle-callback-err: 1 */

describe('cf-abacus-coverage', () => {
    it('reports overall code coverage', (done) => {

        // Spy on the Istanbul coverage reporter
        let reporters = [];
        const Reporter = istanbul.Reporter;
        istanbul.Reporter = function(cfg, dir) {
            const reporter = new Reporter(cfg, dir);
            this.addAll = spy(bind(reporter.addAll, reporter));
            this.write = spy(bind(reporter.write, reporter));
            reporters.push(this);
        };

        // Mock process exit to get called back when the CLI exits
        process.exit = (code) => {
            // Expect exit code to be 0
            expect(code).to.equal(0);

            // Expect reporter.addAll to be called with some report types
            expect(reporters[0].addAll.args[0][0][0]).to.match(/^lcov.*/);
            expect(reporters[0].addAll.args[0][0][1]).to.match(/^json$/);

            // Expect reporter.write to be called with a collector
            const collector = reporters[0].write.args[0][0];
            expect(collector).to.not.equal(undefined);

            // Expect the collector to contain our main index file
            const files = collector.files();
            expect(files[0]).to.equal('index.js');

            done();
        };

        // Setup a test coverage.json, expecting it to be picked up as part of
        // the overall module coverage
        fs.mkdir('.coverage', () => fs.readFile('test/coverage.json', (err, val) => fs.writeFile('.coverage/coverage.json', val, () => {
            // Run the coverage CLI
            coverage.runCLI();
        })));
    });
});

<commit_msg>Restore mocked process.exit after test execution.<commit_after>'use strict';

// Report overall code coverage from Istanbul coverage files.

const _ = require('underscore');
const istanbul = require('istanbul-harmony');
const fs = require('fs');

const bind = _.bind;

const coverage = require('..');

/* eslint handle-callback-err: 1 */

describe('cf-abacus-coverage', () => {
    let exit;
    beforeEach(() => {
        exit = process.exit;
    });
    afterEach(() => {
        process.exit = exit;
    });

    it('reports overall code coverage', (done) => {

        // Spy on the Istanbul coverage reporter
        let reporters = [];
        const Reporter = istanbul.Reporter;
        istanbul.Reporter = function(cfg, dir) {
            const reporter = new Reporter(cfg, dir);
            this.addAll = spy(bind(reporter.addAll, reporter));
            this.write = spy(bind(reporter.write, reporter));
            reporters.push(this);
        };

        // Mock process exit to get called back when the CLI exits
        process.exit = (code) => {
            // Expect exit code to be 0
            expect(code).to.equal(0);

            // Expect reporter.addAll to be called with some report types
            expect(reporters[0].addAll.args[0][0][0]).to.match(/^lcov.*/);
            expect(reporters[0].addAll.args[0][0][1]).to.match(/^json$/);

            // Expect reporter.write to be called with a collector
            const collector = reporters[0].write.args[0][0];
            expect(collector).to.not.equal(undefined);

            // Expect the collector to contain our main index file
            const files = collector.files();
            expect(files[0]).to.equal('index.js');

            done();
        };

        // Setup a test coverage.json, expecting it to be picked up as part of
        // the overall module coverage
        fs.mkdir('.coverage', () => fs.readFile('test/coverage.json', (err, val) => fs.writeFile('.coverage/coverage.json', val, () => {
            // Run the coverage CLI
            coverage.runCLI();
        })));
    });
});

<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2021 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Utility functions for positioning UI elements.
 * @author kozbial@google.com (Monica Kozbial)
 */
'use strict';

goog.module('Blockly.uiPosition');
goog.module.declareLegacyNamespace();

const MetricsManager = goog.requireType('Blockly.MetricsManager');
const Rect = goog.require('Blockly.utils.Rect');
const Scrollbar = goog.require('Blockly.Scrollbar');
const Size = goog.requireType('Blockly.utils.Size');
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
const toolbox = goog.require('Blockly.utils.toolbox');

/**
 * Enum for vertical positioning.
 * @enum {number}
 */
const verticalPosition = {
  TOP: 0,
  BOTTOM: 1
};
/** @package */
exports.verticalPosition = verticalPosition;

/**
 * Enum for horizontal positioning.
 * @enum {number}
 */
const horizontalPosition = {
  LEFT: 0,
  RIGHT: 1
};
/** @package */
exports.horizontalPosition = horizontalPosition;

/**
 * An object defining a horizontal and vertical positioning.
 * @typedef {{
 *   horizontal: !horizontalPosition,
 *   vertical: !verticalPosition
 * }}
 */
let Position;
/** @package */
exports.Position = Position;

/**
 * Enum for bump rules to use for dealing with collisions.
 * @enum {number}
 */
const bumpDirection = {
  UP: 0,
  DOWN: 1
};
/** @package */
exports.bumpDirection = bumpDirection;

/**
 * Returns a rectangle representing reasonable position for where to place a UI
 * element of the specified size given the restraints and locations of the
 * scrollbars. This method does not take into account any already placed UI
 * elements.
 * @param {!Position} position The starting
 *    horizontal and vertical position.
 * @param {!Size} size the size of the UI element to get a start
 *    position for.
 * @param {number} horizontalPadding The horizontal padding to use.
 * @param {number} verticalPadding The vertical padding to use.
 * @param {!MetricsManager.UiMetrics} metrics The workspace UI metrics.
 * @param {!WorkspaceSvg} workspace The workspace.
 * @return {!Rect} The suggested start position.
 */
const getStartPositionRect = function(
    position, size, horizontalPadding,
    verticalPadding, metrics, workspace) {
  // Horizontal positioning.
  let left = 0;
  const hasVerticalScrollbar =
      workspace.scrollbar && workspace.scrollbar.canScrollVertically();
  if (position.horizontal ===
      horizontalPosition.LEFT) {
    left = metrics.absoluteMetrics.left + horizontalPadding;
    if (hasVerticalScrollbar && workspace.RTL) {
      left += Scrollbar.scrollbarThickness;
    }
  } else {  // position.horizontal == horizontalPosition.RIGHT
    left = metrics.absoluteMetrics.left + metrics.viewMetrics.width -
        size.width - horizontalPadding;
    if (hasVerticalScrollbar && !workspace.RTL) {
      left -= Scrollbar.scrollbarThickness;
    }
  }
  // Vertical positioning.
  let top = 0;
  if (position.vertical ===
      verticalPosition.TOP) {
    top = metrics.absoluteMetrics.top + verticalPadding;
  } else {  // position.vertical == verticalPosition.BOTTOM
    top = metrics.absoluteMetrics.top + metrics.viewMetrics.height -
        size.height - verticalPadding;
    if (workspace.scrollbar && workspace.scrollbar.canScrollHorizontally()) {
      // The scrollbars are always positioned on the bottom if they exist.
      top -= Scrollbar.scrollbarThickness;
    }
  }
  return new Rect(
      top, top + size.height, left, left + size.width);
};
/** @package */
exports.getStartPositionRect = getStartPositionRect;

/**
 * Returns a corner position that is on the opposite side of the workspace from
 * the toolbox.
 * If in horizontal orientation, defaults to the bottom corner. If in vertical
 * orientation, defaults to the right corner.
 * @param {!WorkspaceSvg} workspace The workspace.
 * @param {!MetricsManager.UiMetrics} metrics The workspace metrics.
 * @return {!Position} The suggested corner position.
 * @package
 */
const getCornerOppositeToolbox = function(workspace, metrics) {
  const leftCorner =
      metrics.toolboxMetrics.position !== toolbox.Position.LEFT &&
      (!workspace.horizontalLayout || workspace.RTL);
  const topCorner =
      metrics.toolboxMetrics.position === toolbox.Position.BOTTOM;
  const hPosition = leftCorner ?
      horizontalPosition.LEFT : horizontalPosition.RIGHT;
  const vPosition = topCorner ?
      verticalPosition.TOP : verticalPosition.BOTTOM;
  return {
    horizontal: hPosition,
    vertical: vPosition
  };
};
/** @package */
exports.getCornerOppositeToolbox = getCornerOppositeToolbox;

/**
 * Returns a position Rect based on a starting position that is bumped
 * so that it doesn't intersect with any of the provided savedPositions. This
 * method does not check that the bumped position is still within bounds.
 * @param {!Rect} startRect The starting position to use.
 * @param {number} margin The margin to use between elements when bumping.
 * @param {!bumpDirection} bumpDir The direction to bump if there is a collision
 *    with an existing UI element.
 * @param {!Array<!Rect>} savedPositions List of rectangles that
 *    represent the positions of UI elements already placed.
 * @return {!Rect} The suggested position rectangle.
 */
const bumpPositionRect = function(
    startRect, margin, bumpDir, savedPositions) {
  let top = startRect.top;
  const left = startRect.left;
  const width = startRect.right - startRect.left;
  const height = startRect.bottom - startRect.top;

  // Check for collision and bump if needed.
  let boundingRect = startRect;
  for (let i = 0; i < savedPositions.length; i++) {
    const otherEl = savedPositions[i];
    if (boundingRect.intersects(otherEl)) {
      if (bumpDir === bumpDirection.UP) {
        top = otherEl.top - height - margin;
      } else {  // bumpDir == bumpDirection.DOWN
        top = otherEl.bottom + margin;
      }
      // Recheck other savedPositions
      boundingRect = new Rect(
          top, top + height, left, left + width);
      i = -1;
    }
  }
  return boundingRect;
};
/** @package */
exports.bumpPositionRect = bumpPositionRect;
<commit_msg>clang-format core/positionable_helpers.js<commit_after>/**
 * @license
 * Copyright 2021 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Utility functions for positioning UI elements.
 * @author kozbial@google.com (Monica Kozbial)
 */
'use strict';

goog.module('Blockly.uiPosition');
goog.module.declareLegacyNamespace();

const MetricsManager = goog.requireType('Blockly.MetricsManager');
const Rect = goog.require('Blockly.utils.Rect');
const Scrollbar = goog.require('Blockly.Scrollbar');
const Size = goog.requireType('Blockly.utils.Size');
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
const toolbox = goog.require('Blockly.utils.toolbox');

/**
 * Enum for vertical positioning.
 * @enum {number}
 */
const verticalPosition = {
  TOP: 0,
  BOTTOM: 1
};
/** @package */
exports.verticalPosition = verticalPosition;

/**
 * Enum for horizontal positioning.
 * @enum {number}
 */
const horizontalPosition = {
  LEFT: 0,
  RIGHT: 1
};
/** @package */
exports.horizontalPosition = horizontalPosition;

/**
 * An object defining a horizontal and vertical positioning.
 * @typedef {{
 *   horizontal: !horizontalPosition,
 *   vertical: !verticalPosition
 * }}
 */
let Position;
/** @package */
exports.Position = Position;

/**
 * Enum for bump rules to use for dealing with collisions.
 * @enum {number}
 */
const bumpDirection = {
  UP: 0,
  DOWN: 1
};
/** @package */
exports.bumpDirection = bumpDirection;

/**
 * Returns a rectangle representing reasonable position for where to place a UI
 * element of the specified size given the restraints and locations of the
 * scrollbars. This method does not take into account any already placed UI
 * elements.
 * @param {!Position} position The starting
 *    horizontal and vertical position.
 * @param {!Size} size the size of the UI element to get a start
 *    position for.
 * @param {number} horizontalPadding The horizontal padding to use.
 * @param {number} verticalPadding The vertical padding to use.
 * @param {!MetricsManager.UiMetrics} metrics The workspace UI metrics.
 * @param {!WorkspaceSvg} workspace The workspace.
 * @return {!Rect} The suggested start position.
 */
const getStartPositionRect = function(
    position, size, horizontalPadding, verticalPadding, metrics, workspace) {
  // Horizontal positioning.
  let left = 0;
  const hasVerticalScrollbar =
      workspace.scrollbar && workspace.scrollbar.canScrollVertically();
  if (position.horizontal === horizontalPosition.LEFT) {
    left = metrics.absoluteMetrics.left + horizontalPadding;
    if (hasVerticalScrollbar && workspace.RTL) {
      left += Scrollbar.scrollbarThickness;
    }
  } else {  // position.horizontal == horizontalPosition.RIGHT
    left = metrics.absoluteMetrics.left + metrics.viewMetrics.width -
        size.width - horizontalPadding;
    if (hasVerticalScrollbar && !workspace.RTL) {
      left -= Scrollbar.scrollbarThickness;
    }
  }
  // Vertical positioning.
  let top = 0;
  if (position.vertical === verticalPosition.TOP) {
    top = metrics.absoluteMetrics.top + verticalPadding;
  } else {  // position.vertical == verticalPosition.BOTTOM
    top = metrics.absoluteMetrics.top + metrics.viewMetrics.height -
        size.height - verticalPadding;
    if (workspace.scrollbar && workspace.scrollbar.canScrollHorizontally()) {
      // The scrollbars are always positioned on the bottom if they exist.
      top -= Scrollbar.scrollbarThickness;
    }
  }
  return new Rect(top, top + size.height, left, left + size.width);
};
/** @package */
exports.getStartPositionRect = getStartPositionRect;

/**
 * Returns a corner position that is on the opposite side of the workspace from
 * the toolbox.
 * If in horizontal orientation, defaults to the bottom corner. If in vertical
 * orientation, defaults to the right corner.
 * @param {!WorkspaceSvg} workspace The workspace.
 * @param {!MetricsManager.UiMetrics} metrics The workspace metrics.
 * @return {!Position} The suggested corner position.
 * @package
 */
const getCornerOppositeToolbox = function(workspace, metrics) {
  const leftCorner =
      metrics.toolboxMetrics.position !== toolbox.Position.LEFT &&
      (!workspace.horizontalLayout || workspace.RTL);
  const topCorner = metrics.toolboxMetrics.position === toolbox.Position.BOTTOM;
  const hPosition =
      leftCorner ? horizontalPosition.LEFT : horizontalPosition.RIGHT;
  const vPosition = topCorner ? verticalPosition.TOP : verticalPosition.BOTTOM;
  return {horizontal: hPosition, vertical: vPosition};
};
/** @package */
exports.getCornerOppositeToolbox = getCornerOppositeToolbox;

/**
 * Returns a position Rect based on a starting position that is bumped
 * so that it doesn't intersect with any of the provided savedPositions. This
 * method does not check that the bumped position is still within bounds.
 * @param {!Rect} startRect The starting position to use.
 * @param {number} margin The margin to use between elements when bumping.
 * @param {!bumpDirection} bumpDir The direction to bump if there is a collision
 *    with an existing UI element.
 * @param {!Array<!Rect>} savedPositions List of rectangles that
 *    represent the positions of UI elements already placed.
 * @return {!Rect} The suggested position rectangle.
 */
const bumpPositionRect = function(startRect, margin, bumpDir, savedPositions) {
  let top = startRect.top;
  const left = startRect.left;
  const width = startRect.right - startRect.left;
  const height = startRect.bottom - startRect.top;

  // Check for collision and bump if needed.
  let boundingRect = startRect;
  for (let i = 0; i < savedPositions.length; i++) {
    const otherEl = savedPositions[i];
    if (boundingRect.intersects(otherEl)) {
      if (bumpDir === bumpDirection.UP) {
        top = otherEl.top - height - margin;
      } else {  // bumpDir == bumpDirection.DOWN
        top = otherEl.bottom + margin;
      }
      // Recheck other savedPositions
      boundingRect = new Rect(top, top + height, left, left + width);
      i = -1;
    }
  }
  return boundingRect;
};
/** @package */
exports.bumpPositionRect = bumpPositionRect;
<|endoftext|>


<commit_before><commit_msg>add states<commit_after><|endoftext|>


<commit_before>$(function() {

var example_data = [
    {
        label: 'node1',
        id: 123,  // extra data
        children: [
            { label: 'child1' },
            { label: 'child2' }
        ]
    },
    {
        label: 'node2',
        id: 124,
        children: [
            { label: 'child3' }
        ]
    }
];

var format_nodes = function(nodes) {
    var strings = $.map(nodes, function(node) {
        return node.name;
    });
    return strings.join(' ');
};

var isNodeClosed = function($node) {
    return (
        ($node.is('li.folder.closed')) &&
        ($node.find('a:eq(0)').is('a.toggler.closed')) &&
        ($node.find('ul:eq(0)').is('ul'))
    );
}

var isNodeOpen = function($node) {
    return (
        ($node.is('li.folder')) &&
        ($node.find('a:eq(0)').is('a.toggler')) &&
        ($node.find('ul:eq(0)').is('ul')) &&
        (! $node.is('li.folder.closed')) &&
        (! $node.find('span:eq(0)').is('a.toggler.closed'))
    );
}

module("jqtree", {
    teardown: function() {
        $('#tree1').tree('destroy');
    }
});

test("create jqtree from data", function() {
    $('#tree1').tree({
        data: example_data
    });

    equal(
        $('#tree1').children().length, 1,
        'number of children on level 0'
    );
    ok(
        $('#tree1').children().is('ul.tree'),
        'first element is ul.tree'
    );
    equal(
        $('#tree1 ul.tree > li').length, 2,
        'number of children on level 1'
    );
    ok(
        $('#tree1 ul.tree li:eq(0)').is('li.folder.closed'),
        'first child is li.folder.closed'
    );
    ok(
        $('#tree1 ul.tree li:eq(0) > div > a.toggler').is('a.toggler.closed'),
        'button in first folder'
    );
    equal(
        $('#tree1 ul.tree li:eq(0) > div span.title').text(),
        'node1'
    );
});

test('jqtree toggle', function() {
    // create tree
    var $tree = $('#tree1');
    $tree.tree({
        data: example_data
    });

    var tree = $tree.tree('getTree');
    var node1 = tree.children[0];
    var $node1 = $tree.find('ul.tree li:eq(0)');

    // node1 is initially closed
    ok(isNodeClosed($node1), 'node1 is open');

    stop();

    // open node1
    $tree.tree(
        'toggle',
        node1,
        function() {
            start();

            ok(isNodeOpen($node1), 'node1 is open');

            stop();

            // close node1
            $tree.tree(
                'toggle',
                node1,
                function() {
                    start();

                    ok(isNodeClosed($node1), 'node1 is closed');
                }
            );
        }
    );
});

// todo: test jqtree.getTree()

test("click event", function() {
    stop(2000);

    // create tree
    var $tree = $('#tree1');

    $tree.tree({
        data: example_data,
        onClick: function(node) {
            start();
            equal(node.name, 'node1');
        }
    });

    // click on node1
    var $node1 = $tree.find('ul.tree li:first');
    var $text_span = $node1.find('span:first');
    $text_span.click();
});

test('saveState', function() {
    var $tree = $('#tree1');

    var saved_state;

    function setState(state) {
        saved_state = state;
    }

    function getState() {
        return saved_state;
    }

    function createTree() {
        $tree.tree({
            data: example_data,
            saveState: true,
            onSetStateFromStorage: setState,
            onGetStateFromStorage: getState,
            selectable: true
        });
    }

    // create tree
    createTree();

    // nodes are initially closed
    var tree = $tree.tree('getTree');
    tree.iterate(function(node) {
        ok(! node.is_open, 'closed');
        return true;
    });

    // open node1
    $tree.tree('toggle', tree.children[0]);

    // node1 is open
    ok(tree.children[0].is_open, 'node1 is_open');

    // select node2
    $tree.tree('selectNode', tree.children[1]);

    // node2 is selected
    equal(
        $tree.tree('getSelectedNode').name,
        'node2',
        'getSelectedNode'
    );

    // create tree again
    $tree.tree('destroy');
    createTree();

    tree = $tree.tree('getTree');
    ok(tree.children[0].is_open, 'node1 is_open');
    ok(! tree.children[1].is_open, 'node2 is closed');

    // node2 is selected
    equal(
        $tree.tree('getSelectedNode').name,
        'node2',
        'getSelectedNode'
    );
});

test('getSelectedNode', function() {
    var $tree = $('#tree1');

    // create tree
    $tree.tree({
        data: example_data,
        selectable: true
    });

    // there is no node selected
    equal(
        $tree.tree('getSelectedNode'),
        false,
        'getSelectedNode'
    );

    // select node1
    var tree = $tree.tree('getTree');
    var node1 = tree.children[0];
    $tree.tree('selectNode', node1);

    // node1 is selected
    equal(
        $tree.tree('getSelectedNode').name,
        'node1',
        'getSelectedNode'
    );
});

module("Tree");
test("create tree from data", function() {
    var tree = new Tree.Tree();
    tree.loadFromData(example_data);

    equal(
        format_nodes(tree.children),
        'node1 node2',
        'nodes on level 1'
    );
    equal(
        format_nodes(tree.children[0].children),
        'child1 child2',
        'children of node1'
    );
    equal(
        format_nodes(tree.children[1].children),
        'child3',
        'children of node2'
    );
    equal(
        tree.children[0].id,
        123,
        'id'
    );
});

test("tree addChild", function() {
    var tree = new Tree.Tree('tree1');
    tree.addChild(
        new Tree.Node('abc')
    );
    tree.addChild(
        new Tree.Node('def')
    );

    equal(
        format_nodes(tree.children),
        'abc def',
        'children'
    );

    var node = tree.children[0];
    equal(
        node.parent.name,
        'tree1',
        'parent of node'
    );
});

test('tree addChildAtPosition', function() {
    var tree = new Tree.Tree();
    tree.addChildAtPosition(new Tree.Node('abc'), 0);  // first
    tree.addChildAtPosition(new Tree.Node('ghi'), 2);  // index 2 does not exist
    tree.addChildAtPosition(new Tree.Node('def'), 1);
    tree.addChildAtPosition(new Tree.Node('123'), 0);

    equal(
        format_nodes(tree.children),
        '123 abc def ghi',
        'children'
    );
});

test('tree removeChild', function() {
    var tree = new Tree.Tree();

    var abc = new Tree.Node('abc');
    var def = new Tree.Node('def');
    var ghi = new Tree.Node('ghi');
    tree.addChild(abc);
    tree.addChild(def);
    tree.addChild(ghi);

    equal(
        format_nodes(tree.children),
        'abc def ghi',
        'children'
    );

    // remove 'def'
    tree.removeChild(def);
    equal(
        format_nodes(tree.children),
        'abc ghi',
        'children'
    );

    // remove 'ghi'
    tree.removeChild(ghi);
    equal(
        format_nodes(tree.children),
        'abc',
        'children'
    );

    // remove 'abc'
    tree.removeChild(abc);
    equal(
        format_nodes(tree.children),
        '',
        'children'
    );
});

test('tree getChildIndex', function() {
    var tree = new Tree.Tree();

    var abc = new Tree.Node('abc');
    var def = new Tree.Node('def');
    var ghi = new Tree.Node('ghi');
    tree.addChild(abc);
    tree.addChild(def);
    tree.addChild(ghi);

    equal(
        tree.getChildIndex(def),
        1,
        'indef of def'
    );
});

test('tree hasChildren', function() {
    var tree = new Tree.Tree();
    equal(
        tree.hasChildren(),
        false,
        'tree without children'
    );

    tree.addChild(new Tree.Node('abc'));
    equal(
        tree.hasChildren(),
        true,
        'tree has children'
    );
});

test('tree iterate', function() {
    var tree = new Tree.Tree();
    tree.loadFromData(example_data);

    // iterate over all the nodes
    var nodes = [];
    tree.iterate(
        function(node, level) {
            nodes.push(node);
            return true;
        }
    );

    equal(
        format_nodes(nodes),
        'node1 child1 child2 node2 child3',
        'all nodes'
    );

    // iterate over nodes on first level
    nodes = [];
    tree.iterate(
        function(node, level) {
            nodes.push(node);
            return false;
        }
    );

    equal(
        format_nodes(nodes),
        'node1 node2',
        'nodes on first level'
    );
});

test('tree moveNode', function() {
    var tree = Tree.Tree.createFromData(example_data);

    /*
      node1
      ---child1
      ---child2
      node2
      ---child3
    */

    var node1 = tree.children[0];
    var node2 = tree.children[1];
    var child1 = node1.children[0];
    var child2 = node1.children[1];
    equal(node2.name, 'node2', 'node2 name');
    equal(child2.name, 'child2', 'child2 name');

    // move child2 after node2
    tree.moveNode(child2, node2, Tree.Position.AFTER);

    /*
      node1
      ---child1
      node2
      ---child3
      child2
    */
    equal(
        format_nodes(tree.children),
        'node1 node2 child2',
        'tree nodes at first level'
    );
    equal(
        format_nodes(node1.children),
        'child1',
        'node1 children'
    );

    // move child1 inside node2
    // this means it's the first child
    tree.moveNode(child1, node2, Tree.Position.INSIDE);

    /*
      node1
      node2
      ---child1
      ---child3
      child2
    */
    equal(
        format_nodes(node2.children),
        'child1 child3',
        'node2 children'
    );
    equal(
        format_nodes(node1.children),
        '',
        'node1 has no children'
    );

    // move child2 before child1
    tree.moveNode(child2, child1, Tree.Position.BEFORE);

    /*
      node1
      node2
      ---child2
      ---child1
      ---child3
    */
    equal(
        format_nodes(node2.children),
        'child2 child1 child3',
        'node2 children'
    );
    equal(
        format_nodes(tree.children),
        'node1 node2',
        'tree nodes at first level'
    );
})

});
<commit_msg>Added test for toJson function<commit_after>$(function() {

var example_data = [
    {
        label: 'node1',
        id: 123,  // extra data
        children: [
            { label: 'child1' },
            { label: 'child2' }
        ]
    },
    {
        label: 'node2',
        id: 124,
        children: [
            { label: 'child3' }
        ]
    }
];

var format_nodes = function(nodes) {
    var strings = $.map(nodes, function(node) {
        return node.name;
    });
    return strings.join(' ');
};

var isNodeClosed = function($node) {
    return (
        ($node.is('li.folder.closed')) &&
        ($node.find('a:eq(0)').is('a.toggler.closed')) &&
        ($node.find('ul:eq(0)').is('ul'))
    );
}

var isNodeOpen = function($node) {
    return (
        ($node.is('li.folder')) &&
        ($node.find('a:eq(0)').is('a.toggler')) &&
        ($node.find('ul:eq(0)').is('ul')) &&
        (! $node.is('li.folder.closed')) &&
        (! $node.find('span:eq(0)').is('a.toggler.closed'))
    );
}

module("jqtree", {
    teardown: function() {
        $('#tree1').tree('destroy');
    }
});

test("create jqtree from data", function() {
    $('#tree1').tree({
        data: example_data
    });

    equal(
        $('#tree1').children().length, 1,
        'number of children on level 0'
    );
    ok(
        $('#tree1').children().is('ul.tree'),
        'first element is ul.tree'
    );
    equal(
        $('#tree1 ul.tree > li').length, 2,
        'number of children on level 1'
    );
    ok(
        $('#tree1 ul.tree li:eq(0)').is('li.folder.closed'),
        'first child is li.folder.closed'
    );
    ok(
        $('#tree1 ul.tree li:eq(0) > div > a.toggler').is('a.toggler.closed'),
        'button in first folder'
    );
    equal(
        $('#tree1 ul.tree li:eq(0) > div span.title').text(),
        'node1'
    );
});

test('jqtree toggle', function() {
    // create tree
    var $tree = $('#tree1');
    $tree.tree({
        data: example_data
    });

    var tree = $tree.tree('getTree');
    var node1 = tree.children[0];
    var $node1 = $tree.find('ul.tree li:eq(0)');

    // node1 is initially closed
    ok(isNodeClosed($node1), 'node1 is open');

    stop();

    // open node1
    $tree.tree(
        'toggle',
        node1,
        function() {
            start();

            ok(isNodeOpen($node1), 'node1 is open');

            stop();

            // close node1
            $tree.tree(
                'toggle',
                node1,
                function() {
                    start();

                    ok(isNodeClosed($node1), 'node1 is closed');
                }
            );
        }
    );
});

// todo: test jqtree.getTree()

test("click event", function() {
    stop(2000);

    // create tree
    var $tree = $('#tree1');

    $tree.tree({
        data: example_data,
        onClick: function(node) {
            start();
            equal(node.name, 'node1');
        }
    });

    // click on node1
    var $node1 = $tree.find('ul.tree li:first');
    var $text_span = $node1.find('span:first');
    $text_span.click();
});

test('saveState', function() {
    var $tree = $('#tree1');

    var saved_state;

    function setState(state) {
        saved_state = state;
    }

    function getState() {
        return saved_state;
    }

    function createTree() {
        $tree.tree({
            data: example_data,
            saveState: true,
            onSetStateFromStorage: setState,
            onGetStateFromStorage: getState,
            selectable: true
        });
    }

    // create tree
    createTree();

    // nodes are initially closed
    var tree = $tree.tree('getTree');
    tree.iterate(function(node) {
        ok(! node.is_open, 'closed');
        return true;
    });

    // open node1
    $tree.tree('toggle', tree.children[0]);

    // node1 is open
    ok(tree.children[0].is_open, 'node1 is_open');

    // select node2
    $tree.tree('selectNode', tree.children[1]);

    // node2 is selected
    equal(
        $tree.tree('getSelectedNode').name,
        'node2',
        'getSelectedNode'
    );

    // create tree again
    $tree.tree('destroy');
    createTree();

    tree = $tree.tree('getTree');
    ok(tree.children[0].is_open, 'node1 is_open');
    ok(! tree.children[1].is_open, 'node2 is closed');

    // node2 is selected
    equal(
        $tree.tree('getSelectedNode').name,
        'node2',
        'getSelectedNode'
    );
});

test('getSelectedNode', function() {
    var $tree = $('#tree1');

    // create tree
    $tree.tree({
        data: example_data,
        selectable: true
    });

    // there is no node selected
    equal(
        $tree.tree('getSelectedNode'),
        false,
        'getSelectedNode'
    );

    // select node1
    var tree = $tree.tree('getTree');
    var node1 = tree.children[0];
    $tree.tree('selectNode', node1);

    // node1 is selected
    equal(
        $tree.tree('getSelectedNode').name,
        'node1',
        'getSelectedNode'
    );
});

module("Tree");
test("create tree from data", function() {
    var tree = new Tree.Tree();
    tree.loadFromData(example_data);

    equal(
        format_nodes(tree.children),
        'node1 node2',
        'nodes on level 1'
    );
    equal(
        format_nodes(tree.children[0].children),
        'child1 child2',
        'children of node1'
    );
    equal(
        format_nodes(tree.children[1].children),
        'child3',
        'children of node2'
    );
    equal(
        tree.children[0].id,
        123,
        'id'
    );
});

test("tree addChild", function() {
    var tree = new Tree.Tree('tree1');
    tree.addChild(
        new Tree.Node('abc')
    );
    tree.addChild(
        new Tree.Node('def')
    );

    equal(
        format_nodes(tree.children),
        'abc def',
        'children'
    );

    var node = tree.children[0];
    equal(
        node.parent.name,
        'tree1',
        'parent of node'
    );
});

test('tree addChildAtPosition', function() {
    var tree = new Tree.Tree();
    tree.addChildAtPosition(new Tree.Node('abc'), 0);  // first
    tree.addChildAtPosition(new Tree.Node('ghi'), 2);  // index 2 does not exist
    tree.addChildAtPosition(new Tree.Node('def'), 1);
    tree.addChildAtPosition(new Tree.Node('123'), 0);

    equal(
        format_nodes(tree.children),
        '123 abc def ghi',
        'children'
    );
});

test('tree removeChild', function() {
    var tree = new Tree.Tree();

    var abc = new Tree.Node('abc');
    var def = new Tree.Node('def');
    var ghi = new Tree.Node('ghi');
    tree.addChild(abc);
    tree.addChild(def);
    tree.addChild(ghi);

    equal(
        format_nodes(tree.children),
        'abc def ghi',
        'children'
    );

    // remove 'def'
    tree.removeChild(def);
    equal(
        format_nodes(tree.children),
        'abc ghi',
        'children'
    );

    // remove 'ghi'
    tree.removeChild(ghi);
    equal(
        format_nodes(tree.children),
        'abc',
        'children'
    );

    // remove 'abc'
    tree.removeChild(abc);
    equal(
        format_nodes(tree.children),
        '',
        'children'
    );
});

test('tree getChildIndex', function() {
    var tree = new Tree.Tree();

    var abc = new Tree.Node('abc');
    var def = new Tree.Node('def');
    var ghi = new Tree.Node('ghi');
    tree.addChild(abc);
    tree.addChild(def);
    tree.addChild(ghi);

    equal(
        tree.getChildIndex(def),
        1,
        'indef of def'
    );
});

test('tree hasChildren', function() {
    var tree = new Tree.Tree();
    equal(
        tree.hasChildren(),
        false,
        'tree without children'
    );

    tree.addChild(new Tree.Node('abc'));
    equal(
        tree.hasChildren(),
        true,
        'tree has children'
    );
});

test('tree iterate', function() {
    var tree = new Tree.Tree();
    tree.loadFromData(example_data);

    // iterate over all the nodes
    var nodes = [];
    tree.iterate(
        function(node, level) {
            nodes.push(node);
            return true;
        }
    );

    equal(
        format_nodes(nodes),
        'node1 child1 child2 node2 child3',
        'all nodes'
    );

    // iterate over nodes on first level
    nodes = [];
    tree.iterate(
        function(node, level) {
            nodes.push(node);
            return false;
        }
    );

    equal(
        format_nodes(nodes),
        'node1 node2',
        'nodes on first level'
    );
});

test('tree moveNode', function() {
    var tree = Tree.Tree.createFromData(example_data);

    /*
      node1
      ---child1
      ---child2
      node2
      ---child3
    */

    var node1 = tree.children[0];
    var node2 = tree.children[1];
    var child1 = node1.children[0];
    var child2 = node1.children[1];
    equal(node2.name, 'node2', 'node2 name');
    equal(child2.name, 'child2', 'child2 name');

    // move child2 after node2
    tree.moveNode(child2, node2, Tree.Position.AFTER);

    /*
      node1
      ---child1
      node2
      ---child3
      child2
    */
    equal(
        format_nodes(tree.children),
        'node1 node2 child2',
        'tree nodes at first level'
    );
    equal(
        format_nodes(node1.children),
        'child1',
        'node1 children'
    );

    // move child1 inside node2
    // this means it's the first child
    tree.moveNode(child1, node2, Tree.Position.INSIDE);

    /*
      node1
      node2
      ---child1
      ---child3
      child2
    */
    equal(
        format_nodes(node2.children),
        'child1 child3',
        'node2 children'
    );
    equal(
        format_nodes(node1.children),
        '',
        'node1 has no children'
    );

    // move child2 before child1
    tree.moveNode(child2, child1, Tree.Position.BEFORE);

    /*
      node1
      node2
      ---child2
      ---child1
      ---child3
    */
    equal(
        format_nodes(node2.children),
        'child2 child1 child3',
        'node2 children'
    );
    equal(
        format_nodes(tree.children),
        'node1 node2',
        'tree nodes at first level'
    );

    test("tree toJson", function() {
        // setup
        var $tree = $('#tree1');
        $tree.tree({
            data: example_data
        });

        // 1. call toJson
        equal(
            $tree.tree('toJson'),
            '[{"name":"node1","children":'+
            '[{"name":"child1"},{"name":"child2"}],"id":123},'+
            '{"name":"node2","children":[{"name":"child3"}],"id":124}]'
        );

        // Check that properties 'children', 'parent' and 'element' still exist.
        var tree = $tree.tree('getTree');
        equal(tree.children.length, 2);
        ok(tree.children[0].parent != undefined, 'parent');
        ok($(tree.children[0].element).is('li'), 'element');
    });
})

});
<|endoftext|>


<commit_before>import Mixin from '@ember/object/mixin';
import { cancel, later } from '@ember/runloop';

export default Mixin.create({
  actions: {
    prevent() {
      return false;
    },

    open(dropdown) {
      if (this.closeTimer) {
        cancel(this.closeTimer);
        this.closeTimer = null;
      } else {
        dropdown.actions.open();
      }
    },

    closeLater(dropdown) {
      this.closeTimer = later(() => {
        this.closeTimer = null;
        dropdown.actions.close();
      }, 200);
    }
  },

});
<commit_msg>fix random open hover dropdown remaining open<commit_after>import Mixin from '@ember/object/mixin';
import { next, cancel, later } from '@ember/runloop';
import { get, set } from '@ember/object';

export default Mixin.create({
  clostTimer: null,

  actions: {
    prevent() {
      return false;
    },

    open(dropdown) {
      const ct = get(this, 'clostTimer');

      if (ct) {

        next(() => {
          cancel(ct);
        });

        set(this, 'clostTimer', null);

      } else {

        next(() => {
          dropdown.actions.open();
        });

      }
    },

    closeLater(dropdown) {

      this.closeTimer = later(() => {

        this.closeTimer = null;

        dropdown.actions.close();

      }, 200);

    }
  },

});
<|endoftext|>


<commit_before>const ScopeParser = require("../lib/ScopeParser.js");
const fs = require('fs');
const path = require('path');
const beautify = require('js-beautify').js_beautify;
const assert = require('assert');

let scope = new ScopeParser();
let srcDir = path.join(__dirname, "scopeSrc");
let libDir = path.join(__dirname, "scopeLib");
let expectDir = path.join(__dirname, "scopeExpect");
let srcFiles = fs.readdirSync(srcDir);

const tests = [];

srcFiles.forEach((f) => {
	let srcFilename = path.join(srcDir, f);
	let libFilename = path.join(libDir, f.replace(".sc", ".js"));
	let expectFilename = path.join(expectDir, f.replace(".sc", ".js"));
	//let astFilename = path.join(libDir, f.replace(".sc", ".json"));
	let srcCode = fs.readFileSync(srcFilename, "utf8");
	let translation = scope.translate(srcCode);
	//let libAst = JSON.stringify(translation.ast, null, "  ");
	//fs.writeFileSync(astFilename, libAst);
	fs.writeFileSync(libFilename, beautify(translation.js, {indent_size: 2}));
	tests.push({
		program: require(libFilename),
		expectation: require(expectFilename)
	});
});

tests.forEach((obj) => {
	obj.expectation(assert, obj.program);
});<commit_msg>Create lib dir if it doesn't exist<commit_after>const ScopeParser = require("../lib/ScopeParser.js");
const fs = require('fs');
const path = require('path');
const beautify = require('js-beautify').js_beautify;
const assert = require('assert');

let scope = new ScopeParser();
let srcDir = path.join(__dirname, "scopeSrc");
let libDir = path.join(__dirname, "scopeLib");
let expectDir = path.join(__dirname, "scopeExpect");
let srcFiles = fs.readdirSync(srcDir);

const tests = [];

srcFiles.forEach((f) => {
	let srcFilename = path.join(srcDir, f);
	let libFilename = path.join(libDir, f.replace(".sc", ".js"));
	let expectFilename = path.join(expectDir, f.replace(".sc", ".js"));
	//let astFilename = path.join(libDir, f.replace(".sc", ".json"));
	let srcCode = fs.readFileSync(srcFilename, "utf8");
	let translation = scope.translate(srcCode);
	//let libAst = JSON.stringify(translation.ast, null, "  ");
	//fs.writeFileSync(astFilename, libAst);
	if (!fs.existsSync(libDir)) {
		fs.mkdirSync(libDir);
	}
	fs.writeFileSync(libFilename, beautify(translation.js, {indent_size: 2}));
	tests.push({
		program: require(libFilename),
		expectation: require(expectFilename)
	});
});

tests.forEach((obj) => {
	obj.expectation(assert, obj.program);
});<|endoftext|>


<commit_before>var ts = require("./tile-system");
var cu = require("./coordinate-utils");
var assert = require("assert");
var stream = require('stream')
var Readable = stream.Readable;

var MaxDetailLevel = 22;

module.exports = function(db){

  function idToKey(id, callback){
    const key = "keys~" + id;
    return db.get(key);
  }

  /* SLOW */
  function put(position, id, value, callback){
    var newKey = encodeLevelKey(position, id);
    // look up old key
    return idToKey(id)
    .catch(ignoreNotFoundErrors)
    .then(oldKey => {
      var batch = [];

      // add the main update to the batch
      batch.push({type:"put", key:"geos~" + newKey, value:value});
      if (oldKey){
        // remove the old key
        batch.push({type:"del", key:"geos~" + oldKey});
      }
      // update the pointer
      batch.push({type:"put", key:"keys~" + id, value:newKey});
      return db.batch(batch)
      .then(passResToCallbackOrReturn.bind(null, callback))
      .catch(passErrToCallbackOrRethrow(callback));
    });
  }

  /* SLOW */
  function getById(id, callback){
    return idToKey(id)
    .then(key => {
      const geoKey = "geos~" + key;
      return db.get(geoKey)
      .then(data => {
        var output = decodeLevelKey(geoKey);
        output.value = data;
        return passResToCallbackOrReturn(callback, output);
      })
    })
    .catch(passErrToCallbackOrRethrow(callback));
  }

  function get(position, id, callback){
    const key = encodeLevelKey(position, id);
    const geoKey = "geos~" + key;
    return db.get(geoKey)
    .then(data => {
      var output = decodeLevelKey(geoKey);
      output.value = data;
      return passResToCallbackOrReturn(callback, output);
    })
    .catch(passErrToCallbackOrRethrow(callback));
  }

  /* SLOW */
  function del(id, callback){
    return idToKey(id)
    .then(oldKey => {
      if (oldKey){
        var batch = [];
        batch.push({type:"del", key:"keys~" + id});
        batch.push({type:"del", key:"geos~" + oldKey});
        return db.batch(batch)
        .then(passResToCallbackOrReturn.bind(null, callback));
      } else {
        return passResToCallbackOrReturn(callback);
      }
    })
    .catch(passErrToCallbackOrRethrow(callback));
  }

  function search(position, radius){
    var stream = new Readable({objectMode : true});
    var quadKeys = getSearchRange(position,radius);
    var openStreams = 0;
    //var total = 0;
    //var hits = 0;

    quadKeys.forEach(function(quadKey){

      //console.log("http://ak.dynamic.t1.tiles.virtualearth.net/comp/ch/" + quadKey + "?mkt=en-gb&it=G,VE,BX,L,LA&shading=hill&og=18&n=z");

      var options = {}
      options.start = "geos~" + quadKey;
      options.end =  "geos~" + quadKey + "~";
      openStreams++;

      db.createReadStream(options)
        .on('data', function (data) {
          //total++;
        //console.log(data);

          var key = decodeLevelKey(data.key);

          var d = cu.distance(parseFloat(position.lat),parseFloat(position.lon),key.position.lat,key.position.lon);

          if (d <= radius){
            //hits++;
            key.distance = d;
            key.value = data.value;
            stream.push(key);
          }

        })
        .on('end', function () {
          openStreams--;
          if (openStreams == 0) {
            stream.push(null);
            //console.log("stats:" + hits + "/" + total);
          }
        });
      stream._read = function(){};

    });

    return stream;
  }

  function searchKey(position,depth){
    var pixelCoords = ts.latLonToPixelXY(position.lat,position.lon,depth);
    var tileCoords = ts.pixelXYToTileXY(pixelCoords.pixelX,pixelCoords.pixelY);
    return ts.tileXYToQuadKey(tileCoords.tileX,tileCoords.tileY,depth);
  }

  function latLonToQuadKey(position, level){
    var pixelCoords = ts.latLonToPixelXY(position.lat,position.lon,level);
    var tileCoords = ts.pixelXYToTileXY(pixelCoords.pixelX,pixelCoords.pixelY);
    return ts.tileXYToQuadKey(tileCoords.tileX,tileCoords.tileY,level);
  }

  function encodeLevelKey(position, id){
    id = String(id).replace("~","");
    return latLonToQuadKey(position, MaxDetailLevel) + "~" + String(position.lat) + "~" + String(position.lon) + "~" + id;
  }

  function decodeLevelKey(key){
    var parts = key.split("~");
    return {
      quadKey: parts[1],
      position: {
        lat: parseFloat(parts[2]),
        lon: parseFloat(parts[3])},
      id: parts[4]
    }
  }

  function getSearchRange(position, radius){
    var box = cu.boundingRectangle(position.lat, position.lon, radius);
    var topLeft = ts.latLonToPixelXY(box.top,box.left,MaxDetailLevel);
    var bottomRight = ts.latLonToPixelXY(box.bottom,box.right,MaxDetailLevel);
    var numberOfTilesAtMaxDepth = Math.floor((bottomRight.pixelX - topLeft.pixelX) / 256);
    var zoomLevelsToRise = Math.floor(Math.log(numberOfTilesAtMaxDepth) / Math.log(2));
    zoomLevelsToRise++;

    var quadDictionary = {};
    quadDictionary[latLonToQuadKey({lat:box.top, lon:box.left},Math.max(0,MaxDetailLevel - zoomLevelsToRise))] = true;
    quadDictionary[latLonToQuadKey({lat:box.top, lon:box.right},Math.max(0,MaxDetailLevel - zoomLevelsToRise))] = true;
    quadDictionary[latLonToQuadKey({lat:box.bottom, lon:box.left},Math.max(0,MaxDetailLevel - zoomLevelsToRise))] = true;
    quadDictionary[latLonToQuadKey({lat:box.bottom, lon:box.right},Math.max(0,MaxDetailLevel - zoomLevelsToRise))] = true;

    var quadList = [];
    for (x in quadDictionary){
      quadList.push(x);
    }

    return quadList;
  }

  return {
    put:put,
    search:search,
    getByKey:getById,
    get:get,
    del:del
  };
}

const passResToCallbackOrReturn = (callback, res) => {
  if (callback){
    callback(null,res);
  } else {
    return res;
  };
};

const passErrToCallbackOrRethrow = callback => err => {
  if (callback){
    callback(err);
  } else {
    throw err;
  };
};

const ignoreNotFoundErrors = err => {
  if (err.name === 'NotFoundError') {
    return;
  } else {
    throw err;
  }
};
<commit_msg>use `gte` and `lte` insted of `start` and `end`<commit_after>var ts = require("./tile-system");
var cu = require("./coordinate-utils");
var assert = require("assert");
var stream = require('stream')
var Readable = stream.Readable;

var MaxDetailLevel = 22;

module.exports = function(db){

  function idToKey(id, callback){
    const key = "keys~" + id;
    return db.get(key);
  }

  /* SLOW */
  function put(position, id, value, callback){
    var newKey = encodeLevelKey(position, id);
    // look up old key
    return idToKey(id)
    .catch(ignoreNotFoundErrors)
    .then(oldKey => {
      var batch = [];

      // add the main update to the batch
      batch.push({type:"put", key:"geos~" + newKey, value:value});
      if (oldKey){
        // remove the old key
        batch.push({type:"del", key:"geos~" + oldKey});
      }
      // update the pointer
      batch.push({type:"put", key:"keys~" + id, value:newKey});
      return db.batch(batch)
      .then(passResToCallbackOrReturn.bind(null, callback))
      .catch(passErrToCallbackOrRethrow(callback));
    });
  }

  /* SLOW */
  function getById(id, callback){
    return idToKey(id)
    .then(key => {
      const geoKey = "geos~" + key;
      return db.get(geoKey)
      .then(data => {
        var output = decodeLevelKey(geoKey);
        output.value = data;
        return passResToCallbackOrReturn(callback, output);
      })
    })
    .catch(passErrToCallbackOrRethrow(callback));
  }

  function get(position, id, callback){
    const key = encodeLevelKey(position, id);
    const geoKey = "geos~" + key;
    return db.get(geoKey)
    .then(data => {
      var output = decodeLevelKey(geoKey);
      output.value = data;
      return passResToCallbackOrReturn(callback, output);
    })
    .catch(passErrToCallbackOrRethrow(callback));
  }

  /* SLOW */
  function del(id, callback){
    return idToKey(id)
    .then(oldKey => {
      if (oldKey){
        var batch = [];
        batch.push({type:"del", key:"keys~" + id});
        batch.push({type:"del", key:"geos~" + oldKey});
        return db.batch(batch)
        .then(passResToCallbackOrReturn.bind(null, callback));
      } else {
        return passResToCallbackOrReturn(callback);
      }
    })
    .catch(passErrToCallbackOrRethrow(callback));
  }

  function search(position, radius){
    var stream = new Readable({objectMode : true});
    var quadKeys = getSearchRange(position,radius);
    var openStreams = 0;
    //var total = 0;
    //var hits = 0;

    quadKeys.forEach(function(quadKey){

      //console.log("http://ak.dynamic.t1.tiles.virtualearth.net/comp/ch/" + quadKey + "?mkt=en-gb&it=G,VE,BX,L,LA&shading=hill&og=18&n=z");

      var options = {}
      options.gte = "geos~" + quadKey;
      options.lte =  "geos~" + quadKey + "~";
      openStreams++;

      db.createReadStream(options)
        .on('data', function (data) {
          //total++;
        //console.log(data);

          var key = decodeLevelKey(data.key);

          var d = cu.distance(parseFloat(position.lat),parseFloat(position.lon),key.position.lat,key.position.lon);

          if (d <= radius){
            //hits++;
            key.distance = d;
            key.value = data.value;
            stream.push(key);
          }

        })
        .on('end', function () {
          openStreams--;
          if (openStreams == 0) {
            stream.push(null);
            //console.log("stats:" + hits + "/" + total);
          }
        });
      stream._read = function(){};

    });

    return stream;
  }

  function searchKey(position,depth){
    var pixelCoords = ts.latLonToPixelXY(position.lat,position.lon,depth);
    var tileCoords = ts.pixelXYToTileXY(pixelCoords.pixelX,pixelCoords.pixelY);
    return ts.tileXYToQuadKey(tileCoords.tileX,tileCoords.tileY,depth);
  }

  function latLonToQuadKey(position, level){
    var pixelCoords = ts.latLonToPixelXY(position.lat,position.lon,level);
    var tileCoords = ts.pixelXYToTileXY(pixelCoords.pixelX,pixelCoords.pixelY);
    return ts.tileXYToQuadKey(tileCoords.tileX,tileCoords.tileY,level);
  }

  function encodeLevelKey(position, id){
    id = String(id).replace("~","");
    return latLonToQuadKey(position, MaxDetailLevel) + "~" + String(position.lat) + "~" + String(position.lon) + "~" + id;
  }

  function decodeLevelKey(key){
    var parts = key.split("~");
    return {
      quadKey: parts[1],
      position: {
        lat: parseFloat(parts[2]),
        lon: parseFloat(parts[3])},
      id: parts[4]
    }
  }

  function getSearchRange(position, radius){
    var box = cu.boundingRectangle(position.lat, position.lon, radius);
    var topLeft = ts.latLonToPixelXY(box.top,box.left,MaxDetailLevel);
    var bottomRight = ts.latLonToPixelXY(box.bottom,box.right,MaxDetailLevel);
    var numberOfTilesAtMaxDepth = Math.floor((bottomRight.pixelX - topLeft.pixelX) / 256);
    var zoomLevelsToRise = Math.floor(Math.log(numberOfTilesAtMaxDepth) / Math.log(2));
    zoomLevelsToRise++;

    var quadDictionary = {};
    quadDictionary[latLonToQuadKey({lat:box.top, lon:box.left},Math.max(0,MaxDetailLevel - zoomLevelsToRise))] = true;
    quadDictionary[latLonToQuadKey({lat:box.top, lon:box.right},Math.max(0,MaxDetailLevel - zoomLevelsToRise))] = true;
    quadDictionary[latLonToQuadKey({lat:box.bottom, lon:box.left},Math.max(0,MaxDetailLevel - zoomLevelsToRise))] = true;
    quadDictionary[latLonToQuadKey({lat:box.bottom, lon:box.right},Math.max(0,MaxDetailLevel - zoomLevelsToRise))] = true;

    var quadList = [];
    for (x in quadDictionary){
      quadList.push(x);
    }

    return quadList;
  }

  return {
    put:put,
    search:search,
    getByKey:getById,
    get:get,
    del:del
  };
}

const passResToCallbackOrReturn = (callback, res) => {
  if (callback){
    callback(null,res);
  } else {
    return res;
  };
};

const passErrToCallbackOrRethrow = callback => err => {
  if (callback){
    callback(err);
  } else {
    throw err;
  };
};

const ignoreNotFoundErrors = err => {
  if (err.name === 'NotFoundError') {
    return;
  } else {
    throw err;
  }
};
<|endoftext|>


<commit_before>/*global describe, it */
'use strict';
var should = require('should');
var japanese = require('../');

describe('japanese.hiraganize()', function () {
    it('must perfectly convert given katakana into hiragana', function () {
        japanese.hiraganize('モンブラン').should.be.exactly('もんぶらん');
        japanese.hiraganize('ティラミス').should.be.exactly('てぃらみす');
        japanese.hiraganize('ジェラート').should.be.exactly('じぇらーと');
        japanese.hiraganize('セミフレッド').should.be.exactly('せみふれっど');
        japanese.hiraganize('パンナコッタ').should.be.exactly('ぱんなこった');
    });

    it('must perfectly convert katakana-mixed string into hiragana', function () {
        japanese.hiraganize('フェレロ・ロシェ').should.be.exactly('ふぇれろ・ろしぇ');
        japanese.hiraganize('あんドーナツ').should.be.exactly('あんどーなつ');
        japanese.hiraganize('抹茶アイス').should.be.exactly('抹茶あいす');
        japanese.hiraganize('牛乳プリン').should.be.exactly('牛乳ぷりん');
        japanese.hiraganize('リコリス菓子').should.be.exactly('りこりす菓子');
    });

    it('must perfectly convert strange katakana string into hiragana', function () {
        japanese.hiraganize('バクラヴァ').should.be.exactly('ばくらゔぁ');
        japanese.hiraganize('ヴァレニエ').should.be.exactly('ゔぁれにえ');
        japanese.hiraganize('ヱヴァンゲリヲン').should.be.exactly('ゑゔぁんげりをん');
        japanese.hiraganize('チヨコバナヽ').should.be.exactly('ちよこばなゝ');
        japanese.hiraganize('バヾヘラアイス').should.be.exactly('ばゞへらあいす');
    });

    it('must convert unconvertable voiced katakanaes using combining characters', function () {
        japanese.hiraganize('ヸヨロン').should.be.exactly('ゐ゙よろん');
        japanese.hiraganize('ヹルタースオリジナル').should.be.exactly('ゑ゙るたーすおりじなる');
        japanese.hiraganize('シユヷルツヹルダーキルシユトルテ').should.be.exactly('しゆわ゙るつゑ゙るだーきるしゆとるて');
        japanese.hiraganize('ビスコツテイサヺイアルデイ').should.be.exactly('びすこつていさを゙いあるでい');
        japanese.hiraganize('ルートヸヒシユトルヹルク').should.be.exactly('るーとゐ゙ひしゆとるゑ゙るく');
    });

    it('must convert katakana digraphs into separated hiraganaes', function () {
        japanese.hiraganize('オ菓子ヲ食スヿコレ快ナリ').should.be.exactly('お菓子を食すことこれ快なり');
        japanese.hiraganize('板垣死ス𪜈オ菓子ハ死セズ').should.be.exactly('板垣死すともお菓子は死せず');
        japanese.hiraganize('食エ𪜈゙食エ𪜈゙オ菓子ノ山').should.be.exactly('食えども食えどもお菓子の山');
    });

    it('must keep small-ka and small-ke untouched', function () {
        japanese.hiraganize('どら焼 3ヶ入').should.be.exactly('どら焼 3ヶ入');
        japanese.hiraganize('一ヵ月のダイエット').should.be.exactly('一ヵ月のだいえっと');
    });

    it('must keep non-japanese strings untouched', function () {
        japanese.hiraganize('Chocolate').should.be.exactly('Chocolate');
        japanese.hiraganize('Tiramisù').should.be.exactly('Tiramisù');
        japanese.hiraganize('пряник').should.be.exactly('пряник');
        japanese.hiraganize('ฝอยทอง').should.be.exactly('ฝอยทอง');
        japanese.hiraganize('龜苓膏').should.be.exactly('龜苓膏');
    });
});
<commit_msg>Write tests for japanese.katakanize()<commit_after>/*global describe, it */
'use strict';
var should = require('should');
var japanese = require('../');

describe('japanese.hiraganize()', function () {
    it('must perfectly convert given katakana into hiragana', function () {
        japanese.hiraganize('モンブラン').should.be.exactly('もんぶらん');
        japanese.hiraganize('ティラミス').should.be.exactly('てぃらみす');
        japanese.hiraganize('ジェラート').should.be.exactly('じぇらーと');
        japanese.hiraganize('セミフレッド').should.be.exactly('せみふれっど');
        japanese.hiraganize('パンナコッタ').should.be.exactly('ぱんなこった');
    });

    it('must perfectly convert katakana-mixed string into hiragana', function () {
        japanese.hiraganize('フェレロ・ロシェ').should.be.exactly('ふぇれろ・ろしぇ');
        japanese.hiraganize('あんドーナツ').should.be.exactly('あんどーなつ');
        japanese.hiraganize('抹茶アイス').should.be.exactly('抹茶あいす');
        japanese.hiraganize('牛乳プリン').should.be.exactly('牛乳ぷりん');
        japanese.hiraganize('リコリス菓子').should.be.exactly('りこりす菓子');
    });

    it('must perfectly convert strange katakana string into hiragana', function () {
        japanese.hiraganize('バクラヴァ').should.be.exactly('ばくらゔぁ');
        japanese.hiraganize('ヴァレニエ').should.be.exactly('ゔぁれにえ');
        japanese.hiraganize('ヱヴァンゲリヲン').should.be.exactly('ゑゔぁんげりをん');
        japanese.hiraganize('チヨコバナヽ').should.be.exactly('ちよこばなゝ');
        japanese.hiraganize('バヾヘラアイス').should.be.exactly('ばゞへらあいす');
    });

    it('must convert unconvertable voiced katakanaes using combining characters', function () {
        japanese.hiraganize('ヸヨロン').should.be.exactly('ゐ゙よろん');
        japanese.hiraganize('ヹルタースオリジナル').should.be.exactly('ゑ゙るたーすおりじなる');
        japanese.hiraganize('シユヷルツヹルダーキルシユトルテ').should.be.exactly('しゆわ゙るつゑ゙るだーきるしゆとるて');
        japanese.hiraganize('ビスコツテイサヺイアルデイ').should.be.exactly('びすこつていさを゙いあるでい');
        japanese.hiraganize('ルートヸヒシユトルヹルク').should.be.exactly('るーとゐ゙ひしゆとるゑ゙るく');
    });

    it('must convert katakana digraphs into separated hiraganaes', function () {
        japanese.hiraganize('オ菓子ヲ食スヿコレ快ナリ').should.be.exactly('お菓子を食すことこれ快なり');
        japanese.hiraganize('板垣死ス𪜈オ菓子ハ死セズ').should.be.exactly('板垣死すともお菓子は死せず');
        japanese.hiraganize('食エ𪜈゙食エ𪜈゙オ菓子ノ山').should.be.exactly('食えども食えどもお菓子の山');
    });

    it('must keep small-ka and small-ke untouched', function () {
        japanese.hiraganize('どら焼 3ヶ入').should.be.exactly('どら焼 3ヶ入');
        japanese.hiraganize('一ヵ月のダイエット').should.be.exactly('一ヵ月のだいえっと');
    });

    it('must keep non-japanese strings untouched', function () {
        japanese.hiraganize('Chocolate').should.be.exactly('Chocolate');
        japanese.hiraganize('Tiramisù').should.be.exactly('Tiramisù');
        japanese.hiraganize('пряник').should.be.exactly('пряник');
        japanese.hiraganize('ฝอยทอง').should.be.exactly('ฝอยทอง');
        japanese.hiraganize('龜苓膏').should.be.exactly('龜苓膏');
    });
});

describe('japanese.katakanize()', function () {
    it('must perfectly convert given hiragana into katakana', function () {
        japanese.katakanize('もんぶらん').should.be.exactly('モンブラン');
        japanese.katakanize('てぃらみす').should.be.exactly('ティラミス');
        japanese.katakanize('じぇらーと').should.be.exactly('ジェラート');
        japanese.katakanize('せみふれっど').should.be.exactly('セミフレッド');
        japanese.katakanize('ぱんなこった').should.be.exactly('パンナコッタ');
    });

    it('must perfectly convert hiragana-mixed string into katakana', function () {
        japanese.katakanize('ふぇれろ・ろしぇ').should.be.exactly('フェレロ・ロシェ');
        japanese.katakanize('あんどーなつ').should.be.exactly('あんドーナツ');
        japanese.katakanize('抹茶あいす').should.be.exactly('抹茶アイス');
        japanese.katakanize('牛乳ぷりん').should.be.exactly('牛乳プリン');
        japanese.katakanize('りこりす菓子').should.be.exactly('リコリス菓子');
    });

    it('must perfectly convert strange hiragana string into katakana', function () {
        japanese.katakanize('ばくらゔぁ').should.be.exactly('バクラヴァ');
        japanese.katakanize('ゔぁれにえ').should.be.exactly('ヴァレニエ');
        japanese.katakanize('ゑゔぁんげりをん').should.be.exactly('ヱヴァンゲリヲン');
        japanese.katakanize('ちよこばなゝ').should.be.exactly('チヨコバナヽ');
        japanese.katakanize('ばゞへらあいす').should.be.exactly('バヾヘラアイス');
    });

    it('must convert hiragana with combining characters just like normal characters', function () {
        japanese.katakanize('ゐ゙よろん').should.be.exactly('ヸヨロン');
        japanese.katakanize('ゑ゙るたーすおりじなる').should.be.exactly('ヹルタースオリジナル');
        japanese.katakanize('しゆわ゙るつゑ゙るだーきるしゆとるて').should.be.exactly('シユヷルツヹルダーキルシユトルテ');
        japanese.katakanize('びすこつていさを゙いあるでい').should.be.exactly('ビスコツテイサヺイアルデイ');
        japanese.katakanize('るーとゐ゙ひしゆとるゑ゙るく').should.be.exactly('ルートヸヒシユトルヹルク');
    });

    it('must convert katakana digraphs into separated hiraganaes', function () {
        japanese.katakanize('本日ゟかき氷解禁').should.be.exactly('本日ヨリカキ氷解禁');
    });

    it('must keep non-japanese strings untouched', function () {
        japanese.katakanize('Chocolate').should.be.exactly('Chocolate');
        japanese.katakanize('Tiramisù').should.be.exactly('Tiramisù');
        japanese.katakanize('пряник').should.be.exactly('пряник');
        japanese.katakanize('ฝอยทอง').should.be.exactly('ฝอยทอง');
        japanese.katakanize('龜苓膏').should.be.exactly('龜苓膏');
    });
});
<|endoftext|>


<commit_before>// ViewState stores a State and some additional information used for a StateView specifically.
// These states are used internally by a StateView.
function ViewState(positive, normative, attrs) {
  this.positive = new PositiveState(positive);
  this.normative = new NormativeState(normative);

  this.viewFrozen = defaultValue(attrs.viewFrozen, false);

  this.yLabels = defaultValue(attrs.yLabels, null);

  this.chunkView = defaultValue(attrs.chunkView, null);
  this.chunkViewStartIndex = defaultValue(attrs.chunkViewStartIndex, -1);
  this.chunkViewLength = defaultValue(attrs.chunkViewLength, -1);

  this.showingContent = defaultValue(attrs.showingContent, false);
  this.animate = defaultValue(attrs.animate, false);

  this.animating = defaultValue(attrs.animating, false);
  this.animationChunkView = defaultValue(attrs.animationChunkView, null);
  this.animationProgress = defaultValue(attrs.animationProgress, -1);
  this.startLeftmostLabelWidth = defaultValue(attrs.startLeftmostLabelWidth, -1);
  this.startYLabels = defaultValue(attrs.startYLabels, null);

  this.liveLeftmostLabelWidth = defaultValue(attrs.liveLeftmostLabelWidth, -1);
  this.liveContentWidth = defaultValue(attrs.liveContentWidth, -1);
}

// copy generates a quasi-deep copy of this state.
// Every y-label and ChunkView is shallow copied, but everything else is deeply copied.
ViewState.prototype.copy = function() {
  return new ViewState(this.positive, this.normative, this);
};

// State stores both a PositiveState and NormativeState.
function State(positive, normative) {
  this.positive = positive;
  this.normative = normative;
}

// copy generates a deep copy of the state.
State.prototype.copy = function() {
  return new State(new PositiveState(this.positive), new NormativeState(this.normative));
};

// PositiveState stores information about the current visual state of a ContentView.
function PositiveState(attrs) {
  this.dataSourceLength = defaultValue(attrs.dataSourceLength, 0);

  this.visibleChunkStart = defaultValue(attrs.visibleChunkStart, -1);
  this.visibleChunkLength = defaultValue(attrs.visibleChunkLength, -1);

  this.leftmostChunkLength = defaultValue(attrs.leftmostChunkLength, -1);
  this.leftmostYLabelsWidth = defaultValue(attrs.leftmostYLabelsWidth, -1);
  this.leftmostYLabelsPointCount = defaultValue(attrs.leftmostYLabelsPointCount, -1);

  this.contentWidth = defaultValue(attrs.contentWidth, 0);
  this.viewportX = defaultValue(attrs.viewportX, 0);
  this.viewportWidth = defaultValue(attrs.viewportWidth, 0);
  this.viewportHeight = defaultValue(attrs.viewportHeight, 0);
  this.barShowingHeight = defaultValue(attrs.barShowingHeight, 0);
}

// NormativeState stores information about what will or ought to change about the current visual
// state of a content view.
function NormativeState(attrs) {
  this.needsLeftmostChunk = defaultValue(attrs.needsLeftmostChunk, false);
  this.loadingLeftmostChunk = defaultValue(attrs.loadingLeftmostChunk, false);
  this.leftmostChunkLength = defaultValue(attrs.leftmostChunkLength, 0);

  this.needsVisibleChunk = defaultValue(attrs.needsVisibleChunk, false);
  this.loadingVisibleChunk = defaultValue(attrs.loadingVisibleChunk, false);
  this.visibleChunkStart = defaultValue(attrs.visibleChunkStart, 0);
  this.visibleChunkLength = defaultValue(attrs.visibleChunkLength, 0);
}

NormativeState.LEFTMOST_START_BUFFER = 1000;
NormativeState.LEFTMOST_MIN_BUFFER = 0;
NormativeState.VISIBLE_START_BUFFER = 2000;
NormativeState.VISIBLE_MIN_BUFFER = 1000;

// recompute uses a ViewProvider and a PositiveState to update this normative state's fields based
// on what data should be loaded.
NormativeState.prototype.recompute = function(provider, positiveState) {
  this._recomputeLeftmost(provider, positiveState);
  this._recomputeVisible(provider, positiveState);
};

NormativeState.prototype._recomputeLeftmost = function(provider, positiveState) {
  var minWidth = positiveState.viewportWidth + NormativeState.LEFTMOST_MIN_BUFFER;
  var minLength = provider.computeTheoreticalChunk({width: minWidth, left: 0},
    positiveState.dataSourceLength).length;

  if (positiveState.leftmostChunkLength >= minLength) {
    this.needsLeftmostChunk = false;
    this.loadingLeftmostChunk = false;
  } else if (!this.needsLeftmostChunk || this.leftmostChunkLength < minLength) {
    this.loadingLeftmostChunk = true;
    this.needsLeftmostChunk = true;

    var theoreticalChunk = {
      left: 0,
      width: positiveState.viewportWidth + NormativeState.LEFTMOST_START_BUFFER
    };
    this.leftmostChunkLength = provider.computeTheoreticalChunk(theoreticalChunk,
      positiveState.dataSourceLength).length;
  }
};

NormativeState.prototype._recomputeVisible = function(provider, positiveState) {
  var viewportX;
  if (positiveState.visibleChunkLength < 0) {
    console.log(positiveState);
    viewportX = positiveState.contentWidth + positiveState.leftmostYLabelsWidth -
      positiveState.viewportWidth;
  } else {
    viewportX = positiveState.viewportX;
  }
  var minRegion = {
    left: viewportX - positiveState.leftmostYLabelsWidth - NormativeState.VISIBLE_MIN_BUFFER,
    width: NormativeState.VISIBLE_MIN_BUFFER*2 + positiveState.viewportWidth
  };
  var minChunk = provider.computeTheoreticalChunk(minRegion, positiveState.dataSourceLength);

  var visibleChunkEnd = positiveState.visibleChunkStart + positiveState.visibleChunkLength;
  if (positiveState.visibleChunkStart <= minChunk.start &&
      visibleChunkEnd >= minChunk.start+minChunk.length) {
    this.needsVisibleChunk = false;
    this.loadingVisibleChunk = false;
    return;
  }

  if (this.needsVisibleChunk) {
    var gettingChunkEnd = this.visibleChunkStart + this.visibleChunkLength;
    if (this.visibleChunkStart <= minChunk.start &&
        gettingChunkEnd >= minChunk.start+minChunk.length) {
      return;
    }
  }

  var needRegion = {
    left: viewportX - positiveState.leftmostYLabelsWidth - NormativeState.VISIBLE_START_BUFFER,
    width: NormativeState.VISIBLE_START_BUFFER*2 + positiveState.viewportWidth
  };

  // NOTE: we do this to ensure that we use up as much buffer space as possible even if the user is
  // scrolled all the way to the left or to the right.
  if (needRegion.left+needRegion.width > positiveState.contentWidth) {
    needRegion.left -= needRegion.left + needRegion.width - positiveState.contentWidth;
  } else if (needRegion.left < 0) {
    needRegion.left = 0;
  }

  var needChunk = provider.computeTheoreticalChunk(needRegion, positiveState.dataSourceLength);

  this.needsVisibleChunk = true;
  this.loadingVisibleChunk = true;
  this.visibleChunkStart = needChunk.startIndex;
  this.visibleChunkLength = needChunk.length;
};

function defaultValue(value, d) {
  return ('undefined' === typeof value ? d : value);
}
<commit_msg>removed log<commit_after>// ViewState stores a State and some additional information used for a StateView specifically.
// These states are used internally by a StateView.
function ViewState(positive, normative, attrs) {
  this.positive = new PositiveState(positive);
  this.normative = new NormativeState(normative);

  this.viewFrozen = defaultValue(attrs.viewFrozen, false);

  this.yLabels = defaultValue(attrs.yLabels, null);

  this.chunkView = defaultValue(attrs.chunkView, null);
  this.chunkViewStartIndex = defaultValue(attrs.chunkViewStartIndex, -1);
  this.chunkViewLength = defaultValue(attrs.chunkViewLength, -1);

  this.showingContent = defaultValue(attrs.showingContent, false);
  this.animate = defaultValue(attrs.animate, false);

  this.animating = defaultValue(attrs.animating, false);
  this.animationChunkView = defaultValue(attrs.animationChunkView, null);
  this.animationProgress = defaultValue(attrs.animationProgress, -1);
  this.startLeftmostLabelWidth = defaultValue(attrs.startLeftmostLabelWidth, -1);
  this.startYLabels = defaultValue(attrs.startYLabels, null);

  this.liveLeftmostLabelWidth = defaultValue(attrs.liveLeftmostLabelWidth, -1);
  this.liveContentWidth = defaultValue(attrs.liveContentWidth, -1);
}

// copy generates a quasi-deep copy of this state.
// Every y-label and ChunkView is shallow copied, but everything else is deeply copied.
ViewState.prototype.copy = function() {
  return new ViewState(this.positive, this.normative, this);
};

// State stores both a PositiveState and NormativeState.
function State(positive, normative) {
  this.positive = positive;
  this.normative = normative;
}

// copy generates a deep copy of the state.
State.prototype.copy = function() {
  return new State(new PositiveState(this.positive), new NormativeState(this.normative));
};

// PositiveState stores information about the current visual state of a ContentView.
function PositiveState(attrs) {
  this.dataSourceLength = defaultValue(attrs.dataSourceLength, 0);

  this.visibleChunkStart = defaultValue(attrs.visibleChunkStart, -1);
  this.visibleChunkLength = defaultValue(attrs.visibleChunkLength, -1);

  this.leftmostChunkLength = defaultValue(attrs.leftmostChunkLength, -1);
  this.leftmostYLabelsWidth = defaultValue(attrs.leftmostYLabelsWidth, -1);
  this.leftmostYLabelsPointCount = defaultValue(attrs.leftmostYLabelsPointCount, -1);

  this.contentWidth = defaultValue(attrs.contentWidth, 0);
  this.viewportX = defaultValue(attrs.viewportX, 0);
  this.viewportWidth = defaultValue(attrs.viewportWidth, 0);
  this.viewportHeight = defaultValue(attrs.viewportHeight, 0);
  this.barShowingHeight = defaultValue(attrs.barShowingHeight, 0);
}

// NormativeState stores information about what will or ought to change about the current visual
// state of a content view.
function NormativeState(attrs) {
  this.needsLeftmostChunk = defaultValue(attrs.needsLeftmostChunk, false);
  this.loadingLeftmostChunk = defaultValue(attrs.loadingLeftmostChunk, false);
  this.leftmostChunkLength = defaultValue(attrs.leftmostChunkLength, 0);

  this.needsVisibleChunk = defaultValue(attrs.needsVisibleChunk, false);
  this.loadingVisibleChunk = defaultValue(attrs.loadingVisibleChunk, false);
  this.visibleChunkStart = defaultValue(attrs.visibleChunkStart, 0);
  this.visibleChunkLength = defaultValue(attrs.visibleChunkLength, 0);
}

NormativeState.LEFTMOST_START_BUFFER = 1000;
NormativeState.LEFTMOST_MIN_BUFFER = 0;
NormativeState.VISIBLE_START_BUFFER = 2000;
NormativeState.VISIBLE_MIN_BUFFER = 1000;

// recompute uses a ViewProvider and a PositiveState to update this normative state's fields based
// on what data should be loaded.
NormativeState.prototype.recompute = function(provider, positiveState) {
  this._recomputeLeftmost(provider, positiveState);
  this._recomputeVisible(provider, positiveState);
};

NormativeState.prototype._recomputeLeftmost = function(provider, positiveState) {
  var minWidth = positiveState.viewportWidth + NormativeState.LEFTMOST_MIN_BUFFER;
  var minLength = provider.computeTheoreticalChunk({width: minWidth, left: 0},
    positiveState.dataSourceLength).length;

  if (positiveState.leftmostChunkLength >= minLength) {
    this.needsLeftmostChunk = false;
    this.loadingLeftmostChunk = false;
  } else if (!this.needsLeftmostChunk || this.leftmostChunkLength < minLength) {
    this.loadingLeftmostChunk = true;
    this.needsLeftmostChunk = true;

    var theoreticalChunk = {
      left: 0,
      width: positiveState.viewportWidth + NormativeState.LEFTMOST_START_BUFFER
    };
    this.leftmostChunkLength = provider.computeTheoreticalChunk(theoreticalChunk,
      positiveState.dataSourceLength).length;
  }
};

NormativeState.prototype._recomputeVisible = function(provider, positiveState) {
  var viewportX;
  if (positiveState.visibleChunkLength < 0) {
    viewportX = positiveState.contentWidth + positiveState.leftmostYLabelsWidth -
      positiveState.viewportWidth;
  } else {
    viewportX = positiveState.viewportX;
  }
  var minRegion = {
    left: viewportX - positiveState.leftmostYLabelsWidth - NormativeState.VISIBLE_MIN_BUFFER,
    width: NormativeState.VISIBLE_MIN_BUFFER*2 + positiveState.viewportWidth
  };
  var minChunk = provider.computeTheoreticalChunk(minRegion, positiveState.dataSourceLength);

  var visibleChunkEnd = positiveState.visibleChunkStart + positiveState.visibleChunkLength;
  if (positiveState.visibleChunkStart <= minChunk.start &&
      visibleChunkEnd >= minChunk.start+minChunk.length) {
    this.needsVisibleChunk = false;
    this.loadingVisibleChunk = false;
    return;
  }

  if (this.needsVisibleChunk) {
    var gettingChunkEnd = this.visibleChunkStart + this.visibleChunkLength;
    if (this.visibleChunkStart <= minChunk.start &&
        gettingChunkEnd >= minChunk.start+minChunk.length) {
      return;
    }
  }

  var needRegion = {
    left: viewportX - positiveState.leftmostYLabelsWidth - NormativeState.VISIBLE_START_BUFFER,
    width: NormativeState.VISIBLE_START_BUFFER*2 + positiveState.viewportWidth
  };

  // NOTE: we do this to ensure that we use up as much buffer space as possible even if the user is
  // scrolled all the way to the left or to the right.
  if (needRegion.left+needRegion.width > positiveState.contentWidth) {
    needRegion.left -= needRegion.left + needRegion.width - positiveState.contentWidth;
  } else if (needRegion.left < 0) {
    needRegion.left = 0;
  }

  var needChunk = provider.computeTheoreticalChunk(needRegion, positiveState.dataSourceLength);

  this.needsVisibleChunk = true;
  this.loadingVisibleChunk = true;
  this.visibleChunkStart = needChunk.startIndex;
  this.visibleChunkLength = needChunk.length;
};

function defaultValue(value, d) {
  return ('undefined' === typeof value ? d : value);
}
<|endoftext|>


<commit_before><commit_msg>Small fix for notifications.<commit_after><|endoftext|>


<commit_before>'use strict';
var test = require('tap').test;
var proxyquire = require('proxyquire');

function mock(ava) {
  if (!ava) {
    ava = {};
  }
  ava['@noCallThru'] = true;
  return proxyquire('./', {ava: ava});
}

function id(title) {
  return title;
}

test('forwards call to ava', function (t) {
  var test = mock(id);

  t.same(test('name'), 'name');
  t.end();
});

test('supports simple methods', function (t) {
  var test = mock({
    todo: id
  });

  t.same(test.todo('name'), 'name');
  t.end();
});

test('supports chained methods', function (t) {
  var test = mock({
    afterEach: {
      cb: id
    }
  });

  t.same(test.afterEach.cb('name'), 'name');
  t.end();
});

test('describe appends a description to tests', function (t) {
  var test = mock(id);

  var subject = test.describe('Subject');

  t.same(subject('something'), 'Subject something');

  t.end();
});

test('applies modifiers to all tests inside describe', function (t) {
  t.plan(2);

  var test = mock({
    only: {
      skip: id,
      todo: id
    }
  });

  test.only.describe('Something', function (test) {
    t.same(test.skip('is awesome'), 'Something is awesome');
    t.same(test.todo('is awesome'), 'Something is awesome');
    t.end();
  });
});

test('allows for promise-like groups', function (t) {
  var test = mock({only: id});
  var group = test.only.group();

  t.same(group('something'), 'something');
  t.end();
});
<commit_msg>Fix tests<commit_after>'use strict';
var test = require('tap').test;
var proxyquire = require('proxyquire');

function mock(ava) {
  if (!ava) {
    ava = {};
  }
  ava['@noCallThru'] = true;
  return proxyquire('../', {ava: ava});
}

function id(title) {
  return title;
}

test('forwards call to ava', function (t) {
  var test = mock(id);

  t.same(test('name'), 'name');
  t.end();
});

test('supports simple methods', function (t) {
  var test = mock({
    todo: id
  });

  t.same(test.todo('name'), 'name');
  t.end();
});

test('supports chained methods', function (t) {
  var test = mock({
    afterEach: {
      cb: id
    }
  });

  t.same(test.afterEach.cb('name'), 'name');
  t.end();
});

test('describe appends a description to tests', function (t) {
  var test = mock(id);

  var subject = test.describe('Subject');

  t.same(subject('something'), 'Subject something');

  t.end();
});

test('applies modifiers to all tests inside describe', function (t) {
  t.plan(2);

  var test = mock({
    only: {
      skip: id,
      todo: id
    }
  });

  test.only.describe('Something', function (test) {
    t.same(test.skip('is awesome'), 'Something is awesome');
    t.same(test.todo('is awesome'), 'Something is awesome');
    t.end();
  });
});

test('allows for promise-like groups', function (t) {
  var test = mock({only: id});
  var group = test.only.group();

  t.same(group('something'), 'something');
  t.end();
});
<|endoftext|>


<commit_before><commit_msg>generateUserData function to minimize duplicate code<commit_after><|endoftext|>


<commit_before><commit_msg>[lib] Include year in old timestamps<commit_after><|endoftext|>