All streams
Search
Write a publication
Pull to refresh
230
200.4
Андрей Дмитриев @AndreyDmitriev

Пользователь

Send message

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

Спасибо. Да, я когда-то давно дизассемблировал код, сгенерённый из LabVIEW (чтобы понять помечу он медленный) и там в общем всё понятно. Гидру я использую, но не как отладчик, а как дизассемблер, она может сгенерить эквивалентный Си код, в котором проще разобраться (как Ida Pro примерно). А по интерфейсу Ида мне больше нравится. По работе я использую х64dbg и реже WinDbg и в основном для того, чтобы разобраться в причинах падения LabVIEW программы в рантайме, когда выбрасывается исключение, то я ловлю его в отладчик, ну а дальше по обстоятельствам. Ну или для понимая внутренних структур, например там Variant довольно любопытен. Ещё я Раст сейчас изучаю, интересно бывает дизассемблировать его выхлоп, чтобы посмотреть, во что код компиляется (чисто с точки зрения эфективности кодогенерации). Сейчас дописываю любопытную статью о замерах производительности кода несколько нетрадиционным способом, может на следующей неделе опубликую.

Эх, я олькой сто лет не пользовался, а раньше было дело. А что такого есть в олли, чего нет в x64dbg? Пару раз меня этод дебаггер подводил, но я на windbg переходил.

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

А мне Евро ассемблер очень зашёл для небольших набросков, либо микробенчмаркинга.

Вот пример эхо, взвращающего тот же текст, и да, юникод:

EUROASM AutoSegment=Yes, CPU=X64, Unicode=Yes
habr PROGRAM Format=PE, Width=64, Model=Flat, ListMap=Yes, IconFile=, Entry=Start:

INCLUDE winscon.htm, winabi.htm, cpuext64.htm

Msg1 D "Введите текст:",0
Msg2 D "Ваш текст: ",0
Buffer DB 80 * B
    
Start: nop
	StdOutput Msg1, Console=Yes
	StdInput Buffer, Console=Yes
	StdOutput Msg2, Buffer, Console=Yes
	TerminateProgram
ENDPROGRAM habr

Это надо скопировать в habr.asm

Ассемблируется

euroasm.exe habr.asm

И в общем работает

>habr.exe
Введите текст:Prüfung Это мой текст
Ваш текст: Prüfung Это мой текст

Вот пример факториала из соседнего топика:

EUROASM AutoSegment=Yes, CPU=X64
fact PROGRAM Format=PE, Width=64, Model=Flat, ListMap=Yes, IconFile=, Entry=Start:

INCLUDE winscon.htm, winabi.htm, cpuext64.htm

Msg1 D "Enter Number:",0
Msg2 D "Factorial is ",0
Buffer DB 80 * B
    
Start: nop
	StdOutput Msg1, Console=Yes
	StdInput Buffer ; Input Number
	LodD Buffer ; https://euroassembler.eu/maclib/cpuext64.htm#LodD (rax <- Num)

	mov rbx, 1        ; Initialize result to 1
.loop:
	imul rbx, rax     ; Multiply rbx by rax
	dec rax           ; Decrement rax
	cmp rax, 1        ; Check if rax <= 1
	jg .loop          ; If rax > 1, repeat loop
	mov rax, rbx      ; Move result to rax

	StoD Buffer ; https://euroassembler.eu/maclib/cpuext64.htm#StoD (from rax)
	StdOutput Msg2, Buffer, Console=Yes
	TerminateProgram

ENDPROGRAM fact

Сборка и выполнение

>euroasm.exe fact.asm
>fact.exe
Enter Number:6
Factorial is 720

Ну и так далее. В AVX-512 умеет, можно DLL собирать. Портабелен, без зависимостей, линковщик не нужен, написан на себе самом.

Мне бы хотелось немного продолжить, если позволите и с фотографиями

...в 1988 году Жорес Иванович Алфёров организовал в тогда ещё Политехническом институте физико-технический факультет.

Надо сказать, что Физтех и Политех находятся в Питере рядышком, напротив друг друга, через дорогу, и в общем было логичным решением основать факультет "под себя", кузницу кадров так сказать. Я имел честь учиться в самом первом потоке. В рамках этого потока из восьмидесяти студентов было организовано четыре кафедры, на каждую набрали по двадцать человек. Это "Микроэлектроника и полупроводниковые приборы", "Физика плазмы", "Физика твёрдого тела" и "Космофизика". Тех кто учился на физике плазмы и астрофизике называли "плазматики" и "косматики". Косматикам я завидовал — они каждое лето ездили на Кавказ, смотреть на звёзды в горных обсерваториях. Я же поступил на "микроэлектронику и полупроводниковые приборы". Надо сказать, что вообще-то я изначально намеревался пойти в ЛЭТИ (мне с детства нравилось паять всякие разные электронные штуки), но когда я увидел это, то понял, что попал, там реально храм науки:

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

image-20250902145915707

И там ещё была роскошная библиотека. Вот тут есть виртуальный тур - https://vt.spbstu.ru/gz/.

Лекции по физике нам читал Вадим Фёдорович Мастеров:

image-20250902150017831

Он славился тем, что мог легко вынести на экзамене весь поток. Сегодня Мастеров бушует - шептались студенты перед экзаменом. Нерадивый студент после нескольких доп вопросов (с которых собственно и начинался экзамен, а ответ на билет был затравкой) покидал аудиторию с громогласным воплем Вадима Фёдоровича "молодой человек! Вы Физик или дворник?! Вон отсюда!", а вслед ему в открытую дверь летела зачётка. Я сам был в числе таких, когда не смог назубок назвать четыре фундаментальных взаимодействия. Но потом все пару недель грызли гранит науки, и четвёрка" с улыбкой Мастерова была лучшим подарком.

Вообще все преподаватели любили своё дело, у меня вообще нет никаких претензий к качеству преподавания. С одной стороны банальное "вы много чего потом забудете, мы учим вас, чтобы вы научились учиться", но высшая математика, матан и прочее были реально сложными. Но мы учились, и вылетело, кстати, очень немного, в основном все более-менее прилежно занимались. Мне было особенно тяжело, так как большая часть поступила из физмат школ, типа 239-й или 30-й., а я из обычной средней, и чтобы поступить туда, я ночами занимался физикой и математикой, неофициальный конкурс был приличный.

Первые два года мы в основном учились в аудиториях политеха, а на втором курсе нам провели экскурсию по Физтеху. Если встать спиной к политеху, то в здании напротив, в левой части внутри находится токамак:

image-20250902151106742

Это выглядело как космос, так что в конце второго курса я набрался смелости и попросил аудиенции с завкафедрой, это был Рубен Павлович Сейсян:

image-20250902151348646

— Понимаете, теория — это, конечно здорово, но я хочу в Физтех, в лабораторию, чтоб куча проводов и установки, и всё такое. " — Похвально", сказал он, что-нибудь придумаем. Через некоторое время он принёс мне временный пропуск и объяснил как пройти в лабораторию Тучкевича, куда я на третьем курсе и попал лаборантом (так-то практика в лабораториях начиналась с четвёртого курса).

А с третьего нам уже читали лекции сотрудники Физтеха. Матфизика запомнилась особенно, её нам читал Эдуард Абрамович Тропп:

image-20250902151842323
i

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

А физику твёрдого тела и полупроводники нам читал Роберт Арнольдович Сурис:

image-20250902161059993

Хорошие, неторопливые лекции, всё по полочкам.

В лаборатории Владимира Максимовича Тучкевича, куда я попал с подачи Сейсяна, занимались низкотемпературной сверхпроводимостью полимерных плёнок:

image-20250902153905027

Академик Тучкевич вообще был легендарной личностью (одно время он заведовал Физтехом). Впрочем направление было немного тупиковое (открытия не случилось), но именно там я увидел первый компьютер - ДВК-3 и сразу полюбил это дело. Программирования, кстати, у нас было два семестра всего - численные методы на Фортране и потом на Паскале, но я делал курсовые в лаборатории и достаточно успешно. Рунге-Кутта до сих пор могу, вероятно набросать и без ИИ. К компьютеру установка была подключена через КАМАК, всё это бодро мигало лампочками, щёлкало релюшками. Первое время я таскал дьюары с жидким гелием, зато потом пришлось вдоволь попаять всякие малошумящие усилители на операционниках, в то время я засыпал вместе с Хоровицем и Хиллом в обнимку. Постепенно я начал делать всяко разно и для других лабораторий, по соседству была оптическая, я как-то для них сделал модуль для шаговых моторов для оптической скамьи, но вышло не очень (у меня руки из одного места), так зав лаб (Василий Бельков) сказал мне - "видишь ли, результат твоего труда должно быть приятно взять в руки и покрутить со всех сторон, полюбоваться, а этому поделию место в мусорке. Я ХЗ чем ты будешь заниматься в будущем, может и не физикой вовсе, но что бы ты не делал, любое дело надо делать с любовью, короче переделывай.". Я запомнил.

Потом я потихоньку перешёл в лабораторию рентгеновской дифрактометрии, где меня угораздило запрограммировать самодельный дифрактометр на базе отечественного (модель уж не помню), но уже на ДВК-4, получилось неожиданно хорошо. Я всё сделал на Си, который сам же и выучил по Кернигану и Ричи. Там жёсткий диск был на пять мегабайт, после дискет это было круто. Изюминкой установки было то, что я использовал ОС RT11-FB, а не SJ, это дало возможность запускать две задачи, одна из которых управляла установкой и снимала кривые, а во второй оператор параллельно с экспериментом мог обсчитывать сохранённые данные. Всё это, на секундочку в 56 килобайтах оперативки. Часть пришлось написать на ассемблере MACRO-11. Результаты и стали моей дипломной работой, а программирование было тогда просто инструментом, а потом жизнь рассудила иначе.

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

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

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

Вполне, Marantz Model M1, к примеру как раз класс D, по отзывам норм. По цене, правда совсем не норм. У меня на кухне Панасоник HiFi аудио система играет, звук был отстой до тех пор, пока я родную бубнящую акустику не выкинул и на Altec Lansing заменил (у них саб сгорел, а сателлиты норм) и всё заиграло очень приятно, и не скажешь что класс D.

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

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

EUROASM AutoSegment=Yes, CPU=X64
benchm PROGRAM Format=PE, Width=64, Model=Flat, ListMap=Yes, IconFile=, Entry=Start:

INCLUDE winscon.htm, winabi.htm, cpuext64.htm

Msg0 D "Two Loops Benchmark",13,10,0
Msg1 D "Single Branch Ticks:  ",0
Msg2 D "; Dual Branch Ticks:  ",0
Buffer DB 80 * B
N DQ 1_000_000_000 ; Amount of Iterations

StartBench %MACRO
	cpuid ; force all previous instructions to complete (rax...rdx reset)
	rdtsc ; read time stamp counter
	mov edi, eax ; save EAX for later
	mov esi, edx ; save EDX for later
%ENDMACRO StartBench

EndBench %MACRO
	cpuid ; wait to complete before RDTSC
	rdtsc ; read time stamp counter again
	sub eax, edi ; subtract the most recent CPU ticks from the original CPU ticks
	sbb edx, esi ; now, subtract with borrow
	shl rax, 32
	shrd rax, rdx, 32 ; ticks are in rax
%ENDMACRO EndBench
    
Start: nop
	StdOutput Msg0, Console=Yes

; ======== Single Branch Test ======== 
	StartBench 
	mov rbx, 1        ; Initialize result to 1
	mov rax, [N]	  ; Amount of interations
.loop1:
	imul rbx, rax     ; Multiply rbx by rax
	dec rax           ; Decrement rax
	cmp rax, 1        ; Check if rax <= 1
	jg .loop1         ; If rax > 1, repeat loop
	EndBench
	StoD Buffer
	StdOutput Msg1, Buffer, Console=Yes

; ======== Dual Branch Test ======== 
	StartBench
    mov rbx, 1
	mov rax, [N]
.loop2:
	cmp rax, 1
	jle .done
	imul rbx, rax
	dec rax
	jmp .loop2
.done:
	EndBench
	StoD Buffer
	StdOutput Msg2, Buffer, Console=Yes

	TerminateProgram

ENDPROGRAM benchm

Результат примерно такой:

>benchm.exe
Two Loops Benchmark
Single Branch Ticks:  1914967186; Dual Branch Ticks:  1894910657

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

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

	mov rbx, 1        ; Initialize result to 1
.loop1:
	imul rbx, rax     ; Multiply rbx by rax
	dec rax           ; Decrement rax
	jnz .loop1        ; If rax > 1, repeat loop

	mov rax, rbx      ; Move result to rax

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

Это так, но, ещё раз — это же просто простая демка к командам ассемблера, к примеру, написать на чистом асме функцию, которая посчитает и напечатает все цифры, скажем 1000! — тоже хорошее упражнение. На самом деле такие функции в продакшене или при реальных расчётах не пишет никто — есть же библиотеки, скажем в Матлабе я просто возьму Symbolic Math Toolbox, и там вроде вообще лимита нет (за исключением памяти компа).

Это же учебный пример. Ещё Фибоначчи берут иногда. Из таких вот маленьких кирпичиков как раз и складывается программирование. А Хаскель тут слегка избыточен, я согласен, просто автор оригинала (это перевод) судя по всему хорошо им владеет, а вот Си и Ассемблером чуть менее уверенно, судя по терминологии и опущенным важным деталям о механизме возврата из функции.

Для обучения ассемблера, кстати, могу смело порекомендовать Евро Ассемблер (euroassembler.eu). Это на самом деле офигенная, хотя и мало известная игрушка, причём написанная одним человеком из Чехии, который охотно отвечает на вопросы. Что удобно, это ассемблер и компоновщик в одном флаконе, написанный на себе самом.

Если хочется сделать минимальное консольное приложение под Windows для вычисления факториала, то кода будет всего ничего:

EUROASM AutoSegment=Yes, CPU=X64
fact PROGRAM Format=PE, Width=64, Model=Flat, ListMap=Yes, IconFile=, Entry=Start:

INCLUDE winscon.htm, winabi.htm, cpuext64.htm

Msg1 D "Enter Number:",0
Msg2 D "Factorial is ",0
Buffer DB 80 * B
    
Start: nop
	StdOutput Msg1, Console=Yes
	StdInput Buffer ; Input Number
	LodD Buffer ; https://euroassembler.eu/maclib/cpuext64.htm#LodD (rax <- Num)

	mov rbx, 1        ; Initialize result to 1
.loop:
	imul rbx, rax     ; Multiply rbx by rax
	dec rax           ; Decrement rax
	cmp rax, 1        ; Check if rax <= 1
	jg .loop          ; If rax > 1, repeat loop
	mov rax, rbx      ; Move result to rax

	StoD Buffer ; https://euroassembler.eu/maclib/cpuext64.htm#StoD (from rax)
	StdOutput Msg2, Buffer, Console=Yes
	TerminateProgram

ENDPROGRAM fact

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

Ассемблируется командой

euroasm.exe fact.asm
Походу генерит листинг, в котором все ходы расписаны
|                          |EUROASM AutoSegment=Yes, CPU=X64
|                          |fact PROGRAM Format=PE, Width=64, Model=Flat, ListMap=Yes, IconFile=, Entry=Start:
|[.text]                   ::::Section changed.
|00000000:                 |
|00000000:                 |INCLUDE winscon.htm, winabi.htm, cpuext64.htm
|00000000:                 * INCLUDE "./maclib/winscon.htm"
|[.text]                   ::::Section changed.
|00000000:                 * INCLUDE "./maclib/winabi.htm"
|00000000:                 * INCLUDE "./maclib/cpuext64.htm"
|00000000:                 |
|[.data]                   ::::Section changed.
|00000000:456E746572204E75~|Msg1 D "Enter Number:",0
|0000000E:466163746F726961~|Msg2 D "Factorial is ",0
|[.bss]                    ::::Section changed.
|00000000:................~|Buffer DB 80 * B
|00000050:                 |
|[.text]                   ::::Section changed.
|00000000:90               |Start: nop
|00000001:                 |	StdOutput Msg1, Console=Yes
|00000018:                 |	StdInput Buffer ; Input Number
|0000002F:                 |	LodD Buffer ; https://euroassembler.eu/maclib/cpuext64.htm#LodD (rax <- Num)
|0000003B:                 |
|0000003B:BB01000000       |	mov rbx, 1        ; Initialize result to 1
|00000040:                 |.loop:
|00000040:480FAFD8         |	imul rbx, rax     ; Multiply rbx by rax
|00000044:48FFC8           |	dec rax           ; Decrement rax
|00000047:4883F801         |	cmp rax, 1        ; Check if rax <= 1
|0000004B:7FF3             |	jg .loop          ; If rax > 1, repeat loop
|0000004D:4889D8           |	mov rax, rbx      ; Move result to rax
|00000050:                 |
|00000050:                 |	StoD Buffer ; https://euroassembler.eu/maclib/cpuext64.htm#StoD
|0000005E:                 |	StdOutput Msg2, Console=Yes
|00000075:                 |	StdOutput Buffer, Console=Yes
|0000008C:                 |	TerminateProgram
|0000009A:                 |
|                          |ENDPROGRAM fact
|        **** ListMap "fact.exe",model=FLAT,groups=0,segments=5,entry=Start:,stack=
|          [.text],FA=00000400h,VA=00401000h,size=00000479h=1145,width=64,align=0010h,purpose=CODE+LITERAL
|          [.data],FA=00000A00h,VA=00402000h,size=0000001Ch=28,width=64,align=0010h,purpose=DATA
|          [.bss],FA=00000C00h,VA=00403000h,size=00000050h=80,width=64,align=0010h,purpose=BSS
|          [.idata],FA=00000C00h,VA=00404000h,size=00000173h=371,width=64,align=8,purpose=IMPORT+IAT
|          [.reloc],FA=00000E00h,VA=00405000h,size=00000030h=48,width=32,align=4,purpose=BASERELOC
|        **** ListGlobals "fact.exe",Global=0,Public=3,Extern=0,eXport=0,Import=8
|        ExitProcess,[.idata]:0000016Ch,VA=0040416Ch,scope='I',lib="kernel32.dll"
|        GetStdHandle,[.idata]:00000150h,VA=00404150h,scope='I',lib="kernel32.dll"
|        LodD64@RT,[.text]:0000023Eh,VA=0040123Eh,scope='P'
|        ReadConsoleA,[.idata]:00000165h,VA=00404165h,scope='I',lib="kernel32.dll"
|        ReadConsoleW,[.idata]:0000015Eh,VA=0040415Eh,scope='I',lib="kernel32.dll"
|        ReadFile,[.idata]:00000157h,VA=00404157h,scope='I',lib="kernel32.dll"
|        Start,[.text]:00000000h,VA=00401000h,scope='P'
|        StoD64@RT,[.text]:000002CDh,VA=004012CDh,scope='P'
|        WriteConsoleA,[.idata]:00000142h,VA=00404142h,scope='I',lib="kernel32.dll"
|        WriteConsoleW,[.idata]:00000149h,VA=00404149h,scope='I',lib="kernel32.dll"
|        WriteFile,[.idata]:0000013Bh,VA=0040413Bh,scope='I',lib="kernel32.dll"

На выходе исполняемый файл в три с половиной килобайта и работает:

>fact.exe
Enter Number:6
Factorial is 720

Умеет в AVX512, можно сделать DLL вместо консольного приложения. Использую время от времени для небольших набросков и тонкой настройки и бенчмаркинга узких мест в коде (после интрисиков). Эх, надо будет статью как-нибудь написать.

Из современных книжек могу порекомендовать Даниэль Куссвюрм — Профессиональное программирование на ассемблере x64 с расширениями AVX, AVX2 и AVX-512:

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

Ну я вроде нигде не соврамши, и даже не поленился проверить на калькуляторе зарплаты, прежде чем писать. Давайте будем не только честнее, но и реалистичнее — при з/п 190К в год у жены ничего забирать не надо, потому что работать ей в общем нет необходимости. ;) А так да, верно, моя супруга какое-то время работала, и у неё был пятый класс, я знаю, что это такое. Но она ушла не в депрессию, а открыла ИП (в смысле стала selbstständig), теперь работает преподавателем исключительно ради удовольствия (по жизни она доктор искусствоведения). Так то да, в налогах там много факторов, от земли немножко зависит, ну и всякие мелочи, типа она часть времени как Ehrenamtlich, это даёт три тыщщи необлагаемых сверху и до кучи её ИП даёт возможность легально списать часть расходов и т.д. и т.п. По факту налоговая каждый год мне несколько сот евро обратно возвращает.

На примере Германии. 10к на руки это что-то около 220+к евро в год до налогов.

Если быть дотошным, то это, скорее всего, если один на первом налоговом классе. Если же женат и третий класс, то "хватит" и 190K, чтоб осталось 10К в месяц.

Можно было работать параллельно с учёбой. Супруга моя, уже находясь в Германии, вполне себе работала у Лебедева лет этак двадцать назад. Он тогда время от времени писал в ЖЖ с предложением присылать ему работы, она послала, Артемий быстро ответил, её взяли внештатным сотрудником (но, правда, у неё на тот момент уже был красный диплом Мухи, которая нынче Академия Штиглица, по граф дизайну). Вопрос с оплатой был решён примитивно — раз в год она ездила в Питер, заходила в лавку студии на Невском и забирала чемодан денег. Поначалу было всё норм — чёткие ТЗ, сроки, оплата, какие-то её работы вывешивались на сайте студии, но потом как-то стало хуже, задания стали менее чёткими, пошли переделки, ну и сотрудничество как-то заглохло, да и она решила защитить диссертацию, сейчас она доктор искусствоведения. В общем ничего особо плохого или особо хорошего сказать не могу, работа и работа, уж на пост на хабре точно не тянет.

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

inline double fastPow(double a, double b) {
    union {
        double d;
        int x[2];
    } u = { a };
    u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447);
    u.x[0] = 0;
    return u.d;
}

добывали и варили соль в Люнебурге, а люнебургская соль считалась лучшей в Германии

И чтобы торговать ею, прокопали канал (Stecknitzkanal) из Люнебурга в Любек, почти сто километров. А уже из Любека соль доставляли по морю в Норвегию, и другие страны, где и солили рыбу.

Это "helpful suspenders" так автопереведено. Должно быть "дополнительная страховка" или что-то в этом роде. Вот оригинал - https://www.businessinsider.com/ford-uses-ai-cameras-in-factories-prevent-recalls-costly-rework-2025-8

Только с российскими ПДД ездить на них, наверное, неудобно,

Я не знал про такую специфику. В моём случае речь идёт о Германии, я живу в пригороде Гамбурга, тут часть дорог вообще на 30 км/ч ограничена, и скутер - самое то, как на работу, так и за свежими булочками к завтраку сгонять, или там на рынок, когда на авто фиг найдёшь место для парковки, а Веспу я могу почти где угодно приткнуть. По части 50 кубов или 125 кубов есть плюсы и минусы, мне вполне хватает и 50, кроме того, она четырёхтактная, так что не так сильно трещит и не воняет сгоревшим маслом.

Information

Rating
27-th
Location
Ahrensburg, Schleswig-Holstein, Германия
Date of birth
Registered
Activity