<commit_before>const path = require('path');
const chalk = require('chalk');
const settings = require('../../settings.js');
const dfu = require('../lib/dfu');
const when = require('when');
const whenNode = require('when/node');
const Spinner = require('cli-spinner').Spinner;
const fs = require('fs');
const deviceSpecs = require('../lib/deviceSpecs');

Spinner.setDefaultSpinnerString(Spinner.spinners[7]);
const spin = new Spinner('Updating system firmware on the device...');

class UpdateCommand {
	updateDevice() {
		// by default we don't want crazy DFU output
		settings.verboseOutput = false;

		return dfu.findCompatibleDFU().then((deviceId) => {
			return doUpdate(deviceId);
		}).catch((err) => {
			return dfuError(err);
		});
	}
}

function doUpdate(id) {
	const updates = settings.updates[id] || null;
	const steps = [];

	if (!updates) {
		console.log();
		return console.log(
			chalk.cyan('!'),
			'There are currently no system firmware updates available for this device.'
		);
	}
	const parts = Object.keys(updates);
	const specs = deviceSpecs[id];
    /**
	 * Some firmwares also require updating the system bootloader.
     */
	if (specs.requiresBootloaderAscenderApp) {
		const filename = 'user_firmware_backup.bin';

		steps.push((next) => {
			if (fs.existsSync(path)) {
				fs.unlinkSync(filename);
			}

			// save the current user firmware
			whenNode.bindCallback(
                dfu.read(filename, 'userFirmware', false)
                , next);
		});

		steps.push((next) => {
			whenNode.bindCallback(
                dfu.write(filename, 'otaRegion', false)
                , next);
		});
	}

	parts.forEach((part, partNumber) => {
		steps.push((next) => {
			const binary = path.resolve(__dirname, '../../assets/updates', updates[part]);
			const leave = partNumber === parts.length - 1;
			whenNode.bindCallback(
				dfu.write(binary, part, leave).delay(2000)
				, next);
		});
	});

	console.log();
	console.log(chalk.cyan('>'), 'Your device is ready for a system update.');
	console.log(chalk.cyan('>'), 'This process should take about 30 seconds. Here it goes!');
	console.log();

	if (!settings.verboseOutput) {
		spin.start();
	}

	return when.promise((resolve, reject) => {
		flash();
		function flash(err) {
			if (err) {
				return failure(err);
			}
			if (steps.length > 0) {
				return steps.shift()(flash);
			}
			success();
		}

		function success() {
			spin.stop(true);
			console.log(chalk.cyan('!'), 'System firmware update successfully completed!');
			console.log();<commit_msg>delete user_firmware_backup.bin after use using utilities, update timing estimate to 50s<commit_after>const path = require('path');
const chalk = require('chalk');
const settings = require('../../settings.js');
const dfu = require('../lib/dfu');
const when = require('when');
const whenNode = require('when/node');
const Spinner = require('cli-spinner').Spinner;
const fs = require('fs');
const deviceSpecs = require('../lib/deviceSpecs');
const utilities = require('../lib/utilities.js');

Spinner.setDefaultSpinnerString(Spinner.spinners[7]);
const spin = new Spinner('Updating system firmware on the device...');

class UpdateCommand {
	updateDevice() {
		// by default we don't want crazy DFU output
		settings.verboseOutput = false;

		return dfu.findCompatibleDFU().then((deviceId) => {
			return doUpdate(deviceId);
		}).catch((err) => {
			return dfuError(err);
		});
	}
}

function doUpdate(id) {
	const updates = settings.updates[id] || null;
	const steps = [];

	if (!updates) {
		console.log();
		return console.log(
			chalk.cyan('!'),
			'There are currently no system firmware updates available for this device.'
		);
	}
	const parts = Object.keys(updates);
	const specs = deviceSpecs[id];
	/**
	 * Some firmwares also require updating the system bootloader.
	 */
	if (specs.requiresBootloaderAscenderApp) {
		const filename = 'user_firmware_backup.bin';

		steps.push((next) => {
			utilities.tryDelete(filename);

			// save the current user firmware
			whenNode.bindCallback(
				dfu.read(filename, 'userFirmware', false)
				, next);
		});

		steps.push((next) => {
			whenNode.bindCallback(
				dfu.write(filename, 'otaRegion', false)
				, next);
		});

		steps.push((next) => {
			whenNode.bindCallback(
				utilities.tryDelete(filename)
				, next);
		});
	}

	parts.forEach((part, partNumber) => {
		steps.push((next) => {
			const binary = path.resolve(__dirname, '../../assets/updates', updates[part]);
			const leave = partNumber === parts.length - 1;
			whenNode.bindCallback(
				dfu.write(binary, part, leave).delay(2000)
				, next);
		});
	});

	console.log();
	console.log(chalk.cyan('>'), 'Your device is ready for a system update.');
	console.log(chalk.cyan('>'), 'This process should take about ' + (specs.requiresBootloaderAscenderApp?50:30) + ' seconds. Here it goes!');
	console.log();

	if (!settings.verboseOutput) {
		spin.start();
	}

	return when.promise((resolve, reject) => {
		flash();
		function flash(err) {
			if (err) {
				return failure(err);
			}
			if (steps.length > 0) {
				return steps.shift()(flash);
			}
			success();
		}

		function success() {
			spin.stop(true);
			console.log(chalk.cyan('!'), 'System firmware update successfully completed!');
			console.log();
{'fraction_non_alphanumeric': 0.1655578787302794, 'fraction_numerical': 0.004181714502946208, 'mean_word_length': 3.6773333333333333, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 24, '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': '575796', 'n_tokens_mistral': 1904, 'n_tokens_neox': 1669, 'n_words': 394}