with | elements to determine column count."
				);
				$row = $(" | |
");
				for (i = 0; i < tree.columnCount; i++) {
					$row.append("");
				}
			}
			$row.find(">td")
				.eq(tableOpts.nodeColumnIdx)
				.html("");
			if (opts.aria) {
				$row.attr("role", "row");
				$row.find("td").attr("role", "gridcell");
			}
			tree.rowFragment = document.createDocumentFragment();
			tree.rowFragment.appendChild($row.get(0));
			// // If tbody contains a second row, use this as status node template
			// $row = $tbody.children("tr").eq(1);
			// if( $row.length === 0 ) {
			// 	tree.statusRowFragment = tree.rowFragment;
			// } else {
			// 	$row = $row.clone();
			// 	tree.statusRowFragment = document.createDocumentFragment();
			// 	tree.statusRowFragment.appendChild($row.get(0));
			// }
			//
			$tbody.empty();
			// Make sure that status classes are set on the node's |  elements
			tree.statusClassPropName = "tr";
			tree.ariaPropName = "tr";
			this.nodeContainerAttrName = "tr";
			// #489: make sure $container is set to , even if ext-dnd is listed before ext-table
			tree.$container = $table;
			this._superApply(arguments);
			// standard Fancytree created a root UL
			$(tree.rootNode.ul).remove();
			tree.rootNode.ul = null;
			// Add container to the TAB chain
			// #577: Allow to set tabindex to "0", "-1" and ""
			this.$container.attr("tabindex", opts.tabindex);
			// this.$container.attr("tabindex", opts.tabbable ? "0" : "-1");
			if (opts.aria) {
				tree.$container
					.attr("role", "treegrid")
					.attr("aria-readonly", true);
			}
		},
		nodeRemoveChildMarkup: function(ctx) {
			var node = ctx.node;
			//		node.debug("nodeRemoveChildMarkup()");
			node.visit(function(n) {
				if (n.tr) {
					$(n.tr).remove();
					n.tr = null;
				}
			});
		},
		nodeRemoveMarkup: function(ctx) {
			var node = ctx.node;
			//		node.debug("nodeRemoveMarkup()");
			if (node.tr) {
				$(node.tr).remove();
				node.tr = null;
			}
			this.nodeRemoveChildMarkup(ctx);
		},
		/* Override standard render. */
		nodeRender: function(ctx, force, deep, collapsed, _recursive) {
			var children,
				firstTr,
				i,
				l,
				newRow,
				prevNode,
				prevTr,
				subCtx,
				tree = ctx.tree,
				node = ctx.node,
				opts = ctx.options,
				isRootNode = !node.parent;
			if (tree._enableUpdate === false) {
				// $.ui.fancytree.debug("*** nodeRender _enableUpdate: false");
				return;
			}
			if (!_recursive) {
				ctx.hasCollapsedParents = node.parent && !node.parent.expanded;
			}
			// $.ui.fancytree.debug("*** nodeRender " + node + ", isRoot=" + isRootNode, "tr=" + node.tr, "hcp=" + ctx.hasCollapsedParents, "parent.tr=" + (node.parent && node.parent.tr));
			if (!isRootNode) {
				if (node.tr && force) {
					this.nodeRemoveMarkup(ctx);
				}
				if (node.tr) {
					if (force) {
						// Set icon, link, and title (normally this is only required on initial render)
						this.nodeRenderTitle(ctx); // triggers renderColumns()
					} else {
						// Update element classes according to node state
						this.nodeRenderStatus(ctx);
					}
				} else {
					if (ctx.hasCollapsedParents && !deep) {
						// #166: we assume that the parent will be (recursively) rendered
						// later anyway.
						// node.debug("nodeRender ignored due to unrendered parent");
						return;
					}
					// Create new  after previous row
					// if( node.isStatusNode() ) {
					// 	newRow = tree.statusRowFragment.firstChild.cloneNode(true);
					// } else {
					newRow = tree.rowFragment.firstChild.cloneNode(true);
					// }
					prevNode = findPrevRowNode(node);
					// $.ui.fancytree.debug("*** nodeRender " + node + ": prev: " + prevNode.key);
					_assert(prevNode);
					if (collapsed === true && _recursive) {
						// hide all child rows, so we can use an animation to show it later
						newRow.style.display = "none";
					} else if (deep && ctx.hasCollapsedParents) {
						// also hide this row if deep === true but any parent is collapsed
						newRow.style.display = "none";
						//					newRow.style.color = "red";
					}
					if (prevNode.tr) {
						insertSiblingAfter(prevNode.tr, newRow);
					} else {
						_assert(
							!prevNode.parent,
							"prev. row must have a tr, or be system root"
						);
						// tree.tbody.appendChild(newRow);
						insertFirstChild(tree.tbody, newRow); // #675
					}
					node.tr = newRow;
					if (node.key && opts.generateIds) {
						node.tr.id = opts.idPrefix + node.key;
					}
					node.tr.ftnode = node;
					// if(opts.aria){
					// 	$(node.tr).attr("aria-labelledby", "ftal_" + opts.idPrefix + node.key);
					// }
					node.span = $("span.fancytree-node", node.tr).get(0);
					// Set icon, link, and title (normally this is only required on initial render)
					this.nodeRenderTitle(ctx);
					// Allow tweaking, binding, after node was created for the first time
					//				tree._triggerNodeEvent("createNode", ctx);
					if (opts.createNode) {
						opts.createNode.call(tree, { type: "createNode" }, ctx);
					}
				}
			}
			// Allow tweaking after node state was rendered
			//		tree._triggerNodeEvent("renderNode", ctx);
			if (opts.renderNode) {
				opts.renderNode.call(tree, { type: "renderNode" }, ctx);
			}
			// Visit child nodes
			// Add child markup
			children = node.children;
			if (children && (isRootNode || deep || node.expanded)) {
				for (i = 0, l = children.length; i < l; i++) {
					subCtx = $.extend({}, ctx, { node: children[i] });
					subCtx.hasCollapsedParents =
						subCtx.hasCollapsedParents || !node.expanded;
					this.nodeRender(subCtx, force, deep, collapsed, true);
				}
			}
			// Make sure, that 
 order matches node.children order.
			if (children && !_recursive) {
				// we only have to do it once, for the root branch
				prevTr = node.tr || null;
				firstTr = tree.tbody.firstChild;
				// Iterate over all descendants
				node.visit(function(n) {
					if (n.tr) {
						if (
							!n.parent.expanded &&
							n.tr.style.display !== "none"
						) {
							// fix after a node was dropped over a collapsed
							n.tr.style.display = "none";
							setChildRowVisibility(n, false);
						}
						if (n.tr.previousSibling !== prevTr) {
							node.debug("_fixOrder: mismatch at node: " + n);
							var nextTr = prevTr ? prevTr.nextSibling : firstTr;
							tree.tbody.insertBefore(n.tr, nextTr);
						}
						prevTr = n.tr;
					}
				});
			}
			// Update element classes according to node state
			// if(!isRootNode){
			// 	this.nodeRenderStatus(ctx);
			// }
		},
		nodeRenderTitle: function(ctx, title) {
			var $cb,
				res,
				tree = ctx.tree,
				node = ctx.node,
				opts = ctx.options,
				isStatusNode = node.isStatusNode();
			res = this._super(ctx, title);
			if (node.isRootNode()) {
				return res;
			}
			// Move checkbox to custom column
			if (
				opts.checkbox &&
				!isStatusNode &&
				opts.table.checkboxColumnIdx != null
			) {
				$cb = $("span.fancytree-checkbox", node.span); //.detach();
				$(node.tr)
					.find("td")
					.eq(+opts.table.checkboxColumnIdx)
					.html($cb);
			}
			// Update element classes according to node state
			this.nodeRenderStatus(ctx);
			if (isStatusNode) {
				if (opts.renderStatusColumns) {
					// Let user code write column content
					opts.renderStatusColumns.call(
						tree,
						{ type: "renderStatusColumns" },
						ctx
					);
				} else if (opts.table.mergeStatusColumns && node.isTopLevel()) {
					$(node.tr)
						.find(">td")
						.eq(0)
						.prop("colspan", tree.columnCount)
						.text(node.title)
						.addClass("fancytree-status-merged")
						.nextAll()
						.remove();
				} // else: default rendering for status node: leave other cells empty
			} else if (opts.renderColumns) {
				opts.renderColumns.call(tree, { type: "renderColumns" }, ctx);
			}
			return res;
		},
		nodeRenderStatus: function(ctx) {
			var indent,
				node = ctx.node,
				opts = ctx.options;
			this._super(ctx);
			$(node.tr).removeClass("fancytree-node");
			// indent
			indent = (node.getLevel() - 1) * opts.table.indentation;
			if (opts.rtl) {
				$(node.span).css({ paddingRight: indent + "px" });
			} else {
				$(node.span).css({ paddingLeft: indent + "px" });
			}
		},
		/* Expand node, return Deferred.promise. */
		nodeSetExpanded: function(ctx, flag, callOpts) {
			// flag defaults to true
			flag = flag !== false;
			if ((ctx.node.expanded && flag) || (!ctx.node.expanded && !flag)) {
				// Expanded state isn't changed - just call base implementation
				return this._superApply(arguments);
			}
			var dfd = new $.Deferred(),
				subOpts = $.extend({}, callOpts, {
					noEvents: true,
					noAnimation: true,
				});
			callOpts = callOpts || {};
			function _afterExpand(ok) {
				setChildRowVisibility(ctx.node, flag);
				if (ok) {
					if (
						flag &&
						ctx.options.autoScroll &&
						!callOpts.noAnimation &&
						ctx.node.hasChildren()
					) {
						// Scroll down to last child, but keep current node visible
						ctx.node
							.getLastChild()
							.scrollIntoView(true, { topNode: ctx.node })
							.always(function() {
								if (!callOpts.noEvents) {
									ctx.tree._triggerNodeEvent(
										flag ? "expand" : "collapse",
										ctx
									);
								}
								dfd.resolveWith(ctx.node);
							});
					} else {
						if (!callOpts.noEvents) {
							ctx.tree._triggerNodeEvent(
								flag ? "expand" : "collapse",
								ctx
							);
						}
						dfd.resolveWith(ctx.node);
					}
				} else {
					if (!callOpts.noEvents) {
						ctx.tree._triggerNodeEvent(
							flag ? "expand" : "collapse",
							ctx
						);
					}
					dfd.rejectWith(ctx.node);
				}
			}
			// Call base-expand with disabled events and animation
			this._super(ctx, flag, subOpts)
				.done(function() {
					_afterExpand(true);
				})
				.fail(function() {
					_afterExpand(false);
				});
			return dfd.promise();
		},
		nodeSetStatus: function(ctx, status, message, details) {
			if (status === "ok") {
				var node = ctx.node,
					firstChild = node.children ? node.children[0] : null;
				if (firstChild && firstChild.isStatusNode()) {
					$(firstChild.tr).remove();
				}
			}
			return this._superApply(arguments);
		},
		treeClear: function(ctx) {
			this.nodeRemoveChildMarkup(this._makeHookContext(this.rootNode));
			return this._superApply(arguments);
		},
		treeDestroy: function(ctx) {
			this.$container.find("tbody").empty();
			if (this.$source) {
				this.$source.removeClass("fancytree-helper-hidden");
			}
			return this._superApply(arguments);
		},
		/*,
	treeSetFocus: function(ctx, flag) {
//	        alert("treeSetFocus" + ctx.tree.$container);
		ctx.tree.$container.focus();
		$.ui.fancytree.focusTree = ctx.tree;
	}*/
	});
	// Value returned by `require('jquery.fancytree..')`
	return $.ui.fancytree;
}); // End of closure
/*! Extension 'jquery.fancytree.themeroller.js' *//*!
 * jquery.fancytree.themeroller.js
 *
 * Enable jQuery UI ThemeRoller styles.
 * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
 *
 * @see http://jqueryui.com/themeroller/
 *
 * Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
 *
 * Released under the MIT license
 * https://github.com/mar10/fancytree/wiki/LicenseInfo
 *
 * @version 2.38.0
 * @date 2021-02-09T20:03:49Z
 */
(function(factory) {
	if (typeof define === "function" && define.amd) {
		// AMD. Register as an anonymous module.
		define(["jquery", "./jquery.fancytree"], factory);
	} else if (typeof module === "object" && module.exports) {
		// Node/CommonJS
		require("./jquery.fancytree");
		module.exports = factory(require("jquery"));
	} else {
		// Browser globals
		factory(jQuery);
	}
})(function($) {
	"use strict";
	/*******************************************************************************
	 * Extension code
	 */
	$.ui.fancytree.registerExtension({
		name: "themeroller",
		version: "2.38.0",
		// Default options for this extension.
		options: {
			activeClass: "ui-state-active", // Class added to active node
			// activeClass: "ui-state-highlight",
			addClass: "ui-corner-all", // Class added to all nodes
			focusClass: "ui-state-focus", // Class added to focused node
			hoverClass: "ui-state-hover", // Class added to hovered node
			selectedClass: "ui-state-highlight", // Class added to selected nodes
			// selectedClass: "ui-state-active"
		},
		treeInit: function(ctx) {
			var $el = ctx.widget.element,
				opts = ctx.options.themeroller;
			this._superApply(arguments);
			if ($el[0].nodeName === "TABLE") {
				$el.addClass("ui-widget ui-corner-all");
				$el.find(">thead tr").addClass("ui-widget-header");
				$el.find(">tbody").addClass("ui-widget-conent");
			} else {
				$el.addClass("ui-widget ui-widget-content ui-corner-all");
			}
			$el.on("mouseenter mouseleave", ".fancytree-node", function(event) {
				var node = $.ui.fancytree.getNode(event.target),
					flag = event.type === "mouseenter";
				$(node.tr ? node.tr : node.span).toggleClass(
					opts.hoverClass + " " + opts.addClass,
					flag
				);
			});
		},
		treeDestroy: function(ctx) {
			this._superApply(arguments);
			ctx.widget.element.removeClass(
				"ui-widget ui-widget-content ui-corner-all"
			);
		},
		nodeRenderStatus: function(ctx) {
			var classes = {},
				node = ctx.node,
				$el = $(node.tr ? node.tr : node.span),
				opts = ctx.options.themeroller;
			this._super(ctx);
			/*
		.ui-state-highlight: Class to be applied to highlighted or selected elements. Applies "highlight" container styles to an element and its child text, links, and icons.
		.ui-state-error: Class to be applied to error messaging container elements. Applies "error" container styles to an element and its child text, links, and icons.
		.ui-state-error-text: An additional class that applies just the error text color without background. Can be used on form labels for instance. Also applies error icon color to child icons.
		.ui-state-default: Class to be applied to clickable button-like elements. Applies "clickable default" container styles to an element and its child text, links, and icons.
		.ui-state-hover: Class to be applied on mouseover to clickable button-like elements. Applies "clickable hover" container styles to an element and its child text, links, and icons.
		.ui-state-focus: Class to be applied on keyboard focus to clickable button-like elements. Applies "clickable hover" container styles to an element and its child text, links, and icons.
		.ui-state-active: Class to be applied on mousedown to clickable button-like elements. Applies "clickable active" container styles to an element and its child text, links, and icons.
*/
			// Set ui-state-* class (handle the case that the same class is assigned
			// to different states)
			classes[opts.activeClass] = false;
			classes[opts.focusClass] = false;
			classes[opts.selectedClass] = false;
			if (node.isActive()) {
				classes[opts.activeClass] = true;
			}
			if (node.hasFocus()) {
				classes[opts.focusClass] = true;
			}
			// activeClass takes precedence before selectedClass:
			if (node.isSelected() && !node.isActive()) {
				classes[opts.selectedClass] = true;
			}
			$el.toggleClass(opts.activeClass, classes[opts.activeClass]);
			$el.toggleClass(opts.focusClass, classes[opts.focusClass]);
			$el.toggleClass(opts.selectedClass, classes[opts.selectedClass]);
			// Additional classes (e.g. 'ui-corner-all')
			$el.addClass(opts.addClass);
		},
	});
	// Value returned by `require('jquery.fancytree..')`
	return $.ui.fancytree;
}); // End of closure
/*! Extension 'jquery.fancytree.wide.js' *//*!
 * jquery.fancytree.wide.js
 * Support for 100% wide selection bars.
 * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
 *
 * Copyright (c) 2008-2021, Martin Wendt (https://wwWendt.de)
 *
 * Released under the MIT license
 * https://github.com/mar10/fancytree/wiki/LicenseInfo
 *
 * @version 2.38.0
 * @date 2021-02-09T20:03:49Z
 */
(function(factory) {
	if (typeof define === "function" && define.amd) {
		// AMD. Register as an anonymous module.
		define(["jquery", "./jquery.fancytree"], factory);
	} else if (typeof module === "object" && module.exports) {
		// Node/CommonJS
		require("./jquery.fancytree");
		module.exports = factory(require("jquery"));
	} else {
		// Browser globals
		factory(jQuery);
	}
})(function($) {
	"use strict";
	var reNumUnit = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/; // split "1.5em" to ["1.5", "em"]
	/*******************************************************************************
	 * Private functions and variables
	 */
	// var _assert = $.ui.fancytree.assert;
	/* Calculate inner width without scrollbar */
	// function realInnerWidth($el) {
	// 	// http://blog.jquery.com/2012/08/16/jquery-1-8-box-sizing-width-csswidth-and-outerwidth/
	// //	inst.contWidth = parseFloat(this.$container.css("width"), 10);
	// 	// 'Client width without scrollbar' - 'padding'
	// 	return $el[0].clientWidth - ($el.innerWidth() -  parseFloat($el.css("width"), 10));
	// }
	/* Create a global embedded CSS style for the tree. */
	function defineHeadStyleElement(id, cssText) {
		id = "fancytree-style-" + id;
		var $headStyle = $("#" + id);
		if (!cssText) {
			$headStyle.remove();
			return null;
		}
		if (!$headStyle.length) {
			$headStyle = $("")
				.attr("id", id)
				.addClass("fancytree-style")
				.prop("type", "text/css")
				.appendTo("head");
		}
		try {
			$headStyle.html(cssText);
		} catch (e) {
			// fix for IE 6-8
			$headStyle[0].styleSheet.cssText = cssText;
		}
		return $headStyle;
	}
	/* Calculate the CSS rules that indent title spans. */
	function renderLevelCss(
		containerId,
		depth,
		levelOfs,
		lineOfs,
		labelOfs,
		measureUnit
	) {
		var i,
			prefix = "#" + containerId + " span.fancytree-level-",
			rules = [];
		for (i = 0; i < depth; i++) {
			rules.push(
				prefix +
					(i + 1) +
					" span.fancytree-title { padding-left: " +
					(i * levelOfs + lineOfs) +
					measureUnit +
					"; }"
			);
		}
		// Some UI animations wrap the UL inside a DIV and set position:relative on both.
		// This breaks the left:0 and padding-left:nn settings of the title
		rules.push(
			"#" +
			containerId +
			" div.ui-effects-wrapper ul li span.fancytree-title, " +
			"#" +
			containerId +
			" li.fancytree-animating span.fancytree-title " + // #716
				"{ padding-left: " +
				labelOfs +
				measureUnit +
				"; position: static; width: auto; }"
		);
		return rules.join("\n");
	}
	// /**
	//  * [ext-wide] Recalculate the width of the selection bar after the tree container
	//  * was resized.
	//  * May be called explicitly on container resize, since there is no resize event
	//  * for DIV tags.
	//  *
	//  * @alias Fancytree#wideUpdate
	//  * @requires jquery.fancytree.wide.js
	//  */
	// $.ui.fancytree._FancytreeClass.prototype.wideUpdate = function(){
	// 	var inst = this.ext.wide,
	// 		prevCw = inst.contWidth,
	// 		prevLo = inst.lineOfs;
	// 	inst.contWidth = realInnerWidth(this.$container);
	// 	// Each title is precceeded by 2 or 3 icons (16px + 3 margin)
	// 	//     + 1px title border and 3px title padding
	// 	// TODO: use code from treeInit() below
	// 	inst.lineOfs = (this.options.checkbox ? 3 : 2) * 19;
	// 	if( prevCw !== inst.contWidth || prevLo !== inst.lineOfs ) {
	// 		this.debug("wideUpdate: " + inst.contWidth);
	// 		this.visit(function(node){
	// 			node.tree._callHook("nodeRenderTitle", node);
	// 		});
	// 	}
	// };
	/*******************************************************************************
	 * Extension code
	 */
	$.ui.fancytree.registerExtension({
		name: "wide",
		version: "2.38.0",
		// Default options for this extension.
		options: {
			iconWidth: null, // Adjust this if @fancy-icon-width != "16px"
			iconSpacing: null, // Adjust this if @fancy-icon-spacing != "3px"
			labelSpacing: null, // Adjust this if padding between icon and label != "3px"
			levelOfs: null, // Adjust this if ul padding != "16px"
		},
		treeCreate: function(ctx) {
			this._superApply(arguments);
			this.$container.addClass("fancytree-ext-wide");
			var containerId,
				cssText,
				iconSpacingUnit,
				labelSpacingUnit,
				iconWidthUnit,
				levelOfsUnit,
				instOpts = ctx.options.wide,
				// css sniffing
				$dummyLI = $(
					""
				).appendTo(ctx.tree.$container),
				$dummyIcon = $dummyLI.find(".fancytree-icon"),
				$dummyUL = $dummyLI.find("ul"),
				// $dummyTitle = $dummyLI.find(".fancytree-title"),
				iconSpacing =
					instOpts.iconSpacing || $dummyIcon.css("margin-left"),
				iconWidth = instOpts.iconWidth || $dummyIcon.css("width"),
				labelSpacing = instOpts.labelSpacing || "3px",
				levelOfs = instOpts.levelOfs || $dummyUL.css("padding-left");
			$dummyLI.remove();
			iconSpacingUnit = iconSpacing.match(reNumUnit)[2];
			iconSpacing = parseFloat(iconSpacing, 10);
			labelSpacingUnit = labelSpacing.match(reNumUnit)[2];
			labelSpacing = parseFloat(labelSpacing, 10);
			iconWidthUnit = iconWidth.match(reNumUnit)[2];
			iconWidth = parseFloat(iconWidth, 10);
			levelOfsUnit = levelOfs.match(reNumUnit)[2];
			if (
				iconSpacingUnit !== iconWidthUnit ||
				levelOfsUnit !== iconWidthUnit ||
				labelSpacingUnit !== iconWidthUnit
			) {
				$.error(
					"iconWidth, iconSpacing, and levelOfs must have the same css measure unit"
				);
			}
			this._local.measureUnit = iconWidthUnit;
			this._local.levelOfs = parseFloat(levelOfs);
			this._local.lineOfs =
				(1 +
					(ctx.options.checkbox ? 1 : 0) +
					(ctx.options.icon === false ? 0 : 1)) *
					(iconWidth + iconSpacing) +
				iconSpacing;
			this._local.labelOfs = labelSpacing;
			this._local.maxDepth = 10;
			// Get/Set a unique Id on the container (if not already exists)
			containerId = this.$container.uniqueId().attr("id");
			// Generated css rules for some levels (extended on demand)
			cssText = renderLevelCss(
				containerId,
				this._local.maxDepth,
				this._local.levelOfs,
				this._local.lineOfs,
				this._local.labelOfs,
				this._local.measureUnit
			);
			defineHeadStyleElement(containerId, cssText);
		},
		treeDestroy: function(ctx) {
			// Remove generated css rules
			defineHeadStyleElement(this.$container.attr("id"), null);
			return this._superApply(arguments);
		},
		nodeRenderStatus: function(ctx) {
			var containerId,
				cssText,
				res,
				node = ctx.node,
				level = node.getLevel();
			res = this._super(ctx);
			// Generate some more level-n rules if required
			if (level > this._local.maxDepth) {
				containerId = this.$container.attr("id");
				this._local.maxDepth *= 2;
				node.debug(
					"Define global ext-wide css up to level " +
						this._local.maxDepth
				);
				cssText = renderLevelCss(
					containerId,
					this._local.maxDepth,
					this._local.levelOfs,
					this._local.lineOfs,
					this._local.labelSpacing,
					this._local.measureUnit
				);
				defineHeadStyleElement(containerId, cssText);
			}
			// Add level-n class to apply indentation padding.
			// (Setting element style would not work, since it cannot easily be
			// overriden while animations run)
			$(node.span).addClass("fancytree-level-" + level);
			return res;
		},
	});
	// Value returned by `require('jquery.fancytree..')`
	return $.ui.fancytree;
}); // End of closure
// Value returned by `require('jquery.fancytree')`
return $.ui.fancytree;
}));  // End of closure