<commit_before>function toId() {
	// toId has been renamed toID
	alert("You have an old extension/script for Pokemon Showdown which is incompatible with this client. It needs to be removed or updated.");
}

(function ($) {

	Config.sockjsprefix = '/showdown';
	Config.root = '/';

	if (window.nodewebkit) {
		window.gui = require('nw.gui');
		window.nwWindow = gui.Window.get();
	}
	if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
		// Android mobile-web-app-capable doesn't support it very well, but iOS
		// does it fine, so we're only going to show this to iOS for now
		window.isiOS = true;
		$('head').append('<meta name="apple-mobile-web-app-capable" content="yes" />');
	}

	$(document).on('keydown', function (e) {
		if (e.keyCode == 27) { // Esc
			e.preventDefault();
			e.stopPropagation();
			e.stopImmediatePropagation();
			app.closePopup();
		}
	});
	$(window).on('dragover', function (e) {
		if (/^text/.test(e.target.type)) return; // Ignore text fields

		e.preventDefault();
	});
	$(document).on('dragenter', function (e) {
		if (/^text/.test(e.target.type)) return; // Ignore text fields

		e.preventDefault();

		if (!app.dragging && app.curRoom.id === 'teambuilder') {
			var dataTransfer = e.originalEvent.dataTransfer;
			if (dataTransfer.files && dataTransfer.files[0]) {
				var file = dataTransfer.files[0];
				if (file.name.slice(-4) === '.txt') {
					// Someone dragged in a .txt file, hand it to the teambuilder
					app.curRoom.defaultDragEnterTeam(e);
				}
			} else if (dataTransfer.items && dataTransfer.items[0]) {
				// no files or no permission to access files
				var item = dataTransfer.items[0];
				if (item.kind === 'file' && item.type === 'text/plain') {
					// Someone dragged in a .txt file, hand it to the teambuilder
					app.curRoom.defaultDragEnterTeam(e);
				}
			}
		}

		// dropEffect !== 'none' prevents buggy bounce-back animation in
		// Chrome/Safari/Opera
		e.originalEvent.dataTransfer.dropEffect = 'move';
	});
	$(window).on('drop', function (e) {
		if (/^text/.test(e.target.type)) return; // Ignore text fields

		// The default team drop action for Firefox is to open the team as a
		// URL, which needs to be prevented.
		// The default file drop action for most browsers is to open the file
		// in the tab, which is generally undesirable anyway.
		e.preventDefault();
		if (app.dragging && app.draggingRoom) {
			app.rooms[app.draggingRoom].defaultDropTeam(e);
		} else if (e.originalEvent.dataTransfer.files && e.originalEvent.dataTransfer.files[0]) {
			var file = e.originalEvent.dataTransfer.files[0];
			if (file.name.slice(-4) === '.txt' && app.curRoom.id === 'teambuilder') {
				// Someone dragged in a .txt file, hand it to the teambuilder
				app.curRoom.defaultDragEnterTeam(e);
				app.curRoom.defaultDropTeam(e);
			} else if (file.type && file.type.substr(0, 6) === 'image/') {
				// It's an image file, try to set it as a background
				CustomBackgroundPopup.readFile(file);
			} else if (file.type && file.type === 'text/html') {
				BattleRoom.readReplayFile(file);
			}
		}
	});
	if (window.nodewebkit) {
		$(document).on("contextmenu", function (e) {
			e.preventDefault();
			var target = e.target;
			var isEditable = (target.tagName === 'TEXTAREA' || target.tagName === 'INPUT');
			var menu = new gui.Menu();

			if (isEditable) menu.append(new gui.MenuItem({
				label: "Cut",
				click: function () {
					document.execCommand("cut");
				}
			}));
			var link = $(target).closest('a')[0];
			if (link) menu.append(new gui.MenuItem({
				label: "Copy Link URL",
				click: function () {
					gui.Clipboard.get().set(link.href);
				}
			}));
			if (target.tagName === 'IMG') menu.append(new gui.MenuItem({
				label: "Copy Image URL",
				click: function () {
					gui.Clipboard.get().set(target.src);
				}
			}));
			menu.append(new gui.MenuItem({
				label: "Copy",
				click: function () {
					document.execCommand("copy");
				}
			}));
			if (isEditable) menu.append(new gui.MenuItem({
				label: "Paste",
				enabled: !!gui.Clipboard.get().get(),
				click: function () {
					document.execCommand("paste");
				}
			}));

			menu.popup(e.originalEvent.x, e.originalEvent.y);
		});
	}

	// support Safari 6 notifications
	if (!window.Notification && window.webkitNotification) {
		window.Notification = window.webkitNotification;
	}

	// this is called being lazy
	window.selectTab = function (tab) {
		app.tryJoinRoom(tab);
		return false;
	};

	var User = this.User = Backbone.Model.extend({
		defaults: {
			name: '',
			userid: '',
			registered: false,
			named: false,
			avatar: 0,
			settings: {},
			status: '',
			away: false
		},
		initialize: function () {
			app.addGlobalListeners();
			app.on('response:userdetails', function (data) {
				if (data.userid === this.get('userid')) {
					this.set('avatar', '' + data.avatar);
				}
			}, this);
			var self = this;
			this.on('change:name', function () {
				if (!self.get('named')) {
					self.nameRegExp = null;
				} else {
					var escaped = self.get('name').replace(/[^A-Za-z0-9]+$/, '');
					// we'll use `,` as a sentinel character to mean "any non-alphanumeric char"
					// unicode characters can be replaced with any non-alphanumeric char
					for (var i = escaped.length - 1; i > 0; i--) {
						if (/[^\ -\~]/.test(escaped[i])) {
							escaped = escaped.slice(0, i) + ',' + escaped.slice(i + 1);
						}
					}
					escaped = escaped.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
					escaped = escaped.replace(/,/g, "[^A-Za-z0-9]?");
					self.nameRegExp = new RegExp('(?:\\b|(?!\\w))' + escaped + '(?:\\b|\\B(?!\\w))', 'i');
				}
			});
			this.on('change:settings', function () {
				Storage.prefs('serversettings', self.get('settings'));
			});

			var replaceList = {'A': 'ＡⱯȺ', 'B': 'ＢƂƁɃ', 'C': 'ＣꜾȻ', 'D': 'ＤĐƋƊƉꝹ', 'E': 'ＥƐƎ', 'F': 'ＦƑꝻ', 'G': 'ＧꞠꝽꝾ', 'H': 'ＨĦⱧⱵꞍ', 'I': 'ＩƗ', 'J': 'ＪɈ', 'K': 'ＫꞢ', 'L': 'ＬꝆꞀ', 'M': 'ＭⱮƜ', 'N': 'ＮȠƝꞐꞤ', 'O': 'ＯǪǬØǾƆƟꝊꝌ', 'P': 'ＰƤⱣꝐꝒꝔ', 'Q': 'ＱꝖꝘɊ', 'R': 'ＲɌⱤꝚꞦꞂ', 'S': 'ＳẞꞨꞄ', 'T': 'ＴŦƬƮȾꞆ', 'U': 'ＵɄ', 'V': 'ＶƲꝞɅ', 'W': 'ＷⱲ', 'X': 'Ｘ', 'Y': 'ＹɎỾ', 'Z': 'ＺƵȤⱿⱫꝢ', 'a': 'ａąⱥɐ', 'b': 'ｂƀƃɓ', 'c': 'ｃȼꜿↄ', 'd': 'ｄđƌɖɗꝺ', 'e': 'ｅɇɛǝ', 'f': 'ｆḟƒꝼ', 'g': 'ｇɠꞡᵹꝿ', 'h': 'ｈħⱨⱶɥ', 'i': 'ｉɨı', 'j': 'ｊɉ', 'k': 'ｋƙⱪꝁꝃꝅꞣ', 'l': 'ｌſłƚɫⱡꝉꞁꝇ', 'm': 'ｍɱɯ', 'n': 'ｎƞɲŉꞑꞥ', 'o': 'ｏǫǭøǿɔꝋꝍɵ', 'p': 'ｐƥᵽꝑꝓꝕ', 'q': 'ｑɋꝗꝙ', 'r': 'ｒɍɽꝛꞧꞃ', 's': 'ｓꞩꞅẛ', 't': 'ｔŧƭʈⱦꞇ', 'u': 'ｕưừứữửựųṷṵʉ', 'v': 'ｖʋꝟʌ', 'w': 'ｗⱳ', 'x': 'ｘ', 'y': 'ｙɏỿ', 'z': 'ｚƶȥɀⱬꝣ', 'AA': 'Ꜳ', 'AE': 'ÆǼǢ', 'AO': 'Ꜵ', 'AU': 'Ꜷ', 'AV': 'ꜸꜺ', 'AY': 'Ꜽ', 'DZ': 'ǱǄ', 'Dz': 'ǲǅ', 'LJ': 'Ǉ', 'Lj': 'ǈ', 'NJ': 'Ǌ', 'Nj': 'ǋ', 'OI': 'Ƣ', 'OO': 'Ꝏ', 'OU': 'Ȣ', 'TZ': 'Ꜩ', 'VY': 'Ꝡ', 'aa': 'ꜳ', 'ae': 'æǽǣ', 'ao': 'ꜵ', 'au': 'ꜷ', 'av': 'ꜹꜻ', 'ay': 'ꜽ', 'dz': 'ǳǆ', 'hv': 'ƕ', 'lj': 'ǉ', 'nj': 'ǌ', 'oi': 'ƣ', 'ou': 'ȣ', 'oo': 'ꝏ', 'ss': 'ß', 'tz': 'ꜩ', 'vy': 'ꝡ'};
			var normalizeList = {'A': 'ÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄ', 'B': 'ḂḄḆ', 'C': 'ĆĈĊČÇḈƇ', 'D': 'ḊĎḌḐḒḎ', 'E': 'ÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚ', 'F': 'Ḟ', 'G': 'ǴĜḠĞĠǦĢǤƓ', 'H': 'ĤḢḦȞḤḨḪ', 'I': 'ÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬ', 'J': 'Ĵ', 'K': 'ḰǨḲĶḴƘⱩꝀꝂꝄ', 'L': 'ĿĹĽḶḸĻḼḺŁȽⱢⱠꝈ', 'M': 'ḾṀṂ', 'N': 'ǸŃÑṄŇṆŅṊṈ', 'O': 'ÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘ', 'P': 'ṔṖ', 'Q': '', 'R': 'ŔṘŘȐȒṚṜŖṞ', 'S': 'ŚṤŜṠŠṦṢṨȘŞⱾ', 'T': 'ṪŤṬȚŢṰṮ', 'U': 'ÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴ', 'V': 'ṼṾ', 'W': 'ẀẂŴẆẄẈ', 'X': 'ẊẌ', 'Y': 'ỲÝŶỸȲẎŸỶỴƳ', 'Z': 'ŹẐŻŽẒẔ', 'a': 'ẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁ', 'b': 'ḃḅḇ', 'c': 'ćĉċčçḉƈ', 'd': 'ḋďḍḑḓḏ', 'e': 'èéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛ', 'f': '', 'g': 'ǵĝḡğġǧģǥ', 'h': 'ĥḣḧȟḥḩḫẖ', 'i': 'ìíîĩīĭïḯỉǐȉȋịįḭ', 'j': 'ĵǰ', 'k': 'ḱǩḳķḵ', 'l': 'ŀĺľḷḹļḽḻ', 'm': 'ḿṁṃ', 'n': 'ǹńñṅňṇņṋṉ', 'o': 'òóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộ', 'p': 'ṕṗ', 'q': '', 'r': 'ŕṙřȑȓṛṝŗṟ', 's': 'śṥŝṡšṧṣṩșşȿ', 't': 'ṫẗťṭțţṱṯ', 'u': 'ùúûũṹūṻŭüǜǘǖǚủůűǔȕȗụṳ', 'v': 'ṽṿ', 'w': 'ẁẃŵẇẅẘẉ', 'x': 'ẋẍ', 'y': 'ỳýŷỹȳẏÿỷẙỵƴ', 'z': 'źẑżžẓẕ'};
			for (var i in replaceList) {
				replaceList[i] = new RegExp('[' + replaceList[i] + ']', 'g');
			}
			for (var i in normalizeList) {
				normalizeList[i] = new RegExp('[' + normalizeList[i] + ']', 'g');
			}
			this.replaceList = replaceList;
			this.normalizeList = normalizeList;
		},
		updateSetting: function (setting, value) {
			var settings = _.clone(this.get('settings'));
			if (settings[setting] !== value) {
				switch (setting) {
				case 'blockPMs':
					app.send(value ? '/blockpms' : '/unblockpms');
					break;
				case 'blockChallenges':
					app.send(value ? '/blockchallenges' : '/unblockchallenges');
					break;
				case 'language':
					app.send('/language ' + value);
					break;<commit_msg>Persist blocking PMs by rank (#1628)<commit_after>function toId() {
	// toId has been renamed toID
	alert("You have an old extension/script for Pokemon Showdown which is incompatible with this client. It needs to be removed or updated.");
}

(function ($) {

	Config.sockjsprefix = '/showdown';
	Config.root = '/';

	if (window.nodewebkit) {
		window.gui = require('nw.gui');
		window.nwWindow = gui.Window.get();
	}
	if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
		// Android mobile-web-app-capable doesn't support it very well, but iOS
		// does it fine, so we're only going to show this to iOS for now
		window.isiOS = true;
		$('head').append('<meta name="apple-mobile-web-app-capable" content="yes" />');
	}

	$(document).on('keydown', function (e) {
		if (e.keyCode == 27) { // Esc
			e.preventDefault();
			e.stopPropagation();
			e.stopImmediatePropagation();
			app.closePopup();
		}
	});
	$(window).on('dragover', function (e) {
		if (/^text/.test(e.target.type)) return; // Ignore text fields

		e.preventDefault();
	});
	$(document).on('dragenter', function (e) {
		if (/^text/.test(e.target.type)) return; // Ignore text fields

		e.preventDefault();

		if (!app.dragging && app.curRoom.id === 'teambuilder') {
			var dataTransfer = e.originalEvent.dataTransfer;
			if (dataTransfer.files && dataTransfer.files[0]) {
				var file = dataTransfer.files[0];
				if (file.name.slice(-4) === '.txt') {
					// Someone dragged in a .txt file, hand it to the teambuilder
					app.curRoom.defaultDragEnterTeam(e);
				}
			} else if (dataTransfer.items && dataTransfer.items[0]) {
				// no files or no permission to access files
				var item = dataTransfer.items[0];
				if (item.kind === 'file' && item.type === 'text/plain') {
					// Someone dragged in a .txt file, hand it to the teambuilder
					app.curRoom.defaultDragEnterTeam(e);
				}
			}
		}

		// dropEffect !== 'none' prevents buggy bounce-back animation in
		// Chrome/Safari/Opera
		e.originalEvent.dataTransfer.dropEffect = 'move';
	});
	$(window).on('drop', function (e) {
		if (/^text/.test(e.target.type)) return; // Ignore text fields

		// The default team drop action for Firefox is to open the team as a
		// URL, which needs to be prevented.
		// The default file drop action for most browsers is to open the file
		// in the tab, which is generally undesirable anyway.
		e.preventDefault();
		if (app.dragging && app.draggingRoom) {
			app.rooms[app.draggingRoom].defaultDropTeam(e);
		} else if (e.originalEvent.dataTransfer.files && e.originalEvent.dataTransfer.files[0]) {
			var file = e.originalEvent.dataTransfer.files[0];
			if (file.name.slice(-4) === '.txt' && app.curRoom.id === 'teambuilder') {
				// Someone dragged in a .txt file, hand it to the teambuilder
				app.curRoom.defaultDragEnterTeam(e);
				app.curRoom.defaultDropTeam(e);
			} else if (file.type && file.type.substr(0, 6) === 'image/') {
				// It's an image file, try to set it as a background
				CustomBackgroundPopup.readFile(file);
			} else if (file.type && file.type === 'text/html') {
				BattleRoom.readReplayFile(file);
			}
		}
	});
	if (window.nodewebkit) {
		$(document).on("contextmenu", function (e) {
			e.preventDefault();
			var target = e.target;
			var isEditable = (target.tagName === 'TEXTAREA' || target.tagName === 'INPUT');
			var menu = new gui.Menu();

			if (isEditable) menu.append(new gui.MenuItem({
				label: "Cut",
				click: function () {
					document.execCommand("cut");
				}
			}));
			var link = $(target).closest('a')[0];
			if (link) menu.append(new gui.MenuItem({
				label: "Copy Link URL",
				click: function () {
					gui.Clipboard.get().set(link.href);
				}
			}));
			if (target.tagName === 'IMG') menu.append(new gui.MenuItem({
				label: "Copy Image URL",
				click: function () {
					gui.Clipboard.get().set(target.src);
				}
			}));
			menu.append(new gui.MenuItem({
				label: "Copy",
				click: function () {
					document.execCommand("copy");
				}
			}));
			if (isEditable) menu.append(new gui.MenuItem({
				label: "Paste",
				enabled: !!gui.Clipboard.get().get(),
				click: function () {
					document.execCommand("paste");
				}
			}));

			menu.popup(e.originalEvent.x, e.originalEvent.y);
		});
	}

	// support Safari 6 notifications
	if (!window.Notification && window.webkitNotification) {
		window.Notification = window.webkitNotification;
	}

	// this is called being lazy
	window.selectTab = function (tab) {
		app.tryJoinRoom(tab);
		return false;
	};

	var User = this.User = Backbone.Model.extend({
		defaults: {
			name: '',
			userid: '',
			registered: false,
			named: false,
			avatar: 0,
			settings: {},
			status: '',
			away: false
		},
		initialize: function () {
			app.addGlobalListeners();
			app.on('response:userdetails', function (data) {
				if (data.userid === this.get('userid')) {
					this.set('avatar', '' + data.avatar);
				}
			}, this);
			var self = this;
			this.on('change:name', function () {
				if (!self.get('named')) {
					self.nameRegExp = null;
				} else {
					var escaped = self.get('name').replace(/[^A-Za-z0-9]+$/, '');
					// we'll use `,` as a sentinel character to mean "any non-alphanumeric char"
					// unicode characters can be replaced with any non-alphanumeric char
					for (var i = escaped.length - 1; i > 0; i--) {
						if (/[^\ -\~]/.test(escaped[i])) {
							escaped = escaped.slice(0, i) + ',' + escaped.slice(i + 1);
						}
					}
					escaped = escaped.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
					escaped = escaped.replace(/,/g, "[^A-Za-z0-9]?");
					self.nameRegExp = new RegExp('(?:\\b|(?!\\w))' + escaped + '(?:\\b|\\B(?!\\w))', 'i');
				}
			});
			this.on('change:settings', function () {
				Storage.prefs('serversettings', self.get('settings'));
			});

			var replaceList = {'A': 'ＡⱯȺ', 'B': 'ＢƂƁɃ', 'C': 'ＣꜾȻ', 'D': 'ＤĐƋƊƉꝹ', 'E': 'ＥƐƎ', 'F': 'ＦƑꝻ', 'G': 'ＧꞠꝽꝾ', 'H': 'ＨĦⱧⱵꞍ', 'I': 'ＩƗ', 'J': 'ＪɈ', 'K': 'ＫꞢ', 'L': 'ＬꝆꞀ', 'M': 'ＭⱮƜ', 'N': 'ＮȠƝꞐꞤ', 'O': 'ＯǪǬØǾƆƟꝊꝌ', 'P': 'ＰƤⱣꝐꝒꝔ', 'Q': 'ＱꝖꝘɊ', 'R': 'ＲɌⱤꝚꞦꞂ', 'S': 'ＳẞꞨꞄ', 'T': 'ＴŦƬƮȾꞆ', 'U': 'ＵɄ', 'V': 'ＶƲꝞɅ', 'W': 'ＷⱲ', 'X': 'Ｘ', 'Y': 'ＹɎỾ', 'Z': 'ＺƵȤⱿⱫꝢ', 'a': 'ａąⱥɐ', 'b': 'ｂƀƃɓ', 'c': 'ｃȼꜿↄ', 'd': 'ｄđƌɖɗꝺ', 'e': 'ｅɇɛǝ', 'f': 'ｆḟƒꝼ', 'g': 'ｇɠꞡᵹꝿ', 'h': 'ｈħⱨⱶɥ', 'i': 'ｉɨı', 'j': 'ｊɉ', 'k': 'ｋƙⱪꝁꝃꝅꞣ', 'l': 'ｌſłƚɫⱡꝉꞁꝇ', 'm': 'ｍɱɯ', 'n': 'ｎƞɲŉꞑꞥ', 'o': 'ｏǫǭøǿɔꝋꝍɵ', 'p': 'ｐƥᵽꝑꝓꝕ', 'q': 'ｑɋꝗꝙ', 'r': 'ｒɍɽꝛꞧꞃ', 's': 'ｓꞩꞅẛ', 't': 'ｔŧƭʈⱦꞇ', 'u': 'ｕưừứữửựųṷṵʉ', 'v': 'ｖʋꝟʌ', 'w': 'ｗⱳ', 'x': 'ｘ', 'y': 'ｙɏỿ', 'z': 'ｚƶȥɀⱬꝣ', 'AA': 'Ꜳ', 'AE': 'ÆǼǢ', 'AO': 'Ꜵ', 'AU': 'Ꜷ', 'AV': 'ꜸꜺ', 'AY': 'Ꜽ', 'DZ': 'ǱǄ', 'Dz': 'ǲǅ', 'LJ': 'Ǉ', 'Lj': 'ǈ', 'NJ': 'Ǌ', 'Nj': 'ǋ', 'OI': 'Ƣ', 'OO': 'Ꝏ', 'OU': 'Ȣ', 'TZ': 'Ꜩ', 'VY': 'Ꝡ', 'aa': 'ꜳ', 'ae': 'æǽǣ', 'ao': 'ꜵ', 'au': 'ꜷ', 'av': 'ꜹꜻ', 'ay': 'ꜽ', 'dz': 'ǳǆ', 'hv': 'ƕ', 'lj': 'ǉ', 'nj': 'ǌ', 'oi': 'ƣ', 'ou': 'ȣ', 'oo': 'ꝏ', 'ss': 'ß', 'tz': 'ꜩ', 'vy': 'ꝡ'};
			var normalizeList = {'A': 'ÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄ', 'B': 'ḂḄḆ', 'C': 'ĆĈĊČÇḈƇ', 'D': 'ḊĎḌḐḒḎ', 'E': 'ÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚ', 'F': 'Ḟ', 'G': 'ǴĜḠĞĠǦĢǤƓ', 'H': 'ĤḢḦȞḤḨḪ', 'I': 'ÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬ', 'J': 'Ĵ', 'K': 'ḰǨḲĶḴƘⱩꝀꝂꝄ', 'L': 'ĿĹĽḶḸĻḼḺŁȽⱢⱠꝈ', 'M': 'ḾṀṂ', 'N': 'ǸŃÑṄŇṆŅṊṈ', 'O': 'ÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘ', 'P': 'ṔṖ', 'Q': '', 'R': 'ŔṘŘȐȒṚṜŖṞ', 'S': 'ŚṤŜṠŠṦṢṨȘŞⱾ', 'T': 'ṪŤṬȚŢṰṮ', 'U': 'ÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴ', 'V': 'ṼṾ', 'W': 'ẀẂŴẆẄẈ', 'X': 'ẊẌ', 'Y': 'ỲÝŶỸȲẎŸỶỴƳ', 'Z': 'ŹẐŻŽẒẔ', 'a': 'ẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁ', 'b': 'ḃḅḇ', 'c': 'ćĉċčçḉƈ', 'd': 'ḋďḍḑḓḏ', 'e': 'èéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛ', 'f': '', 'g': 'ǵĝḡğġǧģǥ', 'h': 'ĥḣḧȟḥḩḫẖ', 'i': 'ìíîĩīĭïḯỉǐȉȋịįḭ', 'j': 'ĵǰ', 'k': 'ḱǩḳķḵ', 'l': 'ŀĺľḷḹļḽḻ', 'm': 'ḿṁṃ', 'n': 'ǹńñṅňṇņṋṉ', 'o': 'òóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộ', 'p': 'ṕṗ', 'q': '', 'r': 'ŕṙřȑȓṛṝŗṟ', 's': 'śṥŝṡšṧṣṩșşȿ', 't': 'ṫẗťṭțţṱṯ', 'u': 'ùúûũṹūṻŭüǜǘǖǚủůűǔȕȗụṳ', 'v': 'ṽṿ', 'w': 'ẁẃŵẇẅẘẉ', 'x': 'ẋẍ', 'y': 'ỳýŷỹȳẏÿỷẙỵƴ', 'z': 'źẑżžẓẕ'};
			for (var i in replaceList) {
				replaceList[i] = new RegExp('[' + replaceList[i] + ']', 'g');
			}
			for (var i in normalizeList) {
				normalizeList[i] = new RegExp('[' + normalizeList[i] + ']', 'g');
			}
			this.replaceList = replaceList;
			this.normalizeList = normalizeList;
		},
		updateSetting: function (setting, value) {
			var settings = _.clone(this.get('settings'));
			if (settings[setting] !== value) {
				switch (setting) {
				case 'blockPMs':
					app.send(value ? '/blockpms ' + value : '/unblockpms');
					break;
				case 'blockChallenges':
					app.send(value ? '/blockchallenges' : '/unblockchallenges');
					break;
				case 'language':
					app.send('/language ' + value);
					break;
{'fraction_non_alphanumeric': 0.2352872489490892, 'fraction_numerical': 0.002919196637085474, 'mean_word_length': 3.5350807519195127, 'pattern_counts': {'":': 0, '<': 5, '<?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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1114700', 'n_tokens_mistral': 9996, 'n_tokens_neox': 8860, 'n_words': 1579}