<commit_before>function GLApp() {

  // Context
  this.glc = new GLContext("canvas-gl");
  this.gl = this.glc.gl;

  // Shaders
  this.vertexShader = this.glc.newShader("shader-vertex");
  this.fragmentShader = this.glc.newShader("shader-fragment");
  this.glProgram = this.glc.newProgram([this.vertexShader, this.fragmentShader]);
  this.glProgram.use();

  // Vertext Shader Attributes/Uniforms
  this.position = this.glProgram.getAttribute("vPosition", 2);
  this.twist = this.glProgram.getUniform("twist", 1);
  this.scale = this.glProgram.getUniform("scale", 1);

  this.corners = document.getElementById("input-corners");
  this.centers = document.getElementById("input-centers");
  this.depthSpan = document.getElementById("division-depth");
  this.twistSpan = document.getElementById("twist");
  this.scaleSpan = document.getElementById("scale");

  function tesselateTriangle(a, b, c, counter, corners, centers) {
    if (counter == 0) {
      corners.push(a);
      corners.push(b);
      corners.push(c);
    } else {
      var ab = a.mix(b, 0.5);
      var bc = b.mix(c, 0.5);
      var ca = c.mix(a, 0.5);
      var newCounter = counter - 1;
      tesselateTriangle(a, ab, ca, newCounter, corners, centers);
      tesselateTriangle(ab, b, bc, newCounter, corners, centers);
      tesselateTriangle(ca, bc, c, newCounter, corners, centers);
      tesselateTriangle(ab, bc, ca, newCounter, centers, centers);
    }
    return {
      'corners' : corners,
      'centers' : centers
    };
  }

  function getVectors(depth) {
    return tesselateTriangle(
      vec([-0.5, -0.3]),
      vec([0.0, 0.6]),
      vec([0.5, -0.3]),
      depth, [], []
    );
  }

  this.depth = 7;
  this.vectors = getVectors(this.depth);
  this.depthSpan.innerHTML = this.depth;

  // Data Buffers
  this.cornersBuffer = this.glc.newBuffer(vec(this.vectors.corners).flatten());
  this.centersBuffer = this.glc.newBuffer(vec(this.vectors.centers).flatten());

  /* App Methods */

  this.draw = function() {
    this.gl.clear(this.gl.COLOR_BUFFER_BIT);

    if (this.corners.checked) {
      this.position.bindTo(this.cornersBuffer, 0, 0);
      this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vectors.corners.length);
    }

    if (this.centers.checked) {
      this.position.bindTo(this.centersBuffer, 0, 0);
      this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vectors.centers.length);
    }

    this.gl.flush();
  }

  this.setTwist = function(value) {
    this.twist.set([value]);
    this.twistSpan.innerHTML = Math.round(value * 1000) / 1000;
  }

  this.setScale = function(value) {
    this.scale.set([value]);
    this.scaleSpan.innerHTML = Math.round(value * 1000) / 1000;
  }

  this.incDivision = function() {
    if (this.depth < 9) {
      this.depth++;
      this.refrechVectors();
    }
  }

  this.decDivision = function() {
    if (this.depth > 0) {
      this.depth--;
      this.refrechVectors();
    }
  }

  this.refrechVectors = function() {
    this.vectors = getVectors(this.depth);
    this.depthSpan.innerHTML = this.depth;
    this.cornersBuffer.setBuffer(vec(this.vectors.corners).flatten());
    this.centersBuffer.setBuffer(vec(this.vectors.centers).flatten());
  }

  // First Frame
  this.gl.clearColor(1.0, 1.0, 1.0, 1.0);
  this.setTwist(0);
  this.setScale(1);
  this.draw();
}

var PI = 3.1415926;
var app = null;

function init() {
  app = new GLApp();
}

function move(e) {
  if (e.buttons != 0) {
    doMove(e);
  }
}

function touch(e) {
  if (e.changedTouches.length != 0) {
    var t = e.changedTouches[0]
    doMove(t);
  }
}

function doMove(e) {
  if (document.getElementById("input-scale").checked) {
    app.setScale(4 * (e.target.height - e.clientY + e.target.offsetTop) / e.target.height - 2);
  }
  if (document.getElementById("input-twist").checked) {
    app.setTwist(4 * PI * (e.clientX - e.target.offsetLeft) / e.target.width - 2 * PI);
  }
  app.draw();
}

function redraw(e) {
  app.draw();
}

function incDivision(e) {
  app.incDivision();
  app.draw();
}

function decDivision(e) {
  app.decDivision();
  app.draw();
}

<commit_msg>Preventing annoying scrolling<commit_after>function GLApp() {

  // Context
  this.glc = new GLContext("canvas-gl");
  this.gl = this.glc.gl;

  // Shaders
  this.vertexShader = this.glc.newShader("shader-vertex");
  this.fragmentShader = this.glc.newShader("shader-fragment");
  this.glProgram = this.glc.newProgram([this.vertexShader, this.fragmentShader]);
  this.glProgram.use();

  // Vertext Shader Attributes/Uniforms
  this.position = this.glProgram.getAttribute("vPosition", 2);
  this.twist = this.glProgram.getUniform("twist", 1);
  this.scale = this.glProgram.getUniform("scale", 1);

  this.corners = document.getElementById("input-corners");
  this.centers = document.getElementById("input-centers");
  this.depthSpan = document.getElementById("division-depth");
  this.twistSpan = document.getElementById("twist");
  this.scaleSpan = document.getElementById("scale");

  function tesselateTriangle(a, b, c, counter, corners, centers) {
    if (counter == 0) {
      corners.push(a);
      corners.push(b);
      corners.push(c);
    } else {
      var ab = a.mix(b, 0.5);
      var bc = b.mix(c, 0.5);
      var ca = c.mix(a, 0.5);
      var newCounter = counter - 1;
      tesselateTriangle(a, ab, ca, newCounter, corners, centers);
      tesselateTriangle(ab, b, bc, newCounter, corners, centers);
      tesselateTriangle(ca, bc, c, newCounter, corners, centers);
      tesselateTriangle(ab, bc, ca, newCounter, centers, centers);
    }
    return {
      'corners' : corners,
      'centers' : centers
    };
  }

  function getVectors(depth) {
    return tesselateTriangle(
      vec([-0.5, -0.3]),
      vec([0.0, 0.6]),
      vec([0.5, -0.3]),
      depth, [], []
    );
  }

  this.depth = 7;
  this.vectors = getVectors(this.depth);
  this.depthSpan.innerHTML = this.depth;

  // Data Buffers
  this.cornersBuffer = this.glc.newBuffer(vec(this.vectors.corners).flatten());
  this.centersBuffer = this.glc.newBuffer(vec(this.vectors.centers).flatten());

  /* App Methods */

  this.draw = function() {
    this.gl.clear(this.gl.COLOR_BUFFER_BIT);

    if (this.corners.checked) {
      this.position.bindTo(this.cornersBuffer, 0, 0);
      this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vectors.corners.length);
    }

    if (this.centers.checked) {
      this.position.bindTo(this.centersBuffer, 0, 0);
      this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vectors.centers.length);
    }

    this.gl.flush();
  }

  this.setTwist = function(value) {
    this.twist.set([value]);
    this.twistSpan.innerHTML = Math.round(value * 1000) / 1000;
  }

  this.setScale = function(value) {
    this.scale.set([value]);
    this.scaleSpan.innerHTML = Math.round(value * 1000) / 1000;
  }

  this.incDivision = function() {
    if (this.depth < 9) {
      this.depth++;
      this.refrechVectors();
    }
  }

  this.decDivision = function() {
    if (this.depth > 0) {
      this.depth--;
      this.refrechVectors();
    }
  }

  this.refrechVectors = function() {
    this.vectors = getVectors(this.depth);
    this.depthSpan.innerHTML = this.depth;
    this.cornersBuffer.setBuffer(vec(this.vectors.corners).flatten());
    this.centersBuffer.setBuffer(vec(this.vectors.centers).flatten());
  }

  // First Frame
  this.gl.clearColor(1.0, 1.0, 1.0, 1.0);
  this.setTwist(0);
  this.setScale(1);
  this.draw();
}

var PI = 3.1415926;
var app = null;

function init() {
  app = new GLApp();
}

function move(e) {
  if (e.buttons != 0) {
    doMove(e);
  }
}

function touch(e) {
  if (e.changedTouches.length != 0) {
    var t = e.changedTouches[0]
    doMove(t);
  }
  e.preventDefault();
}

function doMove(e) {
  if (document.getElementById("input-scale").checked) {
    app.setScale(4 * (e.target.height - e.clientY + e.target.offsetTop) / e.target.height - 2);
  }
  if (document.getElementById("input-twist").checked) {
    app.setTwist(4 * PI * (e.clientX - e.target.offsetLeft) / e.target.width - 2 * PI);
  }
  app.draw();
}

function redraw(e) {
  app.draw();
}

function incDivision(e) {
  app.incDivision();
  app.draw();
}

function decDivision(e) {
  app.decDivision();
  app.draw();
}

<|endoftext|>


<commit_before>jQuery(document).ready(function(){
	geocoder = new google.maps.Geocoder();

		jQuery('#geotag-search-button').click(function(){
			//alert(jQuery('#geotag-search').val());
			geocode(jQuery('#geotag-search').val());
		});
});

function geocode(address)
{
  geocoder.geocode( {address:address}, function(results, status)
  {
    if (status == google.maps.GeocoderStatus.OK)
    {
		console.log(results[0]);
		jQuery('#geotag-latitude').val(results[0].geometry.location.k);
		jQuery('#geotag-longitude').val(results[0].geometry.location.D);
    } else {
      alert('Geocode was not successful for the following reason: ' + status);
   }
  });
}<commit_msg>remove comment<commit_after>jQuery(document).ready(function(){
	geocoder = new google.maps.Geocoder();

		jQuery('#geotag-search-button').click(function(){
			geocode(jQuery('#geotag-search').val());
		});
});

function geocode(address)
{
  geocoder.geocode( {address:address}, function(results, status)
  {
    if (status == google.maps.GeocoderStatus.OK)
    {
		console.log(results[0]);
		jQuery('#geotag-latitude').val(results[0].geometry.location.k);
		jQuery('#geotag-longitude').val(results[0].geometry.location.D);
    } else {
      alert('Geocode was not successful for the following reason: ' + status);
   }
  });
}<|endoftext|>


<commit_before>import { comparators, helpers } from 'utils/index';
import template from '../../templates/gridheader.hbs';
import InfoButtonView from './InfoButtonView';
import InfoMessageView from './InfoMessageView';

/**
 * @name GridHeaderView
 * @memberof module:core.list.views
 * @class GridHeaderView
 * @constructor
 * @description View используемый для отображения заголовка (шапки) списка
 * @extends Marionette.View
 * @param {Object} options Constructor options
 * @param {Array} options.columns массив колонок
 * @param {Object} options.gridEventAggregator ?
 * */

const classes = {
    expanded: 'collapsible-btn_expanded',
    dragover: 'dragover'
};

const GridHeaderView = Marionette.View.extend({
    initialize(options) {
        if (!options.columns) {
            throw new Error('You must provide columns definition ("columns" option)');
        }
        if (!options.gridEventAggregator) {
            throw new Error('You must provide grid event aggregator ("gridEventAggregator" option)');
        }

        this.gridEventAggregator = options.gridEventAggregator;
        this.collection = options.gridEventAggregator.collection;

        this.styleSheet = options.styleSheet;
        this.listenTo(this.collection, 'dragover:head', this.__handleModelDragOver);
        this.listenTo(this.collection, 'dragleave:head', this.__handleModelDragLeave);
        this.listenTo(this.collection, 'drop:head', this.__handleModelDrop);
        _.bindAll(this, '__draggerMouseUp', '__draggerMouseMove', '__handleColumnSort');
        this.listenTo(this.gridEventAggregator, 'update:collapse:all', this.__updateCollapseAll);
    },

    template: Handlebars.compile(template),

    className: 'grid-header',

    ui: {
        gridHeaderColumn: '.grid-header-column'
    },

    events: {
        'mousedown .grid-header-dragger': '__handleDraggerMousedown',
        'click .js-collapsible-button': '__toggleCollapseAll',
        dragover: '__handleDragOver',
        dragenter: '__handleDragEnter',
        dragleave: '__handleDragLeave',
        drop: '__handleDrop',
        'mouseover .grid-header-column': '__handleColumnSelect',
        'click .grid-header-column': '__handleColumnSelect',
        'click .grid-header-column-title': '__handleColumnSort',
        'click .js-help-text-region': '__handleHelpMenuClick',
        mouseleave: '__onMouseLeaveHeader'
    },

    constants: {
        MIN_COLUMN_WIDTH: 50
    },

    templateContext() {
        return {
            columns: this.options.columns.map(column =>
                Object.assign({}, column, {
                    sortingAsc: column.sorting === 'asc',
                    sortingDesc: column.sorting === 'desc'
                })
            )
        };
    },

    onRender() {
        if (this.options.isTree) {
            this.$el
                .children()[0]
                .insertAdjacentHTML(
                    'afterbegin',
                    `<span class="collapsible-btn js-collapsible-button ${this.getOption('expandOnShow') === true ? classes.expanded : ''}"></span> `
                );
        }

        this.ui.gridHeaderColumn.each((i, el) => {
            const column = this.options.columns[i];
            const helpText = column.helpText;

            if (helpText) {
                this.addRegion(`popoutRegion${i}`, { el: el.querySelector('.js-help-text-region') });

                const infoPopout = Core.dropdown.factory.createPopout({
                    buttonView: InfoButtonView,
                    panelView: InfoMessageView,
                    panelViewOptions: {
                        text: helpText
                    },
                    popoutFlow: 'right',
                    customAnchor: true,
                    class: 'collection-grid-header__help'
                });
                this.showChildView(`popoutRegion${i}`, infoPopout);
            }
        });
    },

    updateSorting() {
        this.render();
    },

    __handleColumnSort(event) {
        if (this.options.columnSort === false) {
            return;
        }
        if (event.target.className.includes('js-collapsible-button')) {
            return;
        }
        const column = this.options.columns[Array.prototype.indexOf.call(event.currentTarget.parentElement.parentElement.children, event.currentTarget.parentElement)];
        const sorting = column.sorting === 'asc' ? 'desc' : 'asc';
        this.options.columns.forEach(c => (c.sorting = null));
        column.sorting = sorting;
        let comparator = sorting === 'desc' ? column.sortDesc : column.sortAsc;
        if (!comparator) {
            comparator = helpers.comparatorFor(comparators.getComparatorByDataType(column.dataType || column.type, sorting), column.key);
        }
        if (comparator) {
            this.updateSorting();
            this.trigger('onColumnSort', column, comparator);
        }
    },

    __handleDraggerMousedown(e) {
        this.__stopDrag();
        this.__startDrag(e);
        this.trigger('header:columnResizeStarted');
        return false;
    },

    __getElementOuterWidth(el) {
        return el.getBoundingClientRect().width;
    },

    __startDrag(e) {
        const dragger = e.target;
        const column = dragger.parentNode;

        const draggedColumn = {
            el: column,
            initialWidth: this.__getElementOuterWidth(column),
            index: Array.prototype.indexOf.call(column.parentNode.children, column)
        };

        this.dragContext = {
            pageOffsetX: e.pageX,
            dragger,
            draggedColumn
        };

        dragger.classList.add('active');

        document.addEventListener('mousemove', this.__draggerMouseMove);
        document.addEventListener('mouseup', this.__draggerMouseUp);
    },

    __stopDrag() {
        if (!this.dragContext) {
            return;
        }

        this.dragContext.dragger.classList.remove('active');
        this.dragContext = null;

        document.removeEventListener('mousemove', this.__draggerMouseMove);
        document.removeEventListener('mouseup', this.__draggerMouseUp);
    },

    __draggerMouseMove(e) {
        if (!this.dragContext) {
            return;
        }

        const ctx = this.dragContext;
        const delta = e.pageX - ctx.pageOffsetX;

        if (delta !== 0) {
            const index = ctx.draggedColumn.index;

            this.updateColumnAndNeighbourWidths(index, delta);
        }

        return false;
    },

    __draggerMouseUp() {
        this.__stopDrag();
        this.trigger('header:columnResizeFinished');
        return false;
    },

    __getFullWidth() {
        return this.el.clientWidth;
    },

    onAttach() {
        this.trigger('set:emptyView:width', this.el.scrollWidth);
    },

    updateColumnAndNeighbourWidths(index, delta) {
        const newColumnWidth = this.dragContext.draggedColumn.initialWidth + delta;

        if (newColumnWidth < this.constants.MIN_COLUMN_WIDTH) {
            return;
        }

        this.trigger('update:width', index, newColumnWidth, this.el.scrollWidth);

        this.gridEventAggregator.trigger('singleColumnResize', newColumnWidth);

        this.el.style.width = `${this.dragContext.tableInitialWidth + delta + 1}px`;
        this.options.columns[index].width = newColumnWidth;
    },

    __toggleCollapseAll() {
        this.__updateCollapseAll(!this.collapsed);
        this.gridEventAggregator.trigger('toggle:collapse:all', this.collapsed);
    },

    __updateCollapseAll(collapsed) {
        this.collapsed = collapsed;
        this.$('.js-collapsible-button').toggleClass(classes.expanded, !collapsed);
    },

    __handleDragOver(event) {
        if (!this.collection.draggingModel) {
            return;
        }
        event.preventDefault();
    },

    __handleDragEnter(event) {
        this.collection.dragoverModel = undefined;
        if (this.__allowDrop()) {
            this.collection.trigger('dragover:head', event);
        }
    },

    __handleModelDragOver() {
        this.el.parentElement && this.el.parentElement.classList.add(classes.dragover);
    },

    __handleDragLeave(event) {
        if (this.collection.dragoverModel !== undefined) {
            this.collection.trigger('dragleave:head', event);
        }
    },

    __handleModelDragLeave() {
        this.el.parentElement && this.el.parentElement.classList.remove(classes.dragover);
    },

    __handleDrop(event) {
        event.preventDefault();
        if (this.__allowDrop()) {
            this.collection.trigger('drop:head', event);
        }
    },

    __allowDrop() {
        if (!this.collection.draggingModel || this.collection.indexOf(this.collection.draggingModel) < 0) {
            return false;
        }
        return true;
    },

    __handleModelDrop() {
        this.el.parentElement && this.el.parentElement.classList.remove(classes.dragover);
        if (this.collection.draggingModel) {
            this.trigger('drag:drop', this.collection.draggingModel, this.model);
        }
    },

    __handleColumnSelect(event) {
        const { currentTarget } = event;
        if (!document.contains(currentTarget)) {
            return;
        }
        this.trigger('handleColumnSelect', {
            event,
            el: currentTarget,
            model: this.options.columns[Array.prototype.indexOf.call(currentTarget.parentElement.children, currentTarget)]
        });
    },

    __onMouseLeaveHeader(event) {
        this.trigger('handleLeave', event);
    }
});

export default GridHeaderView;
<commit_msg>Fix IE support<commit_after>import { comparators, helpers } from 'utils/index';
import template from '../../templates/gridheader.hbs';
import InfoButtonView from './InfoButtonView';
import InfoMessageView from './InfoMessageView';

/**
 * @name GridHeaderView
 * @memberof module:core.list.views
 * @class GridHeaderView
 * @constructor
 * @description View используемый для отображения заголовка (шапки) списка
 * @extends Marionette.View
 * @param {Object} options Constructor options
 * @param {Array} options.columns массив колонок
 * @param {Object} options.gridEventAggregator ?
 * */

const classes = {
    expanded: 'collapsible-btn_expanded',
    dragover: 'dragover'
};

const GridHeaderView = Marionette.View.extend({
    initialize(options) {
        if (!options.columns) {
            throw new Error('You must provide columns definition ("columns" option)');
        }
        if (!options.gridEventAggregator) {
            throw new Error('You must provide grid event aggregator ("gridEventAggregator" option)');
        }

        this.gridEventAggregator = options.gridEventAggregator;
        this.collection = options.gridEventAggregator.collection;

        this.styleSheet = options.styleSheet;
        this.listenTo(this.collection, 'dragover:head', this.__handleModelDragOver);
        this.listenTo(this.collection, 'dragleave:head', this.__handleModelDragLeave);
        this.listenTo(this.collection, 'drop:head', this.__handleModelDrop);
        _.bindAll(this, '__draggerMouseUp', '__draggerMouseMove', '__handleColumnSort');
        this.listenTo(this.gridEventAggregator, 'update:collapse:all', this.__updateCollapseAll);
    },

    template: Handlebars.compile(template),

    className: 'grid-header',

    ui: {
        gridHeaderColumn: '.grid-header-column'
    },

    events: {
        'mousedown .grid-header-dragger': '__handleDraggerMousedown',
        'click .js-collapsible-button': '__toggleCollapseAll',
        dragover: '__handleDragOver',
        dragenter: '__handleDragEnter',
        dragleave: '__handleDragLeave',
        drop: '__handleDrop',
        'mouseover .grid-header-column': '__handleColumnSelect',
        'click .grid-header-column': '__handleColumnSelect',
        'click .grid-header-column-title': '__handleColumnSort',
        'click .js-help-text-region': '__handleHelpMenuClick',
        mouseleave: '__onMouseLeaveHeader'
    },

    constants: {
        MIN_COLUMN_WIDTH: 50
    },

    templateContext() {
        return {
            columns: this.options.columns.map(column =>
                Object.assign({}, column, {
                    sortingAsc: column.sorting === 'asc',
                    sortingDesc: column.sorting === 'desc'
                })
            )
        };
    },

    onRender() {
        if (this.options.isTree) {
            this.$el
                .children()[0]
                .insertAdjacentHTML(
                    'afterbegin',
                    `<span class="collapsible-btn js-collapsible-button ${this.getOption('expandOnShow') === true ? classes.expanded : ''}"></span> `
                );
        }

        this.ui.gridHeaderColumn.each((i, el) => {
            const column = this.options.columns[i];
            const helpText = column.helpText;

            if (helpText) {
                this.addRegion(`popoutRegion${i}`, { el: el.querySelector('.js-help-text-region') });

                const infoPopout = Core.dropdown.factory.createPopout({
                    buttonView: InfoButtonView,
                    panelView: InfoMessageView,
                    panelViewOptions: {
                        text: helpText
                    },
                    popoutFlow: 'right',
                    customAnchor: true,
                    class: 'collection-grid-header__help'
                });
                this.showChildView(`popoutRegion${i}`, infoPopout);
            }
        });
    },

    updateSorting() {
        this.render();
    },

    __handleColumnSort(event) {
        if (this.options.columnSort === false) {
            return;
        }
        if (event.target.className.includes('js-collapsible-button')) {
            return;
        }
        const column = this.options.columns[Array.prototype.indexOf.call(event.currentTarget.parentElement.parentElement.children, event.currentTarget.parentElement)];
        const sorting = column.sorting === 'asc' ? 'desc' : 'asc';
        this.options.columns.forEach(c => (c.sorting = null));
        column.sorting = sorting;
        let comparator = sorting === 'desc' ? column.sortDesc : column.sortAsc;
        if (!comparator) {
            comparator = helpers.comparatorFor(comparators.getComparatorByDataType(column.dataType || column.type, sorting), column.key);
        }
        if (comparator) {
            this.updateSorting();
            this.trigger('onColumnSort', column, comparator);
        }
    },

    __handleDraggerMousedown(e) {
        this.__stopDrag();
        this.__startDrag(e);
        this.trigger('header:columnResizeStarted');
        return false;
    },

    __getElementOuterWidth(el) {
        return el.getBoundingClientRect().width;
    },

    __startDrag(e) {
        const dragger = e.target;
        const column = dragger.parentNode;

        const draggedColumn = {
            el: column,
            initialWidth: this.__getElementOuterWidth(column),
            index: Array.prototype.indexOf.call(column.parentNode.children, column)
        };

        this.dragContext = {
            pageOffsetX: e.pageX,
            dragger,
            draggedColumn
        };

        dragger.classList.add('active');

        document.addEventListener('mousemove', this.__draggerMouseMove);
        document.addEventListener('mouseup', this.__draggerMouseUp);
    },

    __stopDrag() {
        if (!this.dragContext) {
            return;
        }

        this.dragContext.dragger.classList.remove('active');
        this.dragContext = null;

        document.removeEventListener('mousemove', this.__draggerMouseMove);
        document.removeEventListener('mouseup', this.__draggerMouseUp);
    },

    __draggerMouseMove(e) {
        if (!this.dragContext) {
            return;
        }

        const ctx = this.dragContext;
        const delta = e.pageX - ctx.pageOffsetX;

        if (delta !== 0) {
            const index = ctx.draggedColumn.index;

            this.updateColumnAndNeighbourWidths(index, delta);
        }

        return false;
    },

    __draggerMouseUp() {
        this.__stopDrag();
        this.trigger('header:columnResizeFinished');
        return false;
    },

    __getFullWidth() {
        return this.el.clientWidth;
    },

    onAttach() {
        this.trigger('set:emptyView:width', this.el.scrollWidth);
    },

    updateColumnAndNeighbourWidths(index, delta) {
        const newColumnWidth = this.dragContext.draggedColumn.initialWidth + delta;

        if (newColumnWidth < this.constants.MIN_COLUMN_WIDTH) {
            return;
        }

        this.trigger('update:width', index, newColumnWidth, this.el.scrollWidth);

        this.gridEventAggregator.trigger('singleColumnResize', newColumnWidth);

        this.el.style.width = `${this.dragContext.tableInitialWidth + delta + 1}px`;
        this.options.columns[index].width = newColumnWidth;
    },

    __toggleCollapseAll() {
        this.__updateCollapseAll(!this.collapsed);
        this.gridEventAggregator.trigger('toggle:collapse:all', this.collapsed);
    },

    __updateCollapseAll(collapsed) {
        this.collapsed = collapsed;
        this.$('.js-collapsible-button').toggleClass(classes.expanded, !collapsed);
    },

    __handleDragOver(event) {
        if (!this.collection.draggingModel) {
            return;
        }
        event.preventDefault();
    },

    __handleDragEnter(event) {
        this.collection.dragoverModel = undefined;
        if (this.__allowDrop()) {
            this.collection.trigger('dragover:head', event);
        }
    },

    __handleModelDragOver() {
        this.el.parentElement && this.el.parentElement.classList.add(classes.dragover);
    },

    __handleDragLeave(event) {
        if (this.collection.dragoverModel !== undefined) {
            this.collection.trigger('dragleave:head', event);
        }
    },

    __handleModelDragLeave() {
        this.el.parentElement && this.el.parentElement.classList.remove(classes.dragover);
    },

    __handleDrop(event) {
        event.preventDefault();
        if (this.__allowDrop()) {
            this.collection.trigger('drop:head', event);
        }
    },

    __allowDrop() {
        if (!this.collection.draggingModel || this.collection.indexOf(this.collection.draggingModel) < 0) {
            return false;
        }
        return true;
    },

    __handleModelDrop() {
        this.el.parentElement && this.el.parentElement.classList.remove(classes.dragover);
        if (this.collection.draggingModel) {
            this.trigger('drag:drop', this.collection.draggingModel, this.model);
        }
    },

    __handleColumnSelect(event) {
        const { currentTarget } = event;
        if (!document.body.contains(currentTarget)) {
            return;
        }
        this.trigger('handleColumnSelect', {
            event,
            el: currentTarget,
            model: this.options.columns[Array.prototype.indexOf.call(currentTarget.parentElement.children, currentTarget)]
        });
    },

    __onMouseLeaveHeader(event) {
        this.trigger('handleLeave', event);
    }
});

export default GridHeaderView;
<|endoftext|>


<commit_before>const logger = require('logger');
const appConstants = require('app.constants');
const EndpointModel = require('models/endpoint.model');
const VersionModel = require('models/version.model');
const url = require('url');
const EndpointNotFound = require('errors/endpointNotFound');
const NotAuthenticated = require('errors/notAuthenticated');
const FilterError = require('errors/filterError');
const pathToRegexp = require('path-to-regexp');
const requestPromise = require('request-promise');
const utils = require('utils');
const fs = require('fs');

const ALLOWED_HEADERS = [
    'cache-control',
    'charset',
    'location',
    'host',
];

class Dispatcher {

    static getLoggedUser(ctx) {
        return ctx.state.user || ctx.req.user || ctx.state.microservice;
    }

    static async buildUrl(sourcePath, redirectEndpoint, endpoint) {
        logger.debug('Building url');
        const result = endpoint.pathRegex.exec(sourcePath);
        let keys = {}; // eslint-disable-line prefer-const
        endpoint.pathKeys.map((key, i) => (
            keys[key] = result[i + 1]
        ));
        const toPath = pathToRegexp.compile(redirectEndpoint.path);
        const buildUrl = url.resolve(redirectEndpoint.url, toPath(keys));
        logger.debug(`Final url  ${buildUrl}`);
        return buildUrl;
    }

    static buildPathFilter(sourcePath, filterEndpoint, endpoint) {
        logger.debug('Building url');
        const result = endpoint.pathRegex.exec(sourcePath);
        let keys = {}; // eslint-disable-line prefer-const
        endpoint.pathKeys.map((key, i) => (
            keys[filterEndpoint.params[key]] = result[i + 1]
        ));
        const toPath = pathToRegexp.compile(filterEndpoint.path);
        const path = toPath(keys);
        logger.debug(`Final path  ${path}`);
        return path;
    }

    static searchFilterValue(filter, filterValues) {
        logger.debug('Searching filterValue to filter', filter.name);

        if (filterValues) {
            for (let i = 0, length = filterValues.length; i < length; i++) {
                if (filterValues[i].name === filter.name && filterValues[i].path === filter.path &&
                    filterValues[i].method === filter.method && filterValues[i].result.correct) {
                    return filterValues[i].result.data;
                }
            }
        }
        logger.warn('Not find filter value to filter', filter.name);
        return null;
    }

    static checkCompare(compare, condition, dataFilter) {
        logger.debug('Check compare filter to filter', compare, 'and dataFilter', dataFilter);
        if (compare && dataFilter) {
            const compareKeys = Object.keys(compare);

            for (let i = 0, length = compareKeys.length; i < length; i++) {
                const key = compareKeys[i];
                if (typeof compare[key] === 'object') {
                    logger.debug('IS A OBJECT');
                    const match = Dispatcher.checkCompare(compare[key], dataFilter[key]);
                    if (match && condition === 'OR') {
                        return true;
                    } else if (!match && condition === 'AND') {
                        return false;
                    }
                } else if (compare[key] !== dataFilter[key]) {
                    return false;
                }
            }
            if (condition === 'OR') {
                return false;
            } else if (condition === 'AND') {
                return true;
            }
        }
        return false;
    }

    static checkValidRedirects(redirects, filters) {
        logger.debug('Checking redirects with filters');
        const validRedirects = [];
        for (let i = 0, length = redirects.length; i < length; i++) {
            const redirect = redirects[i];
            let valid = true;
            if (redirect.filters) {
                for (let j = 0, lengthRF = redirect.filters.length; j < lengthRF; j++) {
                    const filterValue = Dispatcher.searchFilterValue(redirect.filters[j], filters);
                    if (!filterValue || !Dispatcher.checkCompare(redirect.filters[j].compare, redirect.filters[j].condition, filterValue)) {
                        logger.warn('Not valid filter');
                        valid = false;
                        break;
                    }
                    if (!redirect.data) {
                        redirect.data = {};
                    }
                    redirect.data[redirect.filters[j].name] = filterValue;
                }
            }
            if (valid) {
                validRedirects.push(redirect);
            }
        }
        return validRedirects;
    }

    static async checkFilters(sourcePath, endpoint) {
        logger.debug('Checking filters in endpoint', endpoint);
        let filters = [];
        for (let i = 0, length = endpoint.redirect.length; i < length; i++) {
            if (endpoint.redirect[i].filters) {
                filters = filters.concat(endpoint.redirect[i].filters);
            }
        }
        if (!filters || filters.length === 0) {
            logger.debug('Not contain filters. All redirect are valids');
            return endpoint;
        }
        logger.debug('Obtaining data to check filters');
        const promisesRequest = [];
        let filter = null;
        let path = null;
        for (let i = 0, length = filters.length; i < length; i++) {
            filter = filters[i];
            path = await Dispatcher.buildPathFilter(sourcePath, filter, endpoint);
            const request = await Dispatcher.getRequest({
                request: {
                    url: path,
                    method: filter.method,
                    body: {},
                },
            });
            logger.debug('Config request', request);
            request.configRequest.json = true;
            promisesRequest.push(requestPromise(request.configRequest));

        }
        if (!promisesRequest || promisesRequest.length === 0) {
            return endpoint;
        }
        try {
            logger.debug('Doing requests');
            const results = await Promise.all(promisesRequest);
            // TODO: Add support to serveral filter by each endpoint
            for (let i = 0, length = results.length; i < length; i++) {
                if (results[i].statusCode === 200) {
                    filters[i].result = {
                        data: results[i].body,
                        correct: true,
                    };
                } else {
                    filters[i].result = {
                        correct: false,
                    };
                }
            }
            logger.debug('Checking valid filters');
            const validRedirects = Dispatcher.checkValidRedirects(endpoint.redirect, filters);
            endpoint.redirect = validRedirects;
        } catch (err) {
            logger.error(err);
            throw new FilterError('Error resolving filters');
        }
        return endpoint;
    }

    static getHeadersFromRequest(headers) {
        let validHeaders = {};
        const keys = Object.keys(headers);
        for (let i = 0, length = keys.length; i < length; i++) {
            if (ALLOWED_HEADERS.indexOf(keys[i].toLowerCase()) > -1) {
                validHeaders[keys[i]] = headers[keys[i]];
            }
        }
        return validHeaders;
    }

    static async getRequest(ctx) {
        logger.info(`Searching endpoint where redirect url ${ctx.request.url}
            and method ${ctx.request.method}`);
        logger.debug('Obtaining version');
        const version = await VersionModel.findOne({
            name: appConstants.ENDPOINT_VERSION,
        });
        logger.debug('Version found ', version);
        const parsedUrl = url.parse(ctx.request.url);
        logger.debug('Searching endpoints');
        let endpoint = await EndpointModel.findOne({
            $where: `this.pathRegex && this.pathRegex.test('${parsedUrl.pathname}')`,
            method: ctx.request.method,
            version: version.version,
        });

        if (!endpoint) {
            throw new EndpointNotFound(`${parsedUrl.pathname} not found`);
        } else {
            logger.debug('Endpoint found');
            logger.debug('Checking if is necesary authentication');
            if (endpoint.authenticated && !Dispatcher.getLoggedUser(ctx)) {
                logger.info('Is necesary authentication but the request is not authenticated');
                throw new NotAuthenticated();
            }
            let redirectEndpoint = null;
            endpoint = await Dispatcher.checkFilters(parsedUrl.pathname, endpoint);
            if (endpoint && endpoint.redirect.length === 0) {
                logger.error('Not exist redirects');
                throw new EndpointNotFound(`${parsedUrl.pathname} not found`);
            }

            if (endpoint.redirect && endpoint.redirect.length > 1) {
                logger.debug(`Find several redirect endpoints (num: ${endpoint.redirect.length}).
                Obtaining final endpoint with random`);
                const pos = Math.floor(Math.random() * endpoint.redirect.length);
                logger.debug(`Position choose ${pos}`);
                redirectEndpoint = endpoint.redirect[pos];
            } else {
                logger.debug('Only contain one redirect');
                redirectEndpoint = endpoint.redirect[0];
            }
            logger.info('Dispathing request from %s to %s%s private endpoint.',
                parsedUrl.pathname, redirectEndpoint.url, redirectEndpoint.path);
            logger.debug('endpoint', endpoint);
            const finalUrl = await Dispatcher.buildUrl(parsedUrl.pathname, redirectEndpoint, endpoint);
            let configRequest = { // eslint-disable-line prefer-const
                uri: finalUrl,
                method: redirectEndpoint.method,
                // https://github.com/request/request-promise#user-content-get-a-rejection-only-if-the-request-failed-for-technical-reasons
                simple: false,
                resolveWithFullResponse: true,
                binary: endpoint.binary,
            };
            if (ctx.request.query) {
                logger.debug('Adding query params');
                configRequest.qs = ctx.request.query;
            }

            logger.debug('Create request to %s', configRequest.uri);
            if (configRequest.method === 'POST' || configRequest.method === 'PATCH' ||
                configRequest.method === 'PUT') {
                logger.debug('Method is %s. Adding body', configRequest.method);
                if (ctx.request.body.fields) {
                    logger.debug('Is a form-data request');
                    configRequest.body = ctx.request.body.fields;
                } else {
                    configRequest.body = ctx.request.body;
                }
            }
            if (redirectEndpoint.data || endpoint.authenticated) {
                logger.debug('Adding data');
                if (endpoint.authenticated) {
                    redirectEndpoint.data = Object.assign({}, redirectEndpoint.data, {
                        loggedUser: Dispatcher.getLoggedUser(ctx),
                    });
                }
                if (configRequest.method === 'GET' || configRequest.method === 'DELETE') {
                    configRequest.qs = configRequest.qs || {};
                    const keys = Object.keys(redirectEndpoint.data);
                    for (let i = 0, length = keys.length; i < length; i++) {
                        configRequest.qs[keys[i]] = JSON.stringify(redirectEndpoint.data[keys[i]]);
                    }
                } else {
                    configRequest.body = Object.assign({}, configRequest.body, redirectEndpoint.data);
                }
            }
            if (ctx.request.body.files) {
                logger.debug('Adding files', ctx.request.body.files);
                const files = ctx.request.body.files;
                let formData = {}; // eslint-disable-line prefer-const
                for (const key in files) { // eslint-disable-line no-restricted-syntax
                    if ({}.hasOwnProperty.call(files, key)) {
                        formData[key] = fs.createReadStream(files[key].path);
                    }
                }
                configRequest.body = Object.assign(configRequest.body || {}, formData);
                delete configRequest.body.files;
                // delete configRequest.body.fields;
                configRequest.multipart = true;
            }
            if (ctx.request.headers) {
                logger.debug('Adding headers');
                configRequest.headers = Dispatcher.getHeadersFromRequest(ctx.request.headers);
            }

            logger.debug('Checking if is json or formdata request');
            if (configRequest.multipart) {
                logger.debug('Is FormData request');
                configRequest.formData = configRequest.body;
                delete configRequest.body;
                delete configRequest.multipart;
            } else {
                logger.debug('Is JSON request');
                configRequest.json = true;
                delete configRequest.multipart;
            }
            configRequest.encoding = null; // all request have encoding null

            logger.debug('Returning config', configRequest);
            return {
                configRequest,
                endpoint,
            };
        }
    }

}

module.exports = Dispatcher;
<commit_msg>add conditions in filters<commit_after>const logger = require('logger');
const appConstants = require('app.constants');
const EndpointModel = require('models/endpoint.model');
const VersionModel = require('models/version.model');
const url = require('url');
const EndpointNotFound = require('errors/endpointNotFound');
const NotAuthenticated = require('errors/notAuthenticated');
const FilterError = require('errors/filterError');
const pathToRegexp = require('path-to-regexp');
const requestPromise = require('request-promise');
const utils = require('utils');
const fs = require('fs');

const ALLOWED_HEADERS = [
    'cache-control',
    'charset',
    'location',
    'host',
];

class Dispatcher {

    static getLoggedUser(ctx) {
        return ctx.state.user || ctx.req.user || ctx.state.microservice;
    }

    static async buildUrl(sourcePath, redirectEndpoint, endpoint) {
        logger.debug('Building url');
        const result = endpoint.pathRegex.exec(sourcePath);
        let keys = {}; // eslint-disable-line prefer-const
        endpoint.pathKeys.map((key, i) => (
            keys[key] = result[i + 1]
        ));
        const toPath = pathToRegexp.compile(redirectEndpoint.path);
        const buildUrl = url.resolve(redirectEndpoint.url, toPath(keys));
        logger.debug(`Final url  ${buildUrl}`);
        return buildUrl;
    }

    static buildPathFilter(sourcePath, filterEndpoint, endpoint) {
        logger.debug('Building url');
        const result = endpoint.pathRegex.exec(sourcePath);
        let keys = {}; // eslint-disable-line prefer-const
        endpoint.pathKeys.map((key, i) => (
            keys[filterEndpoint.params[key]] = result[i + 1]
        ));
        const toPath = pathToRegexp.compile(filterEndpoint.path);
        const path = toPath(keys);
        logger.debug(`Final path  ${path}`);
        return path;
    }

    static searchFilterValue(filter, filterValues) {
        logger.debug('Searching filterValue to filter', filter.name);

        if (filterValues) {
            for (let i = 0, length = filterValues.length; i < length; i++) {
                if (filterValues[i].name === filter.name && filterValues[i].path === filter.path &&
                    filterValues[i].method === filter.method && filterValues[i].result.correct) {
                    return filterValues[i].result.data;
                }
            }
        }
        logger.warn('Not find filter value to filter', filter.name);
        return null;
    }

    static checkCompare(compare, dataFilter, condition = 'AND') {
        logger.debug('Check compare filter to filter', compare, 'and dataFilter', dataFilter);
        if (compare && dataFilter) {
            const compareKeys = Object.keys(compare);

            for (let i = 0, length = compareKeys.length; i < length; i++) {
                const key = compareKeys[i];
                if (typeof compare[key] === 'object') {
                    logger.debug('IS A OBJECT');
                    const match = Dispatcher.checkCompare(compare[key], dataFilter[key], condition);
                    if (match && condition === 'OR') {
                        return true;
                    } else if (!match && condition === 'AND') {
                        return false;
                    }
                } else if (compare[key] !== dataFilter[key]) {
                    return false;
                }
            }
            if (condition === 'OR') {
                return false;
            } else if (condition === 'AND') {
                return true;
            }
        }
        return false;
    }

    static checkValidRedirects(redirects, filters) {
        logger.debug('Checking redirects with filters');
        const validRedirects = [];
        for (let i = 0, length = redirects.length; i < length; i++) {
            const redirect = redirects[i];
            let valid = true;
            if (redirect.filters) {
                for (let j = 0, lengthRF = redirect.filters.length; j < lengthRF; j++) {
                    const filterValue = Dispatcher.searchFilterValue(redirect.filters[j], filters);
                    if (!filterValue || !Dispatcher.checkCompare(redirect.filters[j].compare, filterValue, redirect.filters[j].condition)) {
                        logger.warn('Not valid filter');
                        valid = false;
                        break;
                    }
                    if (!redirect.data) {
                        redirect.data = {};
                    }
                    redirect.data[redirect.filters[j].name] = filterValue;
                }
            }
            if (valid) {
                validRedirects.push(redirect);
            }
        }
        return validRedirects;
    }

    static async checkFilters(sourcePath, endpoint) {
        logger.debug('Checking filters in endpoint', endpoint);
        let filters = [];
        for (let i = 0, length = endpoint.redirect.length; i < length; i++) {
            if (endpoint.redirect[i].filters) {
                filters = filters.concat(endpoint.redirect[i].filters);
            }
        }
        if (!filters || filters.length === 0) {
            logger.debug('Not contain filters. All redirect are valids');
            return endpoint;
        }
        logger.debug('Obtaining data to check filters');
        const promisesRequest = [];
        let filter = null;
        let path = null;
        for (let i = 0, length = filters.length; i < length; i++) {
            filter = filters[i];
            path = await Dispatcher.buildPathFilter(sourcePath, filter, endpoint);
            const request = await Dispatcher.getRequest({
                request: {
                    url: path,
                    method: filter.method,
                    body: {},
                },
            });
            logger.debug('Config request', request);
            request.configRequest.json = true;
            promisesRequest.push(requestPromise(request.configRequest));

        }
        if (!promisesRequest || promisesRequest.length === 0) {
            return endpoint;
        }
        try {
            logger.debug('Doing requests');
            const results = await Promise.all(promisesRequest);
            // TODO: Add support to serveral filter by each endpoint
            for (let i = 0, length = results.length; i < length; i++) {
                if (results[i].statusCode === 200) {
                    filters[i].result = {
                        data: results[i].body,
                        correct: true,
                    };
                } else {
                    filters[i].result = {
                        correct: false,
                    };
                }
            }
            logger.debug('Checking valid filters');
            const validRedirects = Dispatcher.checkValidRedirects(endpoint.redirect, filters);
            endpoint.redirect = validRedirects;
        } catch (err) {
            logger.error(err);
            throw new FilterError('Error resolving filters');
        }
        return endpoint;
    }

    static getHeadersFromRequest(headers) {
        let validHeaders = {};
        const keys = Object.keys(headers);
        for (let i = 0, length = keys.length; i < length; i++) {
            if (ALLOWED_HEADERS.indexOf(keys[i].toLowerCase()) > -1) {
                validHeaders[keys[i]] = headers[keys[i]];
            }
        }
        return validHeaders;
    }

    static async getRequest(ctx) {
        logger.info(`Searching endpoint where redirect url ${ctx.request.url}
            and method ${ctx.request.method}`);
        logger.debug('Obtaining version');
        const version = await VersionModel.findOne({
            name: appConstants.ENDPOINT_VERSION,
        });
        logger.debug('Version found ', version);
        const parsedUrl = url.parse(ctx.request.url);
        logger.debug('Searching endpoints');
        let endpoint = await EndpointModel.findOne({
            $where: `this.pathRegex && this.pathRegex.test('${parsedUrl.pathname}')`,
            method: ctx.request.method,
            version: version.version,
        });

        if (!endpoint) {
            throw new EndpointNotFound(`${parsedUrl.pathname} not found`);
        } else {
            logger.debug('Endpoint found');
            logger.debug('Checking if is necesary authentication');
            if (endpoint.authenticated && !Dispatcher.getLoggedUser(ctx)) {
                logger.info('Is necesary authentication but the request is not authenticated');
                throw new NotAuthenticated();
            }
            let redirectEndpoint = null;
            endpoint = await Dispatcher.checkFilters(parsedUrl.pathname, endpoint);
            if (endpoint && endpoint.redirect.length === 0) {
                logger.error('Not exist redirects');
                throw new EndpointNotFound(`${parsedUrl.pathname} not found`);
            }

            if (endpoint.redirect && endpoint.redirect.length > 1) {
                logger.debug(`Find several redirect endpoints (num: ${endpoint.redirect.length}).
                Obtaining final endpoint with random`);
                const pos = Math.floor(Math.random() * endpoint.redirect.length);
                logger.debug(`Position choose ${pos}`);
                redirectEndpoint = endpoint.redirect[pos];
            } else {
                logger.debug('Only contain one redirect');
                redirectEndpoint = endpoint.redirect[0];
            }
            logger.info('Dispathing request from %s to %s%s private endpoint.',
                parsedUrl.pathname, redirectEndpoint.url, redirectEndpoint.path);
            logger.debug('endpoint', endpoint);
            const finalUrl = await Dispatcher.buildUrl(parsedUrl.pathname, redirectEndpoint, endpoint);
            let configRequest = { // eslint-disable-line prefer-const
                uri: finalUrl,
                method: redirectEndpoint.method,
                // https://github.com/request/request-promise#user-content-get-a-rejection-only-if-the-request-failed-for-technical-reasons
                simple: false,
                resolveWithFullResponse: true,
                binary: endpoint.binary,
            };
            if (ctx.request.query) {
                logger.debug('Adding query params');
                configRequest.qs = ctx.request.query;
            }

            logger.debug('Create request to %s', configRequest.uri);
            if (configRequest.method === 'POST' || configRequest.method === 'PATCH' ||
                configRequest.method === 'PUT') {
                logger.debug('Method is %s. Adding body', configRequest.method);
                if (ctx.request.body.fields) {
                    logger.debug('Is a form-data request');
                    configRequest.body = ctx.request.body.fields;
                } else {
                    configRequest.body = ctx.request.body;
                }
            }
            if (redirectEndpoint.data || endpoint.authenticated) {
                logger.debug('Adding data');
                if (endpoint.authenticated) {
                    redirectEndpoint.data = Object.assign({}, redirectEndpoint.data, {
                        loggedUser: Dispatcher.getLoggedUser(ctx),
                    });
                }
                if (configRequest.method === 'GET' || configRequest.method === 'DELETE') {
                    configRequest.qs = configRequest.qs || {};
                    const keys = Object.keys(redirectEndpoint.data);
                    for (let i = 0, length = keys.length; i < length; i++) {
                        configRequest.qs[keys[i]] = JSON.stringify(redirectEndpoint.data[keys[i]]);
                    }
                } else {
                    configRequest.body = Object.assign({}, configRequest.body, redirectEndpoint.data);
                }
            }
            if (ctx.request.body.files) {
                logger.debug('Adding files', ctx.request.body.files);
                const files = ctx.request.body.files;
                let formData = {}; // eslint-disable-line prefer-const
                for (const key in files) { // eslint-disable-line no-restricted-syntax
                    if ({}.hasOwnProperty.call(files, key)) {
                        formData[key] = fs.createReadStream(files[key].path);
                    }
                }
                configRequest.body = Object.assign(configRequest.body || {}, formData);
                delete configRequest.body.files;
                // delete configRequest.body.fields;
                configRequest.multipart = true;
            }
            if (ctx.request.headers) {
                logger.debug('Adding headers');
                configRequest.headers = Dispatcher.getHeadersFromRequest(ctx.request.headers);
            }

            logger.debug('Checking if is json or formdata request');
            if (configRequest.multipart) {
                logger.debug('Is FormData request');
                configRequest.formData = configRequest.body;
                delete configRequest.body;
                delete configRequest.multipart;
            } else {
                logger.debug('Is JSON request');
                configRequest.json = true;
                delete configRequest.multipart;
            }
            configRequest.encoding = null; // all request have encoding null

            logger.debug('Returning config', configRequest);
            return {
                configRequest,
                endpoint,
            };
        }
    }

}

module.exports = Dispatcher;
<|endoftext|>


<commit_before>/**
 * handlebars helper: {{component ComponentName Data Variation}}
 *
 * Usage
 * {{component 'Button' 'button-fancy'}}
 * {{component name='Button' data='button-fancy'}}
 *
 * Usage (passing arguments)
 * {{component name='Button' disabled=true}}
 *
 * Usage (with children)
 * {{#component name='Button'}}Click Me{{/component}}
 * {{#component name='Button' disabled=true}}Not Clickable{{/component}}
 *
 */
var fs = require('fs');
var hbs = require('hbs');
var path = require('path');
var extend = require('extend');
var cfg = require('../core/config');
var utils = require('../core/utils');

module.exports = function component () {

	try {
		var context = arguments[arguments.length - 1];
		var contextDataRoot = context.data && context.data.root ? context.data.root : {};      // default component data from controller & view
		var name = 'string' === typeof arguments[0] ? arguments[0] : context.hash.name;
		var folder = name.replace(/[^A-Za-z0-9-]/g, '');
		var templateFile = context.hash && context.hash.template ? context.hash.template : folder.toLowerCase();
		var dataFile = folder.toLowerCase();                                                   // default data file
		var passedData = null;                                                                 // passed data to component helper
		var componentData = {};                                                                // collected component data

		if (arguments.length >= 3) {
			if ('object' === typeof arguments[1]) {
				passedData = arguments[1];
			}
			else if('string' === typeof arguments[1]) {
				dataFile = arguments[1].replace(/\.json$/i, '').toLowerCase();
			}
		}
		else if (context.hash && context.hash.data) {
			if ('object' === typeof context.hash.data) {
				passedData = context.hash.data;
			}
			else if ('string' === typeof context.hash.data) {
				dataFile = context.hash.data.toLowerCase();
			}
		}

		for (var key in cfg.nitro.components) {
			if (cfg.nitro.components.hasOwnProperty(key)) {
				var component = cfg.nitro.components[key];
				if (component.hasOwnProperty('path')) {
					var templatePath = path.join(
						cfg.nitro.base_path,
						component.path,
						'/',
						folder,
						'/',
						templateFile + '.' + cfg.nitro.view_file_extension
					);

					if (utils.fileExistsSync(templatePath)) {
						var jsonFilename = dataFile + '.json',
							jsonPath = path.join(
								cfg.nitro.base_path,
								component.path,
								'/',
								folder,
								'/_data/',
								jsonFilename
							);

						try {
							if (contextDataRoot._locals) {
								extend(true, componentData, contextDataRoot._locals);
							}

							if (passedData) {
								extend(true, componentData, passedData);
							}
							else if (utils.fileExistsSync(jsonPath)) {
								extend(true, componentData, JSON.parse(fs.readFileSync(jsonPath, 'utf8')));
							}

							if (contextDataRoot._query) {
								extend(true, componentData, contextDataRoot._query);
							}

							// Add attribtues e.g. "disabled" of {{component "Button" disabled=true}}
							if (context.hash) {
								extend(true, componentData, context.hash);
							}

							// Add children e.g. {{#component "Button"}}Click me{{/component}}
							if (context.fn) {
								componentData.children = context.fn(this);
							}

							return new hbs.handlebars.SafeString(
								hbs.handlebars.compile(
									fs.readFileSync(templatePath, 'utf8')
								)(componentData, context)
							);
						}
						catch (e) {
							throw new Error('Parse Error in Component ' + name + ': ' + e.message);
						}
					}
				}
			}
		}

		throw new Error('Component `' + name + '` with template file `'+ templateFile + '.' + cfg.nitro.view_file_extension + '` not found in folder `' + folder + '`.');
	}
	catch (e) {
		return utils.logAndRenderError(e);
	}
};
<commit_msg>allow simple number or boolen data in component helper<commit_after>/**
 * handlebars helper: {{component ComponentName Data Variation}}
 *
 * Usage
 * {{component 'button' 'button-fancy'}}
 * {{component name='button' data='button-fancy'}}
 *
 * Usage (passing arguments)
 * {{component name='button' disabled=true}}
 *
 * Usage (with children)
 * {{#component name='button'}}Click Me{{/component}}
 * {{#component name='button' disabled=true}}Not Clickable{{/component}}
 *
 */
var fs = require('fs');
var hbs = require('hbs');
var path = require('path');
var extend = require('extend');
var cfg = require('../core/config');
var utils = require('../core/utils');

module.exports = function component () {

	try {
		var context = arguments[arguments.length - 1];
		var contextDataRoot = context.data && context.data.root ? context.data.root : {};      // default component data from controller & view
		var name = 'string' === typeof arguments[0] ? arguments[0] : context.hash.name;
		var folder = name.replace(/[^A-Za-z0-9-]/g, '');
		var templateFile = context.hash && context.hash.template ? context.hash.template : folder.toLowerCase();
		var dataFile = folder.toLowerCase();                                                   // default data file
		var passedData = null;                                                                 // passed data to component helper
		var componentData = {};                                                                // collected component data

		if (arguments.length >= 3) {
			switch (typeof arguments[1]) {
				case 'string':
					dataFile = arguments[1].replace(/\.json$/i, '').toLowerCase();
					break;
				case 'object':
					passedData = extend(true, passedData, arguments[1]);
					break;
				case 'number':
				case 'boolean':
					passedData = arguments[1];
					break;
				default:
					break;
			}
		}
		if (context.hash && context.hash.data) {
			switch (typeof context.hash.data) {
				case 'string':
					dataFile = context.hash.data.replace(/\.json$/i, '').toLowerCase();
					break;
				case 'object':
					passedData = extend(true, passedData, context.hash.data);
					break;
				case 'number':
				case 'boolean':
					passedData = context.hash.data;
					break;
				default:
					break;
			}
		}

		for (var key in cfg.nitro.components) {
			if (cfg.nitro.components.hasOwnProperty(key)) {
				var component = cfg.nitro.components[key];
				if (component.hasOwnProperty('path')) {
					var templatePath = path.join(
						cfg.nitro.base_path,
						component.path,
						'/',
						folder,
						'/',
						templateFile + '.' + cfg.nitro.view_file_extension
					);

					if (utils.fileExistsSync(templatePath)) {
						var jsonFilename = dataFile + '.json',
							jsonPath = path.join(
								cfg.nitro.base_path,
								component.path,
								'/',
								folder,
								'/_data/',
								jsonFilename
							);

						try {
							if (contextDataRoot._locals) {
								extend(true, componentData, contextDataRoot._locals);
							}

							if (passedData) {
								extend(true, componentData, passedData);
							}
							else if (utils.fileExistsSync(jsonPath)) {
								extend(true, componentData, JSON.parse(fs.readFileSync(jsonPath, 'utf8')));
							}

							if (contextDataRoot._query) {
								extend(true, componentData, contextDataRoot._query);
							}

							// Add attribtues e.g. "disabled" of {{component "Button" disabled=true}}
							if (context.hash) {
								extend(true, componentData, context.hash);
							}

							// Add children e.g. {{#component "Button"}}Click me{{/component}}
							if (context.fn) {
								componentData.children = context.fn(this);
							}

							return new hbs.handlebars.SafeString(
								hbs.handlebars.compile(
									fs.readFileSync(templatePath, 'utf8')
								)(componentData, context)
							);
						}
						catch (e) {
							throw new Error('Parse Error in Component ' + name + ': ' + e.message);
						}
					}
				}
			}
		}

		throw new Error('Component `' + name + '` with template file `'+ templateFile + '.' + cfg.nitro.view_file_extension + '` not found in folder `' + folder + '`.');
	}
	catch (e) {
		return utils.logAndRenderError(e);
	}
};
<|endoftext|>


<commit_before>import _ from 'lodash'; import React from 'react/addons';

import {Modal,Nav,NavItem} from 'react-bootstrap';
import {MentionsInput, Mention} from 'react-mentions';
import Title from './add-item/title';
import TagsInput from './tags-input';
import StoryTitle from './add-item/story-title';
import MembersDropdown from './add-item/members-dropdown';
import IssueTemplates from './add-item/issue-templates';
import Select from 'react-select';
import LocalStorageMixin from 'react-localstorage';

import ItemActions from '../../actions/item-actions';

const NAV_ITEMS = [
  { type: 'story', label: 'Story' },
  { type: 'task', label: 'Task' },
  { type: 'defect', label: 'Defect' },
  { type: 'test', label: 'Test' },
];

const STORY_ATTRS = ['who', 'what', 'why'];

var AddItemModal = React.createClass({

  propTypes: {
    tags: React.PropTypes.array,
    members: React.PropTypes.array,
    product: React.PropTypes.object
  },

  mixins: [
    React.addons.LinkedStateMixin,
    LocalStorageMixin
  ],

  getInitialState() {
    return {
      type: 'story',
      title: '',
      who: '',
      what: '',
      why: '',
      description: '',
      tags: [],
      assigned_to: null,
      assigneeName: '',
      sendToBacklog: true,
      validation: {
        title: true,
        who: true,
        what: true,
        why: true
      }
    }
  },

  getDefaultProps() {
    return {
      members: []
    }
  },

  setDescription(ev, value) {
    this.setState({ description: value });
  },

  setAssignedTo(value, member) {
    let memberName = _.chain(member).pluck('label').first().value()

    this.setState({
      assigned_to: value,
      assigneeName: memberName
    })
  },

  updateTags(tags) {
    this.setState({ tags });
  },

  changeType(type) {
    var descriptionTemplate = (type === 'defect') ? IssueTemplates.defect : '';
    this.setDescription(null, descriptionTemplate);

    this.setState({ type: type });
  },

  dismiss(ev) {
    ev.preventDefault();
    let state = this.getInitialState();
    this.setState(state);
    this.props.onRequestHide();
  },

  createItem(ev) {
    ev.preventDefault();
    let item = _.pick(this.state, ['type', 'description', 'tags', 'assigned_to']);

    if (this.state.type === 'story') {
      _.assign(item, _.pick(this.state, STORY_ATTRS));
    } else {
      item.title = this.state.title;
    }

    if (this.state.sendToBacklog) {
      item.status = 'backlog';
    }

    ItemActions.addItem(this.props.product.id, item).then( (err) => {
      if (!err) {
        this.setState(this.getInitialState());
        this.props.onRequestHide();
      } else {
        this.updateValidation(err)
      }
    });
  },

  updateValidation(err) {
    let validationState = this.state.validation;

    _.each(err.validationError, (attr) => {
      validationState[attr] = false;
    })

    this.setState({validation: validationState});
  },

  prepareMembersForSelect() {
    return _.chain(this.props.members)
            .map(function(member){
              if (!member.revoked) {
                return {label: `${member.first_name} ${member.last_name}`, value: member.id}
              }
            })
            .compact()
            .value()
  },

  notAssignable() {
    return !this.props.members.length;
  },

  assignPlaceholder() {
    return this.notAssignable() ? 'Nobody to assign to': 'Unassigned';
  },

  assigneeName() {
    return this.state.assigneeName ? this.state.assigneeName : null;
  },

  render() {
    let mentions = _.map(this.props.members, function(member) {
      return {
        id: member.id,
        display: `${member.first_name} ${member.last_name.slice(0,1)}.`
      }
    });

    let tags = _.pluck(this.props.tags, 'tag');
    let members = this.prepareMembersForSelect();

    let title;
    if (this.state.type === 'story') {
      title = <StoryTitle who={this.linkState('who')}
                             what={this.linkState('what')}
                              why={this.linkState('why')}
                      validation={this.linkState('validation')} />
    } else {
      title = <Title title={this.linkState('title')}
                   validation={this.linkState('validation')} />;
    }

    return (
      <Modal {...this.props} className="add-item">

          {_.map(NAV_ITEMS, (item) => {
            return (
              <NavItem tabIndex="1" aria-role="tab" eventKey={item.type} className={`add-item__nav-${item.type}`}>
                {item.label}
              </NavItem>
            )
          })}

          <form onSubmit={this.createItem}>
            {title}

              <MentionsInput
                value={this.state.description}
                onChange={this.setDescription}
                placeholder="Add a description...">
                  <Mention data={mentions} />
              </MentionsInput>

              <TagsInput tags={tags} onChange={this.updateTags} value={this.state.tags}/>

                <Select placeholder={this.assignPlaceholder()}
                        name="form-field-name"
                        className="assign-dropdown"
                        disabled={this.notAssignable()}
                        value={this.assigneeName()}
                        options={members}
                        onChange={this.setAssignedTo}
                        clearable={true} />

                <button className="btn btn-default btn-lg cancel-item" onClick={this.dismiss}>Cancel</button>
                <input type="submit" className="btn btn-primary btn-lg create-item" value="Create Item"/>

                    <input className="backlog-checkbox" type="checkbox" name="backlog" checkedLink={this.linkState('sendToBacklog')}/>
                    Automatically send to backlog.

          </form>

      </Modal>
    );
  }
});

export default AddItemModal;
<commit_msg>Add item input fields persist until successful create<commit_after>import _ from 'lodash'; import React from 'react/addons';

import {Modal,Nav,NavItem} from 'react-bootstrap';
import {MentionsInput, Mention} from 'react-mentions';
import Title from './add-item/title';
import TagsInput from './tags-input';
import StoryTitle from './add-item/story-title';
import MembersDropdown from './add-item/members-dropdown';
import IssueTemplates from './add-item/issue-templates';
import Select from 'react-select';
import LocalStorageMixin from 'react-localstorage';

import ItemActions from '../../actions/item-actions';

const NAV_ITEMS = [
  { type: 'story', label: 'Story' },
  { type: 'task', label: 'Task' },
  { type: 'defect', label: 'Defect' },
  { type: 'test', label: 'Test' },
];

const STORY_ATTRS = ['who', 'what', 'why'];

var AddItemModal = React.createClass({

  propTypes: {
    tags: React.PropTypes.array,
    members: React.PropTypes.array,
    product: React.PropTypes.object
  },

  mixins: [
    React.addons.LinkedStateMixin,
    LocalStorageMixin
  ],

  getInitialState() {
    return {
      type: 'story',
      title: '',
      who: '',
      what: '',
      why: '',
      description: '',
      tags: [],
      assigned_to: null,
      assigneeName: '',
      sendToBacklog: true,
      validation: {
        title: true,
        who: true,
        what: true,
        why: true
      }
    }
  },

  getDefaultProps() {
    return {
      members: []
    }
  },

  setDescription(ev, value) {
    this.setState({ description: value });
  },

  setAssignedTo(value, member) {
    let memberName = _.chain(member).pluck('label').first().value()

    this.setState({
      assigned_to: value,
      assigneeName: memberName
    })
  },

  updateTags(tags) {
    this.setState({ tags });
  },

  changeType(type) {
    var descriptionTemplate = (type === 'defect') ? IssueTemplates.defect : '';
    this.setDescription(null, descriptionTemplate);

    this.setState({ type: type });
  },

  dismiss(ev) {
    ev.preventDefault();
    this.props.onRequestHide();
  },

  createItem(ev) {
    ev.preventDefault();
    let item = _.pick(this.state, ['type', 'description', 'tags', 'assigned_to']);

    if (this.state.type === 'story') {
      _.assign(item, _.pick(this.state, STORY_ATTRS));
    } else {
      item.title = this.state.title;
    }

    if (this.state.sendToBacklog) {
      item.status = 'backlog';
    }

    ItemActions.addItem(this.props.product.id, item).then( (err) => {
      if (!err) {
        this.setState(this.getInitialState());
        this.props.onRequestHide();
      } else {
        this.updateValidation(err)
      }
    });
  },

  updateValidation(err) {
    let validationState = this.state.validation;

    _.each(err.validationError, (attr) => {
      validationState[attr] = false;
    })

    this.setState({validation: validationState});
  },

  prepareMembersForSelect() {
    return _.chain(this.props.members)
            .map(function(member){
              if (!member.revoked) {
                return {label: `${member.first_name} ${member.last_name}`, value: member.id}
              }
            })
            .compact()
            .value()
  },

  notAssignable() {
    return !this.props.members.length;
  },

  assignPlaceholder() {
    return this.notAssignable() ? 'Nobody to assign to': 'Unassigned';
  },

  assigneeName() {
    return this.state.assigneeName ? this.state.assigneeName : null;
  },

  render() {
    let mentions = _.map(this.props.members, function(member) {
      return {
        id: member.id,
        display: `${member.first_name} ${member.last_name.slice(0,1)}.`
      }
    });

    let tags = _.pluck(this.props.tags, 'tag');
    let members = this.prepareMembersForSelect();

    let title;
    if (this.state.type === 'story') {
      title = <StoryTitle who={this.linkState('who')}
                             what={this.linkState('what')}
                              why={this.linkState('why')}
                      validation={this.linkState('validation')} />
    } else {
      title = <Title title={this.linkState('title')}
                   validation={this.linkState('validation')} />;
    }

    return (
      <Modal {...this.props} className="add-item">

          {_.map(NAV_ITEMS, (item) => {
            return (
              <NavItem tabIndex="1" aria-role="tab" eventKey={item.type} className={`add-item__nav-${item.type}`}>
                {item.label}
              </NavItem>
            )
          })}

          <form onSubmit={this.createItem}>
            {title}

              <MentionsInput
                value={this.state.description}
                onChange={this.setDescription}
                placeholder="Add a description...">
                  <Mention data={mentions} />
              </MentionsInput>

              <TagsInput tags={tags} onChange={this.updateTags} value={this.state.tags}/>

                <Select placeholder={this.assignPlaceholder()}
                        name="form-field-name"
                        className="assign-dropdown"
                        disabled={this.notAssignable()}
                        value={this.assigneeName()}
                        options={members}
                        onChange={this.setAssignedTo}
                        clearable={true} />

                <button className="btn btn-default btn-lg cancel-item" onClick={this.dismiss}>Cancel</button>
                <input type="submit" className="btn btn-primary btn-lg create-item" value="Create Item"/>

                    <input className="backlog-checkbox" type="checkbox" name="backlog" checkedLink={this.linkState('sendToBacklog')}/>
                    Automatically send to backlog.

          </form>

      </Modal>
    );
  }
});

export default AddItemModal;
<|endoftext|>


<commit_before>var sys = require("sys");
var fs = require("fs");

function for_each_js(callback) {
  var path = fs.realpathSync("./src/");
  var files = fs.readdirSync(fs.realpathSync("./src/"));

  for (var i = 0; i < files.length; i++) {
    var filename = files[i];
    var complete = path + filename;
    callback(complete);
  }
}

// Compress with google compiler
function compress(file) {
  var rest = require("./vendor/restler/lib/restler");

  var http = require('http');
  var google = http.createClient(80, 'http://closure-compiler.appspot.com/compile');

  //
  var code = fs.readFileSync(file).toString();

  var params = {"js_code" : code,
    "compilation_level" : "SIMPLE_OPTIMIZATIONS",
    "output_format" : "text",
    "output_info" : "compiled_code"
  };

  rest.post("http://closure-compiler.appspot.com/compile", {data : params})
    .addListener('complete', function(data) {
      var filename = file.match(/[^/]+$/i)[0];
      filename = filename.replace(/\.js$/i, ".min.js");
      var path = fs.realpathSync("./minified/");
      fs.writeFileSync(path + "/" + filename, data);
    });
}

function jslint(file) {
  var cp = require('child_process');

  var jslintPath = fs.realpathSync("./vendor/jslint/bin/jslint.js");

  // Run jslint on each file
  var jslint = cp.exec("node " + jslintPath + " " + file, function(error, stdout, stderr) {
    if (error) {
      sys.puts(file + " : " + error);
    }
  });
}

for_each_js(jslint);
for_each_js(compress);

<commit_msg>removed precommit<commit_after><|endoftext|>


<commit_before>var app = {};

app.getNumbers = function() {
  var delivered_begin = new Date().getTime();
  var url = 'http://bvworks.lv5.org:8080/numbers/api/prime/numbers?count=' + app.num;
  $.ajax({
    url: url,
    type: 'get',
    datatype: 'jsonp'
  }).done(function(response) {
    var delivered_end = new Date().getTime();
    app.delivered = delivered_end - delivered_begin;
    app.response = response;
    app.typeNumbers();
  }).error(function(err) {
    console.log(err);
  });
};

app.typeNumbers = function() {
  app.formatNumbers();
  app.timeout(0);
  $('.elapsed').append('calculated in ' + app.response.elapsed + ' ms
').fadeIn('slow');
  $('.elapsed').append('delivered in ' + app.delivered + ' ms').fadeIn('slow');
};

app.timeout = function(count) {
  if (count === app.len) { clearTimeout(app.draw); return; }
  app.draw = setTimeout(function() {
    $('.numbers').append($(app.formatted_numbers[count]).fadeIn(200));
    ++count;
    app.timeout(count);
  }, 10);
};

app.formatNumbers = function() {
  app.formatted_numbers = [];
  for (var x = 0, len = app.response.numbers.length; x < len; ++x) {
    if (x === len - 1) {
      app.formatted_numbers.push("" + app.response.numbers[x] + "");
    } else {
      app.formatted_numbers.push("" + app.response.numbers[x] + ", ");
    }
  }
  app.len = app.formatted_numbers.length;
};

app.matrixify = function() {
  var colors = [
    '#006400',
    '#00CC00',
    '#008000',
    '#00FF00',
    '#32CD32',
    '#00FF7F',
    '#2E8B57',
    '#00e500',
    '#00b200',
    '#009900',
    '#007f00',
    '#006600',
    '#4cff4c',
    '#66ff66',
    '#7CFC00',
    '#66CD00',
    '#76EE00',
    '#629632',
    '#488214',
    '#83F52C',
    '#476A34',
    '#93DB70',
    '#5DFC0A',
    '#84BE6A',
    '#659D32',
    '#4CBB17'
  ];
  return colors[Math.floor(Math.random() * colors.length)];
};

app.run = function() {
  $('.numbers').hide().html('').show();
  $('.elapsed').hide().html('').fadeIn();
  app.num = $('.input').val();
  if (filterInt(app.num)) {
    app.getNumbers();
  } else {
    $('.numbers').append('integers only, please').css('color', '#faebd7').hide().fadeIn();
  }
};

filterInt = function(value) {
  if(/^(\-|\+)?([0-9]+|Infinity)$/.test(value)) {
    return Number(value);
  }
  return NaN;
};

$(document).ready(function() {
  $('.form').submit(function(e) {
    e.preventDefault();
    if (app.draw) {
      clearInterval(app.draw);
    }
      app.run();
  });

  $('.submit').click(function(e) {
    e.preventDefault();
    if (app.draw) {
      clearInterval(app.draw);
    }
      app.run();
  });
});

<commit_msg>display visible error when get request fails/clear elapsed before appending new statz<commit_after>var app = {};

app.getNumbers = function() {
  var delivered_begin = new Date().getTime();
  var url = 'http://bvworks.lv5.org:8080/numbers/api/prime/numbers?count=' + app.num;
  $.ajax({
    url: url,
    type: 'get',
    datatype: 'jsonp'
  }).done(function(response) {
    var delivered_end = new Date().getTime();
    app.delivered = delivered_end - delivered_begin;
    app.response = response;
    app.typeNumbers();
  }).error(function(err) {
    console.log(err);
    app.errorMessage();
  });
};

app.errorMessage = function() {
  $('.numbers').append('there was a problem with the server :(
 please try again').css('color', '#faebd7').hide().fadeIn();
};

app.typeNumbers = function() {
  app.formatNumbers();
  app.timeout(0);
  $('.elapsed').html('');
  $('.elapsed').append('calculated in ' + app.response.elapsed + ' ms
').fadeIn('slow');
  $('.elapsed').append('delivered in ' + app.delivered + ' ms').fadeIn('slow');
};

app.timeout = function(count) {
  if (count === app.len) { clearTimeout(app.draw); return; }
  app.draw = setTimeout(function() {
    $('.numbers').append($(app.formatted_numbers[count]).fadeIn(200));
    ++count;
    app.timeout(count);
  }, 10);
};

app.formatNumbers = function() {
  app.formatted_numbers = [];
  for (var x = 0, len = app.response.numbers.length; x < len; ++x) {
    if (x === len - 1) {
      app.formatted_numbers.push("" + app.response.numbers[x] + "");
    } else {
      app.formatted_numbers.push("" + app.response.numbers[x] + ", ");
    }
  }
  app.len = app.formatted_numbers.length;
};

app.matrixify = function() {
  var colors = [
    '#006400',
    '#00CC00',
    '#008000',
    '#00FF00',
    '#32CD32',
    '#00FF7F',
    '#2E8B57',
    '#00e500',
    '#00b200',
    '#009900',
    '#007f00',
    '#006600',
    '#4cff4c',
    '#66ff66',
    '#7CFC00',
    '#66CD00',
    '#76EE00',
    '#629632',
    '#488214',
    '#83F52C',
    '#476A34',
    '#93DB70',
    '#5DFC0A',
    '#84BE6A',
    '#659D32',
    '#4CBB17'
  ];
  return colors[Math.floor(Math.random() * colors.length)];
};

app.run = function() {
  $('.numbers').hide().html('').show();
  $('.elapsed').hide().html('').fadeIn();
  app.num = $('.input').val();
  if (filterInt(app.num)) {
    app.getNumbers();
  } else {
    $('.numbers').append('integers only, please').css('color', '#faebd7').hide().fadeIn();
  }
};

filterInt = function(value) {
  if(/^(\-|\+)?([0-9]+|Infinity)$/.test(value)) {
    return Number(value);
  }
  return NaN;
};

$(document).ready(function() {
  $('.form').submit(function(e) {
    e.preventDefault();
    if (app.draw) {
      clearInterval(app.draw);
    }
      app.run();
  });

  $('.submit').click(function(e) {
    e.preventDefault();
    if (app.draw) {
      clearInterval(app.draw);
    }
      app.run();
  });
});

<|endoftext|>


<commit_before>/*
 * Prim's algorithm calculates a minimum spanning tree in O(m*n) time
 * http://en.wikipedia.org/wiki/Prim's_algorithm
 *
 * @author Evgeniy Kuznetsov
 * @date 29.03.2015
 */

// section: Helpers

// Calculates a nodes of the given graph
// @param {Graph} g
// @return {Array.<Integer>}
function calcVertices(g) {
  var acc = {};

  for(var ei in g) {
    var cur = g[ei];
    acc[cur[0]] = true;
    acc[cur[1]] = true;
  }

  return Object.keys(acc).map(
    function(e){ return parseInt(e); }
  )
}

// Calculates sum of the weights of the given graph
// @param {Graph} g
// @return {Integer}
function calcWeightsSum(g) {
  return g.map(
    function(e){ return e[2]; }
  ).reduce(
    function(sum, e){ return sum + e; }, 0
  );
}

// section: Prim's mst algorithm

// Prim's mst algorithm
// @param {Graph} g
// @return {Graph}
function primsMst(g) {

  // Edges in a spanning tree
  var x = {};
  x[g[0][0]] = true;

  // Vertices in a spanning tree
  var t = [];

  var nodes = calcVertices(g);

  while(Object.keys(x).length != nodes.length) {
    // Search all vertices where one point in x and another not in x
    //  and calculate a min edge
    var minEdge = undefined;
    for(var ei in g) {
      var curEdge = g[ei];

      // Is any endpoint of the edge in x (XOR)
      var isAnyEndpoint = x[curEdge[0]] ? !x[curEdge[1]] : x[curEdge[1]];

      if(isAnyEndpoint) {

        if(minEdge) {
          minEdge = (minEdge[2] > curEdge[2]) ? curEdge : minEdge;
        } else {
          minEdge = curEdge;
        }

      }

    }

    // Add min edge to T
    t.push(minEdge);

    // Add min edge vertex to x
    x[minEdge[0]] = true;
    x[minEdge[1]] = true;
  }

  return t;
}

// section: Tests

var sampleGraph = [
  [1,2,1],
  [1,3,4],
  [1,4,3],
  [2,4,2],
  [3,4,5]
];

console.log("Case 1:", calcVertices(sampleGraph).length == 4, calcVertices(sampleGraph));

console.log("Case 2:", primsMst(sampleGraph).toString() ==  [ [ 1, 2, 1 ], [ 2, 4, 2 ], [ 1, 3, 4 ]].toString(), primsMst(sampleGraph));

console.log("Case 3:", calcWeightsSum(sampleGraph) == 15, calcWeightsSum(sampleGraph));

<commit_msg>Refactoring<commit_after>/*
 * Prim's algorithm calculates a minimum spanning tree in O(m*n) time
 * http://en.wikipedia.org/wiki/Prim's_algorithm
 *
 * @author Evgeniy Kuznetsov
 * @date 29.03.2015
 */

// section: Helpers

// Calculates a nodes of the given graph
// @param {Graph} g
// @return {Array.<Integer>}
function calcVertices(g) {
  var acc = {};

  for(var ei in g) {
    var cur = g[ei];
    acc[cur[0]] = true;
    acc[cur[1]] = true;
  }

  return Object.keys(acc).map(
    function(e){ return parseInt(e); }
  )
}

// Calculates sum of the weights of the given graph
// @param {Graph} g
// @return {Integer}
function calcWeightsSum(g) {
  return g.map(
    function(e){ return e[2]; }
  ).reduce(
    function(sum, e){ return sum + e; }, 0
  );
}

// section: Prim's mst algorithm

// Prim's mst algorithm
// @param {Graph} g
// @return {Graph}
function primsMst(g) {

  // Edges in a spanning tree
  var x = {};
  x[g[0][0]] = true;

  // Vertices in a spanning tree
  var t = [];

  var nodes = calcVertices(g);

  while(Object.keys(x).length != nodes.length) {
    // Search all vertices where one point in x and another not in x
    //  and calculate a min edge
    var minEdge = undefined;
    for(var ei in g) {
      var curEdge = g[ei];

      // Is any endpoint of the edge in x (XOR)
      if( !x[curEdge[0]] != !x[curEdge[1]] ) {

        if(minEdge) {
          minEdge = (minEdge[2] > curEdge[2]) ? curEdge : minEdge;
        } else {
          minEdge = curEdge;
        }

      }

    }

    // Add min edge to T
    t.push(minEdge);

    // Add min edge vertex to x
    x[minEdge[0]] = true;
    x[minEdge[1]] = true;
  }

  return t;
}

// section: Tests

var sampleGraph = [
  [1,2,1],
  [1,3,4],
  [1,4,3],
  [2,4,2],
  [3,4,5]
];

console.log("Case 1:", calcVertices(sampleGraph).length == 4, calcVertices(sampleGraph));

console.log("Case 2:", primsMst(sampleGraph).toString() ==  [ [ 1, 2, 1 ], [ 2, 4, 2 ], [ 1, 3, 4 ]].toString(), primsMst(sampleGraph));

console.log("Case 3:", calcWeightsSum(sampleGraph) == 15, calcWeightsSum(sampleGraph));

<|endoftext|>