Есть такой антипаттерн -- Паблик Морозов. Заключается он в том, что вокруг класса с закрытыми членами делается обёртка-наследник, выдающая данные закрытых членов. Юмор в данном случае понятен -- согласно известной истории, Павлик Морозов заложил своего отца. И класс-наследник закладывает своего наследодателя.
А сегодня я имел честь видеть класс-самоубийцу (все названия изменены):
class jisatsu { private: float* m_fData; // тут будет храниться массив с данными //... public: float* GetData() { return m_fData; } //... };
Ехал я домой. А мне для того чтобы домой попасть подходят две станции. Ехать надо было с пересадкой и я выбрал некоторую из них. Выхожу на станции (время -- 22:30), чувствую, меня кто-то хватает за рукав и что-то говорит. Я думаю... кто там... МИЛИЦИЯ?! Оборачиваюсь -- там стоит НЕГР. (читать дальше) Негр: Do you speak Enlish? Я туплю. Он повторяет вопрос. В голове вертится только "хай, сукоси". На третий раз я наконец ответил. Я: Yes. Он: (неразборчиво) Я: Repeat please. Он: (неразборчиво) Я: I don't understand. На третий раз он сказал понятно. Он: What is the name of this metro station? Я туплю. Он: %STATION_NAME%, right? Я: Yes! Он: I need help. The police got my friend. Я: . . .
Я: I Understand. Он: Sit down please. Я присаживаюсь на лавочку, он рядом. Он: The police got my friend. This is the immigration police. They need money. I have money, but the need more. I don't know what to do. Мимо проезжает состав. Я начинаю себя чувствовать персонажем Макс Пейн. Я: Where did they got him? Он: Yaroslavskoye (далее неразборчиво) Я: Yaroslavskoye WHAT? Он: Yaroslavskoye shosse (Что он тут-то делал? Это довольно далеко отсюда). Я: What they say? Он: They need money. I have money, but they need more. Я: (господи, у меня 7к с собой!) I... have no money. Он: But you have card. Я: What? Он: Card! Я: (да он проницательный... у меня их даже две) I have no card. Он: No way! (разочарованно) Он: Do you live far from here? Я -- (долгая пауза, а ведь совсем рядом!) Yes, far... (долгая пауза) Он: I don't know what to do. Я: Excuse me, I can't help.
И огородами, огородами.
Это был не конец. Дальше был подземный переход. Там играли на гитаре. Один играл. Вокруг него стояли ещё двое и третья с шляпой. Загораживают проход, трясут шляпой. Я мотаю головой обхожу и иду дальше.
И это ещё не всё. Стою на пешеходном переходе, жду зелёный. Тут останавливается тонированная иномарка и у неё начинает открываться окно пассажира переднего ряда. Я думаю ДА НЕ НУ НАХРЕН, ЩАС СО МНОЙ ГОВОРИТЬ БУДУТ. Быстренько её обхожу и пытаюсь перейти дорогу. Но там едет другая машина, кидаться не могу. Правда эта передумала и поехала дальше. Дальше я уже до дому почти бежал.
А ещё сегодня я не взял с собой пистолет, потому что курточка зимняя была и я переложить забыл.
По поводу этого инцидента хотел бы прокомментировать следующее: 1. Как хорошо, что я сегодня зарплату не стал получать! (пистолета не было, решил в другой день) 2. Позже я подумал, что надо было его отправить в посольство, либо сдать в милициюполицию. Но я не знал, как будет "посольство" (. 3. Я подумал, как жаль, что я не бандит. А то бы ему сказал "а пошли ко мне домой, за деньгами", повязал бы там его, забрал бы его деньги... 4. Даже если это был развод (а это, скорее всего, он и был), то очень эстетичный. Спасибо тебе, негр! 5. Слово "посольство" гораздо важнее, чем я думал. 6. У меня есть принцип -- НЕ ПОДАВАТЬ. В общем случае это значит -- "не одалживать и не дарить денег незнакомцам, а знакомцам -- только с возвратом".
Описаны методики и приёмы именования абстрактных объектов на примере файлов.
Когда нам приходится работать с большим числом более-менее однородных об'ектов, неизбежно возникает необходимость как-то ориентироваться во всём этом барахле. На помощь приходит именование. Это очень древняя система. В современном обществе имя есть практически у каждого человека (в отличие от фамилии -- у членов японской императорской семьи, например, фамилии нет, только имя). Тут следует сделать замечание, что есть две совершенно разные категории именования -- именование различных об'ектов и именование различных версий одного об'екта. Поскольку то, о чём я напишу ниже, работает для любых типов об'ектов, без ограничения общности будем считать, что речь идёт про файлы. С одной стороны, они являются более-менее однородными об'ектами (файлами (= ), с другой стороны, их содержимое может быть совершенно различным как по структуре (форматы), так и по смыслу, в случае одинаковой структуры. А ещё у всех файлов есть имя. Также речь пойдёт только о ситуациях, когда именовать вы имеете право. Если имена даны свыше (или другими существами), вы ничего с этим сделать не можете, это неинтересно. Ниже я опишу основные способы именования, которыми я или не я пользовался или пользуюсь по сей день. (читать далее)
Первое: именование различных об'ектов
Итак, различные об'екты должны именоваться различно -- К.О. Если в жизни различные об'екты могут иметь два полностью одинаковых имени, то в случае с файлами это невозможно. Даже если у вас есть возможность так сделать (названия заметок в KeepNote, например), лучше от этого воздержаться. Причина проста и очевидна -- об'екты с одинаковым именем можно различить только путём непосредственной проверки содержимого, что означает необходимость дополнительных проверок (потеря времени), причём неопределённого (с какой попытки вы угадаете?). Если необходимо всё-таки именовать одинаково, лучше ввести какой-либо различитель -- постфикс к имени, вид иконки или что-либо ещё. Однако, введение постфикса к имени автоматом делает имена различными. Пример различителей из реальной жизни -- именование королей ("Людовик XVI" -- отделение имени от различителя логическое, так как и "Людовик" и "шестнадцать" являются отдельными словами и по другому разбить полное имя нельзя, про разделитель см. ниже).
Как сделать правильный различитель? Он должен легко отделяться от основного имени и предоставлять широкие возможности. Про лёгкое отделение -- тут всё понятно. Нужен символ-разделитель. Или несколько. Например: Черчение-1.wav -- тут всё понятно, разделитель -- дефис; Черчение[1].wav -- тут тоже всё понятно, разделитель -- квадратные скобки. Ещё возможно разделение по признаку принадлежности к другой категории символов, например: черчениеА.wav -- заглавные против строчных; 2черчение.wav -- цифры против букв. Для всех об'ектов разделитель должен быть одним и тем же. Почему? При сортировке (о сортировке -- ниже) всё будет по порядку. Это всё -- если различитель расположен в имени файла. Если различитель где-то ещё, разделитель возникает естественным образом. Лучше, чтобы различитель был в имени -- он будет виден при любом отображении списка файлов (на самом деле, не любом; можно заставить Проводник отображать только "ноготки", без имён). Также это поможет при сортировке.
Отступление: сортировка Тут следует сделать замечание про сортировку. Любые именованные об'екты принято сортировать, для быстрого поиска. Сортировка производится, как правило, в алфавитном порядке. В случае файлов на компьютере, порядок определяется кодировкой, однако принцип алфавитности обычно соблюдается. Единственное, чем плох алфавитный порядок -- расположение букв в таком порядке не об'ясняется логически, только исторически. Другими словами, алфавит придётся выучить. "Определяется кодировкой" означает, что цифры и спец. знаки тоже включены, цифры идут ДО букв, русские буквы идут после латинских, строчные после заглавных. Эти правила общие для почти всех кодировок.
Про широкие возможности -- тут сложнее. Надо ответить на следующие вопросы -- 1) Где расположить различитель? 2) Какие значения может принимать различитель? 3) Как оформить различитель?
Где расположить различитель?
Я не знаю, может быть вы сможете придумать причину, чтобы располагать его в середине имени, но я придумать такую не могу. Различитель имеет смысл располагать либо в начале имени файла, либо в конце (про расширение речи нет). Как правило, в конце. В начале можно располагать в том случае, если различители с одинаковыми значениями могут служить для классификации об'ектов с разными именами, но одинаковыми различителями. Пример: [красный]куб [красный]шар [красный]додэкаэдр [зелёный]куб [зелёный]шар [жёлтый]куб При сортировке появятся сначала жёлтые об'екты, потом зелёные, потом красные. Это может быть полезно. Другой случай, когда различитель является надкатегорией над об'ектами. Тогда тоже можно располагать различитель в начале имени, однако в таком случае лучше все об'екты переместить в эту самую надкатегорию (создать для них папку и положить их туда безо всяких различителей).
Однако чаще проще и лучше размещать различитель в конце: Летит-1.doc Летит-2.doc Летит-3.doc
Какие значения может принимать различитель?
Это тяжёлый вопрос. Если есть у об'ектов недублирующиеся характеристики, лучше, конечно, использовать их. Когда круг об'ектов известен заранее, можно найти такой признак, например, цвет. Когда круг неизвестен, вряд ли удастся. Другой распространённый способ -- различать по номеру.
Отступление: нумерация. Нумерация -- частный случай именования, когда вместо символов имени используются только цифры. Нумерация может быть сквозная или категоризированная. И ту и другую можно наблюдать в нумерации помещений в школах, институтах и других учреждениях. При сквозной нумерации числа, характеризующие об'екты (помещения), идут подряд. При категоризированной, некоторые условные признаки позволяют узнать по номеру что-то ещё, что может облегчить поиск, например. В случае с помещениями, как правило, первая цифра означает номер этажа. Например -- 209 -- 9-я комната на 2-м этаже. И можно не обходить все кабинеты, а сразу на 2-й этаж. Если этажей 3 и более, это существенно сокращает время поиска. Другой пример категоризированной нумерации -- нумерация домов на улице. Как правило (но не всегда!) с одной стороны улицы только чётные дома, с другой только нечётные. Каких-то домов может не быть.
Если душа не лежит к нумерации, а признак не находится, можно использовать любые наименования, которые способны вызвать в мозгу ассоциацию с конкретным об'ектом (желательно, чтобы наименования были из одной категории). В японских школах, например, (согласно аниме) вместо букв классов используют иногда названия растений.
Как оформить различитель?
Тут остаётся рассмотреть два небольших вопроса. Первое -- каким выбрать разделитель? Правильный ответ -- любой (даже пустой, пример ниже), но он должен быть одинаковым. Если у одних файлов "_", а у других "-" -- это приведёт к тому, что при сортировке сначала будут выводиться одни ("-"), потом другие ("_"). Желательно, конечно, чтобы он был легко отличим (т.е., например, если в основном имени используются буквы, он не должен быть буквой). Второе -- какова должна быть длина различителя? Правильный ответ -- лучше, чтобы она была одинаковой и не слишком большой. Не слишком большой -- для простоты восприятия, а желательность одинаковой длины опять связана с поиском и сортировкой. Если не дописывать, например, ведущий нолик к числам, сортировка по имени даст следующий результат: имя1 имя10 имя11 ... имя19 имя2 имя20
Сколько нулей писать, зависит от числа об'ектов, но надо брать "на вырост". После появления нового знака (такое бывает), ко всем старым об'ектам надо дописать ещё один нолик. Как можно быстрее.
Различные об'екты следует именовать различно, с этим разобрались, но как? Тут всё зависит от того, что вы называете. Желательно, чтобы имя файла отражало его суть (: лучше не сохранять порнорассказы в файл доклад.doc, потом можно запутаться (=. Название должно быть информативным, как правило, это значит, что по названию должно быть понятно: 1) Каков тип об'екта? (сервер? кинофильм?) -- эту функцию успешно выполняет т.н. "расширение" файла. 2) Что в этом об'екте? -- либо это название, данное логическому содержимому до нас (например, название фильма), либо категория, к которой его можно отнести (например, "Отчёт"). 3) Какими характерными признаками оно обладает? -- для отчётов это либо тема отчёта, либо автор, либо и то и другое (например: отчёт сидоров.doc), для других файлов может либо отсутствовать, либо показывать какие-то характеристики (см. 2-й пример хорошего имени). Примеры хороших имён: Отчёт по экологии 2011 сидоров.doc [Leopard-Raws] Kuragehime - 07 RAW (CX 1280x720 x264 AAC).mp4 Пример плохих имени: Какая-то хрень.doc Отчёт.doc Последнее допустимо, если название папки даёт дополнительные сведения.
Второе: именование версий одного об'екта
Итак, вы не хотите или не можете использовать систему контроля версий, а ваши файлы всё-таки имеют много версий. Например, у вас есть листинги вашей программы в нескольких файлах.
Отступление: много файлов в об'екте Также, если ваши логические об'екты состоят из нескольких файлов, для хранения версий рекомендую делать тарбол (для виндузятников: архив, для продвинутых виндузятников: архив без сжатия, если разные версии приходится использовать часто) и именовать уже его. Или, что проще, организовывать для каждого об'екта отдельную папку. Но это хуже, т.к. файлов остаётся много, хотя логически об'ект один. Держите в папке только текущую версию, остальные в архивах.
Ключ к лёгкой ориентации в ваших файлах -- в грамотном именовании, опять-таки. Коренного отличия между именованием разных версий одного об'екта и разных об'ектов с одним именем для машины нет. Для человека разница в том, что версии могут по внешнему виду слабо отличаться и поиск отличий может занять длительное время. Тут работает другое правило -- одинаковые об'екты должны называться одинаково -- К.О. В счёт не идёт различитель, разумеется.
Другими словами, всё, что остаётся сделать, это правильно ввести различитель.
В таких случаях различитель может иметь несколько полей. Предлагаю три базовых поля.
Дата Да-да, именно дата (или дата/время) изменения -- главный различитель разных версий. Как его записать? Тут срабатывает правило про надкатегорию, по аналогии с разлечителем перед основным именем. Сначала пишут большие промежутки времени, потом меньшие. Год-месяц-день, как в Японии. Пример: 20111108154744 11 нобяря 2011 года, 15:47 и 44 секунды. Можно и с внутренними разделителями: 2011_11_08_15_47_44 Можно и с двоеточием и слэшем, но понадобится извратиться: придётся использовать ШИРОКИЕ двоеточия и слэши. В отличие от обычных, они разрешены к использованию в именах файлов. Кто не знает, что такое широкие, ищет в гугле.
Нумерация внутри одной даты Тут работает обычное правило с различителями. Например ДАТА-01, ДАТА-02. Если версии не бывают чаще раза в час, можно просто подключить два разряда времени.
Автор изменений Несколько букв позволят понять, кто создал последнюю версию. Это бывает важно, чтобы найти виноватого. Если вы работаете в одиночку, это теряет смысл.
Полный пример:
super_program_2011_11_08-01-VASYA.rar
Вместо даты и кода сегодняшней версии, разумеется, можно использовать сквозной номер: super_program_0167-VASYA.rar
Десерт: тэгирование Эта система нашла широкое применение. Заключается она во включение в имя (или не в имя) файла дополнительных сведений о возможных категоризациях об'екта. О тэгах шары можно долго петь песню, но об этом в другой раз. Применяется тэгирование и для разных об'ектов и для версий одного об'екта и для всего чего угодно. Разделяются тэги квадратными скобками, как правило. Главное требование, которое я советую соблюдать -- вписывать тэги в имя файла по алфавиту, чтобы при поиске можно было сразу указывать маску и не думать над порядком. Или надо установить жёсткий порядок обязательных тегов.
Пример: Есть файлы версий одной программы, обеспечивающей работу некоего научного (или ненаучного) прибора. Называется программа, допустим, KILL_THEM_ALL. Программа бывает двух модификаций -- профессиональная и любительская. Есть три разновидности прибора -- A, B, C, для каждого используются немножко другие функции. Программа бывает в виде бета-версии и в виде финальной версии. И есть специальные признаки -- для внутреннего пользования, нерабочая, версия для слепых. Классификации: Классификация 1, по возможностям: профессиональная [PRO], любительская [AMA] (amateur). Классификация 2, по разновидности прибора: A, B, C, соответственно, [A], [B], [C]. Классификация 3, по завершённости: beta -- [beta], final -- [final]. Это будут обязательные тэги. Признаки: Внутреннего пользования: [IN] (internal). Нерабочая: [NW] (not-work). Версия для слепых: [BL] (blind). Это будут необязательные теги.
Обязательные теги в указанном порядке пишем, необазательные в алфавитном. [PRO][B][FINAL]KILL_THEM_ALL-1.2.3[BL][NW]
Если мы хотим найти все версии для прибора B, маска поиска будет *[B]*, если беты для профессионалов -- [PRO]*[BETA]* (располагаем в оговоренном порядке). Если хотим найти версию для слепых для внутреннего пользования -- маска будет *[BL]*[IN]* (тэги в алфавитном порядке). Линуксоидам проще, у них регулярные выражения.
Применение подобных методик может существенно сократить время поиска нужных файлов. К сожалению, сам я не всегда им следую, но в тех случаях, когда я пользуюсь ими, результат ощутим. Пожалуйста, ознакомьтесь с комментариями!
Только что дошло, что каждый старается рассказать о том, в чём он специалист. И если надо, допустим, сказать общие слова по строению головы, отоларинголог будет в основном рассказывать про уши и носоглотку, а окулист -- почти только про глаза. Пример про медицину, но действует во всех областях человеческой деятельности.
Описано создание XOR-связного списка и его принципы работы. Описаны принципы работы динамических структур данных -- списков и деревьев (на примере двоичных деревьев).
В этой статье описывается создание так называемого XOR-связного списка, основаня идея которого заключается в том, что в каждом элементе списка хранятся не два адреса соседних элементов, а один псевдо-адрес, что является интересным алгоритмически решением и позволяет немного экономить память. Что такое указатель, объяснять не буду. Те, кто этого не знают, могут дальше не читать, им статья будет неинтересна.
1 Введение 1.1 Что такое динамические структуры данных? При работе с самыми различным данными программисты часто сталкиваются с тем, что на момент компиляции программы неизвестно, с каким объёмом данных предстоит работать. Придётся обработать нам всего один байт или пять мегабайт? Нет ответа. Хорошо, если данные хранятся в файле, их можно считывать кусками и нам пофиг, какого файл размера, лишь бы стандартные функции с ним работали. Иногда же приходится держать данные прямо в памяти. Однако многие компилируемые языки программирования не поддерживают возможность "на лету" изменять размеры массивов и подобных структур. Тут на помощь приходит динамическая память -- операционная система выдаёт куски памяти по запросу. Это является хорошим (и стандартным) решением, когда в определённый момент выполнения программы мы узнаём, сколько памяти нам нужно, и в дальнейшем этот объём не меняется. Так тоже бывает не всегда. Зачастую объём хранимых данных меняется прямо во время выполнения программы. Что же делать? Один из способов -- выделить новую память, переписать туда новую версию данных, удалить старую память. Пока данных мало, всё хорошо, но как только их становится много, операции копирования начинают занимать слишком много времени. Для работы с изменяющимся объёмами данных в памяти были придуманы так называемые "динамические структуры данных", позволяющие перемещаться по данным любого объёма, а также динамически менять общий объём данных не занимая полным копированием. Как этого можно достичь? Допустим, все данные разбиты на некоторые логические куски -- "элементы". Они могут быть разного размера, однако по смыслу они должны быть одним и тем же. Например, целые числа, строки, картинки. Хороший и достаточно общий пример элемента -- экземпляр какого-либо класса. Если мы для каждого элемента будем выделять память и складывать его туда, а при удалении освобождать память, которую он занимает, задача хранения данных будет решена (:, но непонятно, как по этим данным перемещаться. Можно, конечно, хранить указатели на каждый элемент в месте использования, ибо копировать-выделять массив указателей быстрее, чем совокупность всех элементов, но хотелось бы от этого копирования-выделения избавиться. Ключ к перемещению без полного копирования прост -- необходимо в каждом элементе хранить ссылки на ещё какие-то элементы (или на пустое место, если связи нет). Типичные динамические структуры данных -- списки и деревья. 1.2 Что такое списки и деревья? Поскольку основная часть посвящена спискам, начнём с деревьев, чтобы после списков перейти к основной теме. 1.2.1 Дерево (показать про дерево; это оффтопик фактически, так что скрываю) Оно называется дерево и имеет с ним некоторую аналогию. Дерево представляет собой ациклический граф. Подробнее об этом можно почитать в вики. Понятно, что дерево может быть n-ричным, но применительно к динамическим структурам данных будем рассматривать только двоичное дерево, как имеющее наибольшую практическую ценность. Не будем углубляться в математику, посмотрим просто как это работает. Забегая вперёд, скажу, что деревья очень хороши для поиска.
Обязательными полями для элемента двоичного дерева являются две ссылки на нижележащие элементы (будем называть их "левый" и "правый", хотя как называния, так и способ применения (см. ниже) не принципиальны, главное применять единообразно), а также так называемый "счётчик", на случай, если у нас будут несколько одинаковых элементов. Также необходимо придумать метод сравнения элементов, который должен отвечать следующим требованиям: 1. Если взять два произвольных элемента, один из них будет либо больше другого, либо меньше, либо равен. 2. Если два элемента по этому методу равны, то элементы являются полностью эквивалентными друг другу. Другими словами, сравнение двух элементов "по размеру" не подходит, так как могут быть несколько элементов не эквивалентных друг другу, но имеющих одинаковый размер. Гораздо лучше сравнение по какому-либо хэшу (например, md5), но у элементов и хэши могут совпасть! (хотя это уже вряд ли). Тут уже надо кропотливо думать. Сравнивать числа и строки, правда, очень просто. Признак, по которому мы сравниваем два элемента иногда называют "ключом" элемента. Есть другой метод. Можно ввести только операцию "меньше", тогда элементы с повторным ключом будут неотличимы от элементов, которые больше. Это необходимо, если возможны различные элементы с одинаковыми ключами. Если такое невозможно (т.к. ключи всегда различны для различных элементов), то у нас будет потенциальное дублирование данных.
1.2.1.1 Заполнение дерева Итак, в месте использования мы храним ровно один указатель на элемент, называемый "корнем дерева". Этот элемент либо есть, либо его нет. Если его нет, дерево пустое. Если мы добавляем элемент в пустое дерево, он становится корнем. Хотим добавить ещё один элемент и тут понимаем, что непонятно, как это следует сделать. Поскольку дерево двоичное, каждый элемент имеет по ДВА указателя на следующие элементы. Куда пихать? А если сделать так? Если новый элемент БОЛЬШЕ корневого, будем сохранять указатель на него СПРАВА (новый > старого, галочка смотрит вправо), а если МЕНЬШЕ -- СЛЕВА, а? Если место с этой стороны уже занято, перейдём по указателю и повторим процедуру с элементом ниже по уровню, пока не найдём пустое место. Если наткнёмся на элемент, который равен текущему, то останется только увеличить счётчик вхождений такого элемента на единицу. Приведу пример заполнения.
Пример 1. Итак, есть числа 7, 4, 9, 5, 2, 4, 3.
1. 7 -- идёт в корень. Уровень 0. 7 2. 4<7. Кладём слева. Уровень 0. 7 / Уровень 1. 4 3. 9>7. Кладём справа. Уровень 0. 7 / \ Уровень 1. 4 9 4. 5<7, но то место уже занято! Спускаемся к 4. 5>4 -- кладём справа от 4. Уровень 0. 7 / \ Уровень 1. 4 9 \ Уровень 2. 5 5. 2<7, 2<4. Уровень 0. 7 / \ Уровень 1. 4 9 / \ Уровень 2. 2 5 5. 4<7, 4=4. Увеличиваем ссылку Уровень 0. 7 / \ Уровень 1. 4(2)9 / \ Уровень 2. 2 5 6. 3<7, 3<4, 3>2. Уровень 0. 7 / \ Уровень 1. 4(2)9 / \ Уровень 2. 2 5 \ Уровень 3. 3
Как заполнять дерево, вроде понятно. А как удалять? 1.2.1.2 Удаление элемента из дерева а) если счётчик больше 1, просто уменьшаем его б) Если мы хотим удалить элемент, у которого нет ссылок на более нижние уровни, всё понятно -- данные удаляются, ссылка, которая ссылалась на него, устанавливается в значение "пусто". в) Если только с одной стороны есть более нижние уровни, элемент удаляем, единственный из двух возможных более нижних элементов, прицепляем вместо удалённого, чтобы верхний ссылался на него. г) Если есть оба более нижних элемента, всё становится печально. Надо найти им новый родительский элемент, при этом следует учесть, что нельзя нарушить порядка больше-меньше, иначе дерево потеряет смысл (о смысле см. далее). Кто же подойдёт на эту роль? Элемент должен быть меньше любого элемента справа, но больше любого элемента слева! Найдём самый левый элемент правого поддерева. Это -- его наименьший элемент. Если его удалить по вышеописанному алгоритму (тут понятно, что один из пунктов "б","в" сработает, ибо "г" бы означал, что это не самый левый элемент, про пункт "а" см. далее)), спрятав данные у себя, то он станет меньше любого элемента в правом поддерева. А то, что он больше любого элемента левого поддерева и так понятно, ведь иначе бы он в нём и находился! Следует учесть, что забирать данные надо вместе со счётчиком а удалять надо все экземпляры (поэтому удаление по пункту "а" никогда не будет), ибо если перенести только один экземлпяр, у нас будет несколько равных элементов в разных местах, этого быть не должно. Данные удаляемого элемента удаляем, а спрятанные пишем вместо них. Вуаля. Пример 2.
Уровень 0. 5 / \ Уровень 1. 3 8 / \ Уровень 2. 6 9 \ Уровень 3. 7 Хотим удалить корень дерева. 1. Придётся работать по пункту "г". В правом поддереве самый левый элемент это 6, копируем к себе (6) и удаляем (работает пункт "в"). Уровень 0. 5 / \ Уровень 1. 3 8 / \ Уровень 2. 7 9 2. Удаляем данные корня, вместо них пишем то, что было в загашнике. Уровень 0. 6 / \ Уровень 1. 3 8 / \ Уровень 2. 7 9 Как видно, порядок больше-меньше не нарушился.
Очевидно, что в случае "г" можно переносить на место удаляемого не только самый левый элемент из правого поддерева, но и самый правый элемент из левого поддерева. 1.2.1.3 Зачем всё это нужно. Поиск и обход дерева Так как мы уже при заполнении определили, кто больше, а кто меньше, поиск превращается в тривиальную задачу, при которой, в добавок, не нужно осматривать все элементы.
Пример 3. Допустим, в дереве из предыдущего примера (до удаления) хотим найти 7.
Уровень 0. 5 / \ Уровень 1. 3 8 / \ Уровень 2. 6 9 \ Уровень 3. 7
1. 7>5, перешли вправо. 2. 7<8, перешли влево. 3. 7>6, перешли вправо. Вот оно! Конец. Разумеется, в нашем примере такой поиск бессмысленен и беспощаден, поскольку наши данные и есть ключ. Если же к нашему числу прилеплено ещё пять мегабайт фигни, смысл очень большой: 1. Мы сравниваем данные только по ключам, а не целиком. 2. Мы просматриваем только часть данных (3 проверки при 6 элементах). Если надо пробежать по всем элементам, делается это следующим образом. 1. Сначала обрабатываем всё, что слева, потом себя, потом всё, что справа. 2. Спустившись на уровень ниже, повторяем пункт 1. Понятно, что мы имеем дело с рекурсией и понятно, что мы обработаем данные в порядке возрастания. Аналогично можно придумать обработку и в порядке убывания. Менее кустарно об этом можно прочитать тут.
К достоинствам дерева можно отнести авто-упорядочивание и быстрый поиск. К недостаткам относится наличие рекурсии (вы заметили? (: ), что ведёт к неконтролируемому использованию стека. К потенциальным недостаткам можно отнести следующую ситуацию. При добавлении уже упорядоченных данных, они будут добавляться всё время с одной и той же стороны дерева, превращая её В СПИСОК (см. далее)! Это называется "разбалансировка", лечится "балансировкой". Короче, надо следить, чтобы дерево было сбалансированным, т.е. слева и справа примерно одинаковое число элементов. 1.2.2 Списки Список -- это проще чем дерево. (: В списке все элементы хранятся последовательно, при этом в каждом есть одна или две ссылки на другие элементы. По направленности списки делятся на: -- однонаправленные; -- двунаправленные. По цикличности списки делятся на -- циклические (циклические); -- ациклические (= (линейные). В однонаправленных ссылка одна и перемещаться можно только вперёд. Как акула. В месте использования надо хранить указатель на один из элементов, желательно первый (а если список ациклический, то обязательно на первый!). В двунаправленных ссылки две -- на предыдущий и на следующий элемент. В циклических списках последний элемент ссылается на первый, в ациклических у последнего в ссылке на следующий стоит "пусто" и у первого в ссылке на предыдущий (если она есть) стоит "пусто". Необходимость использования того или иного типа списка определяется формулировкой задачи. Добавление элемента в список (в конец или в середину) заключается в следующем: 1. Указатель "следующий" старого-предыдущего (если он есть) элемента начинает указывать на новый; 2. Указатель "предыдущий" (если он есть) старого-следующего элемента (если он есть) начинает указывать на новый; 3. Указатели "следующий" и "предыдущий" (если они есть) нового начинают указывать на старый-следующий и старый-предыдущий соответственно. Если следующего/предыдущего элемента нет, в соответствующие указатели нового элемента устанавливается "пусто". Удаление происходит следующим образом. 1. Указатель "следующий" предыдущего элемента начинают указывать на следующий после удаляемого элемент (если он есть; иначе -- "пусто"); 2. Указатель "предыдущий" (если он есть) следующего элемента (если он есть) начинает указывать на предыдущий перед удаляемым элемент (если он есть; иначе -- "пусто"); 3. Удаляемый элемент удаляется и идёт лесом. Перемещение по списку превращается в детскую забаву -- знай себе, переходи по указателю. А поиск только последовательным просмотром. Такие дела. 2 XOR-связный список 2.1 Что такое XOR и с чем его едят С давних времён в программировании и дискретной математике применяются логические (в том числе побитовые) операции. XOR ("исключающее или", "сложение по модулю два", "строгая дизъюнкция" -- одна из них, причём она обладает некоторыми интересным свойствами. Таблица истинности для неё выглядит следующим образом:
Другими словами, для двух логических значений x1 и x2 на выходе "истина", если истенен только один из операндов. Если оба истинны или оба ложны, получается ложь. 2.2 Что такое побитовая операция Операция с двумя операндами называется побитовой, если она проводится над соответствующими битами обоих операндов и записывается в бит с тем же самым номером на выход, при этом соседние биты не затрагиваются. Пример 4. Вычислим побитовое XOR двух двоичных чисел (8-битных байт):
01110010 11010001 ------- 10100011
2.3 Области применения XOR Ну, во первых, это несложное шифрование. Пусть есть сообщение A и ключ шифрования K такой же длины (в битах). Проведём XOR: A XOR K =A1. Очевидно, что если ключ ненулевой, то на выходе будет не то же, что на входе, т.е. данные изменились. Как их достать обратно? Проведём XOR тем же ключом ещё раз! ((A XOR K) XOR K) = A XOR (K XOR K) = A XOR 0 = A. Получили исходное значение. K XOR K = 0, поскольку одинаковые биты первого и второго операнда зануляются (таблица истинности, см. 2.1), а они все одинаковые, значит на выходе 0. A XOR 0 = A, поскольку XOR и истины и лжи с ложью равен исходному значению по таблице истинности, а второе значение состоит целиком и лжи (нолики). Пример 5.
01110010 -- сообщение 11010001 -- ключ ------- 10100011 -- зашифрованное сообщение ---------------------------------------------- 10100011 -- зашифрованное сообщение 11010001 -- ключ -------- 01110010 -- исходное сообщение
Вторая область применения -- это зануление. Дело в том, что операция переноса данных в процессоре гораздо медленнее, чем логическая. Сделать же регистр равным нулю -- довольно распространённая задача. Если решать в лоб, то надо делать так:
MOV AX, 0
Если подумать, то быстрее делать так:
XOR AX, AX
Что исключающее или числа самого с собой равно нулю, мы выяснили выше. Некоторые процессоры, однако, имеют встроенную команду зануления регистра. Может быть можно ещё что-нибудь интересное придумать с XOR? 2.4 Применимость XOR к двунаправленным спискам. Давайте возьмём случай с шифрованием, и рассмотрим один интересный момент: если сделать XOR между исходным сообщением и зашифрованным, получается ключ! Смотрите: A XOR A1= A XOR (A XOR K)= (A XOR A) XOR K = 0 XOR K = K. Теперь давайте вместо A, A1, K писать C1, C2, U (соответственно). Получим: C1 XOR C2 = U U XOR C1 = C2 U XOR C2 = C1 Что же получается-то? Если у нас есть два абстрактных числа, то зная их XOR и одно из чисел, можно найти второе.
Если у нас есть двусвязный список, в нём хранятся адреса следующего и предыдущего элементов. Если хранить их XOR, то зная адрес следующего элемента, можно вычислить адрес предыдущего и наоборот. В дальнейшем XOR-псевдоадрес будем называть "ёж".
Итак, пусть у нас есть пять элементов, при этом их адреса будем обозначать Ai, а ежи -- Ui. Жирным обозначено, когда связь переходит через конец списка, палочки обозначают XOR чего и чего в еже. Кружочки -- сами элементы.
Во избежание проблем будем считать список циклически. Тогда: U1 = A5 XOR A2 U2 = A1 XOR A3 U3 = A2 XOR A4 U4 = A3 XOR A5 U5 = A4 XOR A1
Пусть нам известны адреса 3 и 4 элемента. Мы хотим узнать, что было до и после них. До: берём ёж третьего элемента и делаем исключающее или с адресом четвёртого: U3 XOR A4 = (A3 XOR A4) XOR A4 = A3 XOR (A4 XOR A4) = A3. После: берём ёж четвёртого элемента и делаем исключающее или с адресом третьего: U4 XOR A3 = (A3 XOR A5) XOR A3 = A5 XOR (A3 XOR A3) = A5. Оно работает! А как добавить элемент? Хотим добавить элемент X после A2. Ёж нового элемента -- это просто исключающее или его новых соседей. А вот их ежи придётся пересчитать: UX= A2 XOR A3 U2'=A1 XOR AX U3'=AX XOR A4
2.5 Ежиная арифметика Адрес XOR Адрес = Ёж Ёж XOR Адрес = Адрес Адрес XOR Ёж = Адрес Ёж XOR Ёж =? Не имеет смысла
2.6 Особенности XOR-связного списка 1. Поскольку надо знать сразу два элемента (последовательных), вместо одного указателя на текущий элемент списка, придётся хранить ещё указатель на следующий (предыдущий). 2. Усложнённая арифметика: навигация по списку становится дольше. 3. В каждом элементе хранится только один ёж, а не два адреса, поэтому можно экономить память. Нужна ли такая экономия -- зависит от формулировки задачи.
2.7 Реализация алгоритма Проще всего организовать класс, который будет всем этим заниматься. Пример реализации такого класса вместе с демонстрационной программой представлен в Приложении 1.
3 Заключение XOR-связный список позволяет экономить память, однако из-за усложнённой арифметики переходы происходят дольше, что может быть неприемлемо для критичных к времени задач. Необходимость хранить для перемещения по списку адреса сразу двух элементов (текущего и соседнего с ним) может затруднять чтение листингов, однако если реализовать библиотеку или класс, предназначенные специально для работы с таким списком, работа с ним может быть абсолютно прозрачной и ничем не отличаться от работы с другими списками.
Описана придуманная мной методика проведения абстрактного экзамена.
Сколько не сдаю экзамены, самые разные, убеждаюсь в том, что единственный общий атрибут для всех экзаменов -- выставление оценки. Оценки всегда бывают двух видов -- удовлетворительные и неудовлетворительные (и тех и других может быть несколько).
Когда-то (на тот случай, если мне вдруг придётся принимать какой-нибудь экзамен), я задумался над идеальным алгоритмом проведения экзамена. (читать дальше)Отвечать он должен был двум критериям (тогда я о критериях не задумывался, разумеется): 1) Преподаватель должен получить оценку своему труду 2) Экзаменуемому не надо мешать жить. Если принимает не тот же, кто учил, то первый критерий имеет смысл лишь частично -- если тот, кто учил, узнает мнение экзаменатора о сдающих ("внутренняя ведомость").
Я придумал следующий алгоритм. 1. Экзаменуемые получают экзаменационные задания. 2. Готовятся. Пользоваться можно всем. 3. Экзаменуемые по очереди отвечают. После ответа им выставляется та оценка, которую они желают.
Этот алгоритм обладает существенным недостатком, а именно первый критерий выполняется слабо. Тяжело оценивать свой труд, когда все готовятся по литературе/конспектам.
Недавно я придумал другой, усовершенствованный алгоритм. Он отвечает первому критерию. Сдача состоит из четырёх фаз. 1. Подготовка. Все экзаменуемые готовятся. Пользоваться дополнительными источниками знаний запрещено. Если ловят на списывании, то либо сразу выгоняют, либо запрет на фазы 3 и 4. 2. Ответ. В конце ответа экзаменуемый называет желаемую оценку. Если экзаменатор считает, что экзаменуемый на неё (или выше неё) ответил, желаемая оценка выставляется, до свидания. Если экзаменуемый ответил хуже чем хочет, переходим к фазе 3. Также тут возможно занесение оценки во внутреннюю ведомость экзаменатора, для себя (если он и учил), либо для преподавателя. Вышестоящие инстанции об этой оценке не знают. 3. Экзаменуемый идёт на дополнительную подготовку. Теперь уже можно пользоваться всем, включая головы тех кто на 3+ фазах или уже сдал (или кого выгнали). 4. Экзаменуемый отвечает ещё раз. Если и во второй раз он ответил хуже чем хочет, переходит опять к фазе 3.
Экзаменационные задания (вопросы) могут быть любыми, но не должны сменяться в процессе экзамена, то есть экзаменуемый всё время отвечает экзаменатору одни и те же задания. Экзаменуемые фаз 3 и 4 пересаживаются на отдельный ряд подальше от остальных или вообще выгоняются за пределы помещения, где проходит экзамен -- "внешняя подготовка".
Первые две фазы призваны обеспечить первый критерий, а вторые две -- второй. Этот алгоритм с точки зрения поставленных условий гораздо лучше, но и он не лишён недостатков, а именно: 1. Дыра: если экзаменуемый не хочет готовиться (причём речь идёт и о подготовке к экзамену, и о подготовке к ответу), он может пойти отвечать с пустым листом, помолчать и перейти на фазу 3. 2. Дыра: если экзаменуемый хочет задавить экзаменатора терпеливостью, т.е. продолжать отвечать плохо, желая хорошую оценку, экзамен может затянуться надолго. 3. Кто же будет готовиться, если известно, что оценка будет желаемой? Только совесть может заставить готовиться. Да, можно не сообщать экзаменуемым о способе проведения экзамена, но это нечестно и прокатит только один раз, поскольку экзаменуемые, которые придут сдавать экзамен после (из параллельных групп или те, которые придут через год -- если речь о классических экзаменах в институте), смогут узнать у уже сдавших.
А как бы экзамен провели вы, если бы вам пришлось это сделать? Пожалуйста, ознакомьтесь с комментариями!
Реструктуризация, от основ к специфике, в восемь пунктов!
1. Реструктуризация -- изменение структуры. Связи, связывавшие раньше части системы частично или полностью разрушаются, устанавливаются новые. Части системы также могут быть удалены, добавлены, переразбиты. 2. Можно ли считать добавление в систему новых сущностей реструктуризацией -- мне неизвестно. Скорее всего, да. 3. Реструктуризация может быть проведена проведена над большим числом систем (скорее всего, над любой системой) -- это правительства, организации, комплексы оборудования (связанные единой задачей), программы в конце концов (обычно для программ называют "рефакторинг"). 4. Реструктуризация бывает внутренней и внешней. После внутренней внешнее поведение системы не изменяется. После внешней у системы могут появиться, например, новые возможности (или пропасть старые). 5. Да, это не всегда возможно, но реструктурировать систему надо как можно раньше. Чем дольше работает система, тем сложнее это будет сделать. Желательно проектировать её так, чтобы реструктуризация не понадобилась. Либо реструктуризацию проводить ещё на бумаге, когда ещё нечему функционировать (что входит в проектирование). Однако если вы руководите/поддерживаете систему довольно долго, рано или поздно ситуация изменится и придётся что-то переделывать. 6. Самое главное, задуматься над вопросом целесообразности реструктуризации. После неё всё может стать хуже. 7. Грамотно спланированная реструктуризация может быть почти безболезненной, но на время её проведения всё равно наблюдается ухудшение функционирования системы, вплоть до полной парализации. 8. Под реструктуризацию часто дают дополнительное финансирование. Бывает, что на реструктуризацию уходят не все деньги. Куда деваются остальные -- сложный вопрос.
Хороший пример реструктуризации -- переделка дорожных развязок. Когда поток на регулируемом светофорном перекрёстке (крестовом) становится слишком большим, ставят многоуровневую развязку (например, "клевер"). На время ремонта перекрёсток может быть даже полностью заблокирован. Зато после этого проезд во все стороны становится проще и потоки не пересекаются, что уменьшает время проезда развязки. Однако, если была построена более сложная развазка, предназначенная для различной нагрузки с разных направлений, причём построена была не той стороной, приходит северный пушной зверёк. Налицо ошибка проектирования. Надо реструктурировать заново.
P.S. Я конечно всё так круто написал, но лично проводил только рефакторинг кода. Остальное по наблюдениям.
Я смотрю, у многих устройства и компьютеры не в курсе нововведений и перевели часы куда не надо. Согласно некоторым сведениям, это породило кучу опозданий и так далее. Меня даже спрашивали (в похожей формулировке) "Сколько сейчас времени, чёрт возьми?".
А я с троллфейсом говорил сколько времени. Я знал.
Потому что у меня на компьютере уже несколько лет работает шара (EN), которой для работы необходимо токийское время. И на компьютере тоже токийское время. Японии время не переводит. Да, переводила, С 1946 по 1952 год. Но тогда ещё не было устройств, которые бы делали это автоматически.
Другими словами, мне это только удобнее, не надо перевод токийского времени в московское в моём мозгу переключать. Хотя зимнее время с точки зрения перевода в мозгу было удобнее, т.к. разница составляла 6 часов, а 6 часов прибавлять/вычитать проще, чем 5.
Оригинал Про композитора Произведение является представителем изобретённой композитором "«меблировочной музыки», которую не надо специально слушать, ненавязчивой мелодии, звучащей в магазине или на выставке."(С). Правда в нынешних магазинах такого не пускают. На выставке Дали тоже на фоне была какая-то муть, а в магазинах обычно пускают радио.
Как ни странно, в аниме очень популярна эта мелодия. Почему, мне неизвестно. Возможно, её слышали и вы. Нашёл уже четыре места, где она есть: 1) Tooi Sekai Макото Синкая Video of this (LQ) 2) 15-й эпизод Colorful Video of this 3) Трейлер "Исчезновения Харухи Судзумии" Video of this 4) 12-й эпизод Love Hina Video of this Ссылки на видео приведены с промоткой до тех мест, где начинается мелодия.
th13_udzh11.rpy: TOUHOU13 EXTRA Reimu 129820760 1CC от 2011/10/28 2 экстенда, 4 бомб-экстенда, 4 мисса, 12 бомб (2 дес-бомбы), 5 карт из 13 поймано. 2 бомбы профукал. Это моя первая полностью самостоятельно разобранная экстра, в остальных случаях я видел реплеи до прохождения. Из "обычных" данмаку-игр я ещё не видел экстру 12-й, 2-4-5-9-10-11, к сожалению, видел уже, так что самостоятельно смогу разобрать только ещё 12-ю. Кстати, можно получить 3 экстенда, но надо очень постараться Replay of this (текущий мировой рекорд по очкам) Комментарии Часть А (от начала до мидбосса): по плану прохождения надо запускать транс после 4-го выстрела в 3 ряда (там есть выстрелы в 1, 2, 3, 4 ряда) 1-й спелл: оказывается лучше доджить только горизонтально, так чаще ловится 2-й спелл: всегда бомблю; почти 3-й спелл: - Часть Б (от мидбосса до босса): по плану прохождения -- феи с тремя кусками бомб обслуживаются бомбой же, а семь фей с кусками бомб и жизней -- трансом 4-й спелл: сначала показался очень сложным, но таковым не является 5-й спелл: ого, вертикальный стриминг; там правда ещё одна такая карта есть 6-й спелл:- 7-й спелл: можно было дальше доджить, но забомбил на всякий случай, т.к. транс был по плану нужен для следующей карты 8-й спелл: протрансил 9-й спелл: трюк в том, чтобы во время выстрела человечков стоять в одном ряду с ними а потом сразу подниматься, после этого разлетающие пули будут лететь по горизонтали (почти) и доджить почти не придётся; но все равно забомбил 10-й спелл: адский спелл 11-й спелл: подумал, что забомбив можно почистить поле от лягушек, которые стреляют жёлтыми карточкми, так будет проще; и правда 12-й спелл: протупил 2 бомбы и ещё сдох в конце, в итоге на последний спелл пришёл с 0 жизней и 2 бомбами -- ААА! 13-й спелл: тут я уже особо ни на что не надеялся, а когда спелл перешёл в финальную фазу, тем более ни на что не надеялся, т.к. бомбы уже израсходовал; когда услыша низкий гул (такой издаётся перед самым подыханием босса), я очень сильно удивился, а при финальном замедлении успел подумать "так, аккуратненько, аккуратненько, чтобы не вышло MAMIZOU IS NOT GOOD GIRL AT ALL" (что это значит, ищите на я-трубе). Таки прошёл.
Напоминаю, что Футацуива Мамидзо: второй персонаж в очках после Рикако и очередной с портативной бутылкой сакэ. Тут стало понятно, откуда в атаках человечки -- просто она упилась до чёртиков.
Изначально эти человечки и прочая вызывали ассоциацию с Конан Дойлем -- вот вам и пляшущие человечки и собака Баскервилей Показать
пляшущие человечки собаки баскервилей этюд в багровых тонах
А изображение босса вызвало недоумение -- она же наркоманка с выпученными скошенными глазами! А потом я понял, что это просто очки, а не белки глаз. Успокоился.
Всегда любил Сбербанк. Хороший он. Зелёный. С очередями встречался редко (потому что не в то время прихожу). Обслуживание всегда было адекватное. Возможно, мне просто везло?
И была касса в доме напротив, в пяти минутах ходьбы. И был у неё чудо-банкомат -- в помещении отдельном со входом по карточке. То есть не на улицу банкомат смотрит, как обычно, а дверь с кард-ридером, суёшь карточку, дверь открывается. Внутри помещение, где банкомат и больше ничего. Это гораздо безопаснее, чем банкомат на улице.
А потом кассу вместе с банкоматом закрыли на ремонт. Следующая ближайшая касса расположена уже в 20-30 минутах ходьбы или 15 минутах езды (ещё одна, другая). Стало очень неудобно. Ремонтировали 4-5 месяцев. В процессе ремонта замуровали дверь отдельного банкомата. Ну всё, думаю, сделают как обычно, уличный банкомат. Когда открыли, оказлось, что уличный банкомат так и не сделали. Зашёл в саму кассу посмотреть. Внутри самой кассы стоял 1 банкомат (все операции) и 1 терминал (без выдачи наличных). Меня спросили, что я хочу? Я ответил -- ничего. Мне сказали, что это хорошо! Я сказал, что просто посмотреть пришёл, как тут сделали и покинул помещение.
А оказалось, что помещение с банкоматом отдельное таки есть, его перенесли туда, где раньше был отдел обслуживания юридических лиц. Принцип тот же, только внутри не 1 банкомат, как раньше, а 2 банкомата полноценных и 2 терминала. Это и лучше и хуже, т.к. больше клиентов можно одновременно обслуживать, хотя с приватностью проблемы. На банкоматах почти везде уже стоит новое ПО, которое уже год отлаживается -- глюков всё меньше и меньше. Из положительных моментов хотелось бы отметить контекстные услуги, напирмер, снимаешь деньги, а он пишет "оставить заявку на получение кредитной карты", или платишь за интернет/телефон, а он пишет "подключить автоплатежи". А ещё они стали запоминать телефоны, на которые я деньги клал и теперь можно одним кликом повторно класть на те же номера. Причём запоминание номеров сделали раньше, чем список телефонов, то есть когда список появился, он уже знал номера, на которые я клал деньги.
Выглядит всё круто и ново (мне понравилось), однако есть одна странная особенность. Операционистки (да-да, вы заметили? Операции проводят исключительно женщины. Интересно, во всех банках так?) теперь не отделены от клиентов стеклом с переговорной дыркой/устройством. Это зло, причём сразу по двум причинам: 1) грабители 2) заразные и плюющиеся клиенты. И если проблема 1) сомнительна, так как в наше время есть много более других менее опасных способов получит деньги (в том числе и нелегальных), то 2) по полной программе. Интересно, что будут делать с повышенной заболеваемостью работников.
И про ребрендеринг Сбербанка -- это, наверное, самый дорогой Pan & Zoom в графическом редакторе, который я видел.
Началось это ещё при Лужкове. Самое смешное, что я видел примерно одного инвалида, который этим местом воспользовался. В основном используют их мамы с детьми в колясках. Это очень хорошо -- представляете, колясочного ребёнка теперь можно повезти почти куда угодно, ведь места такие есть почти во всех автобусах.
Есть, правда, проблема -- добавление этих мест уменьшает число сидячих мест. Вторая сторона медали -- эти места (когда не заняты) увеличивают число стоячих мест, так что общее число людей, которые влезают в автобус, всё-таки становится больше.
Разработчики автобусов решили добавить возможность выбора. На местах для инвалидов сделали откидные сиденья. По два на каждое. То есть +2-4 места на автобус. Сомнительно, ну и чёрт с ним.
Просто это ещё не всё. Некоторые гении мысли сделали доп. откидные места в виде лавочки сбоку. Откидываются сиденья по одному, всего их три. Я подумал -- о, как прикольно, решил проехаться. Откинул и сел. Если коротко -- очень неудобно. Ограничителей по бокам у сидений нет (и быть не может, они же откидные!), поэтому любое ускорение-торможение, если вы сидите на крайних местах приводит к риску сползаний с сидения (а автобусы дёргаются сильнее, чем метропоезда, где сиденья сбоку все, да ещё и с ограничителями). До поручня лететь ещё около метра. Спинка на три сидения общая и опереться на неё можно только частью спины в диапазоне от 10 до 40 сантиметров от основания шеи.
В одних интернет-магазинах чем больше стоимость заказа тем меньше стоимость доставки! А в других интернет-магазинах чем больше стоимость заказа тем больше стоимость доставки!
Итак, я хотел посмотреть Freezing. Можно было скачать: 1. ТВ-рип с цензурой. 2. ТВ-рип без цензуры, но всё, кроме заставок -- 4:3 (поля чёрные сбоку). 3. Три блю-рей рипа. Один 34 гига, другой 33, тетий 22 гигов.
Тяжёлый выбор. Я полёз в шару и нашёл там рип всего на 14.5 гигов. Ладно, замнём для ясности.
Интересно, но слишком Ева. Поставил мангу качаться, надо посмотреть, что там было. Ну главная героиня, конечно, няшка -- она в очках и её озвучивает Ното Мамико...