<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/*
 * Boolean Geometric Path Operations
 *
 * This is mostly written for clarity and compatibility, not optimised for
 * performance, and has to be tested heavily for stability.
 *
 * Supported
 *  - paperjs Path and CompoundPath objects
 *  - Boolean Union
 *  - Boolean Intersection
 *  - Boolean Subtraction
 *  - Resolving a self-intersecting Path
 *
 * Not supported yet
 *  - Boolean operations on self-intersecting Paths
 *  - Paths are clones of each other that ovelap exactly on top of each other!
 *
 * @author Harikrishnan Gopalakrishnan
 * http://hkrish.com/playground/paperjs/booleanStudy.html
 */

PathItem.inject(new function() {

	function splitPath(intersections, collectOthers) {
		// Sort intersections by paths ids, curve index and parameter, so we
		// can loop through all intersections, divide paths and never need to
		// readjust indices.
		intersections.sort(function(loc1, loc2) {
			var path1 = loc1.getPath(),
				path2 = loc2.getPath();
			return path1 === path2
					// We can add parameter (0 <= t <= 1) to index (a integer)
					// to compare both at the same time
					? (loc1.getIndex() + loc1.getParameter())
						- (loc2.getIndex() + loc2.getParameter())
					: path1._id - path2._id;
		});
		var others = collectOthers && [];
		for (var i = intersections.length - 1; i >= 0; i--) {
			var loc = intersections[i],
				other = loc.getIntersection(),
				curve = loc.divide(),
				// When the curve doesn't need to be divided since t = 0, 1,
				// #divide() returns null and we can use the existing segment.
				segment = curve && curve.getSegment1() || loc.getSegment();
			if (others)
				others.push(other);
			other.__segment = segment;
			segment._ixPair = other;
		}
		return others;
	}

	/**
	 * To deal with a HTML canvas requirement where CompoundPaths' child contours
	 * has to be of different winding direction for correctly filling holes.
	 * But if some individual countours are disjoint, i.e. islands, we have to
	 * reorient them so that
	 *   the holes have opposit winding direction (already handled by paperjs)
	 *   islands has to have same winding direction (as the first child of the path)
	 *
	 * Does NOT handle selfIntersecting CompoundPaths.
	 *
	 * @param  {CompoundPath} path - Input CompoundPath, Note: This path could be modified if need be.
	 * @return {boolean}	  the winding direction of the base contour(true if clockwise)
	 */
	function reorientCompoundPath(path) {
		if (!(path instanceof CompoundPath))
			return path.isClockwise();
		var children = path._children,
			length = children.length,
			bounds = new Array(length),
			counters = new Array(length),
			clockwise = children[0].isClockwise();
		for (var i = 0; i < length; i++) {
			bounds[i] = children[i].getBounds();
			counters[i] = 0;
		}
		for (var i = 0; i < length; i++) {
			for (var j = 1; j < length; j++) {
				if (i !== j && bounds[i].contains(bounds[j]))
					counters[j]++;
			}
		}
		// Omit the first child
		for (var i = 1; i < length; i++) {
			if (counters[i] % 2 === 0) {
				children[i].setClockwise(clockwise);
			}
		}
		return clockwise;
	}

	function computeBoolean(path1, path2, operator, subtract, _cache) {
		var ixs, path1Id, path2Id;
		// We do not modify the operands themselves
		// The result might not belong to the same type
		// i.e. subtraction(A:Path, B:Path):CompoundPath etc.
		var _path1 = path1.clone(),
			_path2 = path2.clone(),
			path1Id = _path1.id,
			path2Id = _path2.id,
			path1Clockwise = reorientCompoundPath(_path1),
			path2Clockwise = reorientCompoundPath(_path2),
			// Calculate all the intersections
			intersections = _cache && _cache.intersections
					|| _path1.getIntersections(_path2);
		// if we have a empty _cache object as an operand, skip calculating
		// boolean and cache the intersections
		if (_cache && !_cache.intersections) {
			// TODO: Don't we need to clear up and remove _path1 & _path2 again?
			return _cache.intersections = intersections;
		}
		// Now split intersections on both curves, by asking the first call to
		// collect the 'other' intersections for us and passing that on to the
		// second call.
		splitPath(splitPath(intersections, true));
		// Do operator specific calculations before we begin
		if (subtract) {
			_path2.reverse();
			path2Clockwise = !path2Clockwise;
		}

		var paths = [],
			nodes = [],
			result = new CompoundPath(),
			push = paths.push;
		if (_path1 instanceof CompoundPath) {
			push.apply(paths, _path1._children);
		} else {
			paths.push(_path1);
		}
		if (_path2 instanceof CompoundPath) {
			push.apply(paths, _path2._children);
		} else {
			paths.push(_path2);
		}
		// Step 1: Discard invalid links according to the boolean operator
		for (var i = 0, l = paths.length; i < l; i++) {
			var path = paths[i],
				insidePath1 = false,
				insidePath2 = false,
				thisId = path.parent instanceof CompoundPath
						? path.parent.id : path.id,
				clockwise = path.isClockwise(),
				segments = path._segments;
			for (var j = 0, k = segments.length; j < k; j++) {
				var segment = segments[j],
					curve = segment.getCurve(),
					midPoint = curve.getPoint(0.5);
				if (thisId !== path1Id) {
					insidePath1 = _path1.contains(midPoint)
							&& (clockwise === path1Clockwise || subtract
									|| !testOnCurve(_path1, midPoint));
				}
				if (thisId !== path2Id) {
					insidePath2 = _path2.contains(midPoint)
							&& (clockwise === path2Clockwise
									|| !testOnCurve(_path2, midPoint));
				}
				if (operator(thisId === path1Id, insidePath1, insidePath2)) {
					curve._INVALID = true;
					// markPoint(midPoint, '+');
				}
			}
			nodes = nodes.concat(path._segments);
		}

		// Step 2: Retrieve the resulting paths from the graph
		for (var i = 0, l = nodes.length; i < l; i++) {
			var node = nodes[i];
			if (node.curve._INVALID || node._visited) { continue; }
			var path = node.path,
				thisId = (path.parent instanceof CompoundPath)? path.parent.id : path.id,
				nuPath = new Path(),
				firstNode = null,
				firstNode_ix = null;
			if (node.previous.curve._INVALID) {
				node.setHandleIn(node._ixPair
						? node._ixPair.getIntersection().__segment._handleIn
						: Point.create(0, 0));
			}
			while (node && !node._visited && (node !== firstNode && node !== firstNode_ix)) {
				node._visited = true;
				firstNode = firstNode || node;
				firstNode_ix = !firstNode_ix && firstNode._ixPair
						? firstNode._ixPair.getIntersection().__segment
						: firstNode_ix;
				// node._ixPair is this node's intersection CurveLocation object
				// node._ixPair.getIntersection() is the other CurveLocation object this node intersects with
				var nextNode = (node._ixPair && node.curve._INVALID)? node._ixPair.getIntersection().__segment : node;
				if (node._ixPair) {
					nextNode._visited = true;
					nuPath.add(new Segment(node._point, node._handleIn,
							nextNode._handleOut));
					node = nextNode;
				} else {
					nuPath.add(node);
				}
				node = node.next;
			}
			// Avoid stray segments and incomplete paths
			if (nuPath.segments.length > 2 || !nuPath.curves[0].isLinear()) {
				nuPath.closed = true;
				result.addChild(nuPath, true);
			}
		}
		// Delete the proxies
		_path1.remove();
		_path2.remove();
		// And then, we are done.
		return result.reduce();
	}

	function testOnCurve(path, point) {
		var curves = path.getCurves(),
			bounds = path.getBounds();
		if (bounds.contains(point)) {
			for (var i = 0, l = curves.length; i < l; i++) {
				var curve = curves[i];
				if (curve.getBounds().contains(point)
						&& curve.getParameterOf(point))
					return true;
			}
		}
		return false;
	}

	// A boolean operator is a binary operator function of the form
	// function(isPath1, isInPath1, isInPath2)
	//
	// Operators return true if a curve in the operands is to be removed,
	// and they aare called for each curve segment in the graph after all the
	// intersections between the operands are calculated and curves in the
	// operands were split at intersections.
	//
	//  The boolean operator return a Boolean value indicating whether to
	// keep the curve or not.
	//  return true - discard the curve
	//  return false - keep the curve

	return {
		unite: function(path, _cache) {
			return computeBoolean(this, path,
					function(isPath1, isInPath1, isInPath2) {
						return isInPath1 || isInPath2;
					}, false, _cache);
		},

		intersect: function(path, _cache) {
			return computeBoolean(this, path,
					function(isPath1, isInPath1, isInPath2) {
						return !(isInPath1 || isInPath2);
					}, false, _cache);
		},

		subtract: function(path, _cache) {
			return computeBoolean(this, path,
					function(isPath1, isInPath1, isInPath2) {
						return isPath1 && isInPath2 || !isPath1 && !isInPath1;
					}, true, _cache);
		},

		// Compound boolean operators combine the basic boolean operations such
		// as union, intersection, subtract etc.
		// TODO: cache the split objects and find a way to properly clone them!
		// a.k.a. eXclusiveOR
		exclude: function(path) {
			return new Group([this.subtract(path), path.subtract(this)]);
		},

		// Divide path1 by path2
		divide: function(path) {
			return new Group([this.subtract(path), this.intersect(path)]);
		}
	};
});
<commit_msg>More computeBoolean() optimizations and clean up.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/*
 * Boolean Geometric Path Operations
 *
 * This is mostly written for clarity and compatibility, not optimised for
 * performance, and has to be tested heavily for stability.
 *
 * Supported
 *  - paperjs Path and CompoundPath objects
 *  - Boolean Union
 *  - Boolean Intersection
 *  - Boolean Subtraction
 *  - Resolving a self-intersecting Path
 *
 * Not supported yet
 *  - Boolean operations on self-intersecting Paths
 *  - Paths are clones of each other that ovelap exactly on top of each other!
 *
 * @author Harikrishnan Gopalakrishnan
 * http://hkrish.com/playground/paperjs/booleanStudy.html
 */

PathItem.inject(new function() {

	function splitPath(intersections, collectOthers) {
		// Sort intersections by paths ids, curve index and parameter, so we
		// can loop through all intersections, divide paths and never need to
		// readjust indices.
		intersections.sort(function(loc1, loc2) {
			var path1 = loc1.getPath(),
				path2 = loc2.getPath();
			return path1 === path2
					// We can add parameter (0 <= t <= 1) to index (a integer)
					// to compare both at the same time
					? (loc1.getIndex() + loc1.getParameter())
						- (loc2.getIndex() + loc2.getParameter())
					: path1._id - path2._id;
		});
		var others = collectOthers && [];
		for (var i = intersections.length - 1; i >= 0; i--) {
			var loc = intersections[i],
				other = loc.getIntersection(),
				curve = loc.divide(),
				// When the curve doesn't need to be divided since t = 0, 1,
				// #divide() returns null and we can use the existing segment.
				segment = curve && curve.getSegment1() || loc.getSegment();
			if (others)
				others.push(other);
			other.__segment = segment;
			segment._ixPair = other;
		}
		return others;
	}

	/**
	 * To deal with a HTML canvas requirement where CompoundPaths' child contours
	 * has to be of different winding direction for correctly filling holes.
	 * But if some individual countours are disjoint, i.e. islands, we have to
	 * reorient them so that
	 *   the holes have opposit winding direction (already handled by paperjs)
	 *   islands has to have same winding direction (as the first child of the path)
	 *
	 * Does NOT handle selfIntersecting CompoundPaths.
	 *
	 * @param  {CompoundPath} path - Input CompoundPath, Note: This path could be modified if need be.
	 * @return {boolean}	  the winding direction of the base contour(true if clockwise)
	 */
	function reorientPath(path) {
		if (path instanceof CompoundPath) {
			var children = path._children,
				length = children.length,
				bounds = new Array(length),
				counters = new Array(length),
				clockwise = children[0].isClockwise();
			for (var i = 0; i < length; i++) {
				bounds[i] = children[i].getBounds();
				counters[i] = 0;
			}
			for (var i = 0; i < length; i++) {
				for (var j = 1; j < length; j++) {
					if (i !== j && bounds[i].contains(bounds[j]))
						counters[j]++;
				}
			}
			// Omit the first child
			for (var i = 1; i < length; i++) {
				if (counters[i] % 2 === 0) {
					children[i].setClockwise(clockwise);
				}
			}
		}
		return path;
	}

	function computeBoolean(path1, path2, operator, subtract, _cache) {
		// We do not modify the operands themselves
		// The result might not belong to the same type
		// i.e. subtraction(A:Path, B:Path):CompoundPath etc.
		var _path1 = reorientPath(path1.clone()),
			_path2 = reorientPath(path2.clone()),
			path1Clockwise = _path1.isClockwise(),
			path2Clockwise = _path2.isClockwise(),
			path1Id = _path1.id,
			path2Id = _path2.id,
			// Calculate all the intersections
			intersections = _cache && _cache.intersections
					|| _path1.getIntersections(_path2);
		// if we have a empty _cache object as an operand, skip calculating
		// boolean and cache the intersections
		if (_cache && !_cache.intersections) {
			// TODO: Don't we need to clear up and remove _path1 & _path2 again?
			return _cache.intersections = intersections;
		}
		// Now split intersections on both curves, by asking the first call to
		// collect the 'other' intersections for us and passing that on to the
		// second call.
		splitPath(splitPath(intersections, true));
		// Do operator specific calculations before we begin
		if (subtract) {
			_path2.reverse();
			path2Clockwise = !path2Clockwise;
		}

		var paths = []
				.concat(_path1._children || [_path1])
				.concat(_path2._children || [_path2]),
			nodes = [],
			result = new CompoundPath();
		// Step 1: Discard invalid links according to the boolean operator
		for (var i = 0, l = paths.length; i < l; i++) {
			var path = paths[i],
				parent = path._parent,
				id = parent instanceof CompoundPath ? parent._id : path._id,
				clockwise = path.isClockwise(),
				segments = path._segments,
				insidePath1 = false,
				insidePath2 = false;
			for (var j = segments.length - 1; j >= 0; j--) {
				var segment = segments[j],
					midPoint = segment.getCurve().getPoint(0.5);
				if (id !== path1Id) {
					insidePath1 = _path1.contains(midPoint)
							&& (clockwise === path1Clockwise || subtract
									|| !testOnCurve(_path1, midPoint));
				}
				if (id !== path2Id) {
					insidePath2 = _path2.contains(midPoint)
							&& (clockwise === path2Clockwise
									|| !testOnCurve(_path2, midPoint));
				}
				if (operator(id === path1Id, insidePath1, insidePath2)) {
					segment._INVALID = true;
					// markPoint(midPoint, '+');
				} else {
					nodes.push(segment);
				}
			}
		}
		// Step 2: Retrieve the resulting paths from the graph
		for (var i = 0, l = nodes.length; i < l; i++) {
			var node = nodes[i];
			if (node._visited)
				continue;
			var path = node.path,
				nuPath = new Path(),
				firstNode = node,
				firstNode_ix = null;
			if (node.getPrevious()._INVALID) {
				node.setHandleIn(node._ixPair
						? node._ixPair.getIntersection().__segment._handleIn
						: Point.create(0, 0));
			}
			while (node && !node._visited && node !== firstNode_ix) {
				node._visited = true;
				firstNode_ix = firstNode_ix || firstNode._ixPair
						&& firstNode._ixPair.getIntersection().__segment;
				// node._ixPair is this node's intersection CurveLocation object
				// node._ixPair.getIntersection() is the other CurveLocation object this node intersects with
				var nextNode = node._ixPair && node._INVALID
						? node._ixPair.getIntersection().__segment
						: node;
				if (node._ixPair) {
					nuPath.add(new Segment(node._point, node._handleIn,
							nextNode._handleOut));
					nextNode._visited = true;
					node = nextNode;
				} else {
					nuPath.add(node);
				}
				node = node.getNext();
			}
			// Avoid stray segments and incomplete paths
			if (nuPath._segments.length > 2) {
				nuPath.setClosed(true);
				result.addChild(nuPath, true);
			} else {
				nuPath.remove();
			}
		}
		// Delete the proxies
		_path1.remove();
		_path2.remove();
		// And then, we are done.
		return result.reduce();
	}

	function testOnCurve(path, point) {
		var curves = path.getCurves(),
			bounds = path.getBounds();
		if (bounds.contains(point)) {
			for (var i = 0, l = curves.length; i < l; i++) {
				var curve = curves[i];
				if (curve.getBounds().contains(point)
						&& curve.getParameterOf(point))
					return true;
			}
		}
		return false;
	}

	// A boolean operator is a binary operator function of the form
	// function(isPath1, isInPath1, isInPath2)
	//
	// Operators return true if a curve in the operands is to be removed,
	// and they aare called for each curve segment in the graph after all the
	// intersections between the operands are calculated and curves in the
	// operands were split at intersections.
	//
	//  The boolean operator return a Boolean value indicating whether to
	// keep the curve or not.
	//  return true - discard the curve
	//  return false - keep the curve

	return {
		unite: function(path, _cache) {
			return computeBoolean(this, path,
					function(isPath1, isInPath1, isInPath2) {
						return isInPath1 || isInPath2;
					}, false, _cache);
		},

		intersect: function(path, _cache) {
			return computeBoolean(this, path,
					function(isPath1, isInPath1, isInPath2) {
						return !(isInPath1 || isInPath2);
					}, false, _cache);
		},

		subtract: function(path, _cache) {
			return computeBoolean(this, path,
					function(isPath1, isInPath1, isInPath2) {
						return isPath1 && isInPath2 || !isPath1 && !isInPath1;
					}, true, _cache);
		},

		// Compound boolean operators combine the basic boolean operations such
		// as union, intersection, subtract etc.
		// TODO: cache the split objects and find a way to properly clone them!
		// a.k.a. eXclusiveOR
		exclude: function(path) {
			return new Group([this.subtract(path), path.subtract(this)]);
		},

		// Divide path1 by path2
		divide: function(path) {
			return new Group([this.subtract(path), this.intersect(path)]);
		}
	};
});
<|endoftext|>


<commit_before>$(document).ready(function () {

  $('.button-collapse').sideNav({
    closeOnClick: true
  });

  $('.carousel').carousel({
    indicators: true,
  });

}); // end of document ready

/*
window.onload = function() {
  loadImages();
  initMap();
} */

function loadImages() {
  var imgDefer = document.getElementsByTagName('img');
  for (var i=0; i < imgDefer.length; i++) {
    if (imgDefer[i].getAttribute('data-src')) {
      imgDefer[i].setAttribute('src', imgDefer[i].getAttribute('data-src'));
    }
  }
}

function initMap() {
  var uluru = { lat: 8.988971, lng: -79.5243938 };
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 18,
    center: uluru
  });
  var marker = new google.maps.Marker({
    position: uluru,
    map: map
  });
}<commit_msg>speed optimization<commit_after>$(document).ready(function () {

  $('.button-collapse').sideNav({
    closeOnClick: true
  });

  $('.carousel').carousel({
    indicators: true,
  });

}); // end of document ready

window.onload = function() {
  loadImages();
  initMap();
}

function loadImages() {
  var imgDefer = document.getElementsByTagName('img');
  for (var i=0; i < imgDefer.length; i++) {
    if (imgDefer[i].getAttribute('data-src')) {
      imgDefer[i].setAttribute('src', imgDefer[i].getAttribute('data-src'));
    }
  }
}

function initMap() {
  var uluru = { lat: 8.988971, lng: -79.5243938 };
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 18,
    center: uluru
  });
  var marker = new google.maps.Marker({
    position: uluru,
    map: map
  });
}<|endoftext|>


<commit_before>var mbc      = require('mbc-common')
,   config   = mbc.config.Mosto.Mongo
,   mubsub   = require("mubsub")
,   moment   = require("moment")
,   async    = require('async')
,   events   = require ('events')
,   util     = require ('util')
,   logger   = mbc.logger().addLogger('MONGO-DRIVER')
,   models   = require('../../models/Mosto')
,   _        = require('underscore');

function drop_err(callback, err_handler) {
    return function(err,v) {
        if( !err )
            callback(v);
        else if( err_handler )
            err_handler(err);
    };
}

function mongo_driver(conf) {
    this.conf = conf;
    events.EventEmitter.call (this);

    logger.info("Creating mongodb playlists driver");
}
util.inherits (mongo_driver, events.EventEmitter);

mongo_driver.prototype.start = function() {
    var self = this;
    var db = mbc.db(this.conf && this.conf.db);
    self.channel = mbc.pubsub();

    logger.info("Starting mongo playlists driver");

    self.scheds = db.collection('scheds');
    self.lists = db.collection('lists');
    self.pieces = db.collection('pieces');

    self.channel.on('JSONmessage', function(chan, msg) {
        var handler = self.pubsub_handler[chan];
        return handler && (handler.bind(self))(msg);
    });

    self.channel.subscribe('schedbackend.create');
    self.channel.subscribe('schedbackend.update');
    self.channel.subscribe('schedbackend.delete');

};

mongo_driver.prototype.stop = function(timeSpan) {
    var self = this;

    logger.info("Stopping mongo playlists driver");

    self.channel.removeAllListeners('JSONmessage');
    self.channel.unsubscribe('schedbackend.create');
    self.channel.unsubscribe('schedbackend.update');
    self.channel.unsubscribe('schedbackend.delete');
    self.channel.end();

};

mongo_driver.prototype.pubsub_handler = {
    'schedbackend.create': function(msg) {
        var self = this;
        this.createPlaylist(msg.model, (function(err, playlist) {
            if( err ) {
                self.emit('error', err);
                logger.error(err.message);
                return err;
            }
            this.emit('create', playlist);
        }).bind(this));
    },
    'schedbackend.update': function(msg) {
        var self = this;
        this.createPlaylist(msg.model, (function(err, playlist) {
            if( err ) {
                self.emit('error', err);
                logger.error(err.message);
                return err;
            }
            this.emit('update', playlist);
        }).bind(this));
    },
    'schedbackend.delete': function(msg) {
        this.emit('delete', msg.model._id);
    }
};

mongo_driver.prototype.getPlaylists = function(window, callback) {
    // read playlists from the database

    /*
     * This gets the database's 'scheds' and 'lists' collections
     * and turn them into a mosto.api.Playlist. Then return one by one to callback
     * which defaults to self.newPlaylistCallback
     */
    var self = this;

    logger.debug("getPlaylists", window);

    var query = {};
    query.start = { $lte: window.to.valueOf() };
    query.end = { $gte: window.from.valueOf() };

    self.scheds.findItems(query, function(err, scheds) {
        if( err ) {
            logger.error("Error obtaining playlists: ", err);
            return self.emit('md-error', err);
        }

        if( scheds ) {
            logger.debug("Processing sched list:", scheds);
            async.map(scheds, self.createPlaylist.bind(self), function(err, playlists) {
                if( err ) {
                    logger.error("Error processing playlists: ", err);
                    return self.emit('md-error', err);
                } else {
                    logger.debug("Playlists obtained: ", playlists);
                }
                if( callback )
                    callback(playlists);
                else
                    playlists.forEach(function(playlist) {
                        self.emit ("create", playlist);
                    });
            });
        } else {
            logger.debug('No more scheds');
        }
    });
};

mongo_driver.prototype.createPlaylist = function(sched, callback) {
    var self = this;
    logger.debug("Creating Playlist for:", sched);
    self.lists.findById(sched.playlist, function(err, list) {
        if( err ) {
            logger.error("Error obtaining list: ", err);
            callback(err);
            return err;
        }
        logger.debug("LIST:" + list._id);

        logger.info("Processing list:", {"id": list && list._id, "clips": list && list.pieces.length});
        self.pieces.findItems({_id:{"$in": list.pieces}}, function(err, pieces) {
            pieces = _.chain(pieces).map(function(block){
                block._id = (block._id.toHexString && block._id.toHexString()) || block._id;
                return block;
            }).sortBy(function(block){
                return list.pieces.indexOf(block._id);
            }).value();
            var startDate = moment(sched.start);
            var endDate   = moment(sched.end);
            var name = sched.title;
            var playlist_id = (sched._id.toHexString && sched._id.toHexString()) || sched._id;

            var medias = [];
            pieces.forEach(function(block, order) {
                var block_id = (block._id.toHexString && block._id.toHexString()) || block._id;
                var orig_order = order;
                var clip_name = block.name;
                // TODO: don't know what goes in type
                var type = "default";
                var file = block.file;
                var length = moment(block.durationraw, "HH:mm:ss.SSS");
                var fps = block.video.fps;
                medias.push({"id": block_id, "orig_order": orig_order, "name": clip_name, "type": type, "file": file,
                                      "length": moment.duration({
                                          hours: length.hours(),
                                          minutes: length.minutes(),
                                          seconds: length.seconds(),
                                          milliseconds: length.milliseconds(),
                                      }), "fps": parseFloat(fps)});
            });

            var playlist = new models.Playlist({"id": playlist_id, "name": name, "start": startDate, "end": endDate, "mode": "snap", "medias": medias});

            logger.debug("Created Playlist:", playlist);

            callback(err, playlist);
        });
    });
};

exports = module.exports = function(conf) {
    var driver = new mongo_driver(conf);
    return driver;
};
<commit_msg>Modified log message for better debugging<commit_after>var mbc      = require('mbc-common')
,   config   = mbc.config.Mosto.Mongo
,   mubsub   = require("mubsub")
,   moment   = require("moment")
,   async    = require('async')
,   events   = require ('events')
,   util     = require ('util')
,   logger   = mbc.logger().addLogger('MONGO-DRIVER')
,   models   = require('../../models/Mosto')
,   _        = require('underscore');

function drop_err(callback, err_handler) {
    return function(err,v) {
        if( !err )
            callback(v);
        else if( err_handler )
            err_handler(err);
    };
}

function mongo_driver(conf) {
    this.conf = conf;
    events.EventEmitter.call (this);

    logger.info("Creating mongodb playlists driver");
}
util.inherits (mongo_driver, events.EventEmitter);

mongo_driver.prototype.start = function() {
    var self = this;
    var db = mbc.db(this.conf && this.conf.db);
    self.channel = mbc.pubsub();

    logger.info("Starting mongo playlists driver");

    self.scheds = db.collection('scheds');
    self.lists = db.collection('lists');
    self.pieces = db.collection('pieces');

    self.channel.on('JSONmessage', function(chan, msg) {
        var handler = self.pubsub_handler[chan];
        return handler && (handler.bind(self))(msg);
    });

    self.channel.subscribe('schedbackend.create');
    self.channel.subscribe('schedbackend.update');
    self.channel.subscribe('schedbackend.delete');

};

mongo_driver.prototype.stop = function(timeSpan) {
    var self = this;

    logger.info("Stopping mongo playlists driver");

    self.channel.removeAllListeners('JSONmessage');
    self.channel.unsubscribe('schedbackend.create');
    self.channel.unsubscribe('schedbackend.update');
    self.channel.unsubscribe('schedbackend.delete');
    self.channel.end();

};

mongo_driver.prototype.pubsub_handler = {
    'schedbackend.create': function(msg) {
        var self = this;
        this.createPlaylist(msg.model, (function(err, playlist) {
            if( err ) {
                self.emit('error', err);
                logger.error(err.message);
                return err;
            }
            this.emit('create', playlist);
        }).bind(this));
    },
    'schedbackend.update': function(msg) {
        var self = this;
        this.createPlaylist(msg.model, (function(err, playlist) {
            if( err ) {
                self.emit('error', err);
                logger.error(err.message);
                return err;
            }
            this.emit('update', playlist);
        }).bind(this));
    },
    'schedbackend.delete': function(msg) {
        this.emit('delete', msg.model._id);
    }
};

mongo_driver.prototype.getPlaylists = function(window, callback) {
    // read playlists from the database

    /*
     * This gets the database's 'scheds' and 'lists' collections
     * and turn them into a mosto.api.Playlist. Then return one by one to callback
     * which defaults to self.newPlaylistCallback
     */
    var self = this;

    logger.debug("getPlaylists", "From: " + window.from.valueOf(), "To: " + window.to.valueOf());

    var query = {};
    query.start = { $lte: window.to.valueOf() };
    query.end = { $gte: window.from.valueOf() };

    self.scheds.findItems(query, function(err, scheds) {
        if( err ) {
            logger.error("Error obtaining playlists: ", err);
            return self.emit('md-error', err);
        }

        if( scheds ) {
            logger.debug("Processing sched list:", scheds);
            async.map(scheds, self.createPlaylist.bind(self), function(err, playlists) {
                if( err ) {
                    logger.error("Error processing playlists: ", err);
                    return self.emit('md-error', err);
                } else {
                    logger.debug("Playlists obtained: ", playlists);
                }
                if( callback )
                    callback(playlists);
                else
                    playlists.forEach(function(playlist) {
                        self.emit ("create", playlist);
                    });
            });
        } else {
            logger.debug('No more scheds');
        }
    });
};

mongo_driver.prototype.createPlaylist = function(sched, callback) {
    var self = this;
    logger.debug("Creating Playlist for:", sched);
    self.lists.findById(sched.playlist, function(err, list) {
        if( err ) {
            logger.error("Error obtaining list: ", err);
            callback(err);
            return err;
        }
        logger.debug("LIST:" + list._id);

        logger.info("Processing list:", {"id": list && list._id, "clips": list && list.pieces.length});
        self.pieces.findItems({_id:{"$in": list.pieces}}, function(err, pieces) {
            pieces = _.chain(pieces).map(function(block){
                block._id = (block._id.toHexString && block._id.toHexString()) || block._id;
                return block;
            }).sortBy(function(block){
                return list.pieces.indexOf(block._id);
            }).value();
            var startDate = moment(sched.start);
            var endDate   = moment(sched.end);
            var name = sched.title;
            var playlist_id = (sched._id.toHexString && sched._id.toHexString()) || sched._id;

            var medias = [];
            pieces.forEach(function(block, order) {
                var block_id = (block._id.toHexString && block._id.toHexString()) || block._id;
                var orig_order = order;
                var clip_name = block.name;
                // TODO: don't know what goes in type
                var type = "default";
                var file = block.file;
                var length = moment(block.durationraw, "HH:mm:ss.SSS");
                var fps = block.video.fps;
                medias.push({"id": block_id, "orig_order": orig_order, "name": clip_name, "type": type, "file": file,
                                      "length": moment.duration({
                                          hours: length.hours(),
                                          minutes: length.minutes(),
                                          seconds: length.seconds(),
                                          milliseconds: length.milliseconds(),
                                      }), "fps": parseFloat(fps)});
            });

            var playlist = new models.Playlist({"id": playlist_id, "name": name, "start": startDate, "end": endDate, "mode": "snap", "medias": medias});

            logger.debug("Created Playlist:", playlist);

            callback(err, playlist);
        });
    });
};

exports = module.exports = function(conf) {
    var driver = new mongo_driver(conf);
    return driver;
};
<|endoftext|>


<commit_before> /*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $, window, brackets */

define(function (require, exports, module) {
    "use strict";

    var KeyBindingManager = require("command/KeyBindingManager"),
        KeyEvent          = require("utils/KeyEvent"),
        PopUpManager      = require("widgets/PopUpManager"),
        ViewUtils         = require("utils/ViewUtils");

    /**
     * Object to handle events for a dropdown list.
     *
     * DropdownEventHandler handles these events:
     *
     * Mouse:
     * - click       - execute selection callback and dismiss list
     * - mouseover   - highlight item
     * - mouseleave  - remove mouse highlighting
     *
     * Keyboard:
     * - Enter       - execute selection callback and dismiss list
     * - Esc         - dismiss list
     * - Up/Down     - change selection
     * - PageUp/Down - change selection
     *
     * @constructor
     * @param {jQueryObject} $list  associated list object
     * @param {Function} selectionCallback  function called when list item is selected.
     */
    function DropdownEventHandler($list, selectionCallback, closeCallback) {

        this.$list = $list;
        this.$items = $list.find("li");
        this.selectionCallback = selectionCallback;
        this.closeCallback = closeCallback;

        /**
         * @private
         * The selected position in the list; otherwise -1.
         * @type {number}
         */
        this._selectedIndex = -1;
    }

    /**
     * Public open method
     */
    DropdownEventHandler.prototype.open = function () {
        var self = this;

        /**
         * Convert keydown events into hint list navigation actions.
         *
         * @param {KeyboardEvent} event
         * @return {boolean} true if key was handled, otherwise false.
         */
        function _keydownHook(event) {
            var keyCode;

            // (page) up, (page) down, enter and tab key are handled by the list
            if (event.type === "keydown") {
                keyCode = event.keyCode;

                if (keyCode === KeyEvent.DOM_VK_UP) {
                    self._rotateSelection(-1);
                } else if (keyCode === KeyEvent.DOM_VK_DOWN) {
                    self._rotateSelection(1);
                } else if (keyCode === KeyEvent.DOM_VK_PAGE_UP) {
                    self._rotateSelection(-self._itemsPerPage());
                } else if (keyCode === KeyEvent.DOM_VK_PAGE_DOWN) {
                    self._rotateSelection(self._itemsPerPage());
                } else if (self._selectedIndex !== -1 &&
                        (keyCode === KeyEvent.DOM_VK_RETURN)) {

                    // Trigger a click handler to commmit the selected item
                    self._selectionHandler();
                } else {
                    // Let the event bubble.
                    return false;
                }

                event.stopImmediatePropagation();
                event.preventDefault();
                return true;
            }

            // If we didn't handle it, let other global keydown hooks handle it.
            return false;
        }

        /**
         * PopUpManager callback
         */
        function closeCallback() {
            KeyBindingManager.removeGlobalKeydownHook(_keydownHook);
            self._cleanup();
        }

        KeyBindingManager.addGlobalKeydownHook(_keydownHook);

        if (this.$list) {
            this._registerMouseEvents();
            PopUpManager.addPopUp(this.$list, closeCallback, true);
        }
    };

    /**
     * Public close method
     */
    DropdownEventHandler.prototype.close = function () {
        PopUpManager.removePopUp(this.$list);
    };

    /**
     * Cleanup
     */
    DropdownEventHandler.prototype._cleanup = function () {
        if (this.$list) {
            this.$list.off(".dropdownEventHandler");
        }
        if (this.closeCallback) {
            this.closeCallback();
        }
    };

    /**
     * Change selection by specified amount. After selection reaches the last item
     * in the rotation direction, then it wraps around to the start.
     *
     * @param {number} distance  Number of items to move change selection where
     *      positive distance rotates down and negative distance rotates up
     */
    DropdownEventHandler.prototype._rotateSelection = function (distance) {
        var len = this.$items.length,
            pos;

        if (this._selectedIndex < 0) {
            // set the initial selection
            pos = (distance > 0) ? distance - 1 : len - 1;

        } else {
            // adjust current selection
            pos = this._selectedIndex;

            // Don't "rotate" until all items have been shown
            if (distance > 0) {
                if (pos === (len - 1)) {
                    pos = 0;  // wrap
                } else {
                    pos = Math.min(pos + distance, len - 1);
                }
            } else {
                if (pos === 0) {
                    pos = (len - 1);  // wrap
                } else {
                    pos = Math.max(pos + distance, 0);
                }
            }
        }

        // If the item to be selected is a divider, then rotate one more.
        if ($(this.$items[pos]).hasClass("divider")) {
            this._rotateSelection((distance > 0) ? (distance + 1) : (distance - 1));
        } else {
            this._setSelectedIndex(pos, true);
        }
    };

    /**
     * @return {number} The number of items per scroll page.
     */
    DropdownEventHandler.prototype._itemsPerPage = function () {
        var itemsPerPage = 1,
            itemHeight;

        if (this.$items.length !== 0) {
            itemHeight = $(this.$items[0]).height();
            if (itemHeight) {
                // round down to integer value
                itemsPerPage = Math.floor(this.$list.height() / itemHeight);
                itemsPerPage = Math.max(1, Math.min(itemsPerPage, this.$items.length));
            }
        }

        return itemsPerPage;
    };

    /**
     * Call selectionCallback with selected index
     */
    DropdownEventHandler.prototype._selectionHandler = function () {

        if (this._selectedIndex === -1) {
            return;
        }

        var $link = this.$items.eq(this._selectedIndex).find("a");
        this._clickHandler($link);
    };

    /**
     * Call selectionCallback with selected item
     *
     * @param {jQueryObject} $item
     */
    DropdownEventHandler.prototype._clickHandler = function ($link) {

        if (!this.selectionCallback || !this.$list || !$link) {
            return;
        }

        this.selectionCallback($link);
        PopUpManager.removePopUp(this.$list);
    };

    /**
     * Select the item in the hint list at the specified index, or remove the
     * selection if index < 0.
     *
     * @private
     * @param {number} index
     */
    DropdownEventHandler.prototype._setSelectedIndex = function (index, scrollIntoView) {

        // Range check
        index = Math.max(-1, Math.min(index, this.$items.length - 1));

        // Clear old highlight
        if (this._selectedIndex !== -1) {
            this.$items.eq(this._selectedIndex).find("a").removeClass("selected");
        }

        this._selectedIndex = index;

        // Highlight the new selected item, if necessary
        if (this._selectedIndex !== -1) {
            var $item = this.$items.eq(this._selectedIndex);

            if (scrollIntoView) {
                ViewUtils.scrollElementIntoView(this.$list, $item, false);
            }
            $item.find("a").addClass("selected");
        }
    };

    /**
     * Register mouse event handlers
     */
    DropdownEventHandler.prototype._registerMouseEvents = function () {
        var self = this;

        this.$list
            .on("click.dropdownEventHandler", "a", function () {
                self._clickHandler($(this));
            })
            .on("mouseover.dropdownEventHandler", "a", function (e) {
                var $link = $(e.currentTarget),
                    $item = $link.closest("li"),
                    viewOffset = self.$list.offset(),
                    elementOffset = $item.offset();

                // Only set selected if in view
                if (elementOffset.top < viewOffset.top + self.$list.height()) {
                    if (viewOffset.top <= elementOffset.top) {
                        self._setSelectedIndex(self.$items.index($item), false);
                    }
                }
            });
    };

    /**
     * Re-register mouse event handlers
     * @param {!jQueryObject} $list  newly updated list object
     */
    DropdownEventHandler.prototype.reRegisterMouseHandlers = function ($list) {
        if (this.$list) {
            this.$list.off(".dropdownEventHandler");

            this.$list = $list;
            this.$items = $list.find("li");

            this._registerMouseEvents();
        }
    };

    // Export public API
    exports.DropdownEventHandler    = DropdownEventHandler;
});
<commit_msg>Fix item highlighting issues in dropdown list.<commit_after> /*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $, window, brackets */

define(function (require, exports, module) {
    "use strict";

    var KeyBindingManager = require("command/KeyBindingManager"),
        KeyEvent          = require("utils/KeyEvent"),
        PopUpManager      = require("widgets/PopUpManager"),
        ViewUtils         = require("utils/ViewUtils");

    /**
     * Object to handle events for a dropdown list.
     *
     * DropdownEventHandler handles these events:
     *
     * Mouse:
     * - click       - execute selection callback and dismiss list
     * - mouseover   - highlight item
     * - mouseleave  - remove mouse highlighting
     *
     * Keyboard:
     * - Enter       - execute selection callback and dismiss list
     * - Esc         - dismiss list
     * - Up/Down     - change selection
     * - PageUp/Down - change selection
     *
     * @constructor
     * @param {jQueryObject} $list  associated list object
     * @param {Function} selectionCallback  function called when list item is selected.
     */
    function DropdownEventHandler($list, selectionCallback, closeCallback) {

        this.$list = $list;
        this.$items = $list.find("li");
        this.selectionCallback = selectionCallback;
        this.closeCallback = closeCallback;
        this.scrolling = false;

        /**
         * @private
         * The selected position in the list; otherwise -1.
         * @type {number}
         */
        this._selectedIndex = -1;
    }

    /**
     * Public open method
     */
    DropdownEventHandler.prototype.open = function () {
        var self = this;

        /**
         * Convert keydown events into hint list navigation actions.
         *
         * @param {KeyboardEvent} event
         * @return {boolean} true if key was handled, otherwise false.
         */
        function _keydownHook(event) {
            var keyCode;

            // (page) up, (page) down, enter and tab key are handled by the list
            if (event.type === "keydown") {
                keyCode = event.keyCode;

                if (keyCode === KeyEvent.DOM_VK_UP) {
                    self._rotateSelection(-1);
                } else if (keyCode === KeyEvent.DOM_VK_DOWN) {
                    self._rotateSelection(1);
                } else if (keyCode === KeyEvent.DOM_VK_PAGE_UP) {
                    self._rotateSelection(-self._itemsPerPage());
                } else if (keyCode === KeyEvent.DOM_VK_PAGE_DOWN) {
                    self._rotateSelection(self._itemsPerPage());
                } else if (self._selectedIndex !== -1 &&
                        (keyCode === KeyEvent.DOM_VK_RETURN)) {

                    // Trigger a click handler to commmit the selected item
                    self._selectionHandler();
                } else {
                    // Let the event bubble.
                    return false;
                }

                event.stopImmediatePropagation();
                event.preventDefault();
                return true;
            }

            // If we didn't handle it, let other global keydown hooks handle it.
            return false;
        }

        /**
         * PopUpManager callback
         */
        function closeCallback() {
            KeyBindingManager.removeGlobalKeydownHook(_keydownHook);
            self._cleanup();
        }

        KeyBindingManager.addGlobalKeydownHook(_keydownHook);

        if (this.$list) {
            this._registerMouseEvents();
            PopUpManager.addPopUp(this.$list, closeCallback, true);
        }
    };

    /**
     * Public close method
     */
    DropdownEventHandler.prototype.close = function () {
        PopUpManager.removePopUp(this.$list);
    };

    /**
     * Cleanup
     */
    DropdownEventHandler.prototype._cleanup = function () {
        if (this.$list) {
            this.$list.off(".dropdownEventHandler");
        }
        if (this.closeCallback) {
            this.closeCallback();
        }
    };

    /**
     * Change selection by specified amount. After selection reaches the last item
     * in the rotation direction, then it wraps around to the start.
     *
     * @param {number} distance  Number of items to move change selection where
     *      positive distance rotates down and negative distance rotates up
     */
    DropdownEventHandler.prototype._rotateSelection = function (distance) {
        var len = this.$items.length,
            pos;

        if (this._selectedIndex < 0) {
            // set the initial selection
            pos = (distance > 0) ? distance - 1 : len - 1;

        } else {
            // adjust current selection
            pos = this._selectedIndex;

            // Don't "rotate" until all items have been shown
            if (distance > 0) {
                if (pos === (len - 1)) {
                    pos = 0;  // wrap
                } else {
                    pos = Math.min(pos + distance, len - 1);
                }
            } else {
                if (pos === 0) {
                    pos = (len - 1);  // wrap
                } else {
                    pos = Math.max(pos + distance, 0);
                }
            }
        }

        // If the item to be selected is a divider, then rotate one more.
        if ($(this.$items[pos]).hasClass("divider")) {
            this._rotateSelection((distance > 0) ? (distance + 1) : (distance - 1));
        } else {
            this._setSelectedIndex(pos, true);
        }
    };

    /**
     * @return {number} The number of items per scroll page.
     */
    DropdownEventHandler.prototype._itemsPerPage = function () {
        var itemsPerPage = 1,
            itemHeight;

        if (this.$items.length !== 0) {
            itemHeight = $(this.$items[0]).height();
            if (itemHeight) {
                // round down to integer value
                itemsPerPage = Math.floor(this.$list.height() / itemHeight);
                itemsPerPage = Math.max(1, Math.min(itemsPerPage, this.$items.length));
            }
        }

        return itemsPerPage;
    };

    /**
     * Call selectionCallback with selected index
     */
    DropdownEventHandler.prototype._selectionHandler = function () {

        if (this._selectedIndex === -1) {
            return;
        }

        var $link = this.$items.eq(this._selectedIndex).find("a");
        this._clickHandler($link);
    };

    /**
     * Call selectionCallback with selected item
     *
     * @param {jQueryObject} $item
     */
    DropdownEventHandler.prototype._clickHandler = function ($link) {

        if (!this.selectionCallback || !this.$list || !$link) {
            return;
        }

        this.selectionCallback($link);
        PopUpManager.removePopUp(this.$list);
    };

    /**
     * Select the item in the hint list at the specified index, or remove the
     * selection if index < 0.
     *
     * @private
     * @param {number} index
     */
    DropdownEventHandler.prototype._setSelectedIndex = function (index, scrollIntoView) {

        // Range check
        index = Math.max(-1, Math.min(index, this.$items.length - 1));

        // Clear old highlight
        if (this._selectedIndex !== -1) {
            this.$items.eq(this._selectedIndex).find("a").removeClass("selected");
        }

        this._selectedIndex = index;

        // Highlight the new selected item, if necessary
        if (this._selectedIndex !== -1) {
            var $item = this.$items.eq(this._selectedIndex);

            $item.find("a").addClass("selected");
            if (scrollIntoView) {
                this.scrolling = true;
                ViewUtils.scrollElementIntoView(this.$list, $item, false);
            }
        }
    };

    /**
     * Register mouse event handlers
     */
    DropdownEventHandler.prototype._registerMouseEvents = function () {
        var self = this;

        this.$list
            .on("click.dropdownEventHandler", "a", function () {
                self._clickHandler($(this));
            })
            .on("mouseover.dropdownEventHandler", "a", function (e) {
                // Don't select item under mouse cursor when scrolling.
                if (self.scrolling) {
                    self.scrolling = false;
                    return;
                }

                var $link = $(e.currentTarget),
                    $item = $link.closest("li"),
                    viewOffset = self.$list.offset(),
                    elementOffset = $item.offset();

                // Only set selected if in view
                if (elementOffset.top < viewOffset.top + self.$list.height()) {
                    if (viewOffset.top <= elementOffset.top) {
                        self._setSelectedIndex(self.$items.index($item), false);
                    }
                }
            });
    };

    /**
     * Re-register mouse event handlers
     * @param {!jQueryObject} $list  newly updated list object
     */
    DropdownEventHandler.prototype.reRegisterMouseHandlers = function ($list) {
        if (this.$list) {
            this.$list.off(".dropdownEventHandler");

            this.$list = $list;
            this.$items = $list.find("li");

            this._registerMouseEvents();
        }
    };

    // Export public API
    exports.DropdownEventHandler    = DropdownEventHandler;
});
<|endoftext|>


<commit_before>window.Kpcc = Ember.Application.create();

Kpcc.ApplicationAdapter = DS.RESTAdapter;

DS.RESTAdapter.reopen({
    host        : "http://www.scpr.org",
    namespace   : "api/v3"
});

Kpcc.ApplicationSerializer = DS.ActiveModelSerializer.extend({
    normalizePayload: function(payload) {
        delete payload.version;
        delete payload.status;

        return payload;
    }
});
<commit_msg>Only need to delete meta from payload<commit_after>window.Kpcc = Ember.Application.create();

Kpcc.ApplicationAdapter = DS.RESTAdapter;

DS.RESTAdapter.reopen({
    host        : "http://www.scpr.org",
    namespace   : "api/v3"
});

Kpcc.ApplicationSerializer = DS.ActiveModelSerializer.extend({
    normalizePayload: function(payload) {
        delete payload.meta;
        return payload;
    }
});
<|endoftext|>


<commit_before>(function(exports) {
    "use strict";

    function repeat(x, n) {
        var L = [];
        for (var i = 0; i < n; i++)
            L.push(x);
        return L;
    }

    function StructWrapper(props) {
        var type = props.StructName;
        var typeInfo = Runtime.typeInfo['%struct.' + type];
        var size = typeInfo.flatSize;

        var fieldNames = props.Fields;
        if (typeInfo.fields.length != fieldNames.length)
            throw new Error("Invalid fields");

        var constructor = function(ptr) {
            this.$internal = ptr;
        };
        constructor.type = type;
        constructor.typeInfo = typeInfo;
        constructor.size = typeInfo.flatSize;

        var descs = {};

        fieldNames.forEach(function(name, i) {
            var off = typeInfo.flatIndexes[i];
            var type = typeInfo.fields[i];
            descs[name] = { get: function() {
                return getValue(this.$internal + off, type);
            } };
        });

        Object.defineProperties(constructor.prototype, descs);

        return constructor;
    }

    function TypeWrapper(props) {
        var type = props.TypeName;
        var typeInfo = Runtime.typeInfo['%struct.' + type];
        var size = typeInfo.flatSize;

        var init = props.Initialize;
        var finalize = props.Finalize;

        var constructor = function() {
            this.__construct__();
            this.__init__();
        };

        constructor.type = type;
        constructor.typeInfo = typeInfo;
        constructor.size = size;

        var proto = constructor.prototype;
        props.AutoBind.forEach(function(desc) {
            var name = desc.name;
            var args = ['this'].concat(desc.args);
            var nargs = args.length;

            var cname = type + '_' + name.replace(/^_/, '');
            proto[name] = function() {
                var args = [].slice.call(arguments);
                args.unshift(this);
                args = args.map(function(x) {
                    if (x.$internal)
                        return x.$internal;
                    else
                        return x;
                });
                if (args.length != nargs)
                    throw new Error("Invalid number of args to " + cname);

                return ccall(cname, 'number', repeat('number', nargs), args);
            };
        });

        proto.__init__ = function() {
            this[init].apply(this, arguments);
        };

        proto.__construct__ = function() {
            this.$internal = _malloc(size);
        };

        proto.finalize = function() {
            this[finalize].apply(this, arguments);
            _free(this.$internal);
        };

        return constructor;
    }

    var Box = new StructWrapper({
        StructName: 'pixman_box32',
        Fields: ['x1', 'y1', 'x2', 'y2']
    });
    Object.defineProperties(Box.prototype, {
        x: { get: function() { return this.x1; } },
        y: { get: function() { return this.y1; } },
        width: { get: function() { return this.x2 - this.x1; } },
        height: { get: function() { return this.y2 - this.y1; } },
    });
    Box.prototype.toString = function() {
        return "+{x}+{y}x{width}x{height}".replace(/{(\w+)}/g, (function(match, name) {
            return this[name];
        }).bind(this));
    };

    var Region = new TypeWrapper({
        TypeName: 'pixman_region32',
        Initialize: 'init',
        Finalize: 'fini',
        AutoBind: [
            {name: "init", args: []},
            {name: "init_rect", args: ["x", "y", "width", "height"]},
            {name: "fini", args: []},
            {name: "clear", args: []},
            {name: "copy", args: ["source"]},
            {name: "translate", args: ["x", "y"]},
            {name: "union", args: ["r1", "r2"]},
            {name: "union_rect", args: ["source", "x", "y", "width", "height"]},
            {name: "intersect", args: ["r1", "r2"]},
            {name: "intersect_rect", args: ["source", "x", "y", "width", "height"]},
            {name: "subtract", args: ["r1", "r2"]},
            {name: "n_rects", args: []},
            {name: "not_empty", args: []},
            {name: "contains_point", args: ["x", "y"]},
            {name: "_rectangles", args: []},
            {name: "_extents", args: []},
        ]
    });
    Region.prototype.iter_rectangles = function(callback) {
        var ptr = this._rectangles();
        var size = Box.size;
        var end = ptr + this.n_rects() * size;
        for (; ptr < end; ptr += size) {
            callback(new Box(ptr));
        }
    };
    Region.prototype.get_rectangle = function(idx) {
        return new Box(this._rectangles() + Box.size*idx);
    };
    Region.prototype.extents = function() {
        return new Box(this._extents());
    };
    Region.prototype.is_empty = function() {
        return !this.not_empty();
    };
    Region.prototype.toString = function() {
        if (this.is_empty())
            return "[]";

        var S = "[";
        this.iter_rectangles(function(rect) {
            S += rect + ", ";
        });
        S = S.slice(0, -2) + "]";
        return S;
    };

    exports.Region = Region;

})(window);
<commit_msg>pixman-region-wrapper: Optimize a tiny bit<commit_after>(function(exports) {
    "use strict";

    function repeat(x, n) {
        var L = [];
        for (var i = 0; i < n; i++)
            L.push(x);
        return L;
    }

    function StructWrapper(props) {
        var type = props.StructName;
        var typeInfo = Runtime.typeInfo['%struct.' + type];
        var size = typeInfo.flatSize;

        var fieldNames = props.Fields;
        if (typeInfo.fields.length != fieldNames.length)
            throw new Error("Invalid fields");

        var constructor = function(ptr) {
            this.$internal = ptr;
        };
        constructor.type = type;
        constructor.typeInfo = typeInfo;
        constructor.size = typeInfo.flatSize;

        var descs = {};

        fieldNames.forEach(function(name, i) {
            var off = typeInfo.flatIndexes[i];
            var type = typeInfo.fields[i];
            descs[name] = { get: function() {
                return getValue(this.$internal + off, type);
            } };
        });

        Object.defineProperties(constructor.prototype, descs);

        return constructor;
    }

    function TypeWrapper(props) {
        var type = props.TypeName;
        var typeInfo = Runtime.typeInfo['%struct.' + type];
        var size = typeInfo.flatSize;

        var proto = {};
        props.AutoBind.forEach(function(desc) {
            var name = desc.name;
            var args = ['this'].concat(desc.args);
            var nargs = args.length;

            var cname = type + '_' + name.replace(/^_/, '');
            proto[name] = function() {
                var args = [].slice.call(arguments);
                args.unshift(this);
                args = args.map(function(x) {
                    if (x.$internal)
                        return x.$internal;
                    else
                        return x;
                });
                if (args.length != nargs)
                    throw new Error("Invalid number of args to " + cname);

                return ccall(cname, 'number', repeat('number', nargs), args);
            };
        });

        function fromPointer(ptr) {
            var obj = Object.create(proto);
            obj.$internal = ptr;
            return obj;
        }

        var init = proto[props.Initialize];
        var fini = proto[props.Finalize];

        var constructor = function() {
            var obj = fromPointer(_malloc(size));
            init.apply(obj, arguments);
            return obj;
        };
        constructor.prototype = proto;

        proto.finalize = function() {
            fini.apply(this, arguments);
            _free(this.$internal);
        };

        constructor.type = type;
        constructor.typeInfo = typeInfo;
        constructor.size = size;

        return constructor;
    }

    var Box = new StructWrapper({
        StructName: 'pixman_box32',
        Fields: ['x1', 'y1', 'x2', 'y2']
    });
    Object.defineProperties(Box.prototype, {
        x: { get: function() { return this.x1; } },
        y: { get: function() { return this.y1; } },
        width: { get: function() { return this.x2 - this.x1; } },
        height: { get: function() { return this.y2 - this.y1; } },
    });
    Box.prototype.toString = function() {
        return "+{x}+{y}x{width}x{height}".replace(/{(\w+)}/g, (function(match, name) {
            return this[name];
        }).bind(this));
    };

    var Region = new TypeWrapper({
        TypeName: 'pixman_region32',
        Initialize: 'init',
        Finalize: 'fini',
        AutoBind: [
            {name: "init", args: []},
            {name: "init_rect", args: ["x", "y", "width", "height"]},
            {name: "fini", args: []},
            {name: "clear", args: []},
            {name: "copy", args: ["source"]},
            {name: "translate", args: ["x", "y"]},
            {name: "union", args: ["r1", "r2"]},
            {name: "union_rect", args: ["source", "x", "y", "width", "height"]},
            {name: "intersect", args: ["r1", "r2"]},
            {name: "intersect_rect", args: ["source", "x", "y", "width", "height"]},
            {name: "subtract", args: ["r1", "r2"]},
            {name: "n_rects", args: []},
            {name: "not_empty", args: []},
            {name: "contains_point", args: ["x", "y"]},
            {name: "_rectangles", args: []},
            {name: "_extents", args: []},
        ]
    });
    Region.prototype.iter_rectangles = function(callback) {
        var ptr = this._rectangles();
        var size = Box.size;
        var end = ptr + this.n_rects() * size;
        for (; ptr < end; ptr += size) {
            callback(new Box(ptr));
        }
    };
    Region.prototype.get_rectangle = function(idx) {
        return new Box(this._rectangles() + Box.size*idx);
    };
    Region.prototype.extents = function() {
        return new Box(this._extents());
    };
    Region.prototype.is_empty = function() {
        return !this.not_empty();
    };
    Region.prototype.toString = function() {
        if (this.is_empty())
            return "[]";

        var S = "[";
        this.iter_rectangles(function(rect) {
            S += rect + ", ";
        });
        S = S.slice(0, -2) + "]";
        return S;
    };

    exports.Region = Region;

})(window);
<|endoftext|>


<commit_before>/*!
  [be]Lazy.js - v1.1.3 - 2014.01.21
  A lazy loading and multi-serving image script
  (c) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy
*/
var Blazy=function(c,h){function g(b){if(!h.querySelectorAll){var d=h.createStyleSheet();h.querySelectorAll=function(b,a,c,e,g){g=h.all;a=[];b=b.replace(/\[for\b/gi,"[htmlFor").split(",");for(c=b.length;c--;){d.addRule(b[c],"k:v");for(e=g.length;e--;)g[e].currentStyle.k&&a.push(g[e]);d.removeRule(0)}return a}}a=b||{};a.src=a.src||"data-src";a.multi=a.multi||!1;a.error=a.error||!1;a.offset=a.offset||100;a.success=a.success||!1;a.selector=a.selector||".b-lazy";a.separator=a.separator||"|";a.container=a.container?h.querySelectorAll(a.container):!1;a.errorClass=a.errorClass||"b-error";a.successClass=a.successClass||"b-loaded";q=a.src;u=1<c.devicePixelRatio;e=v(w,20);r=v(x,50);x();l(a.multi,function(b){if(b.width>=c.screen.width)return q=b.src,!1});y()}function w(){for(var b=0;b<k;b++){var d=m[b],t=-1!==(" "+d.className+" ").indexOf(" "+a.successClass+" "),f=d.getBoundingClientRect(),c=z+a.offset;if(0<=f.left&&f.right<=A+a.offset&&(0<=f.top&&f.top<=c||f.bottom<=c&&f.bottom>=0-a.offset)||t)t||B(d),m.splice(b,1),k--,b--}0===k&&g.prototype.destroy()}function B(b){if(0<b.offsetWidth&&0<b.offsetHeight){var d=b.getAttribute(q)||b.getAttribute(a.src);if(d){var d=d.split(a.separator),c=d[u&&1<d.length?1:0],d=new Image;l(a.multi,function(a){b.removeAttribute(a.src)});b.removeAttribute(a.src);d.onerror=function(){a.error&&a.error(b,"invalid");b.className=b.className+" "+a.errorClass};d.onload=function(){"img"===b.nodeName.toLowerCase()?b.src=c:b.setAttribute("style",'background-image: url("'+c+'");');b.className=b.className+" "+a.successClass;a.success&&a.success(b)};d.src=c}else a.error&&a.error(b,"missing"),b.className=b.className+" "+a.errorClass}}function C(b){b=h.querySelectorAll(b);for(var a=k=b.length;a--;m.unshift(b[a]));}function x(){var b=h.documentElement;z=c.innerHeight||b.clientHeight;A=c.innerWidth||b.clientWidth}function y(){C(a.selector);s&&(s=!1,a.container&&l(a.container,function(b){n(b,"scroll",e)}),n(c,"scroll",e),n(c,"resize",e),n(c,"resize",r));w()}function n(b,a,c){b.attachEvent?b.attachEvent&&b.attachEvent("on"+a,c):b.addEventListener(a,c,!1)}function p(b,a,c){b.detachEvent?b.detachEvent&&b.detachEvent("on"+a,c):b.removeEventListener(a,c,!1)}function l(b,a){if(b&&a)for(var c=b.length,f=0;f<c&&!1!==a(b[f],f);f++);}function v(a,c){var e=0;return function(){var f=+new Date;f-e<c||(e=f,a.apply(this,arguments))}}var q,a,A,z,u,s=!0,k=0,m=[],e,r;g.prototype.revalidate=function(){y()};g.prototype.load=function(b){-1===(" "+b.className+" ").indexOf(" "+a.successClass+" ")&&B(b)};g.prototype.destroy=function(){a.container&&l(a.container,function(a){p(a,"scroll",e)});p(c,"scroll",e);p(c,"resize",e);p(c,"resize",r);k=0;m.length=0;s=!0};return g}(window,document);<commit_msg>clean the repo before branching<commit_after><|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import AppBar from 'material-ui/AppBar';
import CircularProgress from 'material-ui/CircularProgress';
import Notification from './Notification';
import injectTapEventPlugin from 'react-tap-event-plugin';
import Menu from './Menu';

injectTapEventPlugin();

const Layout = ({ isLoading, children, route }) => (
    <MuiThemeProvider>

            <AppBar title="Admin on REST" iconElementRight={isLoading ? <CircularProgress color="#fff" size={0.5} /> : } />

{children}

                <Menu resources={route.resources} />

            <Notification />

    </MuiThemeProvider>
);

Layout.propTypes = {
    isLoading: PropTypes.bool.isRequired,
    children: PropTypes.node,
    route: PropTypes.object.isRequired,
};

function mapStateToProps(state) {
    return { isLoading: state.admin.loading > 0 };
}

export default connect(
  mapStateToProps,
)(Layout);
<commit_msg>Add link to dashboard in app title<commit_after>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import AppBar from 'material-ui/AppBar';
import CircularProgress from 'material-ui/CircularProgress';
import Notification from './Notification';
import injectTapEventPlugin from 'react-tap-event-plugin';
import Menu from './Menu';

injectTapEventPlugin();

const Layout = ({ isLoading, children, route }) => (
    <MuiThemeProvider>

            <AppBar title={<Link to="/" style={{ color: '#fff' }}>Admin on REST</Link>} iconElementRight={isLoading ? <CircularProgress color="#fff" size={0.5} /> : } />

{children}

                <Menu resources={route.resources} />

            <Notification />

    </MuiThemeProvider>
);

Layout.propTypes = {
    isLoading: PropTypes.bool.isRequired,
    children: PropTypes.node,
    route: PropTypes.object.isRequired,
};

function mapStateToProps(state) {
    return { isLoading: state.admin.loading > 0 };
}

export default connect(
  mapStateToProps,
)(Layout);
<|endoftext|>


<commit_before>var LEM2 = {
    blocks: {},
    dataset: [],
    datasetConcepts: [],
    singleLocalCovering: [],
    goal: new Set(),
    concept: { "decision": "", "value": "", "cases": new Set() },

    newConcepts: function () {
        LEM2.datasetConcepts = [];

        var decisionIndex = LEM2.dataset[0].length - 1;
        var dataset = LEM2.dataset.slice(0);
        var decision = dataset[0][decisionIndex];
        // Remove decision label
        dataset.shift();

        var column = dataset.map(function (value) {
            return value[decisionIndex];
        });

        var decisionValues = column.filter(function (value, index, self) {
            return self.indexOf(value) === index;
        });

        decisionValues.forEach(function (decisionValue) {
            var cases = column.reduce(function (decisionValues, value, index) {
                if (value === decisionValue) {
                    decisionValues.push(index + 1);
                }
                return decisionValues;
            }, []);

            var concept = {
                "decision": decision,
                "value": decisionValue,
                "cases": new Set(cases)
            };

            LEM2.datasetConcepts.push(concept);
        });
    },

    newAttributeValueBlocks: function () {
      LEM2.blocks = {};
      const dataset = [];
      LEM2.dataset.forEach(function (row, rowIndex) {
        dataset[rowIndex] = row.slice(0);
      });

      var attributeNames = dataset[0].slice(0);
      // Remove decision label
      attributeNames.pop();
      // Remove labels
      dataset.shift();
      console.log(attributeNames);

      attributeNames.forEach(function (attributeName, attributeIndex) {
        LEM2.blocks[attributeName] = {};

        var column = dataset.map(function (value) {
          return value[attributeIndex];
        });

        // TODO: Refactor indentation levels
        var attributeValues = [];
        column.forEach(function (attributeValue) {
          if (attributeValue.size) {
            attributeValue.forEach(function (setValue) {
              if (attributeValues.indexOf(setValue) === -1) {
                attributeValues.push(setValue);
              }
            });
            return;
          }

          if (attributeValues.indexOf(attributeValue) !== -1) {
            return;
          }

          attributeValues.push(attributeValue);
        });
        console.log(attributeValues);

        attributeValues.forEach(function (attributeValue) {
          LEM2.blocks[attributeName][attributeValue] = column.reduce(function (attributeValues, value, index) {
            if (value === attributeValue) {
              attributeValues.push(index + 1);
            }
            return attributeValues;
          }, []);
        });
      });
    },

    initialize: function (dataset) {
        LEM2.dataset = dataset;
        LEM2.newConcepts();
        LEM2.newAttributeValueBlocks();
    },

    initializeProcedure: function (concept) {
        LEM2.concept = concept;
        LEM2.singleLocalCovering = [];
        LEM2.updateGoal();
    },

    invokeProcedure: function (concept) {
        LEM2.initializeProcedure(concept);
        LEM2.newRuleset();
        LEM2.compressRuleset();
    },

    newRuleset: function () {
        while (LEM2.goal.size) {
            var rule = LEM2.newRule();
            LEM2.singleLocalCovering.push(rule);
            LEM2.updateGoal();
        }
    },

    newRule: function () {

        var rule = { "conditions": [], "decision": { "name": LEM2.concept.decision, "value": LEM2.concept.value }, "consistent": true };

        do {
            var intersections = LEM2.newGoalBlockIntersections(rule);

            if (intersections.length === 0) {
                rule.consistent = false;
                console.error("Inconsistent Rule Created");
                console.log(rule);
                break;
            }

            var bestBlock = LEM2.selectBestBlock(intersections);
            var condition = { "attribute": bestBlock.attribute, "value": bestBlock.value };
            rule.conditions.push(condition);
            LEM2.goal = LEM2.goal.intersection(bestBlock.cases);

            var coveredCases = LEM2.getCasesCoveredByRule(rule);
            var isSubset = LEM2.concept.cases.isSuperset(coveredCases);
        } while (rule.conditions.length === 0 || !isSubset)

        rule = LEM2.compressRule(rule);
        return rule;
    },

    getCasesCoveredByRuleset: function (ruleset) {

        var coveredCases = new Set();
        ruleset.forEach(function (rule) {
            var coveredCasesByRule = LEM2.getCasesCoveredByRule(rule);
            coveredCases = coveredCases.union(coveredCasesByRule);
        });
        return coveredCases.sort();
    },

    getCasesCoveredByRule: function (rule) {
        var attributes = LEM2.dataset[0];
        var coveredCases = new Set();

        rule.conditions.forEach(function (condition) {
            var block = new Set(LEM2.blocks[condition.attribute][condition.value]);
            if (coveredCases.size === 0) {
                coveredCases = block;
                return;
            }
            coveredCases = coveredCases.intersection(block);
        });

        return coveredCases.sort();
    },

    compressRule: function (rule) {
        var minimalConditions = [];
        var removedConditions = [];
        var minimalRule = {
            "conditions": [],
            "decision": rule.decision,
            "consistent": rule.consistent
        }

        rule.conditions.forEach(function (condition, conditionIndex) {
            var conditionsMinusCondition = rule.conditions.slice(0);
            conditionsMinusCondition.splice(conditionIndex, 1);
            removedConditions.forEach(function (removedIndex) {
                conditionsMinusCondition.splice(removedIndex, 1);
            });

            if (conditionsMinusCondition.length === 0) {
                minimalConditions.push(condition);
                return false;
            }

            minimalRule.conditions = conditionsMinusCondition;
            var coveredCasesMinusCondition = LEM2.getCasesCoveredByRule(minimalRule);

            if (LEM2.concept.cases.isSuperset(coveredCasesMinusCondition)) {
                removedConditions.push(conditionIndex);
            }
            else {
                minimalConditions.push(condition);
            }
        });

        minimalRule.conditions = minimalConditions;
        return minimalRule;
    },

    compressRuleset: function () {
        var minimalRuleset = [];
        var removedRules = [];

        LEM2.singleLocalCovering.forEach(function (rule, ruleIndex) {
            var rulesetMinusRule = LEM2.singleLocalCovering.slice(0);
            rulesetMinusRule.splice(ruleIndex, 1);
            removedRules.forEach(function (removedIndex) {
                rulesetMinusRule.splice(removedIndex, 1);
            });

            if (rulesetMinusRule.length === 0) {
                minimalRuleset.push(rule);
                return false;
            }

            var coveredCasesMinusRule = LEM2.getCasesCoveredByRuleset(rulesetMinusRule);
            var coveredDifference = LEM2.concept.cases.difference(coveredCasesMinusRule);

            // if rules covered by minus ruleset does not equal rules covered by original ruleset, add to minimalRuleset
            if (coveredDifference.size > 0) {
                minimalRuleset.push(rule);
            }
            else {
                removedRules.push(ruleIndex);
            }
        });

        LEM2.singleLocalCovering = minimalRuleset;
    },

    findCondition: function (rule, targetCondition) {
        var targetIndex = -1;

        rule.conditions.forEach(function (condition, conditionIndex) {
            if (condition.attribute !== targetCondition.attribute) {
                return;
            }

            if (condition.value !== targetCondition.value) {
                return;
            }

            targetIndex = conditionIndex;
        });

        return targetIndex;
    },

    newGoalBlockIntersections: function (rule) {
        var intersections = [];

        for (var attribute in LEM2.blocks) {
            var attributeBlocks = LEM2.blocks[attribute];
            for (var attributeValue in attributeBlocks) {
                var conditionIndex = LEM2.findCondition(rule, { "attribute": attribute, "value": attributeValue });
                if (conditionIndex !== -1) {
                    continue;
                }

                var blockCases = new Set(LEM2.blocks[attribute][attributeValue]);
                var intersection = {
                    "attribute": attribute,
                    "value": attributeValue,
                    "cases": blockCases.intersection(LEM2.goal)
                }
                if (intersection.cases.size) {
                    intersections.push(intersection);
                }
            }
        }

        return intersections;
    },

    selectBestBlock: function (intersections) {
        var bestBlock = intersections[0];
        var bestCardinality = LEM2.blocks[intersections[0].attribute][intersections[0].value].length;

        intersections.forEach(function (intersection) {
            var cardinality = LEM2.blocks[intersection.attribute][intersection.value].length;

            if (intersection.cases.size < bestBlock.cases.size) {
                return;
            }

            if (intersection.cases.size > bestBlock.cases.size) {
                bestBlock = intersection;
                bestCardinality = cardinality;
                return;
            }

            if (cardinality > bestCardinality) {
                return;
            }

            if (cardinality < bestCardinality) {
                bestBlock = intersection;
                bestCardinality = cardinality;
                return;
            }
        });

        return bestBlock;
    },

    updateGoal: function () {
        var coveredCases = LEM2.getCasesCoveredByRuleset(LEM2.singleLocalCovering);
        LEM2.goal = LEM2.concept.cases.difference(coveredCases);
    },

    convertToSetValuedDataset: function (dataset) {
      var dataset = JSON.parse(JSON.stringify(dataset));

      dataset.forEach(function (row, rowIndex) {
        if (rowIndex === 0) {
          // skip header
          return;
        }

        row.forEach(function (cell, cellIndex) {
          if (cell.indexOf("|") === -1) {
            return;
          }

          var splitCell = cell.split("|");
          dataset[rowIndex][cellIndex] = new Set(splitCell);
        });
      });

      return dataset;
    }
};

<commit_msg>Add dataset conversion<commit_after>var LEM2 = {
    blocks: {},
    dataset: [],
    datasetConcepts: [],
    singleLocalCovering: [],
    goal: new Set(),
    concept: { "decision": "", "value": "", "cases": new Set() },

    newConcepts: function () {
        LEM2.datasetConcepts = [];

        var decisionIndex = LEM2.dataset[0].length - 1;
        var dataset = LEM2.dataset.slice(0);
        var decision = dataset[0][decisionIndex];
        // Remove decision label
        dataset.shift();

        var column = dataset.map(function (value) {
            return value[decisionIndex];
        });

        var decisionValues = column.filter(function (value, index, self) {
            return self.indexOf(value) === index;
        });

        decisionValues.forEach(function (decisionValue) {
            var cases = column.reduce(function (decisionValues, value, index) {
                if (value === decisionValue) {
                    decisionValues.push(index + 1);
                }
                return decisionValues;
            }, []);

            var concept = {
                "decision": decision,
                "value": decisionValue,
                "cases": new Set(cases)
            };

            LEM2.datasetConcepts.push(concept);
        });
    },

    newAttributeValueBlocks: function () {
      LEM2.blocks = {};
      const dataset = [];
      LEM2.dataset.forEach(function (row, rowIndex) {
        dataset[rowIndex] = row.slice(0);
      });

      var attributeNames = dataset[0].slice(0);
      // Remove decision label
      attributeNames.pop();
      // Remove labels
      dataset.shift();
      console.log(attributeNames);

      attributeNames.forEach(function (attributeName, attributeIndex) {
        LEM2.blocks[attributeName] = {};

        var column = dataset.map(function (value) {
          return value[attributeIndex];
        });

        // TODO: Refactor indentation levels
        var attributeValues = [];
        column.forEach(function (attributeValue) {
          if (attributeValue.size) {
            attributeValue.forEach(function (setValue) {
              if (attributeValues.indexOf(setValue) === -1) {
                attributeValues.push(setValue);
              }
            });
            return;
          }

          if (attributeValues.indexOf(attributeValue) !== -1) {
            return;
          }

          attributeValues.push(attributeValue);
        });
        console.log(attributeValues);

        attributeValues.forEach(function (attributeValue) {
          LEM2.blocks[attributeName][attributeValue] = column.reduce(function (attributeValues, value, index) {
            if (value === attributeValue) {
              attributeValues.push(index + 1);
            }
            return attributeValues;
          }, []);
        });
      });
    },

    initialize: function (dataset) {
        LEM2.dataset = dataset;
        LEM2.dataset = LEM2.convertToSetValuedDataset(LEM2.dataset);
        LEM2.newConcepts();
        LEM2.newAttributeValueBlocks();
    },

    initializeProcedure: function (concept) {
        LEM2.concept = concept;
        LEM2.singleLocalCovering = [];
        LEM2.updateGoal();
    },

    invokeProcedure: function (concept) {
        LEM2.initializeProcedure(concept);
        LEM2.newRuleset();
        LEM2.compressRuleset();
    },

    newRuleset: function () {
        while (LEM2.goal.size) {
            var rule = LEM2.newRule();
            LEM2.singleLocalCovering.push(rule);
            LEM2.updateGoal();
        }
    },

    newRule: function () {

        var rule = { "conditions": [], "decision": { "name": LEM2.concept.decision, "value": LEM2.concept.value }, "consistent": true };

        do {
            var intersections = LEM2.newGoalBlockIntersections(rule);

            if (intersections.length === 0) {
                rule.consistent = false;
                console.error("Inconsistent Rule Created");
                console.log(rule);
                break;
            }

            var bestBlock = LEM2.selectBestBlock(intersections);
            var condition = { "attribute": bestBlock.attribute, "value": bestBlock.value };
            rule.conditions.push(condition);
            LEM2.goal = LEM2.goal.intersection(bestBlock.cases);

            var coveredCases = LEM2.getCasesCoveredByRule(rule);
            var isSubset = LEM2.concept.cases.isSuperset(coveredCases);
        } while (rule.conditions.length === 0 || !isSubset)

        rule = LEM2.compressRule(rule);
        return rule;
    },

    getCasesCoveredByRuleset: function (ruleset) {

        var coveredCases = new Set();
        ruleset.forEach(function (rule) {
            var coveredCasesByRule = LEM2.getCasesCoveredByRule(rule);
            coveredCases = coveredCases.union(coveredCasesByRule);
        });
        return coveredCases.sort();
    },

    getCasesCoveredByRule: function (rule) {
        var attributes = LEM2.dataset[0];
        var coveredCases = new Set();

        rule.conditions.forEach(function (condition) {
            var block = new Set(LEM2.blocks[condition.attribute][condition.value]);
            if (coveredCases.size === 0) {
                coveredCases = block;
                return;
            }
            coveredCases = coveredCases.intersection(block);
        });

        return coveredCases.sort();
    },

    compressRule: function (rule) {
        var minimalConditions = [];
        var removedConditions = [];
        var minimalRule = {
            "conditions": [],
            "decision": rule.decision,
            "consistent": rule.consistent
        }

        rule.conditions.forEach(function (condition, conditionIndex) {
            var conditionsMinusCondition = rule.conditions.slice(0);
            conditionsMinusCondition.splice(conditionIndex, 1);
            removedConditions.forEach(function (removedIndex) {
                conditionsMinusCondition.splice(removedIndex, 1);
            });

            if (conditionsMinusCondition.length === 0) {
                minimalConditions.push(condition);
                return false;
            }

            minimalRule.conditions = conditionsMinusCondition;
            var coveredCasesMinusCondition = LEM2.getCasesCoveredByRule(minimalRule);

            if (LEM2.concept.cases.isSuperset(coveredCasesMinusCondition)) {
                removedConditions.push(conditionIndex);
            }
            else {
                minimalConditions.push(condition);
            }
        });

        minimalRule.conditions = minimalConditions;
        return minimalRule;
    },

    compressRuleset: function () {
        var minimalRuleset = [];
        var removedRules = [];

        LEM2.singleLocalCovering.forEach(function (rule, ruleIndex) {
            var rulesetMinusRule = LEM2.singleLocalCovering.slice(0);
            rulesetMinusRule.splice(ruleIndex, 1);
            removedRules.forEach(function (removedIndex) {
                rulesetMinusRule.splice(removedIndex, 1);
            });

            if (rulesetMinusRule.length === 0) {
                minimalRuleset.push(rule);
                return false;
            }

            var coveredCasesMinusRule = LEM2.getCasesCoveredByRuleset(rulesetMinusRule);
            var coveredDifference = LEM2.concept.cases.difference(coveredCasesMinusRule);

            // if rules covered by minus ruleset does not equal rules covered by original ruleset, add to minimalRuleset
            if (coveredDifference.size > 0) {
                minimalRuleset.push(rule);
            }
            else {
                removedRules.push(ruleIndex);
            }
        });

        LEM2.singleLocalCovering = minimalRuleset;
    },

    findCondition: function (rule, targetCondition) {
        var targetIndex = -1;

        rule.conditions.forEach(function (condition, conditionIndex) {
            if (condition.attribute !== targetCondition.attribute) {
                return;
            }

            if (condition.value !== targetCondition.value) {
                return;
            }

            targetIndex = conditionIndex;
        });

        return targetIndex;
    },

    newGoalBlockIntersections: function (rule) {
        var intersections = [];

        for (var attribute in LEM2.blocks) {
            var attributeBlocks = LEM2.blocks[attribute];
            for (var attributeValue in attributeBlocks) {
                var conditionIndex = LEM2.findCondition(rule, { "attribute": attribute, "value": attributeValue });
                if (conditionIndex !== -1) {
                    continue;
                }

                var blockCases = new Set(LEM2.blocks[attribute][attributeValue]);
                var intersection = {
                    "attribute": attribute,
                    "value": attributeValue,
                    "cases": blockCases.intersection(LEM2.goal)
                }
                if (intersection.cases.size) {
                    intersections.push(intersection);
                }
            }
        }

        return intersections;
    },

    selectBestBlock: function (intersections) {
        var bestBlock = intersections[0];
        var bestCardinality = LEM2.blocks[intersections[0].attribute][intersections[0].value].length;

        intersections.forEach(function (intersection) {
            var cardinality = LEM2.blocks[intersection.attribute][intersection.value].length;

            if (intersection.cases.size < bestBlock.cases.size) {
                return;
            }

            if (intersection.cases.size > bestBlock.cases.size) {
                bestBlock = intersection;
                bestCardinality = cardinality;
                return;
            }

            if (cardinality > bestCardinality) {
                return;
            }

            if (cardinality < bestCardinality) {
                bestBlock = intersection;
                bestCardinality = cardinality;
                return;
            }
        });

        return bestBlock;
    },

    updateGoal: function () {
        var coveredCases = LEM2.getCasesCoveredByRuleset(LEM2.singleLocalCovering);
        LEM2.goal = LEM2.concept.cases.difference(coveredCases);
    },

    convertToSetValuedDataset: function (dataset) {
      var dataset = JSON.parse(JSON.stringify(dataset));

      dataset.forEach(function (row, rowIndex) {
        if (rowIndex === 0) {
          // skip header
          return;
        }

        row.forEach(function (cell, cellIndex) {
          if (cell.indexOf("|") === -1) {
            return;
          }

          var splitCell = cell.split("|");
          dataset[rowIndex][cellIndex] = new Set(splitCell);
        });
      });

      return dataset;
    }
};

<|endoftext|>