LINUX.ORG.RU

Написание свободной(Free as in Freedom) книги-самоучителя по программированию: планы, цели, задачи

 , , ,


17

9

Итак, я решил написать(или как вариант, собрать из кусочков) книгу-самоучилель по программированию, в которой бы не было глупых и нелепых ограничений на распространение. Однако копилефт я все же считаю приемлемым в данном случае. Общественным достоянием это не будет т.к. вполне могут найтись желающие использовать результат в своих проприетарных книгах, а проприетарные книги — плохо. Лицензия самого текста книги-учебника будет или Creative Commons Attribution-ShareAlike (что позволит без каких-либо проблем переиспользовать текст из википедии) или что-то вроде GNU Free Documentation License (без неизменяемых разделов естественно).

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

Теперь к теме того, на кого книга ориентирована, какие начальные знания предполагаются, чему книга будет учить, какой первый ЯП взять и каков будет авторский самысел: С этим моментом я пока что не определился окончательно, и тут есть что обсудить. В частности, я не вижу особого смысла объяснять какие-то базовые понятия комбинаторики, об этом можно доступным языком прочитать из школьных учебников. Системы счисления(СС), перевод из одной СС в другую - вот это еще можно. One's и two's complement представления знаковых чисел — про это тоже можно написать. Если же человек не понимает комбинаторику, он ее быстро поймет на примере кода, который будет достаточно наглядно это показывать, и который всенепременно будет.
Пока что в качестве первого языка я склоняюсь к Си, и тому есть причины. Все прочие распространенные языки (кроме ассемблера, хотя его трудно назвать распространенным) не настолько близки к аппаратному уровню. Про нужность понимания на низком уровне написано тут http://russian.joelonsoftware.com/Articles/BacktoBasics.html https://habrahabr.ru/company/piter/blog/271347/ , не вижу смысла повторяться. Приведу лишь цитату:

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

Притом еще один важный момент: Си будет изучаться параллельно с ассемблером. Если речь идет об изучении ассемблера, необходимо четко зафиксировать то, на какой архитектуре это все происходит и в какой ОС. Так вот, ОС будет GNU/Linux а архитектура x86-64. Будут постоянно проводиться параллели между тем, что из себя представляет код на Си в текстовом виде, и тем, в какой текст на ассемблере его превращает компилятор. В связи с этим, первым делом будет рассказано о goto и конструкции if(условие) goto метка;. Про конструкции вида

if(условие)
{
  что-то_делаем;
}
else
{
  что-то_другое_делаем;
}
Будет рассказано немного позже, притом это будет рассказано и словами, и через написание эквивалентного кода через if(условие) goto метка;. Циклы, for(){} while{}, do{}while(), конструкция switch-case и break continue внутри них будут так же объясняться через все тот же if(условие) goto метка; притом будет делаться явный акцент на том, что намного лучше использовать нормальные циклы, чем лепить всюду этот условный goto. Кроме того, будет так же рассказано про Labels as Values. Почему так важна эта странная штука, if(условие) goto метка;? Потому что она имеет наипрямейшее отношение к тому, как работают ЭВМ, а всякие циклы СКРЫВАЮТ это. Рекурсия в Си будет объясняться только после того, как будет объяснено, что такое стекфрейм и соглашения вызова, будет сказано про оптимизацию хвостовой рекурсии, и о проблеме забивания стека, если такая оптимизация не происходит, притом это будет наглядно показано в ассемблере. Учиться отлаживать код надо будет тоже «с пеленок», притом отлаживать и ассемблер, и всякие там Си. Будет и про асм-вставки в Си, clobber list. В качестве ассемблера будет рассматриваться GAS, а никакой не NASM т.к. GCC умеет выплевывать ассемблер именно в GAS синтаксисе. Насчет выбора Intel или AT&T синтаксиса - тут я склонюсь пожалуй к тому, что надо ЗНАТЬ И УМЕТЬ ПОНИМАТЬ ОБА. Кроме того, GAS давно уже умеет в оба синтаксиса, так что проблем с этим не будет. Единственная проблема с GAS в том, что это однопроходной ассемблер, так что можно освоить и какой-нибудь NASM, YASM.

Первые хеллоуворды будут написаны вообще в особом стиле, без использования printf() и вообще без библиотеки Си; Будут использованы куски на ассемблере, которые делают системный вызов write и read, и с ними можно(нужно) будет линковаться, чтоб что-то вывести на экран. Будет рассказано и про printf естественно, но только когда будет совершенно четко ясно, что такое вообще va_list. Будет куча отсылок к драфту стандарта Си (недрафт почему-то платный). Будет так же рассказано про устройство ОС. В конце скорее всего будет дано задание сделать свою игрушечную ОС так что предполагается что человек к тому моменту должен уже отлично понимать всякие там связные списки, графы, очереди, спинлоки-аллокаторы свои уметь делать на асме при желании. Алгоритмы сортировки, обхода графов, хеш-таблицы, все это будет объяснено на языке Си, и плюсов вообще касаться я не буду.

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

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

Как-то уж слишком дофига, не находите? Может быть не надо так глубоко во все это нырять? Жду предложений и критики по поводу того, что нужно, а чего не нужно писать. Возможно что я слишком много хочу.

cast ASM be_nt_all mister_VA

UPD: Программирование и отладка на C/ASM - Первые программы. Знакомство с C и ассемблером. Компиляция, линковка, код возврата. Вывод текста.

★★★★★

Последнее исправление: CYB3R (всего исправлений: 6)
Ответ на: комментарий от ASM

Один inline тебе не 100% гарантирует что функция будет встроена. https://en.wikipedia.org/wiki/Inline_function

Firstly, it serves as a compiler directive that suggests (but does not require) that the compiler substitute the body of the function inline by performing inline expansion

SZT ★★★★★
() автор топика
Ответ на: комментарий от ASM

Да я вижу. Зря время тратите, имхо.

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

SZT ★★★★★
() автор топика
Ответ на: комментарий от SZT

Ну мне было вполне познавательно.

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

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

Не знал про radare2, действительно полезная штука..... Но книга уже есть на 200 страниц: https://www.gitbook.com/book/radare/radare2book

ASM ★★
()
Ответ на: комментарий от ASM

Я не могу уже редактировать свою тему, так что надо об этом модераторов просить.

Ссылка на эту книгу про radare2 у меня в тексте есть, если что.

SZT ★★★★★
() автор топика
Ответ на: комментарий от SZT

Нашёл таки ссылку, пробежался по тексту, получается ничего так. Имхо, по WTFPL — это детский сад. А ещё есть опечатка: поновеесм

Ну и позанудствую (Вашу позицию знаю, отвечать не обязательно).

user@localhost:~/learn/c/01_hello/puts_hello/0.1$ cd ..
user@localhost:~/learn/c/01_hello/puts_hello$ cp -r 0.1 0.2
user@localhost:~/learn/c/01_hello/puts_hello$ cd 0.2/
user@localhost:~/learn/c/01_hello/puts_hello/0.2$

хуже чем

user@localhost:~/learn/c/01_hello/puts_hello/$ git tag 0.1
ASM ★★
()
Ответ на: комментарий от ASM

Ну во-первых с чего ты взял, что это какие-то толковые ребята - это ламерки криволапые. Кроме огрызка с89 ничего и не осилилось.

Хотя я посмотрел:

#ifdef __cplusplus
extern "C" {

Яснопонятно. Про с89 я уже рассказывал.

registrant27492
()
Ответ на: комментарий от SZT

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

compiler directive

Не является. Но ламеркам это знать не надо.

Хотя там есть намёки:

C++, C99, and GNU C each have support for inline functions.

The specification of inline in C99 requires exactly one additional external definition of a function in another compilation unit, when the corresponding inline definition, that can occur multiple times in different compilation units, if that function is used somewhere. That can easily lead to linker errors because such a definition wasn't provided by the programmer. For this reason, inline in C99 often is used together with static, which gives the function internal linkage.

registrant27492
()
Ответ на: комментарий от registrant27492

Слово directive переводится как «указание», и понимать это надо как как «Во-первых это служит указанием компилятору компилятору...»

лучше сходи на говнокод, там по тебе уже соскучились http://govnokod.ru/19987#comment326851

SZT ★★★★★
() автор топика
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от SZT

Слово directive переводится как «указание», и понимать это надо как как «Во-первых это служит указанием компилятору компилятору...»

Это не служит «указанием компилятору», ламерок. Это function specifier и его поведение никак от компелятора не зависит, но ламерку это знать не нужно.

лучше сходи на говнокод, там по тебе уже соскучились

Что мне там делать? Сраться с ламерками? Мне это не интересно.

registrant27492
()

Научите пользоваться «Labels as Values». Какая может быть задача, которую нельзя написать через switch(){} ?

И в gcc метки видны только внутри функции, а хочется перетасовывать последовательность переходов снаружи.

anonymous
()

Наткнулся на книгу о WEB, назыается Agile Web Development with Rails.

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

С первых строк кода идёт тестирование кода и постоянно указывается, что порабы всё сохранить в git....

Изложение построено по Вашей концепции, объясняем минимум чтобы получить результат, а всё остальное ссылками на сторонние сайты и литературу.

ASM ★★
()
Ответ на: комментарий от SZT

лучше сходи на говнокод, там по тебе уже соскучились

Лол. Царь ходит по провинциальным помойкам и «обоссовывает» кодер-работяг. Тупее занятия не найти.

anonymous
()
Ответ на: комментарий от SZT

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

да, про radare2 с отладчиком, и главное — декомпилятором radeco было бы весьма годно, реквестирую

есть вдохновляющие статейки про крякмисы на radare2 с патченьем шеллкодов вручную, почти рилтайм компо

также radare2 через пайпы с безжалостным скриптованием всего и вся выглядит очень интересно

например, до чего техника дошла

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

всякие детские отмазки типа «вот D/rust/go/лисп/борщехаскель был бы отличный недоязычок, кабы у него был встроенный отладчик/IDE/перделки и свистелки/лестплейи ютубовские» — уже нонче не катят:

отладчик должен быть отладчиком (gdb server), ассемблер ассемблером, а unix это IDE через пайпы

ну или накрутить свой IDE в стиле Plan9 acme/sam/willy или brief/grief или Emacs + org-mode + Literate Programming через org-mode babel.

«programming by poking», интерактивно в духе лисперов

кстати, вот тебе ещё идея: писать книжку сразу в org-mode babel, через «блоки кода» связывать примеры и упражнения, и кодогенерировать емаксом блоки кода из других блоков кода и «блоков данных» через командную строку с тем же radare2/radeco/gcc

презентация в тему, повтыкай там именно над этим слайдом

если Literate Programming/ org-mode не очень знаком, см презентацию сначала и например ссылки neilsen Eric Schulte см. pdf про org и на гитхабе, например

плюсы Emacs org-mode babel кроме того в том, что export в HTML/PDF/latex/WTFормат делаются элементарно в полпинка.

также все примеры извлекаются/компилируются/выполняются_тесты простым M-x org-babel-tangle + make all/make test/make pdf (правда Makefile нужно самому написать :-))

в общем, вполне технологично получается книжки писать в org-mode babel.

с примерами про radare2 я бы почитал, было бы весьма годно.

а так да: удачи с книжкой.

anonymous
()
Ответ на: комментарий от registrant27492

А нахрена нужен лисп?

1. для кодогенерации всяческих DSL. допустим, тебе лень писать полноценный компилятор 10500 раз, и лень пилить нормальный парсер типа ANTLR-ского с синтаксическими/семантическими предикатами, и потом из него генерить парсер на той же сишке. ну или брать хаскель и парсер комбинаторы и опять пилить парсер.

то можно повторно использовать уже готовый компилятор лиспа, и компиляцию в лисп.

здесь особенно отличилась схема вообще и racket в частности — проверку корректности таких DSL делать довольно просто.

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

см. про лайвкодинг, «разработку в REPL», «programming by poking», SLIME и т.п.

например, den73 использует общелисп для кодогенерации SQL из своего DSL и пишет хранимые процедуры на лиспе; активно использует лисп для миграции данных на новую версию схемы данных.

rigidus по ссылке выше активно использует примерно для того же + DSL в org-mode.

3. см. про Emacs org-mode babel и Literate Programming выше. см. про GNU Skribilo — как LaTeX, только на лиспе (схеме Guile). в Racket похожая система Skribe.

4. см. про AutoLISP: BricsCAD + OpenLISP (это реализация ISLISP, а не CL). макросами для ISLISP написана поддержка AutoLISP, реализация быстрее раз в 10.

опять же в контексте 3, здесь деталь — это модель на лиспе. код это данные, данные это код.

параметрическое Literate Programming моделирование.

5. см. презентации Naughty Dog про DSL в геймдеве и тот же GOAL: 1. + 2.

6. опять же, STEP EXPRESS + лисп, например.

в общем, лисп это параметрическое моделирование и кодогенерация с ad-hoc DSL + уже готовый, годный кодогенератор = легко расширяемая инкрементально, «живая» система.

anonymous
()
Ответ на: комментарий от anonymous

Больше книг, хороших и разных.

EXL ★★★★★
()
Ответ на: комментарий от anonymous

Научите пользоваться «Labels as Values». Какая может быть задача, которую нельзя написать через switch(){} ?

напиши интерпретатор. без switch быстрее.

anonymous
()
Ответ на: комментарий от anonymous

Научите пользоваться «Labels as Values». Какая может быть задача, которую нельзя написать через switch(){} ?

напиши интерпретатор. без switch быстрее работае

anonymous
()
Ответ на: комментарий от anonymous

Какая-то неведомая херня. Как связан лисп и кодоген? Как связан лисп и дсл? Как связан лисп с парсерами и его генерацией?

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

Это умеет любая скриптуха.

в общем, лисп это параметрическое моделирование и кодогенерация с ad-hoc DSL + уже готовый, годный кодогенератор = легко расширяемая инкрементально, «живая» система.

Какое-то заклинание.

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

Кодоген, парсер - ну дак где всё это? Где сравнения вида «вот у нас лисп, а вот не лисп»? Либо опять будет какая-то недолиба, которую опять обзовут лиспом? Ну хотя-бы недолибу покажи.

Зачем ты мне ретранслируешь заклинания?

registrant27492
()
Ответ на: комментарий от anonymous

Куда столько умных слов птушнику? Он даже английский не знает.

anonymous
()
Ответ на: комментарий от anonymous

напиши интерпретатор. без switch быстрее работае

Типичный интерпретатор: 1)«получить ввод» -> 2)«действие, зависящее от состояния» - 3)«переход на 1». Это четко ложится на switch.

{
    while(!EOF){
        inp=get_next();
        switch(state){
            case XXX: f(inp); break;
            //...
        }
    }
}
Переходы, написанные через «Labels as Values» будут такие-же. Где выигрыш ?

Или м.б. другой вопрос: Для каких грамматик есть выигрыш ?

anonymous
()
Ответ на: комментарий от anonymous

То, что сказал anonymous про Лисп это очень интересно. Недавно anonymous выложил Let over Lamda, там тоже интересные идеи приводятся. Эту темку хорошо бы развить.

ProtoH
()
Ответ на: комментарий от anonymous

Ты чего курил? На твоих бреднях парсер ломается.

anonymous
()
Ответ на: комментарий от ProtoH

Эту темку хорошо бы развить.

тыкалки, итить. «programming by poking»:

According to Sussman, his students spend most of their time reading manuals for these libraries to figure out how to stitch them together to get a job done. He said that programming today is “More like science. You grab this piece of library and you poke at it. You write programs that poke it and see what it does. And you say, ‘Can I tweak it to do the thing I want?'”. The “analysis-by-synthesis” view of SICP — where you build a larger system out of smaller, simple parts — became irrelevant. Nowadays, we do programming by poking.

anonymous
()
Ответ на: комментарий от anonymous

Перевёл книгу «Let Over Lambda» Дага Хойта.

Археолог перевёл книгу странных ритуалов и заклинаний:

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

«Книга начинается длинным рядом витиеватых молитв, которые далее заменяются рисунками и заклинаниями, — пишет доктор Чот в своей книге, названной „Коптский справочник по сверхъестественной ритуальной силе“ (A Coptic Handbook of Ritual Power).

anonymous
()
Ответ на: комментарий от anonymous

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

ProtoH
()
Ответ на: комментарий от qulinxao

Этот перевод дерьмо! Пол-царства отдам за хорошего переводчика!

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

anonymous
()

Пацаны пацаньчики! Отставить пиздёжь! А теперь все сели писать умную книжку!

anonymous
()
Ответ на: комментарий от anonymous

ээээ своими словами переведи:

My second remark is that our intellectual powers are rather geared to master static relations and that our powers to visualize process evolving in time are relatively poorly developed.

For that reason we should do (as wise programmers aware of our limitations) our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible/

qulinxao ★★☆
()
Ответ на: комментарий от anonymous

также radare2 через пайпы с безжалостным скриптованием всего и вся выглядит очень интересно

например, до чего техника дошла

С esil я пока особо не работал, да и не совсем представляю, как он будет вести себя, когда дело дойдет до самомодифицирующегося кода и JIT. Может быть XVilka (автор этой статьи на xakep.ru) потом поможет, если я решу эту тему разбирать. Пока что из radare2 я использую только отладчик. Я запланировал разобрать ситуации с переполнениями буфера, return-oriented programming (ROP) и прочие такие вещи, но это только когда будет уверенное понимание Си и ассемблера.

Из дополнительных материалов я нашел например вот это http://course.secsem.ru/lections (https://www.youtube.com/watch?v=4lf2GnwrMTI - тут разбираются некие базовые вещи)

И еще вот http://ocw.cs.pub.ro/courses/cns
Там используются лицензия CC BY-SA 3.0 а в лорвики 4.0 но это не проблема т.к. более раннюю можно перевести в более позднюю версию https://creativecommons.org/licenses/by-sa/3.0/legalcode 4.b:

You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License;


отладчик должен быть отладчиком (gdb server), ассемблер ассемблером, а unix это IDE через пайпы

Для отладки ассемблера(и в общем случае программ без исходных кодов) GDB подходит плохо. Когда надо будет отлаживать Си код, я конечно буду рассказывать про GDB и как им пользоваться.

SZT ★★★★★
() автор топика
Последнее исправление: SZT (всего исправлений: 2)
Ответ на: комментарий от ASM

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

У меня будет не одно реальное рабочее приложение, а куча мелких учебных примеров, в т.ч. я думаю показать разбор всяких там crackme

SZT ★★★★★
() автор топика
Ответ на: комментарий от SZT

А сейчас воспользуемся отладчиком, идущим с radare2

А зачем отладчик? Для GNU assembler у отладчик не нужен. Все должны глазами проверять код.

anonymous
()
Ответ на: комментарий от anonymous

начинается как говно

Помоги пацанам.

anonymous
()

Краткий пересказ девяти страниц

Пацаны! Короче дело было так. Столяров написал книжку «Погромирование заведение в профессию». Харьковскому хлопчику SZT стало завидно. И он покритиковав Столярова запилил свой проект.

Но не тут-то было теперь уже пользователю registrant27492 стало завидно — «А чё вся слава SZT достанется что-ли?» И начал registrant27492 беспощадно критиковать SZT. И тут на защиту SZT встал товарищ по имени ASM. И начался мощнейший срач. Пока мужду спорщиками счёт 0:0.

А кстати, гарный москальский хлопчик ASM уже отличился своим критиканством в странице Столярова.

Да здравствует зависть! Толкающая колесо эволюции.

anonymous
()
Ответ на: Краткий пересказ девяти страниц от anonymous

Да здравствует зависть! Толкающая колесо эволюции.

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

Прекращай. И не пиши больше никогда.

ASM ★★
()
Ответ на: комментарий от anonymous

Ну да, ну да, Мастер так завидовал Бездомному!

То что Вы называете анонимуса мастером, только подтверждает, что Вы забыли залогинится. А SZT, между прочим, вполне не плохо пишет, так что я не стал бы называть его бездомным.

ASM ★★
()

the_electric_hand добавь возможность грузить svg на lorwiki.ru если не сложно. Хочу https://en.wikipedia.org/wiki/X86#/media/File:Table_of_x86_Registers_svg.svg добавить, с переводом и возможно некоторыми дополнительными пояснениями.

И кого тут из модераторов принято кастовать по таким вопросам? beastie можешь ссылку https://goo.gl/K4VxYr добавить в текст в самое первое сообщение, чтобы ее не приходилось искать по всему треду?

SZT ★★★★★
() автор топика
Ответ на: комментарий от beastie

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

SZT ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.