<commit_before>class CSV {
	constructor(data) {
		this.data = data;
	}
	toString() {
		const regexp = /"/g;
		return this.data.map(l => l.map(c => '"' + c.replace(regexp, '""') + '"').join(',')).join('\n');
	}
	toBlob() {
		return new Blob([this.toString()], {type: CSV.MIME_TYPE});
	}
	download(name) {
		const filename = name || new Date().toFullDisplay();
		const blob = this.toBlob();
		const file = new File([blob], filename, {type: CSV.MIME_TYPE, lastModified: Date.now()});
		const url = window.URL.createObjectURL(file);
		//Chrome does not support to set location href
		if(/Chrome/.test(navigator.userAgent)) {
			const link = document.createFullElement('a', {href: url, download: filename});
			const event = document.createEvent('MouseEvents');
			event.initUIEvent('click', true, true, window, 1);
			link.dispatchEvent(event);
		}
		else {
			location.href = url;
		}
		//revoke url after event has been dispatched
		setTimeout(function() {
			window.URL.revokeObjectURL(url);
		}, 0);
	}
}<commit_msg>Handle cells with undefined data<commit_after>const regexp = /"/g;

function generate_line(line) {
	return line
		.map(cell => cell || '')
		.map(cell => `"${cell.replace(regexp, '""')}"`)
		.join(',');
}

class CSV {
	constructor(data) {
		this.data = data;
	}
	toString() {
		return this.data.map(generate_line).join('\n');
	}
	toBlob() {
		return new Blob([this.toString()], {type: CSV.MIME_TYPE});
	}
	download(name) {
		const filename = name || new Date().toFullDisplay();
		const blob = this.toBlob();
		const file = new File([blob], filename, {type: CSV.MIME_TYPE, lastModified: Date.now()});
		const url = window.URL.createObjectURL(file);
		//Chrome does not support to set location href
		if(/Chrome/.test(navigator.userAgent)) {
			const link = document.createFullElement('a', {href: url, download: filename});
			const event = document.createEvent('MouseEvents');
			event.initEvent('click', true, true);
			link.dispatchEvent(event);
		}
		else {
			location.href = url;
		}
		//revoke url after event has been dispatched
		setTimeout(function() {
			window.URL.revokeObjectURL(url);
		}, 0);
	}
}
{'fraction_non_alphanumeric': 0.17826904985888994, 'fraction_numerical': 0.0014111006585136407, 'mean_word_length': 4.064285714285714, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4160950', 'n_tokens_mistral': 794, 'n_tokens_neox': 723, 'n_words': 166}