<commit_before>(function(define) {'use strict';
define(function(require) {

   var utils, log1p;

   log1p = require('./basicFunc/log1p').log1p;

   utils = {
      /* mixin */
      mixin: function mixin(target) {
         Array.prototype.slice.call(arguments, 1)
            .forEach(function(source) {
               Object.keys(source).forEach(function(key) {
                  target[key] = source[key];
               });
            });
         return target;
      },
      /* Maximum number of steps for `repeat` iterations. */
      maxSteps: 10000,
      /* repeat, for carrying out repeated improvement until stopping
       * condition is satisfied, or until `utils.maxSteps` have been
       * performed.
       *
       * `init` is the initial value,
       * `step` is a function which returns the new value, and
       * `stop` is a non-negative integer (number of steps to take),
       *  a function of no arguments returning a boolean, or missing.
       *  If `stop` is omitted, the default behavior is using
       * `utils.relativelyCloseTo`.
       *  Iteration will stop after `utils.maxSteps`, regardless.
       */
      repeat: function(init, step, stop) {
         var prev, curr, done, reps;
         curr = init;
         reps = utils.maxSteps;
         if (stop === 0) { return curr; }
         done = typeof stop === 'function' ? stop :
                stop > 0 ? function() { stop -= 1; return stop === 0; } :
                        function() { return utils.relativelyCloseTo(curr, prev, 1e-13); };
         while (reps > 0 && !done() && !isNaN(curr)) {
            reps -= 1;
            prev = curr;
            curr = step();
         }
         if (isNaN(curr)) { console.log('repeat returned NaN'); }
         if (reps === 0) {
            console.log('repeat terminated after too many repetitions');
         }
         return curr;
      },
      /* series
       * - `f` is a function two arguments, `index` and `prev` (previous
       *     value).  It will be called starting at `index` 0.
       * - `stop` is the same as in `repeat`.
       * Add up the terms generated by `f` for index >= 0; stopping conditions
       * are the same as for `repeat`.
       */
      series: function(f, stop) {
         var sum, curr, i;
         i = 0;
         curr = f(0);
         sum = curr;
         return utils.repeat(sum, function() {
            i += 1;
            curr = f(i, curr);
            sum += curr;
            return sum;
         }, stop);
      },
      /* precision used by relativelyCloseTo */
      precision: 1e-10,
      /* relativelyCloseTo returns a boolean indicating whether x, x0 are
       * relatively close to each other as specified by the precision `delta`.
       * If `delta` is not provided, `utils.precision` is used instead.
       *
       * Special cases for NaN, Infinity, -Infinity
       */
      relativelyCloseTo: function(x, x0, delta) {
         delta = delta || utils.precision;
         var absMax = Math.max(Math.abs(x0), Math.abs(x));
         if (isNaN(absMax)) { return isNaN(x) && isNaN(x0); } /* both NaN */
         if (absMax === Infinity) { return x0 === x; }
         if (absMax === 0) { return true; }
         return Math.abs(x - x0) / absMax < delta;
      },
      /* precision used by relativelyCloseTo */
      /* isEssentiallyZero returns a boolean indicating whether x is very
       * close to zero (less than e-100 in absolute value).
       */
      isEssentiallyZero: function(x) {
         return Math.abs(x) < 1e-100;
      },
      /* contFrac
       * A continued fraction has the form
       * a0 + (b1 / (a1 + (b2 / (a2 + ...)))
       * where a is indexed from 0 and b is indexed from 1.    *
       * - `a` and `b` are functions with parameters `i` and `v` for generating
       * the ai and bi sequences; each time, the function returns the ith term
       * of the sequence based on the previous value, `v`.
       * - `stop` is the same as in `repeat`.
       *
       * Return a value for the indicated continued fraction, to a precision
       * as determined by `stop`.
       */
      contFrac: function(a, b, stop) {
         var A, A1, A2; // A2 is "two previous" to A, A1 is "one previous"
         var B, B1, B2, an, bn, i;
         an = a(0);
         A = an;
         A1 = 1;
         bn = 1;
         B = bn;
         B1 = 0;
         i = 0;
         return utils.repeat(A / B, function() {
            A2 = A1;
            A1 = A;
            B2 = B1;
            B1 = B;
            i += 1;
            an = a(i, an);
            bn = b(i, bn);
            A = A1 * an + A2 * bn;
            B = B1 * an + B2 * bn;
            return A / B;
         }, stop);
      },
      /*
       * If lx = log(x), ly = log(y), calculates log(x + y)
       */
      logspaceAdd: function(lx, ly) {
         return Math.max(lx, ly) + log1p(Math.exp(-Math.abs(lx - ly)));
      }
   };

   return utils;

});

}(typeof define === 'function' && define.amd ? define : function(factory) {
   'use strict';
   module.exports = factory(require);
}));
<commit_msg>Move contfrac closer to series<commit_after>(function(define) {'use strict';
define(function(require) {

   var utils, log1p;

   log1p = require('./basicFunc/log1p').log1p;

   utils = {
      /* mixin */
      mixin: function mixin(target) {
         Array.prototype.slice.call(arguments, 1)
            .forEach(function(source) {
               Object.keys(source).forEach(function(key) {
                  target[key] = source[key];
               });
            });
         return target;
      },
      /* Maximum number of steps for `repeat` iterations. */
      maxSteps: 10000,
      /* repeat, for carrying out repeated improvement until stopping
       * condition is satisfied, or until `utils.maxSteps` have been
       * performed.
       *
       * `init` is the initial value,
       * `step` is a function which returns the new value, and
       * `stop` is a non-negative integer (number of steps to take),
       *  a function of no arguments returning a boolean, or missing.
       *  If `stop` is omitted, the default behavior is using
       * `utils.relativelyCloseTo`.
       *  Iteration will stop after `utils.maxSteps`, regardless.
       */
      repeat: function(init, step, stop) {
         var prev, curr, done, reps;
         curr = init;
         reps = utils.maxSteps;
         if (stop === 0) { return curr; }
         done = typeof stop === 'function' ? stop :
                stop > 0 ? function() { stop -= 1; return stop === 0; } :
                        function() { return utils.relativelyCloseTo(curr, prev, 1e-13); };
         while (reps > 0 && !done() && !isNaN(curr)) {
            reps -= 1;
            prev = curr;
            curr = step();
         }
         if (isNaN(curr)) { console.log('repeat returned NaN'); }
         if (reps === 0) {
            console.log('repeat terminated after too many repetitions');
         }
         return curr;
      },
      /* series
       * - `f` is a function two arguments, `index` and `prev` (previous
       *     value).  It will be called starting at `index` 0.
       * - `stop` is the same as in `repeat`.
       * Add up the terms generated by `f` for index >= 0; stopping conditions
       * are the same as for `repeat`.
       */
      series: function(f, stop) {
         var sum, curr, i;
         i = 0;
         curr = f(0);
         sum = curr;
         return utils.repeat(sum, function() {
            i += 1;
            curr = f(i, curr);
            sum += curr;
            return sum;
         }, stop);
      },
      /* contFrac
       * A continued fraction has the form
       * a0 + (b1 / (a1 + (b2 / (a2 + ...)))
       * where a is indexed from 0 and b is indexed from 1.    *
       * - `a` and `b` are functions with parameters `i` and `v` for generating
       * the ai and bi sequences; each time, the function returns the ith term
       * of the sequence based on the previous value, `v`.
       * - `stop` is the same as in `repeat`.
       *
       * Return a value for the indicated continued fraction, to a precision
       * as determined by `stop`.
       */
      contFrac: function(a, b, stop) {
         var A, A1, A2; // A2 is "two previous" to A, A1 is "one previous"
         var B, B1, B2, an, bn, i;
         an = a(0);
         A = an;
         A1 = 1;
         bn = 1;
         B = bn;
         B1 = 0;
         i = 0;
         return utils.repeat(A / B, function() {
            A2 = A1;
            A1 = A;
            B2 = B1;
            B1 = B;
            i += 1;
            an = a(i, an);
            bn = b(i, bn);
            A = A1 * an + A2 * bn;
            B = B1 * an + B2 * bn;
            return A / B;
         }, stop);
      },
      /* precision used by relativelyCloseTo */
      precision: 1e-10,
      /* relativelyCloseTo returns a boolean indicating whether x, x0 are
       * relatively close to each other as specified by the precision `delta`.
       * If `delta` is not provided, `utils.precision` is used instead.
       *
       * Special cases for NaN, Infinity, -Infinity
       */
      relativelyCloseTo: function(x, x0, delta) {
         delta = delta || utils.precision;
         var absMax = Math.max(Math.abs(x0), Math.abs(x));
         if (isNaN(absMax)) { return isNaN(x) && isNaN(x0); } /* both NaN */
         if (absMax === Infinity) { return x0 === x; }
         if (absMax === 0) { return true; }
         return Math.abs(x - x0) / absMax < delta;
      },
      /* precision used by relativelyCloseTo */
      /* isEssentiallyZero returns a boolean indicating whether x is very
       * close to zero (less than e-100 in absolute value).
       */
      isEssentiallyZero: function(x) {
         return Math.abs(x) < 1e-100;
      },
      /*
       * If lx = log(x), ly = log(y), calculates log(x + y)
       */
      logspaceAdd: function(lx, ly) {
         return Math.max(lx, ly) + log1p(Math.exp(-Math.abs(lx - ly)));
      }
   };

   return utils;

});

}(typeof define === 'function' && define.amd ? define : function(factory) {
   'use strict';
   module.exports = factory(require);
}));
<|endoftext|>


<commit_before>import fs from 'fs'

export default function(configFile) {
  if (!fs.existsSync(configFile)) {
    throw new Error(`Specified Tailwind config file "${configFile}" doesn't exist.`)
  }

  return function(css, opts) {
    opts.messages = [
      {
        type: 'dependency',
        file: configFile,
        parent: css.source.input.file,
      },
    ]
  }
}
<commit_msg>Push config file dependency message instead of replacing messages array<commit_after>import fs from 'fs'

export default function(configFile) {
  if (!fs.existsSync(configFile)) {
    throw new Error(`Specified Tailwind config file "${configFile}" doesn't exist.`)
  }

  return function(css, opts) {
    opts.messages.push({
      type: 'dependency',
      file: configFile,
      parent: css.source.input.file,
    })
  }
}
<|endoftext|>


<commit_before>import * as React from 'react';

const HEADERS = ['no.', 'text', 'log'];

export const BuilderDataTable = props => {
  return (

        <BuilderRow
            header={true}
            data={HEADERS}
        />

        <BuilderRow data={} />

  );
}<commit_msg>Flip attribute order in BuilderRow instance<commit_after>import * as React from 'react';

const HEADERS = ['no.', 'text', 'log'];

export const BuilderDataTable = props => {
  return (

        <BuilderRow
            data={HEADERS}
            header
        />

        <BuilderRow data={} />

  );
}<|endoftext|>


<commit_before>/* @flow */

import { config, cache } from '../../core-client';
import Contacts from '../../ui/modules/Contacts';

const {
	protocol,
	host
} = config.server;
const endpoint = `${protocol}//${host}/m/contacts`;

export default function uploadContacts() {
	const session = cache.getState('session');

	if (session) {
		Contacts.sendContacts(endpoint, {
			auth: {
				session
			}
		});
	}
}
<commit_msg>Fix contacts endpoint<commit_after>/* @flow */

import { config, cache } from '../../core-client';
import Contacts from '../../ui/modules/Contacts';

const {
	protocol,
	host
} = config.server;
const endpoint = `${protocol}//${host}/x/contacts`;

export default function uploadContacts() {
	const session = cache.getState('session');

	if (session) {
		Contacts.sendContacts(endpoint, {
			auth: {
				session
			}
		});
	}
}
<|endoftext|>


<commit_before>import * as core from '../../core';
import ExtractBrightnessFilter from './ExtractBrightnessFilter';
import BlurXFilter from '../../filters/blur/BlurXFilter';
import BlurYFilter from '../../filters/blur/BlurYFilter';

export default class BloomBrightnessFilter extends core.Filter
{

    constructor(minBright, toneScale, strength, quality, resolution, kernelSize)
    {
        const vertSrc = [
            'attribute vec2 aVertexPosition;',
            'attribute vec2 aTextureCoord;',
            'uniform mat3 projectionMatrix;',
            'varying vec2 vTextureCoord;',

            'void main() {',
            '    gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);',
            '    vTextureCoord = aTextureCoord;',
            '}',
        ].join('\n');

        const fragSrc = [
            'uniform sampler2D uSampler;',
            'varying vec2 vTextureCoord;',

            'uniform sampler2D bloomTexture;',
            'uniform float toneScale;',

            'void main() {',
            '    vec4 color = vec4(0.0);',
            '    color  = texture2D(uSampler, vTextureCoord) * toneScale;',
            '    color += texture2D(bloomTexture, vTextureCoord);',
            '    gl_FragColor = color;',
            '}',
        ].join('\n');

        super(
            // vertex shader
            vertSrc,
            // fragment shader
            fragSrc
        );

        this._quality = 0;

        this.minBright = minBright || 0.2;
        this.toneScale = toneScale || 0.8;

        this.strength = strength || 8;
        this.quality = quality || 4;
        this.resolution = resolution || core.settings.RESOLUTION;
        this.kernelSize = kernelSize || 7;

        this.extractBrightnessFilter = new ExtractBrightnessFilter(this.minBright);
        this.blurXFilter = new BlurXFilter(this.strength, this.quality, this.resolution, this.kernelSize);
        this.blurYFilter = new BlurYFilter(this.strength, this.quality, this.resolution, this.kernelSize);
    }

    apply(filterManager, input, output, clear, currentState)
    {
        const brightTarget = filterManager.getRenderTarget(true);

        this.extractBrightnessFilter.apply(filterManager, input, brightTarget, true, currentState);

        const blurTarget = filterManager.getRenderTarget(true);

        this.blurXFilter.apply(filterManager, brightTarget, blurTarget, true, currentState);
        this.blurYFilter.apply(filterManager, blurTarget, brightTarget, true, currentState);

        this.uniforms.toneScale = this.toneScale;
        this.uniforms.bloomTexture = brightTarget;
        filterManager.applyFilter(this, input, output, clear);

        filterManager.returnRenderTarget(brightTarget);
        filterManager.returnRenderTarget(blurTarget);
    }

}
<commit_msg>remove needless code<commit_after>import * as core from '../../core';
import ExtractBrightnessFilter from './ExtractBrightnessFilter';
import BlurXFilter from '../../filters/blur/BlurXFilter';
import BlurYFilter from '../../filters/blur/BlurYFilter';

export default class BloomBrightnessFilter extends core.Filter
{

    constructor(minBright, toneScale, strength, quality, resolution, kernelSize)
    {
        const vertSrc = [
            'attribute vec2 aVertexPosition;',
            'attribute vec2 aTextureCoord;',
            'uniform mat3 projectionMatrix;',
            'varying vec2 vTextureCoord;',

            'void main() {',
            '    gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);',
            '    vTextureCoord = aTextureCoord;',
            '}',
        ].join('\n');

        const fragSrc = [
            'uniform sampler2D uSampler;',
            'varying vec2 vTextureCoord;',

            'uniform sampler2D bloomTexture;',
            'uniform float toneScale;',

            'void main() {',
            '    vec4 color = vec4(0.0);',
            '    color  = texture2D(uSampler, vTextureCoord) * toneScale;',
            '    color += texture2D(bloomTexture, vTextureCoord);',
            '    gl_FragColor = color;',
            '}',
        ].join('\n');

        super(
            // vertex shader
            vertSrc,
            // fragment shader
            fragSrc
        );

        this.minBright = minBright || 0.2;
        this.toneScale = toneScale || 0.8;

        this.strength = strength || 8;
        this.quality = quality || 4;
        this.resolution = resolution || core.settings.RESOLUTION;
        this.kernelSize = kernelSize || 7;

        this.extractBrightnessFilter = new ExtractBrightnessFilter(this.minBright);
        this.blurXFilter = new BlurXFilter(this.strength, this.quality, this.resolution, this.kernelSize);
        this.blurYFilter = new BlurYFilter(this.strength, this.quality, this.resolution, this.kernelSize);
    }

    apply(filterManager, input, output, clear, currentState)
    {
        const brightTarget = filterManager.getRenderTarget(true);

        this.extractBrightnessFilter.apply(filterManager, input, brightTarget, true, currentState);

        const blurTarget = filterManager.getRenderTarget(true);

        this.blurXFilter.apply(filterManager, brightTarget, blurTarget, true, currentState);
        this.blurYFilter.apply(filterManager, blurTarget, brightTarget, true, currentState);

        this.uniforms.toneScale = this.toneScale;
        this.uniforms.bloomTexture = brightTarget;
        filterManager.applyFilter(this, input, output, clear);

        filterManager.returnRenderTarget(brightTarget);
        filterManager.returnRenderTarget(blurTarget);
    }

}
<|endoftext|>


<commit_before>;(function () {
  // extend swal with a function for adding forms
  swal.withForm = function () {
    // initialize with field values supplied on `swal.withForm` call
    var swalForm = new SwalForm(arguments[0].formFields)
    // prevent successive calls to add duplicated form fields
    swalForm.removeSwalForm()
    // make form values inserted by the user available at `doneFunction`
    swalForm.addWayToGetFormValuesInDoneFunction(arguments)

    // forward arguments
    swal.apply({}, arguments)

    var htmlForm = swalForm.generateHtmlForm()
    swalForm.insertFormInSwalModal(htmlForm)
    swalForm.allowClickingDirectlyOnInputs()
    swalForm.focusOnFirstInput()
    swalForm.markFirstRadioButtons()
    swalForm.addTabOrder()
  }

  // constructor for helper object
  function SwalForm (formFields) {
    this.formFields = formFields
  }

  // helper methods
  extend(SwalForm.prototype, {
    formClass: 'swal-form',
    generateHtmlForm: function () {
      var form = {
        clazz: this.formClass,
        innerHtml: this.formFields.map(toFormTag.bind(this)).reduce(toSingleString)
      }

      return t("
{innerHtml}
", form)

      function toFormTag (field) {
        var input = Input(field)
        // to separate groups of checkboxes and radiobuttons in different lines
        var conditionalLineBreak = (input.isRadioOrCheckbox() && this.lastFieldName !== field.name) ? '
' : ''
        this.lastFieldName = field.name

        return conditionalLineBreak + input.toHtml()
      }
    },
    addWayToGetFormValuesInDoneFunction: function (swalArgs) {
      var swalFormInstance = this
      var doneFunction = swalArgs[1]
      swalArgs[1] = function (isConfirm) {
        // make form values available at `this` variable inside doneFunction
        this.swalForm = swalFormInstance.getFormValues()

        if (doneFunction.apply(this, arguments) !== false) {

          // clean form to not interfere in normals sweet alerts
          document.querySelector('.swal-form').innerHTML = ''
        }
      }
    },
    getFormValues: function () {
      var inputHtmlCollection = document.getElementsByClassName('swal-form-field')
      var inputArray = [].slice.call(inputHtmlCollection)

      return inputArray
        .filter(uncheckedRadiosAndCheckboxes)
        .map(toValuableAttrs)
        .reduce(toSingleObject, {})

      function uncheckedRadiosAndCheckboxes (tag) {
        return (isRadioOrCheckbox(tag) ? tag.checked : true)
      }

      function toValuableAttrs (tag) {
        var attr = {}
        attr[tag.id || tag.name] = tag.value
        return attr
      }

      function toSingleObject (obj1, obj2) {
        return extendPreventingOverrides(obj1, obj2)

        // for checkboxes we want to obtain all selected values in an array
        function extendPreventingOverrides (a, b) {
          Object.keys(b).forEach(addContentFromBtoA)
          return a

          function addContentFromBtoA (key) {
            if (a.hasOwnProperty(key)) {
              mergeIntoAnArray(a, b, key)
            } else {
              a[key] = b[key]
            }
          }
        }

        function mergeIntoAnArray (a, b, key) {
          if (Array.isArray(a[key])) {
            a[key].push(b[key])
          } else {
            a[key] = [a[key], b[key]]
          }
        }
      }
    },
    insertFormInSwalModal: function (htmlFormString) {
      var formTag = stringToTag(htmlFormString)
      var sweetAlertModal = document.querySelector('.sweet-alert')
      var buttonContainerTag = sweetAlertModal.querySelector('.sa-button-container') || sweetAlertModal.querySelector('.cancel')
      // insert form before swal bottom buttons
      sweetAlertModal.insertBefore(formTag, buttonContainerTag)

      function stringToTag (string) {
        var div = document.createElement('div')
        div.innerHTML = string
        return div.firstChild
      }
    },
    removeSwalForm: function () {
      var formTag = document.querySelector('.' + this.formClass)
      formTag && document.querySelector('.sweet-alert').removeChild(formTag)
    },
    allowClickingDirectlyOnInputs: function () {
      // sweet-alert attaches an onblur handler which prevents clicks on of non
      // button elements until click is made on the modal
      document.querySelector('.sweet-alert button.confirm').onblur = function () {}
      document.querySelector('.sweet-alert button.cancel').onblur = function () {}
    },
    getSelector: function () {
      var firstField = this.formFields[0]
      return (firstField.id ? t('#{id}', firstField) : t("[name='{name}']", firstField))
    },
    focusOnFirstInput: function () {
      setTimeout(focus.bind(this))

      function focus () {
        document.querySelector(this.getSelector()).focus()
      }
    },
    markFirstRadioButtons: function () {
      setTimeout(markAsChecked.bind(this))

      function markAsChecked () {
        document.querySelector(this.getSelector()).checked = true
      }
    },
    addTabOrder: function () {
      var formFields = Array.prototype.slice.call(document.querySelectorAll('.swal-form .swal-form-field'))
      formFields.forEach(addToTabNavigation)

      function addToTabNavigation (formField, index) {
        var myInput = formField
        var nextInput = formFields[index + 1]

        var keyHandler = function (e) {
          var TABKEY = 9
          if (e.keyCode === TABKEY) {
            var next = this
            setTimeout(function () { next.focus() })
          }
        }

        if (myInput.addEventListener) {
          myInput.addEventListener('keydown', keyHandler.bind(nextInput), false)
        } else if (myInput.attachEvent) {
          myInput.attachEvent('onkeydown', keyHandler.bind(nextInput)) /* damn IE hack */
        }
      }
    }
  })

  function isRadioOrCheckbox (tag) {
    return tag.type === 'radio' || tag.type === 'checkbox'
  }

  function extend (o1, o2) {
    for (var key in o2) {
      if (o2.hasOwnProperty(key)) {
        o1[key] = o2[key]
      }
    }
    return o1
  }

  function Input (field) {
    var input = {
      id: field.id || '',
      name: field.name || '',
      placeholder: field.placeholder || camelCaseToHuman(field.id),
      value: field.value || '',
      type: field.type || 'text',
      options: field.options || [],
      isRadioOrCheckbox: function () {
        return isRadioOrCheckbox(input)
      },
      toHtml: function () {
        var inputTag
        if (input.type !== 'select') {
          inputTag = t("<input id='{id}' class='{clazz} swal-form-field' type='{type}' name='{name}'" +
            " value='{value}' title='{placeholder}' placeholder='{placeholder}'>", input)
        } else {
          inputTag = t("<select id='{id}' class='{clazz} swal-form-field' name='{name}'" +
            " value='{value}' title='{placeholder}' style='width:100%'>", input) +
              input.options.reduce(toHtmlOptions, '') +
            '</select>'
        }
        var labelTag = t("{label}", input)

        return inputTag + labelTag

        function toHtmlOptions (optionsString, option) {
          return optionsString + t("<option value='{value}'>{text}</option>", option)
        }
      }
    }
    input.label = input.isRadioOrCheckbox() ? input.value : ''
    input.clazz = !input.isRadioOrCheckbox() ? 'nice-input' : 'patch-swal-styles-for-inputs'

    return input

    function camelCaseToHuman (arg) {
      if (arg) {
        return arg
          .replace(/([A-Z])/g, ' $1') // insert a space before all caps
          .replace(/^./, function (str) { return str.toUpperCase() }) // uppercase the first character
      } else {
        return ''
      }
    }
  }

  // string interpolation hack
  function t (template, data) {
    for (var key in data) {
      template = template.replace(new RegExp('{' + key + '}', 'g'), data[key] || '')
    }
    return template
  }

  function toSingleString (s1, s2) {
    return s1 + s2
  }
})()
<commit_msg>Allow the label of checkbox or radio to be different to the value<commit_after>;(function () {
  // extend swal with a function for adding forms
  swal.withForm = function () {
    // initialize with field values supplied on `swal.withForm` call
    var swalForm = new SwalForm(arguments[0].formFields)
    // prevent successive calls to add duplicated form fields
    swalForm.removeSwalForm()
    // make form values inserted by the user available at `doneFunction`
    swalForm.addWayToGetFormValuesInDoneFunction(arguments)

    // forward arguments
    swal.apply({}, arguments)

    var htmlForm = swalForm.generateHtmlForm()
    swalForm.insertFormInSwalModal(htmlForm)
    swalForm.allowClickingDirectlyOnInputs()
    swalForm.focusOnFirstInput()
    swalForm.markFirstRadioButtons()
    swalForm.addTabOrder()
  }

  // constructor for helper object
  function SwalForm (formFields) {
    this.formFields = formFields
  }

  // helper methods
  extend(SwalForm.prototype, {
    formClass: 'swal-form',
    generateHtmlForm: function () {
      var form = {
        clazz: this.formClass,
        innerHtml: this.formFields.map(toFormTag.bind(this)).reduce(toSingleString)
      }

      return t("
{innerHtml}
", form)

      function toFormTag (field) {
        var input = Input(field)
        // to separate groups of checkboxes and radiobuttons in different lines
        var conditionalLineBreak = (input.isRadioOrCheckbox() && this.lastFieldName !== field.name) ? '
' : ''
        this.lastFieldName = field.name

        return conditionalLineBreak + input.toHtml()
      }
    },
    addWayToGetFormValuesInDoneFunction: function (swalArgs) {
      var swalFormInstance = this
      var doneFunction = swalArgs[1]
      swalArgs[1] = function (isConfirm) {
        // make form values available at `this` variable inside doneFunction
        this.swalForm = swalFormInstance.getFormValues()

        if (doneFunction.apply(this, arguments) !== false) {

          // clean form to not interfere in normals sweet alerts
          document.querySelector('.swal-form').innerHTML = ''
        }
      }
    },
    getFormValues: function () {
      var inputHtmlCollection = document.getElementsByClassName('swal-form-field')
      var inputArray = [].slice.call(inputHtmlCollection)

      return inputArray
        .filter(uncheckedRadiosAndCheckboxes)
        .map(toValuableAttrs)
        .reduce(toSingleObject, {})

      function uncheckedRadiosAndCheckboxes (tag) {
        return (isRadioOrCheckbox(tag) ? tag.checked : true)
      }

      function toValuableAttrs (tag) {
        var attr = {}
        attr[tag.id || tag.name] = tag.value
        return attr
      }

      function toSingleObject (obj1, obj2) {
        return extendPreventingOverrides(obj1, obj2)

        // for checkboxes we want to obtain all selected values in an array
        function extendPreventingOverrides (a, b) {
          Object.keys(b).forEach(addContentFromBtoA)
          return a

          function addContentFromBtoA (key) {
            if (a.hasOwnProperty(key)) {
              mergeIntoAnArray(a, b, key)
            } else {
              a[key] = b[key]
            }
          }
        }

        function mergeIntoAnArray (a, b, key) {
          if (Array.isArray(a[key])) {
            a[key].push(b[key])
          } else {
            a[key] = [a[key], b[key]]
          }
        }
      }
    },
    insertFormInSwalModal: function (htmlFormString) {
      var formTag = stringToTag(htmlFormString)
      var sweetAlertModal = document.querySelector('.sweet-alert')
      var buttonContainerTag = sweetAlertModal.querySelector('.sa-button-container') || sweetAlertModal.querySelector('.cancel')
      // insert form before swal bottom buttons
      sweetAlertModal.insertBefore(formTag, buttonContainerTag)

      function stringToTag (string) {
        var div = document.createElement('div')
        div.innerHTML = string
        return div.firstChild
      }
    },
    removeSwalForm: function () {
      var formTag = document.querySelector('.' + this.formClass)
      formTag && document.querySelector('.sweet-alert').removeChild(formTag)
    },
    allowClickingDirectlyOnInputs: function () {
      // sweet-alert attaches an onblur handler which prevents clicks on of non
      // button elements until click is made on the modal
      document.querySelector('.sweet-alert button.confirm').onblur = function () {}
      document.querySelector('.sweet-alert button.cancel').onblur = function () {}
    },
    getSelector: function () {
      var firstField = this.formFields[0]
      return (firstField.id ? t('#{id}', firstField) : t("[name='{name}']", firstField))
    },
    focusOnFirstInput: function () {
      setTimeout(focus.bind(this))

      function focus () {
        document.querySelector(this.getSelector()).focus()
      }
    },
    markFirstRadioButtons: function () {
      setTimeout(markAsChecked.bind(this))

      function markAsChecked () {
        document.querySelector(this.getSelector()).checked = true
      }
    },
    addTabOrder: function () {
      var formFields = Array.prototype.slice.call(document.querySelectorAll('.swal-form .swal-form-field'))
      formFields.forEach(addToTabNavigation)

      function addToTabNavigation (formField, index) {
        var myInput = formField
        var nextInput = formFields[index + 1]

        var keyHandler = function (e) {
          var TABKEY = 9
          if (e.keyCode === TABKEY) {
            var next = this
            setTimeout(function () { next.focus() })
          }
        }

        if (myInput.addEventListener) {
          myInput.addEventListener('keydown', keyHandler.bind(nextInput), false)
        } else if (myInput.attachEvent) {
          myInput.attachEvent('onkeydown', keyHandler.bind(nextInput)) /* damn IE hack */
        }
      }
    }
  })

  function isRadioOrCheckbox (tag) {
    return tag.type === 'radio' || tag.type === 'checkbox'
  }

  function extend (o1, o2) {
    for (var key in o2) {
      if (o2.hasOwnProperty(key)) {
        o1[key] = o2[key]
      }
    }
    return o1
  }

  function Input (field) {
    var input = {
      id: field.id || '',
      name: field.name || '',
      placeholder: field.placeholder || camelCaseToHuman(field.id),
      value: field.value || '',
      type: field.type || 'text',
      options: field.options || [],
      isRadioOrCheckbox: function () {
        return isRadioOrCheckbox(input)
      },
      toHtml: function () {
        var inputTag
        if (input.type !== 'select') {
          inputTag = t("<input id='{id}' class='{clazz} swal-form-field' type='{type}' name='{name}'" +
            " value='{value}' title='{placeholder}' placeholder='{placeholder}'>", input)
        } else {
          inputTag = t("<select id='{id}' class='{clazz} swal-form-field' name='{name}'" +
            " value='{value}' title='{placeholder}' style='width:100%'>", input) +
              input.options.reduce(toHtmlOptions, '') +
            '</select>'
        }
        var labelTag = t("{label}", input)

        return inputTag + labelTag

        function toHtmlOptions (optionsString, option) {
          return optionsString + t("<option value='{value}'>{text}</option>", option)
        }
      }
    }
    input.label = input.isRadioOrCheckbox() ? (typeof field.label !== 'undefined' ? field.label : input.value) : ''
    input.clazz = !input.isRadioOrCheckbox() ? 'nice-input' : 'patch-swal-styles-for-inputs'

    return input

    function camelCaseToHuman (arg) {
      if (arg) {
        return arg
          .replace(/([A-Z])/g, ' $1') // insert a space before all caps
          .replace(/^./, function (str) { return str.toUpperCase() }) // uppercase the first character
      } else {
        return ''
      }
    }
  }

  // string interpolation hack
  function t (template, data) {
    for (var key in data) {
      template = template.replace(new RegExp('{' + key + '}', 'g'), data[key] || '')
    }
    return template
  }

  function toSingleString (s1, s2) {
    return s1 + s2
  }
})()
<|endoftext|>


<commit_before><commit_msg>log -> puts<commit_after><|endoftext|>


<commit_before>var e = module.exports = {};
var path = require('path');
var fs = require('fs');
var bot;
var cah = {};
var cad = {};
var Canvas = require('canvas');
var Image = Canvas.Image;
var request = require('request');
var bu;

var bot;
e.init = (Tbot, blargutil) => {
    bot = Tbot;
    bu = blargutil;
    if (fs.existsSync(path.join(__dirname, '..', 'cah.json'))) {
        cah = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'cah.json'), 'utf8'));
    }
    request('https://api.cardcastgame.com/v1/decks/JJDFG/cards', (err, res, body) => {
        let tempCad = JSON.parse(body);
        cad.black = tempCad.calls.map(m => {
            return m.text.join('______');
        });
        cad.white = tempCad.responses.map(m => {
            return m.text.join('______');
        });
    });

    e.category = bu.CommandType.GENERAL;
};

e.isCommand = true;

e.requireCtx = require;

e.hidden = false;
e.usage = 'cah';
e.info = 'Generates a set of CAH cards.';
e.longinfo = '
Generates a random set of Cards Against Humanity cards.
';
e.execute = (msg, words) => {
    new Promise((fulfill) => {
        bu.guildSettings.get(msg.channel.guild.id, 'cahnsfw').then(val => {
            if (val && val != 0) {
                bu.isNsfwChannel(msg.channel.id).then(cont => {
                    fulfill(cont);
                });
            } else {
                fulfill(true);
            }
        });
    }).then(cont => {
        if (cont)
            doit(msg, words);
        else
            bu.sendMessageToDiscord(msg.channel.id, bu.config.general.nsfwMessage);
    });
};

function doit(msg, words) {
    let doCad = words[1] && words[1].toLowerCase() == 'cad';
    let cardObj = doCad ? cad : cah;

    var blackphrase = cardObj.black[bu.getRandomInt(0, cardObj.black.length)];
    var blankCount = /.\_([^\_]|$)/g.test(blackphrase) ? blackphrase.match(/.\_([^\_]|$)/g).length : 1;
    var canvas = new Canvas(185 * (1 + blankCount), 254);
    var ctx = canvas.getContext('2d');
    bu.logger.debug(blackphrase);
    var blackcard = new Image();
    blackcard.src = fs.readFileSync(path.join(__dirname, '..', 'img', 'blackcard.png'));
    var whitecard = new Image();
    whitecard.src = fs.readFileSync(path.join(__dirname, '..', 'img', 'whitecard.png'));

    ctx.fillStyle = 'white';
    ctx.drawImage(blackcard, 0, 0);
    wrapText(ctx, blackphrase, 19, 38, 144, 20);
    ctx.fillStyle = 'black';
    var usedCards = [];

    for (var i = 0; i < blankCount; i++) {
        ctx.drawImage(whitecard, ((i + 1) * (184 + 1)), 0);

        var whitephrase = cardObj.white[bu.getRandomInt(0, cardObj.black.length)];
        while (usedCards.indexOf(whitephrase) > -1) {
            whitephrase = cardObj.white[bu.getRandomInt(0, cardObj.black.length)];
        }
        bu.logger.debug(blackphrase);
        usedCards.push(whitephrase);
        wrapText(ctx, whitephrase, 19 + ((i + 1) * (184 + 1)), 38, 144, 20);
    }

    var data = canvas.toBuffer();
    bu.sendMessageToDiscord(msg.channel.id, ``, {
        name: 'cards.png',
        file: data
    }).catch(err => {
        bu.logger.error(err);
    });

}

function wrapText(context, text, x, y, maxWidth, lineHeight) {
    if (text.length > 110) {
        context.font = '16px Arial';
    } else {
        context.font = '20px Arial';

    }
    var words = text.split(' ');
    var line = '';

    for (var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
        var metrics = context.measureText(testLine);
        var testWidth = metrics.width;
        if (testWidth > maxWidth && n > 0) {
            context.fillText(line, x, y);
            line = words[n] + ' ';
            y += lineHeight;
        }
        else {
            line = testLine;
        }
    }
    context.fillText(line, x, y);
}<commit_msg>broken cah<commit_after>var e = module.exports = {};
var path = require('path');
var fs = require('fs');
var bot;
var cah = {};
var cad = {};
var Canvas = require('canvas');
var Image = Canvas.Image;
var request = require('request');
var bu;

var bot;
e.init = (Tbot, blargutil) => {
    bot = Tbot;
    bu = blargutil;
    if (fs.existsSync(path.join(__dirname, '..', 'cah.json'))) {
        cah = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'cah.json'), 'utf8'));
    }

    request('https://api.cardcastgame.com/v1/decks/JJDFG/cards', (err, res, body) => {
        try {
        let tempCad = JSON.parse(body);
        cad.black = tempCad.calls.map(m => {
            return m.text.join('______');
        });
        cad.white = tempCad.responses.map(m => {
            return m.text.join('______');
        });
        } catch (err) {
            console.log(err.stack);
        }
    });

    e.category = bu.CommandType.GENERAL;
};

e.isCommand = true;

e.requireCtx = require;

e.hidden = false;
e.usage = 'cah';
e.info = 'Generates a set of CAH cards.';
e.longinfo = '
Generates a random set of Cards Against Humanity cards.
';
e.execute = (msg, words) => {
    new Promise((fulfill) => {
        bu.guildSettings.get(msg.channel.guild.id, 'cahnsfw').then(val => {
            if (val && val != 0) {
                bu.isNsfwChannel(msg.channel.id).then(cont => {
                    fulfill(cont);
                });
            } else {
                fulfill(true);
            }
        });
    }).then(cont => {
        if (cont)
            doit(msg, words);
        else
            bu.sendMessageToDiscord(msg.channel.id, bu.config.general.nsfwMessage);
    });
};

function doit(msg, words) {
    let doCad = words[1] && words[1].toLowerCase() == 'cad';
    let cardObj = doCad ? cad : cah;

    var blackphrase = cardObj.black[bu.getRandomInt(0, cardObj.black.length)];
    var blankCount = /.\_([^\_]|$)/g.test(blackphrase) ? blackphrase.match(/.\_([^\_]|$)/g).length : 1;
    var canvas = new Canvas(185 * (1 + blankCount), 254);
    var ctx = canvas.getContext('2d');
    bu.logger.debug(blackphrase);
    var blackcard = new Image();
    blackcard.src = fs.readFileSync(path.join(__dirname, '..', 'img', 'blackcard.png'));
    var whitecard = new Image();
    whitecard.src = fs.readFileSync(path.join(__dirname, '..', 'img', 'whitecard.png'));

    ctx.fillStyle = 'white';
    ctx.drawImage(blackcard, 0, 0);
    wrapText(ctx, blackphrase, 19, 38, 144, 20);
    ctx.fillStyle = 'black';
    var usedCards = [];

    for (var i = 0; i < blankCount; i++) {
        ctx.drawImage(whitecard, ((i + 1) * (184 + 1)), 0);

        var whitephrase = cardObj.white[bu.getRandomInt(0, cardObj.black.length)];
        while (usedCards.indexOf(whitephrase) > -1) {
            whitephrase = cardObj.white[bu.getRandomInt(0, cardObj.black.length)];
        }
        bu.logger.debug(blackphrase);
        usedCards.push(whitephrase);
        wrapText(ctx, whitephrase, 19 + ((i + 1) * (184 + 1)), 38, 144, 20);
    }

    var data = canvas.toBuffer();
    bu.sendMessageToDiscord(msg.channel.id, ``, {
        name: 'cards.png',
        file: data
    }).catch(err => {
        bu.logger.error(err);
    });

}

function wrapText(context, text, x, y, maxWidth, lineHeight) {
    if (text.length > 110) {
        context.font = '16px Arial';
    } else {
        context.font = '20px Arial';

    }
    var words = text.split(' ');
    var line = '';

    for (var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
        var metrics = context.measureText(testLine);
        var testWidth = metrics.width;
        if (testWidth > maxWidth && n > 0) {
            context.fillText(line, x, y);
            line = words[n] + ' ';
            y += lineHeight;
        }
        else {
            line = testLine;
        }
    }
    context.fillText(line, x, y);
}<|endoftext|>


<commit_before>class PlayerAI {
  constructor() {
    this.have_ball = false
    this.toball_cnt = 0
    this.agressive_cnt = 0
    this.tofront_cnt = 0
    this.togoal_cnt = 0
    this.managed = []
    for (var p in this.players) {
      if (p.ball) this.have_ball = true
    }
  }

    step(dt) {

    }

  manage(player , dt) {
    if (this.managed[player] == null) {
      this.managed[player] = {
        "mode" : "toball",
        "lastmode_ts" : 0,
      }
    }
    var infos = this.managed[player]
    var goals = [
      [106,-101,-114], // goal area on left side
      [283,-101,-114], // goal area on right side
    ]

    // set  ai behaviour
    if (player.ball) {
      if (player.body.GetPosition().get_x() < (goals[0][0] + 40) // when near the goal and have ball
       && player.body.GetPosition().get_y() < goals[0][1]
       && player.body.GetPosition().get_y() > goals[0][2]) {
         infos.mode = "togoal"
         this.togoal_cnt = this.togoal_cnt + 1
      }
    } else {
      infos.mode = 'tofrontgoal'
      this.tofront_cnt = managed.tofront_cnt + 1
    }

    }

    clear() {

    }
}
<commit_msg>set ai enemy behaviour for player in team<commit_after>class PlayerAI {
  constructor() {
    this.have_ball = false
    this.toball_cnt = 0
    this.agressive_cnt = 0
    this.tofront_cnt = 0
    this.togoal_cnt = 0
    this.managed = []
    for (var p in this.players) {
      if (p.ball) this.have_ball = true
    }
  }

    step(dt) {

    }

  manage(player , dt) {
    if (this.managed[player] == null) {
      this.managed[player] = {
        "mode" : "toball",
        "lastmode_ts" : 0,
      }
    }
    var infos = this.managed[player]
    var mode_duration = 3
    var goals = [
      [106,-101,-114], // goal area on left side
      [283,-101,-114], // goal area on right side
    ]

    // set  ai behaviour
    if (player.ball) {
        if (player.body.GetPosition().get_x() < (goals[0][0] + 40) // when near the goal and have ball
         && player.body.GetPosition().get_y() < goals[0][1]
         && player.body.GetPosition().get_y() > goals[0][2]) {
           infos.mode = "togoal"
           this.togoal_cnt = this.togoal_cnt + 1
        } else {
          infos.mode = 'tofrontgoal'
          this.tofront_cnt = managed.tofront_cnt + 1
        }
      } else {
        if (this.have_ball) { // an another ennemy player have the ball
          infos.mode = 'agressive'
          this.agressive_cnt = managed.agressive_cnt + 1
        } else if (infos.lastmode == null || infos.lastmode_ts  > mode_duration then) {
          infos.lastmode_ts = 0
          if (this.toball_cnt > 0 && (Math.random() < 0.5 or this.toball_cnt == 0)) {
            infos.mode = 'agressive' -- make one agressive, then random
            this.agressive_cnt = this.agressive_cnt + 1
          } else {
            infos.mode = 'toball' -- if one agressive then one here, then random
            this.toball_cnt = this.toball_cnt + 1
          }

        } else {
          infos.lastmode_ts = infos.lastmode_ts + dt
          infos.mode = infos.lastmode
        }

      }

    }

    clear() {

    }
}
<|endoftext|>


<commit_before>var nconf = require('nconf');
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var mongoose = require('mongoose');
var uuid = require('uuid');
var request = require('request');
import logger from './logger';

var empty_config = {
  permissions: [],
  roles: []
};

var Permission = mongoose.model('Permission', {
  "name" : String,
  "description" : String,
  "application" : String,
  "id" : String
});

var Role = mongoose.model('Role', {
  "name" : String,
  "description" : String,
  "id" : String,
  "application" : String,
  "permissions" : [String]
});

class SettingsDBService {

  constructor(options) {
    options = options || {};

    mongoose.connect(nconf.get('MONGODB_CONNECTION_STRING'));
    this.db = mongoose.connection;
    this.db.on('error', function (err) {
      console.log('MongoDB connection error', err);
    });
  }

  getPermissions() {
    return new Promise((resolve, reject) => {
      Permission.find(function(err, permissions) {
        if (err) {
          console.log(err);
          reject(err);
        } else {
          console.log(permissions);
          resolve(permissions);
        }
      });
    }).then((permissions) => {
      return permissions;
    });
  }

  savePermission(permission) {
    return new Promise((resolve, reject) => {
      Permission.findOne({ id : permission.id }, function(err, result) {
        if (err) {
          console.log(err);
        }

        var id = uuid.v4();
        if (result != null)
          id = result.id;

        var permissionDocument = new Permission({
          "name" : permission.name,
          "description" : permission.description,
          "application" : permission.application,
          "id" : id
        });
        permissionDocument.save((err) => {
          if (err)
            console.log(err);
          else
            resolve(permissionDocument);
        });
      });
    }).then((permissionDocument) => {
      return permissionDocument;
    });
  }

  deletePermission(permission_id) {
    return new Promise((resolve, reject) => {
      Permission.remove({ id : permission_id }, function(err, result) {
        if (err) { console.log(err); reject(err); }
        resolve(result);
      });
    }).then((permissions) => {
      return permissions;
    });
  }

  getRoles() {
    return new Promise((resolve, reject) => {
      Role.find(function(err, roles) {
        if (err) {
          console.log(err);
          reject(err);
        } else {
          resolve(roles);
        }
      });
    }).then((roles) => {
      return roles;
    });
  }

  getFlatPermissions(roles) {
    return this.getPermissions()
      .then((permissions) => {
        let permissions_flat = [];

        // Process the user's roles.
        _.forEach(roles, (role) => {
          _.forEach(permissions, (permission) => {
            if (permissions_flat.indexOf(permission.id) === -1) {
              if (role.permissions && role.permissions.indexOf(permission.id) > -1) {
                permissions_flat.push(permission.id);
              }
            }
          });
        });

        // Return a list of role objects.
        return _.chain(permissions_flat)
          .map((permission_id) => {
            return _.find(permissions, { 'id': permission_id });
          })
          .filter((permission) => {
            return permission != null;
          })
          .value();
      });
  }

  getFlatRoles(id_list) {
    return this.getRoles()
      .then((roles) => {

        // This contains a flat list of all roles and sub roles that apply to the id_list
        let roles_flat = [];

        // Recursive method to find roles.
        let findRoles = (role_id) => {
          logger.log('Finding roles for: ' + role_id);

          // Only process each role once.
          if (roles_flat.indexOf(role_id) === -1) {
            roles_flat.push(role_id);

            // Load the role and add sub roles.
            let role = _.find(roles, { 'id': role_id });
            if (role && role.sub_roles) {
              _.forEach(role.sub_roles, (sub_role_id) => {
                findRoles(sub_role_id);
              });
            }
          }
        };
            logger.info(roles_flat);
            logger.info(roles);

        // Process the user's roles.
        _.forEach(id_list, (role_id) => {
          findRoles(role_id);
        });

        // Return a list of role objects.
        return _.chain(roles_flat)
          .map((role_id) => {
            return _.find(roles, { 'id': role_id });
          })
          .filter((role) => {
            return role != null && role !== false;
          })
          .value();
      });
  }

  saveRole(role) {
    return new Promise((resolve, reject) => {
      Role.findOne({ id : role.id }, function(err, result) {
        if (err) {
          console.log(err);
        }

        var id = uuid.v4();
        if (result != null)
          id = result.id;

        var roleDocument = new Role({
          "name" : role.name,
          "description" : role.description,
          "id" : id
        });
        roleDocument.save((err) => {
          if (err)
            console.log(err);
          else
            resolve(roleDocument);
        });
      });
    }).then((roleDocument) => {
      return roleDocument;
    });
  }

  addRolePermissions(roleId, permissions) {
    var role;
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': roleId });
      role = this.config.roles[i];

      if (!role.permissions) {
        role.permissions = [];
      }

      var new_permissions = _.filter(permissions, function(permission) {
        return _.indexOf(role.permissions, permission) === -1;
      });

      _.forEach(new_permissions, function(permission) {
        role.permissions.push(permission);
      })
    }).then(() => {
      return this._writeConfig();
    }).then(() => {
      return role;
    })
  }

  deleteRolePermission(roleId, permissionId) {
    var role;
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': roleId });
      role = this.config.roles[i];

      if (!role.permissions) {
        role.permissions = [];
      }

      var permission_index = role.permissions.indexOf(permissionId);
      if (permission_index > -1) {
        role.permissions.splice(permission_index, 1);
      }

    }).then(() => {
      return this._writeConfig();
    }).then(() => {
      return role;
    })
  }

  addRoleSubRoles(role_id, sub_roles) {
    var role;
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': role_id });
      role = this.config.roles[i];

      if (!role.sub_roles) {
        role.sub_roles = [];
      }

      var new_roles = _.filter(sub_roles, function(r) {
        return _.indexOf(role.sub_roles, r) === -1;
      });

      _.forEach(new_roles, function(r) {
        role.sub_roles.push(r);
      })
    }).then(() => {
      return this._writeConfig();
    }).then(() => {
      return role;
    })
  }

  deleteRoleSubRole(role_id, sub_role_id) {
    var role;
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': role_id });
      role = this.config.roles[i];

      if (!role.sub_roles) {
        role.sub_roles = [];
      }

      var sub_role_index = role.sub_roles.indexOf(sub_role_id);
      if (sub_role_index > -1) {
        role.sub_roles.splice(sub_role_index, 1);
      }

    }).then(() => {
      return this._writeConfig();
    }).then(() => {
      return role;
    })
  }

  deleteRole(role_id) {
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': role_id });
      if (i > -1) {
        this.config.roles.splice(i, 1);
      } else {
        throw 'Invalid role_id';
      }
    }).then(() => {
      return this._writeConfig();
    });
  }

}

module.exports = new SettingsDBService();<commit_msg>Role delete<commit_after>var nconf = require('nconf');
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var mongoose = require('mongoose');
var uuid = require('uuid');
var request = require('request');
import logger from './logger';

var empty_config = {
  permissions: [],
  roles: []
};

var Permission = mongoose.model('Permission', {
  "name" : String,
  "description" : String,
  "application" : String,
  "id" : String
});

var Role = mongoose.model('Role', {
  "name" : String,
  "description" : String,
  "id" : String,
  "application" : String,
  "permissions" : [String]
});

class SettingsDBService {

  constructor(options) {
    options = options || {};

    mongoose.connect(nconf.get('MONGODB_CONNECTION_STRING'));
    this.db = mongoose.connection;
    this.db.on('error', function (err) {
      console.log('MongoDB connection error', err);
    });
  }

  getPermissions() {
    return new Promise((resolve, reject) => {
      Permission.find(function(err, permissions) {
        if (err) {
          console.log(err);
          reject(err);
        } else {
          console.log(permissions);
          resolve(permissions);
        }
      });
    }).then((permissions) => {
      return permissions;
    });
  }

  savePermission(permission) {
    return new Promise((resolve, reject) => {
      Permission.findOne({ id : permission.id }, function(err, result) {
        if (err) {
          console.log(err);
        }

        var id = uuid.v4();
        if (result != null)
          id = result.id;

        var permissionDocument = new Permission({
          "name" : permission.name,
          "description" : permission.description,
          "application" : permission.application,
          "id" : id
        });
        permissionDocument.save((err) => {
          if (err)
            console.log(err);
          else
            resolve(permissionDocument);
        });
      });
    }).then((permissionDocument) => {
      return permissionDocument;
    });
  }

  deletePermission(permission_id) {
    return new Promise((resolve, reject) => {
      Permission.remove({ id : permission_id }, function(err, result) {
        if (err) { console.log(err); reject(err); }
        resolve(result);
      });
    }).then((permissions) => {
      return permissions;
    });
  }

  getRoles() {
    return new Promise((resolve, reject) => {
      Role.find(function(err, roles) {
        if (err) {
          console.log(err);
          reject(err);
        } else {
          resolve(roles);
        }
      });
    }).then((roles) => {
      return roles;
    });
  }

  getFlatPermissions(roles) {
    return this.getPermissions()
      .then((permissions) => {
        let permissions_flat = [];

        // Process the user's roles.
        _.forEach(roles, (role) => {
          _.forEach(permissions, (permission) => {
            if (permissions_flat.indexOf(permission.id) === -1) {
              if (role.permissions && role.permissions.indexOf(permission.id) > -1) {
                permissions_flat.push(permission.id);
              }
            }
          });
        });

        // Return a list of role objects.
        return _.chain(permissions_flat)
          .map((permission_id) => {
            return _.find(permissions, { 'id': permission_id });
          })
          .filter((permission) => {
            return permission != null;
          })
          .value();
      });
  }

  getFlatRoles(id_list) {
    return this.getRoles()
      .then((roles) => {

        // This contains a flat list of all roles and sub roles that apply to the id_list
        let roles_flat = [];

        // Recursive method to find roles.
        let findRoles = (role_id) => {
          logger.log('Finding roles for: ' + role_id);

          // Only process each role once.
          if (roles_flat.indexOf(role_id) === -1) {
            roles_flat.push(role_id);

            // Load the role and add sub roles.
            let role = _.find(roles, { 'id': role_id });
            if (role && role.sub_roles) {
              _.forEach(role.sub_roles, (sub_role_id) => {
                findRoles(sub_role_id);
              });
            }
          }
        };
            logger.info(roles_flat);
            logger.info(roles);

        // Process the user's roles.
        _.forEach(id_list, (role_id) => {
          findRoles(role_id);
        });

        // Return a list of role objects.
        return _.chain(roles_flat)
          .map((role_id) => {
            return _.find(roles, { 'id': role_id });
          })
          .filter((role) => {
            return role != null && role !== false;
          })
          .value();
      });
  }

  saveRole(role) {
    return new Promise((resolve, reject) => {
      Role.findOne({ id : role.id }, function(err, result) {
        if (err) {
          console.log(err);
        }

        var id = uuid.v4();
        if (result != null)
          id = result.id;

        var roleDocument = new Role({
          "name" : role.name,
          "description" : role.description,
          "id" : id
        });
        roleDocument.save((err) => {
          if (err)
            console.log(err);
          else
            resolve(roleDocument);
        });
      });
    }).then((roleDocument) => {
      return roleDocument;
    });
  }

  addRolePermissions(roleId, permissions) {
    var role;
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': roleId });
      role = this.config.roles[i];

      if (!role.permissions) {
        role.permissions = [];
      }

      var new_permissions = _.filter(permissions, function(permission) {
        return _.indexOf(role.permissions, permission) === -1;
      });

      _.forEach(new_permissions, function(permission) {
        role.permissions.push(permission);
      })
    }).then(() => {
      return this._writeConfig();
    }).then(() => {
      return role;
    })
  }

  deleteRolePermission(roleId, permissionId) {
    var role;
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': roleId });
      role = this.config.roles[i];

      if (!role.permissions) {
        role.permissions = [];
      }

      var permission_index = role.permissions.indexOf(permissionId);
      if (permission_index > -1) {
        role.permissions.splice(permission_index, 1);
      }

    }).then(() => {
      return this._writeConfig();
    }).then(() => {
      return role;
    })
  }

  addRoleSubRoles(role_id, sub_roles) {
    var role;
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': role_id });
      role = this.config.roles[i];

      if (!role.sub_roles) {
        role.sub_roles = [];
      }

      var new_roles = _.filter(sub_roles, function(r) {
        return _.indexOf(role.sub_roles, r) === -1;
      });

      _.forEach(new_roles, function(r) {
        role.sub_roles.push(r);
      })
    }).then(() => {
      return this._writeConfig();
    }).then(() => {
      return role;
    })
  }

  deleteRoleSubRole(role_id, sub_role_id) {
    var role;
    return this._ensureLoaded()
    .then(() => {
      var i = _.findIndex(this.config.roles, { 'id': role_id });
      role = this.config.roles[i];

      if (!role.sub_roles) {
        role.sub_roles = [];
      }

      var sub_role_index = role.sub_roles.indexOf(sub_role_id);
      if (sub_role_index > -1) {
        role.sub_roles.splice(sub_role_index, 1);
      }

    }).then(() => {
      return this._writeConfig();
    }).then(() => {
      return role;
    })
  }

  deleteRole(role_id) {
    return new Promise((resolve, reject) => {
      Role.remove({ id : role_id }, function(err, result) {
        if (err) { console.log(err); reject(err); }
        resolve(result);
      });
    }).then((roles) => {
      return roles;
    });
  }
}

module.exports = new SettingsDBService();<|endoftext|>


<commit_before><commit_msg>Add doc comments for renderIn<commit_after><|endoftext|>


<commit_before>var Buffer = require('buffer').Buffer;
var mysql = require('mysql');
var Q = require('q');
var zephyr = require('zephyr');

var conf = require('./config.js');

var MAX_MESSAGES_RETURNED = 100;

// Per vasilvv, use VARBINARY everywhere instead of VARCHAR. MySQL
// collations are sad.

// TODO: We probably can get away with significantly less isolated
// transactions here if it becomes a problem. Potentially worthwhile
// assumptions/benign races.
//
// - entries in subs table are never deleted.
// - subscription/message-insert races can resolve either way.

var schemas = [
  'CREATE TABLE users (' +
    'id BIGINT AUTO_INCREMENT PRIMARY KEY,' +
    'username VARBINARY(255) UNIQUE NOT NULL' +
    ') ENGINE=InnoDB;',

  'CREATE TABLE subs (' +
    'id BIGINT AUTO_INCREMENT PRIMARY KEY,' +
    // Class/inst are post NFKC and casefolding.
    'class VARBINARY(255) NOT NULL,' +
    'instance VARBINARY(255) NULL,' +
    'recipient VARBINARY(255) NOT NULL,' +
    'UNIQUE target_idx (class, instance, recipient)' +
    ') ENGINE=InnoDB;',

  'CREATE TABLE user_subs (' +
    'id BIGINT AUTO_INCREMENT PRIMARY KEY,' +
    'user_id BIGINT NOT NULL,' +
    'FOREIGN KEY user_fkey (user_id) REFERENCES users(id),' +
    'sub_id BIGINT NOT NULL,' +
    'FOREIGN KEY sub_fkey (sub_id) REFERENCES subs(id),' +
    // Ranges of valid indices into the messages table.
    'start BIGINT NOT NULL,' +
    'end BIGINT NULL,' +
    // Preserve the original versions of the strings for display.
    'class VARBINARY(255) NOT NULL,' +
    'instance VARBINARY(255) NULL,' +
    'recipient VARBINARY(255) NULL' +
    ') ENGINE=InnoDB;',

  'CREATE TABLE messages (' +
    'id BIGINT AUTO_INCREMENT PRIMARY KEY,' +
/*
    // Randomly generated public id. This is so we don't leak how many
    // messages are not visible.
    'msgid VARBINARY(255) UNIQUE NOT NULL,' +
*/
    // Each message matches two subscriptions. The full one and the
    // wildcard one. We join against the subscriptions table to
    // query. I think the query itself wants to be a UNION. Seems
    // MySQL does a better job of using indexes in that case than with
    // an OR. In that case, the two queries should filter user_subs by
    // instance being and not being NULL. Hopefully MySQL can realize
    // that the non-wildcard half of the union is basically always
    // trivial.
    'wildcard_sub_id BIGINT NULL,' +
    'FOREIGN KEY wildcard_fkey (wildcard_sub_id) REFERENCES subs(id),' +
    'sub_id BIGINT NULL,' +
    'FOREIGN KEY sub_fkey (sub_id) REFERENCES subs(id),' +
    // Message fields. class and instance are not normalized them for
    // display purposes.
    'class VARBINARY(255) NOT NULL,' +
    'instance VARBINARY(255) NOT NULL,' +
    // Stores the number of milliseconds past the Unix epoch,
    // i.e. what Date.prototype.getTime spits out. Technically zephyr
    // gives you microsecond resolution, but I don't think V8 gives
    // you more than millisecond resolution anyway.
    'time BIGINT NOT NULL,' +
    'auth TINYINT NOT NULL,' +
    'sender VARBINARY(255) NOT NULL,' +
    'recipient VARBINARY(255) NOT NULL,' +
    // TODO(davidben): Don't really need to store this one...
    'realm VARBINARY(255) NOT NULL,' +
    'opcode VARBINARY(255) NOT NULL,' +
    'signature VARBINARY(255) NOT NULL,' +
    'message BLOB NOT NULL' +
    ') ENGINE=InnoDB;',

  // HACK: Until we actually get users and stuff.
  'INSERT INTO users (username) VALUES ("davidben@ATHENA.MIT.EDU")',
];

var pool = mysql.createPool(conf.get('db'));

exports.initTables = function() {
  var connection = mysql.createConnection(conf.get('db'));
  return schemas.reduce(function(soFar, schema) {
    return soFar.then(function() {
      console.log(schema);
      return Q.ninvoke(connection, 'query', schema);
    });
  }, Q()).finally(function() {
    connection.end();
  });
};

function toBufferOrNull(arg) {
  if (arg === null)
    return null;
  return new Buffer(arg);
}

function Connection(connection) {
  this.connection = connection;
};

Connection.prototype.end = function() {
  this.connection.end();
  this.connection = null;
};

Connection.prototype.query = function(query, values) {
  // Q.ninvoke would do this, but it's annoying. Returns an array
  // because the callback has two result arguments.
  var deferred = Q.defer();
  var queryObj = this.connection.query(query, values, function(err, result) {
    if (err) {
      deferred.reject(err);
    } else {
      deferred.fulfill(result);
    }
  });
  console.log(queryObj.sql);
  return deferred.promise;
};

Connection.prototype.withTransaction = function(operation) {
  return this.query('START TRANSACTION').then(function() {
    return operation();
  }).then(function(ret) {
    return this.query('COMMIT').then(function() {
      return ret;
    }.bind(this));
  }.bind(this), function(err) {
    return this.query('ROLLBACK').then(function() {
      throw err;
    });
  }.bind(this));
};

Connection.prototype._nextMessageId = function() {
  return this.query(
    'SELECT id FROM messages ORDER BY id DESC LIMIT 1'
  ).then(function(result) {
    return (result.length > 0) ? (result[0].id + 1) : 1;
  });
};

Connection.prototype._findSubscription = function(klass, inst, recip) {
  klass = zephyr.downcase(klass);
  if (inst !== null)
    inst = zephyr.downcase(inst);
  // Pretty sure this is unnecessary, but meh.
  recip = recip.replace('\0', '\ufffd');

  // Blegh. Equality and NULL. Obnoxious.
  return this.query(
    'SELECT id FROM subs WHERE ' +
      'class = ? AND instance <=> ? AND recipient = ?',
    [new Buffer(klass), toBufferOrNull(inst), new Buffer(recip)]
  ).then(function(rows) {
    if (rows.length === 0)
      return null;
    return rows[0].id;
  });
};

Connection.prototype._findOrInsertSubscription = function(klass, inst, recip) {
  klass = zephyr.downcase(klass);
  if (inst !== null)
    inst = zephyr.downcase(inst);
  // Pretty sure this is unnecessary, but meh.
  recip = recip.replace('\0', '\ufffd');

  return this._findSubscription(klass, inst, recip).then(function(id) {
    if (id != null)
      return id;
    // Insert it.
    return this.query('INSERT INTO subs SET ?', [{
      class: new Buffer(klass),
      instance: toBufferOrNull(inst),
      recipient: new Buffer(recip)
    }]).then(function(result) {
      return result.insertId;
    });
  }.bind(this));
};

Connection.prototype.addUserSubscription = function(user, klass, inst, recip) {
  return this.withTransaction(function() {
    return this._findOrInsertSubscription(
      klass, inst, recip
    ).then(function(subId) {
      // First, see if there is already an active subscription.
      return this.query(
        'SELECT COUNT(*) AS count FROM user_subs ' +
          'WHERE user_id = ? AND sub_id = ? AND end IS NULL',
        [user, subId]
      ).then(function(result) {
        // If we already have an active subscription, no need to do anything.
        if (result[0].count > 0)
          return;

        // Find out the id of the latest message.
        return this._nextMessageId().then(function(start) {
          var userSub = {
            user_id: user,
            sub_id: subId,
            start: start,
            end: null,
            class: new Buffer(klass),
            instance: toBufferOrNull(inst),
            recipient: new Buffer(recip)
          };
          return this.query('INSERT INTO user_subs SET ?', userSub);
        }.bind(this));
      }.bind(this));
    }.bind(this));
  }.bind(this));
};

Connection.prototype.removeUserSubscription = function(user, klass, inst, recip) {
  // TODO(davidben): Prune user_subs entries that never matched anything.
  return this.withTransaction(function() {
    return this._findSubscription(
      klass, inst, recip
    ).then(function(subId) {
      if (subId == null)
        return;
      return this._nextMessageId().then(function(end) {
        return this.query(
          'UPDATE user_subs SET end = ? ' +
            'WHERE user_id = ? AND sub_id = ? AND end IS NULL',
          [end, user, subId]
        );
      }.bind(this));
    }.bind(this));
  }.bind(this));
};

Connection.prototype.getUserSubscriptions = function(user) {
  return this.query(
    'SELECT class, instance, recipient FROM user_subs ' +
      'WHERE user_id = ? AND end IS NULL',
    [user]
  ).then(function(rows) {
    return rows.map(function(row) {
      return [
        row.class.toString('utf8'),
        row.instance == null ? null : row.instance.toString('utf8'),
        row.recipient
      ];
    });
  });
};

Connection.prototype.loadActiveSubs = function() {
  return this.query(
    'SELECT DISTINCT subs.class, subs.instance, subs.recipient ' +
      'FROM subs INNER JOIN user_subs ON subs.id = user_subs.sub_id ' +
      'WHERE user_subs.end IS NULL'
  ).then(function(result) {
    return result.map(function(row) {
      return [row.class.toString('utf8'),
              row.instance ? row.instance.toString('utf8') : null,
              row.recipient.toString('utf8')];
    });
  });
};

Connection.prototype.saveMessage = function(msg) {
  return this.withTransaction(function() {
    // First, get the subscription IDs.
    return this._findSubscription(
      msg.class, msg.instance, msg.recipient
    ).then(function(subId) {
      return this._findSubscription(
        msg.class, null, msg.recipient
      ).then(function(wildcardId) {
        return [subId, wildcardId];
      });
    }.bind(this)).then(function(subs) {
      // If this message matches nothing, just throw it away.
      var subId = subs[0], wildcardId = subs[1];
      if (subId == null && wildcardId == null)
        return;
      return this.query('INSERT INTO messages SET ?',
                        {
                          // msgid: FIXME,
                          wildcard_sub_id: wildcardId,
                          sub_id: subId,
                          class: new Buffer(msg.class),
                          instance: new Buffer(msg.instance),
                          time: msg.time,
                          auth: msg.auth,
                          sender: new Buffer(msg.sender),
                          recipient: new Buffer(msg.recipient),
                          realm: new Buffer(msg.realm),
                          opcode: new Buffer(msg.opcode),
                          signature: new Buffer(msg.signature),
                          message: new Buffer(msg.message),
                        });
    }.bind(this));
  }.bind(this));
};

// TODO: Might want to support other queries? Yeah, I dunno.
Connection.prototype.getMessagesAfter = function(user, msgId, limit) {
  // For sanity, pick a random limit.
  limit = Math.min(limit, MAX_MESSAGES_RETURNED);

  return this.query(
    '(SELECT messages.* ' +
     'FROM messages JOIN subs ON subs.id = messages.sub_id ' +
     'JOIN user_subs ON user_subs.sub_id = subs.id ' +
     'WHERE user_subs.user_id = ? AND ' +
       'messages.id >= ? AND ' +
       'messages.id >= user_subs.start AND ' +
       '(user_subs.end IS NULL OR messages.id < user_subs.end)) ' +
     'UNION ' +
    '(SELECT messages.* ' +
     'FROM messages JOIN subs ON subs.id = messages.wildcard_sub_id ' +
     'JOIN user_subs ON user_subs.sub_id = subs.id ' +
     'WHERE user_subs.user_id = ? AND ' +
       'messages.id >= ? AND ' +
       'messages.id >= user_subs.start AND ' +
       '(user_subs.end IS NULL OR messages.id < user_subs.end)) ' +
    'ORDER BY id ASC ' +
    'LIMIT ?',
    [user, msgId, user, msgId, limit]
  ).then(function(rows) {
    return rows.map(function(row) {
      return {
        id: row.id, // FIXME: opaque ids.
        time: row.time,
        class: row.class.toString('utf8'),
        instance: row.instance.toString('utf8'),
        sender: row.sender.toString('utf8'),
        recipient: row.recipient.toString('utf8'),
        realm: row.realm.toString('utf8'),
        auth: row.auth,
        opcode: row.opcode.toString('utf8'),
        signature: row.signature.toString('utf8'),
        message: row.message.toString('utf8')
      };
    });
  });
};

var getConnection = function() {
  return Q.ninvoke(pool, 'getConnection').then(function(conn) {
    return new Connection(conn);
  });
};

exports.addUserSubscription = function(user, klass, inst, recip) {
  return getConnection().then(function(conn) {
    return conn.addUserSubscription(user, klass, inst, recip).finally(
      conn.end.bind(conn));
  });
};

exports.removeUserSubscription = function(user, klass, inst, recip) {
  return getConnection().then(function(conn) {
    return conn.removeUserSubscription(user, klass, inst, recip).finally(
      conn.end.bind(conn));
  });
};

exports.getUserSubscriptions = function(user) {
  return getConnection().then(function(conn) {
    return conn.getUserSubscriptions(user).finally(conn.end.bind(conn));
  });
};

exports.loadActiveSubs = function() {
  return getConnection().then(function(conn) {
    return conn.loadActiveSubs().finally(conn.end.bind(conn));
  });
};

exports.saveMessage = function(msg) {
  return getConnection().then(function(conn) {
    return conn.saveMessage(msg).finally(conn.end.bind(conn));
  });
};

exports.getMessagesAfter = function(user, msgId, limit) {
  return getConnection().then(function(conn) {
    return conn.getMessagesAfter(user, msgId, limit).finally(conn.end.bind(conn));
  });
};
<commit_msg>The OR version is sliiiightly better<commit_after>var Buffer = require('buffer').Buffer;
var mysql = require('mysql');
var Q = require('q');
var zephyr = require('zephyr');

var conf = require('./config.js');

var MAX_MESSAGES_RETURNED = 100;

// Per vasilvv, use VARBINARY everywhere instead of VARCHAR. MySQL
// collations are sad.

// TODO: We probably can get away with significantly less isolated
// transactions here if it becomes a problem. Potentially worthwhile
// assumptions/benign races.
//
// - entries in subs table are never deleted.
// - subscription/message-insert races can resolve either way.

var schemas = [
  'CREATE TABLE users (' +
    'id BIGINT AUTO_INCREMENT PRIMARY KEY,' +
    'username VARBINARY(255) UNIQUE NOT NULL' +
    ') ENGINE=InnoDB;',

  'CREATE TABLE subs (' +
    'id BIGINT AUTO_INCREMENT PRIMARY KEY,' +
    // Class/inst are post NFKC and casefolding.
    'class VARBINARY(255) NOT NULL,' +
    'instance VARBINARY(255) NULL,' +
    'recipient VARBINARY(255) NOT NULL,' +
    'UNIQUE target_idx (class, instance, recipient)' +
    ') ENGINE=InnoDB;',

  'CREATE TABLE user_subs (' +
    'id BIGINT AUTO_INCREMENT PRIMARY KEY,' +
    'user_id BIGINT NOT NULL,' +
    'FOREIGN KEY user_fkey (user_id) REFERENCES users(id),' +
    'sub_id BIGINT NOT NULL,' +
    'FOREIGN KEY sub_fkey (sub_id) REFERENCES subs(id),' +
    // Ranges of valid indices into the messages table.
    'start BIGINT NOT NULL,' +
    'end BIGINT NULL,' +
    // Preserve the original versions of the strings for display.
    'class VARBINARY(255) NOT NULL,' +
    'instance VARBINARY(255) NULL,' +
    'recipient VARBINARY(255) NULL' +
    ') ENGINE=InnoDB;',

  'CREATE TABLE messages (' +
    'id BIGINT AUTO_INCREMENT PRIMARY KEY,' +
/*
    // Randomly generated public id. This is so we don't leak how many
    // messages are not visible.
    'msgid VARBINARY(255) UNIQUE NOT NULL,' +
*/
    // Each message matches two subscriptions. The full one and the
    // wildcard one. We join against the subscriptions table to
    // query. I think the query itself wants to be a UNION. Seems
    // MySQL does a better job of using indexes in that case than with
    // an OR. In that case, the two queries should filter user_subs by
    // instance being and not being NULL. Hopefully MySQL can realize
    // that the non-wildcard half of the union is basically always
    // trivial.
    'wildcard_sub_id BIGINT NULL,' +
    'FOREIGN KEY wildcard_fkey (wildcard_sub_id) REFERENCES subs(id),' +
    'sub_id BIGINT NULL,' +
    'FOREIGN KEY sub_fkey (sub_id) REFERENCES subs(id),' +
    // Message fields. class and instance are not normalized them for
    // display purposes.
    'class VARBINARY(255) NOT NULL,' +
    'instance VARBINARY(255) NOT NULL,' +
    // Stores the number of milliseconds past the Unix epoch,
    // i.e. what Date.prototype.getTime spits out. Technically zephyr
    // gives you microsecond resolution, but I don't think V8 gives
    // you more than millisecond resolution anyway.
    'time BIGINT NOT NULL,' +
    'auth TINYINT NOT NULL,' +
    'sender VARBINARY(255) NOT NULL,' +
    'recipient VARBINARY(255) NOT NULL,' +
    // TODO(davidben): Don't really need to store this one...
    'realm VARBINARY(255) NOT NULL,' +
    'opcode VARBINARY(255) NOT NULL,' +
    'signature VARBINARY(255) NOT NULL,' +
    'message BLOB NOT NULL' +
    ') ENGINE=InnoDB;',

  // HACK: Until we actually get users and stuff.
  'INSERT INTO users (username) VALUES ("davidben@ATHENA.MIT.EDU")',
];

var pool = mysql.createPool(conf.get('db'));

exports.initTables = function() {
  var connection = mysql.createConnection(conf.get('db'));
  return schemas.reduce(function(soFar, schema) {
    return soFar.then(function() {
      console.log(schema);
      return Q.ninvoke(connection, 'query', schema);
    });
  }, Q()).finally(function() {
    connection.end();
  });
};

function toBufferOrNull(arg) {
  if (arg === null)
    return null;
  return new Buffer(arg);
}

function Connection(connection) {
  this.connection = connection;
};

Connection.prototype.end = function() {
  this.connection.end();
  this.connection = null;
};

Connection.prototype.query = function(query, values) {
  // Q.ninvoke would do this, but it's annoying. Returns an array
  // because the callback has two result arguments.
  var deferred = Q.defer();
  var queryObj = this.connection.query(query, values, function(err, result) {
    if (err) {
      deferred.reject(err);
    } else {
      deferred.fulfill(result);
    }
  });
  console.log(queryObj.sql);
  return deferred.promise;
};

Connection.prototype.withTransaction = function(operation) {
  return this.query('START TRANSACTION').then(function() {
    return operation();
  }).then(function(ret) {
    return this.query('COMMIT').then(function() {
      return ret;
    }.bind(this));
  }.bind(this), function(err) {
    return this.query('ROLLBACK').then(function() {
      throw err;
    });
  }.bind(this));
};

Connection.prototype._nextMessageId = function() {
  return this.query(
    'SELECT id FROM messages ORDER BY id DESC LIMIT 1'
  ).then(function(result) {
    return (result.length > 0) ? (result[0].id + 1) : 1;
  });
};

Connection.prototype._findSubscription = function(klass, inst, recip) {
  klass = zephyr.downcase(klass);
  if (inst !== null)
    inst = zephyr.downcase(inst);
  // Pretty sure this is unnecessary, but meh.
  recip = recip.replace('\0', '\ufffd');

  // Blegh. Equality and NULL. Obnoxious.
  return this.query(
    'SELECT id FROM subs WHERE ' +
      'class = ? AND instance <=> ? AND recipient = ?',
    [new Buffer(klass), toBufferOrNull(inst), new Buffer(recip)]
  ).then(function(rows) {
    if (rows.length === 0)
      return null;
    return rows[0].id;
  });
};

Connection.prototype._findOrInsertSubscription = function(klass, inst, recip) {
  klass = zephyr.downcase(klass);
  if (inst !== null)
    inst = zephyr.downcase(inst);
  // Pretty sure this is unnecessary, but meh.
  recip = recip.replace('\0', '\ufffd');

  return this._findSubscription(klass, inst, recip).then(function(id) {
    if (id != null)
      return id;
    // Insert it.
    return this.query('INSERT INTO subs SET ?', [{
      class: new Buffer(klass),
      instance: toBufferOrNull(inst),
      recipient: new Buffer(recip)
    }]).then(function(result) {
      return result.insertId;
    });
  }.bind(this));
};

Connection.prototype.addUserSubscription = function(user, klass, inst, recip) {
  return this.withTransaction(function() {
    return this._findOrInsertSubscription(
      klass, inst, recip
    ).then(function(subId) {
      // First, see if there is already an active subscription.
      return this.query(
        'SELECT COUNT(*) AS count FROM user_subs ' +
          'WHERE user_id = ? AND sub_id = ? AND end IS NULL',
        [user, subId]
      ).then(function(result) {
        // If we already have an active subscription, no need to do anything.
        if (result[0].count > 0)
          return;

        // Find out the id of the latest message.
        return this._nextMessageId().then(function(start) {
          var userSub = {
            user_id: user,
            sub_id: subId,
            start: start,
            end: null,
            class: new Buffer(klass),
            instance: toBufferOrNull(inst),
            recipient: new Buffer(recip)
          };
          return this.query('INSERT INTO user_subs SET ?', userSub);
        }.bind(this));
      }.bind(this));
    }.bind(this));
  }.bind(this));
};

Connection.prototype.removeUserSubscription = function(user, klass, inst, recip) {
  // TODO(davidben): Prune user_subs entries that never matched anything.
  return this.withTransaction(function() {
    return this._findSubscription(
      klass, inst, recip
    ).then(function(subId) {
      if (subId == null)
        return;
      return this._nextMessageId().then(function(end) {
        return this.query(
          'UPDATE user_subs SET end = ? ' +
            'WHERE user_id = ? AND sub_id = ? AND end IS NULL',
          [end, user, subId]
        );
      }.bind(this));
    }.bind(this));
  }.bind(this));
};

Connection.prototype.getUserSubscriptions = function(user) {
  return this.query(
    'SELECT class, instance, recipient FROM user_subs ' +
      'WHERE user_id = ? AND end IS NULL',
    [user]
  ).then(function(rows) {
    return rows.map(function(row) {
      return [
        row.class.toString('utf8'),
        row.instance == null ? null : row.instance.toString('utf8'),
        row.recipient
      ];
    });
  });
};

Connection.prototype.loadActiveSubs = function() {
  return this.query(
    'SELECT DISTINCT subs.class, subs.instance, subs.recipient ' +
      'FROM subs INNER JOIN user_subs ON subs.id = user_subs.sub_id ' +
      'WHERE user_subs.end IS NULL'
  ).then(function(result) {
    return result.map(function(row) {
      return [row.class.toString('utf8'),
              row.instance ? row.instance.toString('utf8') : null,
              row.recipient.toString('utf8')];
    });
  });
};

Connection.prototype.saveMessage = function(msg) {
  return this.withTransaction(function() {
    // First, get the subscription IDs.
    return this._findSubscription(
      msg.class, msg.instance, msg.recipient
    ).then(function(subId) {
      return this._findSubscription(
        msg.class, null, msg.recipient
      ).then(function(wildcardId) {
        return [subId, wildcardId];
      });
    }.bind(this)).then(function(subs) {
      // If this message matches nothing, just throw it away.
      var subId = subs[0], wildcardId = subs[1];
      if (subId == null && wildcardId == null)
        return;
      return this.query('INSERT INTO messages SET ?',
                        {
                          // msgid: FIXME,
                          wildcard_sub_id: wildcardId,
                          sub_id: subId,
                          class: new Buffer(msg.class),
                          instance: new Buffer(msg.instance),
                          time: msg.time,
                          auth: msg.auth,
                          sender: new Buffer(msg.sender),
                          recipient: new Buffer(msg.recipient),
                          realm: new Buffer(msg.realm),
                          opcode: new Buffer(msg.opcode),
                          signature: new Buffer(msg.signature),
                          message: new Buffer(msg.message),
                        });
    }.bind(this));
  }.bind(this));
};

// TODO: Might want to support other queries? Yeah, I dunno.
Connection.prototype.getMessagesAfter = function(user, msgId, limit) {
  // For sanity, pick a random limit.
  limit = Math.min(limit, MAX_MESSAGES_RETURNED);

  return this.query(
    'SELECT DISTINCT messages.* ' +
    'FROM messages JOIN subs ON (subs.id = messages.sub_id OR ' +
                                'subs.id = messages.wildcard_sub_id) ' +
    'JOIN user_subs ON user_subs.sub_id = subs.id ' +
    'WHERE user_subs.user_id = ? AND ' +
      'messages.id >= ? AND ' +
      'messages.id >= user_subs.start AND ' +
      '(user_subs.end IS NULL OR messages.id < user_subs.end) ' +
    'ORDER BY id ASC ' +
    'LIMIT ?',
    [user, msgId, limit]
  ).then(function(rows) {
    return rows.map(function(row) {
      return {
        id: row.id, // FIXME: opaque ids.
        time: row.time,
        class: row.class.toString('utf8'),
        instance: row.instance.toString('utf8'),
        sender: row.sender.toString('utf8'),
        recipient: row.recipient.toString('utf8'),
        realm: row.realm.toString('utf8'),
        auth: row.auth,
        opcode: row.opcode.toString('utf8'),
        signature: row.signature.toString('utf8'),
        message: row.message.toString('utf8')
      };
    });
  });
};

var getConnection = function() {
  return Q.ninvoke(pool, 'getConnection').then(function(conn) {
    return new Connection(conn);
  });
};

exports.addUserSubscription = function(user, klass, inst, recip) {
  return getConnection().then(function(conn) {
    return conn.addUserSubscription(user, klass, inst, recip).finally(
      conn.end.bind(conn));
  });
};

exports.removeUserSubscription = function(user, klass, inst, recip) {
  return getConnection().then(function(conn) {
    return conn.removeUserSubscription(user, klass, inst, recip).finally(
      conn.end.bind(conn));
  });
};

exports.getUserSubscriptions = function(user) {
  return getConnection().then(function(conn) {
    return conn.getUserSubscriptions(user).finally(conn.end.bind(conn));
  });
};

exports.loadActiveSubs = function() {
  return getConnection().then(function(conn) {
    return conn.loadActiveSubs().finally(conn.end.bind(conn));
  });
};

exports.saveMessage = function(msg) {
  return getConnection().then(function(conn) {
    return conn.saveMessage(msg).finally(conn.end.bind(conn));
  });
};

exports.getMessagesAfter = function(user, msgId, limit) {
  return getConnection().then(function(conn) {
    return conn.getMessagesAfter(user, msgId, limit).finally(conn.end.bind(conn));
  });
};
<|endoftext|>


<commit_before><commit_msg>Add functions for days and months as well<commit_after><|endoftext|>


<commit_before>
((module) => {
	'use strict';

	var createClassFromSuper = require('simple-class-utils').createClass.super.handleArgs;
	var createClass = require('./create-class.js');
	var isIterable = require('./utils/is-iterable.js');
	var Root = require('./root.js').class;

	const EMPTY_ITERABLE = require('./utils/empty-iterable.js');
	const EMPTY_GENERATOR = EMPTY_ITERABLE.EMPTY_GENERATOR;

	var _key_iterator = Symbol.iterator;

	class DeepIterable extends Root {

		constructor(base, deeper, shallower) {
			super();
			this.base = base;
			this.deeper = typeof deeper === 'function' ? deeper : DeepIterable.DEFAULT_DEEPER;
			this.shallower = typeof shallower === 'function' ? shallower : DeepIterable.DEFAULT_SHALLOWER;
		}

		* [_key_iterator]() {
			var deeper = this.deeper;
			var base = this.base;
			var shallower = this.shallower;
			if (isIterable(base) && deeper(base, this)) {
				for (let element of base) {
					yield * new DeepIterable(element, deeper, shallower);
				}
				shallower(base, this);
			} else {
				yield base;
			}
		}

		circular(equal) {
			return new DeepIterable.Circular(this.base, this.deeper, equal);
		}

		static createXIterableClass(Base, deeper) {
			return createClassFromSuper(DeepIterable, (...args) => [new Base(...args), deeper]);
		}

		static ANY_DEEPER(iterable) {
			return true;
		}

		static OBJECT_DEEPER(object) {
			return typeof object === 'object';
		}

		static STRING_DEEPER(string) {
			return typeof string !== 'string' || string.length > 1;
		}

		static CHAR_DEEPER(string) {
			return typeof string !== 'string' || string.length !== 1;
		}

		static LENGTHINESS_DEEPER(lengthiness) {
			return lengthiness.length > 1;
		}

	}

	var Export = module.exports = createClass(DeepIterable);

	DeepIterable.DEFAULT_DEEPER = DeepIterable.OBJECT_DEEPER;
	DeepIterable.DEFAULT_SHALLOWER = (() => {});

	DeepIterable.PreProcessed = createClass.fromGenerator((base, preprocess, ...args) => {

		var iterate = (object) =>
			new Export(preprocess(object) || EMPTY_ITERABLE), ...args)
				.transform(iterate);

		return iterate(base)[_key_iterator]();

	});

	DeepIterable.Circular = createClass(class extends Root {

		constructor(base, deeper, equal, circular) {
			super();
			this.base = base;
			this.deeper = typeof deeper === 'function' ? deeper : DeepIterable.DEFAULT_DEEPER;
			this.equal = typeof equal === 'function' ? equal : Object.is;
			this.circular = typeof circular === 'function' ? circular : DeepIterable.Circular.DEFAULT_CIRCULAR_HANDLER;
		}

		[Symbol.iterator]() {
			var self = this;
			var parents = [];
			var circular = self.circular;
			return iterate(self.base, self.deeper, self.equal);
			function * iterate(base, deeper, equal) {
				if (isIterable(base) && deeper(base, self)) {
					if (parents.find((element) => equal(base, element))) {
						yield * circular(base, self) || EMPTY_GENERATOR;
					} else {
						parents.push(base);
						for (let element of base) {
							yield * iterate(element, deeper, equal);
						}
						parents.pop();
					}
				} else {
					yield base;
				}
			}
		}

		static DEFAULT_CIRCULAR_HANDLER(object) {
			return object;
		}

	});

})(module);
<commit_msg>fix syntax error<commit_after>
((module) => {
	'use strict';

	var createClassFromSuper = require('simple-class-utils').createClass.super.handleArgs;
	var createClass = require('./create-class.js');
	var isIterable = require('./utils/is-iterable.js');
	var Root = require('./root.js').class;

	const EMPTY_ITERABLE = require('./utils/empty-iterable.js');
	const EMPTY_GENERATOR = EMPTY_ITERABLE.EMPTY_GENERATOR;

	var _key_iterator = Symbol.iterator;

	class DeepIterable extends Root {

		constructor(base, deeper, shallower) {
			super();
			this.base = base;
			this.deeper = typeof deeper === 'function' ? deeper : DeepIterable.DEFAULT_DEEPER;
			this.shallower = typeof shallower === 'function' ? shallower : DeepIterable.DEFAULT_SHALLOWER;
		}

		* [_key_iterator]() {
			var deeper = this.deeper;
			var base = this.base;
			var shallower = this.shallower;
			if (isIterable(base) && deeper(base, this)) {
				for (let element of base) {
					yield * new DeepIterable(element, deeper, shallower);
				}
				shallower(base, this);
			} else {
				yield base;
			}
		}

		circular(equal) {
			return new DeepIterable.Circular(this.base, this.deeper, equal);
		}

		static createXIterableClass(Base, deeper) {
			return createClassFromSuper(DeepIterable, (...args) => [new Base(...args), deeper]);
		}

		static ANY_DEEPER(iterable) {
			return true;
		}

		static OBJECT_DEEPER(object) {
			return typeof object === 'object';
		}

		static STRING_DEEPER(string) {
			return typeof string !== 'string' || string.length > 1;
		}

		static CHAR_DEEPER(string) {
			return typeof string !== 'string' || string.length !== 1;
		}

		static LENGTHINESS_DEEPER(lengthiness) {
			return lengthiness.length > 1;
		}

	}

	var Export = module.exports = createClass(DeepIterable);

	DeepIterable.DEFAULT_DEEPER = DeepIterable.OBJECT_DEEPER;
	DeepIterable.DEFAULT_SHALLOWER = (() => {});

	DeepIterable.PreProcessed = createClass.fromGenerator((base, preprocess, ...args) => {

		var iterate = (object) =>
			new Export((preprocess(object) || EMPTY_ITERABLE), ...args)
				.transform(iterate);

		return iterate(base)[_key_iterator]();

	});

	DeepIterable.Circular = createClass(class extends Root {

		constructor(base, deeper, equal, circular) {
			super();
			this.base = base;
			this.deeper = typeof deeper === 'function' ? deeper : DeepIterable.DEFAULT_DEEPER;
			this.equal = typeof equal === 'function' ? equal : Object.is;
			this.circular = typeof circular === 'function' ? circular : DeepIterable.Circular.DEFAULT_CIRCULAR_HANDLER;
		}

		[Symbol.iterator]() {
			var self = this;
			var parents = [];
			var circular = self.circular;
			return iterate(self.base, self.deeper, self.equal);
			function * iterate(base, deeper, equal) {
				if (isIterable(base) && deeper(base, self)) {
					if (parents.find((element) => equal(base, element))) {
						yield * circular(base, self) || EMPTY_GENERATOR;
					} else {
						parents.push(base);
						for (let element of base) {
							yield * iterate(element, deeper, equal);
						}
						parents.pop();
					}
				} else {
					yield base;
				}
			}
		}

		static DEFAULT_CIRCULAR_HANDLER(object) {
			return object;
		}

	});

})(module);
<|endoftext|>


<commit_before><commit_msg>Fix stupid bug in result.charge assignment<commit_after><|endoftext|>


<commit_before>/*
 * Use Cluster to fork this process same number of times as we have cpus!
 */

var cluster = require('cluster'), cpus = require('os').cpus().length;

if (cluster.isMaster) {

  for (var i=0; i<cpus; i++) {
    cluster.fork();
  }
  cluster.on('exit', function () {
    cluster.fork();
  });
  return;
}

/*
 * We are a child process now
 */

/*
 * Get Express up and running
 */

var app = require('express')();
app.get('/', function (req, res) {
  res.sendfile(__dirname+'/public/index.html');
});

/*
 * Create a Server to attach our Express app
 */

var server = require('http').Server(app).listen(process.env.PORT || 3000);

/*
 * Get a Bus and using our Server
 */

var bus = require('bus.io')(server);

/*
 * We want our socket to receive messages when sent to everyone
 */

bus.socket(function (socket, bus) {
  bus.alias(socket, 'everyone');
});

/*
 * For all messages we will set the message actor to either the socket.name or
 * socket.id
 */

bus.in(function (message, socket, next) {
  message.actor(socket.name || socket.id);
  next();
});

/*
 * When we receive a "set name" event from the socket store that on the socket
 * and deliver() the message to the Exchange.
 */

bus.in('set name', function (message, socket) {
  socket.name = message.content();
  message.deliver();
});

/*
 * When we receive a "post" event from the socket, cap the content length to
 * 128 characters.
 */

bus.in('post', function (message, socket) {
  message.target(message.content().pop());
  if (message.content().length && message.content()[0].length > 128) {
    message.content(message.content().slice(0,125)+'...');
  }
  message.deliver();
});

/*
 * When the Bus finnaly gets the "post" message just deliver to the target.
 */

bus.on('post', function (message) {
  message.deliver();
});

/*
 * When the Bus finally gets the "set name" message just deliver to the target.
 */

bus.on('set name', function (message) {
  message.deliver();
});

/*
 * Before we deliver the "set name" event to the socekt,  alias the socket to
 * the "name".
 */

bus.out('set name', function (message, socket, next) {
  bus.alias(socket, message.content());
  next();
});
<commit_msg>updated the doc<commit_after>/*
 * Use Cluster to fork this process same number of times as we have cpus!
 */

var cluster = require('cluster'), cpus = require('os').cpus().length;

if (cluster.isMaster) {

  for (var i=0; i<cpus; i++) {
    cluster.fork();
  }
  cluster.on('exit', function () {
    cluster.fork();
  });
  return;
}

/*
 * We are a child process now
 */

/*
 * Get Express up and running
 */

var app = require('express')();
app.get('/', function (req, res) {
  res.sendfile(__dirname+'/public/index.html');
});

/*
 * Create a Server to attach our Express app
 */

var server = require('http').Server(app).listen(process.env.PORT || 3000);

/*
 * Get a Bus and using our Server
 */

var bus = require('bus.io')(server);

/*
 * We want our socket to receive messages when sent to everyone
 */

bus.socket(function (socket, bus) {
  bus.alias(socket, 'everyone');
});

/*
 * For all messages we will set the message actor to either the socket.name or
 * socket.id. We are handling this message before it gets on the Bus.
 */

bus.in(function (message, socket, next) {
  message.actor(socket.name || socket.id);
  next();
});

/*
 * When we receive a "set name" event from the socket store that on the socket
 * and deliver() the message to the Exchange.  We are handling this message
 * before it gets on the Bus.
 */

bus.in('set name', function (message, socket) {
  socket.name = message.content();
  message.deliver();
});

/*
 * When we receive a "post" event from the socket, cap the content length to
 * 128 characters.  We are handling this message before it gets on the Bus.
 */

bus.in('post', function (message, socket) {
  message.target(message.content().pop());
  if (message.content().length && message.content()[0].length > 128) {
    message.content(message.content().slice(0,125)+'...');
  }
  message.deliver();
});

/*
 * When the Bus finnaly gets the "post" message just deliver to the target.  We
 * are handling this message on the Bus.
 */

bus.on('post', function (message) {
  message.deliver();
});

/*
 * When the Bus finally gets the "set name" message just deliver to the target.
 * We are handling this message on the Bus.
 */

bus.on('set name', function (message) {
  message.deliver();
});

/*
 * Before we deliver the "set name" event to the socekt,  alias the socket to
 * the "name". We are handling this message after it left the bus and on its
 * way to the socket.
 */

bus.out('set name', function (message, socket, next) {
  bus.alias(socket, message.content());
  next();
});
<|endoftext|>


<commit_before><commit_msg>remove focusentity timeout<commit_after><|endoftext|>