<commit_before>/*
    WidgetName
    ========================

    @file      : WidgetName.js
    @version   : {{version}}
    @author    : {{author}}
    @date      : {{date}}
    @copyright : {{copyright}}
    @license   : {{license}}

    Documentation
    ========================
    Describe your widget here.
*/

// Required module list. Remove unnecessary modules, you can always get them back from the boilerplate.
define([
    "dojo/_base/declare",
    "mxui/widget/_WidgetBase",
    "dijit/_TemplatedMixin",
    "mxui/dom",
    "dojo/dom",
    "dojo/dom-prop",
    "dojo/dom-geometry",
    "dojo/dom-class",
    "dojo/dom-style",
    "dojo/dom-construct",
    "dojo/_base/array",
    "dojo/_base/lang",
    "dojo/text",
    "dojo/html",
    "dojo/_base/event",
    "WidgetName/lib/jquery-1.11.2",
    "dojo/text!WidgetName/widget/template/WidgetName.html"
], function(declare, _WidgetBase, _TemplatedMixin, dom, dojoDom, dojoProp, dojoGeometry, dojoClass, dojoStyle, dojoConstruct, dojoArray, dojoLang, dojoText, dojoHtml, dojoEvent, _jQuery, widgetTemplate) {
    "use strict";

    var $ = _jQuery.noConflict(true);

    // Declare widget's prototype.
    return declare("WidgetName.widget.WidgetName", [ _WidgetBase, _TemplatedMixin ], {
        // _TemplatedMixin will create our dom node using this HTML template.
        templateString: widgetTemplate,

        // DOM elements
        inputNodes: null,
        colorSelectNode: null,
        colorInputNode: null,
        infoTextNode: null,

        // Parameters configured in the Modeler.
        mfToExecute: "",
        messageString: "",
        backgroundColor: "",

        // Internal variables. Non-primitives created in the prototype are shared between all widget instances.
        _handles: null,
        _contextObj: null,
        _alertDiv: null,

        // dojo.declare.constructor is called to construct the widget instance. Implement to initialize non-primitive properties.
        constructor: function() {
            this._handles = [];
        },

        // dijit._WidgetBase.postCreate is called after constructing the widget. Implement to do extra setup work.
        postCreate: function() {
            console.log(this.id + ".postCreate");
            this._updateRendering();
            this._setupEvents();
        },

        // mxui.widget._WidgetBase.update is called when context is changed or initialized. Implement to re-render and / or fetch data.
        update: function(obj, callback) {
            console.log(this.id + ".update");

            this._contextObj = obj;
            this._resetSubscriptions();
            this._updateRendering();

            callback();
        },

        // mxui.widget._WidgetBase.enable is called when the widget should enable editing. Implement to enable editing if widget is input widget.
        enable: function() {},

        // mxui.widget._WidgetBase.enable is called when the widget should disable editing. Implement to disable editing if widget is input widget.
        disable: function() {},

        // mxui.widget._WidgetBase.resize is called when the page's layout is recalculated. Implement to do sizing calculations. Prefer using CSS instead.
        resize: function(box) {},

        // mxui.widget._WidgetBase.uninitialize is called when the widget is destroyed. Implement to do special tear-down work.
        uninitialize: function() {
            // Clean up listeners, helper objects, etc. There is no need to remove listeners added with this.connect / this.subscribe / this.own.
        },

        // We want to stop events on a mobile device
        _stopBubblingEventOnMobile: function(e) {
            if (typeof document.ontouchstart !== "undefined") {
                dojoEvent.stop(e);
            }
        },

        // Attach events to HTML dom elements
        _setupEvents: function() {
            this.connect(this.colorSelectNode, "change", function(e) {
                // Function from mendix object to set an attribute.
                this._contextObj.set(this.backgroundColor, this.colorSelectNode.value);
            });

            this.connect(this.infoTextNode, "click", function(e) {
                // Only on mobile stop event bubbling!
                this._stopBubblingEventOnMobile(e);

                // If a microflow has been set execute the microflow on a click.
                if (this.mfToExecute !== "") {
                    mx.data.action({
                        params: {
                            applyto: "selection",
                            actionname: this.mfToExecute,
                            guids: [ this._contextObj.getGuid() ]
                        },
						store: {
							caller: this.mxform
						},
                        callback: function(obj) {
                            //TODO what to do when all is ok!
                        },
                        error: dojoLang.hitch(this, function(error) {
                            console.log(this.id + ": An error occurred while executing microflow: " + error.description);
                        })
                    }, this);
                }
            });
        },

        // Rerender the interface.
        _updateRendering: function() {
            this.colorSelectNode.disabled = this.readOnly;
            this.colorInputNode.disabled = this.readOnly;

            if (this._contextObj !== null) {
                dojoStyle.set(this.domNode, "display", "block");

                var colorValue = this._contextObj.get(this.backgroundColor);

                this.colorInputNode.value = colorValue;
                this.colorSelectNode.value = colorValue;

                dojoHtml.set(this.infoTextNode, this.messageString);
                dojoStyle.set(this.infoTextNode, "background-color", colorValue);
            } else {
                dojoStyle.set(this.domNode, "display", "none");
            }

            // Important to clear all validations!
            this._clearValidations();
        },

        // Handle validations.
        _handleValidation: function(validations) {
            this._clearValidations();

            var validation = validations[0],
                message = validation.getReasonByAttribute(this.backgroundColor);

            if (this.readOnly) {
                validation.removeAttribute(this.backgroundColor);
            } else if (message) {
                this._addValidation(message);
                validation.removeAttribute(this.backgroundColor);
            }
        },

        // Clear validations.
        _clearValidations: function() {
            dojoConstruct.destroy(this._alertDiv);
            this._alertDiv = null;
        },

        // Show an error message.
        _showError: function(message) {
            if (this._alertDiv !== null) {
                dojoHtml.set(this._alertDiv, message);
                return true;
            }
            this._alertDiv = dojoConstruct.create("div", {
                "class": "alert alert-danger",
                "innerHTML": message
            });
            dojoConstruct.place(this.domNode, this._alertDiv);
        },

        // Add a validation.
        _addValidation: function(message) {
            this._showError(message);
        },

        // Reset subscriptions.
        _resetSubscriptions: function() {
            // Release handles on previous object, if any.
            if (this._handles) {
                dojoArray.forEach(this._handles, function (handle) {
                    mx.data.unsubscribe(handle);
                });
                this._handles = [];
            }

            // When a mendix object exists create subscribtions.
            if (this._contextObj) {
                var objectHandle = this.subscribe({
                    guid: this._contextObj.getGuid(),
                    callback: dojoLang.hitch(this, function(guid) {
                        this._updateRendering();
                    })
                });

                var attrHandle = this.subscribe({
                    guid: this._contextObj.getGuid(),
                    attr: this.backgroundColor,
                    callback: dojoLang.hitch(this, function(guid, attr, attrValue) {
                        this._updateRendering();
                    })
                });

                var validationHandle = this.subscribe({
                    guid: this._contextObj.getGuid(),
                    val: true,
                    callback: dojoLang.hitch(this, this._handleValidation)
                });

                this._handles = [ objectHandle, attrHandle, validationHandle ];
            }
        }
    });
});

require(["WidgetName/widget/WidgetName"], function() {
    "use strict";
});
<commit_msg>Format whitespace & remove unnecessary logging<commit_after>/*global logger*/
/*
    WidgetName
    ========================

    @file      : WidgetName.js
    @version   : {{version}}
    @author    : {{author}}
    @date      : {{date}}
    @copyright : {{copyright}}
    @license   : {{license}}

    Documentation
    ========================
    Describe your widget here.
*/

// Required module list. Remove unnecessary modules, you can always get them back from the boilerplate.
define([
    "dojo/_base/declare",
    "mxui/widget/_WidgetBase",
    "dijit/_TemplatedMixin",

    "mxui/dom",
    "dojo/dom",
    "dojo/dom-prop",
    "dojo/dom-geometry",
    "dojo/dom-class",
    "dojo/dom-style",
    "dojo/dom-construct",
    "dojo/_base/array",
    "dojo/_base/lang",
    "dojo/text",
    "dojo/html",
    "dojo/_base/event",

    "WidgetName/lib/jquery-1.11.2",
    "dojo/text!WidgetName/widget/template/WidgetName.html"
], function(declare, _WidgetBase, _TemplatedMixin, dom, dojoDom, dojoProp, dojoGeometry, dojoClass, dojoStyle, dojoConstruct, dojoArray, dojoLang, dojoText, dojoHtml, dojoEvent, _jQuery, widgetTemplate) {
    "use strict";

    var $ = _jQuery.noConflict(true);

    // Declare widget's prototype.
    return declare("WidgetName.widget.WidgetName", [ _WidgetBase, _TemplatedMixin ], {
        // _TemplatedMixin will create our dom node using this HTML template.
        templateString: widgetTemplate,

        // DOM elements
        inputNodes: null,
        colorSelectNode: null,
        colorInputNode: null,
        infoTextNode: null,

        // Parameters configured in the Modeler.
        mfToExecute: "",
        messageString: "",
        backgroundColor: "",

        // Internal variables. Non-primitives created in the prototype are shared between all widget instances.
        _handles: null,
        _contextObj: null,
        _alertDiv: null,

        // dojo.declare.constructor is called to construct the widget instance. Implement to initialize non-primitive properties.
        constructor: function() {
            this._handles = [];
        },

        // dijit._WidgetBase.postCreate is called after constructing the widget. Implement to do extra setup work.
        postCreate: function() {
            logger.debug(this.id + ".postCreate");
            this._updateRendering();
            this._setupEvents();
        },

        // mxui.widget._WidgetBase.update is called when context is changed or initialized. Implement to re-render and / or fetch data.
        update: function(obj, callback) {
            logger.debug(this.id + ".update");

            this._contextObj = obj;
            this._resetSubscriptions();
            this._updateRendering();

            callback();
        },

        // mxui.widget._WidgetBase.enable is called when the widget should enable editing. Implement to enable editing if widget is input widget.
        enable: function() {},

        // mxui.widget._WidgetBase.enable is called when the widget should disable editing. Implement to disable editing if widget is input widget.
        disable: function() {},

        // mxui.widget._WidgetBase.resize is called when the page's layout is recalculated. Implement to do sizing calculations. Prefer using CSS instead.
        resize: function(box) {},

        // mxui.widget._WidgetBase.uninitialize is called when the widget is destroyed. Implement to do special tear-down work.
        uninitialize: function() {
            // Clean up listeners, helper objects, etc. There is no need to remove listeners added with this.connect / this.subscribe / this.own.
        },

        // We want to stop events on a mobile device
        _stopBubblingEventOnMobile: function(e) {
            if (typeof document.ontouchstart !== "undefined") {
                dojoEvent.stop(e);
            }
        },

        // Attach events to HTML dom elements
        _setupEvents: function() {
            this.connect(this.colorSelectNode, "change", function(e) {
                // Function from mendix object to set an attribute.
                this._contextObj.set(this.backgroundColor, this.colorSelectNode.value);
            });

            this.connect(this.infoTextNode, "click", function(e) {
                // Only on mobile stop event bubbling!
                this._stopBubblingEventOnMobile(e);

                // If a microflow has been set execute the microflow on a click.
                if (this.mfToExecute !== "") {
                    mx.data.action({
                        params: {
                            applyto: "selection",
                            actionname: this.mfToExecute,
                            guids: [ this._contextObj.getGuid() ]
                        },
                        store: {
                            caller: this.mxform
                        },
                        callback: function(obj) {
                            //TODO what to do when all is ok!
                        },
                        error: dojoLang.hitch(this, function(error) {
                            logger.error(this.id + ": An error occurred while executing microflow: " + error.description);
                        })
                    }, this);
                }
            });
        },

        // Rerender the interface.
        _updateRendering: function() {
            this.colorSelectNode.disabled = this.readOnly;
            this.colorInputNode.disabled = this.readOnly;

            if (this._contextObj !== null) {
                dojoStyle.set(this.domNode, "display", "block");

                var colorValue = this._contextObj.get(this.backgroundColor);

                this.colorInputNode.value = colorValue;
                this.colorSelectNode.value = colorValue;

                dojoHtml.set(this.infoTextNode, this.messageString);
                dojoStyle.set(this.infoTextNode, "background-color", colorValue);
            } else {
                dojoStyle.set(this.domNode, "display", "none");
            }

            // Important to clear all validations!
            this._clearValidations();
        },

        // Handle validations.
        _handleValidation: function(validations) {
            this._clearValidations();

            var validation = validations[0],
                message = validation.getReasonByAttribute(this.backgroundColor);

            if (this.readOnly) {
                validation.removeAttribute(this.backgroundColor);
            } else if (message) {
                this._addValidation(message);
                validation.removeAttribute(this.backgroundColor);
            }
        },

        // Clear validations.
        _clearValidations: function() {
            dojoConstruct.destroy(this._alertDiv);
            this._alertDiv = null;
        },

        // Show an error message.
        _showError: function(message) {
            if (this._alertDiv !== null) {
                dojoHtml.set(this._alertDiv, message);
                return true;
            }
            this._alertDiv = dojoConstruct.create("div", {
                "class": "alert alert-danger",
                "innerHTML": message
            });
            dojoConstruct.place(this.domNode, this._alertDiv);
        },

        // Add a validation.
        _addValidation: function(message) {
            this._showError(message);
        },

        // Reset subscriptions.
        _resetSubscriptions: function() {
            // Release handles on previous object, if any.
            if (this._handles) {
                dojoArray.forEach(this._handles, function (handle) {
                    mx.data.unsubscribe(handle);
                });
                this._handles = [];
            }

            // When a mendix object exists create subscribtions.
            if (this._contextObj) {
                var objectHandle = this.subscribe({
                    guid: this._contextObj.getGuid(),
                    callback: dojoLang.hitch(this, function(guid) {
                        this._updateRendering();
                    })
                });

                var attrHandle = this.subscribe({
                    guid: this._contextObj.getGuid(),
                    attr: this.backgroundColor,
                    callback: dojoLang.hitch(this, function(guid, attr, attrValue) {
                        this._updateRendering();
                    })
                });

                var validationHandle = this.subscribe({
                    guid: this._contextObj.getGuid(),
                    val: true,
                    callback: dojoLang.hitch(this, this._handleValidation)
                });

                this._handles = [ objectHandle, attrHandle, validationHandle ];
            }
        }
    });
});

require(["WidgetName/widget/WidgetName"], function() {
    "use strict";
});
<|endoftext|>


<commit_before>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails react-core
 */

'use strict';

var update = require('update');

describe('update', function() {
  it('should support push', function() {
    expect(update([1], {$push: [7]})).toEqual([1, 7]);
    expect(update.bind(null, [], {$push: 7})).toThrow(
      'update(): expected spec of $push to be an array; got 7. Did you ' +
      'forget to wrap your parameter in an array?'
    );
    expect(update.bind(null, 1, {$push: 7})).toThrow(
      'update(): expected target of $push to be an array; got 1.'
    );
  });

  it('should support unshift', function() {
    expect(update([1], {$unshift: [7]})).toEqual([7, 1]);
    expect(update.bind(null, [], {$unshift: 7})).toThrow(
      'update(): expected spec of $unshift to be an array; got 7. Did you ' +
      'forget to wrap your parameter in an array?'
    );
    expect(update.bind(null, 1, {$unshift: 7})).toThrow(
      'update(): expected target of $unshift to be an array; got 1.'
    );
  });

  it('should support splice', function() {
    expect(update([1, 4, 3], {$splice: [[1, 1, 2]]})).toEqual([1, 2, 3]);
    expect(update.bind(null, [], {$splice: 1})).toThrow(
      'update(): expected spec of $splice to be an array of arrays; got 1. ' +
      'Did you forget to wrap your parameters in an array?'
    );
    expect(update.bind(null, [], {$splice: [1]})).toThrow(
      'update(): expected spec of $splice to be an array of arrays; got 1. ' +
      'Did you forget to wrap your parameters in an array?'
    );
    expect(update.bind(null, 1, {$splice: 7})).toThrow(
      'Expected $splice target to be an array; got 1'
    );
  });

  it('should support merge', function() {
    expect(update({a: 'b'}, {$merge: {c: 'd'}})).toEqual({a: 'b', c: 'd'});
    expect(update.bind(null, {}, {$merge: 7})).toThrow(
      'update(): $merge expects a spec of type \'object\'; got 7'
    );
    expect(update.bind(null, 7, {$merge: {a: 'b'}})).toThrow(
      'update(): $merge expects a target of type \'object\'; got 7'
    );
  });

  it('should support set', function() {
    expect(update({a: 'b'}, {$set: {c: 'd'}})).toEqual({c: 'd'});
  });

  it('should support apply', function() {
    expect(update(2, {$apply: (x) => x * 2})).toEqual(4);
    expect(update.bind(null, 2, {$apply: 123})).toThrow(
      'update(): expected spec of $apply to be a function; got 123.'
    );
  });

  it('should support deep updates', function() {
    expect(update({a: 'b', c: {d: 'e'}}, {c: {d: {$set: 'f'}}})).toEqual({
      a: 'b',
      c: {d: 'f'},
    });
  });

  it('should require a command', function() {
    expect(update.bind(null, {a: 'b'}, {a: 'c'})).toThrow(
      'update(): You provided a key path to update() that did not contain ' +
      'one of $push, $unshift, $splice, $set, $merge, $apply. Did you ' +
      'forget to include {$set: ...}?'
    );
  });

  it('should perform safe hasOwnProperty check', function() {
    expect(update({}, {'hasOwnProperty': {$set: 'a'}})).toEqual({
      'hasOwnProperty': 'a',
    });
  });
});
<commit_msg>improved react-addons-update tests<commit_after>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails react-core
 */

'use strict';

var update = require('update');

describe('update', function() {

  describe('$push', function() {
    it('pushes', function() {
      expect(update([1], {$push: [7]})).toEqual([1, 7]);
    });
    it('does not mutate the original object', function() {
      var obj = [1];
      update(obj, {$push: [7]});
      expect(obj).toEqual([1]);
    });
    it('only pushes an array', function() {
      expect(update.bind(null, [], {$push: 7})).toThrow(
        'update(): expected spec of $push to be an array; got 7. Did you ' +
        'forget to wrap your parameter in an array?'
      );
    });
    it('only pushes unto an array', function() {
      expect(update.bind(null, 1, {$push: 7})).toThrow(
        'update(): expected target of $push to be an array; got 1.'
      );
    });
  });

  describe('$unshift', function() {
    it('unshifts', function() {
      expect(update([1], {$unshift: [7]})).toEqual([7, 1]);
    });
    it('does not mutate the original object', function() {
      var obj = [1];
      update(obj, {$unshift: [7]});
      expect(obj).toEqual([1]);
    });
    it('only unshifts an array', function() {
      expect(update.bind(null, [], {$unshift: 7})).toThrow(
        'update(): expected spec of $unshift to be an array; got 7. Did you ' +
        'forget to wrap your parameter in an array?'
      );
    });
    it('only unshifts unto an array', function() {
      expect(update.bind(null, 1, {$unshift: 7})).toThrow(
        'update(): expected target of $unshift to be an array; got 1.'
      );
    });
  });

  describe('$splice', function() {
    it('splices', function() {
      expect(update([1, 4, 3], {$splice: [[1, 1, 2]]})).toEqual([1, 2, 3]);
    });
    it('does not mutate the original object', function() {
      var obj = [1, 4, 3];
      update(obj, {$splice: [[1, 1, 2]]});
      expect(obj).toEqual([1, 4, 3]);
    });
    it('only splices an array of arrays', function() {
      expect(update.bind(null, [], {$splice: 1})).toThrow(
        'update(): expected spec of $splice to be an array of arrays; got 1. ' +
        'Did you forget to wrap your parameters in an array?'
      );
      expect(update.bind(null, [], {$splice: [1]})).toThrow(
        'update(): expected spec of $splice to be an array of arrays; got 1. ' +
        'Did you forget to wrap your parameters in an array?'
      );
    });
    it('only splices unto an array', function() {
      expect(update.bind(null, 1, {$splice: 7})).toThrow(
        'Expected $splice target to be an array; got 1'
      );
    });
  });

  describe('$merge', function() {
    it('merges', function() {
      expect(update({a: 'b'}, {$merge: {c: 'd'}})).toEqual({a: 'b', c: 'd'});
    });
    it('does not mutate the original object', function() {
      var obj = {a: 'b'};
      update(obj, {$merge: {c: 'd'}});
      expect(obj).toEqual({a: 'b'});
    });
    it('only merges with an object', function() {
      expect(update.bind(null, {}, {$merge: 7})).toThrow(
        'update(): $merge expects a spec of type \'object\'; got 7'
      );
    });
    it('only merges with an object', function() {
      expect(update.bind(null, 7, {$merge: {a: 'b'}})).toThrow(
        'update(): $merge expects a target of type \'object\'; got 7'
      );
    });
  });

  describe('$set', function() {
    it('sets', function() {
      expect(update({a: 'b'}, {$set: {c: 'd'}})).toEqual({c: 'd'});
    });
    it('does not mutate the original object', function() {
      var obj = {a: 'b'};
      update(obj, {$set: {c: 'd'}});
      expect(obj).toEqual({a: 'b'});
    });
  });

  describe('$apply', function() {
    var applier = function(node) {
      return {v: node.v * 2};
    };
    it('applies', function() {
      expect(update({v: 2}, {$apply: applier})).toEqual({v: 4});
    });
    it('does not mutate the original object', function() {
      var obj = {v: 2};
      update(obj, {$apply: applier});
      expect(obj).toEqual({v: 2});
    });
    it('only applies a function', function() {
      expect(update.bind(null, 2, {$apply: 123})).toThrow(
        'update(): expected spec of $apply to be a function; got 123.'
      );
    });
  });

  it('should support deep updates', function() {
    expect(update({
      a: 'b',
      c: {
        d: 'e',
        f: [1],
        g: [2],
        h: [3],
        i: {j: 'k'},
        l: 4,
      },
    }, {
      c: {
        d: {$set: 'm'},
        f: {$push: [5]},
        g: {$unshift: [6]},
        h: {$splice: [[0, 1, 7]]},
        i: {$merge: {n: 'o'}},
        l: {$apply: (x) => x * 2},
      },
    })).toEqual({
      a: 'b',
      c: {
        d: 'm',
        f: [1, 5],
        g: [6, 2],
        h: [7],
        i: {j: 'k', n: 'o'},
        l: 8,
      },
    });
  });

  it('should require a command', function() {
    expect(update.bind(null, {a: 'b'}, {a: 'c'})).toThrow(
      'update(): You provided a key path to update() that did not contain ' +
      'one of $push, $unshift, $splice, $set, $merge, $apply. Did you ' +
      'forget to include {$set: ...}?'
    );
  });

  it('should perform safe hasOwnProperty check', function() {
    expect(update({}, {'hasOwnProperty': {$set: 'a'}})).toEqual({
      'hasOwnProperty': 'a',
    });
  });
});
<|endoftext|>


<commit_before>var SqlString = exports;

SqlString.escapeId = function (val, forbidQualified) {
  if (forbidQualified) {
    return '`' + val.replace(/`/g, '``') + '`';
  }
  return '`' + val.replace(/`/g, '``').replace(/\./g, '`.`') + '`';
};

SqlString.escape = function(val, stringifyObjects, timeZone, dialect) {
  if (val === undefined || val === null) {
    return 'NULL';
  }

  switch (typeof val) {
    case 'boolean': return (val) ? 'true' : 'false';
    case 'number': return val+'';
  }

  if (val instanceof Date) {
    val = SqlString.dateToString(val, timeZone || "Z");
  }

  if (Buffer.isBuffer(val)) {
    return SqlString.bufferToString(val);
  }

  if (Array.isArray(val)) {
    return SqlString.arrayToList(val, timeZone);
  }

  if (typeof val === 'object') {
    if (stringifyObjects) {
      val = val.toString();
    } else {
      return SqlString.objectToValues(val, timeZone);
    }
  }

  if (dialect == "postgres") {
    // http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS
    val = val.replace(/'/g, "''");
  } else {
    val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
      switch(s) {
        case "\0": return "\\0";
        case "\n": return "\\n";
        case "\r": return "\\r";
        case "\b": return "\\b";
        case "\t": return "\\t";
        case "\x1a": return "\\Z";
        default: return "\\"+s;
      }
    });
  }
  return "'"+val+"'";
};

SqlString.arrayToList = function(array, timeZone) {
  return array.map(function(v) {
    if (Array.isArray(v)) return '(' + SqlString.arrayToList(v) + ')';
    return SqlString.escape(v, true, timeZone);
  }).join(', ');
};

SqlString.format = function(sql, values, timeZone, dialect) {
  values = [].concat(values);

  return sql.replace(/\?/g, function(match) {
    if (!values.length) {
      return match;
    }

    return SqlString.escape(values.shift(), false, timeZone, dialect);
  });
};

SqlString.dateToString = function(date, timeZone) {
  var dt = new Date(date);

  if (timeZone != 'local') {
    var tz = convertTimezone(timeZone);

    dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000));
    if (tz !== false) {
      dt.setTime(dt.getTime() + (tz * 60000));
    }
  }

  var year   = dt.getFullYear();
  var month  = zeroPad(dt.getMonth() + 1);
  var day    = zeroPad(dt.getDate());
  var hour   = zeroPad(dt.getHours());
  var minute = zeroPad(dt.getMinutes());
  var second = zeroPad(dt.getSeconds());

  return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
};

SqlString.bufferToString = function(buffer) {
  var hex = '';
  try {
    hex = buffer.toString('hex');
  } catch (err) {
    // node v0.4.x does not support hex / throws unknown encoding error
    for (var i = 0; i < buffer.length; i++) {
      var byte = buffer[i];
      hex += zeroPad(byte.toString(16));
    }
  }

  return "X'" + hex+ "'";
};

SqlString.objectToValues = function(object, timeZone) {
  var values = [];
  for (var key in object) {
    var value = object[key];
    if(typeof value === 'function') {
      continue;
    }

    values.push(this.escapeId(key) + ' = ' + SqlString.escape(value, true, timeZone));
  }

  return values.join(', ');
};

function zeroPad(number) {
  return (number < 10) ? '0' + number : number;
}

function convertTimezone(tz) {
  if (tz == "Z") return 0;

  var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/);
  if (m) {
    return (m[1] == '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60;
  }
  return false;
}
<commit_msg>Fix string escaping for sqlite<commit_after>var SqlString = exports;

SqlString.escapeId = function (val, forbidQualified) {
  if (forbidQualified) {
    return '`' + val.replace(/`/g, '``') + '`';
  }
  return '`' + val.replace(/`/g, '``').replace(/\./g, '`.`') + '`';
};

SqlString.escape = function(val, stringifyObjects, timeZone, dialect) {
  if (val === undefined || val === null) {
    return 'NULL';
  }

  switch (typeof val) {
    case 'boolean': return (val) ? 'true' : 'false';
    case 'number': return val+'';
  }

  if (val instanceof Date) {
    val = SqlString.dateToString(val, timeZone || "Z");
  }

  if (Buffer.isBuffer(val)) {
    return SqlString.bufferToString(val);
  }

  if (Array.isArray(val)) {
    return SqlString.arrayToList(val, timeZone);
  }

  if (typeof val === 'object') {
    if (stringifyObjects) {
      val = val.toString();
    } else {
      return SqlString.objectToValues(val, timeZone);
    }
  }

  if (dialect === "postgres" || dialect === "sqlite") {
    // http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS
    // http://stackoverflow.com/q/603572/130598
    val = val.replace(/'/g, "''");
  } else {
    val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
      switch(s) {
        case "\0": return "\\0";
        case "\n": return "\\n";
        case "\r": return "\\r";
        case "\b": return "\\b";
        case "\t": return "\\t";
        case "\x1a": return "\\Z";
        default: return "\\"+s;
      }
    });
  }
  return "'"+val+"'";
};

SqlString.arrayToList = function(array, timeZone) {
  return array.map(function(v) {
    if (Array.isArray(v)) return '(' + SqlString.arrayToList(v) + ')';
    return SqlString.escape(v, true, timeZone);
  }).join(', ');
};

SqlString.format = function(sql, values, timeZone, dialect) {
  values = [].concat(values);

  return sql.replace(/\?/g, function(match) {
    if (!values.length) {
      return match;
    }

    return SqlString.escape(values.shift(), false, timeZone, dialect);
  });
};

SqlString.dateToString = function(date, timeZone) {
  var dt = new Date(date);

  if (timeZone != 'local') {
    var tz = convertTimezone(timeZone);

    dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000));
    if (tz !== false) {
      dt.setTime(dt.getTime() + (tz * 60000));
    }
  }

  var year   = dt.getFullYear();
  var month  = zeroPad(dt.getMonth() + 1);
  var day    = zeroPad(dt.getDate());
  var hour   = zeroPad(dt.getHours());
  var minute = zeroPad(dt.getMinutes());
  var second = zeroPad(dt.getSeconds());

  return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
};

SqlString.bufferToString = function(buffer) {
  var hex = '';
  try {
    hex = buffer.toString('hex');
  } catch (err) {
    // node v0.4.x does not support hex / throws unknown encoding error
    for (var i = 0; i < buffer.length; i++) {
      var byte = buffer[i];
      hex += zeroPad(byte.toString(16));
    }
  }

  return "X'" + hex+ "'";
};

SqlString.objectToValues = function(object, timeZone) {
  var values = [];
  for (var key in object) {
    var value = object[key];
    if(typeof value === 'function') {
      continue;
    }

    values.push(this.escapeId(key) + ' = ' + SqlString.escape(value, true, timeZone));
  }

  return values.join(', ');
};

function zeroPad(number) {
  return (number < 10) ? '0' + number : number;
}

function convertTimezone(tz) {
  if (tz == "Z") return 0;

  var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/);
  if (m) {
    return (m[1] == '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60;
  }
  return false;
}
<|endoftext|>


<commit_before>var moment = require("moment")
  , isArrayBufferView
  , SqlString = exports;

if(typeof(ArrayBufferView) === 'function') {
  isArrayBufferView = function(object) { return object && (object instanceof ArrayBufferView); };
} else {
  var arrayBufferViews = [
    Int8Array, Uint8Array, Int16Array, Uint16Array,
    Int32Array, Uint32Array, Float32Array, Float64Array
  ];
  isArrayBufferView = function(object) {
    for(var i=0;i<8;i++) {
      if(object instanceof arrayBufferViews[i]) {
        return true;
      }
    }
    return false;
  };
}

SqlString.escapeId = function (val, forbidQualified) {
  if (forbidQualified) {
    return '`' + val.replace(/`/g, '``') + '`';
  }
  return '`' + val.replace(/`/g, '``').replace(/\./g, '`.`') + '`';
};

SqlString.escape = function(val, stringifyObjects, timeZone, dialect, field) {
  if (arguments.length === 1 && typeof arguments[0] === "object") {
    val = val.val || val.value || null
    stringifyObjects = val.stringifyObjects || val.objects || undefined
    timeZone = val.timeZone || val.zone || null
    dialect = val.dialect || null
    field = val.field || null
  }
  else if (arguments.length < 3 && typeof arguments[1] === "object") {
    timeZone = stringifyObjects.timeZone || stringifyObjects.zone || null
    dialect = stringifyObjects.dialect || null
    field = stringifyObjects.field || null
  }

  if (val === undefined || val === null) {
    return 'NULL';
  }

  switch (typeof val) {
  case 'boolean':
    // SQLite doesn't have true/false support. MySQL aliases true/false to 1/0
    // for us. Postgres actually has a boolean type with true/false literals,
    // but sequelize doesn't use it yet.
    return dialect === 'sqlite' ? +!!val : ('' + !!val);
  case 'number':
    return val+'';
  }

  if (val instanceof Date) {
    val = SqlString.dateToString(val, timeZone || "Z", dialect);
  }

  if (Buffer.isBuffer(val)) {
    return SqlString.bufferToString(val, dialect);
  }

  if (Array.isArray(val)) {
    return SqlString.arrayToList(val, timeZone, dialect, field);
  }

  if (typeof val === 'object') {
    if (stringifyObjects) {
      val = val.toString();
    } else {
      return SqlString.objectToValues(val, timeZone);
    }
  }

  if (dialect === 'postgres' || dialect === 'sqlite') {
    // http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS
    // http://stackoverflow.com/q/603572/130598
    val = val.replace(/'/g, "''");
  } else {
    val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
      switch(s) {
        case "\0": return "\\0";
        case "\n": return "\\n";
        case "\r": return "\\r";
        case "\b": return "\\b";
        case "\t": return "\\t";
        case "\x1a": return "\\Z";
        default: return "\\"+s;
      }
    });
  }
  return "'"+val+"'";
};

SqlString.arrayToList = function(array, timeZone, dialect, field) {
  if (dialect === 'postgres') {
    var ret = 'ARRAY[' + array.map(function(v) {
      return SqlString.escape(v, true, timeZone, dialect, field);
    }).join(',') + ']';
    if (!!field && !!field.type) {
      ret += '::' + field.type.replace(/\(\d+\)/g, '');
    }
    return ret;
  } else {
    return array.map(function(v) {
      if (Array.isArray(v))
        return '(' + SqlString.arrayToList(v, timeZone, dialect) + ')';
      return SqlString.escape(v, true, timeZone, dialect);
    }).join(', ');
  }
};

SqlString.format = function(sql, values, timeZone, dialect) {
  values = [].concat(values);

  return sql.replace(/\?/g, function(match) {
    if (!values.length) {
      return match;
    }

    return SqlString.escape(values.shift(), false, timeZone, dialect);
  });
};

SqlString.formatNamedParameters = function(sql, values, timeZone, dialect) {
  return sql.replace(/\:(\w+)/g, function (value, key) {
    if (values.hasOwnProperty(key)) {
      return SqlString.escape(values[key], false, timeZone, dialect);
    }
    else {
      throw new Error('Named parameter "' + value + '" has no value in the given object.');
    }
  });
};

SqlString.dateToString = function(date, timeZone, dialect) {
  var dt = new Date(date);

  // TODO: Ideally all dialects would work a bit more like this
  if (dialect === "postgres") {
    return moment(dt).zone('+00:00').format("YYYY-MM-DD HH:mm:ss.SSS Z");
  }

  if (timeZone !== 'local') {
    var tz = convertTimezone(timeZone);

    dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000));
    if (tz !== false) {
      dt.setTime(dt.getTime() + (tz * 60000));
    }
  }

  return moment(dt).format("YYYY-MM-DD HH:mm:ss");
};

SqlString.bufferToString = function(buffer, dialect) {
  var hex = '';
  try {
    hex = buffer.toString('hex');
  } catch (err) {
    // node v0.4.x does not support hex / throws unknown encoding error
    for (var i = 0; i < buffer.length; i++) {
      var byte = buffer[i];
      hex += zeroPad(byte.toString(16));
    }
  }

  if (dialect === 'postgres') {
    // bytea hex format http://www.postgresql.org/docs/current/static/datatype-binary.html
    return "E'\\\\x" + hex+ "'";
  }
  return "X'" + hex+ "'";
};

SqlString.objectToValues = function(object, timeZone) {
  var values = [];
  for (var key in object) {
    var value = object[key];
    if(typeof value === 'function') {
      continue;
    }

    values.push(this.escapeId(key) + ' = ' + SqlString.escape(value, true, timeZone));
  }

  return values.join(', ');
};

function zeroPad(number) {
  return (number < 10) ? '0' + number : number;
}

function convertTimezone(tz) {
  if (tz == "Z") return 0;

  var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/);
  if (m) {
    return (m[1] == '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60;
  }
  return false;
}
<commit_msg>Allow SqlString.arrayToList method to process typed arrays<commit_after>var moment = require("moment")
  , isArrayBufferView
  , SqlString = exports;

if(typeof(ArrayBufferView) === 'function') {
  isArrayBufferView = function(object) { return object && (object instanceof ArrayBufferView); };
} else {
  var arrayBufferViews = [
    Int8Array, Uint8Array, Int16Array, Uint16Array,
    Int32Array, Uint32Array, Float32Array, Float64Array
  ];
  isArrayBufferView = function(object) {
    for(var i=0;i<8;i++) {
      if(object instanceof arrayBufferViews[i]) {
        return true;
      }
    }
    return false;
  };
}

SqlString.escapeId = function (val, forbidQualified) {
  if (forbidQualified) {
    return '`' + val.replace(/`/g, '``') + '`';
  }
  return '`' + val.replace(/`/g, '``').replace(/\./g, '`.`') + '`';
};

SqlString.escape = function(val, stringifyObjects, timeZone, dialect, field) {
  if (arguments.length === 1 && typeof arguments[0] === "object") {
    val = val.val || val.value || null
    stringifyObjects = val.stringifyObjects || val.objects || undefined
    timeZone = val.timeZone || val.zone || null
    dialect = val.dialect || null
    field = val.field || null
  }
  else if (arguments.length < 3 && typeof arguments[1] === "object") {
    timeZone = stringifyObjects.timeZone || stringifyObjects.zone || null
    dialect = stringifyObjects.dialect || null
    field = stringifyObjects.field || null
  }

  if (val === undefined || val === null) {
    return 'NULL';
  }

  switch (typeof val) {
  case 'boolean':
    // SQLite doesn't have true/false support. MySQL aliases true/false to 1/0
    // for us. Postgres actually has a boolean type with true/false literals,
    // but sequelize doesn't use it yet.
    return dialect === 'sqlite' ? +!!val : ('' + !!val);
  case 'number':
    return val+'';
  }

  if (val instanceof Date) {
    val = SqlString.dateToString(val, timeZone || "Z", dialect);
  }

  if (Buffer.isBuffer(val)) {
    return SqlString.bufferToString(val, dialect);
  }
  if (Array.isArray(val) || isArrayBufferView(val)) {
    return SqlString.arrayToList(val, timeZone, dialect, field);
  }

  if (typeof val === 'object') {
    if (stringifyObjects) {
      val = val.toString();
    } else {
      return SqlString.objectToValues(val, timeZone);
    }
  }

  if (dialect === 'postgres' || dialect === 'sqlite') {
    // http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS
    // http://stackoverflow.com/q/603572/130598
    val = val.replace(/'/g, "''");
  } else {
    val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
      switch(s) {
        case "\0": return "\\0";
        case "\n": return "\\n";
        case "\r": return "\\r";
        case "\b": return "\\b";
        case "\t": return "\\t";
        case "\x1a": return "\\Z";
        default: return "\\"+s;
      }
    });
  }
  return "'"+val+"'";
};

SqlString.arrayToList = function(array, timeZone, dialect, field) {
  if (dialect === 'postgres') {
    if (array.map) {
      var valstr = array.map(function(v) {
        return SqlString.escape(v, true, timeZone, dialect, field);
      }).join(',');
    } else {
      var valstr = "";
      for (var i = 0; i < array.length; i++) {
        valstr += SqlString.escape(array[i], true, timeZone, dialect, field) + ',';
      }
      valstr = valstr.slice(0,-1);
    }
    var ret = 'ARRAY[' + valstr + ']';
    if (!!field && !!field.type) {
      ret += '::' + field.type.replace(/\(\d+\)/g, '');
    }
    return ret;
  } else {
    if (array.map) {
      return array.map(function(v) {
        if (Array.isArray(v))
          return '(' + SqlString.arrayToList(v, timeZone, dialect) + ')';
        return SqlString.escape(v, true, timeZone, dialect);
      }).join(', ');
    } else {
      var valstr = "";
      for (var i = 0; i < array.length; i++) {
        valstr += SqlString.escape(array[i], true, timeZone, dialect) + ', ';
      }
      return valstr.slice(0, -2);
    }
  }
};

SqlString.format = function(sql, values, timeZone, dialect) {
  values = [].concat(values);

  return sql.replace(/\?/g, function(match) {
    if (!values.length) {
      return match;
    }

    return SqlString.escape(values.shift(), false, timeZone, dialect);
  });
};

SqlString.formatNamedParameters = function(sql, values, timeZone, dialect) {
  return sql.replace(/\:(\w+)/g, function (value, key) {
    if (values.hasOwnProperty(key)) {
      return SqlString.escape(values[key], false, timeZone, dialect);
    }
    else {
      throw new Error('Named parameter "' + value + '" has no value in the given object.');
    }
  });
};

SqlString.dateToString = function(date, timeZone, dialect) {
  var dt = new Date(date);

  // TODO: Ideally all dialects would work a bit more like this
  if (dialect === "postgres") {
    return moment(dt).zone('+00:00').format("YYYY-MM-DD HH:mm:ss.SSS Z");
  }

  if (timeZone !== 'local') {
    var tz = convertTimezone(timeZone);

    dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000));
    if (tz !== false) {
      dt.setTime(dt.getTime() + (tz * 60000));
    }
  }

  return moment(dt).format("YYYY-MM-DD HH:mm:ss");
};

SqlString.bufferToString = function(buffer, dialect) {
  var hex = '';
  try {
    hex = buffer.toString('hex');
  } catch (err) {
    // node v0.4.x does not support hex / throws unknown encoding error
    for (var i = 0; i < buffer.length; i++) {
      var byte = buffer[i];
      hex += zeroPad(byte.toString(16));
    }
  }

  if (dialect === 'postgres') {
    // bytea hex format http://www.postgresql.org/docs/current/static/datatype-binary.html
    return "E'\\\\x" + hex+ "'";
  }
  return "X'" + hex+ "'";
};

SqlString.objectToValues = function(object, timeZone) {
  var values = [];
  for (var key in object) {
    var value = object[key];
    if(typeof value === 'function') {
      continue;
    }

    values.push(this.escapeId(key) + ' = ' + SqlString.escape(value, true, timeZone));
  }

  return values.join(', ');
};

function zeroPad(number) {
  return (number < 10) ? '0' + number : number;
}

function convertTimezone(tz) {
  if (tz == "Z") return 0;

  var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/);
  if (m) {
    return (m[1] == '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60;
  }
  return false;
}
<|endoftext|>


<commit_before>'use strict'

const putMoneyIn = {
    fold    : false
  , check   : false
  , collect : false
  , post    : true
  , call    : true
  , bet     : true
  , raise   : true
}

const cardsOnBoard = {
    preflop  : 0
  , flop     : 3
  , turn     : 4
  , river    : 5
  , showdown : 5
}

/**
 * Takes a script of actions and calculates the states for each.
 * Adds pointers to the state at the beginning of each script.
 *
 * This is useful if you try to jump around in the hand and reset
 * the state of the table.
 *
 * @name hha:storyboard
 * @function
 * @param {Object} script created via @see hha:script
 */
module.exports = function storyboard(script) {
  const states = []

  //
  // initially
  //
  function getVal(acc, k) {
    if (script.board[k]) acc.push(script.board[k])
    return acc
  }

  const board = script.board && Object.keys(script.board).reduce(getVal, []) || []

  // will be sparse if not all players present
  let seats = new Array(script.table.maxseats + 1)
  function addSeat(p, idx) {
    seats[p.seatno] = {
        chips       : p.chipsPreflop
      , name        : p.name
      , m           : p.m
      , sb          : p.sb
      , bb          : p.bb
      , button      : p.button
      , action      : null
      , amount      : 0
      , bet         : 0
      , investedBet : p.bb ? 1 : 0
      , holecards   : p.cards || { card1 : '??', card2 : '??' }
      , playerIdx   : idx
      , seatno      : p.seatno
    }
  }
  script.players.forEach(addSeat)

  //
  // From now on we always map seats even though we reuse the variable
  // in order to avoid affecting previous states
  //

  function resetSeat(s) {
    const street = this.street
    const stage  = this.stage

    const preflop = street === 'preflop'
    const chipsName = 'chips' + street[0].toUpperCase() + street.slice(1)
    const p = script.players[s.playerIdx]
    const chips = p[chipsName]
    return Object.assign({}, seats[p.seatno], {
        chips       : chips
      , action      : null
      , amount      : 0
      , bet         : 0
      , investedBet : preflop && p.bb ? 1 : 0
      , _lastUpdate : stage
    })
  }

  function adaptSeat(s, idx) {
    const p = this.p
    const a = this.a
    const stage = this.stage
    if (typeof s === 'undefined' || p.seatno !== idx) return s

    // cards are not at player's seat anymore after he folded
    const folded = a.type === 'fold'
    const holecards = folded ? null : s.holecards
    const investedBet = putMoneyIn[a.type] ? a.bet : s.investedBet
    return Object.assign({}, s, {
        chips       : a.chipsAfter
      , action      : a.type
      , amount      : a.amount
      , bet         : a.bet || 0
      , investedBet : investedBet || 0
      , holecards   : holecards
      , folded      : folded
      , _lastUpdate : stage
    })
  }

  let streetIdxs = {
      preflop  : null
    , flop     : null
    , turn     : null
    , river    : null
    , showdown : null
  }

  const folded = {}

  function addFolded() {
    for (var i = 0; i < seats.length; i++) {
      const s = seats[i]
      if (s && s.folded) folded[s.seatno] = true
    }
  }

  function collectAction(street) {
    const flop = street === 'flop'
    function tocollect(acc, s) {
      if (folded[s.seatno]) return acc

      // small blinds posted and their bet size is 0 (half a blind)
      // however if they invested more we'll use that amount
      if (s.sb && flop) {
        acc.push({ seatno: s.seatno, bet: s.investedBet || 0 })

      // big blinds need to have their big blind collected at least
      } else if (s.bb) {
        acc.push({ seatno: s.seatno, bet: Math.max(1, (s.investedBet || 0)) })

      // all others have no chips in front of them if they didn't invest
      } else if (s.investedBet) {
        acc.push({ seatno: s.seatno, bet: s.investedBet })
      }
      return acc
    }

    return seats.reduce(tocollect, [])
  }

  function withHolecards(x) {
    return x && !!x.holecards
  }

  function isButton(x) {
    return x && !!x.button
  }

  function getSeatno(x) {
    return x.seatno
  }

  function getStage(street, i) {
    // account for the fact that the first showdown stage already has an action
    if (street !== 'showdown') return street + '+' + (i + 1)
    return i === 0 ? street : street + '+' + i
  }

  function processStreet(street) {
    const actions = script.actions[street]
    const onboard = cardsOnBoard[street] || 0
    const currentBoard = board.slice(0, onboard)
    const preflop = street === 'preflop'
    const showdown = street === 'showdown'

    // collect chips first if we made it to flop, turn, river or showdown
    const collect = !preflop ? collectAction() : []
    // mark folded players so we don't collect their chips again on next street
    addFolded()

    seats = seats.map(resetSeat, { street: street, stage: street })
    const dealerAction = {
      collect: collect
    }
    if (!preflop && !showdown) {
      dealerAction.board = {
          street: street
        , onboard: cardsOnBoard[street]
      }
    }

    if (preflop) {
      const button = seats.filter(isButton).map(getSeatno)[0]
      dealerAction.dealtCards = {
        seatnos: seats.filter(withHolecards).map(getSeatno)
      }
      if (button) {
        dealerAction.button = {
          seatno: button
        }
      }
    }

    // This state is identical to the first action on the street, except the
    // action hasn't executed.
    // Thus it clears up all chips in front of the players and adds cards
    // to the board.
    // Don't create this for the showdown though since nothing changes here
    // until the next player action occurs
    if (street !== 'showdown') {
      states.push({
          board        : currentBoard
        , boardChanged : true
        , pot          : script.pots[street]
        , action       : false
        , stage        : street
        , seats        : seats
        , dealerAction : dealerAction
      })
      streetIdxs[street] = states.length - 1
    } else {
      // showdown points to first action in it
      streetIdxs[street] = states.length
    }

    for (var i = 0; i < actions.length; i++) {
      const action = actions[i]
      const p = script.players[action.playerIndex]
      const a = action.action
      const stage = getStage(street, i)

      seats = seats.map(adaptSeat, { p: p, a: a, stage: stage })
      action.seatno = p.seatno
      states.push({
          board        : currentBoard
        , boardChanged : false
        , pot          : street === 'showdown' ? 0 : a.potAfter
        , action       : action
        , stage        : stage
        , seats        : seats
      })
    }
  }

  processStreet('preflop')
  processStreet('flop')
  processStreet('turn')
  processStreet('river')
  processStreet('showdown')

  return { info: script.info, board: script.board, states: states, streets: streetIdxs }
}
<commit_msg>storyboard: combining showdown collect chips with collect money<commit_after>'use strict'

const putMoneyIn = {
    fold    : false
  , check   : false
  , collect : false
  , post    : true
  , call    : true
  , bet     : true
  , raise   : true
}

const cardsOnBoard = {
    preflop  : 0
  , flop     : 3
  , turn     : 4
  , river    : 5
  , showdown : 5
}

/**
 * Takes a script of actions and calculates the states for each.
 * Adds pointers to the state at the beginning of each script.
 *
 * This is useful if you try to jump around in the hand and reset
 * the state of the table.
 *
 * @name hha:storyboard
 * @function
 * @param {Object} script created via @see hha:script
 */
module.exports = function storyboard(script) {
  const states = []

  //
  // initially
  //
  function getVal(acc, k) {
    if (script.board[k]) acc.push(script.board[k])
    return acc
  }

  const board = script.board && Object.keys(script.board).reduce(getVal, []) || []

  // will be sparse if not all players present
  let seats = new Array(script.table.maxseats + 1)
  function addSeat(p, idx) {
    seats[p.seatno] = {
        chips       : p.chipsPreflop
      , name        : p.name
      , m           : p.m
      , sb          : p.sb
      , bb          : p.bb
      , button      : p.button
      , action      : null
      , amount      : 0
      , bet         : 0
      , investedBet : p.bb ? 1 : 0
      , holecards   : p.cards || { card1 : '??', card2 : '??' }
      , playerIdx   : idx
      , seatno      : p.seatno
    }
  }
  script.players.forEach(addSeat)

  //
  // From now on we always map seats even though we reuse the variable
  // in order to avoid affecting previous states
  //

  function resetSeat(s) {
    const street = this.street
    const stage  = this.stage

    const preflop = street === 'preflop'
    const chipsName = 'chips' + street[0].toUpperCase() + street.slice(1)
    const p = script.players[s.playerIdx]
    const chips = p[chipsName]
    return Object.assign({}, seats[p.seatno], {
        chips       : chips
      , action      : null
      , amount      : 0
      , bet         : 0
      , investedBet : preflop && p.bb ? 1 : 0
      , _lastUpdate : stage
    })
  }

  function adaptSeat(s, idx) {
    const p = this.p
    const a = this.a
    const stage = this.stage
    if (typeof s === 'undefined' || p.seatno !== idx) return s

    // cards are not at player's seat anymore after he folded
    const folded = a.type === 'fold'
    const holecards = folded ? null : s.holecards
    const investedBet = putMoneyIn[a.type] ? a.bet : s.investedBet
    return Object.assign({}, s, {
        chips       : a.chipsAfter
      , action      : a.type
      , amount      : a.amount
      , bet         : a.bet || 0
      , investedBet : investedBet || 0
      , holecards   : holecards
      , folded      : folded
      , _lastUpdate : stage
    })
  }

  let streetIdxs = {
      preflop  : null
    , flop     : null
    , turn     : null
    , river    : null
    , showdown : null
  }

  const folded = {}

  function addFolded() {
    for (var i = 0; i < seats.length; i++) {
      const s = seats[i]
      if (s && s.folded) folded[s.seatno] = true
    }
  }

  function collectAction(street) {
    const flop = street === 'flop'
    function tocollect(acc, s) {
      if (folded[s.seatno]) return acc

      // small blinds posted and their bet size is 0 (half a blind)
      // however if they invested more we'll use that amount
      if (s.sb && flop) {
        acc.push({ seatno: s.seatno, bet: s.investedBet || 0 })

      // big blinds need to have their big blind collected at least
      } else if (s.bb) {
        acc.push({ seatno: s.seatno, bet: Math.max(1, (s.investedBet || 0)) })

      // all others have no chips in front of them if they didn't invest
      } else if (s.investedBet) {
        acc.push({ seatno: s.seatno, bet: s.investedBet })
      }
      return acc
    }

    return seats.reduce(tocollect, [])
  }

  function withHolecards(x) {
    return x && !!x.holecards
  }

  function isButton(x) {
    return x && !!x.button
  }

  function getSeatno(x) {
    return x.seatno
  }

  function getStage(street, i) {
    // account for the fact that the first showdown stage already has an action
    if (street !== 'showdown') return street + '+' + (i + 1)
    return i === 0 ? street : street + '+' + i
  }

  function processStreet(street) {
    const actions = script.actions[street]
    const onboard = cardsOnBoard[street] || 0
    const currentBoard = board.slice(0, onboard)
    const preflop = street === 'preflop'
    const showdown = street === 'showdown'

    // collect chips first if we made it to flop, turn, river or showdown
    const collect = !preflop ? collectAction() : []
    // mark folded players so we don't collect their chips again on next street
    addFolded()

    seats = seats.map(resetSeat, { street: street, stage: street })
    const dealerAction = {
      collect: collect
    }
    if (!preflop && !showdown) {
      dealerAction.board = {
          street: street
        , onboard: cardsOnBoard[street]
      }
    }

    if (preflop) {
      const button = seats.filter(isButton).map(getSeatno)[0]
      dealerAction.dealtCards = {
        seatnos: seats.filter(withHolecards).map(getSeatno)
      }
      if (button) {
        dealerAction.button = {
          seatno: button
        }
      }
    }

    // This state is identical to the first action on the street, except the
    // action hasn't executed.
    // Thus it clears up all chips in front of the players and adds cards
    // to the board.
    // Don't create this for the showdown though since nothing visibly changes here
    // until the next player action occurs.
    if (street !== 'showdown') {
      states.push({
          board        : currentBoard
        , boardChanged : true
        , pot          : script.pots[street]
        , action       : false
        , stage        : street
        , seats        : seats
        , dealerAction : dealerAction
      })
      streetIdxs[street] = states.length - 1
    } else {
      // showdown points to first action in it
      streetIdxs[street] = states.length
    }

    for (var i = 0; i < actions.length; i++) {
      const action = actions[i]
      const p = script.players[action.playerIndex]
      const a = action.action
      const stage = getStage(street, i)

      seats = seats.map(adaptSeat, { p: p, a: a, stage: stage })
      action.seatno = p.seatno
      const state = {
          board        : currentBoard
        , boardChanged : false
        , pot          : street === 'showdown' ? 0 : a.potAfter
        , action       : action
        , stage        : stage
        , seats        : seats
      }
      // for showdown we combine the dealer action with whatever
      // else is going on, i.e. winner collecting money
      if (street === 'showdown') {
        state.dealerAction = dealerAction
      }
      states.push(state)
    }
  }

  processStreet('preflop')
  processStreet('flop')
  processStreet('turn')
  processStreet('river')
  processStreet('showdown')

  return { info: script.info, board: script.board, states: states, streets: streetIdxs }
}
<|endoftext|>


<commit_before>var util = require("util");
var fs = require("fs");
var spawn = require("child_process").spawn;
var path = require("path");
var fileExtensionPattern;
var startChildProcess;
var noRestartOn = null;
var debug = true;
var verbose = false;
var ignoredPaths = {};
var forceWatchFlag = false;
var changedFileArg = false;
var filesChanged = [];

exports.run = run;

function run (args) {
  var arg, next, watch, ignore, program, extensions, executor, poll_interval, debugFlag, debugBrkFlag, debugBrkFlagArg;
  while (arg = args.shift()) {
    if (arg === "--help" || arg === "-h" || arg === "-?") {
      return help();
    } else if (arg === "--quiet" || arg === "-q") {
      debug = false;
      util.debug = function(){};
      util.puts = function(){};
    } else if (arg === "--verbose" || arg === "-V") {
      verbose = true;
    } else if (arg === "--watch" || arg === "-w") {
      watch = args.shift();
    } else if (arg === "--ignore" || arg === "-i") {
      ignore = args.shift();
    } else if (arg === "--poll-interval" || arg === "-p") {
      poll_interval = parseInt(args.shift());
    } else if (arg === "--extensions" || arg === "-e") {
      extensions = args.shift();
    } else if (arg === "--exec" || arg === "-x") {
      executor = args.shift();
    } else if (arg === "--no-restart-on" || arg === "-n") {
      noRestartOn = args.shift();
    } else if (arg === "--debug") {
      debugFlag = true;
    } else if (arg.indexOf('--debug-brk')>=0) {
      debugBrkFlag = true;
      debugBrkFlagArg = arg;
    } else if (arg === "--force-watch") {
      forceWatchFlag = true;
    } else if (arg === "--changed-file-arg") {
      changedFileArg = args.shift();
    } else if (arg === "--") {
      program = args;
      break;
    } else if (arg.indexOf("-") && !args.length) {
      // Assume last arg is the program
      program = [arg];
    }
  }
  if (!program) {
    return help();
  }
  if (!watch) {
    watch = ".";
  }
  if (!poll_interval) {
    poll_interval = 1000;
  }

  var programExt = program.join(" ").match(/.*\.(\S*)/);
  programExt = programExt && programExt[1];

  if (!extensions) {
    // If no extensions passed try to guess from the program
    extensions = "node|js";
    if (programExt && extensions.indexOf(programExt) == -1) {
      // Support coffee and litcoffee extensions
      if(programExt === "coffee" || programExt === "litcoffee") {
        extensions += "|coffee|litcoffee";
      } else {
        extensions += "|" + programExt;
      }
    }
  }
  extensions = extensions.replace(/,/g, "|");
  fileExtensionPattern = new RegExp("^.*\.(" + extensions + ")$");

  if (!executor) {
    executor = (programExt === "coffee" || programExt === "litcoffee") ? "coffee" : "node";
  }

  if (debugFlag) {
    program.unshift("--debug");
  }
  if (debugBrkFlag) {
    program.unshift(debugBrkFlagArg);
  }

  if (executor === "coffee" && (debugFlag || debugBrkFlag)) {
    // coffee does not understand debug or debug-brk, make coffee pass options to node
    program.unshift("--nodejs")
  }

  try {
    // Pass kill signals through to child
    [ "SIGTERM", "SIGINT", "SIGHUP", "SIGQUIT" ].forEach( function(signal) {
      process.on(signal, function () {
        var child = exports.child;
        if (child) {
          util.debug("Sending "+signal+" to child...");
          child.kill(signal);
        }
        process.exit();
      });
    });
  } catch(e) {
    // Windows doesn't support signals yet, so they simply don't get this handling.
    // https://github.com/joyent/node/issues/1553
  }

  util.puts("")
  util.debug("Running node-supervisor (modified) with");
  util.debug("  program '" + program.join(" ") + "'");
  util.debug("  --watch '" + watch + "'");
  util.debug("  --ignore '" + ignore + "'");
  util.debug("  --extensions '" + extensions + "'");
  util.debug("  --exec '" + executor + "'");
  util.puts("");

  // store the call to startProgramm in startChildProcess
  // in order to call it later
  startChildProcess = function() { startProgram(program, executor); };

  // if we have a program, then run it, and restart when it crashes.
  // if we have a watch folder, then watch the folder for changes and restart the prog
  startChildProcess();

  if (ignore) {
    var ignoreItems = ignore.split(',');
    ignoreItems.forEach(function (ignoreItem) {
      ignoreItem = path.resolve(ignoreItem);
      ignoredPaths[ignoreItem] = true;
      util.debug("Ignoring directory '" + ignoreItem + "'.");
    });
  }

  var watchItems = watch.split(',');
  watchItems.forEach(function (watchItem) {
    watchItem = path.resolve(watchItem);
    util.debug("Watching directory '" + watchItem + "' for changes.");
    findAllWatchFiles(watchItem, function(f) {
      watchGivenFile( f, poll_interval );
    });
  });
};

function print (m, n) { util.print(m+(!n?"\n":"")); return print; }

function help () {
  print
    ("")
    ("Node Supervisor is used to restart programs when they crash.")
    ("It can also be used to restart programs when a *.js file changes.")
    ("")
    ("Usage:")
    ("  supervisor [options] <program>")
    ("  supervisor [options] -- <program> [args ...]")
    ("")
    ("Required:")
    ("  <program>")
    ("    The program to run.")
    ("")
    ("Options:")
    ("  -w|--watch <watchItems>")
    ("    A comma-delimited list of folders or js files to watch for changes.")
    ("    When a change to a js file occurs, reload the program")
    ("    Default is '.'")
    ("")
    ("  -i|--ignore <ignoreItems>")
    ("    A comma-delimited list of folders to ignore for changes.")
    ("    No default")
    ("")
    ("  -p|--poll-interval <milliseconds>")
    ("    How often to poll watched files for changes.")
    ("    Defaults to Node default.")
    ("")
    ("  -e|--extensions <extensions>")
    ("    Specific file extensions to watch in addition to defaults.")
    ("    Used when --watch option includes folders")
    ("    Default is 'node|js'")
    ("")
    ("  -x|--exec <executable>")
    ("    The executable that runs the specified program.")
    ("    Default is 'node'")
    ("")
    ("  --debug")
    ("    Start node with --debug flag.")
    ("")
    ("  --debug-brk[=port]")
    ("    Start node with --debug-brk[=port] flag.")
    ("")
    ("  -n|--no-restart-on error|exit")
    ("    Don't automatically restart the supervised program if it ends.")
    ("    Supervisor will wait for a change in the source files.")
    ("    If \"error\", an exit code of 0 will still restart.")
    ("    If \"exit\", no restart regardless of exit code.")
    ("")
    ("  --force-watch")
    ("    Use fs.watch instead of fs.watchFile.")
    ("    This may be useful if you see a high cpu load on a windows machine.")
    ("")
    ("  --changed-file-arg")
    ("    The name of the parameter that will be passed to the supervised program.")
    ("    The value will be a comma-delimited list of files that changed.")
    ("")
    ("  -h|--help|-?")
    ("    Display these usage instructions.")
    ("")
    ("  -q|--quiet")
    ("    Suppress DEBUG messages")
    ("")
    ("  -V|--verbose")
    ("    Show extra DEBUG messages")
    ("")
    ("Examples:")
    ("  supervisor myapp.js")
    ("  supervisor myapp.coffee")
    ("  supervisor -w scripts -e myext -x myrunner myapp")
    ("  supervisor -- server.js -h host -p port")
    ("");
};

function startProgram (prog, exec) {

  var progCopy = prog.slice(0);
  if (changedFileArg) {
    progCopy.push(changedFileArg);
    progCopy.push(filesChanged.join(','));
  }

  util.debug("Starting child process with '" + exec + " " + progCopy.join(" ") + "'");
  crash_queued = false;
  var child = exports.child = spawn(exec, progCopy, {stdio: 'inherit'});
  if (child.stdout) {
    // node < 0.8 doesn't understand the 'inherit' option, so pass through manually
    child.stdout.addListener("data", function (chunk) { chunk && util.print(chunk); });
    child.stderr.addListener("data", function (chunk) { chunk && util.debug(chunk); });
  }
  child.addListener("exit", function (code) {
    if (!crash_queued) {
      util.debug("Program " + exec + " " + prog.join(" ") + " exited with code " + code + "\n");
      exports.child = null;
      if (noRestartOn == "exit" || noRestartOn == "error" && code !== 0) return;
    }
    startProgram(prog, exec);
  });

  filesChanged = [];
}

var timer = null, mtime = null; crash_queued = false;
function crash () {

  if (crash_queued) {
    return;
  }

  crash_queued = true;
  var child = exports.child;
  setTimeout(function() {
    if (child) {
      util.debug("crashing child");
      process.kill(child.pid);
    } else {
      util.debug("restarting child");
      startChildProcess();
    }
  }, 50);
}

function crashWin (event, filename) {
  var shouldCrash = true;
  if( event === 'change' ) {
    if (filename) {
      filename = path.resolve(filename);
      Object.keys(ignoredPaths).forEach(function (ignorePath) {
        if ( filename.indexOf(ignorePath + '\\') === 0 || filename === ignorePath) {
          shouldCrash = false;
        }
      });
    }
    if (shouldCrash) {
      if (filename) filesChanged.push(filename);
      crash();
    }
  }
}

function crashOther (oldStat, newStat) {
  // we only care about modification time, not access time.
  if ( newStat.mtime.getTime() !== oldStat.mtime.getTime() )
    crash();
}

var nodeVersion = process.version.split(".");
var isWindowsWithoutWatchFile = process.platform === 'win32' && parseInt(nodeVersion[1]) <= 6;
function watchGivenFile (watch, poll_interval) {
  if (isWindowsWithoutWatchFile || forceWatchFlag)
    fs.watch(watch, { persistent: true, interval: poll_interval }, crashWin);
  else
    fs.watchFile(watch, { persistent: true, interval: poll_interval }, function(oldStat, newStat) {
      filesChanged.push(watch);
      crashOther(oldStat, newStat);
    });
  if (verbose)
    util.debug("watching file '" + watch + "'");
}

var findAllWatchFiles = function(dir, callback) {
  dir = path.resolve(dir);
  if (ignoredPaths[dir])
    return;
  fs.stat(dir, function(err, stats){
    if (err) {
      util.error('Error retrieving stats for file: ' + dir);
    } else {
      if (stats.isDirectory()) {
        if (isWindowsWithoutWatchFile || forceWatchFlag) callback(dir);
        fs.readdir(dir, function(err, fileNames) {
          if(err) {
            util.error('Error reading path: ' + dir);
          }
          else {
            fileNames.forEach(function (fileName) {
              findAllWatchFiles(path.join(dir, fileName), callback);
            });
          }
        });
      } else {
        if ((!isWindowsWithoutWatchFile || !forceWatchFlag) && dir.match(fileExtensionPattern)) {
          callback(dir);
        }
      }
    }
  });
};
<commit_msg>Removed more testing code<commit_after>var util = require("util");
var fs = require("fs");
var spawn = require("child_process").spawn;
var path = require("path");
var fileExtensionPattern;
var startChildProcess;
var noRestartOn = null;
var debug = true;
var verbose = false;
var ignoredPaths = {};
var forceWatchFlag = false;
var changedFileArg = false;
var filesChanged = [];

exports.run = run;

function run (args) {
  var arg, next, watch, ignore, program, extensions, executor, poll_interval, debugFlag, debugBrkFlag, debugBrkFlagArg;
  while (arg = args.shift()) {
    if (arg === "--help" || arg === "-h" || arg === "-?") {
      return help();
    } else if (arg === "--quiet" || arg === "-q") {
      debug = false;
      util.debug = function(){};
      util.puts = function(){};
    } else if (arg === "--verbose" || arg === "-V") {
      verbose = true;
    } else if (arg === "--watch" || arg === "-w") {
      watch = args.shift();
    } else if (arg === "--ignore" || arg === "-i") {
      ignore = args.shift();
    } else if (arg === "--poll-interval" || arg === "-p") {
      poll_interval = parseInt(args.shift());
    } else if (arg === "--extensions" || arg === "-e") {
      extensions = args.shift();
    } else if (arg === "--exec" || arg === "-x") {
      executor = args.shift();
    } else if (arg === "--no-restart-on" || arg === "-n") {
      noRestartOn = args.shift();
    } else if (arg === "--debug") {
      debugFlag = true;
    } else if (arg.indexOf('--debug-brk')>=0) {
      debugBrkFlag = true;
      debugBrkFlagArg = arg;
    } else if (arg === "--force-watch") {
      forceWatchFlag = true;
    } else if (arg === "--changed-file-arg") {
      changedFileArg = args.shift();
    } else if (arg === "--") {
      program = args;
      break;
    } else if (arg.indexOf("-") && !args.length) {
      // Assume last arg is the program
      program = [arg];
    }
  }
  if (!program) {
    return help();
  }
  if (!watch) {
    watch = ".";
  }
  if (!poll_interval) {
    poll_interval = 1000;
  }

  var programExt = program.join(" ").match(/.*\.(\S*)/);
  programExt = programExt && programExt[1];

  if (!extensions) {
    // If no extensions passed try to guess from the program
    extensions = "node|js";
    if (programExt && extensions.indexOf(programExt) == -1) {
      // Support coffee and litcoffee extensions
      if(programExt === "coffee" || programExt === "litcoffee") {
        extensions += "|coffee|litcoffee";
      } else {
        extensions += "|" + programExt;
      }
    }
  }
  extensions = extensions.replace(/,/g, "|");
  fileExtensionPattern = new RegExp("^.*\.(" + extensions + ")$");

  if (!executor) {
    executor = (programExt === "coffee" || programExt === "litcoffee") ? "coffee" : "node";
  }

  if (debugFlag) {
    program.unshift("--debug");
  }
  if (debugBrkFlag) {
    program.unshift(debugBrkFlagArg);
  }

  if (executor === "coffee" && (debugFlag || debugBrkFlag)) {
    // coffee does not understand debug or debug-brk, make coffee pass options to node
    program.unshift("--nodejs")
  }

  try {
    // Pass kill signals through to child
    [ "SIGTERM", "SIGINT", "SIGHUP", "SIGQUIT" ].forEach( function(signal) {
      process.on(signal, function () {
        var child = exports.child;
        if (child) {
          util.debug("Sending "+signal+" to child...");
          child.kill(signal);
        }
        process.exit();
      });
    });
  } catch(e) {
    // Windows doesn't support signals yet, so they simply don't get this handling.
    // https://github.com/joyent/node/issues/1553
  }

  util.puts("")
  util.debug("Running node-supervisor with");
  util.debug("  program '" + program.join(" ") + "'");
  util.debug("  --watch '" + watch + "'");
  util.debug("  --ignore '" + ignore + "'");
  util.debug("  --extensions '" + extensions + "'");
  util.debug("  --exec '" + executor + "'");
  util.puts("");

  // store the call to startProgramm in startChildProcess
  // in order to call it later
  startChildProcess = function() { startProgram(program, executor); };

  // if we have a program, then run it, and restart when it crashes.
  // if we have a watch folder, then watch the folder for changes and restart the prog
  startChildProcess();

  if (ignore) {
    var ignoreItems = ignore.split(',');
    ignoreItems.forEach(function (ignoreItem) {
      ignoreItem = path.resolve(ignoreItem);
      ignoredPaths[ignoreItem] = true;
      util.debug("Ignoring directory '" + ignoreItem + "'.");
    });
  }

  var watchItems = watch.split(',');
  watchItems.forEach(function (watchItem) {
    watchItem = path.resolve(watchItem);
    util.debug("Watching directory '" + watchItem + "' for changes.");
    findAllWatchFiles(watchItem, function(f) {
      watchGivenFile( f, poll_interval );
    });
  });
};

function print (m, n) { util.print(m+(!n?"\n":"")); return print; }

function help () {
  print
    ("")
    ("Node Supervisor is used to restart programs when they crash.")
    ("It can also be used to restart programs when a *.js file changes.")
    ("")
    ("Usage:")
    ("  supervisor [options] <program>")
    ("  supervisor [options] -- <program> [args ...]")
    ("")
    ("Required:")
    ("  <program>")
    ("    The program to run.")
    ("")
    ("Options:")
    ("  -w|--watch <watchItems>")
    ("    A comma-delimited list of folders or js files to watch for changes.")
    ("    When a change to a js file occurs, reload the program")
    ("    Default is '.'")
    ("")
    ("  -i|--ignore <ignoreItems>")
    ("    A comma-delimited list of folders to ignore for changes.")
    ("    No default")
    ("")
    ("  -p|--poll-interval <milliseconds>")
    ("    How often to poll watched files for changes.")
    ("    Defaults to Node default.")
    ("")
    ("  -e|--extensions <extensions>")
    ("    Specific file extensions to watch in addition to defaults.")
    ("    Used when --watch option includes folders")
    ("    Default is 'node|js'")
    ("")
    ("  -x|--exec <executable>")
    ("    The executable that runs the specified program.")
    ("    Default is 'node'")
    ("")
    ("  --debug")
    ("    Start node with --debug flag.")
    ("")
    ("  --debug-brk[=port]")
    ("    Start node with --debug-brk[=port] flag.")
    ("")
    ("  -n|--no-restart-on error|exit")
    ("    Don't automatically restart the supervised program if it ends.")
    ("    Supervisor will wait for a change in the source files.")
    ("    If \"error\", an exit code of 0 will still restart.")
    ("    If \"exit\", no restart regardless of exit code.")
    ("")
    ("  --force-watch")
    ("    Use fs.watch instead of fs.watchFile.")
    ("    This may be useful if you see a high cpu load on a windows machine.")
    ("")
    ("  --changed-file-arg")
    ("    The name of the parameter that will be passed to the supervised program.")
    ("    The value will be a comma-delimited list of files that changed.")
    ("")
    ("  -h|--help|-?")
    ("    Display these usage instructions.")
    ("")
    ("  -q|--quiet")
    ("    Suppress DEBUG messages")
    ("")
    ("  -V|--verbose")
    ("    Show extra DEBUG messages")
    ("")
    ("Examples:")
    ("  supervisor myapp.js")
    ("  supervisor myapp.coffee")
    ("  supervisor -w scripts -e myext -x myrunner myapp")
    ("  supervisor -- server.js -h host -p port")
    ("");
};

function startProgram (prog, exec) {

  var progCopy = prog.slice(0);
  if (changedFileArg) {
    progCopy.push(changedFileArg);
    progCopy.push(filesChanged.join(','));
  }

  util.debug("Starting child process with '" + exec + " " + progCopy.join(" ") + "'");
  crash_queued = false;
  var child = exports.child = spawn(exec, progCopy, {stdio: 'inherit'});
  if (child.stdout) {
    // node < 0.8 doesn't understand the 'inherit' option, so pass through manually
    child.stdout.addListener("data", function (chunk) { chunk && util.print(chunk); });
    child.stderr.addListener("data", function (chunk) { chunk && util.debug(chunk); });
  }
  child.addListener("exit", function (code) {
    if (!crash_queued) {
      util.debug("Program " + exec + " " + prog.join(" ") + " exited with code " + code + "\n");
      exports.child = null;
      if (noRestartOn == "exit" || noRestartOn == "error" && code !== 0) return;
    }
    startProgram(prog, exec);
  });

  filesChanged = [];
}

var timer = null, mtime = null; crash_queued = false;
function crash () {

  if (crash_queued) {
    return;
  }

  crash_queued = true;
  var child = exports.child;
  setTimeout(function() {
    if (child) {
      util.debug("crashing child");
      process.kill(child.pid);
    } else {
      util.debug("restarting child");
      startChildProcess();
    }
  }, 50);
}

function crashWin (event, filename) {
  var shouldCrash = true;
  if( event === 'change' ) {
    if (filename) {
      filename = path.resolve(filename);
      Object.keys(ignoredPaths).forEach(function (ignorePath) {
        if ( filename.indexOf(ignorePath + '\\') === 0 || filename === ignorePath) {
          shouldCrash = false;
        }
      });
    }
    if (shouldCrash) {
      if (filename) filesChanged.push(filename);
      crash();
    }
  }
}

function crashOther (oldStat, newStat) {
  // we only care about modification time, not access time.
  if ( newStat.mtime.getTime() !== oldStat.mtime.getTime() )
    crash();
}

var nodeVersion = process.version.split(".");
var isWindowsWithoutWatchFile = process.platform === 'win32' && parseInt(nodeVersion[1]) <= 6;
function watchGivenFile (watch, poll_interval) {
  if (isWindowsWithoutWatchFile || forceWatchFlag)
    fs.watch(watch, { persistent: true, interval: poll_interval }, crashWin);
  else
    fs.watchFile(watch, { persistent: true, interval: poll_interval }, function(oldStat, newStat) {
      filesChanged.push(watch);
      crashOther(oldStat, newStat);
    });
  if (verbose)
    util.debug("watching file '" + watch + "'");
}

var findAllWatchFiles = function(dir, callback) {
  dir = path.resolve(dir);
  if (ignoredPaths[dir])
    return;
  fs.stat(dir, function(err, stats){
    if (err) {
      util.error('Error retrieving stats for file: ' + dir);
    } else {
      if (stats.isDirectory()) {
        if (isWindowsWithoutWatchFile || forceWatchFlag) callback(dir);
        fs.readdir(dir, function(err, fileNames) {
          if(err) {
            util.error('Error reading path: ' + dir);
          }
          else {
            fileNames.forEach(function (fileName) {
              findAllWatchFiles(path.join(dir, fileName), callback);
            });
          }
        });
      } else {
        if ((!isWindowsWithoutWatchFile || !forceWatchFlag) && dir.match(fileExtensionPattern)) {
          callback(dir);
        }
      }
    }
  });
};
<|endoftext|>


<commit_before>function setup() {
  createCanvas(windowWidth, windowHeight);
  smooth();
  frameRate(13);
}

function draw() {
  if (mouseIsPressed || touchIsDown) {
  	background(237,34,93);
    fill(255,255,255);
    stroke(35,79,163);
    strokeWeight(3);
      	var dist = 90;
    for (var i = 25; i < width; i+=dist) {
      for (var j = 25; j < height; j+=dist) {
        rectMode(CENTER);
        ellipse(i, j, random(40), random(25));
      }
    }
    fill(35,79,163);
    for (var i = 25; i < width; i+=dist) {
      for (var j = 25; j < height; j+=dist) {
        rectMode(CENTER);
        ellipse(i, j, random(1), random(20));
      }
    }
 } else {
 	background(31,247,183);
    fill(225, 255, 255);
    stroke(35,79,163);
    strokeWeight(1.5);
    var dist = 128;
    for (var i = 30; i < width; i+=dist)
    {
      for (var j = 30; j < height; j+=dist)
      {
        rectMode(CENTER);
        ellipse(i, j, 80, 40);
      }
    }
    fill(35,79,163);
    for (var i = 30; i < width; i+=dist)
    {
      for (var j = 30; j < height; j+=dist)
      {
        var x1 = map(mouseX || touchX, 0, width, i-11.5, 11.5+i);
        var y1 = map(mouseY || touchY, 0, height, j-3.2, j+3);
        ellipse(x1, y1, 30, 30);
      }
    }
  }
}<commit_msg>edit sketch<commit_after>function setup() {
  createCanvas(windowWidth, windowHeight);
  smooth();
  frameRate(13);
}

function draw() {
  if (mouseIsPressed || touchIsDown) {
  	background(237,34,93);
    fill(255,255,255);
    stroke(35,79,163);
    strokeWeight(3);
      	var dist = 90;
    for (var i = 25; i < width; i+=dist) {
      for (var j = 25; j < height; j+=dist) {
        rectMode(CENTER);
        ellipse(i, j, random(40), random(25));
      }
    }
    fill(35,79,163);
    for (var i = 25; i < width; i+=dist) {
      for (var j = 25; j < height; j+=dist) {
        rectMode(CENTER);
        ellipse(i, j, random(1), random(20));
      }
    }
 } else {
 	background(31,247,183);
    fill(225, 255, 255);
    stroke(35,79,163);
    strokeWeight(1.5);
    var dist = 90;
    for (var i = 25; i < width; i+=dist)
    {
      for (var j = 25; j < height; j+=dist)
      {
        rectMode(CENTER);
        ellipse(i, j, 40, 22);
      }
    }
    fill(35,79,163);
    for (var i = 25; i < width; i+=dist)
    {
      for (var j = 25; j < height; j+=dist)
      {
        var x1 = map(mouseX || touchX, 0, width, i-11.5, 11.5+i);
        var y1 = map(mouseY || touchY, 0, height, j-3.2, j+3);
        ellipse(x1, y1, 14, 14);
      }
    }
  }
}<|endoftext|>