<commit_before>

(function( exports ) {
	var _supportsTemplate = 'content' in document.createElement('template');
	
	function _define( name, Parent, protoProps ) {
		// `children` has to be created here — creating it in the
		// `Block` prototype would make it static. Creating it
		// in `initialize` would always create a children object, even
		// when this block will never have children.
		this.prototype.childBlocks || (this.prototype.childBlocks = {});
		if( this.prototype.childBlocks[name] ) {
			throw new Error('Block already defined');
		}
		
		return this.prototype.childBlocks[name] =
		       _createChildBlock(name, Parent, protoProps);
	}
	function _extend( protoProps, staticProps ) {
		return _.inherit(this, {
			prototype: protoProps || {},
			static:    staticProps
		});
	}
	function _createChildBlock( name, Parent, protoProps ) {
		if( !Parent ) {
			protoProps = {};
			Parent     = Block;
		} else if( Parent.constructor == Object ) {
			protoProps = Parent;
			Parent     = Block;
		}
		protoProps || (protoProps = {});
		var ChildBlock = Parent.extend(protoProps);
		
		if( ChildBlock.prototype.name ) {
			throw new Error('Illegal block definition');
		}
		ChildBlock.prototype.name = name;
		
		return ChildBlock;
	}
	
	var Block = exports.Block = function() {
		this.initialize.apply(this, arguments);
	};
	Block.prototype = {
		// Static propertes
		// ----------------
		// These properties remain the same for all instances.
		// 
		name:        undefined,
		// Object with references to child Block classes. This is the
		// logic part of the template tree.
		childBlocks: undefined,
		
		// Instance properties
		// -------------------
		// These properties get set upon instantiation.
		// 
		// Reference to parent instance.
		parent:      undefined,
		// An array with references to added children.
		children:    undefined,
		// Config for rendering this block (and optional children).
		config:      undefined,
		// Reference to the correct template object. This object is used
		// to be able to insert parsed HTML *before it*. It also tries to keep
		// track of which DOM elements belong to this block, so they can be removed
		// from the DOM when this block is removed.
		template:    undefined,
		
		// Constructor that's called when this block is added to be rendered.
		// The `config` parameter:
		// {
		//   vars:     Object with variables used for rendering.
		//   children: Hash map of child objects:
		//             {
		//               blockName: Array of config objects like this one.
		//             }
		// }
		// 
		// The recursiveness of the `config` object allows to build an entire page
		// by passing the complete config to the root block.
		// 
		// * `connect` is true when a block is initialized via `add`.
		// * `connect` is false when intitialized via `give`.
		initialize: function( config, parent, connect ) {
			this.config   = config;
			this.parent   = connect ?
			                parent._addReference(this) :
			                parent;
			this.template = this._initTemplate(this.name);
			this._renderSelf();
		},
		destroy: function() {
			this.children && this.children.forEach(function( child ) {
				child.destroy();
			});
			
			this.remove();
			this.parent._removeReference(this);
			
			if( !this.template ) return;
			// Doesn't work on text-only templates.
			this.template.fragmentNodes.forEach(function( partial ) {
				partial.parentNode.removeChild(partial);
			});
			
			this.children = null;
			this.config   = null;
			this.template = null;
		},
		create: function( blockName, config, connect ) {
			var blockClass = this.childBlocks && this.childBlocks[blockName];
			if( blockClass ) {
				return new blockClass(config, this, !!connect);
			} else {
				return null;
			}
		},
		// Add child block.
		// `how` determines where to place the new block. See `Template.out`
		// to find out what the possible values are, and what they do.
		add: function( blockName, config, how ) {
			var child    = this.create(blockName, config, true)
			  , template = child ?
			               child.template :
			               this._renderPlainChild(blockName);
			Template.out(template, how);
			return child;
		},
		before:  function( blockName, config ) { return this.add(blockName, config, 'before') },
		after:   function( blockName, config ) { return this.add(blockName, config, 'after') },
		prepend: function( blockName, config ) { return this.add(blockName, config, 'prepend') },
		append:  function( blockName, config ) { return this.add(blockName, config, 'append') },
		// Give the template of a child block. Its content will not be
		// appended to the DOM.
		give: function( blockName, config ) {
			var child    = this.create(blockName, config, false)
			  , template = child ?
			               child.template :
			               this._renderPlainChild(blockName);
			return template;
		},
		
		// Overridable methods
		// -------------------
		// A Block subclass can override these methods to implement custom render logic.
		// 
		// For replacing variables in the rendered HTML.
		replaceVariables: function( fragment ) {},
		// For manipulating the DOM structure.
		render: function( fragment ) {},
		// When this block is removed, undo things you did in render here.
		remove: function() {},
		
		
		// Render methods
		// --------------
		_renderSelf: function() {
			// Render the current block and attach it to the DOM.
			this.render();
			this.replaceVariables(this.template.fragment);
		},
		_renderPlainChild: function( name ) {
			var childTemplate = this._initTemplate(name, this.template && this.template.fragmentNodes);
			if( childTemplate ) {
				this.replaceVariables(childTemplate.fragment);
			}
			
			return childTemplate;
		},
		
		// Utility methods
		// ---------------
		// 
		// `_addReference` and `_removeReference` connect a child blocks to
		// its parent; this.
		_addReference: function( child ) {
			this.children || (this.children = []);
			
			if( child.parent ) throw new Error('Child already has a parent');
			child.parent = this;
			this.children.push(child);
			
			return this;
		},
		_removeReference: function( child ) {
			var index;
			if(
				!this.children ||
				child.parent != this ||
				(index = this.children.indexOf(child)) < 0
			) {
				return;
			}
			child.parent = null;
			this.children.splice(index, 1);
			
			return this;
		},
		
		_initTemplate: function( name, fragmentNodes ) {
			var match    = this._findTemplateInFragment(name, fragmentNodes)
			  , ref      = this._findTemplateReference(match)
			  , fragment = this._createFragment(ref || match);
			
			return {
				original: match,
				ref:      ref,
				fragment: fragment,
				// Array of HTML elements that are added to the DOM. These come
				// from the template's DocumentFragment, but since that is emptied
				// when it's added to the DOM, we store its `children` in this
				// static array.
				fragmentNodes: Array.prototype.slice.call(fragment.childNodes)
			};
		},
		
		_findTemplateInFragment: function( name, fragmentNodes ) {
			if( !fragmentNodes ) {
				fragmentNodes = this.parent && this.parent.template ?
				                this.parent.template.fragmentNodes :
				                [document.body];
			}
			
			var match;
			fragmentNodes.some(function find( el ) {
				if( !el.querySelectorAll ) return;
				
				var templates = Template.queryForTemplates(el, name);
				if( templates.length > 1 ) {
					throw new Error('Template block not unique');
				}
				match = templates[0];
				return !!match;
			});
			if( !match ) throw new Error('No matching template found');
			
			return match;
		},
		_findTemplateReference: function( template ) {
			var path = template.getAttribute('data-ref');
			if( path ) {
				var ref = Template.getReference(path);
				if( !ref ) throw new Error('Block not found: '+path);
				return ref.template;
			} else {
				return null;
			}
		},
		
		_createFragment: function( template ) {
			var fragment = document.createDocumentFragment()
			  , source   = _supportsTemplate ?
						         template.content :
						         template;
						       
			// Create a fresh fragment clone, which is passed to `render`.
			Array.prototype.forEach.call(source.childNodes, function( childNode ) {
				var clone = childNode.cloneNode(true);
				// Set `data-clone`, only on elements containing children.
				if( clone.setAttribute && clone.childNodes.length )
					clone.setAttribute('data-clone', 'true');
				fragment.appendChild(clone);
			});
			
			return fragment;
		}
	};
	Block.define = _define;
	Block.extend = _extend;
	
	var Template = exports.Template = new (Block.extend({
		_tree:       undefined,
		childBlocks: {},
		
		initialize: function() {},
		
		define: function( name, Parent, protoProps ) {
			if( this.childBlocks[name] ) {
				throw new Error('Block already defined');
			}
			return this.childBlocks[name] = _createChildBlock(name, Parent, protoProps);
		},
		// Performance optimization: pull the original templates out of the DOM,
		// and replace them with empty <template ref/> elements. Not doing this
		// would cost more memory since nested templates get cloned every time
		// its parent is `add`ed.
		add: function() {
			if( !this._tree ) Template._processTemplates();
			return this.constructor.__super__.add.apply(this, arguments);
		},
		out: function( template, how ) {
			if( !template || !template.original ) {
				throw new Error('Template not found!');
			}<commit_msg>Template: Moved `initialize` content to `constructor`<commit_after>

(function( exports ) {
	var _supportsTemplate = 'content' in document.createElement('template');
	
	function _define( name, Parent, protoProps ) {
		// `childBlocks` has to be created here — creating it in the `Block` prototype
		// would make it static. Creating it in `initialize` would create an empty
		// children object every time this block is added to the DOM, losing the link
		// with its children which is just created once upon defining the block.
		this.prototype.childBlocks || (this.prototype.childBlocks = {});
		if( this.prototype.childBlocks[name] ) {
			throw new Error('Block already defined');
		}
		
		return this.prototype.childBlocks[name] =
		       _createChildBlock(name, Parent, protoProps);
	}
	function _extend( protoProps, staticProps ) {
		return _.inherit(this, {
			prototype: protoProps || {},
			static:    staticProps
		});
	}
	function _createChildBlock( name, Parent, protoProps ) {
		if( !Parent ) {
			protoProps = {};
			Parent     = Block;
		} else if( Parent.constructor == Object ) {
			protoProps = Parent;
			Parent     = Block;
		}
		protoProps || (protoProps = {});
		var ChildBlock = Parent.extend(protoProps);
		
		if( ChildBlock.prototype.name ) {
			throw new Error('Illegal block definition');
		}
		ChildBlock.prototype.name = name;
		
		return ChildBlock;
	}
	
	// * `connect` is true when a block is initialized via `add`.
	// * `connect` is false when intitialized via `give`.
	var Block = exports.Block = function( config, parent, connect ) {
		this.config   = config;
		this.parent   = connect ?
		                parent._addReference(this) :
		                parent;
		this.template = this._initTemplate(this.name);
		
		this.initialize();
		this._renderSelf();
	};
	Block.prototype = {
		constructor: Block,
		
		// Static propertes
		// ----------------
		// These properties remain the same for all instances.
		// 
		name:        undefined,
		// Object with references to child Block classes. This is the
		// logic part of the template tree.
		childBlocks: undefined,
		
		// Instance properties
		// -------------------
		// These properties get set upon instantiation.
		// 
		// Reference to parent instance.
		parent:      undefined,
		// An array with references to added children.
		children:    undefined,
		// Config for rendering this block (and optional children).
		config:      undefined,
		// Reference to the correct template object. This object is used
		// to be able to insert parsed HTML *before it*. It also tries to keep
		// track of which DOM elements belong to this block, so they can be removed
		// from the DOM when this block is removed.
		template:    undefined,
		
		destroy: function() {
			this.children && this.children.forEach(function( child ) {
				child.destroy();
			});
			
			this.remove();
			this.parent._removeReference(this);
			
			if( !this.template ) return;
			// Doesn't work on text-only templates.
			this.template.fragmentNodes.forEach(function( partial ) {
				partial.parentNode.removeChild(partial);
			});
			
			this.children = null;
			this.config   = null;
			this.template = null;
		},
		create: function( blockName, config, connect ) {
			var blockClass = this.childBlocks && this.childBlocks[blockName];
			if( blockClass ) {
				return new blockClass(config, this, !!connect);
			} else {
				return null;
			}
		},
		// Add child block.
		// `how` determines where to place the new block. See `Template.out`
		// to find out what the possible values are, and what they do.
		add: function( blockName, config, how ) {
			var child    = this.create(blockName, config, true)
			  , template = child ?
			               child.template :
			               this._renderPlainChild(blockName);
			Template.out(template, how);
			return child;
		},
		before:  function( blockName, config ) { return this.add(blockName, config, 'before') },
		after:   function( blockName, config ) { return this.add(blockName, config, 'after') },
		prepend: function( blockName, config ) { return this.add(blockName, config, 'prepend') },
		append:  function( blockName, config ) { return this.add(blockName, config, 'append') },
		// Give the template of a child block. Its content will not be
		// appended to the DOM.
		give: function( blockName, config ) {
			var child    = this.create(blockName, config, false)
			  , template = child ?
			               child.template :
			               this._renderPlainChild(blockName);
			return template;
		},
		
		// Overridable methods
		// -------------------
		// A Block subclass can override these methods to implement custom render logic.
		// 
		initialize:       function() {},
		// For replacing variables in the rendered HTML.
		replaceVariables: function() {},
		// For manipulating the DOM structure.
		render:           function() {},
		// When this block is removed, undo things you did in render here.
		remove:           function() {},
		
		
		// Render methods
		// --------------
		_renderSelf: function() {
			// Render the current block and attach it to the DOM.
			this.render();
			this.replaceVariables(this.template.fragment);
		},
		_renderPlainChild: function( name ) {
			var childTemplate = this._initTemplate(name, this.template && this.template.fragmentNodes);
			if( childTemplate ) {
				this.replaceVariables(childTemplate.fragment);
			}
			
			return childTemplate;
		},
		
		// Utility methods
		// ---------------
		// 
		// `_addReference` and `_removeReference` connect a child blocks to
		// its parent; this.
		_addReference: function( child ) {
			this.children || (this.children = []);
			
			if( child.parent ) throw new Error('Child already has a parent');
			child.parent = this;
			this.children.push(child);
			
			return this;
		},
		_removeReference: function( child ) {
			var index;
			if(
				!this.children ||
				child.parent != this ||
				(index = this.children.indexOf(child)) < 0
			) {
				return;
			}
			child.parent = null;
			this.children.splice(index, 1);
			
			return this;
		},
		
		_initTemplate: function( name, fragmentNodes ) {
			var match    = this._findTemplateInFragment(name, fragmentNodes)
			  , ref      = this._findTemplateReference(match)
			  , fragment = this._createFragment(ref || match);
			
			return {
				original: match,
				ref:      ref,
				fragment: fragment,
				// Array of HTML elements that are added to the DOM. These come
				// from the template's DocumentFragment, but since that is emptied
				// when it's added to the DOM, we store its `children` in this
				// static array.
				fragmentNodes: Array.prototype.slice.call(fragment.childNodes)
			};
		},
		
		_findTemplateInFragment: function( name, fragmentNodes ) {
			if( !fragmentNodes ) {
				fragmentNodes = this.parent && this.parent.template ?
				                this.parent.template.fragmentNodes :
				                [document.body];
			}
			
			var match;
			fragmentNodes.some(function find( el ) {
				if( !el.querySelectorAll ) return;
				
				var templates = Template.queryForTemplates(el, name);
				if( templates.length > 1 ) {
					throw new Error('Template block not unique');
				}
				match = templates[0];
				return !!match;
			});
			if( !match ) throw new Error('No matching template found');
			
			return match;
		},
		_findTemplateReference: function( template ) {
			var path = template.getAttribute('data-ref');
			if( path ) {
				var ref = Template.getReference(path);
				if( !ref ) throw new Error('Block not found: '+path);
				return ref.template;
			} else {
				return null;
			}
		},
		
		_createFragment: function( template ) {
			var fragment = document.createDocumentFragment()
			  , source   = _supportsTemplate ?
						         template.content :
						         template;
						       
			// Create a fresh fragment clone, which is passed to `render`.
			Array.prototype.forEach.call(source.childNodes, function( childNode ) {
				var clone = childNode.cloneNode(true);
				// Set `data-clone`, only on elements containing children.
				if( clone.setAttribute && clone.childNodes.length )
					clone.setAttribute('data-clone', 'true');
				fragment.appendChild(clone);
			});
			
			return fragment;
		}
	};
	Block.define = _define;
	Block.extend = _extend;
	
	var Template = exports.Template = new (Block.extend({
		_tree:       undefined,
		childBlocks: {},
		
		constructor: function() {},
		
		define: function( name, Parent, protoProps ) {
			if( this.childBlocks[name] ) {
				throw new Error('Block already defined');
			}
			return this.childBlocks[name] = _createChildBlock(name, Parent, protoProps);
		},
		// Performance optimization: pull the original templates out of the DOM,
		// and replace them with empty <template ref/> elements. Not doing this
		// would cost more memory since nested templates get cloned every time
		// its parent is `add`ed.
		add: function() {
			if( !this._tree ) Template._processTemplates();
			return this.constructor.__super__.add.apply(this, arguments);
		},
		out: function( template, how ) {
			if( !template || !template.original ) {
				throw new Error('Template not found!');
			}
{'fraction_non_alphanumeric': 0.12140866209262435, 'fraction_numerical': 0.0004288164665523156, 'mean_word_length': 2.669748229740362, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, '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': '4353046', 'n_tokens_mistral': 6227, 'n_tokens_neox': 5141, 'n_words': 1648}