<commit_before>const querystring = require('querystring');
const $ = require('jquery');
const Board = require('./board');
const BoardElement = require('./board-element');
const DataElement = require('./data-element');
const Panel = require('./panel');

const params = querystring.parse(location.search.slice(1));

class Stage {
	constructor(game, config) {
		this.game = game;
		this.config = config;
		this.$stage = this.game.$stage;
		this.blockSize = 50;
		this.caseIndex = 0;
		this.maxClock = 0;

		this.board = new Board(this.config, this.blockSize);
		this.boardElement = new BoardElement(this, this.board);
		this.panel = new Panel(this);

		this.updateStyles();
		this.updateClockElement();

		this.board.on('output', (value) => this.output(value));
		this.board.on('halt', () => this.onHalt());

		this.$stage.find('.statement').text(config.statement);

		this.$selectedBlock = this.$stage.find('.panel .block[selected]').first();

		this.$stage.find('.board .block').click((event) => {
			const $block = $(event.target);
			if (!this.board.executing) {
				const type = this.$selectedBlock.data('type');
				this.panel.takeAndPlace($block.data('x'), $block.data('y'), type);
			}
		});

		this.$stage.find('.board .block').bind('contextmenu', (event) => {
			const $block = $(event.target);
			if (!this.board.executing) {
				this.panel.takeAndPlace($block.data('x'), $block.data('y'), 'empty');
			}
			return false;
		});

		this.$stage.find('.execute').click(() => {
			$.fx.off = params.fx === 'off';
			this.execute();
		});

		this.$stage.find('.stop').click(() => {
			this.board.halt();
			$.fx.off = params.fx === 'off';
		});

		this.$stage.find('.exit').click(() => {
			$.fx.off = params.fx === 'off';
			this.game.exitStage();
		});

		this.$stage.find('.rapid').click(() => {
			if ($.fx.off) {
				$.fx.off = params.fx === 'off';
			} else {
				$.fx.off = true;
				this.boardElement.dataElements.forEach((element) => element.$data.finish());
			}
			if (!this.board.executing) {
				this.execute();
			}
		});

		this.$stage.find('.inputs').empty().append(config.input.map((input) => {
			let inputString = (typeof input === 'number') ? input.toString()
				: input.map((x) => (typeof x === 'number')
					? x.toString() : `[${x.toString()}]`).join(',');
			if (inputString.length > 15) {
				inputString = `${inputString.substring(0, 13)}...`;
			}

			return $('<div/>', {class: 'input'}).append($('<span/>', {
				class: 'inner-text',
				text: inputString,
			}));
		}));

		this.$stage.find('.inputs .input').each((index, input) => {
			const $span = $(input).find('.inner-text');
			const inputWidth = $(input).outerWidth();
			const spanWidth = $span.width();
			if (inputWidth < spanWidth) {
				$span.css({fontSize: `${inputWidth / spanWidth * 100 - 2}%`});
			}
		});

		this.$stage.find('.arrows').empty().append(config.output.map(() => (
			$('<div/>', {class: 'arrow'})
		)));

		this.$stage.find('.user-outputs').empty().append(config.output.map(() => (
			$('<div/>', {class: 'output'})
		)));

		this.$stage.find('.correct-outputs').empty().append(config.output.map((output) => (
			$('<div/>', {class: 'output'}).append($('<span/>', {
				class: 'inner-text',
				text: output,
			}
		)))));

		this.$stage.find('.outputs .output').each((index, output) => {
			const $span = $(output).find('.inner-text');
			const outputWidth = $(output).outerWidth();
			const spanWidth = $span.width();
			if (outputWidth < spanWidth) {
				$span.css({fontSize: `${outputWidth / spanWidth * 100 - 2}%`});
			}
		});

		this.$stage.find('button.stop').hide();
		this.$stage.find('button.execute').show();

		this.updateStyles();
	}

	execute() {
		this.caseIndex = 0;
		this.maxClock = 0;
		this.$stage.find('.user-outputs .output').empty().removeClass('correct wrong');

		this.executeCase();
	}

	executeCase() {
		const inputs = this.board.input(this.config.input[this.caseIndex]);
		inputs.forEach((input, index) => {
			input.forEach((value) => {
				new DataElement(this.boardElement, value, this.board.inputBlock[index].top);
			});
		});

		this.$stage.find('button.stop').show();
		this.$stage.find('button.execute').hide();

		this.clockUp();
	}

	clockUp() {
		this.board.step();
		this.updateClockElement();

		if (this.board.executing && !this.board.paused) {
			Promise.all(this.boardElement.animations).then(() => {
				this.boardElement.animations = [];
				this.board.pass();

				if (this.board.clock >= this.board.clockLimit) {
					this.board.halt();
					$.fx.off = params.fx === 'off';

					const $clockLimit = this.$stage.siblings('.result-layer').find('.clock-limit');

					$clockLimit.find('.limit-value').text(this.board.clockLimit);
					$clockLimit.show();
				} else if (this.board.executing && !this.board.paused) {
					this.clockUp();
				}
			});
		}
	}

	updateClockElement() {
		this.$stage.find('.clock-value').text(`${this.board.clock}/${this.board.clockLimit}`);
	}

	onHalt() {
		this.boardElement.animations = [];
		this.boardElement.eraseData();
		this.$stage.find('button.stop').hide();
		this.$stage.find('button.execute').show();
	}

	output(value) {<commit_msg>Fix the border condition of the Stage#clockUp<commit_after>const querystring = require('querystring');
const $ = require('jquery');
const Board = require('./board');
const BoardElement = require('./board-element');
const DataElement = require('./data-element');
const Panel = require('./panel');

const params = querystring.parse(location.search.slice(1));

class Stage {
	constructor(game, config) {
		this.game = game;
		this.config = config;
		this.$stage = this.game.$stage;
		this.blockSize = 50;
		this.caseIndex = 0;
		this.maxClock = 0;

		this.board = new Board(this.config, this.blockSize);
		this.boardElement = new BoardElement(this, this.board);
		this.panel = new Panel(this);

		this.updateStyles();
		this.updateClockElement();

		this.board.on('output', (value) => this.output(value));
		this.board.on('halt', () => this.onHalt());

		this.$stage.find('.statement').text(config.statement);

		this.$selectedBlock = this.$stage.find('.panel .block[selected]').first();

		this.$stage.find('.board .block').click((event) => {
			const $block = $(event.target);
			if (!this.board.executing) {
				const type = this.$selectedBlock.data('type');
				this.panel.takeAndPlace($block.data('x'), $block.data('y'), type);
			}
		});

		this.$stage.find('.board .block').bind('contextmenu', (event) => {
			const $block = $(event.target);
			if (!this.board.executing) {
				this.panel.takeAndPlace($block.data('x'), $block.data('y'), 'empty');
			}
			return false;
		});

		this.$stage.find('.execute').click(() => {
			$.fx.off = params.fx === 'off';
			this.execute();
		});

		this.$stage.find('.stop').click(() => {
			this.board.halt();
			$.fx.off = params.fx === 'off';
		});

		this.$stage.find('.exit').click(() => {
			$.fx.off = params.fx === 'off';
			this.game.exitStage();
		});

		this.$stage.find('.rapid').click(() => {
			if ($.fx.off) {
				$.fx.off = params.fx === 'off';
			} else {
				$.fx.off = true;
				this.boardElement.dataElements.forEach((element) => element.$data.finish());
			}
			if (!this.board.executing) {
				this.execute();
			}
		});

		this.$stage.find('.inputs').empty().append(config.input.map((input) => {
			let inputString = (typeof input === 'number') ? input.toString()
				: input.map((x) => (typeof x === 'number')
					? x.toString() : `[${x.toString()}]`).join(',');
			if (inputString.length > 15) {
				inputString = `${inputString.substring(0, 13)}...`;
			}

			return $('<div/>', {class: 'input'}).append($('<span/>', {
				class: 'inner-text',
				text: inputString,
			}));
		}));

		this.$stage.find('.inputs .input').each((index, input) => {
			const $span = $(input).find('.inner-text');
			const inputWidth = $(input).outerWidth();
			const spanWidth = $span.width();
			if (inputWidth < spanWidth) {
				$span.css({fontSize: `${inputWidth / spanWidth * 100 - 2}%`});
			}
		});

		this.$stage.find('.arrows').empty().append(config.output.map(() => (
			$('<div/>', {class: 'arrow'})
		)));

		this.$stage.find('.user-outputs').empty().append(config.output.map(() => (
			$('<div/>', {class: 'output'})
		)));

		this.$stage.find('.correct-outputs').empty().append(config.output.map((output) => (
			$('<div/>', {class: 'output'}).append($('<span/>', {
				class: 'inner-text',
				text: output,
			}
		)))));

		this.$stage.find('.outputs .output').each((index, output) => {
			const $span = $(output).find('.inner-text');
			const outputWidth = $(output).outerWidth();
			const spanWidth = $span.width();
			if (outputWidth < spanWidth) {
				$span.css({fontSize: `${outputWidth / spanWidth * 100 - 2}%`});
			}
		});

		this.$stage.find('button.stop').hide();
		this.$stage.find('button.execute').show();

		this.updateStyles();
	}

	execute() {
		this.caseIndex = 0;
		this.maxClock = 0;
		this.$stage.find('.user-outputs .output').empty().removeClass('correct wrong');

		this.executeCase();
	}

	executeCase() {
		const inputs = this.board.input(this.config.input[this.caseIndex]);
		inputs.forEach((input, index) => {
			input.forEach((value) => {
				new DataElement(this.boardElement, value, this.board.inputBlock[index].top);
			});
		});

		this.$stage.find('button.stop').show();
		this.$stage.find('button.execute').hide();

		this.clockUp();
	}

	clockUp() {
		this.board.step();
		this.updateClockElement();

		if (this.board.executing && !this.board.paused) {
			Promise.all(this.boardElement.animations).then(() => {
				this.boardElement.animations = [];
				this.board.pass();

				if (this.board.executing && !this.board.paused) {
					if (this.board.clock < this.board.clockLimit) {
						this.clockUp();
					} else {
						this.board.halt();
						$.fx.off = params.fx === 'off';

						const $clockLimit = this.$stage.siblings('.result-layer').find('.clock-limit');

						$clockLimit.find('.limit-value').text(this.board.clockLimit);
						$clockLimit.show();
					}
				}
			});
		}
	}

	updateClockElement() {
		this.$stage.find('.clock-value').text(`${this.board.clock}/${this.board.clockLimit}`);
	}

	onHalt() {
		this.boardElement.animations = [];
		this.boardElement.eraseData();
		this.$stage.find('button.stop').hide();
		this.$stage.find('button.execute').show();
	}

	output(value) {
{'fraction_non_alphanumeric': 0.23446272991287512, 'fraction_numerical': 0.003872216844143272, 'mean_word_length': 3.559135039717564, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 56, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '595789', 'n_tokens_mistral': 4031, 'n_tokens_neox': 3447, 'n_words': 518}