Суббота | 05.07.2025 |02:44
Приветствую Вас Гость Мира Спайро | RSS
Результаты поиска
aleksusklimСообщение # 661 | Тема: Znaczky Пятница, 07.10.2016, 00:08
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Znaczek #4:

Сначала – про Нору Галь:




А знаете, я наконец прочитал.

Ух.

Да уж, это было непросто!
Интересно и познавательно. Но такую вещь на расслабоне не почитаешь, это настраиваться надо.
А вообще – круто! Но дико. В том смысле, что может в одном или в другом, но ВСЮДУ – я бы такие выкрутасы с красивыми словечками выдавать не смог, признаю…

Ха, возможно я тоже весьма отравлен канцеляритом. И обычно я как бы считал это преимуществом, потому что много когда владение им играет большую пользу. Другое же дело, что он и не должен ни для чего требоваться, но это уже не ко мне, я просто приспособился как мог.
Но я ведь понимаю, когда моя речь свободная – канцеляричу как хочу – а когда я создаю некий продукт, где этому не место – и легко избавляюсь от него.
Однако ведь автор книги призывает-то как раз из намеренного искоренения его из обыденной жизни в том числе.

Вообще, книга переполнена её личным отношением ко ВСЕМУ. Хотелось бы больше конкретики, больше точных примеров и ничего лишнего. Нет, там очень и очень много примеров, но он часто разбавлялись возгласами «ну как так, ну сколько ж можно». Понятно конечно, что книга должна быть яркой и мотивирующей, но я-то больше предпочитаю «справочники». Хотя думаю, многим такой стиль изложения наоборот понравится.

Ой, а с этим улучшением-украшением переводимых текстов!
Это надо постоянно как бы кричать самому себе:
– Бред.
– Но так в оригинале!
– Что это значит?
– Ну это как бы…
– Нет. Ещё!
– Это когда…
– Так, и?
– Там вот как бы…
– Проще!
– Ну там всё…
– Ещё проще!!
– Не знаю! Ну это типа…
– Да что это!?
– Это бывает, когда…
– Ну что это такое? ))
– Да это же!
– Ага, во-от!
– И ещё!..
– Всё, так и напиши.

И так на каждую фразу. На примерах показывалось, как битва за каждое слово выигрывает бой за всю фразу.
Хм… В принципе, это именно то, что делает Томас в переводе Spyro2.

Нора Галь агитирует за «дерзкий» перевод!
О, и зря вы сказали, что последние главы можно не читать.
Это же «Best Practices»! Ага, диву даёшься, как они выбрали именно такой вариант перевода. А ещё больше нравятся описания – которые следует бы совать в нос тому, кто в очередной раз заявит «имена не переводятся» или «так написано в оригинале».

Отсюда вытекает ещё одна проблема книги. Ну не будь она такой большой, такой тяжёлой для чтения и вникания…
Вот кому я могу её порекомендовать? Кому захочется в ней копаться?
Тому, кто плохо переводит? Не, если он аж настолько плохо переводит, что только полноценное прочтение такой книги ему поможет – то он и читать её не будет, у него сил и осознанности не хватит.
Тому, кто хорошо переводит? Да, он прочтёт. Но весьма нескоро, у него и так много дел.
Просто показать нужный отрывок в нужный момент? Но тогда не дойдёт вся мораль, весь напор повествования книги, а значит – и авторитет прочтённого.

Вот можно сказать, что я познал истину (это как фильм «Дух времени», наверное). Не то чтобы я её не знал, но теперь я точно уверен в ней!
Но вот «передать» эту истину через эту книгу почти невозможно.
Нельзя заставить прочитать её.
Тем более, нельзя заставить вникнуть в текст! (Даже я пропускал некоторые абзацы, дойдя до их середины – я и слов таких не знаю, и произведения эти не читал… Хотя теперь может «маленького принца» прочту, а то всё муми-тролль, муми-тролль…)
Нельзя «просто сослаться» даже на отрывок, и ожидать, что перешедший по ссылке просветлеет.

Хотите обратный пример?
Берём хренового переводчика за шкирку, и тыкаем сюда:
http://translations.ted.org/wiki....ий_язык
Объявляем это истиной, и приказываем следовать. Не знаю, но по крайней мере одного переводчика, всюду писавшего в субтитрах «Вы» с большой буквы – мы таки переубедили. Но не только одной этой ссылкой… (причём жертва отбивалась неким правилом русского языка, в котором говорилось, что «на "Вы" нельзя обращаться к нескольким лицам», из чего якобы следовал вывод, что к одному лицу – можно и нужно.)




Тут – как я пытался агитировать за неё среди тамошних переводчиков:




Есть довольно полезная книга:
http://royallib.com/book/gal_nora/slovo_givoe_i_mertvoe.html
Интересно, знают ли о ней современные переводчики – такие как мы – ведь мне иногда кажется, что нет.
Польза от книги огромная, но у неё есть одна проблема: это не для лёгкого чтения, и чтобы её прочитать, нужно поставить себе серьёзную цель.

Каждый раз, встречая «имена не переводятся» или «так написано в оригинале», мне хочется бесконечно апеллировать к этой книге. Но вытаскивать оттуда цитаты не так авторитетно, как позволить самой книге открыть глаза другим.

Одно дело, когда переводчик ошибся, что-то пропустил или неправильно понял оригинал – достаточно лишь объяснить и может даже поспорить.
Но если же ошибочное мнение закоренело – то изменить его будет очень и очень непросто, особенно простыми разговорами.
А тут – собрано всё самое яркое, объясняются (может даже слишком часто) последствия, вытекающие из неправильного подхода к переводу. Кажется, всем достаточно просто прочитать всё это – и качество перевода возрастёт. Либо из-за общей смены отношения, либо из-за более частого включения мозга там, где раньше использовалось «первое слово по словарю», а где-то даже из-за скромности самого переводчика, который не рискнёт предлагать плохой вариант, заведомо осознавая его низкокачественность.



SubCmpAlgo v1.1
– а вот что ещё я собрал.
Далее – большая сборная копипаста того, как я создавал алгоритм сравнения субтитров.
Это из разных диалогов и источников, и то лишь самое основное. Сначала я обсуждал задачу с математиками и программистами, а затем уже показывал результат переводчикам из TDT.




Короче, у меня есть две числовые прямые, на них – непересекающиеся отрезки.
Я накладываю эти прямые друг на друга, и хочу порезать на кусочки.
Моя цель – как-то соотнести отрезки на одной прямой с отрезками на другой.

Задание нечёткое, могу лишь примерно описать, чего хочу получить:
Если отрезки начинаются в одинаковых местах – резать по ним.
Если отрезки чуть-чуть сдвинуты – всё равно резать (через какую точку пройдёт – неважно, меня только интересуют группы соотнесения отрезков по участкам)
Если отрезок не соответствует никакому на второй – пофиг, резать его одного.
Если один отрезок поглощает другой – они должны оказаться в одной группе.
Когда один отрезок поглощает несколько – те должны быть объединены в его группу.
И самое главное: отрезок не должен попасть более чем в одну группу.

Пока у меня идея – считать пустые промежутки между отрезками – тоже отрезками, тогда прямые просто разобьются точками.
Потом найти пару противолежащих точек, между которыми наименьшее расстояние – и разбить по ним.
Продолжать до тех пор, пока получаются разрезы.

Верный способ? Или есть контр-пример?

Вообще, это две разные версии субтитров к одному и тому же видео, которые я хочу построчно сравнить.
Но тайминг разный, и количество строк разное.
Но они _примерно_ на тех же местах по времени.

Иногда в одном файле фраза одна и длинная, а в другом – две коротких. Тогда они должны быть соединены, чтобы соответствовать.

Так. У меня есть три файла субтитров.
Субтитры – это наборы текстовых реплик, персонажей и тайминга.
Тайминг – это пара начало+конец каждой реплики относительно всего файла.
Пример:

0:17:11.42,0:17:14.59,Rarity,Who cares what some stuffy unicorn thinks of the food here.
0:17:14.59,0:17:16.30,Rarity,It's exquisite.
0:17:16.58,0:17:17.68,PinkiePie,That's true.
0:17:18.24,0:17:21.64,Rarity,And you don't need three silly hooves in your window to prove it.
0:17:21.64,0:17:23.14,PinkiePie,That's double true.
0:17:23.44,0:17:26.48,Rarity,You just need ponies in here to give it a chance.
0:17:26.82,0:17:29.37,Rarity,Ponies that would tell everypony else in Canterlot
0:17:29.37,0:17:31.94,Rarity,that the "Tasty Treat" is best food in the city!
0:17:32.16,0:17:34.24,PinkiePie,That's true times three!

– некоторые концы совпадают с началами следующих фраз. Но это не запрещает им пересекаться.
Вначале я хочу взять представить их как отрезки во времени, и взять объединение.
Я соберу пересекающиеся фразы в кусочки большего размера, объединив и их текст по порядку (вчера часа в три ночи я думал, что я уже смог запрограммировать это, но теперь вижу, что нет…)
Теперь я имею непересекающиеся (но возможно, касающиеся) отрезки, имеющие начала, концы и свой текст.

Так я поступаю с двумя файлами субтитров.
Основная задача – вывести всё это в таблицу, как в той, что я показал. По строчкам должны располагаться подобранные реплики.
Но основная проблема в том, что тайминг в обоих файлах на за что не совпадёт (его делали разные люди на слух). Более того, разбивка на реплики разная: где-то могут быть большие и длинные фразы, а где-то они же (это субтитры к одному и тому же видео) они разбиваются на более короткие.

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

Но основная задача – сопоставить субтитры. В итоге мне нужно, чтобы программа автоматически собирала напротив друг друга правильные фразы, которые соответствуют друг другу. Без ручного выравнивания.

Предполагаем, что на шкале времени есть некая «информация», а две линии – это субтитры. На линиях – отрезки, которые представляют собой фразы по таймингу. Считаем, что они доносят ту же самую информацию, но не синхронны между линиями.
Нужно порезать отрезки на группы, чтобы в каждую группу старались попасть отрезки с одинаковой информацией. Но резать можно только по границам отрезков.

Понять бы, что считать… Например, нужно ли мне максимизировать количество групп? Видимо, нет. Потому что уж если две к двум фразы никак не сходятся – то их и нужно оставить парой. Грубый пример:
1)
– я
– умею разделять отрезки

2)
– я умею разделять
– отрезки

Тут нет соответствия между фразами, их нужно оставить «две на две». Если бы в одном из них была всего одна целая фраза – она должна была бы соответствовать сразу двум.

Но чаще всего будет соответствие один к одному. Проблема в том, что программа должна предъявить лучшее разделение, основываясь исключительно на тайминге фраз, а не на их смысле в тексте, как делается вручную.

И наконец, у меня не два файла, а три. Ну, в перспективе хочется сделать общий случай для большего количества. Но три нужно точно.
Хотя, я точно знаю, что два из них – ОДИНАКОВЫ. Но это в моём частном случае. Тут бы для двух хотя бы решить, да…

Но мне кажется, если алгоритм будет грамотный, его можно и обобщить. Однако там уже придётся потребовать хотя бы независимость от порядка, в котором на вход приходят файлы, и чтобы при одинаковости нескольких из них алгоритм дал бы тот же вердикт, как если бы файлов было меньше – без этих самых копий.

Надоело оперировать абстрактными понятиями. Собираюсь выгрузить субтитры в условную временную шкалу и по факту посмотреть, как именно по статистике на ней будут расположены настоящие точки начал и концов реплик…

Вот моё визуальное сравнение тайминга последнего эпизода:
http://klimaleksus.narod.ru/Files/T/asscmp0V0.htm

Синяя шкала короче, получается временной лаг. Если настроить на три секунды (поле 300) – то примерно на середине экрана как раз выравнивается.
Светлые полоски – «концы» отрезков (тёмные – начала), если поверх них начало следующего – то не видно.

Взаимная близость.

http://klimaleksus.narod.ru/Files/T/asscmp0V1.htm

Это работает!
Для каждой точки ищу ближайшую точку на второй прямой, и запоминаю её номер.
Если две точки на разных прямых считают друг друга ближайшими – то режу по ним.
Проблем нет ни с поиском, ни с длинными невыгодными разрезами – потому что если ближайшая точка уже занята другим разрезом, то значит для неё текущая не ближайшая, и резать не надо.
Как обобщение на случай нескольких прямых можно рассматривать попарную близость – пусть каждая точка запоминает ближайших на остальных прямых. И резать через всю группу, если они все считают друг друга ближайшими.

Осталась проблема таймлага. Он дискретный, а не плавный.
То есть длительность и скорость всех диалогов одинакова. Но во время уходов на рекламу синхронизация теряется.
Возможно, эти кусочки можно выявить автоматически, потому что разрыв отрезков очень большой (но подбирать надо как-то адаптивно). Потом порезать по рекламе, и устроить регрессию.

Либо проще – взять некий порог (возможно адаптивно), меньше минимальной длительности этих самых пауз от вырезанной рекламы. Потом пройти по всем отрезкам, и если паузы больше, чем порок – сделать её размером ровно с порог, чтобы начала очередных отрезков совпали.

Надо бы вывести все длины промежутков между всеми отрезками и построить таблицу или график…

Ого, даже порогом ограничить вот так просто не получается. Если в одном варианте субтитров, скажем, заставочная песня сопровождена текстом, а в другой – нет, то пустота вместо неё сворачивается в порог, и всё дальнейшее соответствие неверно.

Как-то параллельно надо что ли длинные промежутки пауз искать…

Да наконец!
http://klimaleksus.narod.ru/Files/T/asscmp0V2.htm
(оказывается, отображается нормально только в Firefox)

Смог выровнять по паузам. Алгоритм такой:

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

Теперь, у нас есть две дырки (если одна, то втору считаем максимально удалённой). Берём ту из них, конец которой ближе по времени.

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

Выравниваем! Двигаем все последующие точки на одной из прямых вперёд. На той, точка выравнивания которой ранее (мы же взяли одну точку, и искали соответствующую ближайшую, которая могла быть как до, так и после неё).

Переносим фиксирование на точки, следующие за теми, по которым мы выровняли, и повторяем алгоритм.

О, и я даже придумал, как автоматически выбирать порог!
Пусть он сначала будет минимальным – полсекунды. Каждый раз, когда мы собираемся выровнять – проверяем, превосходит ли добавляемая величина этот порог.
И если да, то отменяем все сделанные манипуляции, сбрасываем массив и увеличиваем порог. Скажем, ещё на полсекунды. И повторяем всё заново до тех пор, пока выравнивание ни разу не перестанет превышать его.
Ага, тут можно даже бинарный поиск применять, но это уж чересчур. Добавление полсекунды и полный пересчёт вполне работают, тем более что чем меньше порог – тем быстрее произойдёт сброс.

А ещё я думал устроить регрессию на участках, которые получаются выравниванием, но вроде и без этого всё отлично вышло.

Белые горизонтальные линии на страничке – разрезы выравнивания. Рядом есть вертикальная чёрточка – на столько были сдвинуты вперёд реплики на соответствующей прямой.

Всё, осталось лишь обобщить на три и более прямых…

Фу-у, я с многомерным массивом запарился…

Не могу сообразить, как попарную взаимность получить. Вот у меня короче что есть:
– N прямых.
– На каждой из них P(n) точек.
– Каждая из них считает «ближайшей» Bn(i,m) одну из точек на каждой из оставшихся прямых (n≠m)

Я, например, храню это вот в таком массиве: M[n][i][m]=j, где
n – исходная прямая (0..N-1)
i – номер точки на ней (0..P(n)-1)
m – целевая прямая (0..N-1)
j – номер точки на целевой (0..P(m)-1)

Изначально я хотел пройти по нему, и делать
t=M[n][i][m]; if (M[m][t][n]==i) {/* у точек взаимная близость */}

, но оказалось что точки других прямых, которые текущая точка на текущей прямой считает ближайшими к себе, даже если они в свою очередь для этой прямой считают данную точку ближайшей и к себе – они не обязаны быть ближайшими между собой!

Для двух прямых это неверно. Для трёх – определяется очень просто (достаточно проверить взаимную близость двух концов ближайших точек от текущей) , но для >=4 – вообще неочевидно, как проверять.

Я думал над чем-то вроде
for(i=1;i<n;i++) { for(j=0;j<i;j++) { /* как-то проверять близость для прямых i и j */ }}
, или например собирать в один массив все найденные близости, а если там уже есть – то проверять, что все имеющиеся тоже взаимно близки с добавляемым.

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

Мне уже несколько раз казалось, что я придумал правильный метод хранения и обработки, но как только я начинаю программировать – понимаю, что всё совершенно не стыкуется…

Ещё у меня сверху нужно отодвигать часть файла, если одна из дорожек внезапно закончилась, чтобы другие не пытались безуспешно взаимно бизиться с ней. Но это вроде я смогу закодить.

Ну и сам финал – импорт .ass, экспорт .csv
И интерактивное сравнение-голосование ^^

Мне нужно как-то высчитать «группы взаимности», в которых все точки между собой попарно ближайшие…

Более того, как обходить прямые?
Если только одну – то она может оказаться короче других, и некоторые точки прочих не будут даже рассмотрены (а там есть условие, что они могут быть взаимно близки между собой, отбросив эту короткую).
А если все – так дубли же!

Если мы сравниваем eng+a2a+tdt, то из того, что в последнем одна фраза, а в первых двух – две, то это значит, что меж ними нет никакой ещё одной группы. И лишние линии надо выкинуть.

Но я сделаю так: когда обнаруживается «большая» дырка на одно прямой – её концы отмечаются, чтобы во-первых, выровнять всё что дальше; а во-вторых – чтобы на этом промежутке её влияние на взаимность других прямых нивелировалось.
Тогда, если останется лишь одна прямая – например, наша заставочная песня – каждая фраза ляжет в отдельную ячейку, как взаимная сама с собой.

Но если на нормальном промежутке хоть у кого-то нет взаимности – отбрасывать! На этом строилась первоначальная версия алгоритма для двух прямых, и она работала идеально!
Вернее, проблема была только в одном месте, когда точки продолжительно идут в шахматном порядке. Но там даже не понятно, что делать (особенно потому что я самих фраз-то не вижу…), может будет понятно, когда таблицу с текстом получу…

У меня есть n линий, на которых стоят точки (одномерные).
Везде далее индекс «c» можно не учитывать.
В массиве f[h][i][c] – координаты i-той точки на h-той линии. На одной линии f[h].length точек.

Сначала я хочу найти для каждой точки на каждой из линий ближайшую точку.
Завожу особый массив m[h][i][H][c]=j – это j-координата точки на H-той линии, и эта точка – ближайшая к точке i на h-той линии.

m=[];
for(h=0;h<n;h++){ // линии
m[h]=[];
for(i=0;i<f[h].length;i++){ // их точки
m[h][i]=[];
for(H=0;H<n;H++)m[h][i][H]={b:-1,e:-1}; // условно m[h][i][H][c]=-1;
}}

– изначально заполняю «-1», то если ближайшая точка ни для кого не известна. Теперь:

for(c in {b:'',e:''}){ // условно c=0
for(h=0;h<n;h++){ // по всем линиям
// для текущей линии:
for(i=0;i<f[h].length;i++){ // по всем её точкам
V=f[h][i][c]; // численное значение текущей точки
m[h][i][h][c]=I; // сама для себя автоматически ближайшая
for(H=0;H<n;H++){ // по всем другим линиям (и по своей тоже)
d=-1;uu=-1; // счётчики расстояния обнуляем
for(j=0;j<f[H].length;j++){ // по всем точкам «второй» линии
v=V-f[H][j][c]; // расстояние от изначальной до текущей
if(v<0)v=-v; // по модулю…
if(d==-1||v<=d){ // если первая или ближе –
d=v;uu=j; // запоминаем новое кратчайшее, и индекс
}} // наконец,
if(uu==-1)console.log(h,i,H,c); // (не выполнится, всё верно)
m[h][i][H][c]=uu; // присваиваем в нужный массив
}}
// закончили
}}

Проблемы возникают уже на следующем шаге:

for(c in {b:'',e:''})for(h=0;h<n;h++)for(i=0;i<f[h].length;i++)for(H=0;H<n;H++)if((v=m[h][i][H][c])>-1&&i!=m[H][v][h][c])m[h][i][H][c]=m[H][v][h][c]=-1;

Я пытаюсь проверить, считают ли какие-то точки друг друга ближайшими по взаимности, и если нет – отбрасываю их.
Если v=m[h][i][H][c] – это для линии h и её точки i индекс ближайшей точки на линии H.
Значит, если я возьму обратное, m[H][v][h][c] – то должен получить текущий же индекс, в том случае, если для линии H и этому индексу точки, ближайшей на текущей линии h будет иметь текущий индекс i.

Но в результате я получаю очевидные ложные срабатывания на точках, которые являются взаимно близкими. Всё, что у меня дальше в коде (а там я ищу группы попарной взаимной близости, когда все точки на разных прямый близки между собой) становится неверным.

И я не могу понять, в чём проблема. Входные данные вроде тоже проверял (точки отсортированы по возрастанию на своих линиях). Метод поиска ближайшей неоднократно менял – сейчас он, кстати, едва ли самый оптимальный на отсортированном-то массиве…

http://klimaleksus.narod.ru/Files/T/asscmp0V3.htm
– розовых не должно быть…

Фуф, релиз. Хотя бы такой, без нормального интерфейса и без самой главной фишки, зачем это делалось.
Но сам алгоритм – жжёт!
http://klimaleksus.narod.ru/Files/T/asscmp1V0.htm

Инструкция:
– поместить несколько разных .ass субтитров к одной серии пони в одну папку.
– на страничке активировать элемент выбора файлов, и выделить их все (оптимально 2-3 файла)
– нажать «открыть» в самом диалоге, и всё. Прокрутить до низу!

Если нет субтитров под рукой, то вот:
http://klimaleksus.narod.ru/Files/T/subs.zip

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

Умеет вырезать рекламу (с автоподбором порога), корректно обрабатывает интро, и небольшую линейную регрессию устраивает.

, правда я себе облегчил задачу в конце, когда понял, что не имеет смысла, скажем, сравнивать между собой лишь три из четырёх дорожек, когда одна уже кончилась или в ней дыра.
Потому что в итоге это же для начисления балов, а так иначе что получается – что в одном столбце будет меньше ячеек, чем в других? И голоса за эти ущербные строчки потеряют смысл.
То есть добавление пустого файла всё действительно ломает – его нельзя сравнить «построчно» с остальными, а значит и их разбиение на строчки должно пропасть.
Зато, с другой стороны, добавление точной копии одного из файлов – вообще ничего не меняет, это да.

Готов, в той или иной степени, мой скрипт сравнения субтитров. Он выполняет две различные функции:
1) Позволяет получить численную субъективную оценку, сколько строчек лучше переведено у нас, чем у анонимов, и наоборот. Нужно просто кликнуть мышкой по лучшему из вариантов в таблице.
2) Позволяет по словам сравнить транскрипт анонимов с транскриптом от Хасбро.
Вот: http://klimaleksus.narod.ru/Files/4/asscmp1V1.htm

И файлик с материалом и сохранёнными примерами:
http://klimaleksus.narod.ru/Files/4/asscmp_test.zip , копия скрипта вложена; прочитайте встроенную справку.

Для пословного анализа, можно просто запустить анонимский английский и хасбро, в режиме Diff, без strict.
Я сохранил его, можете просто открыть файл /diff через нижнюю форму загрузки файла.

А для быстрого сравнения нас с анонимами, открываете наш и их .ass в обычном режиме, этого уже достаточно.
Но я добавил туда и английские варианты, чтобы во-первых, иметь ещё две категории оценок (итого пять: «не оценивается» / «мы выиграли» / «мы проиграли» / «боевая ничья» / «просрано всеми»), а во-вторых, чтобы по транскрипту тоже ориентироваться.

Метода объединения субъективных оценок разных людей я пока не придумал, но сами оценки уже вроде вполне можно получать ^^

А пока правила такие:
– загрузить файл «cmp» через нижнюю форму на страничке.
– щёлкать в таблице по лучшим фразам из средних двух столбцов (анонимы слева, мы справа)
– если переводы одинаково хороши, то отметить крайний правый столбец (транскрипт Хасбро)
– если переводы безнадёжно плохи – то самый левый (транскрипт анонимов).
– не нужно отмечать каждую-каждую строку, надо следить за разбиением. Если разбиение неэквивалентно (всё из-за транскрипта Хасбро, он какой-то кривой местами) – то оставлять некоторые строчки жёлтыми, нетронутыми. Обычно, когда в одной клетке фраза целиком, а в следующую почему-то выпала её часть – то оценивать вторую не следует.
– сохранить результат!

Моё субъективное сравнение:
http://klimaleksus.narod.ru/Files/D/s6e14.zip
– открыть страничку, загрузить в неё файл через нижнюю форму выбора.
Результат: / 6 / 60 / 60 / 182 / – побед и поражений, к сожалению, поровну. И это без учёта аж шести полностью провальных реплик, когда наш вариант, как выяснилось, неправильно интерпретировал оригинальный текст.
Однако, я не засчитывал отдельно «жёстко надрали», когда вражеский вариант ударил в молоко (хотя по идее, под это можно забрать самый правый столбец, тогда отмечая равенство просто отсутствием выбора).

А ещё, я старался считать объективно. Например, рассматривал каждую реплику в контексте своих соседних, то есть не пытался собрать из двух потоков один хороший, а просто оценивал, насколько хорошо данная фраза вписывается в своё окружение.
Поэтому, например, одна удачная реплика не заставит несколько следующих перетянуть чашу весов, потому что да, продолжение подходит к ней замечательно, но ведь и не лучше же, чем в другом столбце, соответствующее продолжение подходило к уже шутке похуже.

Если реплики, в принципе, равнозначны, то я не старался во что бы то ни стало отделить лучшую. Также, если они доносят мысль абсолютно разными путями (что уже делает их несравнимыми), но при этом каждый из них выглядит вполне хорошим, то это ничья.
Однако если один из конкурирующих вариантов содержит хотя бы малый оттенок (может даже частица «-то» и есть единственное их различие) того, что присутствовало в исходной фразе, а другой вариант – нет, то это победа.

Такие общие штуки, как «go-go-go» или тот Рарькин болт, я вообще прямо не оценивал – можно считать это просто разным стилем, как например перевод имён и названий. И следовательно, все зависимые фразы рассматривались в своём контексте. И когда выигрывает одна, то это не значит, что в другом переводе «лучше бы чтобы была она» – а скорее сама конструкция, доносящая мысль лучшим способом, но уже со своей точки зрения.

Во всех спорных случаях я откатывался к ничьей.

HTML результата:
http://klimaleksus.narod.ru/Files/D/s6e14.htm



but nobody came
 
aleksusklimСообщение # 662 | Тема: Znaczky Пятница, 07.10.2016, 00:36
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Znaczek #5:

Тута я скопипастил все свои обсуждения ещё онлайновой версии пада для TDT.
Опять же, всё без разделителей между разными комментариями.




Уф.

Я-то думал, сейчас для пада все хоть сколько-нибудь полезные плагины установлю, базу данных с репликацией зафигачу, и уже можно юзать!
Оказалось, что плагины тупо конфликтуют друг с другом, и после установки второго десятка, ядро самого пада упало и больше не запускалось.

Пришлось откатывать. И откатывать…
Даже в полудохлом состоянии (в среднем 3/5 попыток входа обламываются, пад вылетает или рушится сервер) эта куча кнопок и панелей перекрывали друг друга, прыгали, ломались…

Я думал, выберу ВСЕ (кроме очевидно не нужных нам) плагины, а потом удалю те, что, оказывается, тоже не полезны.
Нифига! Надо переустановить всё с нуля, и ставить их поштучно. Проверяя ПОЛНУЮ работоспособность всех функций пада, и ещё отмечать отдельно для себя, какие плагины и в какой последовательности я ставил.

Не, это всё потому, что их там КУЧА. Плюс, функционал некоторых дублируется, и было слишком наивно полагать, что такое не сконфликтует друг с другом…

Ладно. Зато из хорошего, что я нашёл:
– поддержка тегов sub/sup, которые можно переопределить для сокрытия текста, вместо зачёркивания.
– якорные ссылки типа [[так]], как у Свимика.
– потенциальная возможность загружать файлы (проверить не мог, то ли не встала, то ли сломалась)
– отображение авторов в паде (видимо тоже маркерами)
– возможность поиска по истории на временной шкале, где будут подсвечены места, где есть заданное слово. Также, виден момент, когда его уже удалили.

И что неплохо бы найти:
– разделение пада на «шапку» и «тело» с независимой нумерацией, тоже как у Свимика.
– возможность смотреть лог сервера типа как чат, в котором бы показывались события редактирования. Он бы позволил узнать, кто произвёл удаление чего-то.

Короче.
Я тут несколько часов тыкал в плагины для пада, проверяя каждый отдельно, и изучая их возможности.
Вот отчёт: http://klimaleksus.narod.ru/Files/D/epl.zip

Ещё из хорошего:
– Есть плагин с отличной палитрой! Осталось её настроить.
– Можно менять цвета текста, как один из видов форматирования (то есть аналогия – «жирный» и «красный»), допись внутрь не теряет цвет. Список цветов настрою.
– Метки пользователей, они показывают точное положение курсора ввода, но кратковременно. Надо изменить, чтобы на строке тоже оставалась постоянная метка. Ещё есть «слежение» за участником.
– Два плагина, показывающих авторство при наведении на текст. Один делает это красиво и с задержкой, но не понимает цвета уже вышедших. Другой – показывает всех стандартными всплывающими подсказками, но не обновляется при изменении имён и не отключается кнопкой…
– Есть возможность вставлять картинки прямо в пад! Вот прям скопировать картинку – и вставить её. Или можно ввести ссылку, картинка скачается, и её можно будет «оторвать» от ссылки.
– Заголовки и горизонтальные линии, но там ещё пообрезать кое-то надо.
– Меняющийся размер чата, прям как на Пиратенпаде. Но можно ли раздвигать список пользователей, я пока не понял.
– Подсветка синтаксиса, которую можно настроить так, чтобы она, к примеру, всякие «Twilight:» – заголовки реплик серыми делала, например. Я всё хотел прикрутить такое, чтобы текст от начала английской реплики до первой русской буквы был бы на слегка сером фоне, но мне не удалось пока; либо это ценой предыдущего, там регулярки конфликтуют. Или два «языка» делать.
– Оу, пад стал русским! А я лишь «en-gb» на «ru-ru» поменял…

Из неприятного:
– Ссылки на [[текст]] не работают, или требуют ещё какого-то плагина.
– Как сделать кликабельные номера строчек, чтобы переходить по ним – не понял, хотя аж два плагина предлагали возможность перехода к строкам по якорю в ссылке.
– Как запаролить пад, я пока не разобрался. В наскок прошлый раз же всё поломалось, а там есть порядка 3-5 плагинов, предлагающих эту возможность.
– Пад часто «не прогружается» с какой-то страшной ошибкой (поменять бы её текст…), но есть решение: зажать «Ctrl+R» или «F5», чтобы обно-обно-обно-обновить страницу.
– Картинки на кнопках иногда не отображаются в Firefox.
– Возможность получать информацию о том, кто удалил кусок текста, не предоставляется никаким плагином, вроде бы. И пока не понятно, как сделать её (знали бы вы, что там за 1+*b+0-f/5* в базе храниться…), но как-то же можно.
– Закладок на строки нет. А штука ведь была полезная, надо из моего браузерного плагина вытащить.

Я понял, что проще вытаскивать логику плагинов, перерабатывать её, и вставлять в СВОЙ. Причём, в единственный. Ну или хотя бы группировать по общим свойствам, чтобы не было, что, грубо говоря, для жирного текста один плагин, а для курсива – другой.
Более того, они ещё и неписаны неоптимально. От большого количества всё лагает.
И сам интерфейс ядра пада какой-то хромой.

Короче, что я подумал: зачем наворачивать его до полного блеска, то самой последней фишечки?

Ведь быть может, мы завтра попробуем его, и окажется, что он либо рушится, либо никого не устраивает, либо в нём невозможно работать…

Я пока базовый функционал отладил (может сейчас ещё кликабельными номера строчек сделаю…), давайте хотя бы так его проверим.

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

На всякий случай, можно сделать один и заблокировать создание других падов.

…что за отстой, почему в новом паде нельзя отменять выбеливание!?
«Error: Can't apply USER_CHANGES, because
Trying to submit changes as another author in changeset …».

Более того, случайное нажатие ЛЮБЫМ участником комбинации Ctrl+Shift+C – очищает все авторские цвета документа сходу, а следующее же за ним Ctrl+Z – не срабатывает и выбрасывает из пада, потому что сервер думает, что клиент пытается что-то чужими цветами писать.

Я манал.
Всё, я пошёл системные файлы ядра корректировать…

Странно, на этой строке стоит комментарий:
// the empty author is used in the clearAuthorship functionality so this should be the only exception
if('author' == …

– значит что-то другое вызывает глюк. Пофиг, закомменчу проверку.

Оу май пад!
http://klimaleksus.narod.ru/Files/D/TDTPad.rar (~28 Мб)

Сделано в моих плагинах:
• форматирование текста + смена шрифта, его размера и цвета – сохраняется как атрибут (т.е. применяется к части текста), глобально.
• Масштаб текста всего пада, локальный для каждого.
• Горячие клавиши: Ctrl+S – зачеркнуть, Ctrl+D – выбелить, Ctrl+E – скрыть (ниже); блокировка Ctrl+Q и Ctrl+W, а также подтверждение на F5.
• «@», показывающая что изменения сохранились. Должны быть зелёная/синяя, но будет, видимо, голубая/красная.
• Сокрытие текста по кнопочке «H» на панели, или Ctrl+E. Работает так: если выделен текст, то он будет свёрнут в одну пунктирную «|», это глобально для всех. Если текст не выделен, то команда развернёт (или свернёт обратно) ЛОКАЛЬНО весь скрытый текст в строке с курсором, он будет взят в пунктирную рамочку. Для глобального снятие скрытия, можно выделить «|» с мясом, и нажать Ctrl+E несколько раз: сначала все свернётся в одну, затем локально раскроется но останется выделенным, и наконец – рамочка и атрибут скрытия будут сняты (это проще, чем я описал).

• Разбиение пада на секции, ОЧЕНЬ полезная функция. Секцию начинает строка «==Х», где вместо Х – одна русская заглавная буква, или пробел. Например:
==Ш==
== == // Основной раздел
==П== // песня
– тогда все строки, начиная с этой, будут перенумерованы в
Ш1
Ш2

1
2

П1
П2


– пробел вместо буквы обозначает «обычную» нумерацию без префикса. Естественно, добавление новых строчек в разные секции не собьёт их новую нумерацию (номера обновятся через секунду после изменения). Технически, названия секций могу совпасть, но это нежелательно. Отсюда вытекает:
• Быстрый прыжок на строку. Работает и в чате, и в паде – просто двойной щелчок по «номеру» строки в тексте (число N, либо буква+число XN). Номера никак не выделяются ни в паде, ни в чате, но двойной клик по ним сработает. Разумеется, с учётом секций (обязательно ставьте именно русскую букву перед номером). Технически, прыжок на самую первую строку невозможен.

Включённые плагины, но я внёс в них изменения:

• Палитра. Я вручную выбрал оттенки и их параметры яркости. Хотя, исходный колор-пикер на любой цвет я убирать не стал, так что всегда можно взять свой цвет.
• Вставка картинок в пад. Я наспех добавил туда ещё одну опцию размера (там было 100%, 50%, 25% от ширины пада) – исходный размер картинки. Кстати, изменения этих размеров (нажатия на квадратики внизу) – глобальны для всех!
• Изменяемый размер чата. Он глючный, короче: чтобы раздвинуть его, возьмите мышью за полоску, потом поднимите курсор наверх на панель (а не на пад), и тащите там. По паду на тащится. И совсем свернуть его тоже нельзя.

Плагины как есть:
• звёздочка в заголовке, когда пад был отредактирован кем-то во время того, как окно браузера не было на переднем плане. Потом туда надо и кол-во непрочитанных в чате выводитью.
• Проверка орфографии. Кстати, отключается в настройках на панели.
• Локальная отмена переноса текста по словам. Не отлаживал, меняется тоже в панели настроек.

Глюки пада:
• Грёбанная панель сверху!! У меня иконки на ней постоянно пропадают! Помогает Ctrl+колёсико (масштаб), сворачивание и разворачивание окна, открытие других вкладок. В общем, бред какой-то, я манал. Потом придумаю, как переделать…
• Кнопка «сохранить ревизию», я хотел её в панель настроек убрать, но уф, короче, просто забейте на неё, она бесполезна.
• Таймслайдер имеет какой-то отвратительный интерфейс, но функционал норм.
• Кстати, плагин «поиска текста в истории» при работе нагружает ЦП сервера на 100%, так что я его вырубил пока.
• Если увидите страшную чёрно-красную ошибку – удержите Ctrl+F5, чтобы хорошенько обновить вкладку.

Планы:
• Закладки на строки, как в моём том плагине. С учётом секций.
• Метки, кто где находится, и возможность узнать автора любого текста. На самом деле я оставил выключенными несколько плагинов, их потом можно будет опробовать. Но они могут затормозить пад.
• Сервер-лог, о том, кто где сколько, когда и чего сделал (добавил или удалил, и примерно на какой строке). Я уже придумал, как, но опять-таки требует аккуратной отладки, пока рисковать не стал.
• Может быть: автоматическое выделение другим цветом английского текста в строчках, глобальные динамические закладки, или ещё что-нибудь прикольное.

Установка:
1) Распаковать архив в корень диска. Имя папки должно быть коротким, например C:\ep\ или D:\tdtpad\
2) Открыть и отредактировать «settings.json». Там сверху вписать свой ПУБЛИЧНЫ адрес IP, на который нужно будет всем заходить. Номер порта тоже можно поменять.
3) Запустить «START.BAT». Это откроет большое окно лога сервера. (А программа «nircmd.exe» нужна для повышения его приоритета, и чтобы если вдруг сервер упадёт – был звуковой сигнал и уведомление).
4) Зайти на http://IP:PORT/ и создать новый пад. (делайте сразу два: один основной, а второй для тестирования).
5) Чтобы запретить создание новых падов, закройте сервер (это огромное консоль – сам сервер и есть, его закрытие останавливает пад), и раскомментируйте «"editOnly" : true,» в «settings.json». Перезапустите «START.BAT».
6) Пока плевать на «пользователей» (я отключил администрирование), и на «текст по умолчанию» – легче просто в паде сразу текст изменить.

Я ещё и кроссбраузерность потом настраивал!
И парсер чата, чтобы найденные номера строк ссылки не пороли…

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

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

//////
(function(B,L,F,I){
B=document.getElementById('chatloadmessagesbutton');
if(!B)B=document.getElementById('chatloadmore');
if(!B){return alert('Не найдена кнопка!');}
I=setInterval(function(){
if(B.style.display=='none')return;
B.click();},50);
F=function(E){if(!E.altKey)return;
document.removeEventListener('click',F,true);
clearInterval(I);alert('Остановлено.')};
L=document.addEventListener('click',F,true);
})();
//////

– он просто жмёт по кнопке автоматически, как очередная пачка сообщений прогрузилась.
Для отмены-остановки – щёлкните в чат с зажатым Alt. (Ещё нужно это сделать после того, как все загрузятся.)
Остановить можно в любой момент, а чтобы продолжить – просто выполните скрипт ещё раз.

Запуск, естественно – вставить в консоль браузера (Ctrl+Shift+K/J)

Блин, это правда, что если в паде выделить весь текст и удалить его, а потом отменить удаление – то весь текст для всех остальных будет иметь цвет того, кто удалял его?
То есть он сам увидит, будто все цвета остались какими были, но все остальные – увидят лишь его цвет?
(то есть нельзя отменить удаление всего текста так, чтобы не присвоить его потом себе)

А то я тут пытаюсь придумать, как сделать так, чтобы по Ctrl+С, Ctrl+V из одного пада в другой все цвета авторов сохранились.
Сама авторская система, видимо, дико повязана на том, что нельзя писать чужим цветом. На каком-то этапе предлагаемый цвет меняется на фактический цвет автора.

*прошло 40 минут безуспешный попыток найти нужный кусок кода*

СУКА! Вот оно: («changesettracker.js»)

// Sanitize authorship
// We need to replace all author attribs with thisSession.author, in case they copy/pasted or otherwise inserted other peoples changes

(далее нехилая функция размером в два экрана)

Закомментировал.

Теперь вставлять текст можно прямо с чужими цветами, и норм.

Правда, простое копирование тоже сохраняет цвет скопированного.
Видимо, нужна будет кнопка не только «выбелить», но и «присвоить себе», чтобы окрасить кусок текста своим цветом.

А ещё во всем этом мало толку, если нельзя «входить под другим автором», то есть выбирать свой идентификатор (типа «a.Xv8BLjRJhw0fr9qF»), что всё равно не позволит задавать цвет тем, кого в паде не было.

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

Кстати, я нашёл по крайней мере одну недоработку в ядре лайта, которую даже стоит на гитхаб им запостить.
Но я сам не хочу, там с гитом разбираться, форкать, пуллреквестить…

Клиент, отправивший чейнджсет, получает обратно лишь «true», в то время как все остальные – полную информацию и результат чейндсета.

Если я хочу сделать хук на клиенте, чтобы отслеживать все приходящий чейнджсеты – я эффективно пропускаю собственные… (нет, при отправке ловить – не вариант, там столько всего может случиться).

О-о, я знаю, что такое чейнджсет))
А выглядит он примерно вот так:
«Z:6v>4|7=6t*2+4$Хех.»
– тут кто-то написал «хех»

Оказывается, там решается такая нехилая математическая задача, о том как множество символов, называемое документом, путём некоммутативного умножения на специальную величину, называемую набором изменений, переводится в некий другой документ.
Предлагает алгоритм как сделать так, чтобы два разных пользователя, изменившие документ одновременно, получили адекватный и ОДИНАКОВЫЙ результат в ответ на свои действия.

То есть клиенту не нужно ждать, когда сервер покажется ему, что произойдёт – потому что рассчёт гарантирует, что и у клиента, и у сервера, и у других – даст одинаоквый результат независимо от того, в какой последовательности обрабатывать данные.

(Но в самом алгоритме я конечно не разбирался. Но это блин, круто!)

Давайте гипотетически представим, что я поставил себя в рамки необходимости адаптировать под свои нужны некий open-source проект, славящийся своей «мелкая фича – стабильный релиз» системой, и кучей плагинов (которые при подходе «сначала включу все, а потом удалю ненужные» конфликтуют до умирания всего сервера, вынуждая с нуля добавлять поштучно со строгим контролем за логами), разработанными кучей людей под кучей лицензий, и всё это настолько повязано на git-подходе, что тупо багфиксить ./*/node_modules/*/node_modules/*/somefile.js и хардкодно прописывать туда нужные мне флаги вручную уж как-то совсем-совсем некрасиво и непортабильно получится, а на полном серьёзе делать репозитории, форки и бранчи – это прям какая-то новая ниша для меня, нырять в которую я сейчас совсем не готов.

(Нет, это уже вообще не смешно: http://klimaleksus.narod.ru/Files/T/ep.txt )

Плагин-то один фиг – копирнул, переименовал, МЕНЯЙ. Ну и несовместимость с исходным укажи. А если ядро?..

Итак: \src\node\handler\PadMessageHandler.js \node_modules\ep_etherpad-lite\node\handler\PadMessageHandler.js (я манал, фигли его два)

Кусок такой:

if(author == sessioninfos[sid].author) { client.json.send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); } else { var forWire = Changeset.prepareForWire(revChangeset, pad.pool); var wireMsg = { "type":"COLLABROOM", "data":{type:"NEW_CHANGES", newRev:r, changeset: forWire.translated, apool: forWire.pool, author: author, currentTime: currentTime, timeDelta: currentTime - sessioninfos[sid].time }}; client.json.send(wireMsg); }

– эта байда, кажется, отправляет тому клиенту, кто запостил изменения, сообщение «ACCEPT_COMMIT», а всем остальным клиентам – «NEW_CHANGES». Проблема в том, что я хочу сделать плагин, который слушает эти сообщения, и выводит (на экран или куда либо) некий лог, в котором бы в читабельном формате было понятно, какой участник внёс примерно (хотя бы, было ли это добавление или удаление) какие изменения («changeset»), и примерно где (его текущую позицию «на какой строке», кажется, отсюда не достать, но я предполагаю, что допустим, будет активен другой уже существующий плагин, постоянно постящий «CUSTOM» сообщения с координатами курсора). Я, по-видимому, упираюсь в то, что клиент не слышит своих же «NEW_CHANGES», и они не будут отображены в его локальном логе, а я по меньшей мере хочу, чтобы логи у всех были одинаковые. Можно конечно отловить момент отправки changeset’а на сервер, но это опять искать это в файлах и какие-то хаки прописывать, ещё и обработчик усложняется. К тому же, «отправил» ещё не значит, что «отправилось». Хотелось бы получить сообщение «ACCEPT_COMMIT», в котором были бы все те же данные, что и в «NEW_CHANGES». И более того, раз тут простой author==me, что делает фикс элементарным:

if(false&&author == sessioninfos[sid].author) { client.json.send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}}); } else { var forWire = Changeset.prepareForWire(revChangeset, pad.pool); var wireMsg = { "type":"COLLABROOM", "data":{type:author==sessioninfos[sid].author?"ACCEPT_COMMIT":"NEW_CHANGES", newRev:r, changeset: forWire.translated, apool: forWire.pool, author: author, currentTime: currentTime, timeDelta: currentTime - sessioninfos[sid].time }}; client.json.send(wireMsg); }

Здесь для клиента-коммитера меняется «NEW_CHANGES» на «ACCEPT_COMMIT», а все сопутствующие остаются. По идее, на работу ВСЕГО остального кода, это не должно повлиять, ведь даже если где-то слушается «ACCEPT_COMMIT», то, раз в нём ничего больше не ожидается, то важен сам факт; а лишние данные в объекте будут просто проигнорированы. Хотя и создадут некую _мизерную_ нагрузку на сервер/канал передачи, но учитывать такое – полный бред, особенно если задуматься о том, что похожие сообщения шлёт тот плагин, трассирующий позицию, – при КАЖДОМ щелчке мышью / движению текстового курсора от КАЖДОГО клиента, а сервер вещает это при КАЖДОМ щелчке мышью / движению текстового курсора от КАЖДОГО клиента, а сервер вещает это КАЖДОМУ клиенту (а при коммитах и того дважды), как раз включая себя!

Если поступить ещё разумнее, то с учётом имеющегося в файле var settings = require('../utils/Settings'); – моё «false» и второе ?: условие можно дополнить на нечто вроде «settings.enableSendChangesInCommit», отсутсвующее в конфиге по умолчанию, и вообще не приводящее к изменению работы приложения, без присвоения этой настройки.

Окей… http://etherpad.org/

«The main development happens on Github. To contribute, fork the main repo, branch off a feature branch from develop, make your changes and commit them, push to your fork and submit a pull request for ether/develop.»

– серьёзно? Делать это? А вдруг эта фича у них уже запланирована?

Или же: «If you'd like to help, get in touch!» – ссылка ведёт на mailing-list и ещё куда-то. Может об этом просто написать кому-то?

Либо же – тупо в коде поменять, и положить на всю эту опенсорсную инфраструктуру?..

1) Я не меняю тип сообщения – следовательно всё остальное будет работать как раньше.
2) Да, клиенту эхнется то, что ему по сути не нужно. Но какие удобства это мне даёт при прослушке входящих сообщений!

Я вот говорю же что хочу – чтобы можно было ТОКЕН выбирать.

Чтобы я мог сделаться «a.aleksusklim___» – и тогда в какой бы пад я не вошёл – я всегда буду я, и любой, ЛЮБОЙ мой текст всегда будет моим, даже если он чёрт побери из прошлогодней истории или скопирован из другого пада.

(ну да, если кто другой впишет этот, публично видимы идентификатор – весь мой текст будет его… Но мне не жалко – в конце концов, это наш ОБЩИЙ текст, просто цвет на нём мой. Для нашего же удобства)

Так вот.
Пад сломался от переполнения стека. Причём именно в тот момент, когда я нажал «экспорт в .ertherpad».
Сама трёхгиговая база – абсолютно работоспособна, хотя не факт, что она верно сформирована.

Проблема в том, что в .etherpad формате должно быть сохранено всё содержимое пада, и все его ревизии. И этот формат – JSON.
Забавно, но я уже упирался в этот баг на Апаче, причём тогда решить его не смог. Сейчас же повезло!
Итак, рекурсивная функция заворачивания данных в JSON формат на таком огромном паде привела к переполнению стека на сервере.
Причём Node.js сам сообщил об ошибке, потому что не упал, а достиг заданного предела.
Однако, под Windows, этот предел нельзя просто так расширить, потому что иначе программа рухнет физически.
Лучшее решение – действительно увеличить стек. Стандартный – всего 1Мб, а я теперь увеличил его до 16 Мб (что значит, что по крайней мере на падах, которые не более чем в 30 000 раз больше нашего – можете считать, что это тридцать тысяч часов вместо одного часа стабильной работы – на них переполнений стека возникнуть не должно).

Для этого мне даже не пришлось перекомпилировать из исходников, я нашёл маленькую утилиту, пропачивающую программы – и применил её на «node.exe»:
http://klimaleksus.narod.ru/Files/D/stack.rar

Инструкция:
– распаковать в папку моего пада (содержимое \bin\ должно пойти в имеющийся \bin\), заменив START.BAT (там лишь один новый параметр —stack-size=15360 – виртуальный лимит на 15 Мб для Node.js)
– зайти в \bin\ и запустить «check.bat». Выйдет много инфы (окно можно закрыть или нажат Enter), там должно быть:

100000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit

(это в шестнадцатеричной системе, если что)

– Теперь надо запустить «patch.bat». Нажать Enter, потому что окно никак не сообщит о том, что всё готово. И снова выполнить «check.bat», где на этот раз будет:

1000000 size of stack reserve
10000 size of stack commit
100000 size of heap reserve
1000 size of heap commit

Готово! Теперь можно попробовать ещё раз грузануть нашу огробазу и сделать экспорт.
Собственно, вот он:
http://klimaleksus.narod.ru/Files/D/S06EP18-translate-episode-18.zip – ага, куда экономичнее.

А теперь я вот думаю, с чего база-то так разрослась? Подозреваю что из-за плагина «вставка картинок в пад».
Не то что бы два моих вставленных 1024*768 скриншота очень много весили… но если в базу кладётся каждый раз полная копия текста пада в каждой ревизии, создающейся чуть ли не каждым нажатием очередной клавиши каждым участником? Хотя, я пока так и не понял, что конкретно ложится в базу. Вытащить бы как-то количественно-качественную информацию о том, чем всё-таки забит файл – текстом или же base64 картинками.

И я проведу эксперимент, специально вставляя в пад картинки и замеряя удар по объёму базы (думаю, для MySQL это в перспективе, также актуально), что поставит под вопрос необходимость в таком неэффективном плагине, хотя и удобном.

Если что, вот наша дико ужатая база, которую желательно запустить под сервером на Линуксе, и посмотреть, вылетит ли стек от попытки экспорта:
http://klimaleksus.narod.ru/Files/D/BD_TDTeam.rar

Надо, чтобы эти картинки не как текст пада хранились, а просто на сервер загружались как файлы. А не в базу.
Было бы норм.

Я там уже и с репликацией почти разобрался, но я ЧЕТЫРЕ раза свой финальный вариант запускал с нуля – и он ломался, и снова танцы с бубном.

Последний раз была проблема, что какая-то команда выполняется на Win7, и не пашет на XP, но я не понял, какая.
А когда подгоняю под XP и дерзко тесчу на семёрке – опять баги лезут…

Так что я пока ещё потещу. Там ж ещё сам MySQL выкладывать, лучше пусть сразу всё будет норм.

Так вот. Я тут довольно долго размышлял над тем, как можно устроить в новом паде защиту от подмены персональностей участников, и пришёл к выводу, что если кто-то САМ захочет, чтобы его персональность была подменена – то с этим ничего нельзя сделать.
Это ж как аналоговая дыра (см. википедию), а именно: если кто-то захочет, чтобы из-под его аккаунта действовал другой человек – он всегда может предоставить ему удалённый доступ к своей машине сторонними средствами, не говоря уже о возможности физически передать свой компьютер во временное пользование кому угодно.
И тогда никто на свете не сможет доказать, кто в паде: тот, кто должен быть, или тот, кому тот захотел дать доступ.

Однако, защитить честного пользователя от попытки подмены его ник-нейма в паде злоумышленником – вполне возможно. Первоначально я рассмотрел стратегию доступа с «инвайтами». Грубо говоря, это специальные одноразовые пароли, которые генерируются для всех потенциальных пользователей пада.
Такой инвайт хранит «второе имя» (будем так называть то, что позволит отличать одного законного пользователя от другого – то есть не видимый ник-нейм, но и не безликий ключ сессии или идентификатор автора – цвет) внутри себя. Это значит, что первый зашедший по данному инвайту – получает сессию, связанную с конкретным вторым именем.
Два раза зайти по одному ивайту невозможно. В принципе, пользователи сами, опционально, могут генерировать новые инвайты (в том числе запасные для себя), и раздавать из другим – но тогда внутри инвайтов запоминается история, кто и кому предоставил доступ.
От, грубо говоря, расшариваний пароля, это не спасёт, но зато администратор сможет проследить цепочку инвайтов от своего доверенного лица до ворвавшегося в пад вандала.
Либо, если инвайты сможет создавать только администратор – то доступа в пад не будет ну у кого свыше тех, кто получил инвайт, что, с другой стороны, затрудняет сам процесс приглашения участников в пад: нельзя будет публиковать общую ссылку, по которой все смогли бы зайти. Ему придётся давать каждому свою ссылку, причём лично и секретно.

Такой вариант в наших условиях мне показался неудобным. Зато вторая идея получше: система закрытых и открытых ключей, которые будут создаваться потенциальными участниками, и вноситься в конфигурацию пада администратором.
Для тех кто не знает: система PGP ассиметричного RSA шифрования – это когда клиент может сгенерировать пару ключей (текстовых строк или маленьких файлов), один из которых, закрытый, он должен тайно хранить у себя; а второй, открытый – расшарить остальным, и в особенности, серверу/администратору.

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

Итак, применительно к паду, протокол работает так. В админке пада есть страничка, куда можно добавить пары «второе имя» – «открытый ключ». При обычном входе в пад, клиентский интерфейс предлагает либо сгенерировать новый набор ключей, любо открыть/вставить имеющийся закрытый ключ.
Участники через этот интерфейс создают пару ключей, и отправляют администратору свой логин (вернее, второе имя) и открытый ключ. Тот вносит все ключи на сервер.

Теперь, при входе в пад и выборе закрытого ключа, происходит следующее:
– Все отправляемые сообщения (кроме приветствия, либо же в каждом будет пересылаться копия «второго имени», чтобы сервер знал, чьим ключом оперировать) от клиента серверу шифруются на его закрытом ключе. В приветствии посылается второе имя, которое сервер кладёт в сессию.
– Сервер дешифрует входящие сообщения открытым ключом заявленного пользователя. Но если у него нет такого ключа, или он не подошёл – сообщения игнорируются и остаются без ответа.
– Все отправляемые клиентам сообщения (именно ajax-запросы, а не сами отдаваемые .html странички или .css/.js статику – все это сервится всем желающим без разбора) шифруются на открытом ключе того, кому они предназначаются.
– Клиенты расшифровывают приходящие сообщения на имеющемся закрытом ключе.

Всё это, без дополнительных систем токенов или проверок, гарантирует, что никто не сможет подменить собой никого другого участника без его согласия (что выразилось бы в пересылке ему своего закрытого ключа).
Реализуется довольно просто – изменением части кода ядра пада, отвечающей за непосредственную пересылку и приём сообщений. Как я понял, там можно найти конкретные точки входа и выхода, именно на которых будет достаточно ввести шифрование.

Основная сложность тут, скорее, в самом интерфейсе удобного выбора и добавления ключей. Которые, кстати, не должны храниться в базе данных, а просто оставаться на сервере как файлы.

Я даже нашёл модуль для Node.js, со всеми необходимыми функциями – «node-rsa». Но к сожалению, я не смог заставить его работать в браузере, хотя технически это возможно (через некий «browserify», который не то уже есть в паде, не то отдельно ставится как приложение, но я манал этот линуксовый «npm install», к которому сводятся все советы по использованию…)

О, а ведь я тут действительно исследовал, мог ли плагин вставки картинок в пад быть причиной того, что наша база данных вдруг стала неоправданно большого размера.
Итак, я создал пустой пад, и сделал PrintScreen и несколько Ctrl+V подряд. Штук шесть.
После чего попробовал пописать. Ну вроде, ничего: база росла на глазах, но всего лишь по полмегабайта за коммит. Мало.
Тогда я вставил туда тот же самый скриншот ещё раз десять или пятнадцать, а затем добавил снизу содержимое любого нашего типового пада. Правда у меня браузер так подвис, что сервер его выкинул.
Ну, я перезашёл…

О-о-о, а потом моя бедная мозиллка-тормозилка в течение сорока минут пыталась прогрузить содержимое пада, медленно наращивая память (единственная вкладка) с двухсот до шестисот мегабайт. Я так и не дождался конца, сбросил Диспетчером. Не было ни уведомлений, мол, скрипт завис, ни возможности хоть на что-то нажать в интерфейсе браузера. Труп трупом.

Итого, плагин вставки картинок в пад – зло. Выглядит клёво, но взамен душу заберёт.
Уж лучше вон тот, который локально по ссылкам на изображения эти самые изображения в паде и вырисовывает. А ещё круче, если его можно объединить с каким-нибудь механизмом, загружающим файлы на сам сервер – тогда даже ничего изобретать на надо – загрузил картинку, вставил ссылку.

Теперь насчёт того, как я разобрался с MySQL и репликацией.
http://klimaleksus.narod.ru/Files/4/TDTPAD_MySQL.rar (В архиве – ещё часть данного текста)

Это с расчетом, что все пойдёт на ОК?
– да не пойдёт оно, я уже пять раз так думал.
Вот всё идеально настраивал, ставил на новый комп – и не шло.
А там правил. Правил на мастере, правил на реплике.

Потом путался, где какие изменения.
Или менял что-то, что по идее не должно всё испорить (вроде имени какого-нить файла), а потом на генеральной репетиции – бах, на последнем этапе ошибка именно в его названии, которое я забыл куда-то прописать.

Гуглинг ошибок. Забано, например, было видеть ответом (причём правильным), что «не найден индекс первого бинлога мастера» означает всего лишь, что репликация была подцеплена не к тому серверу (например, к своему же собственному!)

Всё же, чем больше прог что-то меняют в файлах, тем сложнее потом вмешиваться при надобности.

Например у меня сейчас root-пароль генерируется рандомом. Но он может не вступить в силу почему-то, после выполнения скрипта. А почему? А хрен знает.
Но в процесс уже не вмешаться, там всё на автоматике.
Пришлось часть работы оставить пользователю (например, закрыть сам MySQL, когда то будет нормально открыт, ибо скрипт у меня не то что узнать об ошибках не может, он вообще состояние сервера не в силах понять!..)


but nobody came

Сообщение отредактировал aleksusklim - Воскресенье, 05.11.2017, 17:39
 
aleksusklimСообщение # 663 | Тема: Znaczky Пятница, 07.10.2016, 01:03
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Znaczek #6:

Копипащу анонс и полную справку (потому что отдельного описания не, но и несмотря на то, что говорят, что по ней тоже всё равно непонятно, что именно делает эта программа) утилитки для упорядочивания кучи файлов субтитров в списки по персонажам с возможностью воспроизвести любую реплику с высокой вероятностью успеха.




http://klimaleksus.narod.ru/Files/4/AssEasyQuote1V0.rar
С пользой провёл разве что быстрое пробное тестирование:
http://klimaleksus.narod.ru/Files/T/aeq_test.mp3 (ответ кроется в вопросе, насколько быстро мне удалось такое смонтировать)
– сделано на скорость, аж путём глупого внешнего перехвата выходящего потока из плеера, запускаемого моей же программой.
Не знаю, получилось ли сделать отрывок более-менее связным или логичным, но это был просто тест потенциальных возможностей.

Учитывая, что у меня не было ни всех сезонов, ни высококачественных источников, ни даже файлов оригинальных субтитров (подбирал по русским).
На фон взял первую попавшуюся, мне в таких ситуациях, как правило, всегда везёт.




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

Далее программу можно использовать для выборочного воспроизведения реплик из оригинальных видеофайлов.
Для этого:
– Программа запускается фоновым процессом в трее, и предварительно сканирует папку с видеофайлами, запоминая их имена.
– Далее она ждёт горячей клавиши, и по нажатию Ctrl+Alt+Space программа получает содержимое буфера обмена, ожидая обнаружить там номер некоторой строки (он должен быть скопирован вручную)
– Если найденный номер соответствует имеющейся в индексном документе, и программа знает местонахождение видео (или аудио) с тем же именем – запускается фоновое воспроизведение через «Media Player Classic», поддерживающий начальное смещение.
– Программа вычисляет оставшееся время, и после подаёт сигнал плееру об остановке воспроизведения. Возможны задержки во времени из-за загруженности процессора или медлительности чтения большого файла с диска.

Инструкция по запуску:
– Соберите все свои видеофайлы в какую-нибудь папку. Они могут располагаться в разных подпапках внутри неё, но желательно, чтобы там нигде не было множества других файлов, не относящихся к видео или субтитрам.
– Соберите все субтитры вместе, также можно в подпапках. Если у вас субтитры уже лежат рядом с видео, и вы хотите использовать именно их, то можно оставить их там (папка просто будет той же); если же рядом с видеофайлами находятся какие-то другие субтитры, то соберите нужные отдельно.
– Убедитесь, что имена целевых субтитров (без расширения) попарно соответствуют видеофайлам; все файлы должны иметь разные имена, поскольку сравнение происходит без учёта пути. Желательно, чтобы использовались только латинские буквы и цифры, потому что всё остальное заменяется символом подчёркивания при сравнениях. Однако, если имена файлов отличаются именно латиницей и цифрами, то проблем не возникнет даже когда в именах присутствуют русские названия.
– Запустите «AssEasyQuote1V0.exe» двойным щелчком. Перейдите в корневую папку, где лежат целевые субтитры – позже поиск будет произведён в ней и подпапках. Диалог сделан как «сохранение файла», однако туда ничего сохранено не будет (просто так было удобнее папку выбирать, потому что есть куда путь вставлять), нужно лишь в правильной папке формально «сохранить» под любым именем, или дважды щёлкнуть по любому файлу в ней.
– Теперь выберите ту папку, из которой нужно брать видео. Это может быть та же самая папка, потому что в дальнейшем программа сумеет различить .ass субтитры от всего остального.
– Наконец, настоящий диалог сохранения! Выбранное имя файла будет итоговым .ini списком соответствия номеров реплик. Рядом с ним появятся .txt файлы, с именами персонажей и их текстами.
– Далее программа в трее сообщит о прогрессе обработки, и закроется. Можете зайти в целевую папку и посмотреть на извлечённые строчки.

Для прослушивания реплик:
– Перетащить в Проводнике ваш созданный индексный .ini файл на «AssEasyQuote1V0.exe». Он будет прочитан, а указанная в нём папка видеофайлов – просканирована. Если программа уже была запущена, то прошлая её копия будет насильно закрыта. А чтобы не тащить индекс куда-то далеко, можете заранее переместить его в папку с программой (ему не нужны извлечённые реплики в соседних текстовых файлах персонажей – это вам они нужны).
– Программа сообщит в трее, что готова. Теперь откройте любой документ с персонажа в любом текстовом редакторе. Скопируйте интересующую вас строку, или хотя бы её порядковый номер (это шестнадцатеричное число, а захваченные пробельные символы игнорируются). Нажмите Ctrl+Alt+Пробел.
– В трее будет указано имя файла и целевое время этой фразы. Должен запуститься свёрнутый плеер, в котором должно запуститься соответствующее видео с правильного места, и по окончанию реплики остановиться. Если окно с плеером уже открыто, то оно и перехватит команду на воспроизведение.
– Продолжайте слушать фразы, сколько вам нужно. Для выхода из программы, нажмите правой кнопкой на иконку в трее, и щёлкните «Exit». Если плеер по какой-то причине перестал воспроизводить, нажмите Ctrl+Alt+Space дважды – процесс плеера будет сброшен, и повторный вызов должен пройти хорошо. Чтобы воспроизведение не закончилось сразу после конца реплики, можете щёлкнуть по иконке в трее левой кнопкой мыши, остановив работу программы. Для возобновления, снимите галочку с «Script Paused» в контекстном меню иконки; возможно, понадобится закрыть плеер.
– Реплики во фразах персонажей отделяются одной пустой строкой, если не следуют непосредственно друг за другом в исходных субтитрах; и двумя пустыми строками, если вообще принадлежат разным файлам. При создании файлов, если документ с таким персонажем уже существует, то он будет заменён новым – поэтому лучше всегда создавайте новую папку при выборе места для сохранения индексного файла.

Альтернативный способ обработки файлов:
– Для этого нужен «современный» браузер, откройте файл «AssEasyQuote1V0.htm». Этот способ может быть оказаться быстрее предыдущего при очень большом числе субтитров и персонажей.
– Сложите все субтитры в одну папку, и заархивируйте её в .zip
– Откройте архив интерфейсом на страничке, или перетащите его на элемент загрузки файлов.
– Страница, после обработки, вернёт вам некоторый файл. Сохраните его как .zip архив.
– Распакуйте полученный файл. Там окажется, в том числе, один .ini файл.
– Откройте его текстовым редактором, и вставьте на первую пустую строку полный путь к той папке, которую вы бы выбрали как папку с видеофайлами.
– Всё, можете перетащить его на программу и пользоваться как обычно.





А вот ещё этапы разработки и финальная версия скрипта, мониторящего доступность видео на Ютюбе.




Ну пока так, грубовато:
http://klimaleksus.narod.ru/Files/4/ytalert.txt

Инструкция:
1) Зайти браузером на https://www.youtube.com/oembed (там «Not Found»)
2) Открыть консоль браузера (Ctrl+Shift+K/J/C)
3) Вставить туда содержимое текстового файла по первой ссылке.

4) В текстовое поле вставить ссылку на какое-нибудь видео.
5) Нажать Enter или ADD. Добавить ещё несколько видео.

6) Таймер пока одноразовый, без повторной проверки. Кнопка «now» запускает проверку данного, кнопка «DEL» – удаляет строку.
7) Посмотреть результаты работы скрипта – зелёный на хороших видео, красный на плохих.
8) Было бы здорово проверить, что существующее, но удалённое позже видео, при нажатии «now» начинает выдавать красный.

Осталось придумать, какие уведомления выдавать (думаю, что смогу звуком), и выбрать интервал обновления…

http://klimaleksus.narod.ru/Files/4/ytalert1V1.txt

– сейчас объясню, как работает.

Итак, опять же, вставить в консоль браузера.

Если текущая страница не «youtube.com/oembed», то скрипт либо сам переадресует туда в текущей вкладке (если посчитает её содержимое не важным), либо создаст большую кнопку, по которой можно будет перейти туда в новой вкладке (а если зажать Ctrl при щелчке, то скрипт попытается всё же использовать эту вкладку вместо новой). В любом случае, на целевой странице скрипт нужно будет вставить в консоль ещё раз.

Дальше как обычно, вставлять ссылки в поле (хотя я предпочитаю не ссылки кидать, а только сами идентификаторы видео типа «q7s1B-kd_Uc»). Применять можно по Enter или ADD.

Далее в таблице появится серая строка, и через секунду запросит обновления; но прежде идёт дополнительный запрос на заголовок и картинку для видео (ведь на блокированных видео эта информация не выдаётся).

Обновляемая строка горит либо голубым (если новая, или ещё до этого была зелёной), либо жёлтым (если была красная).
Запрос ждёт 20 секунд, и если ответ не пришёл – будут посылаться повторные запросы каждые 20 секунд. Таймер будет идти от нуля в отрицательную сторону.

Пришедший ответ обновляет таймер, устанавливая его на случайное значение от 10 до 35 секунд. Если с видео всё хорошо, то строка станет зелёной.

Если же обнаружен статус "fail", то строка будет красной, и случится уведомление.
Таймер, тем не менее, пойдёт как обычно к нулю, и последующий запрос всё равно произойдёт (скрипт же не знает, почему была неудача, может там сервер просто ответил «повторите позже», тем не менее «причина»будет выведена под названием видео).
Таким образом, если вставлена некорректная ссылка, то уведомления будут случаться постоянно, примерно каждые 20 секунд.

Чтобы остановить такмер на конкретном видео, есть кнопка «stop» под ним. Она сделает цвет строки белым (если он был зелёным или голубым), либо розовым (если красный или жёлтый). Теперь обновлений не будет, а также кнопки «now» (обновить сейчас) и «DEL» (удалить строку) перестанут работать, пока кнопка «enable» (второе состояние этого «stop») не будет снова нажата.

Уведомление – это во-первых, «Desktop Notifications», и браузер, по идее, должен спросить разрешение у пользователя, при добавлении первого видео в таблицу. Нужно разрешить показ уведомлений!
Если браузером поддерживается, то на экране возле трея будет появляться окошечко без иконки, но с идентификатором видео, причиной неудачи, и названием (если поместиться).

Во-вторых, должен быть слышен пронзительный звук сирены ^^.
У меня работало во всех браузерах (ну кроме IE, на который я даже не рассчитывал и не пробовал, потому что в нём этот скрипт работать гарантированно не будет).
Но возможно, если звука нет, то нужно зайти в настройки браузера и либо «включить звуки на веб-страницах», либо отметить «запускать все плагины» (вместо «по запросу / только важные»).

И в-третьих, заголовок страницы (вкладки окна / иконки панели задач) будет в течение пяти секунд постоянно меняться на всякую всячину.

Вот так, вроде всё.
Думаю, что если какое-то видео действительно вдруг оказалось заблокированным – нужно остановить его таймер и принять меры.
После того как меры приняты – нажать «enable» и удалить строку.

О, а ещё, строка в таблице может почему-то стать синей. Это произойдёт, если в ответе сервера не найден «status» вообще, или не равен ни «ok», ни «fail». Это ничего не изменит, должно по идее считаться, что ответ не пришёл (перезапрос через 20 секунд), но если происходит регулярно – дайте ссылку на такое видео))

P.S
Блин, по-моему, я слишом грубо парсил результаты. Вполне возможно, что видео с названием, включающим символы \, &, <, >, = – может всё поломать.
Или нет.

Багфикс + апдейт готов, вот новая версия:
http://klimaleksus.narod.ru/Files/4/ytalert1V2.txt

Баг заключался в том, что _возможно_, новое добавленное видео могло сломать проверку всех предыдущих (угораздило же меня написать «if(A[i ].handle=v)…» и не заметить).

Изменения:
– теперь промежутки времени (интервал, его рандомная добавка и ожидание ответа сервера) задаются как числа в поля на самой странице. Применяются мгновенно при изменении; если невалидно (интервал меньше 1, добавка меньше 0 или ожидание меньше 2, либо если не число) – подсвечивается розовым.
– первый раз картинка на видео прогружается не сразу, а спустя три секунды (чтобы дать возможность маленькой прогрузится, если будет; хотя ждать её нужно было не так…)
– таблица формально не пересоздаётся при добавлении очередной строки.
– при остановке таймера, его кнопки «now» и «DEL» становятся визуально недоступны.
– идентификатор видео во втором столбце теперь является ссылкой, открывающейся в новом окне.

Чёрт с ним, может вот так сделаем –
http://klimaleksus.narod.ru/Files/4/ytalert1V3.txt
–?

Русифицировал интерфейс.
Ну и сделал отлов картиночки именно такой, какой нужно: вначале идёт запрос на картинку высокого качества, которая точно есть (как и название).
Далее, если он пришёл – то название выставляется сразу, а ссылка на картинку – запоминается.

При следующем обычном запросе, если вернулось название – то оно заменит имеющееся, но единожды (кстати, название видео у меня по таймеру вообще не обновляется. А надо?)
Если пришла ссылка на картинку низкого качества – то вырисовывается она. Если же нет, то берётся сохранённая ссылка на большую если есть.

Когда таймер достигает «0» – на сервер посылается запрос на обновление данных, а таймер продолжает идти «в минус».
Состояние запроса никак не отслеживается, то есть верный результат может либо придти, либо нет.

А значит, если ответа нет – через некоторое время нужно повторить посылку запроса (но да, потом могут придти сразу два).
Например, если wait = 15, то запрос будет посылаться при таймере, равном 0, -15, -30, -45…
(меньше 2 поставить нельзя, потому что от 0 до -1 происходит посылка, и где-то от -1 до -2 – приём, поэтому иначе повторный будет послан слишком рано.)

Вернее, даже вот так вот:
http://klimaleksus.narod.ru/Files/4/ytalert1V3.txt
(пофиг, по той же ссылке, просто перекачайте скрипт заново)

Я просто подумал, что браузер может кешировать запросы…
Теперь всё скачивается через POST (ха, Ютюб не банит за это, как Гугль!), и к запросам добавляется случайное число, чтобы URL был формально каждый раз новый.

Там вроде есть кол-во просмотров, но оно было какое-то не очень адекватное, кажется.

Хотя, вроде работает:
http://klimaleksus.narod.ru/Files/4/ytalert1V4.txt
– а при наведении выдаётся и содержимое шорт-поля.

http://klimaleksus.narod.ru/Files/4/ytalert1V5.txt
– теперь принимает список ссылок/идентификаторов, разделённых пробелом (вгружаются через секунду по-очереди, но добавляются одновременно).
Такой список из текущей таблицы – выводится перед ней (ну чтобы можно было скопировать эту строку, и потом целиком и вставить)





Оу, тут можно ещё кусочек про пад добавить, насчёт переполнения стека – косвенный пример:




А вот что у меня было с Апачем.
Забавно, но я делал такой же редактор в реальном времени, как пад – но графический, там можно было одновременно рисовать.
Клиент посылал серверу JSON с перемещением курсора, а сервер сохранял его и пересылал всем остальным по их запросу.

Я хотел устроить хотя бы проверку валидности данных, чтобы клиенты не могли заспамить сервер мусором (он ведь вслепую ретранслирует всё другим клиентам), но без полного парсинга JSON для экономии ресурсов.

Я взял регулярное выражение типа такого:

$r='/^\{"k":0\.[0-9]++,"u":[0-9]++,"l":\[(\{"t":[0-9]++,"r":[0-9]++,"c":[0-9]++,"b":"[0-9]++,[0-9]++,[0-9]++","k":0\.[0-9]++,"a":\[(\{"x":[0-9]++,"y":[0-9]++,"t":[0-9]++\},)*+\{"x":[0-9]++,"y":[0-9]++,"t":[0-9]++\}\]\},)*+(\{"t":[0-9]++,"r":[0-9]++,"c":[0-9]++,"b":"[0-9]++,[0-9]++,[0-9]++","k":0.[0-9]++,"a":\[(\{"x":[0-9]++,"y":[0-9]++,"t":[0-9]++\},)*+\{"x":[0-9]++,"y":[0-9]++,"t":[0-9]++\}\]\})*+\]\}$/ux';

И применял его к строкам типа такой:

$s='{"k":0.03629016666673124,"u":0,"l":[{"t":581,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":32800,"y":10700,"t":5},{"x":33149,"y":11198,"t":5},{"x":33497,"y":11696,"t":5},{"x":33846,"y":12194,"t":21},{"x":34195,"y":12692,"t":21},{"x":34532,"y":13198,"t":38},{"x":34955,"y":13635,"t":55},{"x":35378,"y":14071,"t":55},{"x":35906,"y":14373,"t":71},{"x":36434,"y":14675,"t":71},{"x":36961,"y":14977,"t":71},{"x":37489,"y":15279,"t":71},{"x":37978,"y":15641,"t":84},{"x":38467,"y":16002,"t":84}]},{"t":917,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":43200,"y":17700,"t":4},{"x":43572,"y":17219,"t":35},{"x":43944,"y":16738,"t":35},{"x":44315,"y":16257,"t":35},{"x":44687,"y":15776,"t":35},{"x":45155,"y":15387,"t":50}]},{"t":230,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":60900,"y":16800,"t":4}]},{"t":462,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":53200,"y":11700,"t":5},{"x":52835,"y":11214,"t":5},{"x":52470,"y":10727,"t":5},{"x":52031,"y":10307,"t":21},{"x":51591,"y":9887,"t":21}]},{"t":680,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":47400,"y":7700,"t":5},{"x":46792,"y":7700,"t":5},{"x":46184,"y":7700,"t":34}]},{"t":913,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":37200,"y":21100,"t":5},{"x":37200,"y":21708,"t":5},{"x":37435,"y":22269,"t":35},{"x":37670,"y":22829,"t":35}]},{"t":117,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":58900,"y":27900,"t":1},{"x":59506,"y":27947,"t":17},{"x":60112,"y":27993,"t":17},{"x":60720,"y":27996,"t":28},{"x":61328,"y":27998,"t":28}]},{"t":311,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":62600,"y":28000,"t":7},{"x":62872,"y":28544,"t":19},{"x":63144,"y":29088,"t":19}]},{"t":518,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":46500,"y":40600,"t":0},{"x":45892,"y":40600,"t":17},{"x":45284,"y":40600,"t":17},{"x":44676,"y":40600,"t":27},{"x":44068,"y":40600,"t":27},{"x":43460,"y":40600,"t":27}]},{"t":713,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":40800,"y":36900,"t":4}]},{"t":929,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":56900,"y":33000,"t":6},{"x":57508,"y":33000,"t":23},{"x":58116,"y":33000,"t":23}]},{"t":112,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":68100,"y":37100,"t":4},{"x":68698,"y":37212,"t":14},{"x":69295,"y":37324,"t":14}]},{"t":296,"r":16,"c":1,"b":"264,0,0","k":0.03629016666673124,"a":[{"x":84600,"y":33400,"t":5}]}]}';

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

На сайтах пишут, что такие проблемы с preg_match($r,$s) только под Виндой. Потому Апач там по умолчанию скомпилирован с коротким стеком.
А ещё рекомендовали перекомпилировать его, поменяв часть рекурсивного кода на линейный…
(но тогда мне было вообще не до таких разборок, и мы просто забили на валидацию)



(э, ладно, возьму-ка отсутствующий кусок текста про mysql из предыдущего поста – тот, что в архиве – и плейн-текстом фигану сюда. Ну там, для возможности поиска, тудым-сюдым…)



Поскольку, исправлять баги и плясать с бубном, пока я всё это настраивал, мне приходилось постоянно и многократно – нужно, чтобы пользующиеся моей сборкой чётко понимали, как она работает внутри. Хоть я и свернул всё к простым кликам по .bat файлам, но обязательно что-то пойдёт не так.

Итак, в архиве – куча батников, и папка «MySQLServer5.5» – её переименовывать не надо. В ней есть файл «my.ini» – это основная конфигурация сервера.
Нужно выгрузить это в папку, находящуюся (желательно) в корне жёсткого диска, например чтобы существовал путь:
D:\TDTPAD_MySQL\MySQLServer5.5\my.ini

Теперь этот путь надо прописать в самой конфигурации дважды, и в моём файле «path.bat»:
Там нужен путь типа «@set dir=D:\TDTPAD_MySQL\MySQLServer5.5»
А файле конфигурации «my.ini» – два пути, один к этой папке, а второй – к её «DB» подпапке. Причём слеши там требуются прямые. То есть
basedir="D:/TDTPAD_MySQL/MySQLServer5.5/"
datadir="D:/TDTPAD_MySQL/MySQLServer5.5/DB/"

Все эти пути правильно прописывать ОЧЕНЬ важно. У меня было, что путь «С:\MySQL2\…» был неверен только потому, что там русская «С».
Дальше:

Скрипт «MySQL_totalreset.bat» – очищает всё состояние базы данных до заводского, но не трогает конфигурационный файл. При запуске требует подтверждения – нужно ввести английскую букву «y» и нажать Enter.
Будет сгенерирован новый локальный root пароль, который запишется в файл «pass.bat» и станет автоматически использоваться в дальнейшем.
Откроется окно запущенного сервера с логом работы, если всё в порядке, его нужно закрыть.

Скрипт «MySQL_start.bat» – запускает сервер базы данных. По идее, он работает в фоне и не имеет консольного окна. Больше одного раза сервер запускать нельзя, будут глюки в виде пустых консольных окон или невыполняющихся команд и заблокированных файлов. Если такое случилось – убивайте сервер скриптом «MySQL_kill.bat»

Скрипт «MySQL_stop.bat» – останавливает работающий сервер. Может не сработать, если что-то с root-паролем случилось.

Скрипт «MySQL_kill.bat» – убивает все процессы, имя которых равно «tdtpad_mysqld.exe», это на случай, если предыдущая команда не заставила его остановиться.

Скрипт «MySQL_SHELL.bat» – открывает клиентское окно команд терминала MySQL (это туда надо вводить все те команды, которые можно нагуглить для решения той или иной проблемы), вообще говоря, через него можно сделать что угодно. Но самые главные функции вынесены в отдельные скрипты, а этот потребуется лишь для ручного вмешательства.

Скрипт «MySQL_STATUS.bat» – выводит на экран всю информацию о работе сервера – все процессы с его именем (должен быть один!), его общий статус, текущее состояние репликации и номер бинлога мастера. У меня всё сконфигирировано так, чтобы и мастер и реплика настраивались одинаково, надо просто знать, на что обращать внимание. Если статус вообще не печатается на экран – с сервером что-то не то.

Скрипт «MySQL_debug_log.bat» – запускает сервер (убедитесь, что больше ни одна провисшая копия не активна) в консольном режиме, с выводом лога на экран – сразу покажет примерную причину, почему вдруг сервер не запускается при штатной попытке.

– Ну со всем этим понятно как работать. Сначала «MySQL_totalreset.bat», потом «MySQL_start.bat» и сразу «MySQL_STATUS.bat». Если всё верно – то можно «MySQL_SHELL.bat» попробовать (если есть что писать туда), закрытие или перезапуск – «MySQL_stop.bat» и «MySQL_start.bat» снова. Если пустые окна остаются – то «MySQL_kill.bat», а если всё равно новая копия не поднимается – то «MySQL_debug_log.bat» и вчитываться.

Теперь ближе к паду. Кусочек конфигурации «settings.json» для etherpad-lite:

Так, во-первых, там вверху где «"ip": "127.0.0.1", "port" : 9001,» – айпи, кажется, надо писать «0.0.0.0» – тогда пад будет доступен на машине, независимо от её настоящего адреса (127.0.0.1 ли, 192.168.0.1, или любой внешний). Главное чтобы при подключении порт был тот, который указан тут.
Во-вторых, все строки, связанные с «"dbType" : "dirty"» надо закомментировать или удалить.

В-третьих, раскомментировать секцию, связанную с mysql (настройки в ней объединены с dirty для упрощения выбора). У меня там есть нужный кусочек, вот такой:

"ip": "0.0.0.0",
"port" : 9001,

"dbType" : "mysql",
//"dbType" : "dirty",

"dbSettings" : {
"user" : "etherpad",
"host" : "localhost",
"port" : "3311",
"password": "my-awesome-etherpad-password",
"database": "ep",
"charset" : "utf8mb4",
"filename" : "var/dirty.db"
},

– здесь, «user» – имя пользователя для базы данных, которому разрешён нужный доступ, это слово «etherpad» (тогда полное его имя – это 'etherpad'@' localhost' );
«port» – на каком порту будет ждать локальная база данных. В MySQL этот порт меняется дважды в конфигурационном файле, там написано «port=3311». Желательно, чтобы на всех используемых хостах этот порт был одинаковым (проблем при согласовании меньше будет).
«database» – имя базы данных, куда пад будет всё сохранять. Это строка «ep», далее пойдут несколько работающих с ней скриптов.
«password» – пароль для доступа к базе данных серверу пада. Эту строку можно изменить. Я вот думал, как бы сделать рандомную генерацию, но на самом деле этот пароль и никому не нужен, он же локальный и используется автоматически. Можно написать что угодно, просто скопировать в нужные места – и забыть о нём, ведь всё равно кроме как с «localhost» (это в MySQL настроено) никто к базе не присоединится.

Теперь нужно создать базу данных для пада. После запуска сервера, выполнить скрипт «install_db.bat» – это создаст базу данных «ep», и даст к ней доступ по заданному паролю. Чтобы поменять пароль, отредактируйте сам этот скрипт в Блокноте (менять в «identified by 'my-awesome-etherpad-password';»). Также, там разрешается репликация с этого сервера на любой адрес. Пароль репликации – в «identified by 'my-awesome-replication-password';», если его менять – то менять у всех; к тому же, этот пароль внешнего доступа ни на что, кроме самой репликации, и не даёт.

Наконец, пад можно запустить! В его настройках есть закомментированный кусок «//"dbType" : "dirty",», если поменять его с mysql, то пад переключиться на свою внутреннюю базу данных. Это можно использовать для открытия временного пада на своём хосте, пока MySQL настроен на репликацию главного – а временный пад использовать как средство связи, или писать там адреса альтернативных серверов (раз уж нормальной общей конфы нет).

Для экспорта базы данных, нужно выполнить скрипт «EP_export.bat». Он создаст файл типа «DUMP_$BINLOG.000001$810$.sql.7z», и это – всё содержимое всех падов Пада.
Дамп хорошо сжат, и в его названии через «$» отделены параметры мастера, необходимые для старта репликации с него. Слово «DUMP» можно переименовать, но не используйте там специальных символов: только английские буквы, цифры и «_» да «-».
Фишка! Чтобы расшарить его (да и не только), переместите файл в папку пада по адресу «\node_modules\ep_etherpad-lite\static\» – тогда он будет доступен из корня сайта (типа http://127.0.0.1:9001/DUMP_$BINLOG.000001$810$.sql.7z )

Для импорта – перетащить нужный «…$…$…$.sql.7z» файл на «EP_import.bat». Это _заменит_ текущее содержимое базы данных «ep» пада на то, что в файле. А вот после полного сброса сервера баз данных, то есть после «MySQL_totalreset.bat» – этой самой базы «ep» ещё не будет, и импорт не удастся: поэтому потребуется сначала запустить «install_db.bat».

Импортирование перехватывает параметры бинарных логов мастера для репликации, и сохраняет их в файл «blog.bat».
Кстати! Везде пишут, что для экспорта с репликацией, мастер непременно нужно останавливать, иначе мы не получим значение лога после непосредственного экспорта, ведь в базе к этому времени уже может что-то поменяться. Но мой скрипт делает экспорт как можно быстрее, и сверяет параметры бинарных логов до и после. Если они совпали – значит всё отлично, никаких изменений в паде не было. А если нет – дамп, конечно, создаётся, но он будет непригоден для репликации.
Скрипт позволяет зажать Пробел, чтобы продолжать пытаться заново создать правильные дампы до тех пор, пока не получится успеть между коммитами пада в базу. На крайняк можно просто попросить всех с полминуты ничего в пад не писать, либо всё же закрыть сервер пада, если совсем никак не экспортируется.

А вот как нужно настраивать репликацию.

На запасном хосте, нужно развернуть свою копию MySQL сервера, но в файле конфигурации «my.ini» требуется заранее обязательно изменить «server-id=11» на другое число. Пад можно не запускать, достаточно будет «install_db.bat» и импорта правильного дампа с мастера.

Теперь запускаем «replication_use.bat», и консоль спрашивает IP мастера. Его надо аккуратно ввести и нажать Enter. Будет выведен неинтерактивный статус. Окно можно закрыть, а вскоре – выполнить «MySQL_STATUS.bat», чтобы получить больше информации.

В этой большой таблице важнее всего пункты «Slave_IO_State:» – текущее состояние, должно быть что-то типа «Waiting for master to send event». Если там пусто, или какой-нить реконнект – плохо. «Seconds_Behind_Master:» – самое важно, если там «NULL» – репликация не работает. Должно быть число, обычно «0». А «Last_IO_Error:» – сообщение об ошибке, но я-ще не понял, как его очистить.
Для перезапуска репликации – можно выполнить «replication_use.bat» и просто нажать Enter, чтобы взять старый IP.
Если мастер работает на другом порту – откройте сам скрипт и поменяйте там «echo MASTER_PORT = 3311,»

Остановка репликации – «replication_stop.bat». Кстати, реплицирующий сервер (я надеюсь) блокирует себя для записи, поэтому запущенный к нему пад не должен заработать. Но всё равно, лучше не рисковать, и если на текущем хосте репликация – то в конфиге пада переключить на dirty.

Теперь весь процесс использования репликации:

Первое, назначаем главный хост у кого-нибудь, и запасные хосты.
Каждый из них развёртывает MySQL и пад, проверяет, что всё работает. Запасные пады закрываются.

Второе, главный хост снимает дамп с базы (пусть, даже пока там ничего нет) и передаёт его остальным.
Те импортируют дамп в базу, и запускают репликацию. Нужно быть уверенным, что она работает. (Для этого можно остановиться и запустить базу для пада, увидеть там новые изменения, всё сбросить и снова импортировать изначальный дамп – репликация всегда «догоняет» мастер от сохранённой точки то реального времени.)

Третье, запасные могут раскрыть пады, настроенные на dirtyDB, просто как альтернатива для связи.
Но теперь вся работа проходит на основном хосте.

Четвёртое, мастер упал. Считаем, что связь с хостом потеряна полностью.
Нужно решить, чья реплика теперь станет главной. Останавливаем её, и обязательно снимаем новый дамп со своего варианта базы, расшариваем его.
Запускается пад, настроенный на mysql, и все переходят в него (правда, цвета и имена больше не будут соответствовать прошлым – это потому что хост другой, и cookie не пересекаются, браузеры войдут как в новый пад).

Пятое, все остальные запасные хосты скачивают дамп с этого, и перебрасывают репликацию на него.
Если первый хост оживёт – он может подцепиться как ещё одна реплика.

Если по каким-то причинам, экспорт из базы стал неадекватно большим (хотя он ужимается) – можно просто запустить пад у себя, сделать оттуда экспорт в .etherpad, потом грохнуть базу нафиг, заново пересоздать, импортировать документ в пад, и снять дамп для репликации.

И напоследок:
– чтобы сделать рут-пароль к mysql пустым, нужно удалить папки \data и \DB из \MySQLServer5.5\ (это уничтожит базу данных, если что) и вытащить их из файла \bin\restore – это обычный .7z архив. Теперь, удалить мой «pass.bat».

– чтобы использовать другой порт, меняйте в «my.ini» (мастер) и «replication_use.bat» (реплика).

– чтобы сменить пароль для базы пада, ищите в «install_db.bat» и «settings.json» самого пада. Пароль репликации меняется в «install_db.bat» (мастер) и «replication_use.bat» (реплика).

– ещё раз напомню, что путь к папе нудно менять вручную (то есть все файлы нельзя просто так взять и переместить куда-то), а именно в «my.ini» (два раза, с прямыми слешами) и в «path.bat».

– если будете разводить «локальные копии mysql», весящие на разных портах – во-первых, трижды перепроверяйте пути – не то будет так, что батник запускается из одной папки (путь path.bat), сервер на самом деле работает из другой (соединения проходят через порт, а где сам сервер при этом ж не важно), а используемые файлы самой базы – в третьей (my.ini может показывать куда угодно, например на файлы не своей копии mysql). А во-вторых, последний раз когда я проверял (у меня уже не было двух копмов под рукой) – у меня вообще репликация локально не заработала, до мастера не достучалась.

– имя процесса «mysqld.exe» (в \bin\) я намеренно изменил на «tdtpad_mysqld.exe», чтобы если что, не конфликтовать с потенциально имеющимися базами данных, запущенными на хосте. Поэтому, имя также должно быть прописано в «path.bat». Кстати, если на одной машине несколько копий сервера – команда «MySQL_kill.bat» убьёт все, а не только текущую.

Если кто желает сейчас проверить репликацию (пока я не забыл, как всё работает) – давайте. Я не претендую на то, что использовать её в продакшн. Точно сломается что-нибудь.

Если что, в моём архиве по факту уже выполнен «MySQL_totalreset.bat» и «install_db.bat». Файл «for settings.json» ни для чего не нужен, это просто кусок настроек для пада, а папка \tmp\ – туда я скинул все шаблоны для файла конфигурации, чтобы не мешали. Модуль «7za.exe» в \bin\ – добавлен мною, как и файл «restore», содержащий исходную версию внутренней базы самой MySQL. Прочие проги в \bin\, кажется, не нужны; но я не стал их трогать, чтобы не портить целостность самой сборки.

О, я подумал, что неплохо было бы оставить в файле «coment.txt» всё это моё сообщение, чтобы оно всегда находилось под рукой.



but nobody came
 
aleksusklimСообщение # 664 | Тема: Перевод игр о Спайро – графика + общие вопросы Понедельник, 10.10.2016, 23:09
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Ну в общем тут как было…
Вставляю я значит, совиный атлас, ну там RipBin, FastWad, PGG и WinHex. Думаю, инструкцию надо написать ещё разок, опять от и до. Да и все программы в единый пакет свалить, хотя ничего нового нет.

Потом, когда вставил – понял, что забыл по факту само изображение-то координатами задать, в соответствии со смещениями из прошлого моего комментария.
Ну и я сделал это прямо в памяти, кстати, там где я писал «ширина» – кажется, не столько ширина и высота, сколько координаты противоположного угла рамки (равная ширине и высоте только если позиция в 0,0)

Ну короче, я вставил!
http://klimaleksus.narod.ru/Files/REPEAT/newatlas_1.jpg
– тут ещё неплохо было бы тёмные и светлые пятная на границе подправить.

Забавно, что использованное мной приведение к палитре (а именно, просто пересохранение в 256-цветный в MSPaint), дало очень фиолетовый оттенок во VRAM:
http://klimaleksus.narod.ru/Files/REPEAT/newatlas_2.png

Хотя как видно, приведение было не очень хорошим, нужно попробовать через ещё какую-нибудь программу (с более адаптивной палитрой), а то на затемнении блики разноцветные видны:
http://klimaleksus.narod.ru/Files/REPEAT/newatlas_3.jpg

СТОП

…кто-нибудь заметил что-то подозрительное и очень нехорошее?


Итог: не-а, мы не можем менять размер картинки. Придётся втискиваться в оригинальную. А что теперь будет со шрифтом, я даже представлять не хочу.


*UPD*

Ну, координаты взять же надо?
Чтобы выжать максимум (как будто бы ещё два пикселя справа можно вытащить, но я чё-т не уверен, ну нафиг!), пришлось пропатчить 179-й по смещению:
6FC0h = 00 18 60 00 83 7F 88 00
– там было «81» вместо «83».

Вот сеточка (красная рамка, синяя середина, и зелёные 32*32)
http://klimaleksus.narod.ru/Files/REPEAT/atlas_mod.bmp

Вставлено с ней и без – чтобы знать, какой там фон:
http://klimaleksus.narod.ru/Files/REPEAT/atals_grid.png
http://klimaleksus.narod.ru/Files/REPEAT/atals_none.png
(ориентироваться по нижнему кадру на скинах)


but nobody came

Сообщение отредактировал aleksusklim - Вторник, 11.10.2016, 19:17
 
aleksusklimСообщение # 665 | Тема: Перевод игр о Спайро – озвучивание. Пятница, 14.10.2016, 00:04
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Nightman600, приветствую!

Я просмотрел вашу пробу (она трёхсекундная, всё верно?), и она довольно неплоха.
Но увы, слишком короткая, чтобы судить точнее))

Кстати, роль самого Спайро – по сути, эпизодическая роль, относительно всей игры.
Основная часть текста принадлежит тем персонажам, которые встречаются на уровнях.

В этой теме можно найти и хорошие инструкции о том, как сделать качественную запись, так и ссылки на некоторые тексты для проб.
Но кому хочется копаться в прошлом, верно?

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

А вы, в свою очередь, пообещайте, что не покинете нас, раз уже решили нам помочь и присоединиться к проекту!
(Но если что – мы тормоза. Но вы ж тоже никуда не торопитесь?..)


but nobody came
 
aleksusklimСообщение # 666 | Тема: Перевод Spyro 3: Текст Суббота, 15.10.2016, 16:56
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Короче.

На самом деле я хотел ещё раз перевести Тиков.
Но задумался о том, нельзя ли как вариант рассмотреть перевод их текста в нестихотворной, но эквиритмичной оригиналу форме, чтобы с абсолютной точностью повторить интонацию?
Не знаю, зачем. Если так сделать, то у нас получатся не стихи – но тем не менее, эти фразы обычными уж точно назвать будет нельзя.

Для этого нужно воссоздать исходную слоговую скему, ритмику ударений.
Я так делаю транскрипцией, когда перевожу некоторые песни.
Но тут не песня, и транскрипция только путает. Однако, можно заменить графическую схему на реальный набор русских слов, которые собираются кусочками с верными ударениями.

Но опять же, где взять слова…
Я хотел найти онлайн-сервис, где был бы подбор ударений по маске, но не нашёл.
Искал быстрый словарь ударений, чтобы написать свою программу…
Но у меня был электронный словарь Ожегова, в котором есть и ударения, и вся база в текстовом формате.

Всё что мне осталось – распарсить это регулярными выражениями, и сверстать интерфейсик:

http://klimaleksus.narod.ru/Files/S/ojegov.htm

Использует русские «о» и «х» как маску ударного и безударного слогов; символы можно и поменять.
Всё прочие и переносы строк сохраняются, обновление по написанию или щелчку в поле – маски превращаются в рандомные слова (менять отдельно взятые нельзя, но можно использовать вывод повторно в поле…)

Думаю, этот скрипт, вообще говоря, очень даже может пригодиться и при переводе песен, потому что с ним проще наглядно собрать верную ритмику, хотя её и придётся составлять вручную.
А ещё это почти что словарь ассоциаций… (если кто внатуре вздумает белые стихи на нём шпарить – смените О/Х символы да хоть на =/+, чтобы русские слова как есть принимались на входе)

Вот Тики, с моей ритмикой. Тут я ориентировался именно на интонацию оригинального произношения, а не на сам текст.
Пунктуация – лишь для облегчения при чтении моего суррогата:


352
Rhynocs are running rampant around here,
but I can't get anyone out of the Tiki Lodge
long enough to do anything about it.

хо охо хо ох х,
оох охо ох - оохо х
х ох - ох оох охо!


365
Well, it looks like it's just you and me.
I'll keep a look out while you sort out the rhynocs.

х охо ох оох...
охо ох, ох - охо хо.


451
Here, take this egg.
They were giving them away at the Tiki Lodge last night.

х, оох!
оохо оох, оохо о ох.


126
I'm playing a game of hide and seek with my friends.
If I can't find where they've hidden their heads
they won't let me join the Tiki Lodge.
Help me put them back together
and I'll make you an honorary member.

х о ох ох ох оох!
оох о оохо ох,
ох оохо охо х.
хо хо х охо,
ох о х охооо хо.


277
When you find a head,
land on top of it to pick it up.
Then fly it over to an idol body
to put them back together.

оох ох,
хо хоо: ооох!
охо хо оохо хо
ооох охо.


1095
Take this egg
as a sign of your honorary membership in the lodge.

х ох,
оох, оохооо хоо - оох.


287
When you've picked up a tiki head,
fly over to any body
and use the square button to drop the tiki head.

хо хо охо о,
охоо хо хо,
охо х хо, охо хоо.


1102
Well that's never happened before.
I hope it's not a bad omen.

ох хо хо ох.
охо - хо - х, хо.


318
Are you the dragon looking for all those eggs?
Because I saw a shifty looking character
with one over there.

ох охо хо ооох?
ооох - охо, хо хоо
ох, оох.


1054
Hey, there goes another one.
He was really fast...
maybe if I activate the supercharge you'll be able to catch him.

х! ооохоо.
хо хо х.
хо оохоо охоо, х оохо охо!


517
You should catch that thief
before he steals something valuable.

х ох ох,
ооох - оохоо.


560
Those guys ought to be locked up.

х о ооох о.


328
If you can bring back one person from each of our five worlds,
we can help you use the balloon.

хоо хо х хо, охоо х-х.
оохо х оох.


551
Let's head on over to the balloon!

ооохо, ооох!


351
This balloon will take you to the great Tiki Lodge in the sky!
Just jump on when you're ready.

о ох охо оох, оох оох!
о! ох: оохо.


1013
I'm late for a dinner party at the Tiki Lodge,
and the portal to my home just stopped working.
Maybe the portal will reactivate
after a few more dragons hatch.

ох оохо хо - оохо о,
оохо оох - ох хо.
хо, охоо охоо,
ооохо хоо.


362
At last, my portal is working again!
Come visit me at the Tiki Lodge!

ох! охоо хооо.
охоо оохоо.




Ага, вопрос, где же мой перевод? А не успел…

Сам словарь можно скачать вот тут:
http://klimaleksus.narod.ru/Files/S/ojegov.chm

А вот собранные исходные озвучки тиков, если срочно нужно, а под рукой нет:
http://klimaleksus.narod.ru/Files/S/tiki.zip

Кстати, нашёл отличный mp3-плеер, очень шустрый:
http://klimaleksus.narod.ru/Files/S/stp10603.rar
(удобнее всего будет перетаскивать файлы на его ярлык)


but nobody came

Сообщение отредактировал aleksusklim - Пятница, 28.10.2016, 19:44
 
aleksusklimСообщение # 667 | Тема: Перевод "Legend Of Spyro - A New Beginning (PS2)" Воскресенье, 16.10.2016, 21:32
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
> Давайте прекратим флуд

Эй!
Вообще-то это не флуд, а очень информативно…
 
aleksusklimСообщение # 668 | Тема: Перевод Spyro 3: Текст Понедельник, 17.10.2016, 01:25
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Ну вот я поозвучивал – CloudSpires и SunnyVilla.
Чудики-импы: (мне абсолютно не подходит этот персонаж…)
http://klimaleksus.narod.ru/Files....mps.mp3
– структура: оригинал, первый вариант, второй вариант.
Варианты отличаются логическим ударениям на слова. Может, на каких-то репликах я случайно выбрал не те варианты, но в общем, это верно.


Толстосум:
http://klimaleksus.narod.ru/Files....ney.mp3
– опять по две; в 1022 взял разные переводы.



Зоя из второго уровня, плавно переходящая в первый и шейлу-марко-рапунцель:
http://klimaleksus.narod.ru/Files....zoe.mp3
– разные варианты в 251, 1099 (моя актёрская правка: «для твоих рогов» звучит так, будто я «врагов» выговорить не могу…); а в «I've moved out» замечали какая интересная интонация?



Львята… у них я заметил такой акцент на букву «р». Оно не по-английски произносится.
Я попробовал вторым вариантом – сделать «р» явной, будто я озвучиваю попугаев..
Там, где ни одной эр в тексте нет – поменял текст:
http://klimaleksus.narod.ru/Files....leo.mp3
– а именно в 1153, 497 и 477; в 296 потерял не р-р-рэшную озвучку, а в 381 – местоимение «я».



А вот и Хантер:
http://klimaleksus.narod.ru/Files....unt.mp3
– я уже так запарился к этому времени, что просто записывал в один заход, по одному дублю без второго варианта. Может поэтому бывало, что временами вылетал из роли. А ещё на первой фразе микрофон трещал…


– в 349 поменял «лады» на «да», потому что там другая интонация оригинала; а в 161 – слова сами местами поменялись…


but nobody came
 
aleksusklimСообщение # 669 | Тема: Перевод Spyro 3: Взлом и программы Среда, 19.10.2016, 00:17
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
http://klimaleksus.narod.ru/Files/4/SavestateRunner2V0.rar

Копипаст справки:


SavestateRunner v 2.0!

Программа для быстрого запуска сохранёнок эмулятора Epsxe.

Установка:
1) Поместите файлы «SavestateRunner2V0.exe» и «SavestateRunner.bin» в папку с эмулятором.
2) Запустите «SavestateRunner2V0.exe». Возможно, откроется окно эмулятора (если настойки по умолчанию сработали), его можно закрыть.
3) Появится файл «SavestateRunner2V0.ini», откройте его Блокнотом.
4) Если нужно, измените значение «EPSXE_EXE=ePSXe.exe» на имя исполняемого файла вашей копии эмулятора – например, на «EPSXE_EXE=ePSXe200.exe».
5) Эмулятор должен быть версии 1.7.0. Если это не так, то вам нужно как-то выяснить адрес в его памяти, по которому можно достать идентификатор запущенной игры, и внести его в строку «GAME_ID_PTR=12650304» – например для Epsxe 2.0.0 этот адрес равен «GAME_ID_PTR=23256000».
6) Если вас интересует только какая-то конкретная игра – впишите путь к её образу в строку «DEFAULT_IMAGE=SavestateRunner.bin», например «DEFAULT_IMAGE=D:\DATA\Spyro-Year-Of-The-Dragon gh.iso»

Использование:
1) Снимите дубликат с любой своей сохранёнки (они копятся в подпапке «sstates\»), и смените её расширение на «.SavestateRunner». Например, файл «SCUS_944.67.002» можно переименовать в «SCUS_944.67.000.SavestateRunner». Файл сохранёнки получит иконку.
2) Его можно запустить! Тогда, откроется настроенный эмулятор, в который будет загружена эта сохранёнка, как открытая на образе по умолчанию (изначально «пустой»). Если эта сохранёнка от другой игры – скорее всего, рано или поздно всё сломается.
3) Чтобы запустить сохранёнку под образом конкретной игры – перетащите ваш образ, например .iso, на неё саму – на файл .SavestateRunner (он будет вести себя как «программа», позволяя перетаскивать на себя), и эмулятор загрузит данную сохранёнку с этой игрой. Если сохранёнка действительно от этой игры, то всё должно работать идеально.
4) Также, можно перетаскивать сохранёнки на «SavestateRunner2V0.exe». Либо изменить в настройках опцию «DEFAULT_IMAGE», чтобы задать образ по умолчанию для всех сохранёнок, открытых двойным щелчком, а не перетаскиванием образа на них. Технически, для самой программы: первым аргументом передаётся сохранёнка, а вторым – образ, если есть.

Ограничения:
1) Когда сохранёнка будет запущена – чтобы вручную производить сохранение и загрузку, а также совершать другие действия горячими клавишами Epsxe – вам необходимо один раз нажать F3. Например, вы можете делать свои сохранения после загрузки изначальной – и для этого вы попытаетесь нажимать F2, но окошко с картинкой не станет появляться, пока кнопка F3 не будет нажата хотя бы однажды (первый раз «загрузка savastate» не выполнится).
2) Сворачивание эмулятора через Escape, или любая другая попытка поставить игру на паузу – закроет эмулятор. Чтобы не потерять свой прогресс, сохранитесь в какой-нибудь слот вручную через F1, чтобы потом загрузиться через F3. Но не сохраняйтесь в первый слот, потому что он будет перезаписан при следующем же открытии исходной сохранёнки (которая, кстати, не будет перезаписана ни при каких обстоятельствах), а примените F2 и выберите другой. Если вы желаете продолжить работать с сохранёнкой в эмуляторе так, чтобы иметь возможность сворачиваться в меню, то просто запустите эмулятор обычным способом, выберите открытие того образа, через который была загружена данная сохранёнка (для образа по умолчанию, выберите «SavestateRunner.bin») и нажмите F3 сразу после инициализации эмулятора.


but nobody came
 
aleksusklimСообщение # 670 | Тема: Перевод Spyro 2: Ripto's Rage Четверг, 20.10.2016, 23:26
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Цитата Томас
Ибо всякий, кто дочитывал ту простынищу до конца, вылетал с ошибкой «System Out of Memory»


Да у меня такое от любой страницы этой темы…
Короче, я отсюда и вверх.

Цитата Томас
отдельный пост со всей нашей концепцией?


Нужен, да.
И глоссарий, чтобы не вспоминать, а было ли в названии какого-либо уровня такой-то игры данное слово, или пока свободно.

Цитата Томас
Вроде количества врагов для усилителя в Бризовой Гавани.


Тогда это надо тащить ещё с постов Йамса со времён Вихря…

Цитата Томас
Пересобрала посты по именам и обновила шапку. Внесла правки.



КА-А-АК!?
Что у тебя там за формат такой внутренний, что и правки вносятся легко, и в BB-коды отлично выгружается?
А цепочки цитат-то как собирать…

Цитата Томас
Справедливости ради, в тексте уровня такого сочетания нет.


Я просто озвучил логическое продолжение на слово «бесплодный» и утверждение, что «скелос» тогда не будет звучать как имя существа.
Отнюдь. Старичок такой костлявый получается – ну, он вроде и бойкий такой, но увы.

Цитата Томас
То есть дубина он и есть. И в самом слове «Гронк» есть что-то от удара дубинкой. Грох?


О, только сейчас понял, что «Грох» – это от «грохнуться».
Грох… где был грох?
В каком-то полнометражном мультике. Возможно, он был маленький. Возможно, ребёнок или питомец.
Я думал, «грох» – это от «горошина», почему-то.
Или, мол, «грох ему цена»…

Так ещё раз, я не понял: имена переводим или нет!?
Или и так и так?

Потому что тут среди всех постов – постоянно по два варианта. Между ними идёт выбор, или нет?
И если, скажем, три персонажа на одну тему – то нельзя же двух транслитерировать, а последнего перевести.

Цитата Томас
Итого, Гонки или Трасса?


…а почему не «Гонка»?

Кстати, «time attack» пираты, по-моему, переводили как «гонка со временем» (может, не в этой игре).

Цитата Томас
Foreman – Прораб, Мастер, Бригадир?
Цитата Томас
В крайнем случае можно устроить им распределение по специальности: cлесарь, сварщик, плотник, монтёр…


– вот плотник вроде подходит.
Ещё я думал об инженере. Но мастера нормально.
У нас же мастеров больше нигде, включая все игры и названия миров – нет?

Цитата Томас
Что вообще за дела с этой длиной? При всей той магии, что уж есть, просто-таки стыдно не покорить её.


Вторую игру не ломал.
Но рюкзак должен по идее сработать.
Надо его уже закодить наконец.

Цитата Томас
Fracture Hills – какие Холмы?


Может, трещащие…

Цитата Томас
Насчёт Глиммера, Колоссуса и Хуррикоса


Как-то они через один в списке следую – одно слово, два слова.

Цитата Томас
Они ж при каких-то условиях могут попеременно всплывать или нет?


О, это проверять надо.

Кстати, я во время игры никогда на её телепорт не соглашался: я же хочу знать, как я туда попал…

Цитата Томас
Это наверное был самый вопиющий перегиб во всём тексте.


В смысле, что последний вариант – находка?
Ну да, не могу не согласиться.

Цитата Томас
Если верить искушённым, некоторые фразы в игре, хотя и не отмечены «нулём», можно услышать только с читами:


О, это же тот сайт, что скриншоты из SWV использует!

Цитата Томас
И «Жорик» произнести легче, чем «Джорджик»


, если именно «Джорджик», а не «Joрjик».

Цитата Томас
Когда всё в одном посте, я могу с первого же взгляда мысленно на всё ответить. И уже буквально через месяц я вспомню, что надо бы это ещё и написать. А если нужно ещё что-то дополнительно открыть... этот процесс немного усложняется.
+

Цитата Serlutin
Ну так видеоинструкция же не вышла. Вот Арчик и не сможет разобраться.


Бли-и-ин… Точно же.
На самом деле, мне очень-очень стыдно…

Цитата Serlutin
гораздо проще записать и кинуть ссылку, чем 1. Скачать 2. Установить 3. Записать и сохранить в файл 4. Выложить этот файл куда-нибудь 5. Отослать ссылку.


Ну нет.
Это как «перепечатать с бумаги» v.s «установить дрова на сканер + найти программу по распознаванию текста + отсканировать + исправить документ».
В перспективе – второе куда предпочтительнее.

Плюс тут же для озвучки – и качество / настройки оборудования / формат файла.

Цитата Томас
а Зою добавила к остальным боссам.



Цитата Томас
я знаю одного Джавахарлала... но все называют его Жорой


Да у нас почти всё через Жору сделано.

Цитата Томас
В то же время, лазание по специальным стенам – тоже разновидность скалолазания. Так что на мой взгляд, это не так критично.


А вот эти выделения зелёным – в оригинале они являются неизменными терминами. А у нас будет «летать»/«пролетишь», «лазить»/«карабкаться» – и так далее – и нормально!?

Цитата Томас
Игрок и камера – это ж две стороны. Пассивная камера – активный ты: больше контроля. Разве нет?


Я всегда на активной, кроме очень редких случаев, когда требуется какой-то хитрый манёвр.
С пассивной же приходится постоянно вручную управлять ей – хотя я и умею это делать.

Видимо, это как ручная или коробка-автомат в играх про гонки. Ну кто в своём уме выбирал ручную!? ))

Цитата Томас
*Возвращение блудного Томаса*


Уф. Ну вот, насколько смог в историю погрузиться – настолько смог.
По обсуждениям… на там уже как бы не актуально, последние варианты-то недалеко, а все споры устарели.
По репликам… ну она вроде достаточно хороши. Может максимум где-то запятая спорная, но куда большей пользой было бы проверить по озвучкам, чего я не делал.
А по именам или названиям мне даже придумать вроде нечего, я в саму игру значительно меньше по факту играл, чем в Spyro3 (я ж только его постоянно ломаю), и поэтому что-то революционно новое и подходяще мне не создать.

Насчёт каждого названия можно и подискутировать, но многие из них – КАК ЕСТЬ – меня устраивают.
А остальные – они могут зависеть от чего-то ещё, или их хочется потом увидеть все вместе одним списком…
Так что я сейчас достаточно бесполезен.


but nobody came
 
aleksusklimСообщение # 671 | Тема: Перевод Spyro 3: Текст Среда, 26.10.2016, 23:42
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Озвучил.

Котики (ну с Зоей и Шейлой) :
http://klimaleksus.narod.ru/Files....als.mp3


– на этот раз по одному варианту озвучки. И я как-то сразу стал потоком записывать, и как-то микрофон плохо встал, слышны пыки на «п» и «б».
А ещё мне кажется, если я помещу жевательную резинку себе в правильное место, то буду меньше шепелявить… Надо потом попробовать.

Вот и из домашнего мира:
http://klimaleksus.narod.ru/Files....sun.mp3



*UPD*

Ну вот. (Оригиналы на предыдущей странице форума, в конце)

Во-первых, тут не все. Я думал это легко, а это оказалось почти как реп переводить…
А во-вторых, да, они хреновенькие. Нисколь не претендую.

352
http://context.reverso.net/translation/english-russian/running+rampant

365
Ну, похоже, теперь мы вдвоём.
Я буду в тылу, а ты – разбей злодеев.

451
Глянь, тут яйцо.
В Ложе Тики в ночь вчера раздавали их – возьми.

126
Я вёл друзьям игру «мороз-горячо».
Не найти мне, где же головы их –
Тогда в Ложу Тики закрыт мой путь…
Вместе склеить всех поможешь –
И будем мы почётными гостями!

277
Коль главу нашёл,
Сверху стой на ней, да подними.
Доставишь целой – соберётся идол,
Раз голова на теле.

1095
Вот яйцо.
Это знак полноправного участника в Ложе сей.

287
Если голову взял уже,
Зависни над телом Тики,
С квадратом жми кнопку –
И груз опустится.

1102
Исход раньше такой не видал.
Не знак ли это злых духов?

318
А ты – дракончик, кто яйца тут искал?
Уж видел я – парнишка подозрительный
С одним пробегал.

1054
Эй, там есть ещё другой.
Правда, он бегун…
Может, я включил бы ускорение –
С ним ты догонишь воришку!

517
Ты поймай вора,
Чтоб не украл он что важного.

560
Сей люд в тюрьме давно ждут.

328

551
Ну наконец-то можно к шару!

351
Шар тебя к великой Ложе Тики в эфир отнесёт!
Так вперёд, коль желаешь.

1013
Спешу на вечерний праздник в Ложу Тики я,
А портал ко мне домой исчез вскоре.
Может, он снова заработает,
Вышли б драконы из яиц.

362
Портал работает мой наконец!
Увидимся, в Ложе Тики там.

*UPD* – +277, +1095


but nobody came

Сообщение отредактировал aleksusklim - Пятница, 28.10.2016, 23:23
 
aleksusklimСообщение # 672 | Тема: Перевод Spyro 3: Взлом и программы Пятница, 28.10.2016, 22:05
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Две разные копипасты описания формата, как хранятся тексты Spyro3. Сделаны в разное время для разных людей. Что-то актуально, что-то может быть уже нет. Публикую сюда.




Во-от. Так что пока в теории мой план более надёжен. Итак ещё раз, подробнее.

(далее под «4байта» я буду понимать 32-бит «word» / int)

Берём лист 88-ых объектов. Каждое первое 4байта объекта – локальный указатель на 12 байт (три раза по 4байта) доп-данных. Если последние 4байта не равны «FF000000» – отбросить объект. Далее пойти вниз, по списку указателей на «локальные указатели». Если какой-то из них показывает на 4байта после 12 байт доп-данных, отметить объект как хороший (ещё можно на следующие 4 байта тоже ждать указатель, ещё не знаю, даст ли эта дополнительная строгость отсечение какого-нить мусора). Затем выкинуть все «нехорошие» объекты. Потом читать для каждого всё, что за доп-данными, запоминая первый и последний указатели на строки. Предположение в том, что это всё ЦЕЛИКОМ текст – какие-то реплики. Важно начало и максимальный размер этой области.

Хотя все реплики сами по себе нам тоже понадобятся. Для каждого объекта нужно знать следующее:
• номер WAD_SUB.
• порядковый индекс объекта (позиция в 88-списке).
• его 12 байт (ну 8 на деле) доп-данных, и всё что это может нам дать.
• общее количество его фраз, включая все пустышки.
• имя объекта Теперь для каждой его фразы:
• указатель на то, где расположен непосредственный локальный указатель на эту строку.
• индекс в листе указателей, который отвечает за указатель из предыдущего пункта.
• значение первого байта текста, либо ноль – если это первая фраза = само имя объекта.
• столько байт в начале строки, предшествующие настоящему тексту (всё это придётся куда-то запоминать, потому что этот кусочек должен остаться привязан к переведённой строке, где бы она не оказалась).
• вопрос, нужно ли запоминать [номер] реплики по нашему кривополученному списку соответствия озвучкам? Пока я технического смысла в этом не вижу. С другой стороны, номер позволяет легко идентифицировать каждую строку. Однако как я помню, его очень трудно получить. А ещё, если наше техническое дело-таки дойдёт до озвучики, нам понадобится не только ребилдинг STR (можно считать что уже solved), но и какое-то сопоставление всех озвучек всем текстам, и очень желательно, чтобы оно было полностью автоматическим. Вот чувствую, что там уже номер реплики понадобится как ни крути…

Так вот. Я думал что-то вроде по одному .txt документу на подуровень, скажем, следующей структуры:

12) Zoe
- text 1
- text 2
-
- text 3
45) Hunter
- do it?
- yes
- no
62)
- go off
- come on in
-
116) Zoe
- hint

То есть тут по порядку появления перечисляются говорящие объекты, в формате «номер-скобка-имя» (игнорим пробелы здесь и везде), за которым по строкам перечислены все его реплики в том порядке, в каком следуют указатели на них, в формате «дефис-текст», причём если реплика пустая, то будет просто дефис (ну нам ведь не понадобятся нигде тексты состоящие из одних пробелов или пустых строк?). Все прочие переносы или вхождения, не удовлетворяющие формату – игнорируются. Такой файл вполне себе будет пригоден для ручного редактирования.

Но это не единственный «output» алгоритма, потому что всё то, что я сказал, что нужно знать и запомнить – придётся где-то хранить, и очень желательно, чтобы не здесь. Потому что индексы, байты и указатели – критичная штука, которую мы менять не собираемся, и она не должна быть редактируемой вот так просто. Поэтому придётся в каком-то ещё формате хранить всю кучу данных, единожды извлечённый из, что важно, оригинального WAD.WAD.

Далее тексты будут вставляться, как я сказал, алгоритмом рюкзака, причём сразу для всей игры для всех подуровней. Считываются все строки текущего уровня, а потом перебором разбрасываются по тем имеющимся областям, где когда-то был оригинальный текст.

Ну алгоритм примерно такой (работает математически на цифрах, а не на самих данных): рекурсивная функция, которая пытается разместить текущую строку в доступное свободное место (строки заранее отсортированы по убыванию длины) – если поместилась, то рекурсия на следующую строку; если нет – пытаться положить текущую строку в следующее свободное место, и так далее; если всё равно не удалось – выйти из рекурсии выше, чтобы породившая рекурсия отвергла эту ветку и пыталась далее. А ещё нужно запоминать самый глубокий провал, чтобы в случае, если разместить всё не получилось – выкинуть эту строку (в EXE), а алгоритм повторить без неё.

Итак, если всё вернулось удачно – раскидываем строки как рюкзак приказал. Причём здесь очень аккуратно нужно будет с указателями работать, чтобы всё плотненько и корректно запихать. Если же не всё гладко – ломаем указатель на неудобные строчки в оконечном листе, каждую из них копируем в очередное (ну начиная с какого-то) место в EXE, естественно, запоминая смещение после неё, для копирования других таких. Вычисляем абсолютный указатель на неё в EXE, и вписываем его вместо локального в сам объект.

Ну вроде как всё верно. В итоге, предположим, мы ни в чём себе не отказывали, и реплики у нас дай бог. Тогда некоторые из них улетят в EXE, но при этом же освободят своё место другим строкам! А рюкзак гарантирует, что оно будет использовано максимально. То есть по факту место в EXE, мне кажется, не так уж быстро будет кончаться. И туда всё поместится. Вообще все, что мы захотим.

С именами и того прикольней, можно таких как Зоя и Хантер отдельной бригадой в EXE заточить, и они априори отдадут дополнительные байты тексту. Плюс та фишка с FF000000-пустыми репликами. Их тоже для верности можно в EXE кидать, чё б нет, всего 4 байта.

Но к сожалению, это не всё. Я умолчал о перекодировании нашего текста по таблице соответствия, а также о чистке текста. Чистка – например замена тире на дефисы (физически символ), три точки подряд на многоточье, двойные пробелы на один пробел. Этот надо как-то формализовать, и желательно не в коде программы, чтобы менять можно было.

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

Только пока у меня нет идей, как эффективно (для использования и изменения) хранить эту таблицу. Тут уже .ini структура A=B, C=D не прокатит, потому что сами «B» и «D» – бинарные (особенно для Spyro3), которые могут содержать символ переноса строки или ещё что похуже.

А вот алгоритм рюкзака что я реализовал:
http://klimaleksus.narod.ru/Files/4/bagpack.rar

Считывает файлы в таком формате (все числа целые положительные): «количество участков памяти», «список размеров всех участков»; «количество размещаемых строк», «список размеров строк (включая терминирующий ноль каждой)». Если обработка успешна – пишет в выходной файл для каждой строки (в том же порядке) номер участка, куда её рекомендуется всунуть (участки нумеруются с нуля); либо = «-1», вместо индекса, если данную строку лучше вытащить в EXE. Входной файл передаётся либо в первом аргументе, либо считывается прямо со входного потока; выходной файл – либо во втором аргументе, либо просто пишет на консоль.

bagpack_test.bat – запуск на файл, in.txt – пример. В архиве две версии бинарника, сделанные на разных компиляторах.

Программу можно прикрутить как есть к будущей системе внедрения строк; можно и переписать заново. И кстати, я не уверен в полной правильности его работы, я плохо проверял результаты. На вид работает…




http://klimaleksus.narod.ru/Files/NEXT/Wad_112-4.zip
http://klimaleksus.narod.ru/Files/NEXT/Wad_104.zip

Начнём с первого файла, «Wad_112-4.wad». (Если что, это суб-субфайл)

По смещению 48 Нужно считать указатель.
Это – относительный указатель, он показывает, на сколько байт от текущей позиции (от самого себя) нужно сдвинуться вперёд (или назад, но такого не бывает).
Эффективно, если на самом деле СЧИТЫВАТЬ указатель – то текущая позиция уже будет на 4 байта впереди, поэтому от указателя надо отнять 4.
Если же файл уже в памяти (а это значительно быстрее, чем по 4 байта с диска читать…) – то просто инкремент настоящего указателя на его же значение.
Таким образом, если там число «4» – то оно показывает прямо на следующее же число.

Так вот! По смещению 48 – относительный указатель. Он показывает на следующий относительный указатель. Я это называю «прыжок». Совершить прыжок – значит считать текущее значение и продвинуться на него вперёд.

Требуется совершить 12 прыжков.

http://klimaleksus.narod.ru/Files/NEXT/spec_1.png

– начало файла. Я закрасил цветами те указатели, на которых совершаются прыжки. Тут видно восемь прыжков, последний ведёт ниже:

http://klimaleksus.narod.ru/Files/NEXT/spec_2.png

– ещё два прыжка. Далее дела обстоят так: (выделенные большие области будут описаны ниже)

http://klimaleksus.narod.ru/Files/NEXT/spec_3.png

После двенадцатого прыжка курсор оказывается на относительном указателе, который по совместительству показывает размер области с объектами.
Это – общая выделенная под них память, но заранее инициализированы не все. Количество реально существующих объектов записано в следующем же целом числе – в данном случае, это «5» (на скриншоте – не закрашено, перед жёлтой областью).

Каждый объект – это структура по 88 байт, они следуют прямо друг за другом. То есть дальше можно уже считывать первый объект.

Сейчас в каждой такой структуре нас интересует только первое целое число – это абсолютный указатель на дополнительные данные для этого объекта. Он всегда ненулевой.

Абсолютный указатель означает, что отсчёт ведётся от начала виртуального файла; но не всегда физически от самого бинарного файла; на в данной ситуации, поскольку это уже извлечённый суб-субфайл уровня – указатели прямо фактически от его начала.

Теперь нужно перейти по каждому из них по очереди, чтобы посмотреть на дополнительные данные объекта:

http://klimaleksus.narod.ru/Files/NEXT/spec_4.png

– я покрасил дополнительные данные в цвет того объекта, которому они принадлежат. Мы почему-то считаем, что эти данные всегда занимают не менее 12 байт, так что для простоты можно считать, что они всегда 12, просто располагаются не подряд.

Ещё раз, на эти данные я попал, перейдя по абсолютному указателю в первом целом числе структуры каждого объекта.

Из всех объектов меня интересуют только те, у которых в дополнительных данных третье число, то есть байты с 9 по 12 – равно «255», причём как четырёхбайтное целое, эффективно FF000000. Иными словами, байт номер 9 равен 255, а байты 10, 11, 12 – нулю.

Из всех пяти объектов только один удовлетворяем этому условию, а все остальные – не содержат текста, и должны игнорироваться. Посмотрим на саму структуру его, выше:

http://klimaleksus.narod.ru/Files/NEXT/spec_5.png

– здесь выделен именно первый абсолютный указатель на дополнительные данные, являющийся по факту файловым смещением, на которое нужно перейти.

Далее, раз мы знаем, что дополнительные данные оканчиваются на FF000000, то последующие абсолютные указатели за дополнительными данными – это указатели на строки.

Первый – самый простой, это имя объекта. Простой указатель на начало строки, а все строки начинаются со смещения, которое кратно четырём. А строки оканчиваются нулевым байтом.
Это означает, что строки, следующие вплотную друг за другом – на самом деле могут быть разделены более чем одним нулевым байтом. Строка дополняется столькими нулями, пока смещение следующего за ней символа не станет кратно четырём.
Например если в строке всего один символ – то после него будут 3 нуля, чтобы суммарная длина делилась на 4 без остатка. Для строки из двух символов – два нуля; для трёх символов – всего один настоящий ноль. А вот если длина уже кратная четырём – то в файле будут выделены все четыре нулевых байта, чтобы строки не слиплись.

Зная это, получаем имя объекта – строка по первому абсолютному указателю, до первого нулевого байта. Но не совсем: лучше засчитать в пользу строки и все дополнительные нулевые байты по описанному расчету, чтобы точно получить смещение, где должно ожидаться начало следующей строки.

http://klimaleksus.narod.ru/Files/NEXT/spec_6.png

– на скриншоте после синих данных сверху – раскрашены указатели на строки. Соответствующие им тексты закрашены тем же цветом ниже. (А розовое в самом низу – дополнительные данные последнего объекта, в котором нет текста.)

Но лишь имя объекта является простой строкой! Все его реплики – управляющие строки.
Каждая управляющая строка начинается с байта, в котором записано общее количество управляющих байт в начале этой строки. Его нужно эффективно пропустить, причём первый байт сам по себе считается управляющим.
Таким образом, если на самом деле управляющих байт нет, то первый байт будет равен единице, а сразу после него – сама строка. Однако обычно управляющих байт там может быть от 2 до 7 и более. Причём они считаются входящими в саму строку при расчете количества дополнительных нуле на конце.

Если первый управляющий байт строки равен 255, то это означает, что строка «пустая». Собственно, байт = 0 тоже формально сработает (нет управляющих, значит это и есть начало строки, но ноль её же и завершает). Пустые строки в объектах допустимы, и часто встречаются между репликами. Но они забирают по 4 байта на свою длину, и следующая строка начнётся после этого «255» (опять же как int).

Мы будем считывать подряд указатели на строки, до тех пор, пока последующий вдруг не перестанет показывать ровно на то место, где ожидается начало следующей строки. Если не совпало – значит строки кончились, и можно идти искать следующий объект.

На скриншоте: красная простая строка – имя объекта. Далее две непустые управляющие строки – желтая и зелёная, хотя в обеих управляющий байт всего один.
За ними – ещё аж шесть пустых строк, отмечены тусклыми цветами. Правда, последняя не совсем понятно почему, но начинается с «0100…» – управляющий байт есть, но первым же символом строки является нулевой байт. Думаю, это можно считать эквивалентом пустой «FF00…» строки тоже (хотя может потом придётся поменять).

Последний указатель – число «4» – очевидно не показывает на последующую память, а значит – больше строчек в объекте нет.

Что должен сделать алгоритм?
Получить всё место, отведённое под все строки объекта – прямо всё-всё, большим куском. Однако, все управляющие последовательности в начале каждой управляющей строки нужно сохранить отдельно, чтобы не потерять.

Далее, зная индекс исходной строки, и поданного на вход программы текста перевода – разместить в памяти переведённые строки, не забыв дописать в их начала правильные управляющие последовательности.

Строки могут не начинаться со смещения, кратного четырём. То есть разделять их можно всего лишь одним нулевым байтом, получая таким образом дополнительное пространство.
Более того, все пустые строки (которые выводить не нужно, и в переводе их не будет) всех объектов – можно схлопнуть в единые 4 байта, разместив их где-нибудь. То есть все указатели можно поменять так, чтобы они указывали на одно и то же число 255, эффективно получая ещё по четыре символа с каждой пустой строки.

И разумеется, программа должна корректно поменять все указатели на строки, чтобы они попадали в начала их управляющих последовательностей. На выходе получаем сохранённый файл, в котором и строки перезаписаны, и указатели изменены.

Бонус! «Wad_104.wad»
Как парсить субфайлы уровней, а не суб-субфайлы подуровней.
На самом деле всё просто, нужно только в алгоритме сделать поддержку того, что абсолютные указатели отсчитываются не от фактического начала файла. А ещё проще – загрузить в память нужный косок файла, и пусть алгоритм работает как обычно, если он конечно всё читает сразу из своей памяти как из массива данных.

Так вот, начало файла уровня:

http://klimaleksus.narod.ru/Files/NEXT/spec_7.png

Нужно перейти по смещению 24 – это указатель на первый суб-субфайл подуровня. Его размер – в следующих четырех байтах, и весь субфайл можно сразу считать в память; но можно и игнорировать размер.
В самом суб-субфайле – вести себя как в предыдущем алгоритме: перейти к смещению 48, сделать 12 прыжков…
Но все абсолютные указатели будут именно относительно начала суб-субфайла в памяти.

Указатель на начало следующего субфайла – на 16 байт дальше, чем указатель на данный (цветные на скриншоте). По факту, это смещения 24, 40, 56, 72. Остановиться нужно на том, указатель по которому нулевой.

А в этом файле текста уже гораздо больше, вот например один из объектов:

http://klimaleksus.narod.ru/Files/NEXT/spec_8.png

Выделены 12 дополнительных байт, за которыми следуют указатели на имя и тексты; В трёх видимых текстах количество управляющих байт равно 4, 4, и 6.


but nobody came
 
aleksusklimСообщение # 673 | Тема: Перевод Spyro 3: Взлом и программы Воскресенье, 30.10.2016, 14:14
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Проверял, что будет, если в списке объектов окажется слишком мало места:
http://klimaleksus.narod.ru/Files/4/NobjScorch.rar

Файл «0» – это некорректная попытка, я там что-то нарушил. Но получилось прикольно. Там FreezeCheat, так что нужно нажать и отжать паузу. С Бентли не говорить, а то вылетает; надо сначала отойти от него.
Файл «1» – это уже как надо. Я расширил ту зону, что следует после списка объектов. То есть я укоротил список до, хм… 3+10 штук, и всё былое пространство – внёс как в «дополнительные данные», которые просто не будут использоваться, но ни на что не влияют.
Как видно, игра не вылетела. Она работает стабильно. Разве что, при создании нового объекта – если под него «нет места» – то он тупо не создаётся.
Из чего следует, что мы, в принципе, вполне можем взять себе несколько штучек… (учитывая что в оригинале там сотни!)
Каждый объект даёт нам +88 байт на строки или ещё что-либо. Например, потом надо попробовать вытащить в «последний объект» те строки, что предназначены для меню Help.
Того гляди, и в EXE даже не придётся ничего писать.

Конечно, нельзя забирать слишком много объектов. Знаете, что будет, если места не хватит на Спаркса!?
…да ничего страшного. Просто Спаркс не появится, и Спайро останется с одной жизнью. Ну, я к тому, что мы не можем знать точно, сколько пустого буфера под объекты реально необходимо уровню. Пожалуй, следует написать программу, высчитывающую количество живых объектов в реальном времени, тем более что я по-моему даже знаю, где у них там бит alive…

А вот преимущественно для актёров: (текст вложен в архив)


http://klimaleksus.narod.ru/Files/MinEpsxe.zip (1 Мб)

Минимальная сборка эмулятора Epsxe 1.7.2.

Установка:
1) Распакуйте архив куда-нибудь на жёсткий диск. (Для будущей стабильности убедитесь, что в пути нет всяких специальных символов.)
2) Запустите «install_settings.reg» и подтвердите изменение реестра. (Если не получается, то попробуйте открыть командную строку cmd.exe и написать туда «reg import [пробел]» и перетащить этот файл в консоль, выполнить).

Настройка:
1) Запустить «ePSXe.exe»
2) Выбрать пункт меню «Config > Game Pad > Port1 > Pad1». Здесь можно переназначить кнопки управления.
3) В пункте меню «Config > Video» можно выбрать плагин DirextX или OpenGL. Нажатие Configure – расширенные настройки плагина, самое важное – разрешение экрана вверху. Также есть Soft-плагин, настраиваемый кнопкой ниже. (Если ни один из предыдущих двух плагинов почему-то не работает, попробуйте переименовать «gpu.dat» в «gpu.dll» в папке «plugins\», и потом найдите Soft-плагин в верхнем списке.)

Запуск:
1) Пункт меню «File > Run ISO».
2) Выбрать нужный .iso или .bin файл.
3) Для паузы нажмите Esc. (Для продолжения – пункт «Run > Continue»). Чтобы изменить настройки, эмулятор придётся перезапустить.

Управление эмулятором:
1) Клавиша F1 – сохранение текущего состояния в активный слот. Изначально активен слот номер 1 (имена файлов .000).
2) Клавиша F2 – изменение активного слота с 1 по 5 и по кругу. Картинка предпросмотра будет показываться в верхнем правом углу экрана.
3) Клавиша F3 – загрузка состояния из активного слота. Эмулятор хранит отдельные пять слотов на каждую игру (они привязываются не к файлу-образу, а как бы к самой игре).
4) Клавиша F4 – включение и отключение ускоренного воспроизведения игры, соответствующая иконка отображается справа.
5) Клавиша F7 – переключение на Soft плагини обратно. В настройках по умолчанию, D3D и GL плагины развёрнуты на весь экран, а Soft работает в окне, поэтому F7 эффективно переводит игру в оконный режим; тем не менее, возврат в главное окно всё равно через Escape.
6) Клавиша F8 – снять скриншот экрана. Снимки будут копиться в папке «snap\».
7) По умолчанию графические опции настроены на цифры 1-6. Клавиша 1 активирует панель управления плагином (строка сверху), 2 – включает подсказки. Далее цифры 5-6 меняют текущий активный пункт, а 3-4 – включают или выключают его. Например, первый же пункт управляет ускорением и замедлением игры.
8) Другие клавиши Fx, и цифры 7,8,9,0 – лучше не нажимать.

Контроллер первого игрока по умолчанию: (изменяется в меню)
1) Стрелки вверх-вниз-вправо-влево – стрелки на клавиатуре;
2) Крест – RCtrl, Круг – Num0, Квадрат – RShift, Треугольник – End;
3) Старт – Space, Селект – LCtrl.
4) L1 – Delete, R1 – PageDown, L2 – Insert, R2 – PageUp.

Основные действия кнопок в игре Spyro2/3:
1) Крест – прыжок. Крест в прыжке – полёт.
2) Круг – атака огнём или снарядом.
3) Квадрат – бег и атака рогами, также под водой.
4) Треугольник – зажать на земле – осмотреться/прицелиться; в прыжке – вертикальный удар вниз; в полёте – взмах вверх с приземлением.
5) Старт – пауза, Селект – сразу атлас.
6) L2, R2 – вращение камеры; L1/R1 – центрирование камеры.
7) Техника дальних перелётов: квадрат для разгона; на самом краю – с квадрата удерживать крест и кнопку вперёд, отпустить квадрат; в верхней точке прыжка – быстро отпустить и зажать крест ещё раз, уже можно просто рулить; перед приземлением – в конце держать вперёд и нажать треугольник в самый точный момент, не слишком рано, но и не вплотную к целевой площадке.
8) Большие враги убиваются кнопкой круг, маленькие – кругом или квадратом, металлические – только квадратом; Иногда нужно ударить сверху треугольником.
9) Текущее здоровье показывает стрекоза: жёлтый цвет – 3 жизни, синий – 2, зелёный – 1, отсутствие стрекозы – 0. Здоровье пополняется при уничтожении мелких животных, из которых вылетают бабочки.


but nobody came
 
aleksusklimСообщение # 674 | Тема: Перевод игр о Спайро – графика + общие вопросы Понедельник, 31.10.2016, 22:14
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Вставил лого!

Английское, просто так:
http://klimaleksus.narod.ru/Files/GH/newlogo_eng.png

Русское исходное:
http://klimaleksus.narod.ru/Files/GH/newlogo_rus.png

Оригинал из игры:
http://klimaleksus.narod.ru/Files/GH/newlogo_orig.bmp

Русское приведённое к размеру: (через PaintToolSAI)
http://klimaleksus.narod.ru/Files/GH/newlogo_crop.png

Преобразование к палитре через MSPaint, плохо:
http://klimaleksus.narod.ru/Files/GH/newlogo_sys.bmp

Преобразование к «адоптивной» палитре с помощью Corel Photo Paint:
http://klimaleksus.narod.ru/Files/GH/newlogo_adopt.bmp

Преобразование к «оптимизированной» палитре без целевого цвета, тоже в Corel Photo Paint:
http://klimaleksus.narod.ru/Files/GH/newlogo_optim.bmp

Их сравнение в увеличении. Какой больше нравится?
http://klimaleksus.narod.ru/Files/GH/newlogo_diff.png

Я взял менее зернистый второй вариант. Скриншот:
http://klimaleksus.narod.ru/Files/GH/newlogo_render.jpg

Как оно в памяти:
http://klimaleksus.narod.ru/Files/GH/newlogo_vram.png

Изменённый 7-ой субфайл:
http://klimaleksus.narod.ru/Files/GH/newlogo_wad.zip

P.S.
…чёрт побери, вставилось же нереально чётко.
Если что, вот как выглядит настоящее:
http://klimaleksus.narod.ru/Files/GH/newlogo_shot.jpg


but nobody came

Сообщение отредактировал aleksusklim - Понедельник, 31.10.2016, 22:20
 
aleksusklimСообщение # 675 | Тема: Znaczky Четверг, 03.11.2016, 22:58
Аватар aleksusklim
фдулыгылдшь
Редактор
«1066»
Где: Не в городе Драконов
Znaczek #7:






– Опять овцы на трассе!?

Хантер от испуга выронил охотничий лук и обернулся.

– Спайро? О, ты тут! Зацени.

Он поднял оружие и вставил в него одну из стрел.

– Видишь наконечник? Это Профессор придумал. Там магнитная пыль заряженных камней Харрикоса, и порох с фабрики фейерверков. Я уже пробовал! Напрочь ломает их нейтронную турбину и систему навигации.

– И-и?..

– Тихо, одна летит…

Вдали показалось НЛО, стремительно приближающееся к напарникам. Хантер пригнулся, пробежал вперёд, споткнулся, ещё раз поднял лук с земли, и затаился возле куста.

Дракон продолжал стоять и смотреть на выражение лица а-ля «не пали». Когда тарелка пролетела над ними, Хантер вышел из укрытия, натянул тетиву и выстрелил.

Он промахнулся. Однако стрела, пролетев через кольца, оставляемые двигателем летающей тарелки, внезапно взорвалась. В воздухе возник разноцветный салют, а машина потеряла управление.

Дымящееся НЛО накренилось к земле, его крыша отскочила, а оттуда выпрыгнула белая овца. Вскоре она раскрыла парашют, и плавно опустилась к земле. Однако ветер подул в правильную сторону.

– Яйцо!!

Хантер направил лук со второй стрелой прямо на неё.

– Бе-е-е!

Вдалеке послышался звук от разбившегося летательного аппарата.

– Там было яйцо!?

– Бе-е-е!!

Хантер приблизился к ней в упор, замер на секунду, а потом грустно опустил оружие.

– Ладно, пошла вон.

Спайро моргнул от удивления. Глядь – овечки уже нет.

– И почему ты её отпустил?

– Пустая. Будь у неё яйцо, под ТАКИМ не соврала бы!

Гепард нацелился на нос дракона. Спаркс прожужжал что-то невнятное, а Спайро просто обошёл вокруг. Затем посмотрел в небо на исчезающий след.

– Ну а если бы яйцо там было?

– Поэтому мне и нужен ты! Я буду сбивать тарелки, а ты – спасать из обломков драконьи яйца. Вон ещё трое, готовься!

На горизонте появился штурмовой овечий отряд. Их предводитель летел на тарелке, у которой снизу был шлюз для захвата объектов.

Когда Хантер зарядил очередную стрелу, овцы изменили построение и совершили перекрёстный маневр. Спаркс хотел было прожужжать «Сложность: *****», но Спайро уже помчался вперёд.

Вскоре одна тарелка была подбита.

– Вали главного!

Спайро побежал в направлении чёрного следа, а Хантер по его совету – совершил перебежку на открытую местность, потому что вражеский отряд, видимо, решил отступить.

Когда дракон добрался до рухнувшего НЛО, пилота уже не было. Однако, там действительно лежало драконье яйцо! Он вытащил его и побежал прятать.

Раздался грохот. Овечий командир был подбит, а его напарник – благополучно покинул зону досягаемости стрел. Спайро побежал ко второму потенциальному яйцу.

Там уже стоял Хантер, открывший кабину летающей тарелки. Внутри лежало… яйцо?

– Это… а что с ним?

Объект был размером с драконье яйцо, но странной крапчатой окраски. И был словно весь в перьях. Хантер наклонился и принюхался.

– Может, палкой в него потыкать…

Оно шевельнулось! Спаркс облетел его кругом в негодовании.

– Зоя! Ты тута? Зоя, появись-ка на секунду!..

Спайро искал взглядом полупрозрачную звезду.

– Так это существо!

Фея оказалась позади дракона. Она взмахнула палочкой, и наградила субъект магическим зарядом. Зверюшка приподнялась и открыла два больших глаза. Спайро вдруг осенило.

– Да это же со…

– г.д.е.?

Она пошла на контакт. Хантер решил ответить.

– Ну, эту трассу Спаркс частенько зовёт…

– г.о.д.?

Зоя удивилась.

– Год? Так две тысячи…

– о.х..

Она склонилась, но вскоре встала во весь рост.

– А ты тут, потому что…

– о.в.ц.ы.

Хантер перевёл взгляд на небо.

– Кстати, о них.

– в.п.е.р.ё.д.

Она взмахнула крыльями и вылетела из тарелки. Спайро вопросительно посмотрел на Хантера, а тот приготовил свой лук.

– н.у.?

– В смысле, стрелять? И правда, ну…

Стрела пролетела очень удачно, попав в самый центр построения пяти НЛО. Взрыв поразил несколько из них, и вот небо окрасилось в чёрные полосы, дымовые кольца и катапультирующихся овец.

– с.к.о.р.е.й.!

– Да, но мы собираем…

– я.й.ц.а.

Дракон остановился на секунду, потом кивнул и побежал к ближайшей упавшей овце. Пусто.

– с.ю.д.а.!

Хантер видел, что она вспорхнула наверх, откуда хорошо видны места падения тарелок.

– А ведь неплохо придумано!

Тем более, что он уже успел подбить их все.

Поднимая последнее яйцо, Спайро осторожно задал вопрос.

– Так, ты теперь…

– д.а.

– О, хорошо, просто… Просто у нас есть на примете ещё где…

– и.д.ё.м.

Спаркс даже стал лететь ближе к ней, чем к дракону. Хантер раскрыл рот, что бы что-то сказать, но вовремя понял, что не сможет выразить свою мысль достаточно кратко. Он шёл молча всю дорогу, и смотрел на блестящие наконечники своих стрел.

– Хм. Придётся привыкнуть.

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


but nobody came

Сообщение отредактировал aleksusklim - Понедельник, 07.11.2016, 18:02
 
Поиск:

Кто нас сегодня посетил

Для добавления необходима авторизация