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

	var DEBUG      = false;

	var Fn         = window.Fn;
	var dom        = window.dom;
	var Observable = window.Observable;
	var Sparky     = window.Sparky;
	var frame      = window.frame;
	var A          = Array.prototype;

	var noop       = Fn.noop;
	var before     = dom.before;
	var clone      = dom.clone;
	var remove     = dom.remove;
	var tag        = dom.tag;
	var cue        = frame.cue;
	var uncue      = frame.uncue;
	var observe    = Observable.observe;
	var MarkerNode = Sparky.MarkerNode;

	var $object    = Symbol('object');

	function create(node, object, options) {
		if (DEBUG) { console.groupCollapsed('each: create', node); }
		var sparky = new Sparky(node, object, options);
		if (DEBUG) { console.groupEnd(); }
		sparky[$object] = object;
		return sparky;
	}

	function reorderCache(template, options, array, sparkies) {
		var n    = -1;
		var sparky, object, i;

		// Reorder sparkies
		while (++n < array.length) {
			object = array[n];
			sparky = sparkies[n];

			if (sparky && object === sparky[$object]) {
				continue;
			}

			// i = -1
			i = n - 1;
			while (sparkies[++i] && sparkies[i][$object] !== object);

			sparky = i === sparkies.length ?
				create(clone(template), object, options) :
				sparkies.splice(i, 1)[0];

			sparkies.splice(n, 0, sparky);
		}

		// Reordering has pushed all removed sparkies to the end of the
		// sparkies. Remove them.
		while (sparkies.length > array.length) {
			A.forEach.call(sparkies.pop().stop(), remove);
		}
	}

	function reorderNodes(node, array, sparkies) {
		// Reorder nodes in the DOM
		var l = sparkies.length;
		var n = -1;
		var parent = node.parentNode;

		while (n < l) {
			// Note that node is null where nextSibling does not exist
			node = node ? node.nextSibling : null ;

			while (++n < l && sparkies[n][0] !== node) {
				// Passing null to insertBefore appends to the end I think
				parent.insertBefore(sparkies[n][0], node);
			}
		}
	}

	function eachFrame(stream, fn) {
		var unobserve = noop;

		function update(time) {
//console.log('UPDATE')
			var scope = stream.shift();
			// Todo: shouldnt need this line - observe(undefined) shouldnt call fn
			if (scope === undefined) { return; }

			function render(time) {
				fn(scope);
			}

			unobserve();

			var uno = observe(scope, '', function() {
				cue(render);
			});

			unobserve = function() {
				uno();
				uncue(render);
			};
		}

		function push() {
		//console.log('PUSH')
			cue(update);
		}

		if (stream.on) {
			stream.on('push', push);
		}
		else {
			push();
		}

		return function() {
			stream.off('push', push);
			unobserve();
			uncue(update);
		};
	}

	Sparky.fn.each = function each(node, scopes, params) {
		var sparkies = [];
		var template = node.cloneNode(true);
		var options  = this.interrupt();
		var marker   = MarkerNode(node);
		var isSelect = tag(node) === 'option';

		function update(array) {
			// Selects will lose their value if the selected option is removed
			// from the DOM, even if there is another <option> of same value
			// already in place. (Interestingly, value is not lost if the
			// selected <option> is simply moved). Make an effort to have
			// selects retain their value.
			var value = isSelect ? marker.parentNode.value : undefined ;

			if (DEBUG) { console.log('render: each ' + JSON.stringify(array)); }
			reorderCache(template, options, array, sparkies);
			reorderNodes(marker, array, sparkies);

			// A fudgy workaround because observe() callbacks (like this update
			// function) are not batched to ticks.
			// TODO: batch observe callbacks to ticks.
			if (isSelect && value !== undefined) {<commit_msg>each loops over objects as well as arrays<commit_after>(function(window) {
	"use strict";

	var DEBUG      = false;

	var Fn         = window.Fn;
	var dom        = window.dom;
	var Observable = window.Observable;
	var Sparky     = window.Sparky;
	var frame      = window.frame;
	var A          = Array.prototype;

	var isArray    = Array.isArray;
	var noop       = Fn.noop;
	var before     = dom.before;
	var clone      = dom.clone;
	var remove     = dom.remove;
	var tag        = dom.tag;
	var cue        = frame.cue;
	var uncue      = frame.uncue;
	var observe    = Observable.observe;
	var MarkerNode = Sparky.MarkerNode;

	var $object    = Symbol('object');

	function create(node, object, options) {
		if (DEBUG) { console.groupCollapsed('each: create', node); }
		var sparky = new Sparky(node, object, options);
		if (DEBUG) { console.groupEnd(); }
		sparky[$object] = object;
		return sparky;
	}

	function reorderCache(template, options, array, sparkies) {
		var n    = -1;
		var sparky, object, i;

		// Reorder sparkies
		while (++n < array.length) {
			object = array[n];
			sparky = sparkies[n];

			if (sparky && object === sparky[$object]) {
				continue;
			}

			// i = -1
			i = n - 1;
			while (sparkies[++i] && sparkies[i][$object] !== object);

			sparky = i === sparkies.length ?
				create(clone(template), object, options) :
				sparkies.splice(i, 1)[0];

			sparkies.splice(n, 0, sparky);
		}

		// Reordering has pushed all removed sparkies to the end of the
		// sparkies. Remove them.
		while (sparkies.length > array.length) {
			A.forEach.call(sparkies.pop().stop(), remove);
		}
	}

	function reorderNodes(node, array, sparkies) {
		// Reorder nodes in the DOM
		var l = sparkies.length;
		var n = -1;
		var parent = node.parentNode;

		while (n < l) {
			// Note that node is null where nextSibling does not exist
			node = node ? node.nextSibling : null ;

			while (++n < l && sparkies[n][0] !== node) {
				// Passing null to insertBefore appends to the end I think
				parent.insertBefore(sparkies[n][0], node);
			}
		}
	}

	function eachFrame(stream, fn) {
		var unobserve = noop;

		function update(time) {
			var scope = stream.shift();
			// Todo: shouldnt need this line - observe(undefined) shouldnt call fn
			if (scope === undefined) { return; }

			function render(time) {
				fn(scope);
			}

			unobserve();

			var uno = observe(scope, '', function() {
				cue(render);
			});

			unobserve = function() {
				uno();
				uncue(render);
			};
		}

		function push() {
			cue(update);
		}

		if (stream.on) {
			stream.on('push', push);
		}
		else {
			push();
		}

		return function() {
			stream.off('push', push);
			unobserve();
			uncue(update);
		};
	}

	function entryToKeyValue(entry) {
		return {
			key:   entry[0],
			value: entry[1]
		};
	}

	Sparky.fn.each = function each(node, scopes, params) {
		var sparkies = [];
		var template = node.cloneNode(true);
		var options  = this.interrupt();
		var marker   = MarkerNode(node);
		var isSelect = tag(node) === 'option';

		function update(array) {
			// Selects will lose their value if the selected option is removed
			// from the DOM, even if there is another <option> of same value
			// already in place. (Interestingly, value is not lost if the
			// selected <option> is simply moved). Make an effort to have
			// selects retain their value.
			var value = isSelect ? marker.parentNode.value : undefined ;

			if (!isArray(array)) {
				array = Object.entries(array).map(entryToKeyValue);
			}

			if (DEBUG) { console.log('render: each ' + JSON.stringify(array)); }

			reorderCache(template, options, array, sparkies);
			reorderNodes(marker, array, sparkies);

			// A fudgy workaround because observe() callbacks (like this update
			// function) are not batched to ticks.
			// TODO: batch observe callbacks to ticks.
			if (isSelect && value !== undefined) {
{'fraction_non_alphanumeric': 0.13779423432954244, 'fraction_numerical': 0.0026448029621793175, 'mean_word_length': 2.8119959677419355, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2807626', 'n_tokens_mistral': 2897, 'n_tokens_neox': 2477, 'n_words': 735}