ЧАС-коррект

Исправление наиболее частотных ошибок на просматриваемых страницах

目前為 2015-09-27 提交的版本,檢視 最新版本

// ==UserScript==
// @name          ЧАС-коррект
// @namespace     http://www.example.com/gmscripts
// @description   Исправление наиболее частотных ошибок на просматриваемых страницах
// @include       http://*
// @include       https://*
// @version       0.2.0.1
// ==/UserScript==
(function(){'use strict';
	
/*
Copyright Nikolay Avdeev aka NickKolok aka Николай Авдеев 2015

Всем привет из снежного Воронежа! 

This file is part of CHAS-CORRECT.

    CHAS-CORRECT is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CHAS-CORRECT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CHAS-CORRECT.  If not, see <http://www.gnu.org/licenses/>.

  (Этот файл — часть CHAS-CORRECT.

   CHAS-CORRECT - свободная программа: вы можете перераспространять её и/или
   изменять её на условиях Стандартной общественной лицензии GNU в том виде,
   в каком она была опубликована Фондом свободного программного обеспечения;
   либо версии 3 лицензии, либо (по вашему выбору) любой более поздней
   версии.

   CHAS-CORRECT распространяется в надежде, что она будет полезной,
   но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
   или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
   общественной лицензии GNU.

   Вы должны были получить копию Стандартной общественной лицензии GNU
   вместе с этой программой. Если это не так, см.
   <http://www.gnu.org/licenses/>.)
*/

var storageWrapper={
	///Обёртка над хранилищем, в данном случае - GreaseMonkey
	getKey: function(key,defaultValue){
		return JSON.parse(GM_getValue(key,defaultValue)) || defaultValue;
	},
	setKey: function(key,value){
		GM_setValue(key,JSON.stringify(value));
	},
};


/*
Copyright Nikolay Avdeev aka NickKolok aka Николай Авдеев 2015

Всем привет из снежного Воронежа! 

This file is part of CHAS-CORRECT.

    CHAS-CORRECT is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CHAS-CORRECT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CHAS-CORRECT.  If not, see <http://www.gnu.org/licenses/>.

  (Этот файл — часть CHAS-CORRECT.

   CHAS-CORRECT - свободная программа: вы можете перераспространять её и/или
   изменять её на условиях Стандартной общественной лицензии GNU в том виде,
   в каком она была опубликована Фондом свободного программного обеспечения;
   либо версии 3 лицензии, либо (по вашему выбору) любой более поздней
   версии.

   CHAS-CORRECT распространяется в надежде, что она будет полезной,
   но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
   или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
   общественной лицензии GNU.

   Вы должны были получить копию Стандартной общественной лицензии GNU
   вместе с этой программой. Если это не так, см.
   <http://www.gnu.org/licenses/>.)
*/
'use strict';

var oldTime = new Date().getTime();

var sya="(?=(?:ся|)(?:[^А-Яа-яЁёA-Za-z]|^|$))";
var ca="[цc]+[ао]";

var orphoWordsToCorrect=[
/*
	["",""],
	["",""],
	["",""],
	["",""],
	["",""],
	["",""],
*/
	["по-*которой","по которой"],//Да, и такое бывает. TODO: просклонять
	["про-*запас","про запас"],
	["свеч","свеч"],
	["по-*крайней","по крайней"],
	["н[ао]-*[ао]б[ао]рот","наоборот"],
	["говорю","говорю"],//TODO: проспрягать
	["тол*ь*к[ао]-*что","только что"],
	["покруче","покруче"],
	["поначалу","поначалу"],
	["кое[\s]*где","кое-где"],//TODO: аналоги
	["где-*угодно","где угодно"],
	["луч[ёе]м","лучом"],
	["куда-*как","куда как"],
	["наконец-таки","наконец-таки"],
	["по[\s-]немногу","понемногу"],
	["как-*только","как только"],
	["в-*сч[ёе]т","в счёт"],
	["молодежь","молодежь"],
	["в-*первую","в первую"],
	["понадежнее","понадежнее"],
	["покрупнее","покрупнее"],
	["потому как","потому как"],
	["по сети","по сети"],
	["по-*идее","по идее"],
	["н[еи]зна[еи]т","не знает"],
	["сегодня","сегодня"],
	["зачем-то","зачем-то"],
	["помочь","помочь"],
	["тем-*более","тем более"],
	["так-*что","так что"],
	["иметь в-*виду","иметь в виду"],//TODO: проспрягать
	["как-*нить","как-нибудь"],
	["изменишь","изменишь"],
	["в-*случае","в случае"],
	["так-*как","так как"],
	["во+бще-*то","вообще-то"],
	["рука[\\s-]*об[\\s-]*руку","рука об руку"],
	["вроде-*бы","вроде бы"],
	["по-*возможности","по возможности"],
	["слышь","слышь"],
	["вещь*","вещь"],
	["н[еи][\\s-]+ужели","неужели"],
	["по[\\s]*английски","по-английски"],//TODO: другие языки
	["пол-литра","пол-литра"],
	["не могли","не могли"],//TODO: окончания
	["поподробнее","поподробнее"],
	["тысяч","тысяч"],
	["до-*свидания","до свидания"],
	["до-*свиданья","до свиданья"],
	["м[оа]л[оа]д[её]ж[еи]","молодёжи"],
	["щ[еи]таю","считаю"],
	["кирпич[её]м","кирпичом"],
	["вовремя","вовремя"],
	["по-*факту","по факту"],
	["в[\\s-]*конце[\\s-]*концов","в конце концов"],
	["по-твоему","по-твоему"],
	["режет","режет"],
	["конце-*концов","конце концов"],
	["не[\\s-]гоже","негоже"],
	["по-*делу","по делу"],
	["по[\\s-]пугай","попугай"],
	["по-*отдельности","по отдельности"],
	["вроде","вроде"],
	["по-*аналогии","по аналогии"],
	["не-*совсем","не совсем"],
	["пол-экрана","пол-экрана"],
	["по-лучь*ше","получше"],
	["надо-*бы","надо бы"],
	["на лету","на лету"],//налёт не обижать!
	["что[\\s-]*ле","что ли"],
	["куда ж","куда ж"],
	["не\\s-]*совсем","не совсем"],
	["всего[\\s-]*лишь","всего лишь"],
	["п[ао]дреж","подрежь"],//TODO: приставки
	["ч[иае][вг]о","чего"],
	["б[еи][сз][\\s-]*п[оа]нят[ие]я","без понятия"],
	["как[\\s-]*н[ие][\\s-]*в[\\s-]*ч[еёо]м[\\s-]*н[еи][\\s-]*бывало","как ни в чем не бывало"],
	["ни[\\s-]*за[\\s-]*что","ни за что"],
	["движ[её]к","движок"],
	["каждого","каждого"],
	["написано","написано"],
	["по[\\s-]+наслышке","понаслышке"],
	["тысячу","тысячу"],
	["позиционирование","позиционирование"],
	["н[еи]-*надо","не надо"],
	["ни-*черта","ни черта"],
	["тысячи","тысячи"],
	["в[\\s-]*кратце","вкратце"],
	//[Katzen Gott]: может быть стоит вынести "команд" в префиксы? Нортон Командер с одной "м" вроде нормально выглядит
	["команды","команды"],//TODO: просклонять, не обидев Norton Commander. Или обидев.
	["по\\s*аглийски","по-английски"],
//?	["чесслово","честное слово"],
	["как бы","как бы"],
	["в виде","в виде"],
	["в[\\s-]*догонку","вдогонку"],
	["почему","почему"],
	["это-*ж","это ж"],
	["ес+е*с*т*н[оа]","естественно"],
	["к-*стат[еи]","кстати"],
	["по-*поводу","по поводу"],
	["потому что","потому что"],
	["можно","можно"],
	["в-*целом","в целом"],
	["честно","честно"],//TODO: честный и т. д., не обидеть чеснок
	["по-*сути","по сути"],
	["по-*крайней","по крайней"],
	["поэтому","поэтому"],
	["пол-*года","полгода"],
	["со+твет*ст*вен+о","соответственно"],
	["та же","та же"],
	["тот же","тот же"],
	["возможно","возможно"],
	["кто-то","кто-то"],
	["со[бп]с+т*н[оа]","собственно"],
	["ни разу","ни разу"],
	["по-*минимуму","по минимуму"],
	["по-*максимуму","по максимуму"],
	["по\\s*товарищески","по-товарищески"],
	["финиш","финиш"],
	["от-*тудова","оттуда"],
	["временно","временно"],
	["по\\s*обывательски","по-обывательски"],
	["как-*раз","как раз"],
	["в[\\s-]*том[\\s-]*то[\\s-]*и[\\s-]*дело","в том-то и дело"],
	["по[-]больше","побольше"],
	["поменьше","поменьше"],
	["иное","иное"],//TODO: просклонять, лучше - окончания в кучку
	["границы","границы"],
	["в-*принципе","в принципе"],
	["те-*же","те же"],//TODO: допросклонять
	["из-за","из-за"], //[Katzen Gott]: Не уверена, что к этому нет противопоказаний. Если есть — убирайте.
	["из-за","из-за"],
	["тысяч","тысяч"],
	["по-*умолчанию","по умолчанию"],
	["делает","делает"],
	["взяться","взяться"],
	["каждого","каждого"],
	["поменяться","поменяться"],
	["мериться","мериться"],
	["меряться","меряться"],
	["иметься","иметься"],//Поднимется [Katzen Gott]: может это было "имеется"?
	["говорится","говорится"],
	["учатся","учатся"],//Но обучаться
	["пр[ие]д[её]ть*ся","придётся"],
	["какую-*т[уоа]","какую-то"],
	["отве[дт]ь*те","ответьте"],
	["не[\\s-]*охото","неохота"],
	["неохота","неохота"],
	["хотя-*бы","хотя бы"],
	["душ","душ"],
	["какайа-*то","какая-то"],
	["по-геройски","по-геройски"],
	["по соседству","по соседству"],
	["по привычке","по привычке"],
	["ч[ёо]","что"],
	["по новой","по новой"],
	["по русскому","по русскому"],
	["потихоньку","потихоньку"],
	["по полной","по полной"],
	["ес+-н+о","естественно"],
	["по-*старинке","по старинке"],
	["походу","походу"],
	["да-да","да-да"],
	["занят*"+ca,"заняться"],
/*
	[""+ca,""],
	[""+ca,""],
	[""+ca,""],
	[""+ca,""],
*/
	["пяли"+ca,"пялится"],
	["просну"+ca,"проснуться"],
	["меняю"+ca,"меняются"],
	["каже"+ca,"кажется"],
	["верит"+ca,"верится"],
	["кати"+ca,"катиться"],
	["с[чщ]а[сс]*","сейчас"],
	["станови"+ca,"становится"],
	["н[ие]ч[ёео]","ничего"],
	["валя"+ca,"валяться"],
	["валяю"+ca,"валяются"],
	["будто","будто"],
	["то есть","то есть"],
	["чья-то","чья-то"],
	["рыться","рыться"],
	["напиться","напиться"],
	["добиться","добиться"],
	["режется","режется"],
	["уборщица","уборщица"],
	["померять*ся","помериться"],
	["мерять*cя","мериться"],
	["меняться","меняться"],
	["прид[её]ться","придётся"],
	["по умолчанию","по умолчанию"],
	["что нибу[дт]ь","что-нибудь"],
	["помимо","помимо"],
	["кое-как","кое-как"], //TODO: аналоги
	["в[\\s-]*конце[\s-]*то[\\s-]*концов","в конце-то концов"],
	["ни[\\s-]*при[\\s-]*ч[еёо]м","ни при чём"],//Да, это два разных!
	["не[\\s-]*при[\\s-]*ч[еёо]м","не при чем"],
	["не-*зря","не зря"],
	["кстати","кстати"],
	["мужич[ёе]к","мужичок"],
	["однажды","однажды"],
	["повозражав","повозражав"],
//	["сейчас","сейчас"],
	["бе[сз]толоч","бестолочь"],
	["вовнутрь","вовнутрь"],
	["что-*ль","что ль"],//TODO: просклонять
	["говорит","говорит"],//TODO: добить окончаниями
	["что","что"],// [Katzen Gott]: а если это стилистический прием? (для передачи акцента например)
	["эх","эх"],//Ибо сил моих больше нет
	["шт*об","чтоб"],
	["значит","значит"],
	["короче*","короче"],
	["вы б","вы б"],
	["по-женски","по-женски"],
	["при встрече","при встрече"],
	["все же","все же"],
	["всё же","всё же"],
	["не действует","не действует"],
	["красивее","красивее"],
	["доев","доев"],
	["помоги","помоги"],//Помогичить
	["не-*был","не был"],
	["не-*была","не была"],
	["не-*было","не было"],
	["не были","не были"],
	["хоч[еи]м","хотим"],//хохочем
	["хочешь","хочешь"],
	["хоч[еи]те","хотите"],
	["хочет","хочет"],
	["хотят","хотят"],
	["по слухам","по слухам"],
	["под дых","под дых"],
	["полкило","полкило"],
	["н[еи][ -]*в[ -]*ко[еи]м случа[еи]","ни в коем случае"],
	["во-*скоко","во сколько"],
	["вылезает ","вылезает "],//TODO: аналоги
	["и(?:сч|щ|ш)о","ещё"],
	["лучше","лучше"],
	["жизни","жизни"],
	["сидишь","сидишь"],
	["до кучи","до кучи"],
	["к[ао]во","кого"],
	["ч[ёо]нить","что-нибудь"],//Как отличить от "чинить", не знаю
	["ч[еоё]-нить","что-нибудь"],
	["н[ие]з*ь*зя","нельзя"],
	["ч[ёое]гонить","чего-нибудь"],
	["д[ао]фига","очень много"],//Ибо нефиг!
	["ч[ёое]-*то","что-то"],//TODO: дополнить!
	//["миня","меня"],//Нельзя, речка такая есть! [Katzen Gott] речка с большой буквы должна быть. Так что, наверное, можно
	["опять","опять"],
	["н[ие][фв]курс[ие]","не в курсе"],
	["запиши","запиши"],
	["н[ие][ -]над[ао]","не надо"],
	["кто-*нить","кто-нибудь"],//TODO: допросклонять!
	["что-*нить","что-нибудь"],//TODO: допросклонять!
	["нехоц+а","не хочется"],
	["п[ао]любому","по-любому"],
	["наверн[ао]е*","наверное"],
	["ес[ст]+ес+н[ао]","естественно"],
	["я б","я б"],
	["этими","этими"],//TODO: просклонять, не обидев йети!
	["такой же","такой же"],//TODO: просклонять
	["по-*идее","по идее"],
	["жал бы","жал бы"],
	["было бы","было бы"],
	["не влезает","не влезает"],
	["что-*ж","что ж"],
	["катац+о","кататься"],
	["когда","когда"],
	["скуп","скуп"],
	["в-*зад[еи]","сзади"],
	["с-*зад[еи]","сзади"],
	["з-*зад[еи]","сзади"],
	["на[\s-]*р[ао]вне","наравне"],
	["серебряного","серебряного"],//TODO: просклонять
	["со мной","со мной"],
	["сначала","сначала"],
	["ещё","ещё"],
	["её","её"],
	["к[ао]роч[еь]*","короче"],
	["пароль","пароль"],
	["дрожь","дрожь"],
	["жжёт","жжёт"],
	["не хочу","не хочу"],
	["молодёжь","молодёжь"],
	["пуловер","пуловер"],
	["врасплох","врасплох"],
	["продавца","продавца"],
	["в смысле","в смысле"],
	["штол[еь]","что ли"],
	["н[еи]знаю","не знаю"],
	["это ж","это ж"],
	["подожди","подожди"],
	["во-первых","во-первых"],
	["пожалу*ста","пожалуйста"],
//	["бесплатно","бесплатно"],
	["до свидания","до свидания"],
	["вс[её]таки","всё-таки"],
	["в[\s-]кратце","вкратце"],
	["ключ","ключ"],
	["стороной","стороной"],
	["не могу","не могу"],
	["в[-]*о+бщем","в общем"],
	["тоже","тоже"],
	["также","также"],
	["в(?:об|а)ще","вообще"],
//	["пожалуйста","пожалуйста"],//Объединено
	["сколько","сколько"],
	["с[её]дня","сегодня"],
	["потому","потому"],
	["тогда","тогда"],
	["жутко","жутко"],
	["поорать","поорать"],
	["сандалии","сандалии"],
	["что","что"],
	["скачать","скачать"],
//	["отзов(?=(?:ы||а|у|ом|ам|ами))","отзыв"],
	["тролль","тролль"],
	["прийти","прийти"],
	["класть","класть"],
//	["я ложу","кладу"],//Подойти к ложу / подойти к кладу
	["кладём","кладём"],
	["кладёшь","кладёшь"],
	["кладёте","кладёте"],
	["лож[ау]т","кладут"],
	["лож[ие]т","кладёт"],
//	["светой","святой"],//TODO: склонять
	["не могу","не могу"],
	["ночь","ночь"],
	["вконтакте","вконтакте"],
	["что-то","что-то"],
	["с кем","с кем"],
	["смотреть","смотреть"],
	["ихн(?:ий|его|ему|им|ем|её|яя|ей|юю|ие|их|ими)","их"],
	["натощак","натощак"],
	["что ли","что ли"],
	["здесь","здесь"],
	["не за что","не за что"],
	["колеса","колеса"],
	["какойт[ао]","какой-то"],//TODO: допросклонять
	["какиет[ао]","какие-то"],
	["какаят[ао]","какая-то"],
	["то есть","то есть"],
	["по-другому","по-другому"],
	["значит[её]к","значок"],
	["вкратце","вкратце"],
	["напоследок","напоследок"],
	["по-*мо[ей]му","по-моему"],
	["положить","положить"],
	["никого","никого"],
	["когда","когда"],
	["п[ао]ч[ие]му","почему"],
	["наконец-то","наконец-то"],
	["где бы","где бы"],
	["вс[её]-*время","всё время"],
	["чуть-*ли","чуть ли"],
	["вря[дт]-*ли","вряд ли"],
	["ка[кг]-*бу[дт]то","как будто"],
	["вдогонку","вдогонку"],
	["экспрес*о","эспрессо"],
	["в смысле","в смысле"],
	["вообще","вообще"],
	["потому что","потому что"],
	["что бы","чтобы"],
	["что бы","чтобы"],
	["видите","видите"],//TODO: проспрягать
	["видишь","видишь"],
	["видит","видит"],
	["видим","видим"], //[Katzen Gott]: тут вроде все. Может быть можно как-то их "склеить"?
	["вдогонку","вдогонку"],
	["сп[оа]сиб[оа]","спасибо"],
	["типа","типа"],
	["грамот","грамот"],
	["к[ао]не[шч]но","конечно"], //[Katzen Gott]: надеюсь, я все правильно сделала...
	["ключ[её]м","ключом"],
	["не дай","не дай"],
	["нович[ёе]к","новичок"],
	["надо","надо"],
	["вс[её]-*равно","всё равно"],
	["то бишь","то бишь"],
	["забеременею","забеременею"],
	["не завалялся","не завалялся"],
	["не поверишь","не поверишь"],
	["ни к чему","ни к чему"],
	["щ[ая][сз]*","сейчас"],
	["балкон","балкон"],//TODO: просклонять, не обидев князя Болконского
	["хочешь","хочешь"],
	["очень*(?!-ч)","очень"],
	["н[ие]разу","ни разу"],
	["завтра","завтра"],
	["гаусс","Гаусс"],//TODO: просклонять. В префиксы нельзя, ибо c -> сс
	["из *за","из-за"],
	["из *под","из-под"],
	["металлы","металлы"],//TODO: просклонять, помнить про глагол "метал"
	["щелч[её]к","щелчок"],
	["пол[\- ]часа","полчаса"],
	["не на чем","не на чем"],
	["вещь","вещь"],
	["паранойя","паранойя"],//TODO: досклонять
	["паранойи","паранойи"],
	["не работает","не работает"],
	["не сможешь*","не сможешь"],
	["чему-нибудь","чему-нибудь"],
	["каком-нибудь","каком-нибудь"],
	["что же","что же"],
	["чтонибу[дт]ь","что-нибудь"],
	["н[ие]люблю","не люблю"],
	["почему-то","почему-то"],
	["поскорее","поскорее"],
	["на кого","на кого"],
	["конечно","конечно"],
	["какую-нибудь","какую-нибудь"],//TODO: просклонять
	["рядов","рядов"],
	["будет","будет"],
	["истощена","истощена"],
	["истощено","истощено"],
	["истощены","истощены"],
	["по[ -]*ди[ао]г[ао]нал[еи]","по диагонали"],
	["пребь[ёе]т","прибьёт"],//TODO: проспрягать
	["сотри","сотри"],
	["и[сс][- ]*под[- ]*лобья","исподлобья"],
	["по-русски","по-русски"],
	["подошло","подошло"],
	["и[сс][ -]*д[ао]л[еи]ка","издалека"],
	["по-*порядку","по порядку"],
	["молодожён","молодожён"],//TODO: просклонять
	["не-*спеша","не спеша"],
	//["амбула",??], // [Katzen Gott]: хочется уже убивать за "амбулу", но надо придумать на что её менять.
];

var orphoPrefixToCorrect=[
/*
	["",""],
	["",""],
	["",""],
	["",""],
	["",""],
	["",""],
*/
	["солнц","солнц"],
	["выставк","выставк"],
	["ковычь*к","кавычк"],
	["к[оа]выч[еи]к","кавычек"],
	["корыстн","корыстн"],
	["д[еи][ао]лект","диалект"],
	["спорт*цмен","спортсмен"],
	["совпад","совпад"],
	["ограничив","ограничив"],
	["помощь*ник","помощник"],
	["предъ*истори","предыстори"],
	["прекрасн","прекрасн"],
	["обеспеч","обеспеч"],
	["об[ьъ][её]м","объём"],
	["х[ао]р[ао]ш","хорош"],
	["опада","опада"],
	["большинств","большинств"],
	["г[еи]м+[оа]ро","геморро"],
	["количеств","количеств"],
	["медленн(?!н)","медленн"],
	["попробова","попробова"],
	["помощь","помощь"],
	["чёрт","чёрт"],
	["рассчит","рассчит"],
	["отсутств","отсутств"],
	["здрав*ст*вуй","здравствуй"],
	["неот[ъь]емлим","неотъемлем"],
	["к[оа]м+ентар","комментар"],
	["п[еи]р[еи][оа]дич","периодич"],
	["выигр","выигр"],
	["продава","продава"],
	["встрепен","встрепен"],
	["многомерн","многомерн"],
	["неопасн","неопасн"],
	["безопасн","безопасн"],
	["опасн","опасн"],
	["кулер","кулер"],
	["повтор","повтор"],
	["пр[ие]вр[ао]щ","превращ"],
	["возрожд","возрожд"],
	["заморач","заморач"],
//	["сь","съ"],//TODO: прочие приставки//Мэри Сью
	["учён","учён"],
	["уделя","уделя"],
	["избира","избира"],
/*
	[""+sya,""],
	[""+sya,""],
*/
	["держат"+sya,"держат"],
	["получит"+sya,"получит"],
	["неполуч[еи]т"+sya,"не получит"],
	["обидеть"+sya,"обидеть"],
	["дирать"+sya,"дирать"],
	["творит"+sya,"творит"],
	["перепих","перепих"],
	["уедин","уедин"],
	["извин","извин"],
	["оборач","оборач"],
	["бь","бь"],
	["под(?=ск[ао]льз)","по"],
	["называет","называет"],//5 шт.  на Баше
	["металлич","металлич"],
	["печаль","печаль"],
	["покров","покров"],
	["отдира","отдира"],//TODO: другие приставки
	["пофайлов","пофайлов"],
	["спичеч","спичеч"],
	["дуэл","дуэл"],
	["невидим","невидим"],
	["щелч","щелч"],
	["сильне","сильне"],
	["б[ие]бл[ие]о","библио"],
	["бессвязн","бессвязн"],
	["тролл(?!л)","тролл"],
	["ощущени","ощущени"],
	["миндал","миндал"],
	["сиделок","сиделок"],
	["сиделк","сиделк"],
	["женщин","женщин"],
	["из[- ]*под-","из-под "],
	["из[- ]*за-","из-за "],
	["друг друг","друг друг"],
	["вопрос","вопрос"],
	["спроси","спроси"],
	["ч+[иеа]ст*лив","счастлив"],//TODO: сделать так, чтобы умещалось в одну!
	["щ+[иеа]ст*лив","счастлив"],
	["с[щч]+[иеа]ст*лив","счастлив"],
	["щ+[иеа]ст","счаст"],
	["с[чщ]+[иеа]ст","счаст"],
	["эксплоит","эксплоит"],
	["эксплоит","эксплоит"],
	["п[ао]м[ао]г","помог"],
	["крадуц+а","крадутся"],
	["объясн","объясн"],
	["мороз","мороз"],
	["порнух","порнух"],
	["еп+он","япон"],
	["биомехан","биомехан"],
	["мобил","мобил"],
	["жестян","жестян"],
	["осили(?!н)","осили"],
	["успок","успок"],
	["орангутан","орангутан"],
	["ар[ао]нгутан","орангутан"],
	["мотив","мотив"],
	["пельмен","пельмен"],
	["детств","детств"],
	["ужас","ужас"],
	["кр[еи]ве[тд]к","креветк"], //[Katzen Gott]: "креветко" тоже встречается, или его не трогать?
	["тигров","тигров"],
	["испепел","испепел"],
	["сдрав*ств","здравств"],
	["здравств","здравств"],
	["собутыльник","собутыльник"],
	["окута","окута"],
	["хлыщ","хлыщ"],
	["ево[шн][а-яё]+","его"],
	["коров","коров"],
	["шпаргал","шпаргал"],
	["аттракцион","аттракцион"],
	["режис[ёе]р","режиссёр"],
	["соединен","соединен"],
	["симпатич","симпатич"],
	["девч[её]н","девчон"],
	["мужчин","мужчин"],
	["большинств","большинств"],
	["сидени","сидени"],
	["электр","электр"],
	["преимуществ","преимуществ"],
	["офис","офис"],
	["агентств","агентств"],
	["одн[оа]классник","одноклассник"],
	["одноклассник","одноклассник"],
	["видео","видео"],
	["русск","русск"],
	["смотре","смотре"],
	["рассчит","рассчит"],
	["контакт","контакт"],
	["мастурб","мастурб"],
	["серебрян","серебрян"],
	["правильн","правильн"],
	["баллон","баллон"],
	["комментар","комментар"],
	["прид","прид"],
	["раз*сказ","рассказ"],
	["классн","классн"],
	["оргазм","оргазм"],
	["регистрац","регистрац"],
	["курин","курин"],
	["восстанов","восстанов"],
	["дешёв","дешёв"],
	["пр[ие]з[ие]ватив","презерватив"],
	["телефон","телефон"],
	["где-то","где-то"],
	["частн","частн"],
	["распис","распис"],
	["официал","официал"],
	["здравств","здравств"],
	["тысяч","тысяч"],
	["жест","жест"],
	["премьер","премьер"],
	["сь[её]м","съём"],
	["правил","правил"],
	["если б","если б"],
	["свин","свин"],
	["рассве","рассве"],
	["расписани","расписани"],
	["гостиниц","гостиниц"],
	["коммерч","коммерч"],
	["би[сс]плат","бесплат"],
	["больш","больш"],
	["без(?=[кпстфхцчшщ])","бес"],//TODO: раз/роз
	["бес(?=[бвгджзлмр])","без"],
	["раз(?=[кпстфхцчшщ])","рас"],
	["рас(?=[бвгджзлмнр])","раз"],
	["воз(?=[пстфхцчшщ])","вос"],
	["вос(?=[бгджзлмнр])","воз"],
	["через(?=[кпстфхцчшщ])","черес"],
	["черес(?=[бвгджзлмр])","через"],
	["безы","безы"],
//	["бест","бест"],//TODO: доделать
	["недолюбли","недолюбли"],
	["баян","баян"],
	["будущ","будущ"],
	["лучш","лучш"],
	["курсов","курсов"],
	["винчестер","винчестер"],
	["брошюр","брошюр"],
	["бе[сз]пелот","беспилот"],
	["вместим","вместим"],
	["жёлуд","жёлуд"],
	["возвра","возвра"],
	["в-*течени[ие]","в течение"],
	["выращен","выращен"],
	["коррект","коррект"],
	["грустн","грустн"],
	["грамот","грамот"],
	["не остановлюсь","не остановлюсь"],
	["пол-(?=[бвгджзкмнпрстфхцчшщ])","пол"],//TODO!
	["третьеклассник","третьеклассник"],//TODO!
	["организм","организм"],
	["голов","голов"],
	["ро[сз]сол","рассол"],
	["милостын","милостын"],
	["сатан","сатан"],
	["школьниц","школьниц"],
	["как-то","как-то"],
	["во[\\s-]*первых ","во-первых, "],
	["во-вторых, ","во-вторых, "],
	["в-треть*их ","в-третьих, "],
	["капрал","капрал"],
	["леност","леност"],
	["лестничн","лестничн"],
	["опозда","опозда"],
	["сохран","сохран"],
	["умира","умира"],
	["убира","убира"],
	["собира","собира"],
	["разбира","разбира"],
	["поголовн","поголовн"],
	["пеня","пеня"],
	["иссиня ч[еоё]рн","иссиня-чёрн"],
	["Транс+[еи]льван","Трансильван"],
	["кофе","кофе"],
	["влаз[ие]л","влезал"],
	["свин+","свин"],
	["переборщ","переборщ"],
	["бутерброд","бутерброд"],
	["ч[ие]хотк","чахотк"],
	["прилюдн","прилюдн"],
	["вздохн","вздохн"],
	["тщательн","тщательн"],
	["мальчуган","мальчуган"],
	["не-*многа","немного"],
	["р[ао][сс]д[оа][ёе]т","раздаёт"],
	["р[ие]п[ао]з[ие]т[ао]ри","репозитори"],
	["пр[ие]з[ие]нтац","презентац"],
];

var orphoPostfixToCorrect=[
/*	
	["",""],
	["",""],
	["",""],
	["",""],
	["",""],
*/
	["прячься","прячься"],
	["хранилищ","хранилищ"],
	["знакомься","знакомься"],
	["выгонит","выгонит"],
	["кажется","кажется"],
	["ругался","ругался"],
	["глядит","глядит"],
	["давным\\s*давно","давным-давно"],
	["в-*курсе","в курсе"],
	["\\s*-*\\s+на-*все[вг][оа]","-навсего"],
	["\\s*-*\\s+н[ие]бу[дт]ь","-нибудь"],
	["бер[её]ться","берётся"],
	["кажутся","кажутся"],
	["носятся","носятся"],
	["несутся","несутся"],
	["прягаться","прягаться"],
	["глядеться","глядеться"],
	["казывается","казывается"],
	["удивляться","удивляться"],
	["обращается","обращается"],
	["обращаться","обращаться"],
	["обновятся","обновятся"],
	["обновляться","обновляться"],
	["пишутся","пишутся"],
	["постятся","постятся"],
	["ходятся","ходятся"],
	["бражаться","бражаться"],
	["цепляться","цепляться"],
	["вращаться","вращаться"],
	["видеться","видеться"],
	["йдутся","йдутся"],
	["станется","станется"],
	["станутся","станутся"],
	["бороться","бороться"],
	["смотрится","смотрится"],
	["стремятся","стремятся"],
	["дастся","дастся"],
	["глашаться","глашаться"],
	["нимется","нимется"],
	["-нть","-нибудь"],
	["н[ие]буть","нибудь"],
	["надеяться","надеяться"],
	["гадаться","гадаться"],
	["печататься","печататься"],
/*
	[""+ca,""],
	[""+ca,""],
	[""+ca,""],
	[""+ca,""],
	[""+ca,""],
	[""+ca,""],
*/
	["сыпае"+ca,"сыпается"],
	["рву"+ca,"рвутся"],
	["крыва"+ca,"крываться"],
	["крывае"+ca,"крывается"],
	["нрави"+ca,"нравится"],
	["зывае"+ca,"зывается"],
	["готовятся","готовятся"],
	["боится","боится"],
	["думаться","думаться"],
	["мчится","мчится"],
	["обидеться","обидеться"],
	["ждаться","ждаться"],
	["маяться","маяться"],
	["мыться","мыться"],
	["рваться","рваться"],
	["тираться","тираться"],
	["кусаться","кусаться"],
	["дираться","дираться"],
	["ниматься","ниматься"],
	["ложатся","ложатся"],
	["нравятся","нравятся"],
	["смеяться","смеяться"],
	["сядется","сядется"],
	["гуляться","гуляться"],
	["жаловаться","жаловаться"],
	["пытаться","пытаться"],
	["оваться","оваться"],
	["з[ао]бот[яю]ть*ся","заботятся"],
	["б[ие]ратся","бираться"],
	["плавятся","плавятся"],
	["дерутся","дерутся"],
	["хвастаться","хвастаться"],
	["вертится","вертится"],
	["одеться","одеться"],
	["греться","греться"],
	["еваться","еваться"],
	["ываться","ываться"],
	["зываться","зываться"],
	["врубаться","врубаться"],
	["гружаться","гружаться"],
	["пользоваться","пользоваться"],
	["стебаться","стебаться"],
	["иваться","иваться"],
	["писаться","писаться"],
	["общаться","общаться"],
	["двигаться","двигаться"],
	["колоться","колоться"],
	["являться","являться"],
	["режутся","режутся"],
	["встречатся","встречатся"],
	["браться","браться"],
	["начинаться","начинаться"],
	["трахаться","трахаться"],
	["заняться","заняться"],
	["кажется","кажется"],
	["хочется","хочется"],
	["ходишь","ходишь"],
	["просятся","просятся"],
	["к[оа]зать*ся","казаться"],
	["-ка","-ка"],
	["видил(?=а|и|о|)(?=с[яь])","видел"],
	["трахац+[оа]","трахаться"],
	["батареек","батареек"],
	["глядывац+[ао]","глядываться"],
	["играц+[оа]","играться"],
	["товарищ","товарищ"],
	["сушняч[её]к","сушнячок"],
	["пишется","пишется"],
	["щ[еёо]лк[ао][еи]т","щёлкает"],
	["читаец+а","читается"],
	["будешь","будешь"],
	["пользуются","пользуются"],
	["пытаюц+а","пытаются"],
	["ругаец+о","ругается"],
	["явятся","явятся"],
	["садят","садят"],
	["пускаюц+а","пускаются"],
	["хочешь","хочешь"],
	["следующую","следующую"],
	["борются","борются"],
	["сыпется","сыпется"],
	["г[ао]в[ао]риш","говоришь"],
	["ются","ются"],
	["ётся","ётся"],
	["ается","ается"],
	["оется","оется"],
	["уется","уется"],
	["яется","яется"],
	["еется","еется"],
	["юется","юется"],
	[" ли"," ли"],
	[" же"," же"],
	[" бы"," бы"],
//	["-что"," что"],//кое-что
	["можешь","можешь"],
	["аешь","аешь"],
	["шься","шься"],
	["гл[аея]диш","глядишь"],
	["сыпаться","сыпаться"],
	["рвутся","рвутся"],
	["изм","изм"],//TODO: просклонять
	["ция","ция"],//TODO: просклонять
	["качать","качать"],//TODO: проспрягать
	["рвутся","рвутся"],
	["пользуется","пользуется"],
	["пожж[еа]","позже"],
	["качает","качает"],
	["кочаеть*ся","качается"],
	["алась","алась"],
	["шёл","шёл"],
	["смотр[ие]ш","смотришь"],
	["смотрим","смотрим"],//TODO: допроспрягать. И вообще все глаголы-исключения
	["тирад","тирад"],
	["цами","цами"],
];

var orphoFragmentsToCorrect=[
/*
	["",""],
	["",""],
	["",""],
*/
	["матер[еи]ял","материал"],
	["с[ие]р[ьъ][её]з","серьёз"],
	["элемент","элемент"],
	["тренажёр","тренажёр"],
	["обезьян","обезьян"],
	["р[еи]с+т[ао]ран","ресторан"],
	["ат+р[ие]бут","атрибут"],
	["искусств","искусств"],
	["естеств","естеств"],
	["ъезд","ъезд"],
	["ъезж","ъезж"],
	["нюанс","нюанс"],
	["параллел","параллел"],
	["распростран","распростран"],
	["съ*о+риентир","сориентир"],
	["перманент","перманент"],
	["парашют","парашют"],
	["ъявл","ъявл"],
	["милиц","милиц"],
	["пр[оа]т+[оа]тип","прототип"],
	["[оа]р[еи]нтир","Орентир"],
	["раствор","раствор"],
	["баллотир","баллотир"],
	["интерес","интерес"],
	["тренир","тренир"],
	["полагают","полагают"],
	["ворачива","ворачива"],
//];[
	["топчет"+sya,"топчет"],//sya уже включает границу слова
	["полагает*"+sya,"полагает"],
//	["видит"+sya,"видеть"],//Бред
	["видит"+sya,"видит"],
	["клеит"+sya,"клеит"],
	["клеят"+sya,"клеят"],
	["пялит"+sya,"пялит"],
	["тащит"+sya,"тащит"],
	["бьёт"+sya,"бьёт"],
	["смотрит"+sya,"смотрит"],
	["тр[еия]с[ёе]т"+sya,"трясёт"],//TODO: проспрягать
	["хочет"+sya,"хочет"],
	["зачёт","зачёт"],
	["щетин","щетин"],
	["участн","участн"],
	["розет","розет"],
	["если-*что","если что"],
	["чувств","чувств"],
	["секунд","секунд"],
	["лучш","лучш"],
	["ч[ие]л[оа]в*[еэ]к","человек"],
	["советск","советск"],
	["инсталл(?![лл])","инсталл"],
	["нч","нч"],
	["нщ","нщ"],
	["чн","чн"],
	["щн","щн"],
	["чк","чк"],
	["ы","ы"],
	["э","э"],
	["тендер","тендер"],
	["будущ","будущ"],
	["следующ","следующ"],
	["праздн","праздн"],
	["пр[ие]з[ие]дент","президент"],
	["цикл","цикл"],
	["мед[еи]ц[иы]н","медицин"],
	["интересн","интересн"],
	["классн","классн"],
	["эксплуоат","эксплуоат"],
	["принцип","принцип"],
	["субъект","субъект"],
	["объект","объект"],
	["мыслим","мыслим"],
	["пристег","пристег"],
	["пристёг","пристёг"],
	["формат","формат"],
	["ъедин","ъедин"],
//	["ьед[еи]н","ъедин"],//Объедение
//	["ъед[еи]н","ъедин"],
	["монет","монет"],
	["проблем","проблем"],
	["пропаган","пропаган"],
	["каблук","каблук"],
	["будет","будет"],
	["хотя б","хотя б"],
	["регистр","регистр"],//Или "реестр", но сочтём это санкциями
	["рецидив","рецидив"],
	["очень[еи]рова","очарова"],
	["ъясн","ъясн"],
	["чёрн","чёрн"],
	["авторизир","авторизир"],
	["ил*[еи]м*[еи]нт","элемент"],
	["эл*[еи]м*[еи]нт","элемент"],//TODO: дебажить до "[эи]л*[еи]м*[еи]нт"
	["пробова","пробова"],
	["бутерброд","бутерброд"],
	["cочельнтик","cочельник"],
	["глядыв","глядыв"],
	["бретельк","бретельк"],
	["р[еи]к[ао]ш[еи]т","рикошет"],
	["м[ие]н[ие]рал","минерал"],
];

var matyuki=[
];

var yo=[
];

try{
	module.exports.orphoWordsToCorrect     = orphoWordsToCorrect;
	module.exports.orphoPrefixToCorrect    = orphoPrefixToCorrect;
	module.exports.orphoPostfixToCorrect   = orphoPostfixToCorrect;
	module.exports.orphoFragmentsToCorrect = orphoFragmentsToCorrect;
}catch(e){
	//Значит, не node.js
}
/*
Copyright Nikolay Avdeev aka NickKolok aka Николай Авдеев 2015

Всем привет из снежного Воронежа! 

This file is part of CHAS-CORRECT.

    CHAS-CORRECT is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CHAS-CORRECT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.

  (Этот файл — часть CHAS-CORRECT.

   CHAS-CORRECT - свободная программа: вы можете перераспространять её и/или
   изменять её на условиях Стандартной общественной лицензии GNU в том виде,
   в каком она была опубликована Фондом свободного программного обеспечения;
   либо версии 3 лицензии, либо (по вашему выбору) любой более поздней
   версии.

   CHAS-CORRECT распространяется в надежде, что она будет полезной,
   но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
   или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
   общественной лицензии GNU.

   Вы должны были получить копию Стандартной общественной лицензии GNU
   вместе с этой программой. Если это не так, см.
   <http://www.gnu.org/licenses/>.)
*/

'use strict';

try{
	var dict=require('./dictionary.js');
	for(var chto in dict)
		global[chto]=dict[chto];
}catch(e){
	//Значит, не node.js
}

var wordSplitSymbol="([^А-Яа-яЁёA-Za-z]|^|$)";
//var wordSplitSymbolSafe="(?=[^А-Яа-яЁёA-Za-z]|^|$)";
var leftEnd="(.|^)";//TODO: переписать так, чтобы стал не нужен
//var rightEnd="(.|$)";
//var rightEndSafe="(?=.|[\\s\\S]|$)";
var actionArray=[
	[/[ь]{2,}/g,"ь",/ь/i],
	[/[ъ]{2,}/g,"ъ",/ъ/i],

	[/([ЖжШшЩщ])[ыЫ]/g,"$1и",/[жшщ]ы/i],
	[/([ЧчЩщ])[яЯ]/g,"$1а",/[чщ]я/i],
	[/([ЧчЩщ])[юЮ]/g,"$1у",/[чщ]ю/i],
	[/([^А-Яа-яЁёA-Za-z]|^)з(?=[бжкстф-щБЖКПСТФ-Щ]|д(?!ани|ань|ес|еш|оров|рав|рас))/g,"$1с",/([^А-Яа-яЁёA-Za-z]|^)з(?=[бджкпстф-щБДЖКПСТФ-Щ])/],
	[/([^А-Яа-яЁёA-Za-z]|^)З(?=[бжкстф-щБЖКПСТФ-Щ]|д(?!ани|ань|ес|еш|оров|рав|рас))/g,"$1С",/([^А-Яа-яЁёA-Za-z]|^)З(?=[бджкпстф-щБДЖКПСТФ-Щ])/],
];


var qmInReg=/\(\?[\=\!]/;

function prepareExpression(word, str, prefix, postfix){
	if(word[0] !== str[0])
		return prepareReplaceHeavy(word, str, prefix, postfix);
	var firstLetter=word[0];
	var lostWord=word.substr(1);
//	var safe=qmInReg.test(word)
//	var wordSplitSymbolHere=(postfix && safe) ? wordSplitSymbolSafe : wordSplitSymbol;
//	if(postfix && qmInReg.test(word))
//		correct.log(word+rightEndHere);

	var pattern =
		(prefix ? wordSplitSymbol : leftEnd ) +
		"(["+firstLetter.toLowerCase()+firstLetter.toUpperCase()+"])"+lostWord+
		(postfix ? wordSplitSymbol : "");
	var regexp=new RegExp(pattern,"gm");
//	correct.log(regexp);
	actionArray.push([regexp,"$1$2"+str.substr(1)+(postfix?"$3":""),new RegExp(word,"i"),word]);
//	megaexpressionParts.push(pattern);
}

function prepareReplaceHeavy(reg, str, prefix, postfix){
	var lostreg=reg.substr(1);
	var loststr=str.substr(1);
	var pattern1 =
		(prefix ? wordSplitSymbol : leftEnd ) +
		reg[0].toLowerCase()+lostreg+
		(postfix ? wordSplitSymbol : "" );
	var regexp1=new RegExp(pattern1,"gm");
	var pattern2 =
		(prefix ? wordSplitSymbol : leftEnd ) +
		reg[0].toUpperCase()+lostreg+
		(postfix ? wordSplitSymbol : "" );
	var regexp2=new RegExp(pattern2,"gm");
	actionArray.push([regexp1,"$1"+str[0].toLowerCase()+loststr+(postfix ? "$2" : ""),new RegExp(reg,"i"),str]);
	actionArray.push([regexp2,"$1"+str[0].toUpperCase()+loststr+(postfix ? "$2" : ""),new RegExp(reg,"i"),str]);
}



var megaexpressionParts=[];

var globalArray=[
	[orphoFragmentsToCorrect,orphoPostfixToCorrect],
	[orphoPrefixToCorrect,orphoWordsToCorrect],
];

for(var i1=0; i1<=1;i1++)
	for(var i2=0; i2<=1;i2++)
		for(var i=0; i<globalArray[i1][i2].length; i++){
			prepareExpression(globalArray[i1][i2][i][0],globalArray[i1][i2][i][1],i1,i2);
//			megaexpressionParts.push(globalArray[i1][i2][i][0]);
		}

var actionArrayCopy=actionArray.slice();

var megaexpression;//=new RegExp("("+megaexpressionParts.join(")|(")+")","im");


var correct={
	logArray:[],
	log: function(param){
		this.logArray.push(param);
	},
	logToConsole: function(){
		console.log("chas-correct: "+this.logArray.join("\n\r"));
		this.logArray=[];
	},
	replacedPairs:[],
	logReplaced: function(){
		var rez="";
		var len=this.replacedPairs.length;
		for(var i=0; i<len;i+=2){
			if(this.replacedPairs[i]!=this.replacedPairs[i+1]){
				var slen=this.replacedPairs[i].length;
				for(var j=0; j<slen && this.replacedPairs[i][j]===this.replacedPairs[i+1][j]; j++){
				}
				rez+="\n\r\n\r"+this.replacedPairs[i]+"\n\r->\n\r"+this.replacedPairs[i+1].substr(j-10<0?0:j-10);
			}
		}
		this.replacedPairs=[];
		return rez;
	},
	logTimestamp: function(text, timestamp){
		correct.log(text+" (мс): "+(new Date().getTime() - timestamp));
	},
};

//Теперь удаляем исходные словари - они больше не нужны, все слова уже обработаны, только память занимают
//TODO: делать это вообще при сборке. Когда она будет
orphoWordsToCorrect=orphoPrefixToCorrect=orphoPostfixToCorrect=orphoFragmentsToCorrect=globalArray=null;

try{
	module.exports.actionArray = actionArray;
}catch(e){
	//Значит, не node.js
	correct.log("chas-correct: на подготовку массива регулярных выражений затрачено (мс): "+(new Date().getTime() - oldTime));
}
/*
Copyright Nikolay Avdeev aka NickKolok aka Николай Авдеев 2015

Всем привет из снежного Воронежа! 

This file is part of CHAS-CORRECT.

    CHAS-CORRECT is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CHAS-CORRECT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CHAS-CORRECT.  If not, see <http://www.gnu.org/licenses/>.

  (Этот файл — часть CHAS-CORRECT.

   CHAS-CORRECT - свободная программа: вы можете перераспространять её и/или
   изменять её на условиях Стандартной общественной лицензии GNU в том виде,
   в каком она была опубликована Фондом свободного программного обеспечения;
   либо версии 3 лицензии, либо (по вашему выбору) любой более поздней
   версии.

   CHAS-CORRECT распространяется в надежде, что она будет полезной,
   но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
   или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
   общественной лицензии GNU.

   Вы должны были получить копию Стандартной общественной лицензии GNU
   вместе с этой программой. Если это не так, см.
   <http://www.gnu.org/licenses/>.)
*/

'use strict';

Array.prototype.spliceWithLast=function(index){
	///Заменить элемент под номером index последним, последний удалить
	///Это, очевидно, эффективнее, чем сдвигать весь массив и даже чем просто заменять на null
	'use strict';
	this[index]=this[this.length-1];
	this.length--;
};

var notCyrillicToTrim=/^[^а-яё]+|[^а-яё]+$/i;
function trimNotCyrillic(text) {
	//Да, быстрее так, а не методом-членом
	return text.replace(notCyrillicToTrim,"");
	//TODO: проверить, быстрее одной регуляркой или двумя
}

var observeDOM = (function(){
	///Наблюдение за DOM и вызов корректора при добавлении новых нод
	var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
		eventListenerSupported = window.addEventListener;

	return function(obj, callback){
		if( MutationObserver ){
			// define a new observer
			var obs = new MutationObserver(function(mutations, observer){
				var shouldBeHandled=0;
				var len=mutations.length;
				for(var i=0; i<len; i++){
					for(var j=0; j<mutations[i].addedNodes.length; j++){
						extractTextNodesFrom(mutations[i].addedNodes[j]);
					}
					//Гоняем проверялку только по тем нодам, которые добавились
					//Сложность в том, что добавиться могло целое дерево
					shouldBeHandled+=mutations[i].addedNodes.length;
				}
				if(shouldBeHandled){
					domChangedHandler();
				}else{
					correct.log("Изменение DOM, не добавляющее ноды");
				}
			});
			obs.observe( obj, { childList:true, subtree:true });
		}
		else if( eventListenerSupported ){
			obj.addEventListener('DOMNodeInserted', domChangedHandler, false);
		}
	}
})();

//Кэшируем строки и регэкспы. Вроде как помогает.
var reun1=/[(]{6,}/g		, stun1="(((";
var reun2=/[)]{6,}/g		, stun2=")))";
var reun3=/[!]1+/g			, stun3="!";
var reun4=/[?]7+/g			, stun4="?";
var reun5=/([.?!])\1{3,}/g	, stun5="$1$1$1";
function replaceUniversal(ih){
	return ih.
		replace(reun1,stun1).
		replace(reun2,stun2).
		replace(reun3,stun3).
		replace(reun4,stun4).
		replace(reun5,stun5);
}

var reg3podryad=/([А-Яа-яЁё])\1{3,}/g;
function specialWork(ih){
	ih=ih.replace(reg3podryad,"$1$1$1");//Это не выносится из-за сигнатуры

	return ih;
}

var lAr=[];
var totalNodes=0;
var errorNodes=0;

function mainWork(ih){
	ih=specialWork(ih);

	totalNodes++;

	if(!megaexpression.test(ih))
		return ih;

	errorNodes++;

	correct.replacedPairs.push(ih);
	for(var i=0; i<actionArray.length;i++){
//		if(actionArray[i])
	/*	if(ih.length>50 && /\./.test(ih)){
			var temparr=ih.split(".");
			var len=temparr.length;
			for(var j=0; j<len; j++){
				if(actionArray[i][2].test(temparr[j]))
					temparr[j]=temparr[j].replace(actionArray[i][0],actionArray[i][1]);
			}
			ih=temparr.join(".");
		}else
	*/	
		if(actionArray[i][2].test(ih))
			ih=ih.replace(actionArray[i][0],actionArray[i][1]);
	}
	correct.replacedPairs.push(ih);

	return ih;
}

var regCyr=/[А-Яа-яЁё]/;
function notContainsCyrillic(str){
	return !regCyr.test(str);
}

var textNodes=[];
var kuch=3;

function extractTextNodesFrom(rootNode) {
	///Добавить все текстовые ноды-потомки rootNode в масссив textNodes
	var walker = document.createTreeWalker(
		rootNode,
		NodeFilter.SHOW_TEXT,
		null,
		false
	);

	var node;

	while(node = walker.nextNode()) {
		if(node.data!="" && node.data.trim()!=""){
			node.data=replaceUniversal(node.data);
			if(!notContainsCyrillic(node.data)){
				textNodes.push(node);
			}
		}
	}
}

function extractAllTextNodes() {
	///Заменить textNodes на список
	var timeBeforeNodesExtracting=new Date().getTime();
	textNodes=[];
	extractTextNodesFrom(document.body);
	correct.logTimestamp("На подготовку массива текстовых нод затрачено", timeBeforeNodesExtracting);
}

var regKnown;
var typicalNodes;
var lastActionArrayLength=storageWrapper.getKey("lastActionArrayLength",0);
if(lastActionArrayLength==actionArrayCopy.length){
	typicalNodes=storageWrapper.getKey("chas-correct-typical-nodes",{totalPages:0,nodes:{}});
}else{
	typicalNodes={totalPages:0,nodes:{}};
	storageWrapper.setKey("lastActionArrayLength",actionArrayCopy.length);
	correct.log("Длина словаря изменилась - сбрасываем кэш");
}

var flagEchoMessageDomChanged;
var flagFixMistakesScheduled=0;
var flagAsyncFixLoopFinished=1;
var flagFirstTimeFixLaunch=1;
var firstChangingNode,lastChangingNode;
var timeBeforeMain;

function fixMistakes() {
/*
	if(!flagAsyncFixLoopFinished){
		if(!flagFixMistakesScheduled){
			setTimeout(fixMistakes,20);
			flagFixMistakesScheduled=1;
		}
		return;
	}
*/
	var len=textNodes.length-1;
	var i=0;

	var oldTime3=new Date().getTime();


	var timeBeforeHeader=new Date().getTime();
	if(typicalNodes.nodes){
		//Пропускаем "шапку" страницы
		while(i<=len && textNodes[i].data in typicalNodes.nodes){
			i++;
		};
		//И низушку
		while(i<=len && textNodes[len].data in typicalNodes.nodes){
			len--;
		};
	}
	len++;//Иначе глючит :(
	var cachedNodes=i+textNodes.length-len;
	correct.log("Нод отнесено к шапке: "+cachedNodes+"("+(cachedNodes/textNodes.length*100)+"%), до "+i+"-й и после "+(len-1)+"-й");
	correct.logTimestamp("Выделение шаблона", timeBeforeHeader);


	selectRegs(i,len);
	timeBeforeMain=new Date().getTime();
	
	firstChangingNode=i;//TODO: зарефакторить
	lastChangingNode=len;
/*	if(flagFirstTimeFixLaunch){
		setTimeout(asyncFixLoop,0);
	}else{
		asyncFixLoop();
	}
*/
//	flagFixMistakesScheduled=0;
	asyncFixLoop();
	flagFirstTimeFixLaunch=0;
	flagEchoMessageDomChanged=1;
}

function firstRun() {
	extractAllTextNodes();
	fixMistakes();
	typicalNodes.totalPages++;//Логично, считаем настоящее количество страниц
	setTimeout(cacheRemoveOutdated,4000);//TODO: кэширование вообще растащить
}

firstRun();

var asyncFixLoopStartTime;
var asyncCount=0;
function asyncFixLoop(){
	asyncCount++;
	asyncFixLoopStartTime=new Date().getTime();
	flagEchoMessageDomChanged=1;
	for(;firstChangingNode<=lastChangingNode;firstChangingNode++){
	/*	var textArr=[];
		if(i%kuch == 0){
			for(var j=0; (i+j<len) && (j<kuch); j++){
				textArr.push(textNodes[i+j].data);
			}
			if(!megaexpression.test(textArr.join(" "))){
				i+=kuch;
				continue;
			}
		}
	*/	
		var currentNode=textNodes[firstChangingNode];
		if(!currentNode)//Не знаю, что имеется в виду
			continue;
		if(currentNode.data in typicalNodes.nodes){
			typicalNodes.nodes[currentNode.data]+=20;
		}else{
			currentNode.data=mainWork(currentNode.data);
			typicalNodes.nodes[currentNode.data]=20;
		}

/*		if(
		(firstChangingNode % 100 == 0)
			// || (new Date().getTime() - asyncFixLoopStartTime > 146)
		){
			firstChangingNode++;
			setTimeout(asyncFixLoop,10);
			return;
		}
*/
	}
	correct.logTimestamp("Основной цикл", timeBeforeMain);
	flagAsyncFixLoopFinished=1;
	actionsAfterFixLoop();
}
function actionsAfterFixLoop(){
	observeDOM(document.body, domChangedHandler);

	//Нечего память кушать! Надо будет - новые нагенерятся
	textNodes=[];
	//Кэш не резиновый
	setTimeout(cacheCrop,3000);

	correct.logTimestamp("chas-correct отработал. С момента запуска", oldTime);
	correct.logToConsole();
}

var domChangedLastTime=new Date().getTime();
var keydownLastTime=new Date().getTime();
var domChangedScheduled=0;
var domChangeTimes=0;

var domChangingTimeout=0;

function scheduleDomChangeHandler(time){
	clearTimeout(domChangingTimeout);
	domChangingTimeout=setTimeout(domChangedHandler,time);
}

function domChangedHandler(){
	var newt=new Date().getTime();
	if(flagEchoMessageDomChanged){
		flagEchoMessageDomChanged=0;
		return;
	}
	if(newt - domChangedLastTime < 1468 || newt - keydownLastTime < 2*1468){
//		if(!domChangedScheduled){
//			domChangedScheduled=1;
			scheduleDomChangeHandler(1468);
//		}
		return;
	}
	domChangedLastTime=new Date().getTime();
	domChangedScheduled=0;
	fixMistakes();
	domChangeTimes++;
	correct.logTimestamp("Вызов chas-correct по смене DOM "+domChangeTimes+"-й раз", newt);
	correct.logToConsole();
}

//Кэширование типичных нод

function cacheMetrika(text) {
	return Math.pow(typicalNodes.nodes[text],2)/( typicalNodes.nodes[text].length + 6);
}

function cacheCrop() {
	///Удаление из кэша лишних (по некоторой метрике) нод
	//Считаем количество нод в кэше
	var cacheNodesCount=Object.keys(typicalNodes.nodes).length;
	var timeBefore=new Date().getTime();

	var cacheLength=JSON.stringify(typicalNodes.nodes).length;
	var currentMin;
	var deletedNodes=0;
	var deletedNodesLength=0;
	var lastNode;

	while(
		//Ограничиваем кэш 100 килобайтами на сайт (или 200, т. к. юникод? Не важно)
		cacheLength > 102400
	||
		//Не более 1024 нод
		cacheNodesCount > 1024
	){
		for(var text in typicalNodes.nodes){
			break;
		}
		//Да, это так мы получаем первую ноду из кэша
		//Считаем её минимальной
		currentMin = cacheMetrika(text);
		//Ищем ноду с минимальным отношением квадрата повторяемости к длине
		for(var text2 in typicalNodes.nodes){
			var otherMetrika = cacheMetrika(text2);
			if( otherMetrika < currentMin ){
				text = text2;
				currentMin = otherMetrika;
			}
		}
		//Удаляем одну ноду
		deletedNodes++;
		deletedNodesLength+=text.length;
		delete typicalNodes.nodes[text];

		//Пересчитываем показатели
		cacheNodesCount--;
		cacheLength -= text.length+6;

		//Эталонной нодой снова становится последняя
		text = lastNode;
		//TODO: метрики тоже куда-то кэшировать
	}
	storageWrapper.setKey("chas-correct-typical-nodes",typicalNodes);
	correct.logTimestamp("Редукция кэша (нод: "+deletedNodes+", сумма длин удалённых нод: "+deletedNodesLength+")",timeBefore);
	correct.log("В кэше нод: "+cacheNodesCount+" общей длиной "+cacheLength+", минимум метрики "+currentMin);
}

function cacheRemoveOutdated() {
	for(var text in typicalNodes.nodes){
		typicalNodes.nodes[text]--;
		if(typicalNodes.nodes[text] < 0){
			delete typicalNodes.nodes[text];
		}
	}
}


//Объединение текста всех нод и выкидывание ненужных регулярок
var text="";
function selectRegs(i,len){
//	var textArr=[];
//	megaexpressionParts=[];
	text="";
	var megaexpressionSource="(";
	var delimiter=")|(";
	var t=new Date().getTime();
	var notCyrTest=/^[^а-яё]{2,}|[^а-яё]{2,}$/i
	for(;i<len;i++){
		if(!(textNodes[i].data in typicalNodes.nodes))
//			textArr.push(textNodes[i].data);
//			if(notCyrTest.test(text))
//				text+=" "+trimNotCyrillic(textNodes[i].data);
//			else
				text+=" "+textNodes[i].data;
	}
	text=text.replace(/[^а-яё]{4,}/gi," ");
	if(text.trim()!=""){
		actionArray=actionArrayCopy.slice();//Да, так быстрее: http://jsperf.com/array-slice-vs-push
	}else{
		correct.log("Все ноды в кэше - незачем делать копию словаря");
		actionArray=[];
	}
//	var text=textArr.join(" ");
//	correct.log(text);

//{{Экспериментальное выкидывание регэкспов парами - медленнее
/*	var l=actionArray.length;
	for(var j=1; j<l; j+=2){
		if(
			actionArray[j] && actionArray[j][3] &&
			actionArray[j-1] && actionArray[j-1][3]
		){
			if(!(
					new RegExp(
						"("+
							actionArray[j][3]+")|("+
							actionArray[j-1][3]+
						")"
					)
				).test(text))
			{
				actionArray.spliceWithLast(j);
				actionArray.spliceWithLast(j-1);
				l-=2;
				j-=2;
			}
		}
	}
	console.log(l);
*/
//}}
	var l=actionArray.length;

	for(var j=0; j<l; j++){
		if(actionArray[j] && actionArray[j][2]){
			if(!actionArray[j][2].test(text)){
				actionArray.spliceWithLast(j);//Это быстрее, чем забивать нулями
				l--;
				j--;
			}else{
				megaexpressionParts.push(actionArray[j][2].source);
//				megaexpressionSource+=actionArray[j][3]+delimiter;
			}
		}
	}
//	megaexpression=new RegExp("("+megaexpressionParts.join(")|(")+")","im");
	megaexpression=new RegExp(megaexpressionSource.replace(/\)\|\($/,"")+")","im");
//	correct.log(megaexpression);
	correct.logTimestamp("Выбор регэкспов", t);
}

//Сбросить кэш
function clearNodeCache(){
	storageWrapper.setKey("chas-correct-typical-nodes",{totalPages:0,nodes:{}});
}

//Расстановка типографики + откладывание автокоррекции при наборе
document.onkeydown = keydownHandler;

function keydownHandler(e) {
	keydownLastTime=new Date().getTime();
    e = e || event;
	if ((e.ctrlKey && e.shiftKey && e.keyCode == "A".charCodeAt(0))) {
        forceTypo();
        return false;
    }
}

function forceTypo(){
	extractAllTextNodes();
	var len=textNodes.length;
	for(var i=0; i<len; i++)
		textNodes[i].data=forceTypoInString(textNodes[i].data);
}

//var typoLeft=/ *([,\.!?\):;])( *(?![,\.!?\):;]))/g;
var typoLeft=/ *([,\.!?\):;»]) */g;
var typoRight=/ *([\(«]) */g;
var typoJoin=/([,\.!?\):;]+) *([,\.!?\):;»]+)/g;
var typoSmallLetter=/([а-яё]{2,}[\.!?]) *[а-яё]/g;
function replaceSmallLetter(m,$1){
	console.log(m, $1);
	return $1+" "+m.substr(-1).toUpperCase();
}

function forceTypoInString(ih){
		return ih.
			replace(typoLeft , "$1 ").
			replace(typoRight, " $1").
			replace(typoJoin , "$1$2").
			replace(typoJoin , "$1$2").
			replace(typoSmallLetter,replaceSmallLetter)
			;
}
})();