All streams
Search
Write a publication
Pull to refresh
1940
296.4

Переводчик-фрилансер

Send message

Два лагеря C++

Level of difficultyEasy
Reading time9 min
Views20K

Сейчас ведётся много споров и дискуссий о будущем C++.

Не только на Reddit и одном оранжевом веб-сайте, но и совершенно точно на официальных заседаниях комитета по стандарту C++.

Абсолютное состояние (языка C++)

Похоже, мы находимся в следующей ситуации:

Evolution Working Group (EWG) языка C++ как раз достигла консенсуса по внедрению P3466 R0 - (Re)affirm design principles for future C++ evolution:

Это означает отсутствие поломок ABI, сохранение совместимости компоновки с кодом на C и предыдущими версиями C++.

Также это означает отсутствие «виральных аннотаций» (например, аннотаций времени жизни).

Удвоение усилий по множеству несовместимых задач, например, отсутствия поломок ABI и принципа zero overhead.

Плохо это или хорошо, но это (в буквальном смысле) удвоение усилий по развитию текущей траектории языка C++.

Читать далее

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

Level of difficultyEasy
Reading time11 min
Views4.8K

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

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

Одна из проблем заключается в том, что для преобразования перехваченных сырых данных печати в растровое изображение требуется достаточно долгая настройка. В каком-то оборудовании применяется HP PCL, в другом — Encapsulated Postscript (EPS), а если повезёт, то вывод будет в стандартном растровом формате наподобие PCX.

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

Возможно, пост будет не очень полезен остальным людям, но, может, кому-то он пригодится при гуглении… Как всегда, я работаю с Linux, что сказывается на ПО.

Читать далее

Ломаем капчу 4Chan

Level of difficultyEasy
Reading time10 min
Views5.6K

Этот проект начинался как обучающий: я хотел углубить свои знания в машинном обучении, и в частности в TensorFlow. В конечном итоге мне хотелось получить работающую в браузере модель машинного обучения, которая смогла бы надёжным образом (с точностью не менее 80%, а предпочтительно >90%) решала капчу 4Chan. Я достиг этих целей и расскажу в статье, каким образом мне это удалось!

Код я опубликовал на GitHub.

Читать далее

Создаём пасьянс для забытой периферии Nintendo

Level of difficultyMedium
Reading time11 min
Views2.8K

Недавно я закончил создание пасьянса для Nintendo E-Reader. Мне удалось уместить его на одной карте, и это практически полнофункциональная версия игры. Я очень доволен тем, что получилось.

Что такое E-Reader?

E-Reader — это периферийное устройство для Game Boy Advance, выпущенное компанией Nintendo в 2002 году. Сканируя карты, где есть полоска с кодом из точек, можно загружать мини-игры, дополнительные уровни, анимации и так далее.

Читать далее

Почему LLM так плохо играют в шахматы (и что с этим делать)

Level of difficultyEasy
Reading time14 min
Views11K

В своём последнем посте я говорил об одной загадке: все большие языковые модели (LLM) ужасно играют в шахматы. Все, за исключением gpt-3.5-turbo-instruct, которая по какой-то причине умеет играть на уровне продвинутого любителя. И это несмотря на то, что этой модели больше года и она намного меньше новых моделей. Что происходит?

Я предложил четыре возможных объяснения:

Теория 1: достаточно большие базовые модели хороши в шахматах, но это свойство не сохраняется после их подстройки под чат-модели.

Теория 2: по какой-то причине gpt-3.5-turbo-instruct обучали на большем объёме шахматных данных.

Теория 3: в некоторых архитектурах LLM есть нечто магическое.

Теория 4: существует «конкуренция» между разными типами данных, поэтому чтобы LLM могла хорошо играть в шахматы, большая доля данных должна быть информацией о шахматных партиях.

В Интернете нашлось ещё множество других теорий. Самые распространённые из них:

Теория 5: OpenAI жульничает.

Теория 6: на самом деле LLM не могут играть в шахматы.

Я провёл новые эксперименты. Хорошие новости — ошибались все!

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

Читать далее

Разбираем алгоритм полнотекстового поиска BM25

Level of difficultyEasy
Reading time8 min
Views8.7K

BM25, или Best Match 25 — это широко используемый алгоритм полнотекстового поиска. Среди прочего, он по умолчанию применяется в Lucene/Elasticsearch и SQLite. В последнее время в рамках «гибридного поиска» часто начали комбинировать полнотекстовый поиск и поиск по схожести векторов. Мне захотелось понять, как работает полнотекстовый поиск и в частности BM25, поэтому в этой статье я постараюсь разобраться в этом.

Читать далее

Эффект матового стекла для веба

Level of difficultyEasy
Reading time12 min
Views12K

В процессе разработки UI для игр Forza Horizon 3 и Forza Motorsport 7 я имел возможность поработать с потрясающими акриловыми матовыми элементами дизайна.

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

Читать далее

Ломаем хэши CityHash64, MurmurHash2/3, wyhash и не только…

Level of difficultyEasy
Reading time20 min
Views5.7K

Хэш-функции — невероятно красивые математические объекты. Они могут отображать произвольные данные на небольшую область выходных данных фиксированного размера таким образом, что отображение оказывается детерминированным, хоть и кажется случайным. Такая «детерминированная случайность» невероятно полезна для широкого спектра применений, например, для хэш-таблицконтрольных суммалгоритмов Монте-Карло, распределённых алгоритмов без коммуникаций и так далее.

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

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

cityhash64("orlp-cityhash64-D-:K5yx*zkgaaaaa") == 1337 murmurhash2("orlp-murmurhash64-bkiaaa&JInaNcZ") == 1337 murmurhash3("orlp-murmurhash3_x86_32-haaaPa*+") == 1337 farmhash64("orlp-farmhash64-/v^CqdPvziuheaaa") == 1337

Также я покажу, как можно создавать очень специфичные пары строк, которые можно произвольно конкатенировать таким образом, что при конкатенации k строк любая из 2k комбинаций будет иметь одинаковый хэш вне зависимости от использованного для хэш-функции порождающего значения (seed):

a = "xx0rlpx!xxsXъВ" b = "xxsXъВxx0rlpx!"
murmurhash2(a + a, seed) == murmurhash2(a + b, seed)
murmurhash2(a + a, seed) == murmurhash2(b + a, seed)
murmurhash2(a + a, seed) == murmurhash2(b + b, seed)
a = "!&orlpՓ" b = "yǏglp$X"
murmurhash3(a + a, seed) == murmurhash3(a + b, seed)
murmurhash3(a + a, seed) == murmurhash3(b + a, seed)
murmurhash3(a + a, seed) == murmurhash3(b + b, seed)

Читать далее

Реализация алгоритма двумерной упаковки Skyline

Level of difficultyEasy
Reading time9 min
Views1.7K

Упаковка 2D-прямоугольников в прямоугольники большего фиксированного размера необходима в большинстве мультимедийных проектов. В программировании GPU изменение текстур (binding) — затратный процесс. Поэтому при рендеринге текста не стоит использовать по одной текстуре на глиф, вместо этого желательно упаковать глифы в единую текстуру, называемую атласом. В 2D-играх содержащие спрайты атласы называются листами спрайтов (spritesheet). Листы спрайтов также используются для веб-сайтов, потому что скачивать один большой файл удобнее, чем по одному файлу на каждый значок/логотип.

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

Самым ценным ресурсом из найденных мной стал превосходный обзор Юкки Йулянки. В нём описано четыре типа алгоритмов и их практическая оценка. Выделяются из них два:

MAXRECTS если вы знаете заранее, какие прямоугольники будете упаковывать («офлайн-упаковка»)

SKYLINE если не знаете («онлайн-упаковка»)

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

Именно поэтому я остановился на алгоритме skyline. Он применяется в stb_rect_pack.hfontstash, а значит, и в nanovg.

В этой статье объяснён алгоритм skyline и представлена его реализация. Реализация доступна онлайн и в общественном достоянии (UNLICENSE).

Читать далее

Почему при установке Windows 95 использовались три операционные системы?

Level of difficultyEasy
Reading time3 min
Views41K

Пользователь Twitter @tthirtle спросил, почему установка Windows 95 проходит через три операционные системы: MS-DOS, Windows 3.1, а уже потом Windows 95. Почему не перейти от MS-DOS сразу к Windows 95?

Ещё один хороший вопрос: почему в установке Windows 95 используется три разных UI. DOS, Win3.x и Win9x?

— Thomas (@tthirtle) July 7, 2024

Установка Windows 95 может быть апгрейдом с трёх начальных точек: MS-DOS, Windows 3.1 или Windows 95. (Да, можно проапгрейдить Windows 95 до Windows 95. Это может понадобиться для того, чтобы восстановить повреждённую систему и сохранить при этом данные.)

Один из вариантов решения — написать три версии установки Windows 95: одна для установки из MS-DOS, другая для установки из Windows 3.1 и третья для установки из Windows 95.

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

Читать далее

Проверяем фактор автобуса для опенсорсных проектов

Level of difficultyEasy
Reading time5 min
Views2.4K

Из Википедии: фактор автобуса (англ. bus factor, либо truck factor) проекта — это мера сосредоточения информации среди отдельных членов проекта; фактор показывает количество участников проекта, после потери которых (в оригинале — «попадания» которых под автобус или грузовик, варианты: увольнения, заболевания, рождения у них ребёнка, наступления несчастного случая и других форс-мажорных обстоятельств) проект не сможет быть завершён оставшимися участниками.

Мотивация

Во всех компаниях, где я работал (в строительстве и разработке ПО), в тот или иной момент времени возникал вопрос «фактора автобуса» в управлении разработкой проектов.

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

В разработке ПО можно провести множество параллелей, но по природе нашей работы поставка выпущенного кода — это единственный способ измерения фактора автобуса. По крайней мере, именно её изучали многие исследователи, в том числе и в научной статье, имеющей большое количество цитирований (156, согласно Google Scholar!) с момента её публикации в 2016 году (препринт выпустили в 2015 году). Ша отправил мне статью, а после того, как мы обнаружили её исходные данные и исходный код, это стало идеальным проектом на выходные, который бы позволил, как минимум, получить представление об интересных метриках open source.

Читать далее

Разбор регулярного выражения, проверяющего простоту чисел

Level of difficultyEasy
Reading time16 min
Views11K

Как-то я исследовал способы наиболее эффективного определения простоты числа и наткнулся на показанный выше код.

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

Если вы заинтересовались, продолжайте чтение, я проанализирую это регулярное выражение и объясню, что же в нём происходит. Объяснение не зависит от языка программирования, однако я приведу версии показанного выше Java-кода на PythonJavaScript и Perl  и объясню, почему они немного различаются.

Я объясню, как регулярное выражение ^.?$|^(..+?)\1+$ способно отфильтровывать все простые числа. Почему это выражение, а не .?|(..+?)\1+ (использованное в примере кода на Java)? Это связано с тем, как работает String.matches(), о чём я расскажу ниже.

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

Читать далее

Оптимизируем использование памяти для поиска IP-адресов

Level of difficultyMedium
Reading time9 min
Views3.1K

Около трёх лет у меня возникали проблемы с моим обучающим сайтом Mess With DNS: периодически у него заканчивалась память и он перезагружался по OOM.

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

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

Читать далее

Когда есть разница регистров, но это не верхний и не нижний регистры?

Level of difficultyEasy
Reading time2 min
Views7.1K

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

У-у-у-у, загадочно и пугающе.

Иными словами, это символ c, обладающий следующими свойствами:

toUpper(c) ≠ toLower(c), однако

c ≠ toUpper(c) и c ≠ toLower(c).

Поздравляю, вы обнаружили таинственный третий регистр: Title case.

Читать далее

Я прождал 10 миллиардов тактов и дождался лишь экрана загрузки

Level of difficultyEasy
Reading time7 min
Views17K

Современное оборудование невероятно быстрое. M1 Max, на котором я пишу эту статью, работает с частотой 3,2 ГГц. То есть 3,2 МИЛЛИАРДА тактов в секунду. Однако Microsoft Teams требуется 3 секунды, чтобы открыть ссылку, и я отказываюсь верить, что для открытия ссылки требуется 9,6 МИЛЛИАРДА тактов. Очевидно, я упрощаю, но смысл остаётся прежним: как так получается, что оборудование становится быстрее, а приложения — только медленнее?

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

Превосходный пример мощи современного «железа» — это видеоигры. Я могу симулировать огромные 3D-среды с физикой и освещением, полученным трассировкой лучей, при этом играть в реальном времени с друзьями из других штатов и даже стран; вполне доступный компьютер потребительского уровня выдаёт 124 миллионов пикселей в секунду1.

[1. 1080p при 60 FPS = 1920 × 1080 × 60 = 124416000]

Можно посмотреть и в обратном направлении: людям удаётся запускать DOOM на почти любом устройстве с процессором: на калькуляторах, iPod, фотокамерах. Невероятно маломощные, зачастую одноразовые устройства обладают достаточными вычислительными ресурсами, чтобы выполнять сверхсовременную на 1993 год игру. Это не особо удивляет, ведь прошло три десятка лет, но показывает, какой путь мы проделали.

Читать далее

Как мы нашли уязвимость в SQLite при помощи LLM

Level of difficultyMedium
Reading time9 min
Views7.1K

В нашем предыдущем посте Project Naptime: Evaluating Offensive Security Capabilities of Large Language Models мы рассказали о фреймворке для исследований уязвимостей при помощи языковых моделей и продемонстрировали его потенциал, усовершенствовав показатели современных бенчмарков CyberSecEval2 компании Meta. С тех пор Naptime эволюционировал в Big Sleep — совместный проект Google Project Zero и Google DeepMind.

Сегодня мы с радостью готовы поделиться первой уязвимостью из реального мира. обнаруженной агентом Big Sleep: отрицательным переполнением (underflow) буфера стека с возможностью реализации эксплойтов в SQLite, — широко используемом опенсорсном движке баз данных. Мы обнаружили уязвимость и сообщили о ней разработчикам в начале октября, и они устранили её в тот же день. К счастью, мы обнаружили эту проблему до её появления в официальном релизе, так что она не затронула пользователей SQLite.

Мы считаем, что это первый публичный пример обнаружения ИИ-агентом ранее неизвестной уязвимости безопасности по памяти в широко используемом реальном ПО. В этом же году на мероприятии DARPA AIxCC команда Team Atlanta обнаружила разыменование нулевого указателя в SQLite, что вдохновило нас использовать его в нашем тестировании, чтобы проверить, сможем ли мы найти более серьёзную уязвимость.

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

Сама уязвимость довольно любопытна, к тому же существующая инфраструктура тестирования SQLite (и через OSS-Fuzz, и через собственную инфраструктуру проекта) не обнаружила проблему, так что мы провели дополнительное исследование.

Читать далее

Как устроены тени в старых 3D-играх

Level of difficultyEasy
Reading time10 min
Views13K

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

Бизнесмен: Тени. Становятся ли они темнее, когда накладываются друг на друга?
Хираяма: Не знаю.
Бизнесмен: Я не знаю ещё очень многого... Именно так заканчивается жизнь... Наверно.
Хираяма: Давайте узнаем прямо сейчас.
Бизнесмен: Что?

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

Хотя Бизнесмен и не видит разницы, Хираяма уверен, что пересекающиеся тени действительно становятся темнее. «Они должны становиться темнее, это логично». Очень сильная сцена.

К сожалению, Хираяма ошибается. Тени не становились темнее. Источник света всего один, и он довольно далеко, поэтому тень — это просто отсутствие света. Не важно, сколько раз перекрыт источник света.

В 3D-видеоиграх же тени — это нечто совсем иное. Очень легко нарисовать тёмное пятно под ногами персонажа и предполагать, что всё остальное освещено. Возможно, Хираяма вспоминал тень-пятно из Metal Gear Solid, которая становится темнее, когда накладывается на другие?

Читать далее

Неформатированный текст не так уж прост

Level of difficultyEasy
Reading time7 min
Views2K

Когда мы взаимодействуем с текстовым файлом при помощи редактора, то, что мы видим, не всегда отражает содержимое файла. Да, содержимое файла с неформатированным текстом — это байтовые коды, закодированные в таких форматах, как ASCII, UTF8 и UTF16, и в этих байтовых кодах находится источник истины. Но в конечном итоге, именно текстовый редактор выбирает, как интерпретировать и отображать пользователю источник истины (двоичные коды). Это значит, что два файла могут выглядеть одинаково или один и тот же файл может выглядеть по-разному в зависимости от редактора.

Текстовый редактор может подсвечивать (или нет) отдельные части на основании распознанного им синтаксиса, может управлять отображением табов (2 пробела, 4 пробела или даже 8). Он решает, как кодировать нажатие клавиши Tab, например, как \t или как заданное количество пробелов. То же относится и к нажатию на клавишу Enter для создания новой строки — будет ли она кодироваться как \n (UNIX) или \r\n (Windows), зависит от конфигурации редактора.

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

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

Читать далее

Детекторы ИИ ошибаются, и это сильно бьёт по студентам

Level of difficultyEasy
Reading time9 min
Views5.3K

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

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

Для 24-летней Олмстед это обвинение стало огромным ударом. Кроме того, оно угрожало её дальнейшей учёбе в университете. «Я была потрясена, ведь у меня могли забрать плоды моих трудов за то, чего я не делала», — рассказывает она.

Читать далее

Полное руководство по обработке ошибок в Python

Reading time15 min
Views21K

Я часто сталкиваюсь с разработчиками, очень хорошо знающими механику обработки ошибок в Python, однако когда я начинаю выполнять ревью их кода, он оказывается далеко неидеальным. Исключения в Python — это одна из тех областей, поверхностный уровень которого знает большинство, но многие разработчики даже не догадываются о существовании более глубокого, почти тайного уровня. Если вы хотите протестировать себя по этой теме, то проверьте, сможете ли вы ответить на следующие вопросы:

  • Когда следует перехватывать исключения, генерируемые вызываемыми вами функциями, а когда этого делать не нужно?
  • Как узнать, какие классы исключений нужно перехватывать?
  • Что нужно делать при перехвате исключений для их «обработки»?
  • Почему перехватывание всех исключений считается порочной практикой, и когда делать это приемлемо?

Вы готовы узнать секреты обработки ошибок в Python? Тогда поехали!
Читать дальше →

Information

Rating
Does not participate
Location
Россия
Registered
Activity