<commit_before>import { Morph, Text, show } from "./index.js"
import { pt, Color, Rectangle } from "lively.graphics";
import { arr, fun, obj } from "lively.lang";
import { signal } from "lively.bindings";

function asItem(obj) {
  return obj && obj.isListItem ? obj : {
    isListItem: true, value: obj, string: String(obj)
  }
}

class ListItemMorph extends Text {

  constructor(props) {
    super({
      fixedWidth: true, fixedHeight: false, readOnly: true, selectable: false,
      fill: null, textString: "", itemIndex: undefined, ...props
    });
  }

  displayItem(item, itemIndex, pos, isSelected = false) {
    this.itemIndex = itemIndex;
    this.textString = item.string || "no item.string";
    this.position = pos;
    this.width = this.owner.width;
    this.fill = isSelected ? Color.blue : null;
    this.fontColor = isSelected ? Color.white : Color.black;
  }

  onMouseDown(evt) {
    this.owner.owner.selectItemMorph(this);
  }
}

var listCommands = [
  {
    name: "page up",
    exec: (list) => {
      var index = list.selectedIndex,
          newIndex = Math.max(0, index - Math.round(list.height / list.itemHeight));
      list.gotoIndex(newIndex);
      return true;
    }
  },

  {
    name: "page down",
    exec: (list) => {
      var index = list.selectedIndex,
          newIndex = Math.min(list.items.length-1, index + Math.round(list.height / list.itemHeight))
      list.gotoIndex(newIndex);
      return true;
    }
  },

  {
    name: "goto first item",
    exec: (list) => { list.gotoIndex(0); return true; }
  },

  {
    name: "goto last item",
    exec: (list) => { list.gotoIndex(list.items.length-1); return true; }
  },

  {
    name: "arrow up",
    exec: (list) => { list.gotoIndex((list.selectedIndex || list.items.length) - 1); return true; }
  },

  {
    name: "arrow down",
    exec: (list) => {
      var index = list.selectedIndex,
          newIndex = ((typeof index === "number" ? index : -1) + 1) % list.items.length;
      list.gotoIndex(newIndex);
      return true;
    }
  }
];

export class List extends Morph {

  constructor(props) {
    super({
      layoutPolicy: "vertical",
      fontFamily: "Helvetica Neue, Arial, sans-serif",
      fontSize: 12,
      items: [],
      selectedIndexes: [],
      clipMode: "auto",
      ...props
    });
    this.update();
  }

  get connections() {
    return {selection: {signalOnAssignment: false}};
  }

  // horizonal or vertical (tiling?)
  get layoutPolicy() { return this.getProperty("layoutPolicy"); }
  set layoutPolicy(value) { this.addValueChange("layoutPolicy", value); }

  get fontFamily() { this.invalidateCache(); return this.getProperty("fontFamily"); }
  set fontFamily(value) { this.addValueChange("fontFamily", value); }

  get fontSize() { this.invalidateCache(); return this.getProperty("fontSize"); }
  set fontSize(value) { this.addValueChange("fontSize", value); }

  get items() { return this.getProperty("items"); }
  set items(items) {
    this.addValueChange("items", items.map(asItem));
    this.groupChangesWhile(undefined, () => this.update());
  }

  invalidateCache() {
    delete this._itemHeight;
  }

  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  // items

  find(itemOrValue) {
    return this.items.find(item => item === itemOrValue || item.value === itemOrValue);
  }

  findIndex(itemOrValue) {
    return this.items.findIndex(item => item === itemOrValue || item.value === itemOrValue);
  }

  addItem(item) { return this.addItemAt(item); }

  addItemAt(item, index = this.items.length) {
    var items = this.items,
        index = Math.min(items.length, Math.max(0, index));
    items.splice(index, 0, asItem(item));

    this.addMethodCallChangeDoing({
      target: this,
      selector: "addItemAt",
      args: [item, index],
      undo: {
        target: this,
        selector: "removeItem",
        args: [item],
      }
    }, () => this.update());

  }

  removeItem(itemOrValue) {
    var item = this.find(itemOrValue),
        items = this.items,
        index = items.indexOf(item)
    if (index === -1) return;

    items.splice(index, 1);

    this.addMethodCallChangeDoing({
      target: this,
      selector: "removeItem",
      args: [item],
      undo: {
        target: this,
        selector: "addItemAt",
        args: [item, index],
      }
    }, () => this.update());

  }

  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  // selection

  get selectedIndex() { return this.selectedIndexes[0]; }
  set selectedIndex(i) { return this.selectedIndexes = typeof i === "number" ? [i] : []; }
  get selectedIndexes() { return this.getProperty("selectedIndexes") || []; }
  set selectedIndexes(indexes) {
    var maxLength = this.items.length;
    this.addValueChange(
      "selectedIndexes",
      (indexes || []).filter(i => 0 <= i && i < maxLength));
    this.groupChangesWhile(undefined, () => this.update());
    signal(this, "selection", this.selection);
  }

  get selection() { return this.selections[0]; }
  set selection(itemOrValue) { this.selections = [itemOrValue]; }

  get selections() { return this.selectedIndexes.map(i => this.items[i] && this.items[i].value); }
  set selections(sels) { this.selectedIndexes = sels.map(ea => this.findIndex(ea)); }

  get selectedItems() { return this.selectedIndexes.map(i => this.items[i]); }

  selectItemMorph(itemMorph) {
    this.selectedIndexes = [itemMorph.itemIndex];
  }

  gotoIndex(i) {
    this.scrollIndexIntoView(this.selectedIndex = i);
  }

  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  // rendering

  get listItemContainer() {
    return this.getSubmorphNamed("listItemContainer") || this.addMorph({
      name: "listItemContainer", fill: null, clipMode: "visible"
    });
  }

  get itemMorphs() { return this.listItemContainer.submorphs; }

  get itemHeight() {
    return this._itemHeight
       || (this._itemHeight = this.env.fontMetric.sizeFor(this.fontFamily+this.fontSize, "O").height);
  }

  update() {
    var {
          itemHeight,
          items, itemMorphs, listItemContainer,
          selectedIndexes,
          scroll: {x: left, y: top},
          extent: {x: width, y: height},
          fontSize, fontFamily
        } = this,
        firstItemIndex = Math.floor(top / itemHeight),
        lastItemIndex = Math.ceil((top+height) / itemHeight);

    listItemContainer.extent = pt(this.width, itemHeight*items.length);

    for (var i = 0; i < lastItemIndex-firstItemIndex; i++) {
      var itemIndex = firstItemIndex+i,
          item = items[itemIndex];

      if (!item) {
        // if no items to display, remove remaining itemMorphs
        itemMorphs.slice(i).forEach(itemMorph => itemMorph.remove());
        break;
      }

      var itemMorph = itemMorphs[i] || (itemMorphs[i] = listItemContainer.addMorph(new ListItemMorph({fontFamily, fontSize})));

      itemMorph.displayItem(item, itemIndex,
        pt(0, itemHeight*(itemIndex)),
        selectedIndexes.includes(itemIndex));
    }

    itemMorphs.slice(lastItemIndex-firstItemIndex).forEach(ea => ea.remove());
  }

  scrollIndexIntoView(idx) {
    var {itemHeight, width, scroll} = this,
        itemBounds = new Rectangle(0, idx*itemHeight, width, itemHeight),
        visibleBounds = this.innerBounds().translatedBy(scroll),
        offsetX = 0, offsetY = 0
    if (itemBounds.bottom() > visibleBounds.bottom())
      offsetY = itemBounds.bottom() - visibleBounds.bottom()
    if (itemBounds.top() < visibleBounds.top())
      offsetY = itemBounds.top() - visibleBounds.top()
    this.scroll = scroll.addXY(offsetX, offsetY);
  }

  onScroll() {
    fun.debounceNamed(this.id + "scroll", 81, () => this.update(), true)();
  }

}

// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import { connect } from "lively.bindings";
import FontMetric from "./rendering/font-metric.js";

export class FilterableList extends Morph {

  constructor(props = {}) {
    var fontFamily = props.fontFamily || "Arial",
        fontSize = props.fontSize || 11,
        input = props.input || "",
        inputText = Text.makeInputLine({
          name: "input",
          textString: input,
          fill: null,
          borderWidth: 1, borderColor: Color.gray,
          padding: Rectangle.inset(2),
          fontSize, fontFamily
        }),
        list = new List({
          name: "list", items: [],
          fill: null,
          clipMode: "auto",
          fontSize, fontFamily
        });

    super({borderWidth: 1, borderColor: Color.gray, submorphs: [inputText, list]});

    props = obj.dissoc(props, ["fontFamily", "fontSize", "input"]);

    this.state = {allItems: null};

    Object.assign(this, {
      items: [],
      extent: props.bounds ? props.bounds.extent() : pt(400, 360),
      ...props
    });

    this.relayout();

    connect(this.get("input"), "inputChanged", this, "updateFilter");
    connect(this, "extent", this, "relayout");

    this.addKeyBindings([
      {keys: "Down|Ctrl-N", command: "arrow down"},
      {keys: "Up|Ctrl-P", command: "arrow up"},
      {keys: "Ctrl-V|PageDown", command: "page down"},
      {keys: "Alt-V|PageUp", command: "page up"},
      {keys: "Alt-Shift-,", command: "goto first item"},
      {keys: "Alt-Shift-.", command: "goto last item"},
      {keys: "Enter", command: "accept input"},
      {keys: "Escape|Ctrl-G", command: "cancel"}
    ]);
  }

  focus() { this.get("input").focus(); }

  relayout() {
    var i = this.get("input"),
        l = this.get("list"),
        inputHeight = i.env.fontMetric.sizeFor(i.fontFamily, i.fontSize, "X").height + 2*2,
        ext = this.extent;
    i.setBounds(new Rectangle(0,0, ext.x, inputHeight));
    l.setBounds(new Rectangle(0, inputHeight, ext.x, ext.y-inputHeight));
  }

  get items() { return this.state.allItems || []; }
  set items(items) {
    var l = this.get("list");
    this.state.allItems = items.map(asItem);
    this.updateFilter();
  }
  get visibleItems() { return this.get("list").items; }

  get selection() { return this.get("list").selection; }
  set selection(x) { this.get("list").selection = x; }
  get selectedIndex() { return this.get("list").selectedIndex; }
  set selectedIndex(x) { this.get("list").selectedIndex = x; }

  updateFilter() {
    var filterText = this.get("input").textString,
        filterTokens = filterText.split(/\s+/).map(ea => ea.toLowerCase()),
        filteredItems = this.state.allItems.filter(item => filterTokens.every(token => item.string.toLowerCase().includes(token)));
    this.get("list").items = filteredItems;
  }

  get commands()  {
    var list = this.get("list");
    return super.commands.concat([
      {
        name: "accept input",
        exec: (morph) => {
//           signal(morph, "accepted", list.selection);
          signal(morph, "accepted", list.selectedIndex in this.get("list").items ? list.selection: null);
          return true;
        }
      },

      {
        name: "cancel",
        exec: (morph) => {
          signal(morph, "canceled");
          return true;
        }
      },

      ...listCommands.map(cmd => ({...cmd, exec: (morph, opts, count) => cmd.exec(list, opts, count)}))
    ]);
  }

}
<commit_msg>lists: keybindings + select via filter (alt-space)<commit_after>import { Morph, Text, show } from "./index.js"
import { pt, Color, Rectangle } from "lively.graphics";
import { arr, fun, obj } from "lively.lang";
import { signal } from "lively.bindings";

function asItem(obj) {
  return obj && obj.isListItem ? obj : {
    isListItem: true, value: obj, string: String(obj)
  }
}

class ListItemMorph extends Text {

  constructor(props) {
    super({
      fixedWidth: true, fixedHeight: false, readOnly: true, selectable: false,
      fill: null, textString: "", itemIndex: undefined, ...props
    });
  }

  displayItem(item, itemIndex, pos, isSelected = false) {
    this.itemIndex = itemIndex;
    this.textString = item.string || "no item.string";
    this.position = pos;
    this.width = this.owner.width;
    this.fill = isSelected ? Color.blue : null;
    this.fontColor = isSelected ? Color.white : Color.black;
  }

  onMouseDown(evt) {
    this.owner.owner.selectItemMorph(this);
  }
}

var listCommands = [
  {
    name: "page up",
    exec: (list) => {
      var index = list.selectedIndex,
          newIndex = Math.max(0, index - Math.round(list.height / list.itemHeight));
      list.gotoIndex(newIndex);
      return true;
    }
  },

  {
    name: "page down",
    exec: (list) => {
      var index = list.selectedIndex,
          newIndex = Math.min(list.items.length-1, index + Math.round(list.height / list.itemHeight))
      list.gotoIndex(newIndex);
      return true;
    }
  },

  {
    name: "goto first item",
    exec: (list) => { list.gotoIndex(0); return true; }
  },

  {
    name: "goto last item",
    exec: (list) => { list.gotoIndex(list.items.length-1); return true; }
  },

  {
    name: "arrow up",
    exec: (list) => { list.gotoIndex((list.selectedIndex || list.items.length) - 1); return true; }
  },

  {
    name: "arrow down",
    exec: (list) => {
      var index = list.selectedIndex,
          newIndex = ((typeof index === "number" ? index : -1) + 1) % list.items.length;
      list.gotoIndex(newIndex);
      return true;
    }
  },

  {
    name: "select via filter",
    exec: async (list) => {
      list.selection = await list.world().filterableListPrompt("Select item", list.items, {preselect: list.selectedIndex});
      list.scrollSelectionIntoView();
      list.update();
      return true;
    }
  }
];

export class List extends Morph {

  constructor(props) {
    super({
      layoutPolicy: "vertical",
      fontFamily: "Helvetica Neue, Arial, sans-serif",
      fontSize: 12,
      items: [],
      selectedIndexes: [],
      clipMode: "auto",
      ...props
    });
    this.update();
  }

  get connections() {
    return {selection: {signalOnAssignment: false}};
  }

  // horizonal or vertical (tiling?)
  get layoutPolicy() { return this.getProperty("layoutPolicy"); }
  set layoutPolicy(value) { this.addValueChange("layoutPolicy", value); }

  get fontFamily() { this.invalidateCache(); return this.getProperty("fontFamily"); }
  set fontFamily(value) { this.addValueChange("fontFamily", value); }

  get fontSize() { this.invalidateCache(); return this.getProperty("fontSize"); }
  set fontSize(value) { this.addValueChange("fontSize", value); }

  get items() { return this.getProperty("items"); }
  set items(items) {
    this.addValueChange("items", items.map(asItem));
    this.groupChangesWhile(undefined, () => this.update());
  }

  invalidateCache() {
    delete this._itemHeight;
  }

  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  // items

  find(itemOrValue) {
    return this.items.find(item => item === itemOrValue || item.value === itemOrValue);
  }

  findIndex(itemOrValue) {
    return this.items.findIndex(item => item === itemOrValue || item.value === itemOrValue);
  }

  addItem(item) { return this.addItemAt(item); }

  addItemAt(item, index = this.items.length) {
    var items = this.items,
        index = Math.min(items.length, Math.max(0, index));
    items.splice(index, 0, asItem(item));

    this.addMethodCallChangeDoing({
      target: this,
      selector: "addItemAt",
      args: [item, index],
      undo: {
        target: this,
        selector: "removeItem",
        args: [item],
      }
    }, () => this.update());

  }

  removeItem(itemOrValue) {
    var item = this.find(itemOrValue),
        items = this.items,
        index = items.indexOf(item)
    if (index === -1) return;

    items.splice(index, 1);

    this.addMethodCallChangeDoing({
      target: this,
      selector: "removeItem",
      args: [item],
      undo: {
        target: this,
        selector: "addItemAt",
        args: [item, index],
      }
    }, () => this.update());

  }

  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  // selection

  get selectedIndex() { return this.selectedIndexes[0]; }
  set selectedIndex(i) { return this.selectedIndexes = typeof i === "number" ? [i] : []; }
  get selectedIndexes() { return this.getProperty("selectedIndexes") || []; }
  set selectedIndexes(indexes) {
    var maxLength = this.items.length;
    this.addValueChange(
      "selectedIndexes",
      (indexes || []).filter(i => 0 <= i && i < maxLength));
    this.groupChangesWhile(undefined, () => this.update());
    signal(this, "selection", this.selection);
  }

  get selection() { return this.selections[0]; }
  set selection(itemOrValue) { this.selections = [itemOrValue]; }

  get selections() { return this.selectedIndexes.map(i => this.items[i] && this.items[i].value); }
  set selections(sels) { this.selectedIndexes = sels.map(ea => this.findIndex(ea)); }

  get selectedItems() { return this.selectedIndexes.map(i => this.items[i]); }

  selectItemMorph(itemMorph) {
    this.selectedIndexes = [itemMorph.itemIndex];
  }

  gotoIndex(i) {
    this.scrollIndexIntoView(this.selectedIndex = i);
  }

  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  // rendering

  get listItemContainer() {
    return this.getSubmorphNamed("listItemContainer") || this.addMorph({
      name: "listItemContainer", fill: null, clipMode: "visible"
    });
  }

  get itemMorphs() { return this.listItemContainer.submorphs; }

  get itemHeight() {
    return this._itemHeight
       || (this._itemHeight = this.env.fontMetric.sizeFor(this.fontFamily+this.fontSize, "O").height);
  }

  update() {
    var {
          itemHeight,
          items, itemMorphs, listItemContainer,
          selectedIndexes,
          scroll: {x: left, y: top},
          extent: {x: width, y: height},
          fontSize, fontFamily
        } = this,
        firstItemIndex = Math.floor(top / itemHeight),
        lastItemIndex = Math.ceil((top+height) / itemHeight);

    listItemContainer.extent = pt(this.width, itemHeight*items.length);

    for (var i = 0; i < lastItemIndex-firstItemIndex; i++) {
      var itemIndex = firstItemIndex+i,
          item = items[itemIndex];

      if (!item) {
        // if no items to display, remove remaining itemMorphs
        itemMorphs.slice(i).forEach(itemMorph => itemMorph.remove());
        break;
      }

      var itemMorph = itemMorphs[i] || (itemMorphs[i] = listItemContainer.addMorph(new ListItemMorph({fontFamily, fontSize})));

      itemMorph.displayItem(item, itemIndex,
        pt(0, itemHeight*(itemIndex)),
        selectedIndexes.includes(itemIndex));
    }

    itemMorphs.slice(lastItemIndex-firstItemIndex).forEach(ea => ea.remove());
  }

  scrollSelectionIntoView() {
    if (this.selection) this.scrollIndexIntoView(this.selectedIndex);
  }

  scrollIndexIntoView(idx) {
    var {itemHeight, width, scroll} = this,
        itemBounds = new Rectangle(0, idx*itemHeight, width, itemHeight),
        visibleBounds = this.innerBounds().translatedBy(scroll),
        offsetX = 0, offsetY = 0
    if (itemBounds.bottom() > visibleBounds.bottom())
      offsetY = itemBounds.bottom() - visibleBounds.bottom()
    if (itemBounds.top() < visibleBounds.top())
      offsetY = itemBounds.top() - visibleBounds.top()
    this.scroll = scroll.addXY(offsetX, offsetY);
  }

  onScroll() {
    fun.debounceNamed(this.id + "scroll", 81, () => this.update(), true)();
  }

  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  // event handling
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  get keybindings() {
    return [
      {keys: "Down|Ctrl-N", command: "arrow down"},
      {keys: "Up|Ctrl-P", command: "arrow up"},
      {keys: "Ctrl-V|PageDown", command: "page down"},
      {keys: "Alt-V|PageUp", command: "page up"},
      {keys: "Alt-Shift-,", command: "goto first item"},
      {keys: "Alt-Shift-.", command: "goto last item"},
      {keys: "Enter", command: "accept input"},
      {keys: "Escape|Ctrl-G", command: "cancel"},
      {keys: "Alt-Space", command: "select via filter"},
    ].concat(super.keybindings);
  }

  get commands() {
    return listCommands;
  }

}

// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import { connect } from "lively.bindings";
import FontMetric from "./rendering/font-metric.js";

export class FilterableList extends Morph {

  constructor(props = {}) {
    var fontFamily = props.fontFamily || "Arial",
        fontSize = props.fontSize || 11,
        input = props.input || "",
        inputText = Text.makeInputLine({
          name: "input",
          textString: input,
          fill: null,
          borderWidth: 1, borderColor: Color.gray,
          padding: Rectangle.inset(2),
          fontSize, fontFamily
        }),
        list = new List({
          name: "list", items: [],
          fill: null,
          clipMode: "auto",
          fontSize, fontFamily
        });

    super({borderWidth: 1, borderColor: Color.gray, submorphs: [inputText, list]});

    props = obj.dissoc(props, ["fontFamily", "fontSize", "input"]);

    this.state = {allItems: null};

    Object.assign(this, {
      items: [],
      extent: props.bounds ? props.bounds.extent() : pt(400, 360),
      ...props
    });

    this.relayout();

    connect(this.get("input"), "inputChanged", this, "updateFilter");
    connect(this, "extent", this, "relayout");
  }

  focus() { this.get("input").focus(); }

  relayout() {
    var i = this.get("input"),
        l = this.get("list"),
        inputHeight = i.env.fontMetric.sizeFor(i.fontFamily, i.fontSize, "X").height + 2*2,
        ext = this.extent;
    i.setBounds(new Rectangle(0,0, ext.x, inputHeight));
    l.setBounds(new Rectangle(0, inputHeight, ext.x, ext.y-inputHeight));
  }

  get items() { return this.state.allItems || []; }
  set items(items) {
    var l = this.get("list");
    this.state.allItems = items.map(asItem);
    this.updateFilter();
  }
  get visibleItems() { return this.get("list").items; }

  get selection() { return this.get("list").selection; }
  set selection(x) { this.get("list").selection = x; }
  get selectedIndex() { return this.get("list").selectedIndex; }
  set selectedIndex(x) { this.get("list").selectedIndex = x; }

  updateFilter() {
    var filterText = this.get("input").textString,
        filterTokens = filterText.split(/\s+/).map(ea => ea.toLowerCase()),
        filteredItems = this.state.allItems.filter(item => filterTokens.every(token => item.string.toLowerCase().includes(token)));
    this.get("list").items = filteredItems;
  }

  get keybindings() {
    return [
      {keys: "Down|Ctrl-N", command: "arrow down"},
      {keys: "Up|Ctrl-P", command: "arrow up"},
      {keys: "Ctrl-V|PageDown", command: "page down"},
      {keys: "Alt-V|PageUp", command: "page up"},
      {keys: "Alt-Shift-,", command: "goto first item"},
      {keys: "Alt-Shift-.", command: "goto last item"},
      {keys: "Enter", command: "accept input"},
      {keys: "Escape|Ctrl-G", command: "cancel"}
    ].concat(super.keybindings);
  }

  get commands()  {
    var list = this.get("list");
    return super.commands.concat([
      {
        name: "accept input",
        exec: (morph) => {
          signal(morph, "accepted", list.selectedIndex in this.get("list").items ? list.selection: null);
          return true;
        }
      },

      {
        name: "cancel",
        exec: (morph) => {
          signal(morph, "canceled");
          return true;
        }
      },

      ...listCommands.map(cmd => ({...cmd, exec: (morph, opts, count) => cmd.exec(list, opts, count)}))
    ]);
  }

}
<|endoftext|>


<commit_before>define([], function() {
    'use strict'
    /***
    Litejs_core
    ***/
    var _dataTypeOf = function(data) {
        return Object.prototype.toString.call(data).slice(8, -1);
    }
    var _hasClass = function(elem, className) {
        return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
    }

    var addClass = function(elem, classNameArray) {
        if (_dataTypeOf(classNameArray) !== "Array") {
            throw new TypeError("The classname should be an array instead of " +
                _dataTypeOf(classNameArray))
        }
        for (var i = 0; i < classNameArray.length; i++) {
            if (!_hasClass(elem, classNameArray[i])) {
                elem.className += ' ' + classNameArray[i];
            }
        }

    }

    var removeClass = function(elem, classNameArray) {
        if (_dataTypeOf(classNameArray) !== "Array") {
            throw new TypeError("The classname should be an array instead of " +
                _dataTypeOf(classNameArray))
        }
        for (var i = 0; i < classNameArray.length; i++) {
            var newClass = ' ' + elem.className.replace(/[\t\r\n]/g, ' ') + ' ';
            if (_hasClass(elem, classNameArray[i])) {
                while (newClass.indexOf(' ' + classNameArray[i] + ' ') >= 0) {
                    newClass = newClass.replace(' ' + classNameArray[i] + ' ', ' ');
                }
                elem.className = newClass.replace(/^\s+|\s+$/g, '');
            }
        }

    }
    var indexOf = function(parentNode, childNode) {
        return Array.prototype.indexOf.call(parentNode, childNode);
    }

    /***
    Litejs_class_factory
    ***/

    function extendsClass(parent, child) {

        var callSuper = parent.prototype;
        var newChild = function() {

            parent.call(this);
            child.call(this);
        }
        newChild.prototype = Object.create(parent.prototype, {
            constructor: {
                configurable: true,
                enumberable: true,
                value: newChild,
                writable: true
            },
            super: {
                configurable: true,
                enumberable: true,
                value: callSuper,
                writable: true
            }
        })

        newChild.callSuper = newChild.prototype.super

        return newChild;
    }

    /***
    Litejs_UI_component
    ***/

    //constructor for liteUI component base class
    function liteComponent() {

    }

    /***
    Litejs_cus_event
    ***/
    var addCusEventListener = function(elements, event_name, fn) {
        for (var i = 0; i < elements.length; i++) {
            elements[i].addEventListener(event_name, fn, false);
        }
    };
    var removeCusEventListener = function(elements, event_name, fn) {
        for (var i = 0; i < elements.length; i++) {
            elements[i].removeEventListener(event_name, fn, false);
        }
    };
    var dispatchCusEvent = function(element, event_name, detail) {
        //var event = new Event(event_name);
        var event = new CustomEvent(event_name, {
            "detail": detail
        });
        element.dispatchEvent(event);
    };

    /***
    Litejs_touch v0.0.1
    ***/

    var swipe = (function() {

        function _swipe_event_handler(elements, event_name, flag, e_flag) {
            var startPosition, endPosition, deltaX, deltaY, moveLength, direction;

            var touchstart = function _onTouchstart(e) {

                var touch = e.touches[0];
                startPosition = {
                    x: touch.pageX,
                    y: touch.pageY
                }
            }
            var touchmove = function _onTouchmove(e) {
                e.preventDefault();
                var touch = e.touches[0];
                endPosition = {
                    x: touch.pageX,
                    y: touch.pageY
                }
                deltaX = endPosition.x - startPosition.x;
                deltaY = endPosition.y - startPosition.y;
                if (!e_flag) {
                    _onSwipeEnd(event_name, deltaX, deltaY, this);
                }
            }
            var touchend = function _onTouchend(e) {

                e.preventDefault();
                if (e_flag) {
                    _onSwipeEnd(event_name, deltaX, deltaY, this);
                }

            }
            if (flag) {
                for (i = 0; i < elements.length; i++) {

                    elements[i].addEventListener('touchstart', touchstart);

                    elements[i].addEventListener('touchmove', touchmove);

                    elements[i].addEventListener('touchend', touchend)
                }
            } else {
                for (i = 0; i < elements.length; i++) {

                    elements[i].removeEventListener('touchstart', touchstart);

                    elements[i].removeEventListener('touchmove', touchmove);

                    elements[i].removeEventListener('touchend', touchend)
                }
            }
        }

        function _onSwipeEnd(event_name, deltaX, deltaY, element) {
            var detail = {
                "deltaX": deltaX,
                "deltaY": deltaY
            }
            if (event_name === "swipe") {
                dispatchCusEvent(element, event_name, detail);
            } else {

                switch (event_name) {
                    case "swipeLeft":
                        if (deltaX < 0) {
                            dispatchCusEvent(element, event_name, detail);
                        };
                        break;
                    case "swipeRight":
                        if (deltaX > 0) {
                            dispatchCusEvent(element, event_name, detail);
                        };
                        break;
                    case "swipeTop":
                        if ((deltaX - deltaY) > 0) {
                            dispatchCusEvent(element, event_name, detail);
                        };
                        break;
                    case "swipeBottom":
                        if ((deltaX - deltaY) < 0) {
                            dispatchCusEvent(element, event_name, detail);
                        };
                        break;
                }
            }
        }

        function init(elements, event_name, fn, flag) {
            addCusEventListener(elements, event_name, fn);
            _swipe_event_handler(elements, event_name, true, flag);
        }

        function remove(elements, event_name, fn) {
            removeCusEventListener(elements, event_name, fn);
            _swipe_event_handler(elements, false);
        }

        return {
            init: init,
            remove: remove
        }
    })();

    /***
    Litejs_ajax
    ***/

    var ajax = function(obj) {
        var xhr, setOption, beforeSend;
        setOption = function(obj) {
            obj.type = obj.type || "GET";
            obj.isAsync = obj.isAsync || true;
            return obj;
        }
        beforeSend = function(obj) {
            for (header in obj.headers) {
                xhr.setRequestHeader(header, obj.headers[header]);
            }
        }
        obj = setOption(obj);
        xhr = new XMLHttpRequest;
        if (obj.headers) {
            beforeSend(obj);
        }
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                    var data = xhr.responseText || xhr.responseXML;
                    obj.success(data, xhr.status);
                } else {
                    if (obj.error) {
                        obj.error(xhr.status);
                    }
                }
            }
        };
        xhr.open(obj.type, obj.url, obj.isAsync);
        if (xhr.data) {
            xhr.send(null);
        } else {
            xhr.send(xhr.data)
        }
        return xhr;
    }

    return {
        addClass: addClass,
        removeClass: removeClass,
        indexOf: indexOf,
        addSwipe: swipe.init,
        removeSwipe: swipe.remove,
        ajax: ajax
    }
})
<commit_msg>update liteUI-component-base-class<commit_after>define([], function() {
    'use strict'
    /***
    Litejs_core
    ***/
    var _dataTypeOf = function(data) {
        return Object.prototype.toString.call(data).slice(8, -1);
    }
    var _hasClass = function(elem, className) {
        return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
    }

    var addClass = function(elem, classNameArray) {
        if (_dataTypeOf(classNameArray) !== "Array") {
            throw new TypeError("The classname should be an array instead of " +
                _dataTypeOf(classNameArray))
        }
        for (var i = 0; i < classNameArray.length; i++) {
            if (!_hasClass(elem, classNameArray[i])) {
                elem.className += ' ' + classNameArray[i];
            }
        }

    }

    var removeClass = function(elem, classNameArray) {
        if (_dataTypeOf(classNameArray) !== "Array") {
            throw new TypeError("The classname should be an array instead of " +
                _dataTypeOf(classNameArray))
        }
        for (var i = 0; i < classNameArray.length; i++) {
            var newClass = ' ' + elem.className.replace(/[\t\r\n]/g, ' ') + ' ';
            if (_hasClass(elem, classNameArray[i])) {
                while (newClass.indexOf(' ' + classNameArray[i] + ' ') >= 0) {
                    newClass = newClass.replace(' ' + classNameArray[i] + ' ', ' ');
                }
                elem.className = newClass.replace(/^\s+|\s+$/g, '');
            }
        }

    }
    var indexOf = function(parentNode, childNode) {
        return Array.prototype.indexOf.call(parentNode, childNode);
    }

    /***
    Litejs_class_factory
    ***/

    function extendsClass(parent, child) {

        var callSuper = parent.prototype;
        var newChild = function() {

            parent.call(this);
            child.call(this);
        }
        newChild.prototype = Object.create(parent.prototype, {
            constructor: {
                configurable: true,
                enumberable: true,
                value: newChild,
                writable: true
            },
            super: {
                configurable: true,
                enumberable: true,
                value: callSuper,
                writable: true
            }
        })

        newChild.callSuper = newChild.prototype.super

        return newChild;
    }

    function mixin(sourceObj, targetObj){
        for (var key in sourceObj){
            if(!(key in targetObj)){
                targetObj[key] = sourceObj[key];
            }
        }
    }

    /***
    Litejs_UI_component
    ***/

    //constructor for liteUI component base class
    function liteComponent() {
        this.defaults = {};
        this.prototype.init = function(options){
            this.options = mixin(this.defaults,this.options);
        }
    }

    /***
    Litejs_cus_event
    ***/
    var addCusEventListener = function(elements, event_name, fn) {
        for (var i = 0; i < elements.length; i++) {
            elements[i].addEventListener(event_name, fn, false);
        }
    };
    var removeCusEventListener = function(elements, event_name, fn) {
        for (var i = 0; i < elements.length; i++) {
            elements[i].removeEventListener(event_name, fn, false);
        }
    };
    var dispatchCusEvent = function(element, event_name, detail) {
        //var event = new Event(event_name);
        var event = new CustomEvent(event_name, {
            "detail": detail
        });
        element.dispatchEvent(event);
    };

    /***
    Litejs_touch v0.0.1
    ***/

    var swipe = (function() {

        function _swipe_event_handler(elements, event_name, flag, e_flag) {
            var startPosition, endPosition, deltaX, deltaY, moveLength, direction;

            var touchstart = function _onTouchstart(e) {

                var touch = e.touches[0];
                startPosition = {
                    x: touch.pageX,
                    y: touch.pageY
                }
            }
            var touchmove = function _onTouchmove(e) {
                e.preventDefault();
                var touch = e.touches[0];
                endPosition = {
                    x: touch.pageX,
                    y: touch.pageY
                }
                deltaX = endPosition.x - startPosition.x;
                deltaY = endPosition.y - startPosition.y;
                if (!e_flag) {
                    _onSwipeEnd(event_name, deltaX, deltaY, this);
                }
            }
            var touchend = function _onTouchend(e) {

                e.preventDefault();
                if (e_flag) {
                    _onSwipeEnd(event_name, deltaX, deltaY, this);
                }

            }
            if (flag) {
                for (i = 0; i < elements.length; i++) {

                    elements[i].addEventListener('touchstart', touchstart);

                    elements[i].addEventListener('touchmove', touchmove);

                    elements[i].addEventListener('touchend', touchend)
                }
            } else {
                for (i = 0; i < elements.length; i++) {

                    elements[i].removeEventListener('touchstart', touchstart);

                    elements[i].removeEventListener('touchmove', touchmove);

                    elements[i].removeEventListener('touchend', touchend)
                }
            }
        }

        function _onSwipeEnd(event_name, deltaX, deltaY, element) {
            var detail = {
                "deltaX": deltaX,
                "deltaY": deltaY
            }
            if (event_name === "swipe") {
                dispatchCusEvent(element, event_name, detail);
            } else {

                switch (event_name) {
                    case "swipeLeft":
                        if (deltaX < 0) {
                            dispatchCusEvent(element, event_name, detail);
                        };
                        break;
                    case "swipeRight":
                        if (deltaX > 0) {
                            dispatchCusEvent(element, event_name, detail);
                        };
                        break;
                    case "swipeTop":
                        if ((deltaX - deltaY) > 0) {
                            dispatchCusEvent(element, event_name, detail);
                        };
                        break;
                    case "swipeBottom":
                        if ((deltaX - deltaY) < 0) {
                            dispatchCusEvent(element, event_name, detail);
                        };
                        break;
                }
            }
        }

        function init(elements, event_name, fn, flag) {
            addCusEventListener(elements, event_name, fn);
            _swipe_event_handler(elements, event_name, true, flag);
        }

        function remove(elements, event_name, fn) {
            removeCusEventListener(elements, event_name, fn);
            _swipe_event_handler(elements, false);
        }

        return {
            init: init,
            remove: remove
        }
    })();

    /***
    Litejs_ajax
    ***/

    var ajax = function(obj) {
        var xhr, setOption, beforeSend;
        setOption = function(obj) {
            obj.type = obj.type || "GET";
            obj.isAsync = obj.isAsync || true;
            return obj;
        }
        beforeSend = function(obj) {
            for (header in obj.headers) {
                xhr.setRequestHeader(header, obj.headers[header]);
            }
        }
        obj = setOption(obj);
        xhr = new XMLHttpRequest;
        if (obj.headers) {
            beforeSend(obj);
        }
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                    var data = xhr.responseText || xhr.responseXML;
                    obj.success(data, xhr.status);
                } else {
                    if (obj.error) {
                        obj.error(xhr.status);
                    }
                }
            }
        };
        xhr.open(obj.type, obj.url, obj.isAsync);
        if (xhr.data) {
            xhr.send(null);
        } else {
            xhr.send(xhr.data)
        }
        return xhr;
    }

    return {
        addClass: addClass,
        removeClass: removeClass,
        indexOf: indexOf,
        addSwipe: swipe.init,
        removeSwipe: swipe.remove,
        ajax: ajax
    }
})
<|endoftext|>


<commit_before>/**
 * @externs
 * @license
 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */

/** @type {boolean|undefined} */
CustomElementRegistry.prototype.forcePolyfill;

/** @type {boolean|undefined} */
CustomElementRegistry.prototype.noHtmlImports;

/** @type {boolean|undefined} */
CustomElementRegistry.prototype.noConstructionObserver;

/** @type {boolean|undefined} */
CustomElementRegistry.prototype.fastWalk;

class AlreadyConstructedMarkerType {}

/**
 * @typedef {{
 *  localName: string,
 *  constructorFunction: !Function,
 *  connectedCallback: Function,
 *  disconnectedCallback: Function,
 *  adoptedCallback: Function,
 *  attributeChangedCallback: Function,
 *  observedAttributes: !Array<string>,
 *  constructionStack: !Array<!HTMLElement|!AlreadyConstructedMarkerType>,
 * }}
 */
let CustomElementDefinition;

// These properties are defined in the closure externs so that they will not be
// renamed during minification.

// Used for both Documents and Nodes which represent documents in the HTML
// Imports polyfill.

/** @type {boolean|undefined} */
Node.prototype.__CE_hasRegistry;

/** @type {boolean|undefined} */
Node.prototype.__CE_isImportDocument;

/** @type {boolean|undefined} */
Node.prototype.__CE_documentLoadHandled;

// Apply generally to Node.

/** @type {boolean|undefined} */
Node.prototype.__CE_patched;

/** @type {string} */
Node.prototype.readyState;

// Apply generally to Element.

/** @type {number|undefined} */
Element.prototype.__CE_state;

/** @type {!CustomElementDefinition|undefined} */
Element.prototype.__CE_definition;

/** @type {!DocumentFragment|undefined} */
Element.prototype.__CE_shadowRoot;
<commit_msg>More removal of `noHtmlImports` flag<commit_after>/**
 * @externs
 * @license
 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */

/** @type {boolean|undefined} */
CustomElementRegistry.prototype.forcePolyfill;

/** @type {boolean|undefined} */
CustomElementRegistry.prototype.noConstructionObserver;

/** @type {boolean|undefined} */
CustomElementRegistry.prototype.fastWalk;

class AlreadyConstructedMarkerType {}

/**
 * @typedef {{
 *  localName: string,
 *  constructorFunction: !Function,
 *  connectedCallback: Function,
 *  disconnectedCallback: Function,
 *  adoptedCallback: Function,
 *  attributeChangedCallback: Function,
 *  observedAttributes: !Array<string>,
 *  constructionStack: !Array<!HTMLElement|!AlreadyConstructedMarkerType>,
 * }}
 */
let CustomElementDefinition;

// These properties are defined in the closure externs so that they will not be
// renamed during minification.

// Used for both Documents and Nodes which represent documents in the HTML
// Imports polyfill.

/** @type {boolean|undefined} */
Node.prototype.__CE_hasRegistry;

/** @type {boolean|undefined} */
Node.prototype.__CE_isImportDocument;

/** @type {boolean|undefined} */
Node.prototype.__CE_documentLoadHandled;

// Apply generally to Node.

/** @type {boolean|undefined} */
Node.prototype.__CE_patched;

/** @type {string} */
Node.prototype.readyState;

// Apply generally to Element.

/** @type {number|undefined} */
Element.prototype.__CE_state;

/** @type {!CustomElementDefinition|undefined} */
Element.prototype.__CE_definition;

/** @type {!DocumentFragment|undefined} */
Element.prototype.__CE_shadowRoot;
<|endoftext|>


<commit_before>/*global every,toArray */

/*
Description:

*/

/*
Degrades:
In browsers without a while loop
*/

var areFeatures;

areFeatures = function() {
	var i = arguments.length;
	while (i--) {
		if (!arguments[i]) {
			return false;
		}
	}
	return true;
};<commit_msg>remove dependencies<commit_after>/*
Description:

*/

/*
Degrades:
In browsers without a while loop
*/

var areFeatures;

areFeatures = function() {
	var i = arguments.length;
	while (i--) {
		if (!arguments[i]) {
			return false;
		}
	}
	return true;
};<|endoftext|>


<commit_before>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Datastructure: Pool.
 *
 *
 * A generic class for handling pools of objects.
 * When an object is released, it is attempted to be reused.
 */

goog.provide('goog.structs.Pool');

goog.require('goog.Disposable');
goog.require('goog.structs.Queue');
goog.require('goog.structs.Set');

/**
 * A generic pool class. If min is greater than max, an error is thrown.
 * @param {number=} opt_minCount Min. number of objects (Default: 0).
 * @param {number=} opt_maxCount Max. number of objects (Default: 10).
 * @constructor
 * @extends {goog.Disposable}
 * @template T
 */
goog.structs.Pool = function(opt_minCount, opt_maxCount) {
  goog.Disposable.call(this);

  /**
   * Minimum number of objects allowed
   * @private {number}
   */
  this.minCount_ = opt_minCount || 0;

  /**
   * Maximum number of objects allowed
   * @private {number}
   */
  this.maxCount_ = opt_maxCount || 10;

  // Make sure that the max and min constraints are valid.
  if (this.minCount_ > this.maxCount_) {
    throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
  }

  /**
   * Set used to store objects that are currently in the pool and available
   * to be used.
   * @private {goog.structs.Queue<T>}
   */
  this.freeQueue_ = new goog.structs.Queue();

  /**
   * Set used to store objects that are currently in the pool and in use.
   * @private {goog.structs.Set<T>}
   */
  this.inUseSet_ = new goog.structs.Set();

  /**
   * The minimum delay between objects being made available, in milliseconds. If
   * this is 0, no minimum delay is enforced.
   * @protected {number}
   */
  this.delay = 0;

  /**
   * The time of the last object being made available, in milliseconds since the
   * epoch (i.e., the result of Date#toTime). If this is null, no access has
   * occurred yet.
   * @protected {number?}
   */
  this.lastAccess = null;

  // Make sure that the minCount constraint is satisfied.
  this.adjustForMinMax();

  // TODO(user): Remove once JSCompiler's undefined properties warnings
  // don't error for guarded properties.
  var magicProps = {canBeReused: 0};
};
goog.inherits(goog.structs.Pool, goog.Disposable);

/**
 * Error to throw when the max/min constraint is attempted to be invalidated.
 * I.e., when it is attempted for maxCount to be less than minCount.
 * @type {string}
 * @private
 */
goog.structs.Pool.ERROR_MIN_MAX_ =
    '[goog.structs.Pool] Min can not be greater than max';

/**
 * Error to throw when the Pool is attempted to be disposed and it is asked to
 * make sure that there are no objects that are in use (i.e., haven't been
 * released).
 * @type {string}
 * @private
 */
goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_ =
    '[goog.structs.Pool] Objects not released';

/**
 * Sets the minimum count of the pool.
 * If min is greater than the max count of the pool, an error is thrown.
 * @param {number} min The minimum count of the pool.
 */
goog.structs.Pool.prototype.setMinimumCount = function(min) {
  // Check count constraints.
  if (min > this.maxCount_) {
    throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
  }
  this.minCount_ = min;

  // Adjust the objects in the pool as needed.
  this.adjustForMinMax();
};

/**
 * Sets the maximum count of the pool.
 * If max is less than the max count of the pool, an error is thrown.
 * @param {number} max The maximum count of the pool.
 */
goog.structs.Pool.prototype.setMaximumCount = function(max) {
  // Check count constraints.
  if (max < this.minCount_) {
    throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
  }
  this.maxCount_ = max;

  // Adjust the objects in the pool as needed.
  this.adjustForMinMax();
};

/**
 * Sets the minimum delay between objects being returned by getObject, in
 * milliseconds. This defaults to zero, meaning that no minimum delay is
 * enforced and objects may be used as soon as they're available.
 * @param {number} delay The minimum delay, in milliseconds.
 */
goog.structs.Pool.prototype.setDelay = function(delay) {
  this.delay = delay;
};

/**
 * @return {T|undefined} A new object from the pool if there is one available,
 *     otherwise undefined.
 */
goog.structs.Pool.prototype.getObject = function() {
  var time = goog.now();
  if (goog.isDefAndNotNull(this.lastAccess) &&
      time - this.lastAccess < this.delay) {
    return undefined;
  }

  var obj = this.removeFreeObject_();
  if (obj) {
    this.lastAccess = time;
    this.inUseSet_.add(obj);
  }

  return obj;
};

/**
 * Returns an object to the pool of available objects so that it can be reused.
 * @param {T} obj The object to return to the pool of free objects.
 * @return {boolean} Whether the object was found in the Pool's set of in-use
 *     objects (in other words, whether any action was taken).
 */
goog.structs.Pool.prototype.releaseObject = function(obj) {
  if (this.inUseSet_.remove(obj)) {
    this.addFreeObject(obj);
    return true;
  }
  return false;
};

/**
 * Removes a free object from the collection of objects that are free so that it
 * can be used.
 *
 * NOTE: This method does not mark the returned object as in use.
 *
 * @return {T|undefined} The object removed from the free collection, if there
 *     is one available. Otherwise, undefined.
 * @private
 */
goog.structs.Pool.prototype.removeFreeObject_ = function() {
  var obj;
  while (this.getFreeCount() > 0) {
    obj = this.freeQueue_.dequeue();

    if (!this.objectCanBeReused(obj)) {
      this.adjustForMinMax();
    } else {
      break;
    }
  }

  if (!obj && this.getCount() < this.maxCount_) {
    obj = this.createObject();
  }

  return obj;
};

/**
 * Adds an object to the collection of objects that are free. If the object can
 * not be added, then it is disposed.
 *
 * @param {T} obj The object to add to collection of free objects.
 */
goog.structs.Pool.prototype.addFreeObject = function(obj) {
  this.inUseSet_.remove(obj);
  if (this.objectCanBeReused(obj) && this.getCount() < this.maxCount_) {
    this.freeQueue_.enqueue(obj);
  } else {
    this.disposeObject(obj);
  }
};

/**
 * Adjusts the objects held in the pool to be within the min/max constraints.
 *
 * NOTE: It is possible that the number of objects in the pool will still be
 * greater than the maximum count of objects allowed. This will be the case
 * if no more free objects can be disposed of to get below the minimum count
 * (i.e., all objects are in use).
 */
goog.structs.Pool.prototype.adjustForMinMax = function() {
  var freeQueue = this.freeQueue_;

  // Make sure the at least the minimum number of objects are created.
  while (this.getCount() < this.minCount_) {
    freeQueue.enqueue(this.createObject());
  }

  // Make sure no more than the maximum number of objects are created.
  while (this.getCount() > this.maxCount_ && this.getFreeCount() > 0) {
    this.disposeObject(freeQueue.dequeue());
  }
};

/**
 * Should be overridden by sub-classes to return an instance of the object type
 * that is expected in the pool.
 * @return {T} The created object.
 */
goog.structs.Pool.prototype.createObject = function() {
  return {};
};

/**
 * Should be overridden to dispose of an object. Default implementation is to
 * remove all its members, which should render it useless. Calls the object's
 * {@code dispose()} method, if available.
 * @param {T} obj The object to dispose.
 */
goog.structs.Pool.prototype.disposeObject = function(obj) {
  if (typeof obj.dispose == 'function') {
    obj.dispose();
  } else {
    for (var i in obj) {
      obj[i] = null;
    }
  }
};

/**
 * Should be overridden to determine whether an object has become unusable and
 * should not be returned by getObject(). Calls the object's
 * {@code canBeReused()}  method, if available.
 * @param {T} obj The object to test.
 * @return {boolean} Whether the object can be reused.
 */
goog.structs.Pool.prototype.objectCanBeReused = function(obj) {
  if (typeof obj.canBeReused == 'function') {
    return obj.canBeReused();
  }
  return true;
};

/**
 * Returns true if the given object is in the pool.
 * @param {T} obj The object to check the pool for.
 * @return {boolean} Whether the pool contains the object.
 */
goog.structs.Pool.prototype.contains = function(obj) {
  return this.freeQueue_.contains(obj) || this.inUseSet_.contains(obj);
};

/**
 * Returns the number of objects currently in the pool.
 * @return {number} Number of objects currently in the pool.
 */
goog.structs.Pool.prototype.getCount = function() {
  return this.freeQueue_.getCount() + this.inUseSet_.getCount();
};

/**
 * Returns the number of objects currently in use in the pool.
 * @return {number} Number of objects currently in use in the pool.
 */
goog.structs.Pool.prototype.getInUseCount = function() {
  return this.inUseSet_.getCount();
};

/**
 * Returns the number of objects currently free in the pool.
 * @return {number} Number of objects currently free in the pool.
 */
goog.structs.Pool.prototype.getFreeCount = function() {
  return this.freeQueue_.getCount();
};

/**
 * Determines if the pool contains no objects.
 * @return {boolean} Whether the pool contains no objects.
 */
goog.structs.Pool.prototype.isEmpty = function() {
  return this.freeQueue_.isEmpty() && this.inUseSet_.isEmpty();
};

/**
 * Disposes of the pool and all objects currently held in the pool.
 * @override
 * @protected
 */
goog.structs.Pool.prototype.disposeInternal = function() {
  goog.structs.Pool.superClass_.disposeInternal.call(this);
  if (this.getInUseCount() > 0) {
    throw Error(goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_);
  }
  delete this.inUseSet_;

  // Call disposeObject on each object held by the pool.
  var freeQueue = this.freeQueue_;
  while (!freeQueue.isEmpty()) {
    this.disposeObject(freeQueue.dequeue());
  }
  delete this.freeQueue_;
};
<commit_msg>Fix the documentation for setMaximumCount.<commit_after>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Datastructure: Pool.
 *
 *
 * A generic class for handling pools of objects.
 * When an object is released, it is attempted to be reused.
 */

goog.provide('goog.structs.Pool');

goog.require('goog.Disposable');
goog.require('goog.structs.Queue');
goog.require('goog.structs.Set');

/**
 * A generic pool class. If min is greater than max, an error is thrown.
 * @param {number=} opt_minCount Min. number of objects (Default: 0).
 * @param {number=} opt_maxCount Max. number of objects (Default: 10).
 * @constructor
 * @extends {goog.Disposable}
 * @template T
 */
goog.structs.Pool = function(opt_minCount, opt_maxCount) {
  goog.Disposable.call(this);

  /**
   * Minimum number of objects allowed
   * @private {number}
   */
  this.minCount_ = opt_minCount || 0;

  /**
   * Maximum number of objects allowed
   * @private {number}
   */
  this.maxCount_ = opt_maxCount || 10;

  // Make sure that the max and min constraints are valid.
  if (this.minCount_ > this.maxCount_) {
    throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
  }

  /**
   * Set used to store objects that are currently in the pool and available
   * to be used.
   * @private {goog.structs.Queue<T>}
   */
  this.freeQueue_ = new goog.structs.Queue();

  /**
   * Set used to store objects that are currently in the pool and in use.
   * @private {goog.structs.Set<T>}
   */
  this.inUseSet_ = new goog.structs.Set();

  /**
   * The minimum delay between objects being made available, in milliseconds. If
   * this is 0, no minimum delay is enforced.
   * @protected {number}
   */
  this.delay = 0;

  /**
   * The time of the last object being made available, in milliseconds since the
   * epoch (i.e., the result of Date#toTime). If this is null, no access has
   * occurred yet.
   * @protected {number?}
   */
  this.lastAccess = null;

  // Make sure that the minCount constraint is satisfied.
  this.adjustForMinMax();

  // TODO(user): Remove once JSCompiler's undefined properties warnings
  // don't error for guarded properties.
  var magicProps = {canBeReused: 0};
};
goog.inherits(goog.structs.Pool, goog.Disposable);

/**
 * Error to throw when the max/min constraint is attempted to be invalidated.
 * I.e., when it is attempted for maxCount to be less than minCount.
 * @type {string}
 * @private
 */
goog.structs.Pool.ERROR_MIN_MAX_ =
    '[goog.structs.Pool] Min can not be greater than max';

/**
 * Error to throw when the Pool is attempted to be disposed and it is asked to
 * make sure that there are no objects that are in use (i.e., haven't been
 * released).
 * @type {string}
 * @private
 */
goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_ =
    '[goog.structs.Pool] Objects not released';

/**
 * Sets the minimum count of the pool.
 * If min is greater than the max count of the pool, an error is thrown.
 * @param {number} min The minimum count of the pool.
 */
goog.structs.Pool.prototype.setMinimumCount = function(min) {
  // Check count constraints.
  if (min > this.maxCount_) {
    throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
  }
  this.minCount_ = min;

  // Adjust the objects in the pool as needed.
  this.adjustForMinMax();
};

/**
 * Sets the maximum count of the pool.
 * If max is less than the min count of the pool, an error is thrown.
 * @param {number} max The maximum count of the pool.
 */
goog.structs.Pool.prototype.setMaximumCount = function(max) {
  // Check count constraints.
  if (max < this.minCount_) {
    throw Error(goog.structs.Pool.ERROR_MIN_MAX_);
  }
  this.maxCount_ = max;

  // Adjust the objects in the pool as needed.
  this.adjustForMinMax();
};

/**
 * Sets the minimum delay between objects being returned by getObject, in
 * milliseconds. This defaults to zero, meaning that no minimum delay is
 * enforced and objects may be used as soon as they're available.
 * @param {number} delay The minimum delay, in milliseconds.
 */
goog.structs.Pool.prototype.setDelay = function(delay) {
  this.delay = delay;
};

/**
 * @return {T|undefined} A new object from the pool if there is one available,
 *     otherwise undefined.
 */
goog.structs.Pool.prototype.getObject = function() {
  var time = goog.now();
  if (goog.isDefAndNotNull(this.lastAccess) &&
      time - this.lastAccess < this.delay) {
    return undefined;
  }

  var obj = this.removeFreeObject_();
  if (obj) {
    this.lastAccess = time;
    this.inUseSet_.add(obj);
  }

  return obj;
};

/**
 * Returns an object to the pool of available objects so that it can be reused.
 * @param {T} obj The object to return to the pool of free objects.
 * @return {boolean} Whether the object was found in the Pool's set of in-use
 *     objects (in other words, whether any action was taken).
 */
goog.structs.Pool.prototype.releaseObject = function(obj) {
  if (this.inUseSet_.remove(obj)) {
    this.addFreeObject(obj);
    return true;
  }
  return false;
};

/**
 * Removes a free object from the collection of objects that are free so that it
 * can be used.
 *
 * NOTE: This method does not mark the returned object as in use.
 *
 * @return {T|undefined} The object removed from the free collection, if there
 *     is one available. Otherwise, undefined.
 * @private
 */
goog.structs.Pool.prototype.removeFreeObject_ = function() {
  var obj;
  while (this.getFreeCount() > 0) {
    obj = this.freeQueue_.dequeue();

    if (!this.objectCanBeReused(obj)) {
      this.adjustForMinMax();
    } else {
      break;
    }
  }

  if (!obj && this.getCount() < this.maxCount_) {
    obj = this.createObject();
  }

  return obj;
};

/**
 * Adds an object to the collection of objects that are free. If the object can
 * not be added, then it is disposed.
 *
 * @param {T} obj The object to add to collection of free objects.
 */
goog.structs.Pool.prototype.addFreeObject = function(obj) {
  this.inUseSet_.remove(obj);
  if (this.objectCanBeReused(obj) && this.getCount() < this.maxCount_) {
    this.freeQueue_.enqueue(obj);
  } else {
    this.disposeObject(obj);
  }
};

/**
 * Adjusts the objects held in the pool to be within the min/max constraints.
 *
 * NOTE: It is possible that the number of objects in the pool will still be
 * greater than the maximum count of objects allowed. This will be the case
 * if no more free objects can be disposed of to get below the minimum count
 * (i.e., all objects are in use).
 */
goog.structs.Pool.prototype.adjustForMinMax = function() {
  var freeQueue = this.freeQueue_;

  // Make sure the at least the minimum number of objects are created.
  while (this.getCount() < this.minCount_) {
    freeQueue.enqueue(this.createObject());
  }

  // Make sure no more than the maximum number of objects are created.
  while (this.getCount() > this.maxCount_ && this.getFreeCount() > 0) {
    this.disposeObject(freeQueue.dequeue());
  }
};

/**
 * Should be overridden by sub-classes to return an instance of the object type
 * that is expected in the pool.
 * @return {T} The created object.
 */
goog.structs.Pool.prototype.createObject = function() {
  return {};
};

/**
 * Should be overridden to dispose of an object. Default implementation is to
 * remove all its members, which should render it useless. Calls the object's
 * {@code dispose()} method, if available.
 * @param {T} obj The object to dispose.
 */
goog.structs.Pool.prototype.disposeObject = function(obj) {
  if (typeof obj.dispose == 'function') {
    obj.dispose();
  } else {
    for (var i in obj) {
      obj[i] = null;
    }
  }
};

/**
 * Should be overridden to determine whether an object has become unusable and
 * should not be returned by getObject(). Calls the object's
 * {@code canBeReused()}  method, if available.
 * @param {T} obj The object to test.
 * @return {boolean} Whether the object can be reused.
 */
goog.structs.Pool.prototype.objectCanBeReused = function(obj) {
  if (typeof obj.canBeReused == 'function') {
    return obj.canBeReused();
  }
  return true;
};

/**
 * Returns true if the given object is in the pool.
 * @param {T} obj The object to check the pool for.
 * @return {boolean} Whether the pool contains the object.
 */
goog.structs.Pool.prototype.contains = function(obj) {
  return this.freeQueue_.contains(obj) || this.inUseSet_.contains(obj);
};

/**
 * Returns the number of objects currently in the pool.
 * @return {number} Number of objects currently in the pool.
 */
goog.structs.Pool.prototype.getCount = function() {
  return this.freeQueue_.getCount() + this.inUseSet_.getCount();
};

/**
 * Returns the number of objects currently in use in the pool.
 * @return {number} Number of objects currently in use in the pool.
 */
goog.structs.Pool.prototype.getInUseCount = function() {
  return this.inUseSet_.getCount();
};

/**
 * Returns the number of objects currently free in the pool.
 * @return {number} Number of objects currently free in the pool.
 */
goog.structs.Pool.prototype.getFreeCount = function() {
  return this.freeQueue_.getCount();
};

/**
 * Determines if the pool contains no objects.
 * @return {boolean} Whether the pool contains no objects.
 */
goog.structs.Pool.prototype.isEmpty = function() {
  return this.freeQueue_.isEmpty() && this.inUseSet_.isEmpty();
};

/**
 * Disposes of the pool and all objects currently held in the pool.
 * @override
 * @protected
 */
goog.structs.Pool.prototype.disposeInternal = function() {
  goog.structs.Pool.superClass_.disposeInternal.call(this);
  if (this.getInUseCount() > 0) {
    throw Error(goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_);
  }
  delete this.inUseSet_;

  // Call disposeObject on each object held by the pool.
  var freeQueue = this.freeQueue_;
  while (!freeQueue.isEmpty()) {
    this.disposeObject(freeQueue.dequeue());
  }
  delete this.freeQueue_;
};
<|endoftext|>


<commit_before>var gameModule = angular.module('app', []).
	controller("gameTheoryControl", function gameTheoryControl($scope){

	    	function number(num){
	    		this.name = num;
	    		this.selected = false;
	    		return this;
	    	}

	    	$scope.numbers=[];
	    	$scope.solutions=[];

	    	$scope.getStarter = function(){
	    		var isEven = ($scope.solutions.length % 2) == 0;

	    		if(isEven){
	    			return "Alice";
	    		}
	    		else{
	    			return "Bob";
	    		}
	    	}

	    	function solution(x, parts){
	    		this.number = x;
	    		this.parts = parts;
	    	}

	    	$scope.amount = 5;

	    	$scope.newNumbers = function(){
			$scope.numbers = [];

			intAmount = parseInt($scope.amount);

			for(var i = 1; i < intAmount + 1; i++){
				$scope.numbers.push(new number(i));
			}
		}

		$scope.deleteSelected = function(){
			for(var num in $scope.numbers){
				if($scope.numbers[num].selected){
					$scope.numbers.splice(num, 1);
					num--;
				}
			}
		}

		function sumOf(parts){
			var num = 0;
			for(var i = 0; i < parts.length; i++){
				num += parts[i];
			}
			return num;
		}

		function getSmallerNumbers(number){
			var newArray = [];
			for(var i = 0; i < $scope.numbers.length; i++){
				if($scope.numbers[i].name <= number){
					newArray.push($scope.numbers[i].name);
				}
				else{
					break;
				}
			}
			return newArray;
		}

		/*var getCombinations = function(startArray, arrayOfNumbers){
			var results = [];
			for(var i = 0; i < arrayOfNumbers.length; i++){
				results.push(startArray.concat(arrayOfNumbers[i]));

				var tempArray = [];
				for(var j = i + 1; j < arrayOfNumbers.length; j++){
					tempArray.push(arrayOfNumbers[j]);
				}

				results = results.concat(getCombinations(startArray.concat(arrayOfNumbers[i]), tempArray));
			}
			return results;
		}*/

		var getResult = function(startArray, arrayOfNumbers, expected){
			var results = [];
			for(var i = arrayOfNumbers.length - 1; i > -1; i--){
				results.push(startArray.concat(arrayOfNumbers[i]));
				if(sumOf(startArray.concat(arrayOfNumbers[i]))==expected){
					return {result: true, values: startArray.concat(arrayOfNumbers[i])};
				}

				var tempArray = [];
				for(var j = 0; j < i; j++){
					tempArray.push(arrayOfNumbers[j]);
				}

				var newCombinations = getResult(startArray.concat(arrayOfNumbers[i]), tempArray, expected);
				if(newCombinations.result = true){return newCombinations;}
				else{
					results = results.concat(newCombinations);
				}
			}
			return results;
		}

		$scope.getSolutions = function(){
			$scope.solutions = [];
			var calculable = true;
			var currentNumber = 1;

			while(calculable){
				parts = [];

				var solved = false;

				var smallerNums = getSmallerNumbers(currentNumber);

				if(smallerNums.length == 0){
					calculable = false; break;
				}

				for(var i = 0; i < $scope.numbers.length; i++){
					if($scope.numbers[i].name == currentNumber)
					{
						solved = true;
						$scope.solutions.push(new solution(currentNumber, [$scope.numbers[i].name]));
					}
				}

				if(!solved){
					var returnses = getResult([], smallerNums, currentNumber);
					if(returnses.result == true){
						solved = true;
					}
					else{
						calculable = false; break;
					}
				}

				/*if(!solved){
					var combinations = getCombinations([], smallerNums);

						for(var i = 0; i < combinations.length; i++){
							if(sumOf(combinations[i]) == currentNumber){
								$scope.solutions.push(new solution(currentNumber, combinations[i]));
								solved = true;
								break;
							}
							if(solved){break;}
						}

					if(!solved){
						calculable = false; break;
					}
				}*/

				currentNumber++;
			}
		}

		$scope.newNumbers();

	});
<commit_msg>Update gameTheoryController.js<commit_after>var gameModule = angular.module('app', []).
	controller("gameTheoryControl", function gameTheoryControl($scope){

	    	function number(num){
	    		this.name = num;
	    		this.selected = false;
	    		return this;
	    	}

	    	$scope.numbers=[];
	    	$scope.solutions=[];

	    	$scope.getStarter = function(){
	    		var isEven = ($scope.solutions.length % 2) == 0;

	    		if(isEven){
	    			return "Alice";
	    		}
	    		else{
	    			return "Bob";
	    		}
	    	}

	    	function solution(x, parts){
	    		this.number = x;
	    		this.parts = parts;
	    	}

	    	$scope.amount = 5;

	    	$scope.newNumbers = function(){
			$scope.numbers = [];

			intAmount = parseInt($scope.amount);

			for(var i = 1; i < intAmount + 1; i++){
				$scope.numbers.push(new number(i));
			}
		}

		$scope.deleteSelected = function(){
			for(var num in $scope.numbers){
				if($scope.numbers[num].selected){
					$scope.numbers.splice(num, 1);
					num--;
				}
			}
		}

		function sumOf(parts){
			var num = 0;
			for(var i = 0; i < parts.length; i++){
				num += parts[i];
			}
			return num;
		}

		function getSmallerNumbers(number){
			var newArray = [];
			for(var i = 0; i < $scope.numbers.length; i++){
				if($scope.numbers[i].name <= number){
					newArray.push($scope.numbers[i].name);
				}
				else{
					break;
				}
			}
			return newArray;
		}

		/*var getCombinations = function(startArray, arrayOfNumbers){
			var results = [];
			for(var i = 0; i < arrayOfNumbers.length; i++){
				results.push(startArray.concat(arrayOfNumbers[i]));

				var tempArray = [];
				for(var j = i + 1; j < arrayOfNumbers.length; j++){
					tempArray.push(arrayOfNumbers[j]);
				}

				results = results.concat(getCombinations(startArray.concat(arrayOfNumbers[i]), tempArray));
			}
			return results;
		}*/

		var getResult = function(startArray, arrayOfNumbers, expected){
			var results = [];
			for(var i = arrayOfNumbers.length - 1; i > -1; i--){
				results.push(startArray.concat(arrayOfNumbers[i]));
				if(sumOf(startArray.concat(arrayOfNumbers[i]))==expected){
					return {result: true, values: startArray.concat(arrayOfNumbers[i])};
				}

				var tempArray = [];
				for(var j = 0; j < i; j++){
					tempArray.push(arrayOfNumbers[j]);
				}

				var newCombinations = getResult(startArray.concat(arrayOfNumbers[i]), tempArray, expected);
				if(newCombinations.result == true){return newCombinations;}
				else{
					results = results.concat(newCombinations);
				}
			}
			return results;
		}

		$scope.getSolutions = function(){
			$scope.solutions = [];
			var calculable = true;
			var currentNumber = 1;

			while(calculable){
				parts = [];

				var solved = false;

				var smallerNums = getSmallerNumbers(currentNumber);

				if(smallerNums.length == 0){
					calculable = false; break;
				}

				for(var i = 0; i < $scope.numbers.length; i++){
					if($scope.numbers[i].name == currentNumber)
					{
						solved = true;
						$scope.solutions.push(new solution(currentNumber, [$scope.numbers[i].name]));
					}
				}

				if(!solved){
					var returnses = getResult([], smallerNums, currentNumber);
					if(returnses.result == true){
						solved = true;
					}
					else{
						calculable = false; break;
					}
				}

				/*if(!solved){
					var combinations = getCombinations([], smallerNums);

						for(var i = 0; i < combinations.length; i++){
							if(sumOf(combinations[i]) == currentNumber){
								$scope.solutions.push(new solution(currentNumber, combinations[i]));
								solved = true;
								break;
							}
							if(solved){break;}
						}

					if(!solved){
						calculable = false; break;
					}
				}*/

				currentNumber++;
			}
		}

		$scope.newNumbers();

	});
<|endoftext|>


<commit_before>var assert = require('assert');
var common = require('../../common');

var table = 'timezone_test';
var tests = [0, 1, 5, 12, 26, -1, -5, -20, 'Z', 'local'];

common.getTestConnection(function (err, connection) {
  assert.ifError(err);

  common.useTestDb(connection);

  connection.query([
    'CREATE TEMPORARY TABLE ?? (',
    '`offset` varchar(10),',
    '`dt` datetime',
    ') ENGINE=InnoDB DEFAULT CHARSET=utf8'
  ].join('\n'), [table], assert.ifError);

  testNextDate(connection);
});

function testNextDate(connection) {
  if (tests.length === 0) {
    connection.end(assert.ifError);
    return;
  }

  var dt = new Date();
  var offset = tests.pop();

  // datetime will round fractional seconds up, which causes this test to fail
  // depending on when it is executed. MySQL 5.6.4 and up supports datetime(6)
  // which would not require this change.
  // http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
  dt.setMilliseconds(0);

  if (offset === 'Z' || offset === 'local') {
    connection.config.timezone = offset;
  } else {
    connection.config.timezone = (offset < 0 ? "-" : "+") + pad2(Math.abs(offset)) + ":00";
  }

  connection.query('INSERT INTO ?? SET ?', [table, {offset: offset, dt: dt}], assert.ifError);

  if (offset === 'Z') {
    dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000));
  } else if (offset !== 'local') {
    dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000) + (offset * 3600000));
  }

  var options = {
    sql: 'SELECT * FROM ?? WHERE offset = ?',
    typeCast: function (field, next) {
      if (field.type != 'DATETIME') return next();

      return new Date(field.string());
    },
    values: [table, offset]
  };

  connection.query(options, function (err, rows) {
    assert.ifError(err);
    assert.strictEqual(dt.toString(), rows[0].dt.toString());
    testNextDate(connection);
  });
}

function pad2(v) {
  return (v < 10 ? "0" : "") + v;
}
<commit_msg>tests: improve fragility of timezone test<commit_after>var assert = require('assert');
var common = require('../../common');

var table = 'timezone_test';
var tests = [0, 1, 5, 12, 26, -1, -5, -20, 'Z', 'local'];

common.getTestConnection(function (err, connection) {
  assert.ifError(err);

  common.useTestDb(connection);

  connection.query([
    'CREATE TEMPORARY TABLE ?? (',
    '`offset` varchar(10),',
    '`dt` datetime',
    ') ENGINE=InnoDB DEFAULT CHARSET=utf8'
  ].join('\n'), [table], assert.ifError);

  testNextDate(connection);
});

function testNextDate(connection) {
  if (tests.length === 0) {
    connection.end(assert.ifError);
    return;
  }

  var dt = new Date();
  var offset = tests.pop();

  // datetime will round fractional seconds up, which causes this test to fail
  // depending on when it is executed. MySQL 5.6.4 and up supports datetime(6)
  // which would not require this change.
  // http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
  dt.setSeconds(0);
  dt.setMilliseconds(0);

  if (offset === 'Z' || offset === 'local') {
    connection.config.timezone = offset;
  } else {
    connection.config.timezone = (offset < 0 ? "-" : "+") + pad2(Math.abs(offset)) + ":00";
  }

  connection.query('INSERT INTO ?? SET ?', [table, {offset: offset, dt: dt}], assert.ifError);

  if (offset === 'Z') {
    dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000));
  } else if (offset !== 'local') {
    dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000) + (offset * 3600000));
  }

  dt.setSeconds(0);
  dt.setMilliseconds(0);

  var options = {
    sql: 'SELECT * FROM ?? WHERE offset = ?',
    typeCast: function (field, next) {
      if (field.type != 'DATETIME') return next();

      return new Date(field.string());
    },
    values: [table, offset]
  };

  connection.query(options, function (err, rows) {
    assert.ifError(err);
    assert.strictEqual(dt.toString(), rows[0].dt.toString());
    testNextDate(connection);
  });
}

function pad2(v) {
  return (v < 10 ? "0" : "") + v;
}
<|endoftext|>


<commit_before>var Game = function(){

    var mainCanvas = document.getElementById("canvas");
    mainCanvas.width = WIDTH;
    mainCanvas.height = HEIGHT;
    var mainCanvasContext = mainCanvas.getContext("2d");

    var backCanvas = getCanvasInstance();
    var backCanvasContext = backCanvas.getContext("2d");

    var lightManager = new RenderManager();

    var player = undefined;
    var maze = undefined;
    var stopwatch = undefined;

    var delta, now, then;

    var paused = false;

    function step() {
        setDelta();
        update();
        lightManager.render(mainCanvasContext, render);
        if(!paused)
            animate(step);
    }

    function update() {
        player.update(delta);
        handleControls();
    }

    function render(ctx){
        renderMaze(ctx);
        player.render(ctx);
    }

    function renderMaze(ctx){
        ctx.drawImage(backCanvas, 0, 0);
    }

    function setDelta(){
        now = Date.now();
        delta = (now - then) / 1000; // seconds since last frame
        then = now;
    }

    function getCanvasInstance(){
        var canvas = document.createElement('canvas');
        canvas.width = WIDTH;
        canvas.height = HEIGHT;
        return canvas;
    }

    function handleControls(){
        if(!player.isMoving){
            f: for (var key in keysDown) {
                var value = Number(key);
                switch (value) {
                    case KEY_LEFT:
                        if(player.moveTo(player.x - 2, player.y, delta, maze)) break f;
                        break;
                    case KEY_UP:
                        if(player.moveTo(player.x, player.y - 2, delta, maze)) break f;
                        break;
                    case KEY_RIGHT:
                        if(player.moveTo(player.x + 2, player.y, delta, maze)) break f;
                        break;
                    case KEY_DOWN:
                        if(player.moveTo(player.x, player.y + 2, delta, maze)) break f;
                        break;
                }
            }
        }
        for (var key in keysDown) {
            var value = Number(key);
            if(value == KEY_MATCH){
                player.lightMatch(lightManager);
            }
        }
    }

    this.start = function() {
        maze = new Maze(lightManager);
        player = new Player(maze.positioning);
        player.setEndGameCallback(this.stop);
        stopwatch = new Stopwatch(document.getElementById('time'));
        stopwatch.start();
        maze.render(backCanvasContext);
        animate(step);
    };

    this.stop = function(){
        stopwatch.stop();
        paused = true;
    }
};

var game = new Game();

window.onload = function() {
    loadImages(function(){
    game.start();
    });
};

var animate = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    function(callback) { window.setTimeout(callback, 1000 / FRAMES_PER_SECOND) };<commit_msg>Simplified controls handling.<commit_after>var Game = function(){

    var mainCanvas = document.getElementById("canvas");
    mainCanvas.width = WIDTH;
    mainCanvas.height = HEIGHT;
    var mainCanvasContext = mainCanvas.getContext("2d");

    var backCanvas = getCanvasInstance();
    var backCanvasContext = backCanvas.getContext("2d");

    var lightManager = new RenderManager();

    var player = undefined;
    var maze = undefined;
    var stopwatch = undefined;

    var delta, now, then;

    var paused = false;

    function step() {
        setDelta();
        update();
        lightManager.render(mainCanvasContext, render);
        if(!paused)
            animate(step);
    }

    function update() {
        player.update(delta);
        handleControls();
    }

    function render(ctx){
        renderMaze(ctx);
        player.render(ctx);
    }

    function renderMaze(ctx){
        ctx.drawImage(backCanvas, 0, 0);
    }

    function setDelta(){
        now = Date.now();
        delta = (now - then) / 1000; // seconds since last frame
        then = now;
    }

    function getCanvasInstance(){
        var canvas = document.createElement('canvas');
        canvas.width = WIDTH;
        canvas.height = HEIGHT;
        return canvas;
    }

    function handleControls(){
        if(keysDown[KEY_MATCH]) player.lightMatch(lightManager);
        if(!player.isMoving){
            if(keysDown[KEY_LEFT])  player.moveTo(player.x - 2, player.y, delta, maze);
            if(keysDown[KEY_RIGHT]) player.moveTo(player.x + 2, player.y, delta, maze);
            if(keysDown[KEY_UP])    player.moveTo(player.x, player.y - 2, delta, maze);
            if(keysDown[KEY_DOWN])  player.moveTo(player.x, player.y + 2, delta, maze);
        }
    }

    this.start = function() {
        maze = new Maze(lightManager);
        player = new Player(maze.positioning);
        player.setEndGameCallback(this.stop);
        stopwatch = new Stopwatch(document.getElementById('time'));
        stopwatch.start();
        maze.render(backCanvasContext);
        animate(step);
    };

    this.stop = function(){
        stopwatch.stop();
        paused = true;
    }
};

var game = new Game();

window.onload = function() {
    loadImages(function(){
    game.start();
    });
};

var animate = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    function(callback) { window.setTimeout(callback, 1000 / FRAMES_PER_SECOND) };<|endoftext|>


<commit_before>var pg = require('pg');
var geojson = require('../helpers/geojson');
var jsonp = require('../helpers/jsonp');
module.exports.controller = function (app) {

	/* enable CORS */
	app.all('*', function (req, res, next) {
		res.header("Access-Control-Allow-Origin", "*");
		res.header("Access-Control-Allow-Headers", "X-Requested-With");
		next();
	});

	/* feature retrieval */

	/**
	 * retrieve all features (this could be really slow and is probably not what you really want to do)
	 */

app.get('/vector/:schema/:table/:geom/intersect', function (req, res, next) {
  var queryshape= ' {"type": "Point", "coordinates": [' + req.query['lng']  + ',' + req.query['lat']  +'] }'
		var geom = req.params.geom.toLowerCase();
		console.log('1');
		if ((geom != "features") && (geom != "geometry")) {
			res.status(404).send("Resource '" + geom + "' not found");
			return;
		}
		var client = new pg.Client(app.conString);
		console.log('2');
		var schemaname = req.params.schema;
		var tablename = req.params.table;
		var fullname = schemaname + "." + tablename;
		client.connect(function(err) {
		console.log('3');
		var spatialcol = "wkb_geometry";
    var sql;
		var coll;
		if (geom == "features") {
				console.log('5');
				sql = "select st_asgeojson(st_transform(" + spatialcol + ",4326)) as geojson, * from " + tablename + " where ST_INTERSECTS(" + spatialcol + ", ST_SetSRID(ST_GeomFromGeoJSON('" + queryshape + "'),4326));"
				coll = {
					type : "FeatureCollection",
					features : []
				};
				client.query(sql, function(err,result){
					console.log(6);
					console.log(result);
					res.send(jsonp.getJsonP(req.query.callback, coll));
					client.end();
				});
			}

			// query.on('row', function (result) {
			// 	console.log('here');
			// 	var props = new Object;
			// 	if (!result) {
			// 		return res.send('No data found');
			// 	} else {
			// 		if (geom == "features") {
			// 			coll.features.push(geojson.getFeatureResult(result, spatialcol));
			// 		} else if (geom == "geometry") {
			// 			var shape = JSON.parse(result.geojson);
			// 			coll.geometries.push(shape);
			// 		}
			// 	}
			// });

			// query.on('end', function (result) {

			// });
			// query.on('error', function (error) {
   //                              client.end();
			// 	//handle the error
			// 	//res.status(500).send(error);
			// 	//next();
			// });
	});
		// });
	});
// 	app.get('/vector/:schema/:table/:geom', function (req, res, next) {
// 		var client = new pg.Client(app.conString);
// 		var geom = req.params.geom.toLowerCase();
// 		if ((geom != "features") && (geom != "geometry")) {
// 			res.status(404).send("Resource '" + geom + "' not found");
// 			return;
// 		}
// 		var schemaname = req.params.schema;
// 		var tablename = req.params.table;
// 		var fullname = schemaname + "." + tablename;
//                 var proptype = req.query.type;
// 		var whereclause = ";";
// 		if (typeof proptype != "undefined") {
// 			if (proptype.toLowerCase() != "all") {
// 				whereclause = " where structure_ = '" + proptype + "';";
// 			}
// 		}
// 		var coll;
// 		var sql = "";
// 		client.connect(function (err) {
// 			if (err) {
// 				res.status(500).send(err);
// 				client.end();
// 				return console.error('could not connect to postgres', err);
// 			}
// 			client.query("select * from " + tablename + ";", function (err, result) {
// 				if (err) {
// 					res.status(500).send(err);
// 					client.end();
// 					return console.error('error running query', err);
// 				}
// 				spatialcol = result.rows[0].wkb_geometry;
// 				if (geom == "features") {
//                                         sql = "select st_asgeojson(st_transform(wkb_geometry,4326)) as geojson, * from " + tablename + ";";
// 					//sql = "select st_asgeojson(st_transform(" + spatialcol + ",4326)) as geojson, * from " + fullname + whereclause;
//                                         //if(tablename == 'uk') sql = "select st_asgeojson(wkb_geometry) as geojson, * from " + tablename + " limit 100;";
//                                         //console.log(sql);
// 					coll = {
// 						type : "FeatureCollection",
// 						features : []
// 					};
// 				} else if (geom == "geometry") {
//                                         sql = "select st_asgeojson(st_transform(wkb_geometry,4326)) as geojson, * from " + tablename + ";";
//                                         //console.log(sql);
// 						coll = {
// 						type : "GeometryCollection",
// 						geometries : []
// 					};
// 				}
// 				client.query(sql, function (err, result) {
// 					if (err) {
// 						res.status(500).send(err);
// 						client.end();
// 						return console.error('error running query', err);
// 					}
// 					for (var i = 0; i < result.rows.length; i++) {
// 						if (geom == "features") {
// 							coll.features.push(geojson.getFeatureResult(result.rows[i], "shape"));
// 						} else if (geom == "geometry") {
// 							var shape = JSON.parse(result.rows[i].geojson);
// 							//shape.crs = crsobj;
// 							coll.geometries.push(shape);
// 						}
// 					}
// 					client.end();
// 					res.send(jsonp.getJsonP(req.query.callback, coll));

// });
// });
// });
// });

		var client = new pg.Client(app.conString);
}
<commit_msg>cleaning up core.js<commit_after>var pg = require('pg');
var geojson = require('../helpers/geojson');
var jsonp = require('../helpers/jsonp');
module.exports.controller = function (app) {

	/* enable CORS */
	app.all('*', function (req, res, next) {
		res.header("Access-Control-Allow-Origin", "*");
		res.header("Access-Control-Allow-Headers", "X-Requested-With");
		next();
	});

	/* feature retrieval */

	/**
	 * retrieve all features (this could be really slow and is probably not what you really want to do)
	 */

app.get('/vector/:schema/:table/:geom/intersect', function (req, res, next) {
  var queryshape= ' {"type": "Point", "coordinates": [' + req.query['lng']  + ',' + req.query['lat']  +'] }'
		var geom = req.params.geom.toLowerCase();
		console.log('1');
		if ((geom != "features") && (geom != "geometry")) {
			res.status(404).send("Resource '" + geom + "' not found");
			return;
		}
		var client = new pg.Client(app.conString);
		console.log('2');
		var schemaname = req.params.schema;
		var tablename = req.params.table;
		var fullname = schemaname + "." + tablename;
		client.connect(function(err) {
		console.log('3');
		var spatialcol = "wkb_geometry";
    var sql;
		var coll;
		if (geom == "features") {
				console.log('5');
				sql = "select st_asgeojson(st_transform(" + spatialcol + ",4326)) as geojson, * from " + tablename + " where ST_INTERSECTS(" + spatialcol + ", ST_SetSRID(ST_GeomFromGeoJSON('" + queryshape + "'),4326));"
				coll = {
					type : "FeatureCollection",
					features : []
				};
				client.query(sql, function(err,result){
					console.log(6);
					console.log(result);
					console.log(7);
					res.send(jsonp.getJsonP(req.query.callback, result));
					client.end();
				});
			}

			// query.on('row', function (result) {
			// 	console.log('here');
			// 	var props = new Object;
			// 	if (!result) {
			// 		return res.send('No data found');
			// 	} else {
			// 		if (geom == "features") {
			// 			coll.features.push(geojson.getFeatureResult(result, spatialcol));
			// 		} else if (geom == "geometry") {
			// 			var shape = JSON.parse(result.geojson);
			// 			coll.geometries.push(shape);
			// 		}
			// 	}
			// });

			// query.on('end', function (result) {

			// });
			// query.on('error', function (error) {
   //                              client.end();
			// 	//handle the error
			// 	//res.status(500).send(error);
			// 	//next();
			// });
	});
		// });
	});
// 	app.get('/vector/:schema/:table/:geom', function (req, res, next) {
// 		var client = new pg.Client(app.conString);
// 		var geom = req.params.geom.toLowerCase();
// 		if ((geom != "features") && (geom != "geometry")) {
// 			res.status(404).send("Resource '" + geom + "' not found");
// 			return;
// 		}
// 		var schemaname = req.params.schema;
// 		var tablename = req.params.table;
// 		var fullname = schemaname + "." + tablename;
//                 var proptype = req.query.type;
// 		var whereclause = ";";
// 		if (typeof proptype != "undefined") {
// 			if (proptype.toLowerCase() != "all") {
// 				whereclause = " where structure_ = '" + proptype + "';";
// 			}
// 		}
// 		var coll;
// 		var sql = "";
// 		client.connect(function (err) {
// 			if (err) {
// 				res.status(500).send(err);
// 				client.end();
// 				return console.error('could not connect to postgres', err);
// 			}
// 			client.query("select * from " + tablename + ";", function (err, result) {
// 				if (err) {
// 					res.status(500).send(err);
// 					client.end();
// 					return console.error('error running query', err);
// 				}
// 				spatialcol = result.rows[0].wkb_geometry;
// 				if (geom == "features") {
//                                         sql = "select st_asgeojson(st_transform(wkb_geometry,4326)) as geojson, * from " + tablename + ";";
// 					//sql = "select st_asgeojson(st_transform(" + spatialcol + ",4326)) as geojson, * from " + fullname + whereclause;
//                                         //if(tablename == 'uk') sql = "select st_asgeojson(wkb_geometry) as geojson, * from " + tablename + " limit 100;";
//                                         //console.log(sql);
// 					coll = {
// 						type : "FeatureCollection",
// 						features : []
// 					};
// 				} else if (geom == "geometry") {
//                                         sql = "select st_asgeojson(st_transform(wkb_geometry,4326)) as geojson, * from " + tablename + ";";
//                                         //console.log(sql);
// 						coll = {
// 						type : "GeometryCollection",
// 						geometries : []
// 					};
// 				}
// 				client.query(sql, function (err, result) {
// 					if (err) {
// 						res.status(500).send(err);
// 						client.end();
// 						return console.error('error running query', err);
// 					}
// 					for (var i = 0; i < result.rows.length; i++) {
// 						if (geom == "features") {
// 							coll.features.push(geojson.getFeatureResult(result.rows[i], "shape"));
// 						} else if (geom == "geometry") {
// 							var shape = JSON.parse(result.rows[i].geojson);
// 							//shape.crs = crsobj;
// 							coll.geometries.push(shape);
// 						}
// 					}
// 					client.end();
// 					res.send(jsonp.getJsonP(req.query.callback, coll));

// });
// });
// });
// });

		var client = new pg.Client(app.conString);
}
<|endoftext|>