<commit_before>/* ===========================================================
 * trumbowyg.allowTagsFromPaste.js v1.0.2
 * It cleans tags from pasted text, whilst allowing several specified tags
 * http://alex-d.github.com/Trumbowyg
 * ===========================================================
 * Author	: Fathi Anshory (0x00000F5C)
 * Twitter	: @fscchannl
 * Notes:
 *  - removeformatPasted must be set to FALSE since it was applied prior to pasteHandlers, or else it will be useless
 *	- It is most advisable to use along with the cleanpaste plugin, or else you'd end up with dirty markup
 */

(function ($) {
    'use strict';

    var defaultOptions = {
        // When empty, all tags are allowed making this plugin useless
        // If you want to remove all tags, use removeformatPasted core option instead
        allowedTags: [],
        // List of tags which can be allowed
        removableTags: [
            'a',
            'abbr',
            'address',
            'b',
            'bdi',
            'bdo',
            'blockquote',
            'br',
            'cite',
            'code',
            'del',
            'dfn',
            'details',
            'em',
            'h1',
            'h2',
            'h3',
            'h4',
            'h5',
            'h6',
            'hr',
            'i',
            'ins',
            'kbd',
            'mark',
            'meter',
            'pre',
            'progress',
            'q',
            'rp',
            'rt',
            'ruby',
            's',
            'samp',
            'small',
            'span',
            'strong',
            'sub',
            'summary',
            'sup',
            'time',
            'u',
            'var',
            'wbr',
            'img',
            'map',
            'area',
            'canvas',
            'figcaption',
            'figure',
            'picture',
            'audio',
            'source',
            'track',
            'video',
            'ul',
            'ol',
            'li',
            'dl',
            'dt',
            'dd',
            'table',
            'caption',
            'th',
            'tr',
            'td',
            'thead',
            'tbody',
            'tfoot',
            'col',
            'colgroup',
            'style',
            'div',
            'p',
            'form',
            'input',
            'textarea',
            'button',
            'select',
            'optgroup',
            'option',
            'label',
            'fieldset',
            'legend',
            'datalist',
            'keygen',
            'output',
            'iframe',
            'link',
            'nav',
            'header',
            'hgroup',
            'footer',
            'main',
            'section',
            'article',
            'aside',
            'dialog',
            'script',
            'noscript',
            'embed',
            'object',
            'param'
        ]
    };

    $.extend(true, $.trumbowyg, {
        plugins: {
            allowTagsFromPaste: {
                init: function (trumbowyg) {
                    // Force disable remove format pasted
                    trumbowyg.o.removeformatPasted = false;

                    if (!trumbowyg.o.plugins.allowTagsFromPaste) {
                        return;
                    }

                    var allowedTags = trumbowyg.o.plugins.allowTagsFromPaste.allowedTags || defaultOptions.allowedTags;
                    var removableTags = trumbowyg.o.plugins.allowTagsFromPaste.removableTags || defaultOptions.removableTags;

                    if (allowedTags.length === 0) {
                        return;
                    }

                    // Get list of tags to remove
                    var tagsToRemove = $(removableTags).not(allowedTags).get();

                    trumbowyg.pasteHandlers.push(function () {
                        setTimeout(function () {
                            var processNodes = trumbowyg.$ed.html();
                            $.each(tagsToRemove, function (iterator, tagName) {
                                processNodes = processNodes.replace(new RegExp('<\\/?' + tagName + '(\\s[^>]*)?>', 'gi'), '');
                            });
                            trumbowyg.$ed.html(processNodes);
                        }, 0);
                    });
                }
            }
        }
    });
})(jQuery);
<commit_msg>Don't turn off removeformatPasted if not needed<commit_after>/* ===========================================================
 * trumbowyg.allowTagsFromPaste.js v1.0.2
 * It cleans tags from pasted text, whilst allowing several specified tags
 * http://alex-d.github.com/Trumbowyg
 * ===========================================================
 * Author	: Fathi Anshory (0x00000F5C)
 * Twitter	: @fscchannl
 * Notes:
 *  - removeformatPasted must be set to FALSE since it was applied prior to pasteHandlers, or else it will be useless
 *	- It is most advisable to use along with the cleanpaste plugin, or else you'd end up with dirty markup
 */

(function ($) {
    'use strict';

    var defaultOptions = {
        // When empty, all tags are allowed making this plugin useless
        // If you want to remove all tags, use removeformatPasted core option instead
        allowedTags: [],
        // List of tags which can be allowed
        removableTags: [
            'a',
            'abbr',
            'address',
            'b',
            'bdi',
            'bdo',
            'blockquote',
            'br',
            'cite',
            'code',
            'del',
            'dfn',
            'details',
            'em',
            'h1',
            'h2',
            'h3',
            'h4',
            'h5',
            'h6',
            'hr',
            'i',
            'ins',
            'kbd',
            'mark',
            'meter',
            'pre',
            'progress',
            'q',
            'rp',
            'rt',
            'ruby',
            's',
            'samp',
            'small',
            'span',
            'strong',
            'sub',
            'summary',
            'sup',
            'time',
            'u',
            'var',
            'wbr',
            'img',
            'map',
            'area',
            'canvas',
            'figcaption',
            'figure',
            'picture',
            'audio',
            'source',
            'track',
            'video',
            'ul',
            'ol',
            'li',
            'dl',
            'dt',
            'dd',
            'table',
            'caption',
            'th',
            'tr',
            'td',
            'thead',
            'tbody',
            'tfoot',
            'col',
            'colgroup',
            'style',
            'div',
            'p',
            'form',
            'input',
            'textarea',
            'button',
            'select',
            'optgroup',
            'option',
            'label',
            'fieldset',
            'legend',
            'datalist',
            'keygen',
            'output',
            'iframe',
            'link',
            'nav',
            'header',
            'hgroup',
            'footer',
            'main',
            'section',
            'article',
            'aside',
            'dialog',
            'script',
            'noscript',
            'embed',
            'object',
            'param'
        ]
    };

    $.extend(true, $.trumbowyg, {
        plugins: {
            allowTagsFromPaste: {
                init: function (trumbowyg) {
                    if (!trumbowyg.o.plugins.allowTagsFromPaste) {
                        return;
                    }

                    // Force disable remove format pasted
                    trumbowyg.o.removeformatPasted = false;

                    var allowedTags = trumbowyg.o.plugins.allowTagsFromPaste.allowedTags || defaultOptions.allowedTags;
                    var removableTags = trumbowyg.o.plugins.allowTagsFromPaste.removableTags || defaultOptions.removableTags;

                    if (allowedTags.length === 0) {
                        return;
                    }

                    // Get list of tags to remove
                    var tagsToRemove = $(removableTags).not(allowedTags).get();

                    trumbowyg.pasteHandlers.push(function () {
                        setTimeout(function () {
                            var processNodes = trumbowyg.$ed.html();
                            $.each(tagsToRemove, function (iterator, tagName) {
                                processNodes = processNodes.replace(new RegExp('<\\/?' + tagName + '(\\s[^>]*)?>', 'gi'), '');
                            });
                            trumbowyg.$ed.html(processNodes);
                        }, 0);
                    });
                }
            }
        }
    });
})(jQuery);
<|endoftext|>


<commit_before>'use strict';

angular.module('vleApp')
  .directive('datasetSelector', function(Dataset, Config, Spec, Logger) {
    return {
      templateUrl: 'components/datasetselector/datasetselector.html',
      restrict: 'E',
      replace: true,
      scope: {},
      controller: function($scope) {
        $scope.Dataset = Dataset;

        $scope.datasetChanged = function() {
          var dataset = Dataset.dataset;

          Logger.logInteraction("Dataset changed", dataset.name);

          Dataset.update(dataset).then(function() {
            Config.updateDataset(dataset);
            Spec.reset();
          });
        };
      }
    };
  });
<commit_msg>Fix dataset selector<commit_after>'use strict';

angular.module('vleApp')
  .directive('datasetSelector', function(Dataset, Config, Fields, Logger) {
    return {
      templateUrl: 'components/datasetselector/datasetselector.html',
      restrict: 'E',
      replace: true,
      scope: {},
      controller: function($scope) {
        $scope.Dataset = Dataset;

        $scope.datasetChanged = function() {
          var dataset = Dataset.dataset;

          Logger.logInteraction('Dataset changed', dataset.name);

          Dataset.update(dataset).then(function() {
            Config.updateDataset(dataset);
            Fields.updateSchema(Dataset.dataschema);
          });
        };
      }
    };
  });
<|endoftext|>


<commit_before>/* Exports a function which returns an object that overrides the default &
 *   plugin grunt configuration object.
 *
 * You can familiarize yourself with Lineman's defaults by checking out:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
 *   - https://github.com/linemanjs/lineman/blob/master/config/plugins
 *
 * You can also ask Lineman's about config from the command line:
 *
 *   $ lineman config #=> to print the entire config
 *   $ lineman config concat.js #=> to see the JS config for the concat task.
 */
module.exports = function(lineman) {
  //Override application configuration here. Common examples follow in the comments.
  return {

    // API Proxying
    //
    // During development, you'll likely want to make XHR (AJAX) requests to an API on the same
    // port as your lineman development server. By enabling the API proxy and setting the port, all
    // requests for paths that don't match a static asset in ./generated will be forwarded to
    // whatever service might be running on the specified port.
    //
    // server: {
    //   apiProxy: {
    //     enabled: true,
    //     host: 'localhost',
    //     port: 3000
    //   }
    // }

    // Sass
    //
    // Lineman supports Sass via grunt-contrib-sass, which requires you first
    // have Ruby installed as well as the `sass` gem. To enable it, comment out the
    // following line:
    //
    // enableSass: false

    // Asset Fingerprints
    //
    // Lineman can fingerprint your static assets by appending a hash to the filename
    // and logging a manifest of logical-to-hashed filenames in dist/assets.json
    // via grunt-asset-fingerprint
    //
    // enableAssetFingerprint: false

  };
};
<commit_msg>Comment out "true" instead of default<commit_after>/* Exports a function which returns an object that overrides the default &
 *   plugin grunt configuration object.
 *
 * You can familiarize yourself with Lineman's defaults by checking out:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
 *   - https://github.com/linemanjs/lineman/blob/master/config/plugins
 *
 * You can also ask Lineman's about config from the command line:
 *
 *   $ lineman config #=> to print the entire config
 *   $ lineman config concat.js #=> to see the JS config for the concat task.
 */
module.exports = function(lineman) {
  //Override application configuration here. Common examples follow in the comments.
  return {

    // API Proxying
    //
    // During development, you'll likely want to make XHR (AJAX) requests to an API on the same
    // port as your lineman development server. By enabling the API proxy and setting the port, all
    // requests for paths that don't match a static asset in ./generated will be forwarded to
    // whatever service might be running on the specified port.
    //
    // server: {
    //   apiProxy: {
    //     enabled: true,
    //     host: 'localhost',
    //     port: 3000
    //   }
    // }

    // Sass
    //
    // Lineman supports Sass via grunt-contrib-sass, which requires you first
    // have Ruby installed as well as the `sass` gem. To enable it, comment out the
    // following line:
    //
    // enableSass: true

    // Asset Fingerprints
    //
    // Lineman can fingerprint your static assets by appending a hash to the filename
    // and logging a manifest of logical-to-hashed filenames in dist/assets.json
    // via grunt-asset-fingerprint
    //
    // enableAssetFingerprint: true

  };
};
<|endoftext|>


<commit_before>exports.capabilities = {}
_globals.closeApp = function() {
	log("closeApp: stub")
}

exports.init = function(ctx) {
	log('backend initialization...')
	var options = ctx.options
	var nativeContext = options.nativeContext

	var oldOn = fd.Object.prototype.on
	fd.Element.prototype.on = function(name, callback) {
		oldOn.call(this, name, ctx.wrapNativeCallback(callback))
	}

	ctx._attachElement(nativeContext)
	ctx.width = nativeContext.width
	ctx.height = nativeContext.height
	nativeContext.on('resize', function(w, h) {
		log("resizing context to " + w + 'x' + h)
		ctx.system.resolutionWidth = w
		ctx.system.resolutionHeight = h
		ctx.width = w
		ctx.height = h
	})
	nativeContext.on('keydown', ctx.wrapNativeCallback(function(key) {
		var event = {
			timestamp: new Date().getTime()
		}
		return ctx.processKey(key, event)
	}))
	log('window size', ctx.width, ctx.height)
}

exports.run = function(ctx, callback) {
	//schedule onload event
	callback()
}

exports.initSystem = function(system) {
}

exports.createElement = function(ctx, tag, cls) {
	switch(tag) {
		case 'input':
			return new fd.Input()
		default:
			return new fd.Element()
	}
}

exports.initRectangle = function(rect) {
	rect._attachElement(new fd.Rectangle())
}

exports.initImage = function(image) {
	image._attachElement(new fd.Image())
}

var ImageStatusNull			= 0
var ImageStatusLoaded		= 1
var ImageStatusUnloaded		= 2
var ImageStatusError		= 3

exports.loadImage = function(image) {
	image.element.load(image.source, function(metrics) {
		if (metrics) {
			image.sourceWidth = metrics.width
			image.sourceHeight = metrics.height
			image.paintedWidth = metrics.width
			image.paintedHeight = metrics.height
		}
		else
			image._onError()
	})
}

exports.initText = function(text) {
	text._attachElement(new fd.Text())
}

exports.setText = function(text, html) {
	text.element.setText(html)
}

exports.layoutText = function(text) {
	text.element.layoutText(function(metrics) {
		if (metrics !== null) {
			text.paintedWidth = metrics.width
			text.paintedHeight = metrics.height
		} else
			console.log('failed to layout text', text.text)
	})
}

exports.setAnimation = function (component, name, animation) {
	return false
}

exports.requestAnimationFrame = function(callback) {
	return setTimeout(callback, 0)
}

exports.cancelAnimationFrame = function (timer) {
	clearTimeout(timer)
}

exports.tick = function(ctx) {
	fd.paint()
}

exports.ajax = function(ui, request) {
	var error = request.error, done = request.done
	var ctx = ui._context
	if (error)
		request.error = ctx.wrapNativeCallback(function(event) { ui.loading = false; log("Error", event); error(event); })
	if (done)
		request.done = ctx.wrapNativeCallback(function(event) { ui.loading = false; done(event); })

	ui.loading = true
	return fd.httpRequest(request)
}
<commit_msg>Set android image status to ready when image is loaded<commit_after>exports.capabilities = {}
_globals.closeApp = function() {
	log("closeApp: stub")
}

exports.init = function(ctx) {
	log('backend initialization...')
	var options = ctx.options
	var nativeContext = options.nativeContext

	var oldOn = fd.Object.prototype.on
	fd.Element.prototype.on = function(name, callback) {
		oldOn.call(this, name, ctx.wrapNativeCallback(callback))
	}

	ctx._attachElement(nativeContext)
	ctx.width = nativeContext.width
	ctx.height = nativeContext.height
	nativeContext.on('resize', function(w, h) {
		log("resizing context to " + w + 'x' + h)
		ctx.system.resolutionWidth = w
		ctx.system.resolutionHeight = h
		ctx.width = w
		ctx.height = h
	})
	nativeContext.on('keydown', ctx.wrapNativeCallback(function(key) {
		var event = {
			timestamp: new Date().getTime()
		}
		return ctx.processKey(key, event)
	}))
	log('window size', ctx.width, ctx.height)
}

exports.run = function(ctx, callback) {
	//schedule onload event
	callback()
}

exports.initSystem = function(system) {
}

exports.createElement = function(ctx, tag, cls) {
	switch(tag) {
		case 'input':
			return new fd.Input()
		default:
			return new fd.Element()
	}
}

exports.initRectangle = function(rect) {
	rect._attachElement(new fd.Rectangle())
}

exports.initImage = function(image) {
	image._attachElement(new fd.Image())
}

var ImageStatusNull			= 0
var ImageStatusLoaded		= 1
var ImageStatusUnloaded		= 2
var ImageStatusError		= 3

exports.loadImage = function(image) {
	image.element.load(image.source, function(metrics) {
		if (metrics) {
			image.sourceWidth = metrics.width
			image.sourceHeight = metrics.height
			image.paintedWidth = metrics.width
			image.paintedHeight = metrics.height
			image.status = ImageStatusLoaded
		}
		else
			image._onError()
	})
}

exports.initText = function(text) {
	text._attachElement(new fd.Text())
}

exports.setText = function(text, html) {
	text.element.setText(html)
}

exports.layoutText = function(text) {
	text.element.layoutText(function(metrics) {
		if (metrics !== null) {
			text.paintedWidth = metrics.width
			text.paintedHeight = metrics.height
		} else
			console.log('failed to layout text', text.text)
	})
}

exports.setAnimation = function (component, name, animation) {
	return false
}

exports.requestAnimationFrame = function(callback) {
	return setTimeout(callback, 0)
}

exports.cancelAnimationFrame = function (timer) {
	clearTimeout(timer)
}

exports.tick = function(ctx) {
	fd.paint()
}

exports.ajax = function(ui, request) {
	var error = request.error, done = request.done
	var ctx = ui._context
	if (error)
		request.error = ctx.wrapNativeCallback(function(event) { ui.loading = false; log("Error", event); error(event); })
	if (done)
		request.done = ctx.wrapNativeCallback(function(event) { ui.loading = false; done(event); })

	ui.loading = true
	return fd.httpRequest(request)
}
<|endoftext|>


<commit_before>require('../../support');
var _ = require('ramda');

// Exercise 1
//==============
// Refactor to remove all arguments by partially applying the function

// var words = function (str) {
//   return split(' ', str);
// };

var words = _.split(' ');

// Exercise 1a
//==============
// Use map to make a new words fn that works on an array of strings.

var sentences = _.map(words);

// Exercise 2
//==============
// Refactor to remove all arguments by partially applying the functions

// var filterQs = function (xs) {
//   return filter(function (x) { return match(/q/i, x);  }, xs);
// };

var matchQs = match(/q/i);
var filterQs = filter(matchQs);

// Exercise 3
//==============
// Use the helper function _keepHighest to refactor max to not reference any arguments

// LEAVE BE:
var _keepHighest = function(x,y){ return x >= y ? x : y; };

// REFACTOR THIS ONE:
// var max = function (xs) {
//   return reduce(function (acc, x) {
//     return _keepHighest(acc, x);
//   }, 0, xs);
// };

var max = reduce(_keepHighest, 0);

// Bonus 1:
// ============
// wrap array's slice to be functional and curried.
// //[1,2,3].slice(0, 2)
var slice = _.curry(function (x, y, xs) { return xs.slice(x, y); });

// Bonus 2:
// ============
// use slice to define a function "take" that takes n elements. Make it curried
var take = undefined;

module.exports = { words: words,
                   sentences: sentences,
                   filterQs: filterQs,
                   max: max,
                   slice: slice,
                   take: take
                 };
<commit_msg>Curry - bonus exercise 2<commit_after>require('../../support');
var _ = require('ramda');

// Exercise 1
//==============
// Refactor to remove all arguments by partially applying the function

// var words = function (str) {
//   return split(' ', str);
// };

var words = _.split(' ');

// Exercise 1a
//==============
// Use map to make a new words fn that works on an array of strings.

var sentences = _.map(words);

// Exercise 2
//==============
// Refactor to remove all arguments by partially applying the functions

// var filterQs = function (xs) {
//   return filter(function (x) { return match(/q/i, x);  }, xs);
// };

var matchQs = match(/q/i);
var filterQs = filter(matchQs);

// Exercise 3
//==============
// Use the helper function _keepHighest to refactor max to not reference any arguments

// LEAVE BE:
var _keepHighest = function(x,y){ return x >= y ? x : y; };

// REFACTOR THIS ONE:
// var max = function (xs) {
//   return reduce(function (acc, x) {
//     return _keepHighest(acc, x);
//   }, 0, xs);
// };

var max = reduce(_keepHighest, 0);

// Bonus 1:
// ============
// wrap array's slice to be functional and curried.
// //[1,2,3].slice(0, 2)
var slice = _.curry(function (x, y, xs) { return xs.slice(x, y); });

// Bonus 2:
// ============
// use slice to define a function "take" that takes n elements. Make it curried

var take = slice(0);

module.exports = { words: words,
                   sentences: sentences,
                   filterQs: filterQs,
                   max: max,
                   slice: slice,
                   take: take
                 };
<|endoftext|>


<commit_before>(function () {

    Sudoku.Solver = function (gameBoard, solver) {

        Utils.EventDispatcher.call(this);

        this._n = gameBoard.getGameSize();
        this._nSqrd = this._n * this._n;
        this._gameBoard = gameBoard;

        if (solver instanceof Sudoku.Solver) {
            this._parent = solver;
        } else {
            this._parent = null;
        }

        this._children = []; //for exploring forks

        this._entryList = []; //batch array for values this solver has entered into the gameboard in the order they were entered

        this._certainCells = [];

        this._possibilityCube = Utils.MultiArray(this._nSqrd, this._nSqrd, this._nSqrd);

        for (var i = 0; i < this._nSqrd; i++) {
            for (var j = 0; j < this._nSqrd; j++) {
                for (var k = 0; k < this._nSqrd; k++) {
                    this._possibilityCube[i][j][k] = Sudoku.Solver.possibilityAlive;
                }
            }
        }

        this._rowCounters = Utils.MultiArray(this._nSqrd, this._nSqrd);
        this._columnCounters = Utils.MultiArray(this._nSqrd, this._nSqrd);
        this._elementCounters = Utils.MultiArray(this._nSqrd, this._nSqrd);

        for (var i = 0; i < this._nSqrd; i++) {
            for (var j = 0; j < this._nSqrd; j++) {
                this._rowCounters[i][j] = this._nSqrd;
                this._columnCounters[i][j] = this._nSqrd;
                this._elementCounters[i][j] = this._nSqrd;
            }
        }

        this._subGridCounters = Utils.MultiArray(this._n, this._n, this._nSqrd);

        for (var i = 0; i < this._n; i++) {
            for (var j = 0; j < this._n; j++) {
                for (var k = 0; k < this._nSqrd; k++) {
                    this._subGridCounters[i][j][k] = this._nSqrd;
                }
            }
        }

        initialize.call(this);

    }

    Sudoku.Solver.possibilityAlive = 1;

    Sudoku.Solver.possibilityDead = 0;

    Sudoku.Solver.prototype = {

        constructor:Sudoku.Solver,

        autoSolver:function (delay) {

        },

        possibilityIsAlive:function (i, j, value) {

            return this._possibilityCube[i][j][value - 1] === Sudoku.Solver.possibilityAlive;

        },

        getListOfCertainCells:function () {

            var arr = []
                , tmp = []
                ;

            for (var i = 0, l = this._certainCells.length; i < l; i++) {
                arr[i] = {
                    i:this._certainCells[i].i,
                    j:this._certainCells[i].j,
                    value:this._certainCells[i].value
                }
            }

            return arr;

        }

    };

    function initialize() {

        var value
            ;

        for (var i = 0; i < this._nSqrd; i++) {
            for (var j = 0; j < this._nSqrd; j++) {
                if (value = this._gameBoard.getValue(i, j) !== Sudoku.GameBoard.emptyCell) {
                    killPossibilities.call(this, {i:i, j:j, value:value});
                }
            }
        }

        this._gameBoard.addEventListener('valueEntered', killPossibilities.bind(this));

        this._gameBoard.addEventListener('valueCleared', revivePossibilities.bind(this));

        this._gameBoard.addEventListener('batchValueEntered', batchKillPossibilities.bind(this));

        this._gameBoard.addEventListener('batchValueCleared', batchRevivePossibilities.bind(this));

        this.addEventListener('insolvableBranch', insolvableBranch.bind(this));

        return this;

    }

    function killPossibilities(event) {

        var i = event.i
            , j = event.j
            , k = event.value - 1
            , sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j)
            , gbc = {i:event.i, j:event.j, value:event.value}
            , iTemp
            , jTemp
            , kTemp
            ;

        /*killRowPossibilities*/
        for (var jTemp = 0; jTemp < this._nSqrd; jTemp++) {
            killPossibility.call(this, i, jTemp, k, gbc);
        }
        /*killColumnPossibilities*/
        for (var iTemp = 0; iTemp < this._nSqrd; iTemp++) {
            killPossibility.call(this, iTemp, j, k, gbc);
        }
        /*killElementPossibilities*/
        for (var kTemp = 0; kTemp < this._nSqrd; kTemp++) {
            killPossibility.call(this, i, j, kTemp, gbc);
        }
        /*killSubGridPossibilities*/
        for (var iTemp = sgb.iLower; iTemp <= sgb.iUpper; iTemp++) {
            for (var jTemp = sgb.jLower; jTemp <= sgb.jUpper; jTemp++) {
                killPossibility.call(this, iTemp, jTemp, k, gbc);
            }
        }

        return this;

    }

    function revivePossibilities(event) {

        var i = event.i
            , j = event.j
            , k = event.value - 1
            , sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j)
            , iTemp
            , jTemp
            , kTemp
            ;

        /*reviveRowPossibilities*/
        for (var jTemp = 0; jTemp < this._nSqrd; jTemp++) {
            revivePossibility.call(this, i, jTemp, k);
        }
        /*reviveColumnPossibilities*/
        for (var iTemp = 0; iTemp < this._nSqrd; iTemp++) {
            revivePossibility.call(this, iTemp, j, k);
        }
        /*reviveElementPossibilities*/
        for (var kTemp = 0; kTemp < this._nSqrd; kTemp++) {
            revivePossibility.call(this, i, j, kTemp);
        }
        /*revivesubGridPossibilities*/
        for (var iTemp = sgb.iLower; iTemp <= sgb.iUpper; iTemp++) {
            for (var jTemp = sgb.jLower; jTemp <= sgb.jUpper; jTemp++) {
                revivePossibility.call(this, iTemp, jTemp, k)
            }
        }

        return this;

    }

    function batchKillPossibilities(event) {

        event.batch.forEach(
            function (el, idx, arr) {
                killPossibilities.call(this, el);
            },
            this
        );

        return this;

    }

    function revivePossibility(i, j, k) {

        if (this._possibilityCube[i][j][k] === Sudoku.Solver.possibilityDead) {
            this._possibilityCube[i][j][k] = Sudoku.Solver.possibilityAlive;
            incrementCounters.call(this, i, j, k);
            this.dispatchEvent({
                type:"possibilityRevived",
                i:i,
                j:j,
                k:k
            });
        }
        return this;
    }

    function batchRevivePossibilities(event) {

        event.batch.forEach(
            function (el, idx, arr) {
                revivePossibilities.call(this, el);
            },
            this
        );

        return this;

    }

    function killPossibility(i, j, k, gbc) {

        if (this._possibilityCube[i][j][k] === Sudoku.Solver.possibilityAlive) {
            this._possibilityCube[i][j][k] = Sudoku.Solver.possibilityDead;
            decrementCounters.call(this, i, j, k, gbc);
            this.dispatchEvent({
                type:"possibilityKilled",
                i:i,
                j:j,
                k:k
            });
        }
        return this;

    }

    function getListOfCertainCells(certainCells) {

        var sgb;

        for (var i = 0; i < this._nSqrd; i++) {
            for (var k = 0; k < this._nSqrd; k++) {
                if (this._rowCounters[i][k] === 1) {
                    for (var jTemp = 0; jTemp < this._nSqrd; jTemp++) {
                        if (this._possibilityCube[i][jTemp][k] === Sudoku.Solver.possibilityAlive) {
                            certainCells.push({i:i, j:jTemp, value:k + 1, type:['row']});
                            break;
                        }
                    }
                }
            }
        }
        for (var j = 0; j < this._nSqrd; j++) {
            for (var k = 0; k < this._nSqrd; k++) {
                if (this._columnCounters[j][k] === 1) {
                    for (var iTemp = 0; iTemp < this._nSqrd; iTemp++) {
                        if (this._possibilityCube[iTemp][j][k] === Sudoku.Solver.possibilityAlive) {
                            certainCells.push({i:iTemp, j:j, value:k + 1, type:['column']});
                            break;
                        }
                    }
                }
            }
        }
        for (var i = 0; i < this._nSqrd; i++) {
            for (var j = 0; j < this._nSqrd; j++) {
                if (this._elementCounters[i][j] === 1) {
                    for (var kTemp = 0; kTemp < this._nSqrd; kTemp++) {
                        if (this._possibilityCube[i][j][kTemp] === Sudoku.Solver.possibilityAlive) {
                            certainCells.push({i:i, j:j, value:kTemp + 1, type:['element']});
                            break;
                        }
                    }
                }
            }
        }
        for (var i = 0; i < this._n; i++) {
            for (var j = 0; j < this._n; j++) {
                for (var k = 0; k < this._nSqrd; k++) {
                    if (this._subGridCounters[i][j][k] === 1) {
                        sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j);

                    }
                }
            }
        }
    }

    function consolidateCertainCells(newEl) {

        var newElAdded = false;

        certainCells.forEach(
            function (el, idx, arr) {
                if (el.i === newE) {

                }
            },
            this
        );

        if (!newElAdded) {

        }

    }

    /* gbc -> gameBoardCell coordinates and value for the
     cell that started the killing process for error checking
     purposes
     */
    function decrementCounters(i, j, k, gbc) {
        var errorFound = false
            , sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j)
            , gbcSgb = this._gameBoard.getSubGridBoundsContainingCell(gbc.i, gbc.j)
            ;
        /*
         decrement relevant counters and if the counter
         is zero and the relevant dimension is not the same
         as the originating cell that started the killing process this
         branch has no solution and need not be investigated further
         */
        this._rowCounters[i][k]--;
        this._columnCounters[j][k]--;
        this._elementCounters[i][j]--;
        this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k]--;

        if (this._rowCounters[i][k] === 1) {
            addCertainCellByRowCounter.call(this, i, k);
        }
        if (this._columnCounters[j][k] === 1) {
            addCertainCellByColumnCounter.call(this, j, k);
        }
        if (this._elementCounters[i][j] === 1) {
            addCertainCellByElementCounter.call(this, i, j);
        }
        if (this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k] === 1) {
            addCertainCellBySubGridCounter.call(this, sgb.iSubGrid, sgb.jSubGrid, k);
        }

        if (this._rowCounters[i][k] === 0) {
            removeCertainCellByRowCounter.call(this, i, k);
            if (gbc.i !== i) {
                errorFound = true;
            }
        }
        if (this._columnCounters[j][k] === 0) {
            removeCertainCellByColumnCounter.call(this, j, k);
            if (gbc.j !== j) {
                errorFound = true;
            }
        }
        if (this._elementCounters[i][j] === 0) {
            removeCertainCellByElementCounter.call(this, i, j);
            if (gbc.i !== i && gbc.j !== j) {
                errorFound = true;
            }
        }
        if (this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k] === 0) {
            removeCertainCellBySubGridCounter.call(this, sgb.iSubGrid, sgb.jSubGrid, k);
            if (gbcSgb.iSubGrid !== sgb.iSubGrid && gbcSgb.jSubGrid !== sgb.jSubGrid) {
                errorFound = true;
            }
        }

        if (errorFound) {
            this.dispatchEvent({
                type:"insolvableBranch"
            });
        }
    }

    function incrementCounters(i, j, k) {

        var sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j);

        this._rowCounters[i][k]++;
        this._columnCounters[j][k]++;
        this._elementCounters[i][j]++;
        this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k]++;

        if (this._rowCounters[i][k] === 1) {
            addCertainCellByRowCounter.call(this, i, k);
        }
        if (this._columnCounters[j][k] === 1) {
            addCertainCellByColumnCounter.call(this, j, k);
        }
        if (this._elementCounters[i][j] === 1) {
            addCertainCellByElementCounter.call(this, i, j);
        }
        if (this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k] === 1) {
            addCertainCellBySubGridCounter.call(this, sgb.iSubGrid, sgb.jSubGrid, k);
        }

        if (this._rowCounters[i][k] === 2) {
            removeCertainCellByRowCounter.call(this, i, k);
        }
        if (this._columnCounters[j][k] === 2) {
            removeCertainCellByColumnCounter.call(this, j, k);
        }
        if (this._elementCounters[i][j] === 2) {
            removeCertainCellByElementCounter.call(this, i, j);
        }
        if (this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k] === 2) {
            removeCertainCellBySubGridCounter.call(this, sgb.iSubGrid, sgb.jSubGrid, k);
        }
    }

    function insolvableBranch() {

    }

})();<commit_msg>much work done on issue #1 adding underlying functionality to solver.<commit_after>(function () {

    Sudoku.Solver = function (gameBoard, solver, guessedCell) {

        Utils.EventDispatcher.call(this);

        this._n = gameBoard.getGameSize();
        this._nSqrd = this._n * this._n;
        this._gameBoard = gameBoard;

        if (solver instanceof Sudoku.Solver) {
            this._parent = solver;
            this._guessedCell = guessedCell;
        } else {
            this._parent = null;
            this._guessedCell = null;
        }

        this._children = []; //for exploring forks

        this._entryList = []; //batch array for values this solver has entered into the gameboard in the order they were entered

        this._certainCells = [];

        this._possibilityCube = Utils.MultiArray(this._nSqrd, this._nSqrd, this._nSqrd);

        for (var i = 0; i < this._nSqrd; i++) {
            for (var j = 0; j < this._nSqrd; j++) {
                for (var k = 0; k < this._nSqrd; k++) {
                    this._possibilityCube[i][j][k] = Sudoku.Solver.possibilityAlive;
                }
            }
        }

        this._rowCounters = Utils.MultiArray(this._nSqrd, this._nSqrd);
        this._columnCounters = Utils.MultiArray(this._nSqrd, this._nSqrd);
        this._elementCounters = Utils.MultiArray(this._nSqrd, this._nSqrd);

        for (var i = 0; i < this._nSqrd; i++) {
            for (var j = 0; j < this._nSqrd; j++) {
                this._rowCounters[i][j] = this._nSqrd;
                this._columnCounters[i][j] = this._nSqrd;
                this._elementCounters[i][j] = this._nSqrd;
            }
        }

        this._subGridCounters = Utils.MultiArray(this._n, this._n, this._nSqrd);

        for (var i = 0; i < this._n; i++) {
            for (var j = 0; j < this._n; j++) {
                for (var k = 0; k < this._nSqrd; k++) {
                    this._subGridCounters[i][j][k] = this._nSqrd;
                }
            }
        }

        initialize.call(this);

    }

    Sudoku.Solver.possibilityAlive = 1;

    Sudoku.Solver.possibilityDead = 0;

    Sudoku.Solver.prototype = {

        constructor:Sudoku.Solver,

        autoSolve:function (delay) {

        },

        possibilityIsAlive:function (i, j, value) {

            return this._possibilityCube[i][j][value - 1] === Sudoku.Solver.possibilityAlive;

        },

        getListOfCertainCells:function () {

            var arr = []
                , tempType = []
                ;

            for (var i = 0, l = this._certainCells.length; i < l; i++) {
                for (var j = 0, l = this._certainCells[i].type.length; j < l; j++) {
                    tempType.push(this._certainCells[i].type[j]);
                }
                arr.push({
                    i:this._certainCells[i].i,
                    j:this._certainCells[i].j,
                    value:this._certainCells[i].value,
                    type:tempType
                });
            }

            return arr;

        }

    };

    function initialize() {

        var value
            ;

        for (var i = 0; i < this._nSqrd; i++) {
            for (var j = 0; j < this._nSqrd; j++) {
                if (value = this._gameBoard.getValue(i, j) !== Sudoku.GameBoard.emptyCell) {
                    killPossibilities.call(this, {i:i, j:j, value:value});
                }
            }
        }

        this._gameBoard.addEventListener('valueEntered', killPossibilities.bind(this));

        this._gameBoard.addEventListener('valueCleared', revivePossibilities.bind(this));

        this._gameBoard.addEventListener('batchValueEntered', batchKillPossibilities.bind(this));

        this._gameBoard.addEventListener('batchValueCleared', batchRevivePossibilities.bind(this));

        this.addEventListener('insolvableBranch', insolvableBranch.bind(this));

        return this;

    }

    function killPossibilities(event) {

        var i = event.i
            , j = event.j
            , k = event.value - 1
            , sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j)
            , gbc = {i:event.i, j:event.j, value:event.value}
            , iTemp
            , jTemp
            , kTemp
            ;

        /*killRowPossibilities*/
        for (var jTemp = 0; jTemp < this._nSqrd; jTemp++) {
            killPossibility.call(this, i, jTemp, k, gbc);
        }
        /*killColumnPossibilities*/
        for (var iTemp = 0; iTemp < this._nSqrd; iTemp++) {
            killPossibility.call(this, iTemp, j, k, gbc);
        }
        /*killElementPossibilities*/
        for (var kTemp = 0; kTemp < this._nSqrd; kTemp++) {
            killPossibility.call(this, i, j, kTemp, gbc);
        }
        /*killSubGridPossibilities*/
        for (var iTemp = sgb.iLower; iTemp <= sgb.iUpper; iTemp++) {
            for (var jTemp = sgb.jLower; jTemp <= sgb.jUpper; jTemp++) {
                killPossibility.call(this, iTemp, jTemp, k, gbc);
            }
        }

        return this;

    }

    function revivePossibilities(event) {

        var i = event.i
            , j = event.j
            , k = event.value - 1
            , sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j)
            , iTemp
            , jTemp
            , kTemp
            ;

        /*reviveRowPossibilities*/
        for (var jTemp = 0; jTemp < this._nSqrd; jTemp++) {
            revivePossibility.call(this, i, jTemp, k);
        }
        /*reviveColumnPossibilities*/
        for (var iTemp = 0; iTemp < this._nSqrd; iTemp++) {
            revivePossibility.call(this, iTemp, j, k);
        }
        /*reviveElementPossibilities*/
        for (var kTemp = 0; kTemp < this._nSqrd; kTemp++) {
            revivePossibility.call(this, i, j, kTemp);
        }
        /*revivesubGridPossibilities*/
        for (var iTemp = sgb.iLower; iTemp <= sgb.iUpper; iTemp++) {
            for (var jTemp = sgb.jLower; jTemp <= sgb.jUpper; jTemp++) {
                revivePossibility.call(this, iTemp, jTemp, k)
            }
        }

        return this;

    }

    function batchKillPossibilities(event) {

        event.batch.forEach(
            function (el, idx, arr) {
                killPossibilities.call(this, el);
            },
            this
        );

        return this;

    }

    function batchRevivePossibilities(event) {

        event.batch.forEach(
            function (el, idx, arr) {
                revivePossibilities.call(this, el);
            },
            this
        );

        return this;

    }

    function revivePossibility(i, j, k) {

        if (this._possibilityCube[i][j][k] === Sudoku.Solver.possibilityDead) {
            this._possibilityCube[i][j][k] = Sudoku.Solver.possibilityAlive;
            incrementCounters.call(this, i, j, k);
            this.dispatchEvent({
                type:"possibilityRevived",
                i:i,
                j:j,
                k:k
            });
        }
        return this;
    }

    function killPossibility(i, j, k, gbc) {

        if (this._possibilityCube[i][j][k] === Sudoku.Solver.possibilityAlive) {
            this._possibilityCube[i][j][k] = Sudoku.Solver.possibilityDead;
            decrementCounters.call(this, i, j, k, gbc);
            this.dispatchEvent({
                type:"possibilityKilled",
                i:i,
                j:j,
                k:k
            });
        }
        return this;

    }

    function addCertainCell(cert) {

        var certAdded = false
            , certDuplicate = false
            ;

        for (var i = 0, l = this._certainCells.length; i < l; i++) {
            if (this._certainCells[i].i === cert.i && this._certainCells[i].j === cert.j) {
                if (this._certainCells[i].type.indexOf(cert.type[0]) === -1) {
                    this._certainCells[i].type.push(cert.type[0]);
                    certAdded = true;
                } else {
                    certDuplicate = true;
                }
            }
        }

        if (!certAdded && !certDuplicate) {
            this._certainCells.push(cert)
        }

        return this;

    }

    function removeCertainCell(cert) {

        var idx;

        for (var i = 0, l = this._certainCells.length; i < l; i++) {
            if (this._certainCells[i].i === cert.i && this._certainCells[i].j === cert.j) {
                idx = this._certainCells[i].type.indexOf(cert.type[0]);
                if(idx !== -1){
                    this._certainCells[i].type.splice(idx,1);
                    if(this._certainCells[i].type.length === 0){
                        this._certainCells.splice(i,1);
                    }
                }
            }
        }

        return this;

    }

    /* gbc -> gameBoardCell coordinates and value for the
     cell that started the killing process for error checking
     purposes
     */
    function decrementCounters(i, j, k, gbc) {
        var errorFound = false
            , sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j)
            , gbcSgb = this._gameBoard.getSubGridBoundsContainingCell(gbc.i, gbc.j)
            ;
        /*
         decrement relevant counters and if the counter
         is zero and the relevant dimension is not the same
         as the originating cell that started the killing process this
         branch has no solution and need not be investigated further
         */
        this._rowCounters[i][k]--;
        this._columnCounters[j][k]--;
        this._elementCounters[i][j]--;
        this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k]--;

        if (this._rowCounters[i][k] === 1) {
            addCertainCellByRowCounter.call(this, i, k);
        }
        if (this._columnCounters[j][k] === 1) {
            addCertainCellByColumnCounter.call(this, j, k);
        }
        if (this._elementCounters[i][j] === 1) {
            addCertainCellByElementCounter.call(this, i, j);
        }
        if (this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k] === 1) {
            addCertainCellBySubGridCounter.call(this, sgb.iSubGrid, sgb.jSubGrid, k);
        }

        if (this._rowCounters[i][k] === 0) {
            removeCertainCellByRowCounter.call(this, i, k);
            if (gbc.i !== i) {
                errorFound = true;
            }
        }
        if (this._columnCounters[j][k] === 0) {
            removeCertainCellByColumnCounter.call(this, j, k);
            if (gbc.j !== j) {
                errorFound = true;
            }
        }
        if (this._elementCounters[i][j] === 0) {
            removeCertainCellByElementCounter.call(this, i, j);
            if (gbc.i !== i && gbc.j !== j) {
                errorFound = true;
            }
        }
        if (this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k] === 0) {
            removeCertainCellBySubGridCounter.call(this, sgb.iSubGrid, sgb.jSubGrid, k);
            if (gbcSgb.iSubGrid !== sgb.iSubGrid && gbcSgb.jSubGrid !== sgb.jSubGrid) {
                errorFound = true;
            }
        }

        if (errorFound) {
            this.dispatchEvent({
                type:"insolvableBranch"
            });
        }
    }

    function incrementCounters(i, j, k) {

        var sgb = this._gameBoard.getSubGridBoundsContainingCell(i, j);

        this._rowCounters[i][k]++;
        this._columnCounters[j][k]++;
        this._elementCounters[i][j]++;
        this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k]++;

        if (this._rowCounters[i][k] === 1) {
            addCertainCellByRowCounter.call(this, i, k);
        }
        if (this._columnCounters[j][k] === 1) {
            addCertainCellByColumnCounter.call(this, j, k);
        }
        if (this._elementCounters[i][j] === 1) {
            addCertainCellByElementCounter.call(this, i, j);
        }
        if (this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k] === 1) {
            addCertainCellBySubGridCounter.call(this, sgb.iSubGrid, sgb.jSubGrid, k);
        }

        if (this._rowCounters[i][k] === 2) {
            removeCertainCellByRowCounter.call(this, i, k);
        }
        if (this._columnCounters[j][k] === 2) {
            removeCertainCellByColumnCounter.call(this, j, k);
        }
        if (this._elementCounters[i][j] === 2) {
            removeCertainCellByElementCounter.call(this, i, j);
        }
        if (this._subGridCounters[sgb.iSubGrid][sgb.jSubGrid][k] === 2) {
            removeCertainCellBySubGridCounter.call(this, sgb.iSubGrid, sgb.jSubGrid, k);
        }
    }

    function insolvableBranch() {

    }

})();<|endoftext|>


<commit_before>function ContainerBuilder() {
    _.superClass(ContainerBuilder, this);
}

window.InfinniUI.ContainerBuilder = ContainerBuilder;

_.inherit(ContainerBuilder, ElementBuilder);

/**
 * @abstract
 */
_.extend(ContainerBuilder.prototype, {

    /**
     *
     * @param params
     * @returns {{itemsBinding: {DataBinding}}}
     */
    applyMetadata: function (params) {
        var metadata = params.metadata;
        var element = params.element;
        var itemsBinding;

        ElementBuilder.prototype.applyMetadata.call(this, params);

        itemsBinding = this.initItems(params);
        this.initGroup(params, itemsBinding);

        return {
            itemsBinding: itemsBinding
        };
    },

    initItems: function (params) {
        var metadata = params.metadata;
        var itemsBinding = null;

        if (Array.isArray(metadata.Items)) {  // отдельные не шаблонизируемые items, в metadata.Items - список методанных item'ов
            this.initNotTemplatingItems(params);
        } else if (metadata.Items) {                          // шаблонизируемые однотипные items, в metadata.Items - биндинг на данные item'ов
            itemsBinding = this.initTemplatingItems(params);
        }

        return itemsBinding;
    },

    initTemplatingItems: function (params) {
        var metadata = params.metadata;
        var element = params.element;
        var itemTemplate;
        var binding;
        var property;

        binding = params.builder.buildBinding(metadata.Items, {
            parentView: params.parentView,
            basePathOfProperty: params.basePathOfProperty
        });

        binding.setMode(InfinniUI.BindingModes.toElement);

        //if ('ItemComparator' in metadata) {
        this.bindElementItemsWithSorting(binding, params);
        //} else {
        //    binding.bindElement(element, 'items');
        //}

        if ('ItemTemplate' in metadata) {
            itemTemplate = this.buildItemTemplate(metadata.ItemTemplate, params);
        } else if ('ItemFormat' in metadata) {
            itemTemplate = this.buildItemFormat(binding, metadata.ItemFormat, params);
        } else if ('ItemSelector' in metadata) {
            itemTemplate = this.buildItemSelector(binding, metadata.ItemSelector, params);
        } else {
            if ('ItemProperty' in metadata) {
                property = metadata.ItemProperty;
            } else {
                property = '';
            }
            itemTemplate = this.buildItemProperty(binding, property, params);
        }

        element.setItemTemplate(itemTemplate);

        return binding;
    },

    initNotTemplatingItems: function (params) {
        var itemsMetadata = params.metadata.Items;
        var element = params.element;
        //var fakeItems = (new Array(itemsMetadata.length + 1)).join(' ').split('');
        var items = itemsMetadata.slice(0);
        element.getItems().set(items);
        var itemTemplate = this.buildItemTemplateForUniqueItem(items, params);
        element.setItemTemplate(itemTemplate);
    },

    tuneItemsBinding: function (itemsBinding) {
        var source = itemsBinding.getSource();
        if (typeof source.tryInitData == 'function') {
            source.tryInitData();
        }
    },

    initGroup: function (params, itemsBinding) {
        if (this.hasGrouping(params)) {
            this.initGroupValueSelector(params);
            this.initGroupItemTemplate(params, itemsBinding);
        }
    },

    hasGrouping: function (params) {
        return params.metadata.GroupValueSelector || params.metadata.GroupValueProperty;
    },

    initGroupValueSelector: function (params) {
        var metadata = params.metadata,
            element = params.element,
            groupValueSelector;

        /* element.setGroupItemComparator(function(a, b) {
         if (a < b) {
         return -1;
         }

         if (a > b) {
         return 1;
         }

         return 0;
         });*/

        if (metadata.GroupValueSelector) {
            groupValueSelector = function (context, args) {
                var scriptExecutor = new ScriptExecutor(element.getScriptsStorage());
                return scriptExecutor.executeScript(metadata.GroupValueSelector.Name || metadata.GroupValueSelector, args)
            };
        } else if (metadata.GroupValueProperty) {
            groupValueSelector = function (context, args) {
                return InfinniUI.ObjectUtils.getPropertyValue(args.value, metadata.GroupValueProperty);
            }
        } else {
            //Без группировки
            groupValueSelector = null
        }
        element.setGroupValueSelector(groupValueSelector);
    },

    initGroupItemTemplate: function (params, itemsBinding) {
        var metadata = params.metadata;
        var element = params.element;
        var itemTemplate;
        var property;

        if (metadata.GroupItemTemplate) {
            itemTemplate = this.buildItemTemplate(metadata.GroupItemTemplate, params);
        } else if (metadata.GroupItemFormat) {
            itemTemplate = this.buildItemFormat(itemsBinding, metadata.GroupItemFormat, params);
        } else if (metadata.GroupItemSelector) {
            itemTemplate = this.buildItemSelector(itemsBinding, metadata.GroupItemSelector, params);
        } else if (metadata.GroupItemProperty) {
            itemTemplate = this.buildItemProperty(itemsBinding, metadata.GroupItemProperty, params);
        }

        if (itemTemplate) {
            element.setGroupItemTemplate(itemTemplate);
        }
    },

    buildItemProperty: function (itemsBinding, itemPropertyMetadata, params) {

        return function (context, args) {
            var index = args.index;
            var label = new Label(this);
            var sourceProperty;
            var source = itemsBinding.getSource();
            var binding = new DataBinding();

            sourceProperty = index.toString();
            if (itemsBinding.getSourceProperty() != '') {
                sourceProperty = itemsBinding.getSourceProperty() + '.' + sourceProperty;
            }
            if (itemPropertyMetadata != '') {
                sourceProperty = sourceProperty + '.' + itemPropertyMetadata;
            }

            binding.bindSource(source, sourceProperty);
            binding.bindElement(label, 'value');

            return label;
        };
    },

    buildItemFormat: function (itemsBinding, itemFormatMetadata, params) {

        var format = this.buildDisplayFormat(itemFormatMetadata, params);
        return function (context, args) {
            var index = args.index;
            var label = new Label(this);

            var sourceProperty = itemsBinding.getSourceProperty();
            var source = itemsBinding.getSource();
            var binding = new DataBinding();

            sourceProperty = index.toString();
            if (itemsBinding.getSourceProperty() != '') {
                sourceProperty = itemsBinding.getSourceProperty() + '.' + sourceProperty;
            }

            label.setDisplayFormat(format);

            binding.bindSource(source, sourceProperty);
            binding.bindElement(label, 'value');

            return label;
        };

    },

    buildItemSelector: function (itemsBinding, itemSelectorMetadata, params) {

        return function (context, args) {
            var index = args.index;
            var label = new Label(this);
            var scriptExecutor = new ScriptExecutor(params.parentView);

            var sourceProperty = itemsBinding.getSourceProperty();
            var source = itemsBinding.getSource();
            var binding = new DataBinding();
            binding.setMode(InfinniUI.BindingModes.toElement);

            sourceProperty = index.toString();
            if (itemsBinding.getSourceProperty() != '') {
                sourceProperty = itemsBinding.getSourceProperty() + '.' + sourceProperty;
            }

            binding.setConverter({
                toElement: function (_context, _args) {
                    return scriptExecutor.executeScript(itemSelectorMetadata.Name || itemSelectorMetadata, _args);
                }
            });

            binding.bindSource(source, sourceProperty);
            binding.bindElement(label, 'value');

            return label;
        }
    },

    buildItemTemplate: function (templateMetadata, params) {
        var element = params.element;
        var builder = params.builder;
        var basePathOfProperty = params.basePathOfProperty || new BasePathOfProperty('');
        var propertyForSource = params.metadata['Items']['Property'] || '';
        var that = this;

        return function (context, args) {
            var index = args.index;
            var bindingIndex;
            var argumentForBuilder = {
                parent: params.element,
                parentView: params.parentView
            };

            if (index !== undefined && index !== null) {
                bindingIndex = that.bindingIndexByItemsIndex(index, params);

                if (bindingIndex !== undefined && bindingIndex !== null) {
                    argumentForBuilder.basePathOfProperty = basePathOfProperty.buildChild(propertyForSource, bindingIndex);
                } else {
                    argumentForBuilder.basePathOfProperty = basePathOfProperty.buildChild(propertyForSource, index);
                }
            }

            return builder.build(templateMetadata, argumentForBuilder);
        };
    },

    /**
     * @public
     * @memberOf ContainerBuilder
     * @description Возвращает функцию itemTemplate для не шаблонизируемого item'а.
     * @param {Object} itemMetadata метаданные.
     * @param {Object} params стандартные params, передаваемые внутри билдеров.
     **/
    buildItemTemplateForUniqueItem: function (itemsMetadata, params) {
        var element = params.element;
        var builder = params.builder;
        var basePathOfProperty = params.basePathOfProperty || new BasePathOfProperty('');

        return function (context, args) {

            var
                index = args.index,
                item = element.getItems().getByIndex(index),
                argumentForBuilder = {
                    parent: params.element,
                    parentView: params.parentView,
                    basePathOfProperty: basePathOfProperty
                };

            return builder.build(item, argumentForBuilder);
        };
    },

    bindingIndexByItemsIndex: function (index, params) {
        var element = params.element,
            items = element.getItems();

        return items.getProperty(index, 'bindingIndex');
    },

    bindElementItemsWithSorting: function (binding, params) {
        // нетривиальный биндинг элементов нужен для того, чтобы правильно учитывались индексы при сортировке элементов

        var metadata = params.metadata,
            element = params.element,
            scriptExecutor = new ScriptExecutor(params.parent),
            itemComparator;

        if(metadata.ItemComparator){
            itemComparator = function (item1, item2) {
                return scriptExecutor.executeScript(metadata.ItemComparator.Name || metadata.ItemComparator, {item1: item1, item2: item2});
            };
        }

        var source = binding.getSource();
        source.onPropertyChanged('*', function (context, args) {
            var items = element.getItems();
            //При замене целого элемента списка, заменить элемент в коллекции
            if (args.property && args.property.match(/^\d+$/)) {
                items.replace(args.oldValue, args.newValue);
            }
        });

        binding.bindElement({
            setProperty: function (name, value) {
                var items = element.getItems(),
                    isCollectionChanged;

                if(itemComparator){

                    isCollectionChanged = items.set(value, true);

                    items.forEach(function (item, index, collection) {
                        collection.setProperty(index, 'bindingIndex', index);
                    });

                    if (isCollectionChanged) {
                        items.sort(itemComparator);
                    }

                }else{

                    isCollectionChanged = items.set(value);

                    items.forEach(function (item, index, collection) {
                        collection.setProperty(index, 'bindingIndex', index);
                    });
                }

            },

            onPropertyChanged: function () {
            }

        }, 'items');
    }

}, displayFormatBuilderMixin);

<commit_msg>UI-2586: При больших объемах данных заметно подвисание представления #resolved<commit_after>function ContainerBuilder() {
    _.superClass(ContainerBuilder, this);
}

window.InfinniUI.ContainerBuilder = ContainerBuilder;

_.inherit(ContainerBuilder, ElementBuilder);

/**
 * @abstract
 */
_.extend(ContainerBuilder.prototype, {

    /**
     *
     * @param params
     * @returns {{itemsBinding: {DataBinding}}}
     */
    applyMetadata: function (params) {
        var metadata = params.metadata;
        var element = params.element;
        var itemsBinding;

        ElementBuilder.prototype.applyMetadata.call(this, params);

        itemsBinding = this.initItems(params);
        this.initGroup(params, itemsBinding);

        return {
            itemsBinding: itemsBinding
        };
    },

    initItems: function (params) {
        var metadata = params.metadata;
        var itemsBinding = null;

        if (Array.isArray(metadata.Items)) {  // отдельные не шаблонизируемые items, в metadata.Items - список методанных item'ов
            this.initNotTemplatingItems(params);
        } else if (metadata.Items) {                          // шаблонизируемые однотипные items, в metadata.Items - биндинг на данные item'ов
            itemsBinding = this.initTemplatingItems(params);
        }

        return itemsBinding;
    },

    initTemplatingItems: function (params) {
        var metadata = params.metadata;
        var element = params.element;
        var itemTemplate;
        var binding;
        var property;

        binding = params.builder.buildBinding(metadata.Items, {
            parentView: params.parentView,
            basePathOfProperty: params.basePathOfProperty
        });

        binding.setMode(InfinniUI.BindingModes.toElement);

        //if ('ItemComparator' in metadata) {
        this.bindElementItemsWithSorting(binding, params);
        //} else {
        //    binding.bindElement(element, 'items');
        //}

        if ('ItemTemplate' in metadata) {
            itemTemplate = this.buildItemTemplate(metadata.ItemTemplate, params);
        } else if ('ItemFormat' in metadata) {
            itemTemplate = this.buildItemFormat(binding, metadata.ItemFormat, params);
        } else if ('ItemSelector' in metadata) {
            itemTemplate = this.buildItemSelector(binding, metadata.ItemSelector, params);
        } else {
            if ('ItemProperty' in metadata) {
                property = metadata.ItemProperty;
            } else {
                property = '';
            }
            itemTemplate = this.buildItemProperty(binding, property, params);
        }

        element.setItemTemplate(itemTemplate);

        return binding;
    },

    initNotTemplatingItems: function (params) {
        var itemsMetadata = params.metadata.Items;
        var element = params.element;
        //var fakeItems = (new Array(itemsMetadata.length + 1)).join(' ').split('');
        var items = itemsMetadata.slice(0);
        element.getItems().set(items);
        var itemTemplate = this.buildItemTemplateForUniqueItem(items, params);
        element.setItemTemplate(itemTemplate);
    },

    tuneItemsBinding: function (itemsBinding) {
        var source = itemsBinding.getSource();
        if (typeof source.tryInitData == 'function') {
            source.tryInitData();
        }
    },

    initGroup: function (params, itemsBinding) {
        if (this.hasGrouping(params)) {
            this.initGroupValueSelector(params);
            this.initGroupItemTemplate(params, itemsBinding);
        }
    },

    hasGrouping: function (params) {
        return params.metadata.GroupValueSelector || params.metadata.GroupValueProperty;
    },

    initGroupValueSelector: function (params) {
        var metadata = params.metadata,
            element = params.element,
            groupValueSelector;

        /* element.setGroupItemComparator(function(a, b) {
         if (a < b) {
         return -1;
         }

         if (a > b) {
         return 1;
         }

         return 0;
         });*/

        if (metadata.GroupValueSelector) {
            groupValueSelector = function (context, args) {
                var scriptExecutor = new ScriptExecutor(element.getScriptsStorage());
                return scriptExecutor.executeScript(metadata.GroupValueSelector.Name || metadata.GroupValueSelector, args)
            };
        } else if (metadata.GroupValueProperty) {
            groupValueSelector = function (context, args) {
                return InfinniUI.ObjectUtils.getPropertyValue(args.value, metadata.GroupValueProperty);
            }
        } else {
            //Без группировки
            groupValueSelector = null
        }
        element.setGroupValueSelector(groupValueSelector);
    },

    initGroupItemTemplate: function (params, itemsBinding) {
        var metadata = params.metadata;
        var element = params.element;
        var itemTemplate;
        var property;

        if (metadata.GroupItemTemplate) {
            itemTemplate = this.buildItemTemplate(metadata.GroupItemTemplate, params);
        } else if (metadata.GroupItemFormat) {
            itemTemplate = this.buildItemFormat(itemsBinding, metadata.GroupItemFormat, params);
        } else if (metadata.GroupItemSelector) {
            itemTemplate = this.buildItemSelector(itemsBinding, metadata.GroupItemSelector, params);
        } else if (metadata.GroupItemProperty) {
            itemTemplate = this.buildItemProperty(itemsBinding, metadata.GroupItemProperty, params);
        }

        if (itemTemplate) {
            element.setGroupItemTemplate(itemTemplate);
        }
    },

    buildItemProperty: function (itemsBinding, itemPropertyMetadata, params) {

        return function (context, args) {
            var index = args.index;
            var label = new Label(this);
            var sourceProperty;
            var source = itemsBinding.getSource();
            var binding = new DataBinding();

            sourceProperty = index.toString();
            if (itemsBinding.getSourceProperty() != '') {
                sourceProperty = itemsBinding.getSourceProperty() + '.' + sourceProperty;
            }
            if (itemPropertyMetadata != '') {
                sourceProperty = sourceProperty + '.' + itemPropertyMetadata;
            }

            binding.bindSource(source, sourceProperty);
            binding.bindElement(label, 'value');

            return label;
        };
    },

    buildItemFormat: function (itemsBinding, itemFormatMetadata, params) {

        var format = this.buildDisplayFormat(itemFormatMetadata, params);
        return function (context, args) {
            var index = args.index;
            var label = new Label(this);

            var sourceProperty = itemsBinding.getSourceProperty();
            var source = itemsBinding.getSource();
            var binding = new DataBinding();

            sourceProperty = index.toString();
            if (itemsBinding.getSourceProperty() != '') {
                sourceProperty = itemsBinding.getSourceProperty() + '.' + sourceProperty;
            }

            label.setDisplayFormat(format);

            binding.bindSource(source, sourceProperty);
            binding.bindElement(label, 'value');

            return label;
        };

    },

    buildItemSelector: function (itemsBinding, itemSelectorMetadata, params) {

        return function (context, args) {
            var index = args.index;
            var label = new Label(this);
            var scriptExecutor = new ScriptExecutor(params.parentView);

            var sourceProperty = itemsBinding.getSourceProperty();
            var source = itemsBinding.getSource();
            var binding = new DataBinding();
            binding.setMode(InfinniUI.BindingModes.toElement);

            sourceProperty = index.toString();
            if (itemsBinding.getSourceProperty() != '') {
                sourceProperty = itemsBinding.getSourceProperty() + '.' + sourceProperty;
            }

            binding.setConverter({
                toElement: function (_context, _args) {
                    return scriptExecutor.executeScript(itemSelectorMetadata.Name || itemSelectorMetadata, _args);
                }
            });

            binding.bindSource(source, sourceProperty);
            binding.bindElement(label, 'value');

            return label;
        }
    },

    buildItemTemplate: function (templateMetadata, params) {
        var element = params.element;
        var builder = params.builder;
        var basePathOfProperty = params.basePathOfProperty || new BasePathOfProperty('');
        var propertyForSource = params.metadata['Items']['Property'] || '';
        var that = this;

        return function (context, args) {
            var index = args.index;
            var bindingIndex;
            var argumentForBuilder = {
                parent: params.element,
                parentView: params.parentView
            };

            if (index !== undefined && index !== null) {
                bindingIndex = that.bindingIndexByItemsIndex(index, params);

                if (bindingIndex !== undefined && bindingIndex !== null) {
                    argumentForBuilder.basePathOfProperty = basePathOfProperty.buildChild(propertyForSource, bindingIndex);
                } else {
                    argumentForBuilder.basePathOfProperty = basePathOfProperty.buildChild(propertyForSource, index);
                }
            }

            return builder.build(templateMetadata, argumentForBuilder);
        };
    },

    /**
     * @public
     * @memberOf ContainerBuilder
     * @description Возвращает функцию itemTemplate для не шаблонизируемого item'а.
     * @param {Object} itemMetadata метаданные.
     * @param {Object} params стандартные params, передаваемые внутри билдеров.
     **/
    buildItemTemplateForUniqueItem: function (itemsMetadata, params) {
        var element = params.element;
        var builder = params.builder;
        var basePathOfProperty = params.basePathOfProperty || new BasePathOfProperty('');

        return function (context, args) {

            var
                index = args.index,
                item = element.getItems().getByIndex(index),
                argumentForBuilder = {
                    parent: params.element,
                    parentView: params.parentView,
                    basePathOfProperty: basePathOfProperty
                };

            return builder.build(item, argumentForBuilder);
        };
    },

    bindingIndexByItemsIndex: function (index, params) {
        var element = params.element,
            items = element.getItems();

        return items.getProperty(index, 'bindingIndex');
    },

    bindElementItemsWithSorting: function (binding, params) {
        // нетривиальный биндинг элементов нужен для того, чтобы правильно учитывались индексы при сортировке элементов

        var metadata = params.metadata,
            element = params.element,
            scriptExecutor = new ScriptExecutor(params.parent),
            itemComparator;

        if(metadata.ItemComparator){
            itemComparator = function (item1, item2) {
                return scriptExecutor.executeScript(metadata.ItemComparator.Name || metadata.ItemComparator, {item1: item1, item2: item2});
            };
        }

        var source = binding.getSource();
        source.onPropertyChanged('*', function (context, args) {
            var items = element.getItems();
            //При замене целого элемента списка, заменить элемент в коллекции
            if (args.property && args.property.match(/^\d+$/)) {
                items.replace(args.oldValue, args.newValue);
            }
        });

        binding.bindElement({
            setProperty: function (name, value) {
                var items = element.getItems(),
                    isCollectionChanged;

                if(!element.isRemoved) {
                    if (itemComparator) {

                        isCollectionChanged = items.set(value, true);

                        items.forEach(function (item, index, collection) {
                            collection.setProperty(index, 'bindingIndex', index);
                        });

                        if (isCollectionChanged) {
                            items.sort(itemComparator);
                        }

                    } else {

                        isCollectionChanged = items.set(value);

                        items.forEach(function (item, index, collection) {
                            collection.setProperty(index, 'bindingIndex', index);
                        });
                    }
                }

            },

            onPropertyChanged: function () {
            }

        }, 'items');
    }

}, displayFormatBuilderMixin);

<|endoftext|>


<commit_before>/**
* Lumberjack
* A logging library for Sails
*/
(function() {
    var winston = require('winston');
    var useFile = true;

    // Parse config
    var logging = sails && sails.config && sails.config.logging;
    if (typeof(logging) === 'undefined') {
        useFile = false;
    } else {
        if (typeof(logging.logFilePath) === 'undefined') {
            useFile = false;
        }
    }

    // Available transports
    var transports = [
        new (winston.transports.Console)({
            colorize: true
        })
    ];

    // If sails.config.logging.useFile option is set, write log output to a flat file
    if (useFile) {
        transports.push(
            new (winston.transports.File)({
                filename: logging.logFilePath,
                maxsize: 10000000,
                maxFiles: 10,
                level: 'info',
                json: false
            })
        );
    }

    // Instantiate winston
    var logger = new (winston.Logger)({
        transports: transports
    });

    // Add logger to global namespace
    sails.log = logger.debug;
    sails.log.debug = exports.debug = logger.debug;
    sails.log.info = exports.info = logger.info;
    sails.log.warn = exports.warn = logger.warn;
    sails.log.error= exports.error = logger.error;
})();
<commit_msg>Made logger accessible to /bin<commit_after>/**
* Lumberjack
* A logging library for Sails
*/
(function() {
    var winston = require('winston');
    var useFile = true;

    // Parse config
    var logging;
    try {
        logging = sails.config.logging;
    }
    catch (e) {
        logging = undefined;
    }

    if (typeof(logging) === 'undefined') {
        useFile = false;
    } else {
        if (typeof(logging.logFilePath) === 'undefined') {
            useFile = false;
        }
    }

    // Available transports
    var transports = [
        new (winston.transports.Console)({
            colorize: true
        })
    ];

    // If sails.config.logging.useFile option is set, write log output to a flat file
    if (useFile) {
        transports.push(
            new (winston.transports.File)({
                filename: logging.logFilePath,
                maxsize: 10000000,
                maxFiles: 10,
                level: 'info',
                json: false
            })
        );
    }

    // Instantiate winston
    var logger = new (winston.Logger)({
        transports: transports
    });

    // Add logger to global namespace
    sails.log = logger.debug;
    sails.log.debug = exports.debug = logger.debug;
    sails.log.info = exports.info = logger.info;
    sails.log.warn = exports.warn = logger.warn;
    sails.log.error= exports.error = logger.error;
})();
<|endoftext|>


<commit_before>define([
  'jquery',
  'backbone',
  'underscore',
  'app',
  'views/views',
  'dc',
  'jqueryresize'
], function($, Backbone, _, App, Views, dc) {

    metricMap = {};
    var palette = d3.scale.category10();
    var graph, hoverDetail, axes;

    var hour = 60*60*1000;

    var dates = {
        "hour": {text: "Last hour", offset: hour, dateformat: "%l:%M"},
        "6hour": {text: "Last 3 hours", offset: 3*hour, dateformat: "%l:%M"},
        "day": {text: "Last day", offset: 24*hour, dateformat: "%l:%M"},
        "week": {text: "Last week", offset: 7*24*hour},
        "month": {text: "Last month", offset: 30*24*hour},
        "6month": {text: "Last 6 months", offset: 182*24*hour},
        "year": {text: "Last year", offset: 365*24*hour}

    };

    var period = dates["day"].offset;

    function setPeriod(p) {
        period = p;
    }

    function getPeriod() {
        return period;
    }

    /*
     * returns a Date() object
     * offset - a key in the 'dates' object or 'now'
     */
    function getDate(offset) {

        var now = new Date();

        if (!offset) {
            return now;
        } else {
            var now_ms = now.getTime();
            return new Date(now_ms - offset);
        }
    }

    function getDomain() {
        return [getDate(getPeriod()), getDate()];
    }

    var EntityView = Backbone.View.extend({
        tagName: 'tr',
        className: 'entity-row',
        template: _.template("<%= label %>	<%= id %>	"),

        events: {'click': 'clickHandler'},

        clickHandler: function () {
            $('.' + this.className).removeClass('success');
            $(this.el).addClass('success');
            _populateCheckTable(this.model);
        },

        render: function() {
            $(this.el).addClass('clickable');
            $(this.el).html(this.template(this.model.toJSON()));
            return this;
        }
    });

    var CheckView = Backbone.View.extend({
        tagName: 'tr',
        className: 'check-row',
        template: _.template("<%= label %>	<%= id %>	"),

        events: {'click': 'clickHandler'},

        clickHandler: function () {
            $('.' + this.className).removeClass('success');
            $(this.el).addClass('success');
            _populateMetricTable(this.model);
        },

        render: function () {
            $(this.el).addClass('clickable');
            $(this.el).html(this.template(this.model.toJSON()));
        }
    });

    var MetricView = Backbone.View.extend({
        tagName: 'tr',
        className: 'metric-row',
        template: _.template("<%= name %>	"),

        events: {'click': 'clickHandler'},

        clickHandler: function () {
            toggleMetric(this.model);
            if(inMetrics(this.model)) {
                $(this.el).addClass('success');
            } else {
                $(this.el).removeClass('success');
            }
        },

        render: function () {
            $(this.el).addClass('clickable');
            if(inMetrics(this.model)) {
                $(this.el).addClass('success');
            }
            $(this.el).html(this.template(this.model.toJSON()));
        }
    });

    var EntityListView = Backbone.View.extend({
        events: {},

        render: function()
        {
            $(this.el).empty();
            return this;
        },

        add: function(m)
        {
            var e = new EntityView({
                model: m
            });
            e.render();
            $(this.el).append(e.el);
        }
    });

    var CheckListView = Backbone.View.extend({
        events: {},

        render: function()
        {
            $(this.el).empty();
            return this;
        },

        add: function(m)
        {
            var e = new CheckView({
                model: m
            });
            e.render();
            $(this.el).append(e.el);
        }
    });

    var MetricListView = Backbone.View.extend({
        events: {},

        render: function()
        {
            $(this.el).empty();
            return this;
        },

        add: function(m)
        {
            var e = new MetricView({
                model: m
            });
            e.render();
            $(this.el).append(e.el);
        }
    });

    function _populateMetricTable (check) {
        var app = App.getInstance();
        var metricListView;

        var metric_fetch_success = function (collection, response) {

            metricListView = new MetricListView({'el': $('#metric-table')});
            metricListView.render();
            collection.each(function (metric) {
                metricListView.add(metric);
            });

        };

        var metric_fetch_failure = function (collection, response) {
            $('#metric-table').html('
Failed to fetch metrics
');

        };

        $('#metric-table').html('
loading metrics
');
        check.metrics.fetch({"success": metric_fetch_success, "error": metric_fetch_failure});

    }

    function _populateCheckTable (entity) {
        var app = App.getInstance();
        var checkListView;

        var check_fetch_success = function (collection, response) {

            checkListView = new CheckListView({'el': $('#check-table')});
            checkListView.render();
            collection.each(function (check) {
                checkListView.add(check);
            });

        };

        var check_fetch_failure = function (collection, response) {
            $('#check-table').html('
Failed to fetch checks
');

        };

        $('#metric-table').empty();
        $('#check-table').html('
loading checks
');
        entity.checks.fetch({"success": check_fetch_success, "error": check_fetch_failure});

    }

    function _populateEntityTable () {

        var app = App.getInstance();
        var entityListView;

        entityListView = new EntityListView({'el': $('#entity-table')});
        entityListView.render();
        app.account.entities.each(function (entity) {
            entityListView.add(entity);
        });

    }

    function _getMetricKey(metric) {
        return [metric.get('entity_id'), metric.get('check_id'), metric.get('name')].join();
    }

    function inMetrics(metric) {
        return _getMetricKey(metric) in metricMap;
    }

    function addMetric (metric) {
        metricMap[_getMetricKey(metric)] = metric;
        _renderGraph();
    }

    function delMetric(metric) {
        delete metricMap[_getMetricKey(metric)];
        _renderGraph();
    }

    function getMetrics() {
        var metrics = [];
        for(var key in metricMap) {
            metrics.push(metricMap[key]);
        }
        return metrics;
    }

    function toggleMetric(metric) {
        if(inMetrics(metric)) {
            delMetric(metric);
            return false;
        } else {
            addMetric(metric);
            return true;
        }
    }

    function _getRecentData(metric, options) {
        return metric.getRecentData(getPeriod(), 100, options);
    }

    /* Fetch */
    function _getChart(metric, parentChart) {
        return _getRecentData(metric).then(function(response) {
            var data = crossfilter(response);

            /* Create a timestamp dimension for this data */
            var dataByTimestamp = data.dimension(function(d){
                return d.timestamp;
            });

            /* For each timestamp, the "group" is the average */
            var dataByTimestampGroup = dataByTimestamp.group().reduceSum(function(d) {
                return d.average;
            });

            var min = Math.min.apply(null, _.map(dataByTimestampGroup.all(), function(d){return d.value;}));

            var max = Math.max.apply(null, _.map(dataByTimestampGroup.all(), function(d){return d.value;}));

            return [dc.lineChart(parentChart).dimension(dataByTimestamp).group(dataByTimestampGroup), min, max]; //.y(d3.scale.linear().domain([min, max]));
        });
    }

    /* Return a list of charts, one for each metric, that are suitable to constuct a compound chart for graphing */
    function _getCharts(parentChart) {
        return _.map(getMetrics(), function(m){
            return _getChart(m, parentChart);
        });
    }

    function _renderGraph () {
        /* Get a list of deferreds, one for each chart to be generated, based upon asynchronous
           HTTP requests to the monitoring API. When all deferreds are done, then construct the
           composite chart and render it. */

        var chart = dc.compositeChart("#chart");

        var fake = crossfilter([{x:0, y:1}]);

        var fakeDimension = fake.dimension(function(d){
            return d.x;
        });

        var fakeGroup = fakeDimension.group().reduceSum(function(d){
            return d.y;
        });

        $.when.apply(this, _getCharts(chart)).done(function(){

            var charts = _.map(arguments, function(d){return d[0];});

            // Perform some math to find the min for the y axis
            var mins = _.map(arguments, function(d){return d[1];});
            mins.push(0);
            var min = Math.min.apply(null, mins);

            // Perform some math to find the max for the y axis
            var maxs = _.map(arguments, function(d){return d[2];});
            maxs.push(0);
            var max = Math.max.apply(null, maxs);

            chart.width($('#chart').width())
            .height(400)
            .transitionDuration(500)
            .margins({top: 10, right: 10, bottom: 30, left: 40})
            .dimension(fakeDimension)
            .group(fakeGroup)
            .yAxisPadding(100)
            .xAxisPadding(500)
            .x(d3.time.scale().domain(getDomain()))
            .y(d3.scale.linear().domain([min, max]))
            .renderHorizontalGridLines(true)
            .renderVerticalGridLines(true)
            .compose(charts) // Use magic arguments "array" containind all of the constructed charts
            .brushOn(false);

            dc.renderAll();
        });

    }

    function renderGraph () {

        Views.renderView('grapher');

        _populateEntityTable();

        _renderGraph();
        $("#chart").resize(_renderGraph);

    }

    return {'renderGraph': renderGraph, 'addMetric': addMetric, 'delMetric': delMetric, 'getMetrics': getMetrics, 'setPeriod': setPeriod, 'getPeriod': getPeriod};

});
<commit_msg>Scaled y axis to 125% of max<commit_after>define([
  'jquery',
  'backbone',
  'underscore',
  'app',
  'views/views',
  'dc',
  'jqueryresize'
], function($, Backbone, _, App, Views, dc) {

    metricMap = {};
    var palette = d3.scale.category10();
    var graph, hoverDetail, axes;

    var hour = 60*60*1000;

    var dates = {
        "hour": {text: "Last hour", offset: hour, dateformat: "%l:%M"},
        "6hour": {text: "Last 3 hours", offset: 3*hour, dateformat: "%l:%M"},
        "day": {text: "Last day", offset: 24*hour, dateformat: "%l:%M"},
        "week": {text: "Last week", offset: 7*24*hour},
        "month": {text: "Last month", offset: 30*24*hour},
        "6month": {text: "Last 6 months", offset: 182*24*hour},
        "year": {text: "Last year", offset: 365*24*hour}

    };

    var period = dates["day"].offset;

    function setPeriod(p) {
        period = p;
    }

    function getPeriod() {
        return period;
    }

    /*
     * returns a Date() object
     * offset - a key in the 'dates' object or 'now'
     */
    function getDate(offset) {

        var now = new Date();

        if (!offset) {
            return now;
        } else {
            var now_ms = now.getTime();
            return new Date(now_ms - offset);
        }
    }

    function getDomain() {
        return [getDate(getPeriod()), getDate()];
    }

    var EntityView = Backbone.View.extend({
        tagName: 'tr',
        className: 'entity-row',
        template: _.template("<%= label %>	<%= id %>	"),

        events: {'click': 'clickHandler'},

        clickHandler: function () {
            $('.' + this.className).removeClass('success');
            $(this.el).addClass('success');
            _populateCheckTable(this.model);
        },

        render: function() {
            $(this.el).addClass('clickable');
            $(this.el).html(this.template(this.model.toJSON()));
            return this;
        }
    });

    var CheckView = Backbone.View.extend({
        tagName: 'tr',
        className: 'check-row',
        template: _.template("<%= label %>	<%= id %>	"),

        events: {'click': 'clickHandler'},

        clickHandler: function () {
            $('.' + this.className).removeClass('success');
            $(this.el).addClass('success');
            _populateMetricTable(this.model);
        },

        render: function () {
            $(this.el).addClass('clickable');
            $(this.el).html(this.template(this.model.toJSON()));
        }
    });

    var MetricView = Backbone.View.extend({
        tagName: 'tr',
        className: 'metric-row',
        template: _.template("<%= name %>	"),

        events: {'click': 'clickHandler'},

        clickHandler: function () {
            toggleMetric(this.model);
            if(inMetrics(this.model)) {
                $(this.el).addClass('success');
            } else {
                $(this.el).removeClass('success');
            }
        },

        render: function () {
            $(this.el).addClass('clickable');
            if(inMetrics(this.model)) {
                $(this.el).addClass('success');
            }
            $(this.el).html(this.template(this.model.toJSON()));
        }
    });

    var EntityListView = Backbone.View.extend({
        events: {},

        render: function()
        {
            $(this.el).empty();
            return this;
        },

        add: function(m)
        {
            var e = new EntityView({
                model: m
            });
            e.render();
            $(this.el).append(e.el);
        }
    });

    var CheckListView = Backbone.View.extend({
        events: {},

        render: function()
        {
            $(this.el).empty();
            return this;
        },

        add: function(m)
        {
            var e = new CheckView({
                model: m
            });
            e.render();
            $(this.el).append(e.el);
        }
    });

    var MetricListView = Backbone.View.extend({
        events: {},

        render: function()
        {
            $(this.el).empty();
            return this;
        },

        add: function(m)
        {
            var e = new MetricView({
                model: m
            });
            e.render();
            $(this.el).append(e.el);
        }
    });

    function _populateMetricTable (check) {
        var app = App.getInstance();
        var metricListView;

        var metric_fetch_success = function (collection, response) {

            metricListView = new MetricListView({'el': $('#metric-table')});
            metricListView.render();
            collection.each(function (metric) {
                metricListView.add(metric);
            });

        };

        var metric_fetch_failure = function (collection, response) {
            $('#metric-table').html('
Failed to fetch metrics
');

        };

        $('#metric-table').html('
loading metrics
');
        check.metrics.fetch({"success": metric_fetch_success, "error": metric_fetch_failure});

    }

    function _populateCheckTable (entity) {
        var app = App.getInstance();
        var checkListView;

        var check_fetch_success = function (collection, response) {

            checkListView = new CheckListView({'el': $('#check-table')});
            checkListView.render();
            collection.each(function (check) {
                checkListView.add(check);
            });

        };

        var check_fetch_failure = function (collection, response) {
            $('#check-table').html('
Failed to fetch checks
');

        };

        $('#metric-table').empty();
        $('#check-table').html('
loading checks
');
        entity.checks.fetch({"success": check_fetch_success, "error": check_fetch_failure});

    }

    function _populateEntityTable () {

        var app = App.getInstance();
        var entityListView;

        entityListView = new EntityListView({'el': $('#entity-table')});
        entityListView.render();
        app.account.entities.each(function (entity) {
            entityListView.add(entity);
        });

    }

    function _getMetricKey(metric) {
        return [metric.get('entity_id'), metric.get('check_id'), metric.get('name')].join();
    }

    function inMetrics(metric) {
        return _getMetricKey(metric) in metricMap;
    }

    function addMetric (metric) {
        metricMap[_getMetricKey(metric)] = metric;
        _renderGraph();
    }

    function delMetric(metric) {
        delete metricMap[_getMetricKey(metric)];
        _renderGraph();
    }

    function getMetrics() {
        var metrics = [];
        for(var key in metricMap) {
            metrics.push(metricMap[key]);
        }
        return metrics;
    }

    function toggleMetric(metric) {
        if(inMetrics(metric)) {
            delMetric(metric);
            return false;
        } else {
            addMetric(metric);
            return true;
        }
    }

    function _getRecentData(metric, options) {
        return metric.getRecentData(getPeriod(), 100, options);
    }

    /* Fetch */
    function _getChart(metric, parentChart) {
        return _getRecentData(metric).then(function(response) {
            var data = crossfilter(response);

            /* Create a timestamp dimension for this data */
            var dataByTimestamp = data.dimension(function(d){
                return d.timestamp;
            });

            /* For each timestamp, the "group" is the average */
            var dataByTimestampGroup = dataByTimestamp.group().reduceSum(function(d) {
                return d.average;
            });

            var min = Math.min.apply(null, _.map(dataByTimestampGroup.all(), function(d){return d.value;}));

            var max = Math.max.apply(null, _.map(dataByTimestampGroup.all(), function(d){return d.value;}));

            return [dc.lineChart(parentChart).dimension(dataByTimestamp).group(dataByTimestampGroup), min, max]; //.y(d3.scale.linear().domain([min, max]));
        });
    }

    /* Return a list of charts, one for each metric, that are suitable to constuct a compound chart for graphing */
    function _getCharts(parentChart) {
        return _.map(getMetrics(), function(m){
            return _getChart(m, parentChart);
        });
    }

    function _renderGraph () {
        /* Get a list of deferreds, one for each chart to be generated, based upon asynchronous
           HTTP requests to the monitoring API. When all deferreds are done, then construct the
           composite chart and render it. */

        var chart = dc.compositeChart("#chart");

        var fake = crossfilter([{x:0, y:1}]);

        var fakeDimension = fake.dimension(function(d){
            return d.x;
        });

        var fakeGroup = fakeDimension.group().reduceSum(function(d){
            return d.y;
        });

        $.when.apply(this, _getCharts(chart)).done(function(){

            var charts = _.map(arguments, function(d){return d[0];});

            // Perform some math to find the min for the y axis
            var mins = _.map(arguments, function(d){return d[1];});
            mins.push(0);
            var min = Math.min.apply(null, mins);

            // Perform some math to find the max for the y axis
            var maxs = _.map(arguments, function(d){return d[2];});
            maxs.push(0);
            var max = Math.max.apply(null, maxs);

            chart.width($('#chart').width())
            .height(400)
            .transitionDuration(500)
            .margins({top: 10, right: 10, bottom: 30, left: 40})
            .dimension(fakeDimension)
            .group(fakeGroup)
            .yAxisPadding(100)
            .xAxisPadding(500)
            .x(d3.time.scale().domain(getDomain()))
            .y(d3.scale.linear().domain([min, max*1.25]))
            .renderHorizontalGridLines(true)
            .renderVerticalGridLines(true)
            .compose(charts) // Use magic arguments "array" containind all of the constructed charts
            .brushOn(false);

            dc.renderAll();
        });

    }

    function renderGraph () {

        Views.renderView('grapher');

        _populateEntityTable();

        _renderGraph();
        $("#chart").resize(_renderGraph);

    }

    return {'renderGraph': renderGraph, 'addMetric': addMetric, 'delMetric': delMetric, 'getMetrics': getMetrics, 'setPeriod': setPeriod, 'getPeriod': getPeriod};

});
<|endoftext|>