text:
@implementation BeeUITableViewCell

@dynamic gridCell;

@dynamic cellData;
@dynamic cellLayout;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
	self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
	if ( self )
	{
//		self.backgroundColor = [UIColor clearColor];
		self.selectionStyle = UITableViewCellSelectionStyleNone;
		self.accessoryType = UITableViewCellAccessoryNone;
		self.editingAccessoryType = UITableViewCellAccessoryNone;
		self.showsReorderControl = NO;
		self.shouldIndentWhileEditing = NO;
		self.indentationLevel = 0;
		self.indentationWidth = 0.0f;
		self.alpha = 1.0f;
		self.layer.masksToBounds = YES;
		self.layer.opaque = YES;

		self.contentView.layer.masksToBounds = YES;
		self.contentView.layer.opaque = YES;
		self.contentView.autoresizesSubviews = YES;
	}
	return self;
}

- (BeeUIGridCell *)gridCell
{
	return _gridCell;
}

- (void)setGridCell:(BeeUIGridCell *)gridCell
{
	if ( _gridCell != gridCell )
	{
		[_gridCell release];

		_gridCell = [gridCell retain];
		_gridCell.autoresizesSubviews = YES;
		_gridCell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

		if ( gridCell.superview != self.contentView )
		{
			[gridCell.superview removeFromSuperview];
		}

		[self.contentView addSubview:_gridCell];
	}
}

- (NSObject *)cellData
{
	return _gridCell.cellData;
}

- (void)setCellData:(NSObject *)data
{
	_gridCell.cellData = data;
}

- (NSObject *)cellLayout
{
	return _gridCell.cellLayout;
}

- (void)setCellLayout:(NSObject *)layout
{
	_gridCell.cellLayout = layout;
}

- (void)setFrame:(CGRect)rc
{
	[super setFrame:CGRectZeroNan(rc)];

	[_gridCell setFrame:self.bounds];
//	[_gridCell layoutSubcells];
}

- (void)setCenter:(CGPoint)pt
{
	[super setCenter:pt];

	[_gridCell setFrame:self.bounds];
//	[_gridCell layoutSubcells];
}

// if the cell is reusable (has a reuse identifier),
// this is called just before the cell is returned from the table view method
// dequeueReusableCellWithIdentifier:.  If you override, you MUST call super.
- (void)prepareForReuse
{
	[super prepareForReuse];

	_gridCell.cellData = nil;
}

- (void)willTransitionToState:(UITableViewCellStateMask)state
{
	[super willTransitionToState:state];

	self.showsReorderControl = NO;
	self.shouldIndentWhileEditing = NO;
	self.indentationLevel = 0;
	self.indentationWidth = 0.0f;

	[_gridCell layoutSubcells];
}

- (void)didTransitionToState:(UITableViewCellStateMask)state
{
	[super didTransitionToState:state];

	self.showsReorderControl = NO;
	self.shouldIndentWhileEditing = NO;
	self.indentationLevel = 0;
	self.indentationWidth = 0.0f;

	[_gridCell layoutSubcells];
}

- (void)dealloc
{
	[_gridCell removeFromSuperview];
	[_gridCell release];
	_gridCell = nil;

	[super dealloc];
}

@end

#pragma mark -

@interface BeeUITableBoard(Private)
- (void)disableScrollsToTopPropertyOnAllSubviewsOf:(UIView *)view;
- (void)enableScrollsToTopPropertyOnAllSubviewsOf:(UIView *)view;
- (void)operateReloadData;
- (void)layoutSearchBar:(BOOL)animated;
- (void)layoutTableView:(BOOL)animated;
- (void)layoutViews:(BOOL)animated;
- (void)didSearchMaskHidden;
- (void)syncScrollPosition;
@end

#pragma mark -

@implementation BeeUITableBoard

@synthesize style = _style;
@synthesize reloading = _reloading;
@synthesize updating = _updating;
@synthesize searching = _searching;
@synthesize tableView = _tableView;
@synthesize searchBar = _searchBar;
@synthesize pullLoader = _pullLoader;
@synthesize searchBarStyle = _searchBarStyle;

@synthesize lastScrollPosition = _lastScrollPosition;
@synthesize currentScrollPosition = _currentScrollPosition;

DEF_SIGNAL( RELOADED )				// 数据重新加载
DEF_SIGNAL( PULL_REFRESH )			// 下拉刷新
DEF_SIGNAL( SEARCH_ACTIVE )			// 搜索开始
DEF_SIGNAL( SEARCH_UPDATE )			// 搜索更新
DEF_SIGNAL( SEARCH_DEACTIVE )		// 搜索结束
DEF_SIGNAL( SEARCH_COMMIT )			// 搜索提交
//DEF_SIGNAL( SCROLL_START )			// 滚动开始
//DEF_SIGNAL( SCROLL_UPDATE )			// 滚动更新
//DEF_SIGNAL( SCROLL_STOP )			// 滚动结束
//DEF_SIGNAL( SCROLL_REACH_TOP )		// 触顶
//DEF_SIGNAL( SCROLL_REACH_BOTTOM )	// 触底

DEF_INT( SEARCHBAR_STYLE_BOTTOM,	0 );
DEF_INT( SEARCHBAR_STYLE_TOP,		1 );

- (void)load
{
	_style = UITableViewStylePlain;
	_baseInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);

	_lastScrollPosition = CGPointZero;
	_currentScrollPosition = CGPointZero;

	_searchBarStyle = BeeUITableBoard.SEARCHBAR_STYLE_BOTTOM;
}

- (void)unload
{
	[NSObject cancelPreviousPerformRequestsWithTarget:self];
}

- (BeeUITableViewCell *)dequeueWithContentClass:(Class)clazz
{
	NSString * clazzName = [NSString stringWithUTF8String:class_getName(clazz)];
	BeeUITableViewCell * cell = (BeeUITableViewCell *)[_tableView dequeueReusableCellWithIdentifier:clazzName];
	if ( nil == cell )
	{
		cell = [[[BeeUITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:clazzName] autorelease];
		if ( [clazz isSubclassOfClass:[BeeUIGridCell class]] )
		{
			cell.gridCell = [(BeeUIGridCell *)[[BeeRuntime allocByClass:clazz] init] autorelease];
		}
	}

	return cell;
}

- (BeeUITableViewCell *)dequeueWithContentCell:(BeeUIGridCell *)innerCell
{
	NSString * clazzName = [[innerCell class] description];
	BeeUITableViewCell * cell = (BeeUITableViewCell *)[_tableView dequeueReusableCellWithIdentifier:clazzName];
	if ( nil == cell )
	{
		cell = [[[BeeUITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:clazzName] autorelease];
		cell.gridCell = innerCell;
	}

	return cell;
}

- (BeeUIGridCell *)contentForRowAtIndexPath:(NSIndexPath *)indexPath
{
	BeeUITableViewCell * cell = (BeeUITableViewCell *)[self tableView:self.tableView cellForRowAtIndexPath:indexPath];
	if ( cell )
	{
		return cell.gridCell;
	}

	return nil;
}

- (void)handleUISignal:(BeeUISignal *)signal
{
	[super handleUISignal:signal];

	if ( [signal isKindOf:BeeUIBoard.SIGNAL] )
	{
		if ( [signal is:BeeUIBoard.CREATE_VIEWS] )
		{
			_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:_style];

			if ( _style == UITableViewStylePlain )
			{
				_tableView.backgroundColor = [UIColor clearColor];
			}

			_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
			_tableView.delegate = self;
			_tableView.dataSource = self;
			_tableView.rowHeight = 44;
			_tableView.contentInset = _baseInsets;
//			_tableView.decelerationRate = _tableView.decelerationRate * 0.98f;
			_tableView.showsVerticalScrollIndicator = YES;
			_tableView.showsHorizontalScrollIndicator = NO;
			_tableView.bounces = YES;
//			_tableView.scrollsToTop = YES;
			[self.view addSubview:_tableView];

			_searchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
			_searchBar.delegate = self;
			_searchBar.barStyle = UIBarStyleBlackOpaque;
//			_searchBar.tintColor = [UIColor colorWithRed:242.0f/255.0f green:81.0f/255.0f blue:134.0f/255.0f alpha:1.0f];
			_searchBar.hidden = YES;
			_searchBar.backgroundColor = [UIColor clearColor];
			_searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
			[self.view addSubview:_searchBar];

//			[[_searchBar.subviews objectAtIndex:0] removeFromSuperview];
//			for ( UIView * subview in _searchBar.subviews )
//			{
//				if ( [subview isKindOfClass:NSClassFromString(@"UISearchBarBackground")] )
//				{
//					[subview removeFromSuperview];
//					break;
//				}
//			}

			_pullLoader = [[BeeUIPullLoader spawn] retain];
			_pullLoader.hidden = YES;
			_pullLoader.autoresizingMask = UIViewAutoresizingFlexibleWidth;
			_pullLoader.backgroundColor = [UIColor clearColor];
			[_tableView addSubview:_pullLoader];

			[self layoutViews:NO];

			[self observeNotification:BeeUIKeyboard.SHOWN];
			[self observeNotification:BeeUIKeyboard.HEIGHT_CHANGED];
			[self observeNotification:BeeUIKeyboard.HIDDEN];
		}
		else if ( [signal is:BeeUIBoard.DELETE_VIEWS] )
		{
			[self unobserveAllNotifications];

			SAFE_RELEASE_SUBVIEW( _tableView );
			SAFE_RELEASE_SUBVIEW( _searchBar );
			SAFE_RELEASE_SUBVIEW( _pullLoader );
		}
		else if ( [signal is:BeeUIBoard.LOAD_DATAS] )
		{
			[self asyncReloadData];
		}
		else if ( [signal is:BeeUIBoard.FREE_DATAS] )
		{
		}
		else if ( [signal is:BeeUIBoard.LAYOUT_VIEWS] )
		{
			_tableView.frame = self.viewBound;

			if ( NO == _searchBar.hidden )
			{
				[self layoutSearchBar:NO];
			}

			[self layoutTableView:NO];

//			CGRect searchFrame;
//			searchFrame.origin.x = 0.0f;
//			searchFrame.origin.y = 0.0f; // bounds.size.height - SEARCH_BAR_HEIGHT;
//			searchFrame.size.width = self.view.width;
//			searchFrame.size.height = SEARCH_BAR_HEIGHT;
//			_searchBar.frame = searchFrame;

			CGRect pullFrame;
			pullFrame.origin.x = 0.0f;
			pullFrame.origin.y = - _pullLoader.height;
			pullFrame.size.width = self.view.width;
			pullFrame.size.height = _pullLoader.height;
			_pullLoader.frame = pullFrame;
		}
		else if ( [signal is:BeeUIBoard.WILL_APPEAR] )
		{
			[self layoutViews:YES];
			[self asyncReloadData];

//			[self disableScrollsToTopPropertyOnAllSubviewsOf:_tableView];
		}
		else if ( [signal is:BeeUIBoard.DID_APPEAR] )
		{
			[_tableView flashScrollIndicators];
			[_tableView deselectRowAtIndexPath:[_tableView indexPathForSelectedRow] animated:YES];

//			[self enableScrollsToTopPropertyOnAllSubviewsOf:_tableView];
		}
		else if ( [signal is:BeeUIBoard.WILL_DISAPPEAR] )
		{
		}
		else if ( [signal is:BeeUIBoard.DID_DISAPPEAR] )
		{
		}
	}
}

- (void)handleNotification:(NSNotification *)notification
{
	if ( [notification is:BeeUIKeyboard.HEIGHT_CHANGED] ||
		[notification is:BeeUIKeyboard.SHOWN] ||
		[notification is:BeeUIKeyboard.HIDDEN] )
	{
		if ( NO == _searchBar.hidden )
		{
			[self layoutSearchBar:YES];
			[self layoutTableView:YES];
		}
	}
}

#pragma mark -

- (void)layoutSearchBar:(BOOL)animated
{
	if ( animated )
	{
		// Animate up or down
		[UIView beginAnimations:nil context:nil];
		[UIView setAnimationDuration:[BeeUIKeyboard sharedInstance].animationDuration];
		[UIView setAnimationCurve:[BeeUIKeyboard sharedInstance].animationCurve];
		[UIView setAnimationBeginsFromCurrentState:YES];
	}

	if ( BeeUITableBoard.SEARCHBAR_STYLE_BOTTOM == _searchBarStyle )
	{
		CGRect bounds = self.viewBound;
		CGRect searchFrame;
		searchFrame.origin.x = 0.0f;
		searchFrame.origin.y = bounds.size.height - SEARCH_BAR_HEIGHT;
		searchFrame.size.width = bounds.size.width;
		searchFrame.size.height = SEARCH_BAR_HEIGHT;

		if ( [BeeUIKeyboard sharedInstance].shown )
		{
			searchFrame.origin.y -= [BeeUIKeyboard sharedInstance].height;
		}

		_searchBar.frame = searchFrame;
	}
	else
	{
		CGRect bounds = self.viewBound;
		CGRect searchFrame;
		searchFrame.origin.x = 0.0f;
		searchFrame.origin.y = 0.0f; // bounds.size.height - SEARCH_BAR_HEIGHT;
		searchFrame.size.width = bounds.size.width;
		searchFrame.size.height = SEARCH_BAR_HEIGHT;

		_searchBar.frame = searchFrame;
	}

	if ( animated )
	{
		[UIView commitAnimations];
	}
}

- (void)layoutTableView:(BOOL)animated
{
	if ( animated )
	{
		// Animate up or down
		[UIView beginAnimations:nil context:nil];
		[UIView setAnimationDuration:[BeeUIKeyboard sharedInstance].animationDuration];
		[UIView setAnimationCurve:[BeeUIKeyboard sharedInstance].animationCurve];
		[UIView setAnimationBeginsFromCurrentState:YES];

//		[UIView beginAnimations:nil context:NULL];
//		[UIView setAnimationDuration:0.3f];
//		[UIView setAnimationBeginsFromCurrentState:YES];
	}

	CGRect bounds = self.viewBound;
	CGRect tableFrame;
	tableFrame.origin = CGPointZero;
	tableFrame.size.width = bounds.size.width;
	tableFrame.size.height = bounds.size.height;

	if ( [BeeUIKeyboard sharedInstance].shown )
	{
		tableFrame.size.height -= [BeeUIKeyboard sharedInstance].height;
	}

	if ( NO == _searchBar.hidden )
	{
		tableFrame.size.height -= SEARCH_BAR_HEIGHT;
	}

	_tableView.frame = tableFrame;

	if ( animated )
	{
		[UIView commitAnimations];
	}
}

- (float)getScrollPercent
{
	float height = _tableView.contentSize.height;
	float offset = _tableView.contentOffset.y;
	float percent = (offset / height);

	CC( @"height = %0.2f, offset = %0.2f, percent = %0.2f", height, offset, percent );
	return percent;
}

- (float)getScrollSpeed
{
	float speed = _lastScrollPosition.y - _currentScrollPosition.y;
	float normalizedSpeed = fabsf( fmaxf( -1.0f, fminf( 1.0f, speed / 20.0f ) ) );
	return normalizedSpeed;
}

- (void)setBaseInsets:(UIEdgeInsets)insets
{
	if ( _tableView.tableHeaderView && NO == _tableView.tableHeaderView.hidden )
	{
		insets.top -= 20.0f;
	}

	if ( _tableView.tableFooterView && NO == _tableView.tableFooterView.hidden )
	{
		insets.bottom -= 20.0f;
	}

	_baseInsets = insets;
	_tableView.contentInset = insets;
}

- (UIEdgeInsets)getBaseInsets
{
	return _baseInsets;
}

- (void)reloadData
{
	[self syncReloadData];
}

- (void)syncReloadData
{
	if ( nil == _tableView )
		return;

	_tableView.userInteractionEnabled = NO;

	[self cancelReloadData];
	_reloading = YES;
	[self operateReloadData];

	_tableView.userInteractionEnabled = YES;
}

- (void)updateRowHeights
{
	_updating = YES;
}

- (void)asyncReloadData
{
	if ( NO == _reloading )
	{
		[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(operateReloadData) object:nil];
		[self performSelector:@selector(operateReloadData) withObject:nil afterDelay:0.01f];
		_reloading = YES;
	}
}

- (void)cancelReloadData
{
	if ( YES == _reloading )
	{
		[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(operateReloadData) object:nil];
		_reloading = NO;
	}
}

- (void)operateReloadData
{
	if ( nil == _tableView )
		return;

	if ( YES == _reloading )
	{
		_reloading = NO;

//		if ( _updating )
//		{
//			[_tableView beginUpdates];
//		}

		[_tableView reloadData];

//		if ( _updating )
//		{
//			[_tableView endUpdates];
			_updating = NO;
//		}

		[self sendUISignal:BeeUITableBoard.RELOADED];
	}
}

- (void)showSearchBar:(BOOL)en animated:(BOOL)animated
{
	if ( en )
	{
		_searchBar.hidden = NO;
	}
	else
	{
		_searchBar.hidden = YES;
	}

	[self layoutViews:animated];
}

- (void)showPullLoader:(BOOL)en animated:(BOOL)animated
{
	if ( en )
	{
		_pullLoader.hidden = NO;
	}
	else
	{
		_pullLoader.hidden = YES;
	}

	[self layoutViews:animated];
}

- (void)setPullLoading:(BOOL)en
{
	if ( en )
	{
		if ( BeeUIPullLoader.STATE_LOADING != _pullLoader.state )
		{
			if ( BeeUIPullLoader.STATE_NORMAL == _pullLoader.state )
			{
				_baseInsets = _tableView.contentInset;
			}

			[UIView beginAnimations:nil context:NULL];
			[UIView setAnimationDuration:0.3f];
			UIEdgeInsets insets = _baseInsets;
			insets.top += _pullLoader.bounds.size.height;
			_tableView.contentInset = insets;
			[UIView commitAnimations];

			[_pullLoader changeState:BeeUIPullLoader.STATE_LOADING animated:YES];
		}
	}
	else
	{
		if ( BeeUIPullLoader.STATE_NORMAL != _pullLoader.state )
		{
			[UIView beginAnimations:nil context:NULL];
			[UIView setAnimationDuration:0.3f];
			_tableView.contentInset = _baseInsets;
			[UIView commitAnimations];

			[_pullLoader changeState:BeeUIPullLoader.STATE_NORMAL animated:YES];
		}
	}
}

- (void)scrollToTop:(BOOL)animated
{
	CGPoint offset;
	offset.x = 0.0f;
	offset.y = -1.0f * _baseInsets.top;

	[_tableView setContentOffset:offset animated:animated];
}

- (void)scrollToSection:(NSInteger)index animated:(BOOL)animated
{
	NSInteger rowCount = [self tableView:_tableView numberOfRowsInSection:index];
	if ( rowCount > 0 )
	{
		[_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:index] atScrollPosition:UITableViewScrollPositionMiddle animated:animated];
	}
}

- (void)scrollToSection:(NSInteger)index row:(NSInteger)row animated:(BOOL)animated
{
	NSInteger rowCount = [self tableView:_tableView numberOfRowsInSection:index];
	if ( row < rowCount )
	{
		[_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:index] atScrollPosition:UITableViewScrollPositionMiddle animated:animated];
	}
}

- (void)disableScrollsToTopPropertyOnAllSubviewsOf:(UIView *)view
{
    for ( UIView * subview in view.subviews )
	{
        if ( [subview isKindOfClass:[UIScrollView class]] )
		{
            ((UIScrollView *)subview).scrollsToTop = NO;
        }

        [self disableScrollsToTopPropertyOnAllSubviewsOf:subview];
    }
}

- (void)enableScrollsToTopPropertyOnAllSubviewsOf:(UIView *)view
{
    for ( UIView *subview in view.subviews )
	{
        if ( [subview isKindOfClass:[UIScrollView class]] )
		{
            ((UIScrollView *)subview).scrollsToTop = YES;
        }

        [self enableScrollsToTopPropertyOnAllSubviewsOf:subview];
    }
}

- (UITableViewCell *)visibleFirstCell
{
	NSArray * cells = [self.tableView visibleCells];
	if ( cells && [cells count] > 0 )
	{
		return (UITableViewCell *)[cells objectAtIndex:0];
	}
	else
	{
		return nil;
	}
}

- (UITableViewCell *)visibleLastCell
{
	NSArray * cells = [self.tableView visibleCells];
	if ( cells && [cells count] > 0 )
	{
		return (UITableViewCell *)[cells lastObject];
	}
	else
	{
		return nil;
	}
}

- (NSRange)visibleRange
{
	NSArray * cells = [self.tableView visibleCells];
	if ( cells && [cells count] > 0 )
	{
		UITableViewCell * firstCell = [cells objectAtIndex:0];
		UITableViewCell * lastCell = [cells lastObject];

		NSRange range;

		if ( firstCell == lastCell )
		{
			range.location = [self.tableView indexPathForCell:firstCell].row;
			range.length = 1;
		}
		else
		{
			range.location = [self.tableView indexPathForCell:firstCell].row;
			range.length = [self.tableView indexPathForCell:lastCell].row - range.location + 1;
		}

//		if ( range.location > 0 )
//		{
//			range.location -= 1;
//		}
//
//		range.length += 1;

		return range;
	}
	else
	{
		return NSMakeRange( 0, 0 );
	}
}

- (NSArray *)visibleCells
{
	NSArray * cells = [self.tableView visibleCells];
	if ( cells && [cells count] > 0 )
	{
		return cells;
	}
	else
	{
		return [NSArray array];
	}
}

- (void)layoutViews:(BOOL)animated
{
	if ( animated )
	{
		CGContextRef context = UIGraphicsGetCurrentContext();

		[UIView beginAnimations:nil context:context];
		[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
		[UIView setAnimationDuration:0.3f];
	}

	CGRect bounds = self.viewBound;

	if ( BeeUITableBoard.SEARCHBAR_STYLE_TOP == _searchBarStyle )
	{
		self.tableView.frame = CGRectMake(0, 0, bounds.size.width, bounds.size.height);
	}
	else
	{
		if ( _searchBar.hidden )
		{
			self.tableView.frame = CGRectMake(0, 0, bounds.size.width, bounds.size.height);
		}
		else
		{
			self.tableView.frame = CGRectMake(0, 0, bounds.size.width, bounds.size.height - SEARCH_BAR_HEIGHT);
		}
	}

	if ( animated )
	{
		[UIView commitAnimations];
	}

	[self sendUISignal:BeeUIBoard.LAYOUT_VIEWS];
}

#pragma mark -
#pragma mark UITableViewDelegate

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
//	float normalizedSpeed = [self getScrollSpeed];
//
//	cell.layer.opacity = (normalizedSpeed > 0.0f ? (1.0f - normalizedSpeed) : 1.0f);
//
//	[UIView beginAnimations:nil context:NULL];
//	[UIView setAnimationDuration:0.3f];
//
//	cell.layer.transform = CATransform3DIdentity;
//	cell.layer.opacity = 1.0f;
//
//	[UIView commitAnimations];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
	return 44.0f;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
	return 0.0f;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
	return 0.0f;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
	return nil;
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
	return nil;
}

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
	return indexPath;
}

- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
	return indexPath;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
	[_tableView deselectRowAtIndexPath:[_tableView indexPathForSelectedRow] animated:YES];
}

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
}

#pragma mark -
#pragma mark UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	return [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
	return 1;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
	return nil;
}

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
	return nil;
}

// Controls whether the background is indented while editing.  If not implemented, the default is YES.  This is unrelated to the indentation level below.  This method only applies to grouped style table views.
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
	return NO;
}

- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
	return 0;
}

#pragma mark -
#pragma mark UIScrollViewDelegate Methods

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//	[self sendUISignal:BeeUITableBoard.SCROLL_START];
//	[self sendUISignal:BeeUITableBoard.SCROLL_UPDATE];

	[self syncScrollPosition];
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
//	[self sendUISignal:BeeUITableBoard.SCROLL_UPDATE];

	[self syncScrollPosition];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//	CGFloat offset = scrollView.contentOffset.y + scrollView.contentInset.top;

	if ( scrollView.dragging )
	{
		if ( NO == _pullLoader.hidden && BeeUIPullLoader.STATE_LOADING != _pullLoader.state )
		{
			if ( BeeUIPullLoader.STATE_NORMAL == _pullLoader.state )
			{
				_baseInsets = _tableView.contentInset;
			}

			CGFloat offset = scrollView.contentOffset.y;
			CGFloat boundY = -(_baseInsets.top + 60.0f);

			if ( offset < boundY )
			{
				if ( BeeUIPullLoader.STATE_PULLING != _pullLoader.state )
				{
					[_pullLoader changeState:BeeUIPullLoader.STATE_PULLING animated:YES];
				}
			}
			else if ( offset < 0.0f )
			{
				if ( BeeUIPullLoader.STATE_NORMAL != _pullLoader.state )
				{
					[_pullLoader changeState:BeeUIPullLoader.STATE_NORMAL animated:YES];
				}
			}
		}
	}

	_lastScrollPosition = _currentScrollPosition;
    _currentScrollPosition = [scrollView contentOffset];

//	[self sendUISignal:BeeUITableBoard.SCROLL_UPDATE];
	[self syncScrollPosition];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
	if ( decelerate )
	{
		if ( NO == _pullLoader.hidden && BeeUIPullLoader.STATE_LOADING != _pullLoader.state )
		{
			CGFloat offset = scrollView.contentOffset.y;
			CGFloat boundY = -(_baseInsets.top + 80.0f);

			if ( offset <= boundY )
			{
				if ( BeeUIPullLoader.STATE_LOADING != _pullLoader.state )
				{
					[UIView beginAnimations:nil context:NULL];
					[UIView setAnimationDuration:0.3f];
					UIEdgeInsets insets = _baseInsets;
					insets.top += _pullLoader.bounds.size.height;
					_tableView.contentInset = insets;
					[UIView commitAnimations];

					[_pullLoader changeState:BeeUIPullLoader.STATE_LOADING animated:YES];

					[self sendUISignal:BeeUITableBoard.PULL_REFRESH];
				}
			}
			else
			{
				if ( BeeUIPullLoader.STATE_NORMAL != _pullLoader.state )
				{
					[UIView beginAnimations:nil context:NULL];
					[UIView setAnimationDuration:0.3f];
					_tableView.contentInset = _baseInsets;
					[UIView commitAnimations];

					[_pullLoader changeState:BeeUIPullLoader.STATE_NORMAL animated:YES];
				}
			}
		}
	}

//	[self sendUISignal:BeeUITableBoard.SCROLL_UPDATE];
	[self syncScrollPosition];
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
//	[self sendUISignal:BeeUITableBoard.SCROLL_STOP];
	[self syncScrollPosition];
}

- (void)syncScrollPosition
{
//	CGFloat offset = _tableView.contentOffset.y + _tableView.contentInset.top;
//	CC( @"offset = %f", offset );

//	if ( offset <= _baseInsets.top )
//	{
//		[self sendUISignal:BeeUITableBoard.SCROLL_REACH_TOP];
//		return;
//	}
//
//	CGFloat bottom = _tableView.contentSize.height + _baseInsets.top + _baseInsets.bottom;
//	if ( offset >= bottom )
//	{
//		[self sendUISignal:BeeUITableBoard.SCROLL_REACH_BOTTOM];
//		return;
//	}
}

#pragma mark -
#pragma mark SearchBar delegate

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
	return YES;
}

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
	[self.view bringSubviewToFront:_searchBar];

	_searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
	[_searchBar setShowsCancelButton:YES animated:YES];

	[self layoutSearchBar:YES];
	[self layoutTableView:YES];

//	_searchBar.text = @"";
	_searching = YES;

	[self sendUISignal:BeeUITableBoard.SEARCH_ACTIVE];
	[self searchBar:nil	textDidChange:@""];
}

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
	[self layoutSearchBar:YES];
	[self layoutTableView:YES];

	[self sendUISignal:BeeUITableBoard.SEARCH_DEACTIVE];
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
	[self sendUISignal:BeeUITableBoard.SEARCH_COMMIT];
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
	[_searchBar setShowsCancelButton:NO animated:YES];
	[_searchBar resignFirstResponder];

//	_searchBar.text = @"";
	_searching = NO;

	[self sendUISignal:BeeUITableBoard.SEARCH_DEACTIVE];
	[self syncReloadData];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
	_searching = YES;

	[self sendUISignal:BeeUITableBoard.SEARCH_UPDATE];
	[self syncReloadData];
}

@end


text:
<!DOCTYPE html>

<meta charset="UTF-8">

<link rel="stylesheet" type="text/css" href="style.css"></link>

redpajama_set_name: RedPajamaGithub


text:
package com.intellij.mock;

import com.intellij.lang.Language;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceRegistrar;
import com.intellij.psi.PsiReferenceService;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;

/**
 * @author yole
 */
@Deprecated
public class MockReferenceProvidersRegistry extends ReferenceProvidersRegistry {
  @Override
  public PsiReferenceRegistrar getRegistrar(Language language) {
    return null;
  }

  @Override
  protected PsiReference[] doGetReferencesFromProviders(PsiElement context, PsiReferenceService.Hints hints) {
    return PsiReference.EMPTY_ARRAY;
  }
}


text:
using ModestTree;
using UnityEngine;
using Zenject;

namespace Zenject.Tests.ToGameObject
{
    public class Bar : MonoBehaviour
    {
        [Inject]
        public void Init(Foo foo, Gorp gorp)
        {
            Assert.IsNotNull(gorp);
            Assert.IsNotNull(foo);

            Log.Trace("Received decorated bindings in Bar");
        }
    }
}


text:
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System.Threading.Tasks;

namespace TravelopediaNunitHotelTest
{
    [TestFixture]
    public class EventTest
    {
        private IWebDriver driver;
        private StringBuilder verificationErrors;
        private string baseURL;
        private bool acceptNextAlert = true;

        [SetUp]
        public void SetupTest()
        {
            driver = new FirefoxDriver();
            baseURL = "https://www.katalon.com/";
            verificationErrors = new StringBuilder();
        }

        [TearDown]
        public void TeardownTest()
        {
            try
            {
                driver.Quit();
            }
            catch (Exception)
            {
                // Ignore errors if unable to close the browser
            }
            Assert.AreEqual("", verificationErrors.ToString());
        }

        [Test]
        public void TheEventTest()
        {
            driver.Navigate().GoToUrl("http://traveltoexplore.biz/");

            var timeout = 30000; // in milliseconds
            var wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(timeout));
            wait.Until(d => ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete"));

            driver.FindElement(By.Id("login")).Click();
         //   driver.FindElement(By.Id("MainContent_Email")).Click();
        //    driver.FindElement(By.Id("MainContent_Email")).Clear();
          //  driver.FindElement(By.Id("MainContent_Email")).SendKeys("shrutipuranik0710@gmail.com");
           // driver.FindElement(By.Id("MainContent_Password")).Click();
           // driver.FindElement(By.Id("MainContent_Password")).Clear();
           // driver.FindElement(By.Id("MainContent_Password")).SendKeys("Shruti_07");
           // driver.FindElement(By.Name("ctl00$MainContent$ctl05")).Click();
            driver.FindElement(By.Name("provider")).Click();

            timeout = 90000; // in milliseconds
            wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(timeout));
            wait.Until(ExpectedConditions.ElementIsVisible(By.Id("identifierId")));

            driver.FindElement(By.Id("identifierId")).Clear();
            driver.FindElement(By.Id("identifierId")).SendKeys("shrutipuranik0710" + Keys.Enter);

            timeout = 60000; // in milliseconds
            wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(timeout));
            wait.Until(ExpectedConditions.ElementIsVisible(By.Name("password")));

            driver.FindElement(By.Name("password")).SendKeys("Shruti_07");

            timeout = 60000; // in milliseconds
            wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(timeout));
            wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//div[@id='passwordNext']/div[2]")));

            driver.FindElement(By.XPath("//div[@id='passwordNext']/div[2]")).Click();

            timeout = 60000; // in milliseconds
            wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(timeout));
            wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//li[@id='4']/a/span")));

            driver.FindElement(By.XPath("//li[@id='4']/a/span")).Click();
            driver.FindElement(By.Id("eventLocation")).Click();
            //driver.FindElement(By.XPath("//div[@id='Activities']/span/span/div/span/div/p")).Click();
            driver.FindElement(By.Id("eventLocation")).Clear();

            driver.FindElement(By.Id("eventLocation")).SendKeys("Miami");
            driver.FindElement(By.Id("eventLocation")).SendKeys(Keys.Down);
            driver.FindElement(By.Id("eventLocation")).SendKeys(Keys.Enter);
            driver.FindElement(By.Id("MainContent_btnSearchEvents")).Click();

            timeout = 60000; // in milliseconds
            wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(timeout));
            wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("(//button[@type='button'])[6]")));

            driver.FindElement(By.XPath("(//button[@type='button'])[6]")).Click();
            driver.FindElement(By.XPath("(//button[@type='button'])[6]")).Click();

            driver.Close();
            Assert.Pass("Event Test Passed");
        }
        private bool IsElementPresent(By by)
        {
            try
            {
                driver.FindElement(by);
                return true;
            }
            catch (NoSuchElementException)
            {
                return false;
            }
        }

        private bool IsAlertPresent()
        {
            try
            {
                driver.SwitchTo().Alert();
                return true;
            }
            catch (NoAlertPresentException)
            {
                return false;
            }
        }

        private string CloseAlertAndGetItsText()
        {
            try
            {
                IAlert alert = driver.SwitchTo().Alert();
                string alertText = alert.Text;
                if (acceptNextAlert)
                {
                    alert.Accept();
                }
                else
                {
                    alert.Dismiss();
                }
                return alertText;
            }
            finally
            {
                acceptNextAlert = true;
            }
        }
    }
}


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">

		<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
		<title>HBase 0.94.8 Reference Package org.apache.hadoop.hbase.client.metrics</title>
		<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="style" />

        	org.apache.hadoop.hbase.client.metrics

Classes

            	ScanMetrics


text:
cd $dp/qr/bond_metrics

jar -cvf bond_metrics.jar -C . .project .classpath src doc `find bin/bondmetrics -type f | sed -e 's;^bin;-C bin ;'`
jar tf bond_metrics.jar
gzip bond_metrics.jar
exit


text:
#include "hmi/unsubscribe_button_request.h"

#include <memory>
#include <string>

#include "application_manager/commands/command_request_test.h"
#include "application_manager/mock_application.h"
#include "application_manager/mock_event_dispatcher.h"
#include "application_manager/mock_resume_ctrl.h"
#include "application_manager/resumption/resumption_data_processor.h"

#include "gtest/gtest.h"

namespace test {
namespace components {
namespace commands_test {
namespace hmi_commands_test {
namespace unsubscribe_button_request {

using ::testing::_;
using ::testing::Return;
namespace am = ::application_manager;
namespace strings = am::strings;
using am::commands::RequestToHMI;
using am::event_engine::Event;
using sdl_rpc_plugin::commands::hmi::UnsubscribeButtonRequest;
using ::test::components::application_manager_test::MockApplication;

typedef std::shared_ptr<MockApplication> MockAppPtr;
typedef std::shared_ptr<RequestToHMI> RequestToHMIPtr;
typedef std::shared_ptr<UnsubscribeButtonRequest> UnsubscribeButtonRequestPtr;

namespace {
const uint32_t kCorrelationId = 2u;
const uint32_t kAppId = 1u;
const hmi_apis::Common_ButtonName::eType kButtonName =
    hmi_apis::Common_ButtonName::CUSTOM_BUTTON;
const hmi_apis::FunctionID::eType kFunctionID =
    hmi_apis::FunctionID::Buttons_UnsubscribeButton;
const mobile_apis::ButtonName::eType kMobileCustomButtonName =
    mobile_apis::ButtonName::CUSTOM_BUTTON;
}  // namespace

class HMIUnsubscribeButtonRequestTest
    : public CommandRequestTest<CommandsTestMocks::kIsNice> {
 protected:
  MessageSharedPtr CreateCommandMsg() {
    MessageSharedPtr command_msg(CreateMessage(smart_objects::SmartType_Map));
    (*command_msg)[strings::msg_params][strings::app_id] = kAppId;
    (*command_msg)[strings::msg_params][strings::button_name] = kButtonName;
    (*command_msg)[strings::params][strings::correlation_id] = kCorrelationId;
    (*command_msg)[strings::params][strings::function_id] = kFunctionID;

    return command_msg;
  }

  void InitCommand(const uint32_t& timeout) OVERRIDE {
    mock_app_ = CreateMockApp();
    CommandRequestTest<CommandsTestMocks::kIsNice>::InitCommand(timeout);
    ON_CALL((*mock_app_), hmi_app_id()).WillByDefault(Return(kAppId));
    ON_CALL(app_mngr_, application_by_hmi_app(kAppId))
        .WillByDefault(Return(mock_app_));
    ON_CALL(app_mngr_, application(kAppId)).WillByDefault(Return(mock_app_));
  }

  MockAppPtr mock_app_;
};

TEST_F(HMIUnsubscribeButtonRequestTest, Run_SendRequest_SUCCESS) {
  MessageSharedPtr command_msg = CreateCommandMsg();
  RequestToHMIPtr command(CreateCommand<UnsubscribeButtonRequest>(command_msg));
  EXPECT_CALL(mock_rpc_service_, SendMessageToHMI(command_msg));
  ASSERT_TRUE(command->Init());

  command->Run();
}

TEST_F(HMIUnsubscribeButtonRequestTest,
       onTimeOut_RequestIsExpired_HandleOnTimeout) {
  MessageSharedPtr command_msg = CreateCommandMsg();
  RequestToHMIPtr command(CreateCommand<UnsubscribeButtonRequest>(command_msg));

  resumption_test::MockResumeCtrl mock_resume_ctrl;
  ON_CALL(app_mngr_, resume_controller())
      .WillByDefault(ReturnRef(mock_resume_ctrl));
  EXPECT_CALL(mock_resume_ctrl, HandleOnTimeOut(_, _));

  command->OnTimeOut();
}

TEST_F(HMIUnsubscribeButtonRequestTest,
       OnEvent_SuccessfulResponse_ButtonUnsubscribed) {
  MessageSharedPtr command_msg = CreateCommandMsg();
  UnsubscribeButtonRequestPtr command =
      CreateCommand<UnsubscribeButtonRequest>(command_msg);

  MessageSharedPtr event_msg = CreateCommandMsg();
  (*event_msg)[am::strings::params][am::hmi_response::code] =
      hmi_apis::Common_Result::SUCCESS;
  Event event(kFunctionID);
  event.set_smart_object(*event_msg);

  EXPECT_CALL(*mock_app_, UnsubscribeFromButton(kMobileCustomButtonName))
      .WillOnce(Return(true));

  command->on_event(event);
}

TEST_F(HMIUnsubscribeButtonRequestTest,
       OnEvent_UnsuccessfulResponse_ButtonNotUnsubscribed) {
  MessageSharedPtr command_msg = CreateCommandMsg();
  UnsubscribeButtonRequestPtr command =
      CreateCommand<UnsubscribeButtonRequest>(command_msg);

  MessageSharedPtr event_msg = CreateCommandMsg();
  (*event_msg)[am::strings::params][am::hmi_response::code] =
      hmi_apis::Common_Result::GENERIC_ERROR;
  Event event(kFunctionID);
  event.set_smart_object(*event_msg);

  EXPECT_CALL(*mock_app_, UnsubscribeFromButton(kMobileCustomButtonName))
      .Times(0);

  command->on_event(event);
}

TEST_F(HMIUnsubscribeButtonRequestTest, onEvent_App_NULL) {
  MessageSharedPtr command_msg = CreateCommandMsg();
  UnsubscribeButtonRequestPtr command =
      CreateCommand<UnsubscribeButtonRequest>(command_msg);

  MessageSharedPtr event_msg = CreateCommandMsg();
  (*event_msg)[am::strings::params][am::hmi_response::code] =
      hmi_apis::Common_Result::SUCCESS;

  Event event(kFunctionID);
  event.set_smart_object(*event_msg);

  MockAppPtr mock_app = NULL;
  EXPECT_CALL(app_mngr_, application_by_hmi_app(kAppId))
      .WillOnce(Return(mock_app));

  EXPECT_CALL(*mock_app_, UnsubscribeFromButton(kMobileCustomButtonName))
      .Times(0);

  command->on_event(event);
}

}  // namespace unsubscribe_button_request
}  // namespace hmi_commands_test
}  // namespace commands_test
}  // namespace components
}  // namespace test


text:
var ssr = require("../lib/");
var helpers = require("./helpers");
var assert = require("assert");
var path = require("path");
var through = require("through2");

describe("Using steal.done() in a module", function(){
	this.timeout(10000);

	before(function(){
		this.render = ssr({
			config: "file:" + path.join(__dirname, "tests", "package.json!npm"),
			main: "stealdone/main"
		}, {
			strategy: 'safe',
		});
	});

	it("returns a Promise", function(done){
		var render = this.render;

		var stream = render("/");
		stream.on("error", done);

		stream.pipe(through(function(buffer){
			var html = buffer.toString();
			var node = helpers.dom(html);

			var tn = helpers.find(node, function(node){
				return node.nodeType === 3;
			});

			assert.equal(tn.nodeValue, "object");
			done();
		}));
	});
});


text:
console.log('watermark: Start');

(function() {
  console.log('watermark: Init defaults');
  var defaults = {
        file: 'Owned_Stamp.png',
        xpos: 0,
        ypos: 0,
        xrepeat: 0,
        opacity: 100,
        clickable: false,
        url: "",
        className: 'vjs-watermark'
    },
    extend = function() {
      var args, target, i, object, property;
      args = Array.prototype.slice.call(arguments);
      target = args.shift() || {};
      for (i in args) {
        object = args[i];
        for (property in object) {
          if (object.hasOwnProperty(property)) {
            if (typeof object[property] === 'object') {
              target[property] = extend(target[property], object[property]);
            } else {
              target[property] = object[property];
            }
          }
        }
      }
      return target;
    };

    //! global varible containing reference to the DOM element
    var div;

  /**
   * register the thubmnails plugin
   */
  videojs.plugin('watermark', function(options) {
    console.log('watermark: Register init');

    var settings, video, img, link;
    settings = extend(defaults, options);

    /* Grab the necessary DOM elements */
    video = this.el();

    // create the watermark element
    if (!div) {
        div = document.createElement('div');
        div.className = options.className;
    }
    else {
        //! if div already exists, empty it
        div.innerHTML = '';
    }

    // if text is set, display text
    if (options.text)
        div.textContent = options.text;

    // if img is set, add img
    if (options.file) {
        img = document.createElement('img');
        div.appendChild(img);
        img.src = options.file;
    }

    //img.style.bottom = "0";
    //img.style.right = "0";
    if ((options.ypos === 0) && (options.xpos === 0)) // Top left
    {
      div.style.top = "0";
      div.style.left = "0";
    }
    else if ((options.ypos === 0) && (options.xpos === 100)) // Top right
    {
      div.style.top = "0";
      div.style.right = "0";
    }
    else if ((options.ypos === 100) && (options.xpos === 100)) // Bottom right
    {
      div.style.bottom = "0";
      div.style.right = "0";
    }
    else if ((options.ypos === 100) && (options.xpos === 0)) // Bottom left
    {
      div.style.bottom = "0";
      div.style.left = "0";
    }
    else if ((options.ypos === 50) && (options.xpos === 50)) // Center
    {
      div.style.top = (this.height()/2)+"px";
      div.style.left = (this.width()/2)+"px";
    }
    div.style.opacity = options.opacity;

    //div.style.backgroundImage = "url("+options.file+")";
    //div.style.backgroundPosition.x = options.xpos+"%";
    //div.style.backgroundPosition.y = options.ypos+"%";
    //div.style.backgroundRepeat = options.xrepeat;
    //div.style.opacity = (options.opacity/100);

    //if user wants watermark to be clickable, add anchor elem
    //todo: check if options.url is an actual url?
    if (options.clickable && options.url !== "") {
      link = document.createElement("a");
      link.href = options.url;
      link.target = "_blank";
      link.appendChild(div);
      //add clickable watermark to the player
      video.appendChild(link);
    } else {
      //add normal watermark to the player
      video.appendChild(div);
    }

    //video.oncontextmenu = function(){alert("Hello!");}
    console.log('watermark: Register end');
  });
})();


text:
/////////////////////////////////////////////////////////////////////////////////
//                                                                             //
// AliFemtoPairCutRadialDistanceKKdistT - a pair cut which checks                     //
// for some pair qualities that attempt to identify slit/doubly                //
// reconstructed tracks and also selects pairs based on their separation       //
// at the entrance to the TPC                                                  //
//                                                                             //
/////////////////////////////////////////////////////////////////////////////////
/********************************************************************************
 *
 * Authors: Johanna Gramling, University of Heidelberg, jgramlin@cern.ch
 *          Malgorzata Janik, Warsaw University of Technology, majanik@cern.ch
 *          Lukasz Graczykowski, Warsaw University of Technology, lgraczyk@cern.ch
 *
 ********************************************************************************/

#ifndef AliFemtoPairCutRadialDistanceKKdist_H
#define AliFemtoPairCutRadialDistanceKKdist_H

// do I need these lines ?
//#ifndef StMaker_H
//#include "StMaker.h"
//#endif

#include "AliFemtoPairCut.h"
#include "AliFemtoShareQualityPairCut.h"
#include "AliFemtoPairCutAntiGamma.h"

#include "AliAODInputHandler.h"
#include "AliAnalysisManager.h"

class AliFemtoPairCutRadialDistanceKKdist : public AliFemtoPairCutAntiGamma {
public:
  AliFemtoPairCutRadialDistanceKKdist();
  AliFemtoPairCutRadialDistanceKKdist(const AliFemtoPairCutRadialDistanceKKdist& c);
  virtual ~AliFemtoPairCutRadialDistanceKKdist();
  AliFemtoPairCutRadialDistanceKKdist& operator=(const AliFemtoPairCutRadialDistanceKKdist& c);

  virtual bool Pass(const AliFemtoPair* pair);
  virtual AliFemtoString Report();
  virtual TList *ListSettings();
  virtual AliFemtoPairCut* Clone();
 // void SetPhiStarDifferenceMinimum(double dtpc);
 // void SetEtaDifferenceMinimum(double etpc);
  void SetAverageSeparation(double minrad);
  //void SetMaximumRadius(double maxrad);
  //void SetMagneticFieldSign(int magsign);
 // void SetPhiStarMin(Bool_t);

 protected:
  //Double_t fDPhiStarMin;          // Minimum allowed pair separation //at the specified radius
  //Double_t fRadius;           // Radius at which the separation is calculated
  //Double_t fEtaMin;           // Minimum allowed pair separation in eta
  Double_t fMinRad;
  //Double_t fMaxRad;
  //Int_t fMagSign;
 // Bool_t fPhistarmin;

#ifdef __ROOT__
  ClassDef(AliFemtoPairCutRadialDistanceKKdist, 0)
#endif
};

inline AliFemtoPairCut* AliFemtoPairCutRadialDistanceKKdist::Clone() { AliFemtoPairCutRadialDistanceKKdist* c = new AliFemtoPairCutRadialDistanceKKdist(*this); return c;}

#endif


text:
const express = require('express')
const app = express()
const AWS = require('aws-sdk');

AWS
  .config
  .update({region: 'us-gov-west-1'});

const s3 = new AWS.S3();

app.use(require('cookie-parser')());
const sessionDecoder = require('rails-session-decoder');

// Use the shared SECRET_KEY_BASE from the env file to setup the Rails session
// decoder.
const decoder = sessionDecoder(process.env.SECRET_KEY_BASE);
const sessionCookieName = '_caseflow_session';

// Setup a middleware to decode the Rails session cookie. Whenever "_caseflow_session"
// is present, it will be decoded.
app.use(function (req, res, next) {
  if (req.cookies && req.cookies[sessionCookieName]) {
    decoder
      .decodeCookie(req.cookies[sessionCookieName], function (err, sessionData) {
        req.cookies[sessionCookieName] = JSON.parse(sessionData);
        next(err);
      });
  } else {
    next();
  }
});

// stream-download re-check user's authority from its session, and pipe
// the request directly to S3 if the user is authorized for this download.
app.get('/stream-download/:filename', function (req, res) {
  const session = req.cookies[sessionCookieName];
  if (!session || !session.user || !session.user.roles || session.user.roles.indexOf('Download efolder') != -1) {
    return res
      .status(403)
      .send('not authorized');
  }

  s3
    .getObject({Bucket: process.env.AWS_BUCKET_NAME, Key: req.params.filename })
    .on('httpHeaders', function (statusCode, headers) {
      res.set('Content-Length', headers['content-length']);
      res.set('Content-Type', headers['content-type']);
      this
        .response
        .httpResponse
        .createUnbufferedStream()
        .pipe(res);
    })
    .send();
})

// Nginx is expected to proxy /stream-download to port 3002.
app.listen(3002, function () {
  console.log('listening on 3002')
})


text:
(function(){

'use strict';

angular.module('myApp.box5', [])

.config(['$stateProvider', function($stateProvider) {
  $stateProvider
  .state('box5', {
    url: '/box5',
    templateUrl: 'sandbox/box5/box5.html',
    controller: 'Box5Ctrl'
  })
.state('box5.sports', {
  abstract: true,
  url: '/sports/{sportId:int}'
})
  .state('box5.sports.home', {
    url: '/home'
  })
  .state('box5.sports.photo', {
    url: '/photo'
  })
  .state('box5.sports.video', {
    url: '/video'
  })
.state('box5.clubs', {
  abstract: true,
  url: '/clubs/{clubId:int}'
})
  .state('box5.clubs.home', {
    url: '/home'
  })
  .state('box5.clubs.photo', {
    url: '/photo'
  })
  .state('box5.clubs.video', {
    url: '/video'
  })
  .state('box5.clubs.contact', {
    url: '/contact'
  })
.state('box5.spots', {
  abstract: true,
  url: '/spots/{spotId:int}'
})
  .state('box5.spots.home', {
    url: '/home'
  })
  .state('box5.spots.photo', {
    url: '/photo'
  })
  .state('box5.spots.video', {
    url: '/video'
  })
.state('box5.prices', {
  url: '/prices'
});
}])

.controller('Box5Ctrl', function($scope, MuineDataSvc, $state) {

$scope.data = MuineDataSvc.getData();

$scope.dataKeysList = Object.keys($scope.data);

$scope.rootState = $state.current.name.split('.')[0];

$scope.stateList = $state.get();

})

.controller('mainMenuItemCtrl2', function ($scope, $timeout, $stateParams, $state) {
console.log($scope.dataPath + ' > controller load');

//light version of data collection (only names and ids) for this menu item (dataPath)
$scope.col = [];
$scope.data[$scope.dataPath].forEach(function (item) {
  $scope.col.push({
    name: item.name,
    id: item.id
  });
});
//collection length is frequently used in following functions
$scope.colLength = $scope.col.length;
//itemIdParam - to access this item's $stateParam id
$scope.itemIdParam = $scope.dataPath.slice(0, -1).concat('Id');

//current id is either allready specified or provided in url and accessed through $stateParams. Otherwise take first collection element
$scope.id = $scope.id || parseInt($stateParams[$scope.itemIdParam]) || $scope.col[0].id;

//index of current item in collection is used to access its properties and find siblings
$scope.indexById = function (id) {
  for (var i = 0; i < $scope.colLength; i++) {
    if ($scope.col[i].id === id) {
      return i;
    }
  }
};
$scope.index = $scope.indexById($scope.id);

$scope.$watch('index', function () {
  //console.log('ctrl watch index > '+$scope.index);
});

//list of all child states
$scope.childStates = [];
$scope.stateList.forEach(function (state) {
  var nameArr = state.name.split('.');
  if (nameArr[0] === $scope.rootState && nameArr[1] === $scope.dataPath && nameArr[2]) {
    $scope.childStates.push(nameArr[2]);
  }
});

$scope.prevId = function () {
  if ($scope.index === 0) {return $scope.col[$scope.colLength - 1].id;}
  return $scope.col[$scope.index - 1].id;
};
$scope.nextId = function () {
  if ($scope.index === $scope.colLength - 1) {return $scope.col[0].id;}
  return $scope.col[$scope.index + 1].id;
};

//functions to populate ng-href links
//TODO check situation with to many requests per stateChange to the following functions
$scope.uiSref = function () {
  return '#/'+ $scope.rootState +'/'+ $scope.dataPath +'/'+$scope.id+'/';
};
$scope.prevUiSref = function () {
  return '#/'+ $scope.rootState +'/'+ $scope.dataPath +'/'+$scope.prevId()+'/'+ $scope.childStates[0];
};
$scope.nextUiSref = function () {
  return '#/'+ $scope.rootState +'/'+ $scope.dataPath +'/'+$scope.nextId()+'/'+ $scope.childStates[0];
};

// $scope.$on('$stateChangeSuccess', function(){
//   if ($state.includes($scope.rootState +'.'+ $scope.dataPath)) {
//     $scope.id = parseInt($stateParams[$scope.itemIdParam]);
//     $scope.index = $scope.indexById($scope.id);
//     $scope.menuList = [$scope.col[$scope.index]];
//     $scope.menuExpanded = false;
//     console.log('stateChange > $scope.id > '+ $scope.id +', $scope.index > '+ $scope.index);
//   }
// });

});

})();


text:
import { constructors, artefact, group } from '../core/library.js';
import { currentGroup } from '../core/document.js';
import { mergeOver, mergeDiscard, pushUnique, λnull, λthis, xta, Ωempty } from '../core/utilities.js';

import { makeState, stateKeys } from '../factory/state.js';
import { requestCell, releaseCell } from '../factory/cell.js';

import baseMix from '../mixin/base.js';
import deltaMix from '../mixin/delta.js';
import anchorMix from '../mixin/anchor.js';

// #### Loom constructor
const Loom = function (items = Ωempty) {

    this.makeName(items.name);
    this.register();

    this.state = makeState(Ωempty);

    this.set(this.defs);

    if (!items.group) items.group = currentGroup;

    this.onEnter = λnull;
    this.onLeave = λnull;
    this.onDown = λnull;
    this.onUp = λnull;

    this.delta = {};

    this.set(items);

    this.fromPathData = [];
    this.toPathData = [];

    this.watchFromPath = null;
    this.watchIndex = -1;
    this.engineInstructions = [];
    this.engineDeltaLengths = [];

    return this;
};

// #### Loom prototype
let P = Loom.prototype = Object.create(Object.prototype);
P.type = 'Loom';
P.lib = 'entity';
P.isArtefact = true;
P.isAsset = false;

// #### Mixins
P = baseMix(P);
P = deltaMix(P);
P = anchorMix(P);

// #### Loom attributes
// + Attributes defined in the [base mixin](../mixin/base.html): __name__.
// + Attributes defined in the [anchor mixin](../mixin/anchor.html): __anchor__.
let defaultAttributes = {

// __fromPath__, __toPath__ - A Loom entity uses 2 Shape paths to construct a frame between which the image will be redrawn. These attributes can be set using the Shapes' name-String, or the Shape objects themselves
// + The positioning, scaling etc of each strut is set in the constituent Shape entitys, not the Loom entity.
// + We can use a single path for both attributes, though nothing will show if the `start/end` attributs do not have differing values.
    fromPath: null,
    toPath: null,

// __fromPathStart__, __fromPathEnd__ and __toPathStart__, __toPathEnd__ - float Numbers generally between `0.0 - 1.0` - The Loom entity can set the start and end cursors on each of its path struts, between which the image will be drawn.
// + These can be animated to allow the image to _flow_ between one part of the display and another, changing its shape as it moves.
    fromPathStart: 0,
    fromPathEnd: 1,

    toPathStart: 0,
    toPathEnd: 1,

// __synchronizePathCursors__ - Boolean flag - To make sure the `from...` and `to...` strut start points, and end points, have the same value set the attribute to `true` (default).
// + Setting it to `false` allows the cursors to be set independently on each strut ... which in turn may lead to unexpected display consequences.
    synchronizePathCursors: true,

//  __loopPathCursors__ - Boolean flag - For animation purposes, the image will move between the struts with the bottom of the page appearing again at the top of the Loom as it moves down (and vice versa).
// + To change this functionality - so that the image slowly disappears as it animates up and down past the ends of the struts, set the attribute to `false`.
    loopPathCursors: true,
    constantPathSpeed: true,

// __isHorizontalCopy__ - Boolean flag - Copying the source image to the output happens, by default, by rows - which effectively means the struts are on the left-hand and right-hand edges of the image.
// + To change this to columns (which sets the struts to the top and bottom edges of the image) set the attribute to `false`
    isHorizontalCopy: true,

// __showBoundingBox__ (Boolean), __boundingBoxColor__ (CSS color String) - Mainly for library development/testing work - shows the loom entity's bounding box - which is calculated from the constituent Shape entitys' current bounding boxes.
    showBoundingBox: false,
    boundingBoxColor: '#000000',

// __source__ - The Picture entity source for this loom. For initialization and/or `set`, we can supply either the Picture entity itself, or its name-String value.
// + The content image displayed by the Loom entity are set in the Picture entity, not the Loom, and can be any artefact supported by the Picture (image, video, sprite, or a Cell artefact).
// + Note that any ___filters should be applied to the Picture entity___; Loom entitys do not support filter functionality but will apply a Picture's filters to the source image as-and-where appropriate.
    source: null,

// __sourceIsVideoOrSprite__ - Boolean flag - If the Picture entity is hosting a video or sprite asset, we need to update the input on every frame.
// + It's easier to tell the Loom entity to do this using a flag, rather than get the Picture entity to update all its Loom subscribers on every display cycle.
// + For Pictures using image assets the flag must be set to `false` (the default); setting the flag to `true` will significantly degrade display and animation performance.
    sourceIsVideoOrSprite: false,

// The current Frame drawing process often leads to [moiré interference patterns](https://en.wikipedia.org/wiki/Moir%C3%A9_pattern) appearing in the resulting image. Scrawl-canvas uses a resize trick to blur out these patterns.
//
// __interferenceLoops__ (positive integer Number), __interferenceFactor__ (positive float Number) - The interferenceFactor attribute sets the resizing ratio; while he interferenceLoops attribute sets the number of times the image gets resized.
// + If inteference patterns still appear in the final image, tweak these values to see if a better output can be achieved.
    interferenceLoops: 2,
    interferenceFactor: 1.03,

// The Loom entity does not use the [position](./mixin/position.html) or [entity](./mixin/entity.html) mixins (used by most other entitys) as its positioning is entirely dependent on the position, rotation, scale etc of its constituent Shape path entity struts.
//
// It does, however, use these attributes (alongside their setters and getters): __visibility__, __order__, __delta__, __host__, __group__, __anchor__, __collides__.
    visibility: true,
    calculateOrder: 0,
    stampOrder: 0,
    host: null,
    group: null,
    anchor: null,

// __noCanvasEngineUpdates__ - Boolean flag - Canvas engine updates are required for the Loom's border - strokeStyle and line styling; if a Loom is to be drawn without a border, then setting this flag to `true` may help improve rendering efficiency.
    noCanvasEngineUpdates: false,

// __noDeltaUpdates__ - Boolean flag - Loom entitys support delta animation - achieved by updating the `...path` attributes by appropriate (and small!) values. If the Loom is not going to be animated by delta values, setting the flag to `true` may help improve rendering efficiency.
    noDeltaUpdates: false,

// __onEnter__, __onLeave__, __onDown__, __onUp__ - Loom entitys support ___collision detection___, reporting a hit when a test coordinate falls within the Loom's output image. As a result, Looms can also accept and act on the four __on__ functions - see [entity event listener functions](../mixin/entity.html#section-11) for more details.
    onEnter: null,
    onLeave: null,
    onDown: null,
    onUp: null,

// __noUserInteraction__ - Boolean flag - To switch off collision detection for a Loom entity - which might help improve rendering efficiency - set the flag to `true`.
    noUserInteraction: false,

// [Anchor objects](./anchor.html) can be assigned to Loom entitys, meaning the following attributes are supported:
// + anchorDescription
// + anchorType
// + anchorTarget
// + anchorRel
// + anchorReferrerPolicy
// + anchorPing
// + anchorHreflang
// + anchorHref
// + anchorDownload
//
// And the anchor attributes can also be supplied as a key:value object assigned to the __anchor__ attribute:
// ```
//     anchor: {
//         description
//         download
//         href
//         hreflang
//         ping
//         referrerpolicy
//         rel:
//         target:
//         anchorType
//         clickAction:
//     }
// ```
//
// Note that Loom entitys DO NOT SUPPORT the sensor component of the Scrawl-canvas collisions system and will return an empty array when asked to supply sensor coordinates for testing against other artefacts.

// __method__ - All normal Scrawl-canvas entity stamping methods are supported.
    method: 'fill',

// Loom entitys support appropriate styling attributes, mainly for their stroke styles (used with the `draw`, `drawAndFill`, `fillAndDraw`, `drawThenFill` and `fillThenDraw` stamping methods).
// + These ___state___ attributes are stored directly on the object, rather than in a separate [State](./state.html) object.
//
// The following attributes are thus supported:
//
// Alpha and Composite operations will be applied to both the Loom entity's border (the Shape entitys, with connecting lines between their paths' start and end points) and fill (the image displayed between the Loom's struts)
// + __globalAlpha__
// + __globalCompositeOperation__
//
// All line attributes are supported
// + __lineWidth__
// + __lineCap__
// + __lineJoin__
// + __lineDash__
// + __lineDashOffset__
// + __miterLimit__
//
// The Loom entity's strokeStyle can be any style supported by Scrawl-canvas - color strings, gradient objects, and pattern objects
// + __strokeStyle__
//
// The shadow attributes will only be applied to the stroke (border), not to the Loom's fill (image)
// + __shadowOffsetX__
// + __shadowOffsetY__
// + __shadowBlur__
// + __shadowColor__
};
P.defs = mergeOver(P.defs, defaultAttributes);

// #### Packet management
P.packetExclusions = pushUnique(P.packetExclusions, ['pathObject', 'state']);
P.packetExclusionsByRegex = pushUnique(P.packetExclusionsByRegex, ['^(local|dirty|current)', 'Subscriber$']);
P.packetCoordinates = pushUnique(P.packetCoordinates, []);
P.packetObjects = pushUnique(P.packetObjects, ['group', 'fromPath', 'toPath', 'source']);
P.packetFunctions = pushUnique(P.packetFunctions, ['onEnter', 'onLeave', 'onDown', 'onUp']);

P.processPacketOut = function (key, value, includes) {

    let result = true;

    if(includes.indexOf(key) < 0 && value === this.defs[key]) result = false;

    return result;
};

P.finalizePacketOut = function (copy, items) {

    let stateCopy = JSON.parse(this.state.saveAsPacket(items))[3];
    copy = mergeOver(copy, stateCopy);

    copy = this.handlePacketAnchor(copy, items);

    return copy;
};

P.handlePacketAnchor = function (copy, items) {

    if (this.anchor) {

        let a = JSON.parse(this.anchor.saveAsPacket(items))[3];
        copy.anchor = a;
    }
    return copy;
}

// #### Clone management
// TODO - this functionality is currently disabled, need to enable it and make it work properly
P.clone = λthis;

// #### Kill management
// No additional kill functionality required

// #### Get, Set, deltaSet
let G = P.getters,
    S = P.setters,
    D = P.deltaSetters;

// __get__ - copied over from the entity mixin
P.get = function (item) {

    const getter = this.getters[item];

    if (getter) return getter.call(this);

    else {

        const def = this.defs[item],
            state = this.state;

        let val;

        if (typeof def != 'undefined') {

            val = this[item];
            return (typeof val != 'undefined') ? val : def;
        }

        def = state.defs[item];

        if (typeof def != 'undefined') {

            val = state[item];
            return (typeof val != 'undefined') ? val : def;
        }
        return null;
    }
};

// __set__ - copied over from the entity mixin.
P.set = function (items = Ωempty) {

    const keys = Object.keys(items),
        keysLen = keys.length;

    if (keysLen) {

        const setters = this.setters,
            defs = this.defs,
            state = this.state;

        const stateSetters = (state) ? state.setters : Ωempty;
        const stateDefs = (state) ? state.defs : Ωempty;

        let predefined, i, key, value;

        for (i = 0; i < keysLen; i++) {

            key = keys[i];
            value = items[key];

            if (key && key != 'name' && value != null) {

                if (stateKeys.indexOf(key) < 0) {

                    predefined = setters[key];

                    if (predefined) predefined.call(this, value);
                    else if (typeof defs[key] != 'undefined') this[key] = value;
                }
                else {

                    predefined = stateSetters[key];

                    if (predefined) predefined.call(state, value);
                    else if (typeof stateDefs[key] != 'undefined') state[key] = value;
                }
            }
        }
    }
    return this;
};

// __setDelta__ - copied over from the entity mixin.
P.setDelta = function (items = Ωempty) {

    const keys = Object.keys(items),
        keysLen = keys.length;

    if (keysLen) {

        const setters = this.deltaSetters,
            defs = this.defs,
            state = this.state;

        const stateSetters = (state) ? state.deltaSetters : Ωempty;
        const stateDefs = (state) ? state.defs : Ωempty;

        let predefined, i, key, value;

        for (i = 0; i < keysLen; i++) {

            key = keys[i];
            value = items[key];

            if (key && key != 'name' && value != null) {

                if (stateKeys.indexOf(key) < 0) {

                    predefined = setters[key];

                    if (predefined) predefined.call(this, value);
                    else if (typeof defs[key] != 'undefined') this[key] = addStrings(this[key], value);
                }
                else {

                    predefined = stateSetters[key];

                    if (predefined) predefined.call(state, value);
                    else if (typeof stateDefs[key] != 'undefined') state[key] = addStrings(state[key], value);
                }
            }
        }
    }
    return this;
};

// __host__, __getHost__ - copied over from the position mixin.
S.host = function (item) {

    if (item) {

        let host = artefact[item];

        if (host && host.here) this.host = host.name;
        else this.host = item;
    }
    else this.host = '';
};

// __group__ - copied over from the position mixin.
G.group = function () {

    return (this.group) ? this.group.name : '';
};
S.group = function (item) {

    let g;

    if (item) {

        if (this.group && this.group.type === 'Group') this.group.removeArtefacts(this.name);

        if (item.substring) {

            g = group[item];

            if (g) this.group = g;
            else this.group = item;
        }
        else this.group = item;
    }

    if (this.group && this.group.type === 'Group') this.group.addArtefacts(this.name);
};

// __getHere__ - returns current core position.
P.getHere = function () {

    return currentCorePosition;
};

// __delta__ - copied over from the position mixin.
S.delta = function (items) {

    if (items) this.delta = mergeDiscard(this.delta, items);
};

// __fromPath__
S.fromPath = function (item) {

    if (item) {

        let oldPath = this.fromPath,
            newPath = (item.substring) ? artefact[item] : item,
            name = this.name;

        if (newPath && newPath.name && newPath.useAsPath) {

            if (oldPath && oldPath.name !== newPath.name) removeItem(oldPath.pathed, name);

            pushUnique(newPath.pathed, name);

            this.fromPath = newPath;

            this.dirtyStart = true;
        }
    }
};

// __toPath__
S.toPath = function (item) {

    if (item) {

        let oldPath = this.toPath,
            newPath = (item.substring) ? artefact[item] : item,
            name = this.name;

        if (newPath && newPath.name && newPath.useAsPath) {

            if (oldPath && oldPath.name !== newPath.name) removeItem(oldPath.pathed, name);

            pushUnique(newPath.pathed, name);

            this.toPath = newPath;

            this.dirtyStart = true;
        }
    }
};

// __source__
S.source = function (item) {

    item = (item.substring) ? artefact[item] : item;

    if (item && item.type === 'Picture') {

        let src = this.source;

        if (src && src.type === 'Picture') src.imageUnsubscribe(this.name);

        this.source = item;
        item.imageSubscribe(this.name);
        this.dirtyInput = true;
    }
};

// __isHorizontalCopy__
S.isHorizontalCopy = function (item) {

    this.isHorizontalCopy = (item) ? true : false;
    this.dirtyPathData = true;
};

// __synchronizePathCursors__
S.synchronizePathCursors = function (item) {

    this.synchronizePathCursors = (item) ? true : false;

    if (item) {

        this.toPathStart = this.fromPathStart;
        this.toPathEnd = this.fromPathEnd;
    }

    this.dirtyPathData = true;
};

// __loopPathCursors__
S.loopPathCursors = function (item) {

    this.loopPathCursors = (item) ? true : false;

    if (item) {

        let c,
            floor = Math.floor;

        c = this.fromPathStart
        if (c < 0 || c > 1) this.fromPathStart = c - floor(c);

        c = this.fromPathEnd
        if (c < 0 || c > 1) this.fromPathEnd = c - floor(c);

        c = this.toPathStart
        if (c < 0 || c > 1) this.toPathStart = c - floor(c);

        c = this.toPathEnd
        if (c < 0 || c > 1) this.toPathEnd = c - floor(c);
    }

    this.dirtyOutput = true;
};

// __fromPathStart__
S.fromPathStart = function (item) {

    if (this.loopPathCursors && (item < 0 || item > 1)) item = item - Math.floor(item);
    this.fromPathStart = item;
    if (this.synchronizePathCursors) this.toPathStart = item;
    this.dirtyPathData = true;
};
D.fromPathStart = function (item) {

    let val = this.fromPathStart += item;

    if (this.loopPathCursors && (val < 0 || val > 1)) val = val - Math.floor(val);
    this.fromPathStart = val;
    if (this.synchronizePathCursors) this.toPathStart = val;
    this.dirtyPathData = true;
};

// __fromPathEnd__
S.fromPathEnd = function (item) {

    if (this.loopPathCursors && (item < 0 || item > 1)) item = item - Math.floor(item);
    this.fromPathEnd = item;
    if (this.synchronizePathCursors) this.toPathEnd = item;
    this.dirtyPathData = true;
};
D.fromPathEnd = function (item) {

    let val = this.fromPathEnd += item;

    if (this.loopPathCursors && (val < 0 || val > 1)) val = val - Math.floor(val);
    this.fromPathEnd = val;
    if (this.synchronizePathCursors) this.toPathEnd = val;
    this.dirtyPathData = true;
};

// __toPathStart__
S.toPathStart = function (item) {

    if (this.loopPathCursors && (item < 0 || item > 1)) item = item - Math.floor(item);
    this.toPathStart = item;
    if (this.synchronizePathCursors) this.fromPathStart = item;
    this.dirtyPathData = true;
};
D.toPathStart = function (item) {

    let val = this.toPathStart += item;

    if (this.loopPathCursors && (val < 0 || val > 1)) val = val - Math.floor(val);
    this.toPathStart = val;
    if (this.synchronizePathCursors) this.fromPathStart = val;
    this.dirtyPathData = true;
};

// __toPathEnd__
S.toPathEnd = function (item) {

    if (this.loopPathCursors && (item < 0 || item > 1)) item = item - Math.floor(item);
    this.toPathEnd = item;
    if (this.synchronizePathCursors) this.fromPathEnd = item;
    this.dirtyPathData = true;
};
D.toPathEnd = function (item) {

    let val = this.toPathEnd += item;

    if (this.loopPathCursors && (val < 0 || val > 1)) val = val - Math.floor(val);
    this.toPathEnd = val;
    if (this.synchronizePathCursors) this.fromPathEnd = val;
    this.dirtyPathData = true;
};

// #### Prototype functions

// `getHost` - copied over from the position mixin.
P.getHost = function () {

    if (this.currentHost) return this.currentHost;
    else if (this.host) {

        let host = artefact[this.host];

        if (host) {

            this.currentHost = host;
            this.dirtyHost = true;
            return this.currentHost;
        }
    }
    return currentCorePosition;
};

// Invalidate mid-init functionality
P.midInitActions = λnull;

// Force the Loom entity to update
// + Because it doesn't automatically keep check of changes in its picture source
P.update = function () {

    this.dirtyInput = true;
    this.dirtyOutput = true;
};

// #### Display cycle functionality

// `prepareStamp` - function called as part of the Display cycle `compile` step.
// + This function is called before we get into the entity stamp promise cascade (thus it's a synchronous function). This is where we need to check whether we need to recalculate the path data which we'll use later to build the Loom entity's output image.
// + We only need to recalculate the path data on the initial render, and afterwards when the __dirtyPathData__ flag has been set.
// + If we perform the recalculation, then we need to make sure to set the __dirtyOutput__ flag, which will trigger the output image build.
P.prepareStamp = function() {

    let fPath = this.fromPath,
        tPath = this.toPath;

    // Sanity check 1
    // + `getBoundingBox` will recalculate and set the `dirtyPathData` flag
    // + if paths have set the Loom's `dirtyStart` flag
    let [startX, startY, outputWidth, outputHeight] = this.getBoundingBox();

    // Sanity check 2
    // + we can set the `dirtyPathData` ourselves if paths `start/end` coordinates have changed
    // + in case Shape path `roll/scale/flip/etc` updates don't get messaged to the Loom entity
    if (!this.dirtyPathData) {

        let {x: testFromStartX, y: testFromStartY} = fPath.getPathPositionData(0);
        let {x: testFromEndX, y: testFromEndY} = fPath.getPathPositionData(1);
        let {x: testToStartX, y: testToStartY} = tPath.getPathPositionData(0);
        let {x: testToEndX, y: testToEndY} = tPath.getPathPositionData(1);

        let localPathTests = [testFromStartX, testFromStartY, testFromEndX, testFromEndY, testToStartX, testToStartY, testToEndX, testToEndY];

        if (!this.pathTests || this.pathTests.some((item, index) => item !== localPathTests[index])) {

            this.pathTests = localPathTests;
            this.dirtyPathData = true;
        }
    }

    if (this.dirtyPathData || !this.fromPathData.length) {

        this.dirtyPathData = false;

        this.watchIndex = -1;
        this.engineInstructions.length = 0;
        this.engineDeltaLengths.length = 0;

        let mCeil = Math.ceil,
            mMax = Math.max,
            mMin = Math.min,
            mFloor = Math.floor;

        let fromPathData = this.fromPathData;
        fromPathData.length = 0;

        let toPathData = this.toPathData;
        toPathData.length = 0;

        if(fPath && tPath) {

            let fPathLength = mCeil(fPath.length),
                tPathLength = mCeil(tPath.length),
                pathSteps, pathDelta, x, y;

            pathSteps = this.setSourceDimension(mMax(fPathLength, tPathLength));

            let fPathStart = this.fromPathStart,
                fPathEnd = this.fromPathEnd,
                tPathStart = this.toPathStart,
                tPathEnd = this.toPathEnd,
                fPartial, tPartial, fRatio, tRatio, minPartial,
                pathSpeed = this.constantPathSpeed;

            if (fPathStart < fPathEnd) fPartial = fPathEnd - fPathStart;
            else fPartial = fPathEnd + (1 - fPathStart);
            if (fPartial < 0.005) fPartial = 0.005;

            if (tPathStart < tPathEnd) tPartial = tPathEnd - tPathStart;
            else tPartial = tPathEnd + (1 - tPathStart);
            if (tPartial < 0.005) tPartial = 0.005;

            minPartial = mCeil(mMin(fPartial, tPartial));

            pathDelta = 1 / (pathSteps * (1 / minPartial));

            for (let cursor = 0; cursor <= 1; cursor += pathDelta) {

                ({x, y} = fPath.getPathPositionData(cursor, pathSpeed));
                fromPathData.push([x - startX, y - startY]);

                ({x, y} = tPath.getPathPositionData(cursor, pathSpeed));
                toPathData.push([x - startX, y - startY]);
            }

            this.fromPathSteps = fPartial / minPartial;
            this.toPathSteps = tPartial / minPartial;

            this.watchFromPath = (this.fromPathSteps === 1) ? true : false;

            this.dirtyOutput = true;
        }
        else this.dirtyPathData = true;
    }
};

// `setSourceDimension` - internal function called by `prepareStamp`.
// + We make the source dimensions a square of the longest path length
// + This way, we can do a horizontal scan, or a vertical scan with no further calculation
P.setSourceDimension = function (val) {

    // + `prepareStamp` does the dimension calculation itself, then supplies the new value
    // + we just need to update this.sourceDimension and set the dirtyInput flag
    if (val) {

        if (this.sourceDimension !== val) {

            this.sourceDimension = val;
            this.dirtyInput = true;
        }
    }

    // if other functions call setSourceDimension, they will do it without supplying a new value
    // + in which case we can calculate and update it here
    // + other functions do it as a sanity check
    else {

        let fPath = this.fromPath,
            tPath = this.toPath;

        if(fPath && tPath) {

            let mCeil = Math.ceil,
                fPathLength = mCeil(fPath.length),
                tPathLength = mCeil(tPath.length);

            let steps = Math.max(fPathLength, tPathLength);

            if (this.sourceDimension !== steps) this.sourceDimension = steps;
        }
        else this.sourceDimension = 0;
    }
    return this.sourceDimension;
};

// `simpleStamp` - Simple stamping is entirely synchronous
// + TODO: we may have to disable this functionality for the Loom entity, if we use a Web Assembly module for either the prepareStamp calculations, or to build the output image itself
P.simpleStamp = function (host, changes) {

    if (host && host.type === 'Cell') {

        this.currentHost = host;

        if (changes) {

            this.set(changes);
            this.prepareStamp();
        }
        this.regularStamp();
    }
};

// `stamp` - All entity stamping, except for simple stamps, goes through this function.
// + While other entitys have to worry about applying filters as part of the stamping process, this is not an issue for Loom entitys because filters are defined on, and applied to, the source Picture entity, not the Loom itself
//
// Here we check which dirty flags need actioning, and call a range of different functions to process the work. These flags are:
// + `dirtyInput` - the Picture entity has reported a change in its source, or copy attributes)
// + `dirtyOutput` - to render the cleaned input, or take account that the Loom paths' cursors have changed)
P.stamp = function (force = false, host, changes) {

    if (force) {

        if (host && host.type === 'Cell') this.currentHost = host;

        if (changes) {

            this.set(changes);
            this.prepareStamp();
        }
        return this.regularStamp();
    }

    if (this.visibility) {

        if (this.sourceIsVideoOrSprite || this.dirtyInput) this.sourceImageData = this.cleanInput();

        if (this.dirtyOutput) this.output = this.cleanOutput();

        this.regularStamp();
    }
};

// #### Clean functions

// `cleanInput` - internal function called by `stamp`
P.cleanInput = function () {

    this.dirtyInput = false;

    let sourceDimension = this.sourceDimension;

    if (!sourceDimension) {

        this.dirtyInput = true;
        return false;
    }

    let cell = requestCell(),
        engine = cell.engine,
        canvas = cell.element;

    canvas.width = sourceDimension;
    canvas.height = sourceDimension;
    engine.setTransform(1, 0, 0, 1, 0, 0);

    this.source.stamp(true, cell, {
        startX: 0,
        startY: 0,
        handleX: 0,
        handleY: 0,
        offsetX: 0,
        offsetY: 0,
        roll: 0,
        scale: 1,

        width: sourceDimension,
        height: sourceDimension,

        method: 'fill',
    });
    return engine.getImageData(0, 0, sourceDimension, sourceDimension);
};

// `cleanOutput` - internal function called by `stamp`
// + If you're not a fan of big functions, please look away now.
P.cleanOutput = function () {

    this.dirtyOutput = false;

    let sourceDimension = this.sourceDimension,
        sourceData = this.sourceImageData;

    if (sourceDimension && sourceData) {

        let mHypot = Math.hypot,
            mFloor = Math.floor,
            mCeil = Math.ceil,
            mAtan2 = Math.atan2,
            mCos = Math.cos,
            mSin = Math.sin;

        let fromPathData = this.fromPathData,
            toPathData = this.toPathData,

            dataLen = fromPathData.length,

            fPathStart = this.fromPathStart,
            fCursor = fPathStart * dataLen,
            fStep = this.fromPathSteps || 1,

            tPathStart = this.toPathStart,
            tCursor = tPathStart * dataLen,
            tStep = this.toPathSteps || 1,

            magicHorizontalPi = 0.5 * Math.PI,
            magicVerticalPi = magicHorizontalPi - 1.5708,

            isHorizontalCopy = this.isHorizontalCopy,
            loop = this.loopPathCursors,

            fx, fy, tx, ty, dx, dy, dLength, dAngle, cos, sin,

            watchFromPath = this.watchFromPath,
            watchIndex = this.watchIndex,
            engineInstructions = this.engineInstructions,
            engineDeltaLengths = this.engineDeltaLengths,
            instruction;

        let [startX, startY, outputWidth, outputHeight] = this.getBoundingBox();

        let inputCell = requestCell(),
            inputEngine = inputCell.engine,
            inputCanvas = inputCell.element;

        inputCanvas.width = sourceDimension;
        inputCanvas.height = sourceDimension;
        inputEngine.setTransform(1, 0, 0, 1, 0, 0);
        inputEngine.putImageData(sourceData, 0, 0);

        let outputCell = requestCell(),
            outputEngine = outputCell.engine,
            outputCanvas = outputCell.element;

        outputCanvas.width = outputWidth;
        outputCanvas.height = outputHeight;
        outputEngine.globalAlpha = this.state.globalAlpha;
        outputEngine.setTransform(1, 0, 0, 1, 0, 0);

        if(!engineInstructions.length) {

            for (let i = 0; i < sourceDimension; i++) {

                if (watchIndex < 0) {

                    if (watchFromPath && fCursor < 1) watchIndex = i;
                    else if (!watchFromPath && tCursor < 1) watchIndex = i;
                }

                if (fCursor < dataLen && tCursor < dataLen && fCursor >= 0 && tCursor >= 0) {

                    [fx, fy] = fromPathData[mFloor(fCursor)];
                    [tx, ty] = toPathData[mFloor(tCursor)];

                    dx = tx - fx;
                    dy = ty - fy;

                    dLength = mHypot(dx, dy);

                    if (isHorizontalCopy) {

                        dAngle = -mAtan2(dx, dy) + magicHorizontalPi;
                        cos = mCos(dAngle);
                        sin = mSin(dAngle);

                        engineInstructions.push([cos, sin, -sin, cos, fx, fy]);
                        engineDeltaLengths.push(dLength);
                    }
                    else {

                        dAngle = -mAtan2(dx, dy) + magicVerticalPi;
                        cos = mCos(dAngle);
                        sin = mSin(dAngle);

                        engineInstructions.push([cos, sin, -sin, cos, fx, fy, dLength]);
                        engineDeltaLengths.push(dLength);
                    }
                }
                else {

                    engineInstructions.push(false);
                    engineDeltaLengths.push(false);
                }

                fCursor += fStep;
                tCursor += tStep;

                if (loop) {

                    if (fCursor >= dataLen) fCursor -= dataLen;
                    if (tCursor >= dataLen) tCursor -= dataLen;
                }
            }
            if (watchIndex < 0) watchIndex = 0;
            this.watchIndex = watchIndex;
        }

        if (isHorizontalCopy) {

            for (let i = 0; i < sourceDimension; i++) {

                instruction = engineInstructions[watchIndex];

                if (instruction) {

                    outputEngine.setTransform(...instruction);
                    outputEngine.drawImage(inputCanvas, 0, watchIndex, sourceDimension, 1, 0, 0, engineDeltaLengths[watchIndex], 1);
                }
                watchIndex++;

                if (watchIndex >= sourceDimension) watchIndex = 0;
            }
        }
        else {

            for (let i = 0; i < sourceDimension; i++) {

                instruction = engineInstructions[watchIndex];

                if (instruction) {

                    outputEngine.setTransform(...instruction);
                    outputEngine.drawImage(inputCanvas, watchIndex, 0, 1, sourceDimension, 0, 0, 1, engineDeltaLengths[watchIndex]);
                }
                watchIndex++;

                if (watchIndex >= sourceDimension) watchIndex = 0;
            }
        }

        let iFactor = this.interferenceFactor,
            iLoops = this.interferenceLoops,

            iWidth = mCeil(outputWidth * iFactor),
            iHeight = mCeil(outputHeight * iFactor);

        inputCanvas.width = iWidth;
        inputCanvas.height = iHeight;

        outputEngine.setTransform(1, 0, 0, 1, 0, 0);
        inputEngine.setTransform(1, 0, 0, 1, 0, 0);

        for (let j = 0; j < iLoops; j++) {

            inputEngine.drawImage(outputCanvas, 0, 0, outputWidth, outputHeight, 0, 0, iWidth, iHeight);
            outputEngine.drawImage(inputCanvas, 0, 0, iWidth, iHeight, 0, 0, outputWidth, outputHeight);
        }

        let outputData = outputEngine.getImageData(0, 0, outputWidth, outputHeight);

        releaseCell(inputCell);
        releaseCell(outputCell);

        this.dirtyTargetImage = true;

        return outputData;
    }
    return false;
        // else return new Error(`${this.name} - cleanOutput Error: source has a zero dimension, or no data`);
};

// `regularStamp` - internal function called by `stamp`
P.regularStamp = function () {

    let dest = this.currentHost;

    if (dest) {

        let engine = dest.engine;

        if (!this.noCanvasEngineUpdates) dest.setEngine(this);

        this[this.method](engine);
    }
};

// `getBoundingBox` - internal function called by `prepareStamp` and `cleanOutput` functions, as well as the various ___method___ functions.
// + Loom calculates its bounding box from the Shape path entitys associated with it
// + This function recalculates when presented with a `dirtyStart` flag - we rely on the Shape entitys to tell us when their paths have changed/updated
// + Results get stashed in the __boundingBox__ attribute for easier access, but all the method functions call this function just in case the box needs recalculating.
P.getBoundingBox = function () {

    let fPath = this.fromPath,
        tPath = this.toPath;

    if(fPath && tPath) {

        if (this.dirtyStart) {

            if (fPath.getBoundingBox && tPath.getBoundingBox) {

                this.dirtyStart = false;

                let [lsx, lsy, sw, sh, sx, sy] = fPath.getBoundingBox();
                let [lex, ley, ew, eh, ex, ey] = tPath.getBoundingBox();

                if (isNaN(lsx) || isNaN(lsy) || isNaN(sw) || isNaN(sh) || isNaN(sx) || isNaN(sy) || isNaN(lex) || isNaN(ley) || isNaN(ew) || isNaN(eh) || isNaN(ex) || isNaN(ey)) this.dirtyStart = true;

                if (lsx == lex && lsy == ley && sw == ew && sh == eh && sx == ex && sy == ey) this.dirtyStart = true;

                lsx += sx;
                lsy += sy;
                lex += ex;
                ley += ey;

                let minX = Math.min(lsx, lex);
                let maxX = Math.max(lsx + sw, lex + ew);
                let minY = Math.min(lsy, ley);
                let maxY = Math.max(lsy + sh, ley + eh);

                this.boundingBox = [minX, minY, maxX - minX, maxY - minY];

                this.dirtyPathData = true;
            }
            else this.boundingBox = [0, 0, 0, 0];
        }
    }
    else this.boundingBox = [0, 0, 0, 0];

    return this.boundingBox;
};

// ##### Stamp methods
// These 'method' functions stamp the Loom entity onto the canvas context supplied to them in the `engine` argument.

// `fill`
P.fill = function (engine) {

    this.doFill(engine);

    if (this.showBoundingBox) this.drawBoundingBox(engine);

};

// `draw`
P.draw = function (engine) {

    this.doStroke(engine);

    if (this.showBoundingBox) this.drawBoundingBox(engine);
};

// `drawAndFill`
P.drawAndFill = function (engine) {

    this.doStroke(engine);
    this.currentHost.clearShadow();
    this.doFill(engine);

    if (this.showBoundingBox) this.drawBoundingBox(engine);
};

// `fillAndDraw`
P.fillAndDraw = function (engine) {

    this.doFill(engine);
    this.currentHost.clearShadow();
    this.doStroke(engine);

    if (this.showBoundingBox) this.drawBoundingBox(engine);
};

// `drawThenFill`
P.drawThenFill = function (engine) {

    this.doStroke(engine);
    this.doFill(engine);

    if (this.showBoundingBox) this.drawBoundingBox(engine);
};

// `fillThenDraw`
P.fillThenDraw = function (engine) {

    this.doFill(engine);
    this.doStroke(engine);

    if (this.showBoundingBox) this.drawBoundingBox(engine);
};

// `clear`
P.clear = function (engine) {

    let output = this.output,
        canvas = (this.currentHost) ? this.currentHost.element : false,
        gco = engine.globalCompositeOperation;

    if (output && canvas) {

        let tempCell = requestCell(),
            tempEngine = tempCell.engine,
            tempCanvas = tempCell.element;

        let [x, y, w, h] = this.getBoundingBox();

        tempCanvas.width = w;
        tempCanvas.height = h;

        tempEngine.putImageData(output, 0, 0);
        engine.setTransform(1, 0, 0, 1, 0, 0);
        engine.globalCompositeOperation = 'destination-out';
        engine.drawImage(tempCanvas, 0, 0, w, h, x, y, w, h);
        engine.globalCompositeOperation = gco;

        releaseCell(tempCell);
        if (this.showBoundingBox) this.drawBoundingBox(engine);
    }
};

// `none`, `clip`
P.none = λnull;
P.clip = λnull;

// These __stroke__ and __fill__ functions handle most of the stuff that the method functions require to stamp the Loom entity onto a canvas cell.

// `doStroke`
P.doStroke = function (engine) {

    let fPath = this.fromPath,
        tPath = this.toPath;

    if(fPath && fPath.getBoundingBox && tPath && tPath.getBoundingBox) {

        let host = this.currentHost;

        if (host) {

            let fStart = fPath.currentStampPosition,
                fEnd = fPath.getPathPositionData(1),
                tStart = tPath.currentStampPosition,
                tEnd = tPath.getPathPositionData(1);

            host.rotateDestination(engine, fStart[0], fStart[1], fPath);
            engine.stroke(fPath.pathObject);

            host.rotateDestination(engine, tStart[0], tStart[1], fPath);
            engine.stroke(tPath.pathObject);

            engine.setTransform(1,0, 0, 1, 0, 0);
            engine.beginPath()
            engine.moveTo(fEnd.x, fEnd.y);
            engine.lineTo(tEnd.x, tEnd.y);
            engine.moveTo(...tStart);
            engine.lineTo(...fStart);
            engine.closePath();
            engine.stroke();
        }
    }
};

// `doFill`
// + Canvas API's `putImageData` function turns transparent pixels in the output into transparent in the host canvas - which is not what we want
// + Problem solved by putting output into a pool cell, then drawing it from there to the host cell
P.doFill = function (engine) {

    let output = this.output,
        canvas = (this.currentHost) ? this.currentHost.element : false;

    if (output && canvas) {

        let tempCell = requestCell(),
            tempEngine = tempCell.engine,
            tempCanvas = tempCell.element;

        let [x, y, w, h] = this.getBoundingBox();

        tempCanvas.width = w;
        tempCanvas.height = h;

        tempEngine.putImageData(output, 0, 0);
        engine.setTransform(1, 0, 0, 1, 0, 0);
        engine.drawImage(tempCanvas, 0, 0, w, h, x, y, w, h);

        releaseCell(tempCell);
    }
};

// `drawBoundingBox`
// + Usually only need to draw the bounding box during development work, to make sure the getBoundingBox calculation is operating correctly
P.drawBoundingBox = function (engine) {

    if (this.dirtyStart) this.getBoundingBox();

    engine.save();

    let t = engine.getTransform();
    engine.setTransform(1, 0, 0, 1, 0, 0);

    engine.strokeStyle = this.boundingBoxColor;
    engine.lineWidth = 1;
    engine.globalCompositeOperation = 'source-over';
    engine.globalAlpha = 1;
    engine.shadowOffsetX = 0;
    engine.shadowOffsetY = 0;
    engine.shadowBlur = 0;

    engine.strokeRect(...this.boundingBox);

    engine.restore();
    engine.setTransform(t);
};

// #### Collision functionality

// The `checkHit` functionality can be used in the same way it is for other entitys (and groups)
// + One difference is that this function checks hits against an ImageData object, thus doesn't need to be supplied with a pool canvas so that it can do its job
// + Note: will check for the `dirtyTargetImage` flag, which normally gets checked as part of the rendering cycle
P.checkHit = function (items = []) {

    if (this.noUserInteraction) return false;

    let tests = (!Array.isArray(items)) ?  [items] : items,
        targetData = (this.output && this.output.data) ? this.output.data : false,
        tx, ty, cx, cy, index;

    if (targetData) {

        let [x, y, w, h] = this.getBoundingBox();

        if (tests.some(test => {

            if (Array.isArray(test)) {

                tx = test[0];
                ty = test[1];
            }
            else if (xta(test, test.x, test.y)) {

                tx = test.x;
                ty = test.y;
            }
            else return false;

            if (!tx.toFixed || !ty.toFixed || isNaN(tx) || isNaN(ty)) return false;

            cx = tx - x;
            cy = ty - y;

            if (cx < 0 || cx > w || cy < 0 || cy > h) return false;

            index = (((cy * w) + cx) * 4) + 3;

            if (targetData) return (targetData[index] > 0) ? true : false;
            else return false;

        }, this)) {

            return {
                x: tx,
                y: ty,
                artefact: this
            };
        }
    }
    return false;
};

// #### Factory
// ```
// scrawl.makeQuadratic({
//
//     name: 'my-quad',
//     // [... rest of definition]
// });
//
// let myBez = scrawl.makeBezier({
//
//     name: 'my-bezier',
//     // [... rest of definition]
// });
//
// scrawl.makePicture({
//
//     name: 'myFlower',
//
//     // Loom will respect the Picture's copy attributes when creating its output
//     copyStartX: 0,
//     copyStartY: 0,
//
//     copyWidth: '100%',
//     copyHeight: '100%',
//
//     // Best practice - set visibility to false
//     visibility: false,
//
//     // [... rest of definition]
// });
//
// let myLoom = scrawl.makeLoom({
//
//     name: 'display-loom',
//
//     fromPath: 'my-quad',
//     toPath: myBez,
//
//     source: 'myFlower',
//
//     lineWidth: 2,
//     lineCap: 'round',
//     strokeStyle: 'orange',
//
//     boundingBoxColor: 'red',
//     showBoundingBox: true,
//
//     method: 'fillThenDraw',
// });
// ```
const makeLoom = function (items) {

    if (!items) return false;
    return new Loom(items);
};

constructors.Loom = Loom;

// #### Exports
export {
    makeLoom,
};