Если нельзя, но очень хочется, то нужно обязательно и ничего в мире не стоит того, чтобы делать из этого проблему!


Интересна Java? Кликай по ссылке и изучай!
Если тебе полезно что-то из того, чем я делюсь в своем блоге - можешь поделиться своими деньгами со мной.
с пожеланием
столько времени читатели провели на блоге - 
сейчас онлайн - 

понедельник, 29 ноября 2010 г.

How to: Макросы в Microsoft Word. Как автоматизировать рутину с помощью Visual Basic

Давно хотел написать про замечательный инструмент имя которому макросы в Microsoft Office. Office я всегда считал и считаю одним из лучших ПО. Один раз, из любопытства, я открыл для себя макросы, после чего стал их использовать для избавления от рутины, как то вырезать из большого фрагмента текста состоящего из повторяющихся структур некоторые данные. Идея макросов проста - они помогают там, где приходится делать много однообразной повторяющейся работы.

Читать дальше...

Например, есть большой (в примере для постоты тект взят не большой) фрагмент текста

йцу кен3 uio
выв ваыаыва1 sdhg
dsf turtr4 dfsfhgf
выапып thyrth1 выв
праовр выорфыор9 црцр
выалрфл фыор2 erw
fdskajfhk ворыва6 вылваор
фыалор фло5 р
dakfjh af3 лор
sdf sdfsdf5 sdf
dsfglsdh askfjdgh8 kajg
dsakfjh a9 sjdg
выалор фыопр7 влор
askfhg asdhg9 h
выплор оап3 роы
выап лофр2 уо
ва sfg3 d
sda asd8 вы
sadd df4 fff
ggg gg6 g
h h2 h
оооке авпр6 gdh
вап ва4 а
ап а3 ааа

Его формат таков, что в каждой строчке есть по три слова, разделенных пробелом. Второе слово заканчивается цифрой. Допустим мне нужно получить одной строкой все эти цифры. Что я буду делать?

Могу пройтись вручную и скопипастить все цифры. Но, человек ошибается часто, а я тем более - внесу ошибку. Кроме того это скучно.

А могу записать макрос. Как это делается? Просто. Для начала нам нужно попробовать сделать это вручную с тем, чтобы определить какие клавиши мы нажимаем и то, где начинаем идти по кругу.

Ставлю курсор в исходную позицию - самое начала документа. И начинаю колдовать: Ctrl-Right, Ctrl-Right, Left, Shift-Left, Ctrl-Ins, Home, Shift-End, Shift-Ins, Enter. После этого вместо строчки из трех слов будет одна цифра, содержавшаяся в конце второго слова. Дальше мне придется повторить это колдовство с начала и уже во второй строчке вместо стрех слов будет всего лишь цифра. Это первый этап.

Вторым этапом будет записать это заклинание в макрос. Делается это так. Ставим курсор в начало документа как и раньше. Выбираем пункт меню Сервис->Макрос->Начать запись.


В диалоговом окне выбираем "Назначить клавишам"


После жмем какую-то неиспользуемую комбинацию клавиш (я для этих целей чаще всего выбираю Alt-Q) и нажимаем кнопку "Назначить"


А потом "Закрыть"


Узнать используется ли клавиша можно просто взглянув в поле "Текущее назначение" - там должно значится "[нет]" или название прошлого (уже не нужного) макроса.


Сразу после нажатия "Закрыть" пойдет запись. Тут важно не нажимать ничего постороннего, ведь даже переключение из одного окна Word на другое - так же записывается. Вводим наше магическое Ctrl-Right, Ctrl-Right, Left, Shift-Left, Ctrl-Ins, Home, Shift-End, Shift-Ins, Enter.

После ввода комбинации клавиш можно останавливать запись.


Теперь нажимаем Alt-Q (или другую клавишу, которую назначили) и радуемся тому как быстро весь текст превращается в строку цифр.

Комбинацию клавиш не обязательно нажимать снова для каждой новой строчки - можно просто зажать клавиши и через секунду сработает автоповтор. Ближе к концу документа стоит быть внимательным ведь строк больше нет, и макрос может повести себя непредсказуемо - часто бывало, что после обработки текста макросом, он брался за уже обработанный текст и делал с ним нечто невообразимое. Благо всегда есть Ctrl-Z и отмена делается так же пошагово, как если бы не было никаких макросов. Но наш макрос безопасен и он просто ничего не сделает достигнув конца документа, но внимательность не повредит.

В результате мы получим вот такой вот столбик. Ее можно вручную собрать в строку, а можно записать другой макрос :)


Определим для начала что будет нашим заклинанием? Для этого отправимся в исходную точку, и начнем собирать вручную: Left, Del, Left, Del, Left-... Значит в наш новый макрос стоит записать Left, Del. Так и сделаем.





После этого нажмем Left, Del и остановим запись


После этого нам останется нажать и удержать Alt-W до тех пор, пока столбец не превратится в строчку.


Вот так просто пишутся макросы.

Ключевым является то место, в котором определяется последовательность нажимаемых клавиш - наше заклинание-комбинация. Эта последовательность должна быть рабочей для всех элементов структуры (в нашем случае для всех строк текста). Допустим на секунду, что текст может состоять из произвольного числа слов, а в предпоследнем содержится слово с цифрой. Вот так:

sdf sdf впр йцу кен3 uio
gdsh ah trjw  fh ttвыв ваыаыва1 sdhg
th kg hdkgjh dsf turtr4 dfsfhgf
df hkjsd hgksвыапып thyrth1 выв
sj agrj srпраовр выорфыор9 црцр
ser рыекш srвыалрфл фыор2 erw
в sj rtsfdskajfhk ворыва6 вылваор
jsfju фыалор фло5 р
rt jsdrt jdakfjh af3 лор
sr tjstrsdf sdfsdf5 sdf
tsrj dsfglsdh askfjdgh8 kajg
ste jtrdsakfjh a9 sjdg
в кеовкое вкевыалор фыопр7 влор
кве оaskfhg asdhg9 h
выплор оап3 роы
еук рвыап лофр2 уо
выпр ва sfg3 d
пsda asd8 вы
df4 fff
gg6 g
апо h h2 h
вар авпр6 gdh
а4 а
sd3 ааа

Тут нам не особо поможет прошлое заклинание - оно учитывает тот факт, что слов в каждой строке 3 - оно начиналось с Ctrl-Right, Ctrl-Right - так мы проскакивали два первых слова.

Немного поразмыслив можно прийти в кодифицированной версии исходной комбинации, которая будет вначале отправляться в конец строки и оттуда отсчитывать местоположение слова с цифрой. Выглядеть оно будет так: End, Ctrl-Left, Left, Shift-Left, и дальше как обычно - Ctrl-Ins, Home, Shift-End, Shift-Ins, Enter. Запишем его в макрос и превратим усложненную структуру в столбик цифр.

Пойдем дальше, еще немного усложнив исходную структуру. Пускай теперь цифр может быть одна или две в зависимости от чего-то там, природа чего нам не ясна. Но перед этими цифрами всегда находится либо знак № либо знак #. Тут простыми комбинациями не обойтись. Но можно подготовить текст таким образом, чтобы он стал подготовлен к извлечению полезной информации с помощью некой последовательности нажатых комбинаций клавиш. Что тут можно придумать? Часто помогает либо ручная доработка текста (а к примеру, если бы полезные строки отставали друг друга на произвольное число пустых или других бесполезных строк), либо с помощью Replace All. Итак исходный текст таков:

sdf sdf впр йцу кен№34 uio
gdsh ah trjw  fh ttвыв ваыаыва№143 sdhg
th kg hdkgjh dsf turtr№45 dfsfhgf
df hkjsd hgksвыапып thyrth№13 выв
sj agrj srпраовр выорфыор№95 црцр
ser рыекш srвыалрфл фыор№26 erw
в sj rtsfdskajfhk ворыва№67 вылваор
jsfju фыалор фло№54 р
rt jsdrt jdakfjh af#3 лор
sr tjstrsdf sdfsdf№54 sdf
tsrj dsfglsdh askfjdgh№8535345 kajg
ste jtrdsakfjh a#96 sjdg
в кеовкое вкевыалор фыопр№75 влор
кве оaskfhg asdhg#93 h
выплор оап№35 роы
еук рвыап лофр№26 уо
выпр ва sfg#37 d
пsda asd№8555 вы
df#45 fff
gg№65 g
апо h h#24 h
вар авпр#65 gdh
а№45 а
sd#366666 ааа

Вначале сделаем замену знака "№" на "-".

Как это сделать? Отправляемся в начало документа и выбираем пункт меню Правка->Заменить.


Наберем эти два символа в соответствующие поля и нажмем "Заменить все" (тут одно допущение, что этот символ более нигде в тексте не встречается лишь в предпоследнем слове и только перед числом, которое необходимо извлечь)


Ок, спасибо


Теперь то же с заменой знака "№" на "-".




Теперь текст выглядит таким образом, что с ним вполне может справиться заклинание из комбинации клавиш. Дело в том, что символ "-" при использовании комбинаций Ctrl-Left и Ctrl-Right ведет себя так же как и знак пробела - то есть считается разделителем слов. Напомню что комбинации Ctrl-Left и Ctrl-Right перемещают курсор ввода влево и вправо не на символ, как Left и Right, а на слово, т.е. на набор символов разделенных одним из символов разделителей, в число которых входит и пробел и знак "-".

Комбинация-заклинание будет такой: End, Ctrl-Left, Left, Ctrl-Shift-Left, и дальше как обычно - Ctrl-Ins, Home, Shift-End, Shift-Ins, Enter.

Вот так хитро можно заработать еще пару баллов. Фишка в том, что найти способ изощриться можно в 99% случаев - помогут любые познания в возможностях Word. Но все же бывают случаи, когда ничего на ум не приходит. Текст большой, обработать его надо, к макросам привык... Вот бы если можно было бы модифицировать написанный макрос. А почему, собственно, нельзя? Интересно как и где хранится макрос? В любом случае, если ничего не найду, то всегда смогу обработать все руками...

Немного инвестированного времени и удивительное открытие! Замечательно, что каждое действие с Word (думаю, что так же и с любым другим приложением Office) при включенной записи макроса записывается в текстовый файл. Текстовый файл - является исходным кодом на языке Visual Basic. Значит, разобравшись в этом не хитром языке, я смогу научить компьютер управлять Word'ом более разумно, чем тупое повторение записанных ранее действий.

Усложним еще немного наш текст, убрав символы маркеры № и #, которые раньше отмечали в предпоследнем слове начало последовательности цифр. Хотя стоп! Тут тоже есть возможность решить задачу без копания в кишках записанных макросов. Только что появилась идея, видать как ответ на вопрос, заданный в десятке абзацев выше по тексту. Идея проста, если знать о возможностях поиска в Word.

Итак у нас есть последовательность символов без каких либо символов маркеров:

sdf sdf впр йцу кен34 uio
gdsh ah trjw  fh ttвыв ваыаыва143 sdhg
th kg hdkgjh dsf turtr45 dfsfhgf
df hkjsd hgksвыапып thyrth13 выв
sj agrj srпраовр выорфыор95 црцр
ser рыекш srвыалрфл фыор26 erw
в sj rtsfdskajfhk ворыва67 вылваор
jsfju фыалор фло54 р
rt jsdrt jdakfjh af3 лор
sr tjstrsdf sdfsdf54 sdf
tsrj dsfglsdh askfjdgh8535345 kajg
ste jtrdsakfjh a96 sjdg
в кеовкое вкевыалор фыопр75 влор
кве оaskfhg asdhg93 h
выплор оап35 роы
еук рвыап лофр26 уо
выпр ва sfg37 d
пsda asd8555 вы
df45 fff
gg65 g
апо h h24 h
вар авпр65 gdh
а45 а
sd366666 ааа

Сам факт того, что у нас есть число, а вслед за ним цифра - является маркером. В текстовом поиске Word (я использую MSOffice 2003 SP3) нет регулярных выражений (а зря, хотя я уже знаю как это пофиксить с помощью макросов - позже расскажу), но есть некоторые шаблоны.

Станем в исходную позицию в начало текста. Начнем запись макроса, как и в прошлые разы.





Откроем диалог поиска


Нажмем "Больше", если он до сих пор не нажат


После нажмем "Специальный" и выберем "Любая буква"


А после "Специальный" и "Любая цифра"


Шаблон будет выглядеть так, а мы выберем направление поиска "вперед" и нажмем "Найти далее"


Помним при этом что происходит запись - никаких лишних движений. Если что-то сделали не так, пробуем либо остановить запись макроса и начать с начала либо исправить это. Сказав "исправить" я имел ввиду, к примеру, если случайно при записи нажал Left, то можно нажать Right и ничего страшного. Но стоит помнить, что исправление как часть заклинания будет выполняться многократно для всех последующих строк и возможно для какой-то из строк вызовет сбой

В результате поиска курсор выделит первых (сразу после того место, в котором стоял курсор) два символа в тексте удовлетворяющим шаблону "одна буква+одна цифра". Больше нам от поиска ничего не надо, а потому закроем его.


Теперь можно нажать на комбинацию Left, Right, Ctrl-Shift-Right, Shift-Left, и дальше как обычно - Ctrl-Ins, Home, Shift-End, Shift-Ins, Enter.

Вот и все хитроумное решение. Запись можно заканчивать и залипать комбинацию клавиш, которую выставили на этот макрос. Хотя я бы советовал на первых порах потестить то, что только что записано критически всматриваясь в результаты работы макроса - извлечение цифр их строк. Может в процессе записи макроса допущена ошибка?

Есть у макросов и другое патогенное свойство - когда человек делает некоторую однотипную операцию, он может допустить ошибку, но он сразу отреагирует, если перед ним возникнут данные, которые не попадают под привычный шаблон. Компьютер (макрос) как раз наоборот - сделает все красиво по шаблону, но не заметит, если в исходных данных возникнет исключение. Это стоит иметь ввиду.

Еще немного усложним задание и расставим цифры везде по тексту. Как и прежде, фильтровать будем цифры в конце предпоследнего слова, расположенные сразу за буквой. Тут опять же можно хитро извертеться. Исходный текст:

s65df s54df в645п5р 4656йцу к5ен34 ui8o
gds456h a4546h t5rjw  f64h ttвы46в ваы65аыва143 sdhg456
456th k456g8ы hd456kgjh d4456sf tu65rtr45 dfs56fhg4f
d6f hk456j3sd hg456ksвыапып54 thyrth13 выв
sj ag84r56j srп48раовр выорфыор95 црцр
se4566r ры4546екш s3rвыалрфл ф4ыор26 erw
в 546j rt46346sfdskajfhk ворыва67 вылваор
jsf25ju фыа456лор фло54 р
rt jsd6rt jdak5fj4h af3 л46ор
sr tjst56rsdf sdfsd2f54 s46df
tsrj dsfgl5dh3 askfjdgh8535345 kajg
ste jtrd654sakfjh2 a96 sjd54g
в кеов54кое вкев64ыалор фыопр74565 влор
кве 53466оaskfhg6 asdh4g93 h
вып46лор о456п35 роы
еук рвыа456п лофр26 уо
вы46пр ва2 sfg37 d
пs56da asd8555 вы456
df42645 fff14
gg665 g456
ап456о h h424 h456
вар346 а456впр65 gdh456
а645 6а
sd366666 а82аа

Видимо тут нам надо сместиться в конец строки, потом перескочить через одно слово по направлению в начало, после включить хитрый поиск по шаблону "буква+цифра" по направлению от курсора ввода к началу текста и так найти начало нашей последовательности цифр, а дальше как обычно - скопировать ее и вставить вместо существующей строки. Вперед!

Отправляемся в начало текста и включаем запись макроса





Комбинация будет такой: End, Ctrl-Left, Ctrl-F (это поиск), далее настраиваем поиск и ищем


После закрываем его


И как в прошлый раз: Left, Right, Ctrl-Shift-Right, Shift-Left, а дальше как обычно - Ctrl-Ins, Home, Shift-End, Shift-Ins, Enter.

Все :)

Кстаи тут можно проверить что бывает, когда макрос пытаются выполнить на тексте, для которого он не написан. Достигнув конца документа, вызови еще пару раз макрос. Word мне сказал


А потом


Кстати именно так я узнал про то, как хранятся макросы. Если теперь нажать на "Debug" то можно отправиться к редактору Mocrosoft Visual Basic и там увидеть исходный код со строчкой, в которой произошел сбой.


Другой способ, как добраться до этого окна (на случай, если выполнение макроса в конце документа не привело к сбою) - идем в меню Сервис->Макрос->Макросы...


Дальше выбираем некоторый (самый последний по порядковому номеру или же какой-то другой, имя которого запомнил) макрос и нажимаем "Изменить"



Как результат то же окно редактирования исходного кода макроса.

Это и есть наш последний макрос. Если разобраться, то можно сопоставить строку кода бейсике и действие совершенное в ходе записи макроса. Напомню что мы делали:
End, Ctrl-Left, Ctrl-F (это поиск), далее настраиваем поиск и ищем, Left, Right, Ctrl-Shift-Right, Shift-Left, Ctrl-Ins, Home, Shift-End, Shift-Ins, Enter.

Тот же код, с моими комментариями-сопоставлениями


Теперь, если требование поменяется к примеру так, что надо будет оставлять последовательность цифр только тогда, когда сумма всех цифр будет кратна двум, тогда без изменния этого кода - нам никак не обойтись.

Вот модификация исходного макроса так, чтобы он работал по новому алгоритму.

Sub Макрос16()
'
' Макрос16 Макрос
' Макрос записан 28.11.2010 СанЁк Баглай
'
    ' End
    Selection.EndKey Unit:=wdLine

    ' Ctrl-Left
    Selection.MoveLeft Unit:=wdWord, Count:=1

    ' Ctrl-F
    Selection.Find.ClearFormatting

    ' настраиваем поиск и ищем
    With Selection.Find
        .Text = "^$^#"
        .Replacement.Text = ""
        .Forward = False
        .Wrap = wdFindAsk
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute

    ' Left
    Selection.MoveLeft Unit:=wdCharacter, Count:=1

    ' Right
    Selection.MoveRight Unit:=wdCharacter, Count:=1

    ' Ctrl-Shift-Right
    Selection.MoveRight Unit:=wdWord, Count:=1, Extend:=wdExtend

    ' Shift-Left
    Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend

    ' Ctrl-Ins
    Selection.Copy
    
    ' получаем скопированную строку
    Dim Numbers As String
    Numbers = Selection.Text
    
    ' суммируем все цифры в строке
    Dim Sum As Integer
    Sum = 0
    For Index = 1 To Len(Numbers)
        Sum = Sum + Mid(Numbers, Index, 1)
    Next
       
    ' Home
    Selection.HomeKey Unit:=wdLine

    ' Shift-End
    Selection.EndKey Unit:=wdLine, Extend:=wdExtend
    
    ' Delete
    Selection.Delete
    
    ' если сумма цифр делится на два нацело, тогда вставим число в текст
    If ((Sum Mod 2) = 0) Then
        ' Shift-Ins
        Selection.PasteAndFormat (wdPasteDefault)
        
        ' Enter
        Selection.TypeParagraph
    End If
End Sub

А вот те линки, которые мне помогли разобраться в незнакомом для меня языке.
определение переменных visual basic, Selection объект visual basic, String как массив visual basic, остаток от деления visual basic,
Как видишь - все спрашивал у гугла. Подобным образом можешь и ты нагуглить себе решение.

Делать как ты понимаешь с текстом можно все, что угодно, т.е. все, что позволит язык программирования высокого уровня (а это стремится к "все").

Бонус для тех, кто пишет мануалы с большим количеством рисунков и постит их в blogger. Количество рисунков в этом посте 42. Бывают посты, в которых количество скриншотов достиргает пару сотен. Естественно писать такие мануалы не просто, но написав пару штук придумаываешь способ оптимизации. Я к примеру пишу текст и создаю скриншоты параллельно с тем, как проделываю что-то, что описываю. Текст пишу в реадкторе blogger, а рисунки сохраняюю в какой-то папке с именами 1.png, 2.png, 3.png и так далее. В тексте же оставляю ссылки - вот например кусок исходника этой же статьи


После того, как статья готова - мне надо как-то слить текст с рисунками. Вначале я добавляю все рисунки в начало текста.



В режиме редактора блоггера "Изменить HTML" их можно наблюдать как div'ы.


После копиную весь пост в этом же режиме "Изменить HTML" в Word, где у меня уже есть подготовленный макрос, который вставляет первый div с рисунком на свое место, а потом удалит его.

Макрос записывался так:

В начале я сделал глобальную замену всех строк "рисунок " на "рисунок #"



Так я знаю точное количество ссылок, и могу сравнить его с количество файлов-скриншотов. Если числа не совпадают - значит есть либо ошибка, либо в тексте где-то встречается слово "рисунок ". Потому советую на будущее использовать какое-то другое ключевое слово, чтобы исключить "либо-либо"

После замены и перепроверки я установил курсор в исходную позицию и включил запись макроса.





Далее я нашел порядковый номер скриншота в текущем div (строку ".PNG" />").



После этого я скопировал порядковый номер файла, а потом скопировал еще весь div, нажав последовательность комбинаций: Left, Shift-Ctrl-Left, Ctrl-Ins, End, Shift-Ctrl-Home, Ctrl-Ins, Del, Del, Ctrl-F

Дальше я нашел строку "рисунок #1" вперед по тексту и закрыл поиск за ненадобностью


После я просто вставил из буфера обмена скопированный ранее div, заменив ним ссылку "рисунок #1"


и вернулся в исходное положение, нажав Ctrl-Home.

Теперь можно отправиться к исходнику нашего полуфабриката и доработать его.



Вот макрос-полуфабрикат. Почему полуфабрикат? Потому что работает он только для «рисунок #1»


Сделаем его рабочим для всех остальных дивов + добавим немного проверок для пущей уверенности

Sub Макрос20()
'
' Макрос20 Макрос
' Макрос записан 29.11.2010 СанЁк Баглай
'    
    ' находим позицию с порядковым номером рисунка
    Selection.Find.ClearFormatting
    With Selection.Find
        .Text = ".PNG"" />"
        .Forward = True
        .Wrap = wdFindAsk
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute
        
    ' копируем и сохраняем порядковый номер рисунка
    Selection.MoveLeft Unit:=wdCharacter, Count:=1
    Selection.MoveLeft Unit:=wdWord, Count:=1, Extend:=wdExtend
    Selection.Copy
    Dim Number As String
    Number = Selection.Text
    
    ' копируем весь div с рисунком и удаляем его, освобождая очередь второму
    Selection.EndKey Unit:=wdLine
    Selection.HomeKey Unit:=wdStory, Extend:=wdExtend
    Selection.Copy
    
    ' проверка скопировали ли мы div или что-то другое
    Dim Div As String
    Div = Selection.Text
    If (Len(Div) < 400) Then
        ' удаляем скопированный div
        Selection.Delete Unit:=wdCharacter, Count:=1
        Selection.Delete Unit:=wdCharacter, Count:=1
        Selection.Delete Unit:=wdCharacter, Count:=1
        
        ' ищем строчку "рисунок #N", где N - порядковый номер, который мы скопировали
        Selection.Find.ClearFormatting
        With Selection.Find
            .Text = "рисунок #" + Number
            .Forward = True
            .Wrap = wdFindAsk
            .Format = False
            .MatchCase = False
            .MatchWholeWord = False
            .MatchWildcards = False
            .MatchSoundsLike = False
            .MatchAllWordForms = False
        End With
        Selection.Find.Execute
        
        ' если нашли соотвествующую сноску
        If (Selection.Text = Selection.Find.Text) Then
            ' заменяем строку "рисунок #N" на div
            Selection.EndKey Unit:=wdLine, Extend:=wdExtend
            Selection.PasteAndFormat (wdPasteDefault)
            Selection.TypeParagraph
        End If
    End If
    
    ' возвращаемся в исходню позицию
    Selection.HomeKey Unit:=wdStory
End Sub

Простенько, но какая экономия времени (естественно, чем больше текст и чем чаще им пользоваться - тем больше экономия времени).

Надеюсь тема раскрыта.

Enjoy.

5 комментариев:

  1. Простенько и экономия времени:
    перейти на Emacs )))

    ОтветитьУдалить
  2. Ответы
    1. Спасибо за пост, очень выручил. Очень удобно и быстро если правильно настроить))

      Удалить
    2. Пожалуйста Юрий. Рад помочь!

      Удалить
  3. Анонимный19 мая 2013 г., 0:59

    Этот комментарий был удален администратором блога.

    ОтветитьУдалить