<commit_before><div class='app-controls'>
	<ExampleSelector :examples bind:name on:select/>

	<div style='text-align: right;'>
		{{#if $user}}
			<UserMenu/>
		{{else}}
			<a class='login' on:click='login(event)' href='auth/login'>Login to save</a>
		{{/if}}

		<button disabled={{downloading}} on:click='download()' title='download zip file' class=icon style='background-image: url(icons/download.svg)'>download</button>

		{{#if $user}}
			<button disabled={{forking || !$user}} on:click='fork()' title='fork' class=icon style='background-image: url(icons/fork.svg)'>fork</button>
			<button disabled={{saving || !canSave}} on:click='save()' title='save' class=icon style='background-image: url(icons/save.svg)'>save</button>
		{{/if}}

		{{#if gist}}
			<a href='{{gist.html_url}}' title='link to gist' class=icon style='background-image: url(icons/link.svg)'>link to gist</a>
		{{/if}}
	</div>
</div>

<style>
	.app-controls {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		border-bottom: 1px solid #eee;
		background-color: #f4f4f4;
		padding: 0.5em;
		height: 3em;
	}

	.icon {
		display: block;
		float: right;
		width: 2em;
		height: 2em;
		text-indent: -9999px;
		background: transparent no-repeat 0 50%;
		background-size: 1.6em 1.6em;
		opacity: 0.6;
	}

	a.icon {
		line-height: 0;
		color: transparent;
	}

	.icon:hover {
		opacity: 1;
	}

	.icon:disabled {
		filter: grayscale(1);
		opacity: 0.4;
	}

	.login {
		/* position: relative;
		padding: 0 2em 0 0; */
		line-height: 1.2;
		display: inline-block;
		float: right;
		padding: 0.5em;
		font-family: Rajdhani;
		font-weight: 400;
		color: #333;
	}
</style>

<script>
	import ExampleSelector from './ExampleSelector.html';
	import UserMenu from './UserMenu.html';

	export default {
		components: {
			ExampleSelector,
			UserMenu
		},

		computed: {
			canSave: ($user, gist) => {
				if (!$user) return false;
				if (!gist) return false;
				return $user.id == gist.owner.id; // comparing number and string
			}
		},

		methods: {
			login(event) {
				event.preventDefault();
				const loginWindow = window.open(`${window.location.origin}/auth/login`, 'login', 'width=600,height=400');

				const handleLogin = event => {
					loginWindow.close();
					this.store.set({ user: event.data.user });
					window.removeEventListener('message', handleLogin);
				};

				window.addEventListener('message', handleLogin);
			},

			async fork() {
				const { name, components, json } = this.get();

				this.set({ forking: true });<commit_msg>avoid fat-fingering and overwriting built-in examples - fixes #232<commit_after><div class='app-controls'>
	<ExampleSelector :examples bind:name on:select/>

	<div style='text-align: right;'>
		{{#if $user}}
			<UserMenu/>
		{{else}}
			<a class='login' on:click='login(event)' href='auth/login'>Login to save</a>
		{{/if}}

		<button disabled={{downloading}} on:click='download()' title='download zip file' class=icon style='background-image: url(icons/download.svg)'>download</button>

		{{#if $user}}
			<button disabled={{forking || !$user}} on:click='fork()' title='fork' class=icon style='background-image: url(icons/fork.svg)'>fork</button>
			<button disabled={{saving || !canSave}} on:click='save()' title='save' class=icon style='background-image: url(icons/save.svg)'>save</button>
		{{/if}}

		{{#if gist}}
			<a href='{{gist.html_url}}' title='link to gist' class=icon style='background-image: url(icons/link.svg)'>link to gist</a>
		{{/if}}
	</div>
</div>

<style>
	.app-controls {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		border-bottom: 1px solid #eee;
		background-color: #f4f4f4;
		padding: 0.5em;
		height: 3em;
	}

	.icon {
		display: block;
		float: right;
		width: 2em;
		height: 2em;
		text-indent: -9999px;
		background: transparent no-repeat 0 50%;
		background-size: 1.6em 1.6em;
		opacity: 0.6;
	}

	a.icon {
		line-height: 0;
		color: transparent;
	}

	.icon:hover {
		opacity: 1;
	}

	.icon:disabled {
		filter: grayscale(1);
		opacity: 0.4;
	}

	.login {
		/* position: relative;
		padding: 0 2em 0 0; */
		line-height: 1.2;
		display: inline-block;
		float: right;
		padding: 0.5em;
		font-family: Rajdhani;
		font-weight: 400;
		color: #333;
	}
</style>

<script>
	import ExampleSelector from './ExampleSelector.html';
	import UserMenu from './UserMenu.html';
	import examples from '../_examples.json';

	const gistIds = new Set();
	examples.forEach(group => {
		group.examples.forEach(example => {
			gistIds.add(example.gist);
		});
	});

	export default {
		components: {
			ExampleSelector,
			UserMenu
		},

		computed: {
			canSave: ($user, gist) => {
				if (!$user) return false;
				if (!gist) return false;
				return $user.id == gist.owner.id && !gistIds.has(gist.id); // comparing number and string
			}
		},

		methods: {
			login(event) {
				event.preventDefault();
				const loginWindow = window.open(`${window.location.origin}/auth/login`, 'login', 'width=600,height=400');

				const handleLogin = event => {
					loginWindow.close();
					this.store.set({ user: event.data.user });
					window.removeEventListener('message', handleLogin);
				};

				window.addEventListener('message', handleLogin);
			},

			async fork() {
				const { name, components, json } = this.get();

				this.set({ forking: true });
{'fraction_non_alphanumeric': 0.18157795394488485, 'fraction_numerical': 0.020196300490751228, 'mean_word_length': 3.701863354037267, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4319762', 'n_tokens_mistral': 2217, 'n_tokens_neox': 1871, 'n_words': 423}