Колючие пинагоры – очень странные рыбы. Они решили забить на обтекаемость и приблизиться к идеальной форме – форме шара. А чтобы ручейки и речушки не мотыляли их туда-сюда, рыбки превратили свои передние плавники в присоски.
Теперь присасываются к камушкам и сидят, пока не проголодаются.
Снято днем 8 мая в Кампу-Гранди, столице бразильского штата Мату-Гросу-ду-Сул. По утверждению водителей, это не первый случай, когда двухколесная барышня вызывающе ведет себя на дороге.
Мода на бумбоксы со встроенным телевизором большинство из которых имели даже не жидкокристаллическую матрицу, а классический кинескоп небольшой диагонали, началась в конце 1970-х годов и достигла своего пика после запуска в начале 1980-х музыкального телевидения.
Philips 10CX 1130-Combi
Пожалуй, это самый большой кассетный бумбокс с телевизором, впервые выпущенный в 1981 году. Центральную часть фронтальной панели занимает цветной (!) телевизор с 10-дюймовым экраном.
Panasonic TR-1200X
Геттобластер 1982 года выпуска включал внушительный черно-белый телевизор размером 29 см по диагонали.
Sony FX-41
Данная магнитола выпускалась с 1979 года. Встроенный телевизор был чёрно-белый, c ЭЛТ-трубкой размером 3,7 дюйма по диагонали.
Sharp CT-6001
Мощный и весьма дорогой геттобластер 1980 года с опять же цветным (!) телевизором, достаточно редким для тех лет. Вторым названием модели для японского рынка было The Searcher.
Не рекомендуется принимать данную статью близко к сердцу или как истину в последней инстанции. Скорее как научпоп-грелку для мозгов. Тут довольно много упрощений, упущений или просто странно написанных моментов. Если что-то объяснено совсем криво, то добро пожаловать в комментарии.
Все сказанное далее применимо везде, но детали описаны для защищенного режима x86 (только я опустил префиксEдля регистров) и языков семейства C (в основном C и C++, местами C#). Для понимания рекомендуется знать про указатели и базово представлять, что происходит в процессоре.
Приятного чтения.
Думаю все помнят, что такое функция в математике
Начнем со сложного
Глоссарий
Чувствую, что большинство не имеет ни малейшего представления об указателях
В части про x86 я упоминал о том, что процессор представляет из себя бешенный самоуправляемый калькулятор, которому указом может быть разве что хранилище кода, аппаратный сброс и немаскируемое прерывание. И что у него есть системная шина, состоящая из шины адреса, шины данных и шины управления, к которой подключена память, хранящая данные и код.
А память это огромная одномерная полоска, в которой каждая ячейка имеет свой порядковый номер от 0 до 2^(разрядность шины адреса)-1. И указатель представляет из себя самую обычную численную переменную, хранящую номер (адрес) любой ячейки.
Я не понимаю, почему для многих это настолько сложная тема, а существенное количество новичков забрасывают изучение C после встречи с ними. Они в своей сути максимально элементарны (до тех пор, пока не нужно исправлять уязвимости и ошибки, которые появились в результате злоупотребления или неполного понимания нюансов).
Также существуют ссылки, так или иначе представляющие из себя подвид указателей, но обычно с запретом на арифметику с ними (основная сложность и опасность указателей) и/или подсчетом количества активных ссылок для сборки мусора.
Все языки или имеют указатели (Pascal, C, C++, блоки unsafe в C# и Rust), или являются ссылочными (Java, C#, Python, JS, т.д. (почти все современные языки)). С++ тоже имеет ссылки, но как синтаксический сахар над указателями, призванный упростить их передачу в функции и избавиться от проблемы нулевых указателей.
Ассемблер - если вы даже примерно не знаете, что это такое, то первую часть статьи вероятно можно пролистать и перейти на обсуждение парадигм.
Регистр - именованная численная переменная внутри процессора. Может иметь особое предназначение, а может просто использоваться для хранения любых чисел и арифметики. Их немного.
Инструкция - одиночная команда, представляет из себя последовательность из нескольких байт со специальным значением. Любая программа представляет из себя последовательность инструкций внутри памяти. Указатель на инструкцию, которая будет выполнена следующей, содержится в регистре IP, который сам увеличивается после выполнения каждой инструкции. По-хорошему стоило нарисовать пошаговую наглядную анимацию с демонстрацией всех регистров и куском ассемблерного кода, но мне лень, а в гугле я ничего толкового не нашел.
Метка - константа, содержащая адрес чего-либо. К примеру процедуры или глобальной переменной. Примерно как метка для goto в высокоуровневых языках, но универсальнее. Применяются при написании на ассемблере, в процессоре как таковые не существуют и разрушаются до обычных чисел при ассемблировании и линковке.
Разыменование - операция над указателем, когда тот превращается в переменную с адресом, который был записан в указателе (своеобразный пульт Д/У для переменной).
Парадигма - "стиль" написания и постройки архитектуры программы, частично определяется языком. Технически на том же C можно писать в практически любой парадигме (через костыли можно писать в стиле ООП, через макросы реализовать метапрограммирование, а через нестандартные расширения вообще ядерный бред), но родная для него - процедурная. А Go, к примеру, хоть и имеет недоклассы и методы, но лишен практически всех благ ООП и не сильно далеко ушел от C.
Синтаксический сахар - необязательная возможность, которая сокращает количество кода, повышает его читаемость или удобство поддержки
Стек
Большинство процессоров Фон-Неймановской архитектуры в своей конструкции предлагают механизмы стека. Кто играл в покер должны вспомнить стеки фишек. То есть некие значения, сложенные друг на друга (обычно это переменные, в частности адреса в памяти). При этом основными операциями являются добавление фишки на вершину (инструкция PUSH) и ее снятие (инструкция POP). Еще можно косвенно читать и заменять (перезаписывать) фишки относительно вершины (на вершину указывает регистр SP, неявно обновляется через POP и PUSH) или основания (указывает регистр BP) вглубь.
Стеки можно переключать (но не в MOS6502), это нужно для многозадачности
Помимо хранения локальных переменных стек позволяет делать довольно интересную вещь: мы можем положить на стек все необходимые аргументы (x в математике, но их может быть несколько), адрес следующей инструкции (взяв из указателя инструкции IP, это будет адрес возврата), после чего совершить прыжок на какой-нибудь другой адрес (сохранение адреса и прыжок делаются инструкцией CALL).
А на этом адресе может быть функция. Сначала она кладет текущий BP на стек, после чего приравнивает основание к вершине (BP к SP), тем самым создав для себя "новый стек" сразу после предыдущего (это еще называется стековым кадром), в котором якобы лежит только значение старого основания стека (BP), чтобы можно было восстановить его перед возвратом.
Серое это стековый кадр от предыдущей функции
После чего функция может прочитать переданные ей аргументы относительно основания своего стека вниз (технически это будет выход за границы текущего стека), выполнить с этим какие-либо действия (записать в файл, вывести в консоль, просто перемножить) и сохранить результат (обычно результат сохраняется не на стек, а в регистр AX).
После чего функция восстанавливает старое значение BP, сняв его со стека, и выполняет команду RET, которая снимает со стека адрес возврата и совершает переход на него, тем самым переключившись на инструкцию сразу после CALL.
И эта система так или иначе перекочевала в большинство высокоуровневых языков начиная с FORTRAN. К примеру в C CALL превратился в круглые скобки, RET в return, а адреса и метки в имена (при этом без скобок они все еще являются указателями, то есть адресами).
Пример кода (к сожалению, штатного форматирования не предусмотрено):
#include <stdio.h> int pow2(int x) { return x * x; } int main() { int y = pow2(16); // Вызов функции. В y будет сохранено число 256 printf("%p", pow2); // Без скобок вместо вызова просто выведет адрес функции return 0; // Возврат нуля из главной функции означает отсутствие ошибок. }
Такой стиль программирования называется процедурным (выделение кода в блоки называется структурным). А вот называть процедурный язык функциональным совершенно неправильно, ибо функциональное программирование ≠ процедурное, они даже в разных категориях (императивное и декларативное).
А теперь скомпилируем этот код и разберем ассемблерный листинг
Важно понимать, что стек в большинстве архитектур традиционно растет от больших адресов к меньшим (и в x86). То есть для того, чтобы отодвинуть его вершину вверх, от регистра SP нужно отнимать значения, а вот для ужимания и съедания ненужных значений к указателю на вершину значения прибавляют. И для доступа к значениям относительно основания или вершины это тоже важно учитывать. Это может звучать запутанно, но через время привыкаешь и всё становится очевидным.
Надеюсь это возможно будет разобрать. Код скомпилирован MSVC v19.28 для x86 со стандартными настройками в Godbolt
Post scriptum
Это всё довольно упрощенно. Как минимум, в защищенном режиме используется больше 5 разных соглашений о вызове, которые отличаются деталями реализации. Это было описание для cdecl, обычно используемого в C. Еще часто используются соглашения pascal, fastcall, thiscall, winapi и другие. Fastcall, к примеру, избегает хранения аргументов на стеке, если их возможно передать через регистры, что улучшает производительность. А winapi отличается от cdecl тем, что функция сама очищает стек от аргументов для себя при возврате. А еще я упустил, к примеру, сохранение регистров, которые функция может перезаписать и испортить, а потому обязана предварительно сохранить и перед возвратом восстановить, передачу переменного количества аргументов (как в printf) и возврат значений шире 32 бит (которые не влезут в EAX).
Плюс сейчас мало кто компилирует ПО под защищенный 32-битный режим, а в длинном режиме (AMD64) используется пара других соглашений, основанных на fastcall и имеющих несколько отличий друг от друга.
Так процедура или функция? Или подпрограмма?
Процедурное программирование предлагает делить код на подпрограммы, которые принято называть функциями и процедурами (функция обычно является наиболее понятным, частым и обобщенным названием, поэтому я его использую).
Процедура от функции отличается только тем, что функция возвращает какое-то значение (как в математике), а вот процедура этого не делает. Не во всех языках явно есть процедуры (в Pascal есть, но не в C). В таком случае их заменяют функции, возвращающие ничего (void, Unit, undefined, None).
Хотя и тут есть свои особенности. К примеру функция, возвращающая void в C и Java является прямым аналогом процедур, как-либо использовать возвращенное значение из такой функции невозможно, ибо его нет физически. А вот Unit в Kotlin это синглтон (а-ля единственная и уникальная константа уникального типа), ссылку на который можно присвоить в переменную, но в этом особого смысла нет. Undefined в JS и None в Python тоже уникальные константы специальных типов.
Но не тут-то было
Вроде бы процедура никогда не может ничего вернуть...
Только она этого никогда не делает напрямую. При она этом может записать результат в глобальную переменную, а еще часто принимает в себя указатели или ссылки, по которым может записать результат. Это еще удобно тем, что можно "вернуть" несколько значений. Пример:
void procedure(int x1, int *x2, int *x3) { // Функция ничего не возвращает, то есть это процедура *x2 = x1 * x1; // Разыменовываем указатель и записываем по его адресу результат. *x3 = x1 * x1 * x1; // Разыменовываем другой указатель и записываем по его адресу результат. } int y1, y2; procedure(16, &y1, &y2); // В y1 оказался результат, аналогичный прошлому примеру. А в y2 куб числа.
PS: оператор звездочка при указании типа превращает его в тип-указатель, а при применении на переменную-указатель разыменовывает ее до изначальной переменной. Амперсанд превращает переменную в указатель на нее (иногда еще называется оператором получения адреса).
То есть мы вернули сразу 2 разных значения из процедуры, которая якобы ничего не возвращает. Чудеса. Подобные чудеса есть в том числе в Pascal с явным делением на процедуры и функции (плюс там это сделано немного удобнее). Хотя механизм тут отличается от того, который используется в возврате значения из функции и совпадает с механизмом передачи обычных аргументов, поэтому никакой магии.
Еще про связь с математикой
Главное отличие функций в программировании от функций в математике в том, что они могут делать что-то на стороне и не обязаны возвращать одинаковый результат при одинаковых аргументах.
К примеру функция получения случайного числа по определению не может существовать в математике, если она не принимает в себя предыдущее случайное число или зерно для его видоизменения. Или функция записи в файл, возвращающая 0 в случае успеха и другое число при провале. Ко всему прочему, такая функция имеет побочный нематематический эффект, то есть запись в файл, что тоже недопустимо традиционной математикой без высоких абстракций.
Поэтому придумали чистые функции. По сути это ограничитель, которые делают функцию полным отражением таковой в математике. Им запрещено возвращать разные значения при одинаковых аргументах (точнее запрещено всё, что может такое позволить сделать), запрещено обращаться к нечистым функциям, запрещено обращаться к тому, что не является аргументом или локальной переменной, запрещены вообще любые действия, которые могут сделать что-то на стороне (даже функция sin() в C не всегда является чистой, ибо может зависеть от состояния FPU).
Чистые функции через ключевое слово pure явно есть в D и FORTRAN (проверка на чистоту во время компиляции), а также являются основой функционального программирования.
Чистая процедура тоже имеет право на жизнь, используя механизм со ссылками (на счет указателей не уверен из-за возможности арифметики над ними).
Функциональное программирование
Это очень сложная категория, которую постоянно путают с процедурным программированием. А еще это де-факто противоположный стиль: декларативный. Традиционное императивное программирование детально описывает процесс получения результата, а декларативное сам результат, без деталей реализации (хотя разделение обычно довольно нечеткое). При этом второй типичен для языков разметки типа HTML и CSS. То есть, условно, как одна и та же операция могла бы выглядеть в императивном и декларативном стиле:
document.tags.A.color = "blue" /* Императивный (JSSS). Сделать ссылки синими */
a { color: blue } /* Декларативный (CSS). Ссылки должны быть синими */
Почувствуйте разницу.
И функциональное программирование я никогда не изучал и слишком мало о нем знаю. Так что готовьтесь к ошибкам и не воспринимайте всё за чистую монету.
Внутри чистого функционального программирования
Основано полностью на математике, все функции обязаны быть чистыми. Операция присваивания запрещена (разрешены константы), переменных в привычном виде нет. Прикольно? Очень!
Во многих процедурных языках функции и процедуры являются объектами второго класса (не путать с классами из ООП), что не позволяет их свободно присваивать в переменные, передавать как аргументы в другие функции или возвращать из них (только через указатели). Функциональные языки расценивают функцию как объект первого класса, то есть их можно, а часто нужно передавать в другие функции напрямую.
Это дает некоторые преимущества, особенно в плане безопасности и при работе с многопоточностью (по причине неизменяемости данных и отсутствия глобального состояния), но вся концепция имеет один фатальный недостаток: вы мало чего полезного можете сделать, ибо что ввод, что вывод являются математически нечистыми, а потому запрещены. Вот такое вот гениальное изобретение безумных математиков.
Функциональное и процедурное программирование. Холст, масло
Каждый чисто функциональный язык выкручивается из этого по-своему, к примеру через монады. Это позволяет им существовать вне шуток и даже использоваться на практике.
Это не все особенности функциональных языков, но одни из самых важных. Самый известный такой язык: Haskell. Функциональные F#, Lisp, ML и многие другие не являются 100% чистыми.
Смешанное функциональное программирование
Последнее время часто используются смешанные языки, к примеру вместе с процедурным или объектно-ориентированным программированием, что избавляет от ограничений математики, но дает гибкость в том, что функциями можно оперировать как с любыми другими типами данных, а еще дает много очень удобного сахара вроде замыканий и лямбд. Это C#, Python, JS, частично Java и C++ (в них нужны костыли в виде интерфейсов из одного метода или оберток над указателями).
Особенности
Функции как объект первого класса. К примеру в C# это реализовано через систему делегатов, которые представляют из себя тип-обертку для функций:
Action<string> printer = Console.WriteLine; // Action<string> - тип-делегат. Неявно создаем его объект и присваиваем туда функцию printer("Hello, World!"); // Вызываем функцию через делегат
Локальные функции: как обычные, только вложенные в другую функцию (объявленные внутри нее)
void Func1() { // Глобальная функция void Func2() { // Локальная функция Console.WriteLine("В локальной функции"); } Func2(); }
Лямбды: возможность объявить безымянную функцию посреди кода (часто удобнее локальных)
var pow2AsLambda = x => x * x; // => - оператор лямбда-выражения pow2AsLambda(5); // Вернет 25
Замыкания (можно использовать вместе с лямбдами и локальными функциями):
int someValue = 42; var pow2AsLambda = x => x * x + someValue; // someValue будет захвачено замыканием, хотя напрямую не передано pow2AsLambda(5); // Вернет 67
Особенность замыканий в том, что они могут захватить локальную переменную родительской функции внутрь себя, продлевая ей время жизни за пределы блока с кодом. После чего такую лямбду можно передать в другую функцию, которая просто так не имеет доступа к someValue (в обычных условиях someValue вообще уже будет уничтожен), а вот переданная лямбда сможет ее прочитать или записать всегда и откуда угодно. И самое интересное то, что значение этой переменной будет сохранятся между вызовами к замыканию. То есть она становится глобальной, но видимой только из функции-замыкания.
ООП
Посмотрим на индекс TIOBE по популярности языков. Фиолетовым я пометил чистые функциональные языки. Языки, имеющие возможности, присущие функциональным языкам (смешанные) - синим, процедурным - красным, а объектно-ориентированным (ООП) - зеленым. Языки, в которых нельзя объявить функцию, принадлежащую самой себе или модулю, процедурными считать не совсем корректно (Java).
Не претендую на 100% точность
Видите фиолетовые точки? И я не вижу. А вот синих 12. В то же время красных и зеленых по 16. При этом реально применяемый чисто процедурный язык всего 1: С. Остальные имеют какую-либо встроенную поддержку других парадигм.
И сейчас практически всё большое ПО пишут в ООП. Ибо позволяет хоть как-то сдерживать структурированность кода после перехода с десятков тысяч строк к сотням (и миллионам).
Внутри
ООП является развитием идеи процедурного программирования. Проблема была в том, что помимо кода в программе существуют еще и данные, которые было бы неплохо связать с соответствующим им кодом. И через некоторое время после появления процедур появились структуры (они же записи в Pascal, не путать со структурным программированием).
Структуры были удобным способом объединить несколько переменных в единое целое. Пример:
typedef struct user_struct { char *username; int userid; int reputation; } user_t; user_t someuser = { "IvanKr08", 17002, 253 }; // Инициализируем значениями someuser.reputation += 10; // Обращаемся к полю
(Вместе с этим объявляем структуру новым типом через typedef, что не делается по умолчанию в C, в отличии от C++. Один из ярких примеров несовместимости C и C++):
После чего user_t превращается в новый тип, как int или char. Можно создать полноценную переменную типа user_t (или массив такого типа), а потом обратиться к какой-нибудь ее части (полю) через оператор точки (.). Можно сделать функцию, которая будет принимать или возвращать переменную типа user_t (к примеру someuser). Можно сделать указатель на user_t, тогда для обращение к полю используется оператор стрелки (->). Или можно встроить переменную типа одной структуры в другую, это тоже не запрещено. Внутри структурная переменная представляет из себя последовательно слепленные поля в одно целое.
Если поля разного размера, то часто добавляют пустоты между полей в целях выравнивания по размеру наибольшего поля и улучшения производительности, но это сложная тема
Возвращаемся к ООП
Суть ООП в том, что помимо полей структуры могут содержать процедуры и функции. Такая структура называется классом, переменная класса - объект, а процедура класса - метод.
Метод принципиально ничем не отличается от любой процедуры или функции, кроме того, что неявно принимает в себя специальный аргумент this (в Python это делается явно, в некоторых языках вместо this может быть self). Он содержит в себе ссылку/указатель на объект класса, от которого был вызван. Пример:
class User { public: char *username; int userid; int reputation;
void print() { printf("Пользователь \"%s\" (%i). Репутация: %i\n", this->username, this->userid, this->reputation); // Постоянно писать this-> не обязательно. Если локальной переменной с таким именем нет, то будет произведен доступ к полю } }; User someuser = { "IvanKr08", 17002, 253 }; // Инициализируем значениями someuser.print(); // Вызвали метод, print() неявно получил в себя указатель this, который указывает на someuser someuser.reputation += 10;// Обращаемся к полю someuser.print(); // Теперь вывод поменяется
Да, никто не мешает объявить обычную функцию, которая будет явно принимать в себя указатель на User и ничего не поменяется, и так повсеместно делают в C (тот же WinAPI на этом построен целиком и полностью), но ООП на самом деле крайне сложная, большая и холиварная тема, которая развивалась на протяжении 60 лет в разных направлениях и которую поднимать тут глупо. Только опишу еще несколько разновидностей методов:
Статичный метод - как обычный метод, только не получает в себя this и вызывается от имени класса, а не объекта (не someuser.method(), а User::method()). Зачем это нужно и в чем отличие от просто функции? Статичный метод можно спрятать за инкапсуляцией, плюс он привязан к классу, а не болтается в глобальном пространстве имен.
Конструктор - автоматически вызывается при создании нового объекта. Может иметь аргументы, тогда обязан явно вызываться как функция с именем класса, т.е. User("IvanKr08", 17002, 253)
Деструктор - есть в C++. В C# называется финализатором и имеет несколько важных отличий. Автоматически вызывается перед уничтожением объекта (к примеру выход из области видимости, явное удаление оператором delete или удаление сборщиком мусора в C#). Не может иметь аргументов.
Свойство - есть в Delphi и C#, куда перешел от первого. С точки зрения синтаксиса это поле, которое можно читать и записывать, только вместо прямого обращения в память вызываются соответствующие методы (set и get). Пример: ... int SomeProperty{ get =>42; set => Console.WriteLine("Set"); } ... test.SomeProperty = 10; // Значение никуда не сохранится, будет выведено "Set" в консоль Console.WriteLine(test.SomeProperty); // Всегда будет 42
Перегрузка оператора - специальный метод, который позволяет переопределить стандартные операции для типа. К примеру нельзя сложить два объекта User или User и число, но если перегрузить оператор +, то можно будет определить свою логику для этого (не обязательно, чтобы оно что-то реально складывало. Это может быть любое действие).
Индексатор - синоним перегрузки оператора квадратных скобок. Объект начинает вести себя как массив.
Функтор - перегрузка оператора круглых скобок (иначе называется перегрузкой оператора вызова функции). Позволяет "вызывать" объект так же, как и функцию. Звучит запутанно, но можно погуглить. Есть в C++. Также бывает функтор в функциональном программировании, но он не имеет ничего общего с функтором в C++.
Виртуальная функция (метод) - самый интересный и сложный тип, составляет основу полиморфизма. Вкратце объяснить его невозможно, но одним из ключевых принципов ООП является наследование, то есть один класс (наследник) копирует в себя все поля и методы другого класса (родитель), и может добавить новые. И суть в том, что указатель (ссылка) на объект класса-наследника может быть присвоен в переменную-указатель родительского типа. А самое интересное то, что любые обращения (к примеру вызовы методов), сделанные через родительский указатель, будут вести себя аналогично обращениям, сделанным напрямую через указатель с типом наследника. Это называется полиформизмом. Но это было бы не слишком полезным, если бы не возможность объявить метод в родительском классе виртуальным, а в наследнике полностью переопределить его код.
И то, что я забыл
Послесловие
Если вы осилили эти 3000 слов и даже смогли что-то понять, то найдите и распечатайте себе утешительную грамоту. А я устал и пойду искать смысл жизни...
UPD: исправлены косяки форматирования, очепятки, добавлено еще пару пунктов про разновидности методов и функциональное программирование.
Сегодня мне жена, дама, можно сказать, постбальзаковского возраста, с высшим образованием, заявила на голубом глазу, что у коровы вымя - это 2 соска, причем находятся между передних ног, потому что именно там у коровы самое вкусное мясо - грудинка. Я было решил, что это шутка, ан нет, она была предельно серьёзна. Дитя асфальта, блин...
1. Мой отец скончался в прошлом году. Он всегда говорил, что хочет, чтобы я подарил ему дробовик, который изначально принадлежал его деду. Много лет он хранил это ружье на чердаке. После того, как он ушел, я пошел на чердак поискать его, но ничего не нашел. Несколько месяцев спустя мне приснился сон, в котором я спросил у отца, куда он положил дробовик. Он сказал, что оружие лежит в чулане свободной спальни. Конечно же, дробовик был там. Вполне возможно, что отец сказал мне это при жизни, и сон был просто воспоминанием, но я не помню, чтобы это было так.
2. Моя мама рассказала мне эту историю на днях, и она меня чертовски напугала. Когда моя старшая сестра была маленькой, лет трех, она попросила тетю, которая тогда была беременной, взять ее на руки и подержать. Мама сказала ей: «Тетя не может взять тебя на руки, дорогая, у нее в животике ребенок». А сестра заявляет: «Этот ребенок мертв!» Мама испугалась, но с тетей и бабушкой все было в порядке, и они решили, что ребенок совсем маленький и не знает, что говорит. А на следующий день тетя пошла к врачу на плановый осмотр по поводу беременности, и там выяснилось, что ребенок умер.
3. Когда мне было 15, мы с мамой стояли на кухне и разговаривали. На стене на расстоянии около 8 футов стояла стойка с ключами. Ключ со стойки пролетел через комнату и упал на пол у наших ног. Это единственное событие в моей жизни, которому у меня нет объяснения. Многие спрашивают, куда делся ключ. Я не знаю. Это был старый, тяжелый ключ. Дом был построен в 1880-х годах, поэтому мог быть оригинальным.
4. Самый страшный момент в моей жизни произошел, когда мы с другом, будучи подростками, были в палаточном лагере на востоке Канады. Мы решили переночевать в заброшенном кемпере, который нашли в лесу. Он стоял там так долго, что вокруг него выросли деревья. Мы наткнулись на него несколько месяцев назад и подумали, что было бы круто переночевать там. В один из выходных мы сделали это.
Приехали после наступления темноты, потому что заблудились. У нас был слабый фонарик, что еще больше усложняло задачу. Как только мы нашли его, открыли ржавую дверь и вошли внутрь. Звуки внутри кемпера были пронзительными и гулкими. Вокруг были разбросаны типичные туристические вещи: чашки, пустые банки, бульварные романы.
Уставшие, мы легли в конце кемпера, где изначально была кровать, прежде чем подушки сгнили почти полностью. Длинный коридор растянулся на всю длину, так что мы могли все видеть из конца в конец.
Это была жуткая ночь. Там жили крысы. Я видел, как они смотрели на нас из проржавевшего потолка. Когда дул ветер, кемпер визжал и стонал. Нам даже показалось, что снаружи гуляет медведь. Но мы набрались храбрости и вели себя так, будто хорошо проводим время, хотя и были на грани.
Я проснулся от неприятного сна и краем глаза заметил какое-то движение. В другом конце кемпера было маленькое окно, в котором я увидел силуэт мужчины. Он смотрел прямо на меня.
Я подумал, что это странная форма дерева, но когда я немного подвинулся, чтобы лучше рассмотреть, человек явно отреагировал и замер. Сердце у меня сильно колотилось, и я тут же разбудил друга, повторяя шепотом «кто-то здесь есть», и не отрывая глаз от его профиля. Он сразу проснулся, и я кивнул в сторону окна.
Он тоже его видел. Мы лихорадочно перешептывались о том, кто это может быть и почему он смотрит на нас. Чем дольше мы смотрели на него, тем больше нам было страшно. Время от времени он двигался, но всегда не спускал с нас глаз. В конце концов, я крикнул ему: «Эй!». Никакой реакции.
Мой друг оказался смелее и решил посветить фонариком. Как только он это сделал, мы осознали нашу ошибку. На другой стороне кемпера было вовсе не окно. Это было зеркало. Мы смотрели на себя с самого начала. Полный идиотизм. Но это был самый страшный момент в моей жизни, который я никогда не забуду. Это самое близкое к паранормальному, что я когда-либо видел.
Его профессия так и называется - ледорез. Весной он буквально выпиливает суда из замерзшего водоема, чтобы избежать повреждения корпуса при таянии и движении льда.
Во-первых, поздравляю всех с великим праздником Победы!
Сегодня мы посетили прекрасный образец архитектуры, истории, религии и ландшафтного дизайна, храм святого апостола Петра и праведной Тавифы.
Храм был построен на участке, приобретённом при участии православного архимандрита Антонина (Капустина) в 1868 году. Ещё до строительства церкви на купленной земле был построен странноприимный дом (гостиница) для православных паломников, прибывавших в Палестину через порт Яффа, выкопан колодец, посажены плодовые (апельсины, лимоны, маслины, гранаты, смоквы) и декоративные (кипарисы, эвкалипты, сосны) деревья.
Нам повезло. На сайте написано, что храм открыт с 15. Но на входе был телефон. Мы позвонили и нам открыли. Правда до этого выдержали атаку неприятного мужичка, который ездил вокруг нас на велосипеде с украинскими песнями и орал, что в церкви празднуют 9 мая, что храм нужно снести, а все деревья вырубить. Когда он отъехал, матушка нас быстро запустила.
Большая территория храма с любовью засажена прекрасными цветами. Повсюду летают десятки павлинов, попугаев, голубей, майн.
Зато кусок мха из неё получился просто замечательный. Кожные выросты и бородавки разной формы вкупе с интересной окраской размывают силуэт лягухи и делают её практически невидимой на фоне мха, которого в дождевых лесах Южной Азии полным-полно!
Вчера в Белореченске (Краснодарский край) 16-летний уебан подросток на питбайке сбил 65-летнюю пенсионерку на пешеходном переходе. Женщина погибла на месте до приезда скорой медицинской помощи.
Сообщается, что ранее несовершеннолетний уже привлекался за управление транспортным средством без права управления, также материалы за передачу управления транспортным средством лицу, не имеющему водительского удостоверения, были составлены в отношении родителей.
Ежегодно в Ратчабури проходит фестиваль света NaSatta Light Festival. В живописном парке представлены различные световые инсталляции, посвященные тайской культуре и национальной самобытности.
Как ни удивительно, но развал СССР дал сильный толчок к развитию в РФ и странах СНГ методам криптоанализа, которые превзошли зарубежные аналоги.
При этом данные процедуры хорошо были изложены в учебной литературе для ВУЗов господином П.А. Трушевым.
К сожалению книга очень и очень дефицитная - ознакомится не удалось
Данные отечественные средства имеют высокую степень успешного взлома всех криптоалгоритмов, таких как DES, 3DES, AES, Blowfish, Twofish, Serpent, Кузнечик, Магма, ГОСТ 28147-89 и даже "одноразовый блокнот". Вероятность успешного взлома достигает 99.9%, причём одна десятая процента неудачных взломов образуется исключительно на подготовительных этапах - выбор носителя ключевой информации и выбора самой процедуры.
Что самое примечательное, то оборудование, необходимое для проведения данных процедур стоит копейки и реализуется через обычную розничную сеть:
Его величество ЭПСН 100ВТ 220В выполненный по ГОСТ 7219-83 "Терморектальный криптоанализатор, устройство, принципы действия, технические условия производства".
Различают два способа проведения процедуры криптоанализа:
1. Терморектальный криптоанализ - прибор непосредственно применяется к «цели» УЖЕ прогретым до рабочих температур, что обеспечивает высокую скорость и точность взлома шифра, однако в этом методе имеется недостаток - носитель криптоключа будет значительно повреждён и в некоторых случаях это может привести к его непреднамеренному уничтожению до окончания процедуры взлома.
2. Ректотермальный криптоанализ - тот же прибор изначально вводится в "целеуказатель" и только потом начинается его прогрев. Применяется при работе со старыми, имеющими дефекты вспомогательных систем (сердце, сосуды и т.п.), т.е. там, где есть риск непреднамеренного уничтожения носителя ключевой информации, работая по первому способу. При этом эффективность несколько ниже, а время проведения криптоанализа увеличивается.
Замечено множество случаев, когда при проведении этих процедур добывалась ключевая информация даже если носитель ею не обладал.
Некоторые факты о б этом приборе:
* При использовании терморектального криптоанализатора скорость перебора пароля прямо пропорциональна квадрату температуры.
* В отличие от разработок западных ученых, использующих для взлома пароля сложные технические изделия, терморектальный криптоанализатор использует обычную бытовую сеть 220 Вольт/50 Герц и не требует специальной технической подготовки оператора.
* Сложность задачи в случае использования криптоанализатора не зависит от длины ключа и типа используемого алгоритма шифрования.
* Есть свидетельства успешных взломов даже если носитель ранее не обладал ключевой информацией, изучив данные свидетельства Донецкий завод паяльников выпустил новую и улучшенную серию полиграфов «Электровспоминатель-3000».
Зарубежные системы криптоанализа не так эффективны и сложны технически, доказательство ниже:
Информация, представленная в этом посте получена из достовернейших источников: 123
5 мая 1821 года на острове Святой Елены, затерянном в Атлантическом океане, завершилась жизнь одного из самых противоречивых деятелей мировой истории -Наполеона Бонапарта. Его смерть стала кульминацией шестилетней ссылки, наполненной физическими страданиями, политической изоляцией и борьбой за сохранение достоинства.
Предпосылки изгнания и упадок здоровья
После поражения при Ватерлоо 18 июня 1815 году Наполеон, дважды отрекшийся от престола, оказался в руках англичан. Битва при Ватерлоо стала финалом знаменитых «100 дней» Наполеона Бонапарта , в которой он пытался вернуть свою утерянную власть.
Внесу маленькую ремарку, которая не относится к данной статье.
Так же интересным фактом является то, что данные события "100 дней" упомянуты в книге "Граф Монте - Кристо". В рамках художественного произведения именно встреча молодого Дантеса с Наполеоном и послужило спусковым крючком в побеге Бонапарта с острова Эльба, а так же причиной всех бедствий будущего "графа Монте - Кристо". Тем кто не читал - очень советую прочитать, книга восхитительная. А битва при Ватерлоо заслуживает отдельной статьи, которую опубликую 18 июня).
Вместо ожидаемого убежища в Великобритании его отправили на остров Святой Елены - «скалу посреди океана», как он сам называл это место. Условия содержания были строгими: дом окружала каменная стена с часовыми, переписка подвергалась цензуре, а губернатор Хадсон Лоу намеренно унижал бывшего императора, отказываясь признавать его титул.
Первые годы ссылки Наполеон сохранял активность, диктовал мемуары и надеялся на изменение политической ситуации в Европе. Однако к 1819 году его здоровье начало стремительно ухудшаться. Он жаловался на боли в желудке, опухание ног, слабость и приступы рвоты. Личный врач Франческо Антоммарки диагностировал гепатит, но сам Наполеон, зная, что его отец умер от рака желудка в 38 лет, подозревал онкологию. К 1821 году его состояние стало критическим: он почти не вставал с постели, а в последние недели жизни страдал от невыносимых болей, которые называл «Ватерлоо, вошедшим внутрь».
Споры о причинах смерти
Вскрытие, проведённое 6 мая 1821 года, выявило язву желудка с прободением в печень и признаки раковой опухоли. Однако мнения медиков разделились: английские врачи настаивали на раке, а Антоммарки связывал смерть с «пагубным климатом» острова, что могло скрыть ответственность британских властей.
В 1960-х годах шведский токсиколог Стен Форсхуфвуд выдвинул версию об отравлении мышьяком. Анализ пряди волос Наполеона показал содержание яда, превышающее норму в 4–65 раз. Форсхуфвуд объяснял этим такие симптомы, как ожирение, светобоязнь и глухоту, а также предполагал, что мышьяк могли добавлять в вино или использовать для консервации волос. Однако поздние исследования, включая работу токсиколога Паскаля Кинца (2001), опровергли эту теорию: мышьяк в волосах был минеральным, а не органическим, что исключало отравление через обои или косметику.
Последние дни и наследие
В апреле 1821 года Наполеон продиктовал завещание, распределив средства между близкими и выразив желание быть похороненным «на берегах Сены». Его последние слова, произнесённые в бреду - «Голова армии!» (фр. La tête de l’armée!) - стали символом связи с военным прошлым. Тело Наполеона первоначально погребли в долине Герани на острове, но в 1840 году его останки перевезли в Париж и поместили в Дом инвалидов, выполнив волю императора. Эта церемония, сопровождавшаяся массовым скорбью французов, реабилитировала его образ в национальной памяти, несмотря на противоречивость наследия: от авторитаризма и восстановления рабства в колониях до создания Гражданского кодекса и реформ образования.
Смерть Наполеона не поставила точку в спорах о его роли. Для одних он - «герой Просвещения», стабилизировавший революцию и распространивший её идеалы в Европе. Для других - «могильщик республики» и предтеча диктатур XX века. Его противостояние с Англией, трагедия «100 дней» и миф о «возвращении с Эльбы» стали частью истории Западной культуры, а загадка смерти продолжает будоражить умы учёных и по спей день.