{

	class Waiter {

		constructor() {

			this.promise = new Promise( ( resolve ) => {

				this.resolve = resolve;

			} );

		}

	}

	async function getSVGDocument( elem ) {

		const data = elem.data;
		elem.data = '';
		elem.data = data;
		const waiter = new Waiter();
		elem.addEventListener( 'load', waiter.resolve );
		await waiter.promise;
		return elem.getSVGDocument();

	}

	const diagrams = {
		lookup: {
			async init( elem ) {

				const svg = await getSVGDocument( elem );
				const partsByName = {};
				[
					'[id$=-Input]',
					'[id$=-Output]',
					'[id$=-Result]',
				].forEach( ( selector ) => {

					[ ...svg.querySelectorAll( '[id^=Effect]' ) ].forEach( ( elem ) => {

						// because affinity designer doesn't export blend modes (T_T)
						// and because I'd prefer not to have to manually fix things as I edit.
						// I suppose I could add a build process.
						elem.style.mixBlendMode = elem.id.split( '-' )[ 1 ];

					} );
					[ ...svg.querySelectorAll( selector ) ].forEach( ( elem ) => {

						const [ name, type ] = elem.id.split( '-' );
						partsByName[ name ] = partsByName[ name ] || {};
						partsByName[ name ][ type ] = elem;
						elem.style.visibility = 'hidden';

					} );

				} );
				const parts = Object.keys( partsByName ).sort().map( k => partsByName[ k ] );
				let ndx = 0;
				let step = 0;
				let delay = 0;
				setInterval( () => {

					const part = parts[ ndx ];
					switch ( step ) {

						case 0:
							part.Input.style.visibility = '';
							++ step;
							break;
						case 1:
							part.Output.style.visibility = '';
							++ step;
							break;
						case 2:
							part.Result.style.visibility = '';
							++ step;
							break;
						case 3:
							part.Input.style.visibility = 'hidden';
							part.Output.style.visibility = 'hidden';
							ndx = ( ndx + 1 ) % parts.length;
							if ( ndx === 0 ) {

								step = 4;
								delay = 4;

							} else {

								step = 0;

							}

							break;
						case 4:
							-- delay;
							if ( delay <= 0 ) {

								for ( const part of parts ) {

									for ( const elem of Object.values( part ) ) {

										elem.style.visibility = 'hidden';

									}

								}

								step = 0;

							}

							break;

					}

				}, 500 );

			},
		},
	};

	[ ...document.querySelectorAll( '[data-diagram]' ) ].forEach( createDiagram );

	function createDiagram( base ) {

		const name = base.dataset.diagram;
		const info = diagrams[ name ];
		if ( ! info ) {

			throw new Error( `no diagram ${name}` );

		}

		info.init( base );

	}

}

