[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"technologies":3,"\u002Fopen-source\u002Fdxpdf":167,"glossary":1438},[4,10,15,21,26,32,38,43,48,53,58,63,68,73,77,82,87,92,97,103,108,113,118,123,128,133,138,143,147,152,157,162],{"title":5,"description":6,"slug":7,"category":8,"icon":9},"Android","Каждое наше приложение выходит и на Android — платформенные API, фоновое выполнение, разрешения и требования магазина вместе с ними.","android","framework","logos:android-icon",{"title":11,"description":12,"slug":13,"category":8,"icon":14},"Angular","Фронтенд-фреймворк, в котором мы работаем, когда продукт уже на Angular, — строгая структура, подходящая большим долгоживущим приложениям.","angular","logos:angular-icon",{"title":16,"description":17,"slug":18,"category":19,"icon":20},"Dart","Язык, на котором написано каждое наше Flutter-приложение, — строгая null safety, полноценный pattern matching и компиляция в нативный код и веб.","dart","language","logos:dart",{"title":22,"description":23,"slug":24,"category":8,"icon":25},"Django","Python-фреймворк, который мы берём, когда продукту нужны админка, аутентификация и модель данных в первый же день, а не самописный сервис.","django","logos:django-icon",{"title":27,"description":28,"slug":29,"category":30,"icon":31},"Docker","Каждый наш сервис поставляется в виде контейнера, поэтому на ноутбуке, в CI и в продакшене работает один и тот же артефакт, а не три разных.","docker","infrastructure","logos:docker-icon",{"title":33,"description":34,"slug":35,"category":36,"icon":37},"Fastlane","Автоматизация релизов в нашей мобильной разработке — подпись, сборки и загрузка в сторы идут из CI, а не с ноутбука одного инженера в день релиза.","fastlane","tools","logos:fastlane",{"title":39,"description":40,"slug":41,"category":8,"icon":42},"Flutter","Наш основной мобильный стек с 2018 года — одна кодовая база на Dart для iOS, Android, веба и десктопа без отдельной команды под каждую платформу.","flutter","logos:flutter",{"title":44,"description":45,"slug":46,"category":36,"icon":47},"Git","Все проекты, к которым мы прикасаемся, живут в Git — ревью пул-реквестов, CI на каждой ветке и история, понятная и спустя месяцы.","git","logos:git-icon",{"title":49,"description":50,"slug":51,"category":19,"icon":52},"Go","Наш бэкенд-язык для real-time API и сервисов под нагрузкой — маленькие бинарники, быстрая сборка и конкурентность, которая остаётся читаемой.","go","logos:gopher",{"title":54,"description":55,"slug":56,"category":30,"icon":57},"Google Cloud","Облако, в котором работают наши продакшен-нагрузки, — управляемый Kubernetes, хранилище и сеть без серверов, которые надо обслуживать руками.","gcp","logos:google-cloud",{"title":59,"description":60,"slug":61,"category":36,"icon":62},"Gradle","Система сборки, через которую проходит каждый Android-релиз, — флейворы, конфигурации подписи и вся обвязка зависимостей под Flutter-приложением.","gradle","logos:gradle",{"title":64,"description":65,"slug":66,"category":30,"icon":67},"Helm","Так мы упаковываем деплой в Kubernetes — сервис, конфигурация, секреты и ingress как одна версионируемая единица, которую можно выкатить и откатить.","helm","logos:helm",{"title":69,"description":70,"slug":71,"category":19,"icon":72},"Kotlin","То, что мы берём, когда Flutter-приложению нужен настоящий Android под ним, — platform channels, фоновые задачи и интеграции с нативными SDK.","kotlin","logos:kotlin-icon",{"title":74,"description":75,"slug":76,"category":8,"icon":72},"Kotlin Multiplatform","Общая бизнес-логика для iOS и Android, а нативный интерфейс у каждой платформы свой, — альтернатива, когда Flutter не подходит.","kmp",{"title":78,"description":79,"slug":80,"category":30,"icon":81},"Kubernetes","Так мы запускаем сервисы в продакшене — деплой в Helm-чартах, откатываемые выкатки и масштабирование, для которого не нужен человек в три ночи.","kubernetes","logos:kubernetes",{"title":83,"description":84,"slug":85,"category":30,"icon":86},"NATS","Лёгкий обмен сообщениями между сервисами — publish\u002Fsubscribe и request\u002Freply без эксплуатационного веса полноценного кластера брокера.","nats","logos:nats-icon",{"title":88,"description":89,"slug":90,"category":8,"icon":91},"Nuxt","Vue с серверным рендерингом, роутингом и SEO из коробки — так мы делаем сайты и веб-приложения, которые должны быстро грузиться и индексироваться.","nuxt","logos:nuxt-icon",{"title":93,"description":94,"slug":95,"category":19,"icon":96},"PHP","Там, где PHP-бэкенд уже есть: дорабатываем его, интегрируемся с ним и делаем мобильные и веб-клиенты, которые он обслуживает.","php","logos:php",{"title":98,"description":99,"slug":100,"category":101,"icon":102},"PostgreSQL","Наша база данных по умолчанию — от проектирования схемы до настройки индексов мы берём её, если у продукта нет конкретной причины взять другую.","postgres","database","logos:postgresql",{"title":104,"description":105,"slug":106,"category":19,"icon":107},"Python","Наш язык для бэкендов, работы с данными и AI-интеграций — включая Python-биндинги, которые мы выпускаем к собственным инструментам на Rust.","python","logos:python",{"title":109,"description":110,"slug":111,"category":8,"icon":112},"React","Фронтенд-библиотека, в которой мы работаем, когда продукт уже на React, — компоненты, хуки и выросшая вокруг них экосистема.","react","logos:react",{"title":114,"description":115,"slug":116,"category":101,"icon":117},"Redis","Место для данных, которые должны быть быстрыми и которые не жалко пересчитать, — кэши, сессии, лимиты и очереди фоновых задач.","redis","logos:redis",{"title":119,"description":120,"slug":121,"category":19,"icon":122},"Ruby","Язык, на котором написана автоматизация наших мобильных релизов, — лейны Fastlane, кастомные действия и связка с CI, доставляющая сборки в сторы.","ruby","logos:ruby",{"title":124,"description":125,"slug":126,"category":19,"icon":127},"Rust","Куда мы идём, когда важны и скорость, и корректность, — рендеринг документов, CLI-инструменты и сервисы, которые обязаны оставаться быстрыми и предсказуемыми.","rust","simple-icons:rust",{"title":129,"description":130,"slug":131,"category":101,"icon":132},"SQLite","База данных, которая поставляется внутри приложения, — локальные кэши, offline-first хранилище и всё, что должно работать без сети.","sqlite","logos:sqlite",{"title":134,"description":135,"slug":136,"category":8,"icon":137},"Strapi","Headless CMS, к которой мы обращаемся, когда контент должны вести сами редакторы, — готовая админка и чистый API вместо самописных.","strapi","logos:strapi-icon",{"title":139,"description":140,"slug":141,"category":19,"icon":142},"Swift","То, что мы берём, когда Flutter-приложению нужен настоящий iOS под ним, — platform channels, интеграции нативных SDK, виджеты и App Clips.","swift","logos:swift",{"title":144,"description":145,"slug":146,"category":8,"icon":142},"SwiftUI","UI-фреймворк Apple, на котором мы делаем нативные поверхности, недоступные Flutter-приложению, — виджеты, App Clips и расширения.","swiftui",{"title":148,"description":149,"slug":150,"category":8,"icon":151},"Tailwind CSS","Так мы стилизуем весь фронтенд — утилитарные классы и дизайн-токены вместо таблицы стилей, которая только растёт и никогда не чистится.","tailwind","logos:tailwindcss-icon",{"title":153,"description":154,"slug":155,"category":19,"icon":156},"TypeScript","Стандарт для всего, что мы пишем для браузера и для Node-сервисов, — типы ловят ошибки интеграции раньше, чем код доходит до ревью.","typescript","logos:typescript-icon",{"title":158,"description":159,"slug":160,"category":8,"icon":161},"Vue","Наш фронтенд-фреймворк для админок, дашбордов мерчантов и веб-приложений, которые должны оставаться поддерживаемыми годами, а не спринтами.","vue","logos:vue",{"title":163,"description":164,"slug":165,"category":36,"icon":166},"Whisper","Открытая модель распознавания речи от OpenAI — движок транскрипции для голосового ввода, который работает и как бэкенд-сервис, и прямо на устройстве в приложении.","whisper","simple-icons:openai",{"id":168,"title":169,"body":170,"description":1390,"extension":1391,"links":1392,"meta":1399,"metaDescription":1400,"metaTitle":1401,"navigation":635,"ogDescription":1402,"path":1403,"repository":1404,"seo":1407,"slug":169,"stem":1408,"technologies":1409,"updated":1410,"__hash__":1411,"stats":1412},"open_source_ru\u002Fopen-source\u002Fdxpdf.md","dxpdf",{"type":171,"value":172,"toc":1371},"minimark",[173,178,187,190,213,221,225,235,242,252,278,293,297,312,409,413,418,421,459,463,466,593,596,883,887,890,904,943,946,950,957,972,1109,1116,1137,1141,1150,1252,1258,1261,1265,1269,1275,1279,1282,1286,1289,1293,1296,1303,1307,1314,1355,1363,1367],[174,175,177],"h2",{"id":176},"проблема","Проблема",[179,180,181,182,186],"p",{},"Конвертация документов Word в PDF — одна из самых распространённых задач в бизнес-софте. Счета, договоры, отчёты, регуляторные формы — они начинаются как ",[183,184,185],"code",{},".docx","-файлы и должны стать PDF для обмена, архивирования или печати.",[179,188,189],{},"Каждое существующее решение требует серьёзных компромиссов:",[191,192,193,201,207],"ul",{},[194,195,196,200],"li",{},[197,198,199],"strong",{},"Microsoft Office \u002F LibreOffice"," — требует установки полного офисного пакета на каждый сервер. Headless-режим LibreOffice медленный, потребляет много памяти и выдаёт разный результат от версии к версии. Масштабирование означает запуск нескольких экземпляров, потребляющих гигабайты оперативной памяти.",[194,202,203,206],{},[197,204,205],{},"Облачные API"," (Google Docs, Adobe, CloudConvert) — добавляют задержку, берут плату за каждую конвертацию и отправляют потенциально конфиденциальные документы на сторонние серверы. Неприемлемо для регулируемых отраслей или изолированных сред.",[194,208,209,212],{},[197,210,211],{},"Инструменты HTML-to-PDF"," (wkhtmltopdf, Puppeteer) — требуют предварительного преобразования DOCX в HTML с потерей точности форматирования. Таблицы, колонтитулы и разрывы страниц редко переживают такую цепочку преобразований.",[179,214,215,216,220],{},"Ни одно из этих решений не подходит, когда нужна быстрая и точная офлайн-конвертация в больших объёмах — особенно в автоматизированных пайплайнах, ",[217,218],"term",{"slug":219},"ci-cd","-системах или встраиваемых приложениях, где установка LibreOffice невозможна.",[174,222,224],{"id":223},"как-dxpdf-решает-эту-задачу","Как dxpdf решает эту задачу",[179,226,227,228,231,232,234],{},"dxpdf — это автономный конвертер DOCX в PDF, написанный на Rust и использующий графическую библиотеку Google ",[217,229],{"slug":230},"skia",". Он читает ",[183,233,185],{},"-файлы напрямую, парсит OOXML-структуру и рендерит PDF с пиксельной точностью — всё в одном бинарнике без внешних зависимостей, кроме Skia.",[179,236,237,238,241],{},"Модель ",[197,239,240],{},"сначала измерить, потом разместить",", заимствованная у Flutter, следит за тем, чтобы перенос текста, размеры таблиц и разрывы страниц совпадали с тем, что делает Microsoft Word:",[243,244,249],"pre",{"className":245,"code":247,"language":248},[246],"language-text","DOCX (ZIP) → Parse → Document Model → Resolve → Layout → Subset → Paint → PDF\n             Twips\u002FEmu\u002FHalfPoints        ←──── Pt throughout ────→      Skia\n","text",[183,250,247],{"__ignoreMap":251},"",[179,253,254,255,258,259,258,262,265,266,269,270,273,274,277],{},"Через весь пайплайн проходят типобезопасные единицы измерения: единицы OOXML (",[183,256,257],{},"Twips",", ",[183,260,261],{},"Emu",[183,263,264],{},"HalfPoints",") в разобранной модели хранятся как ",[183,267,268],{},"i64"," и потому переводятся туда-обратно без потерь, вёрстка работает в типографских пунктах (",[183,271,272],{},"Pt","), а голый ",[183,275,276],{},"f32"," появляется только на границе с рендерингом в Skia — так что смешение единиц становится ошибкой компиляции, а не документом с едва заметной ошибкой.",[179,279,280,281,284,285,288,289,292],{},"Результат — конвертер, который превращает 3-страничный документ с таблицами и изображениями в PDF за ",[197,282,283],{},"170 мс",", потребляя ",[197,286,287],{},"54 МБ памяти",", а документ на 171 страницу и 14 МБ — за ",[197,290,291],{},"420 мс",": достаточно быстро для запуска внутри обработчика запросов или пакетной обработки тысяч документов.",[174,294,296],{"id":295},"возможности","Возможности",[179,298,299,300,303,304,311],{},"Проверено по ISO 29500 (Office Open XML): ",[197,301,302],{},"75 позиций реализованы полностью, 12 — частично, 11 пока не поддерживаются"," — ",[305,306,310],"a",{"href":307,"rel":308},"https:\u002F\u002Fgithub.com\u002Fnerdy-pro\u002Fdxpdf#ooxml-feature-coverage",[309],"nofollow","полная матрица"," перечисляет каждую позицию со статусом. Главное:",[191,313,314,320,326,332,338,344,354,360,366,372,378,388,394,403],{},[194,315,316,319],{},[197,317,318],{},"Форматирование текста"," — жирный, курсив, подчёркивание, выделение цветом, размер шрифта, гарнитура, цвет, межсимвольный интервал, масштабирование символов, надстрочный и подстрочный текст, заливка и границы символов",[194,321,322,325],{},[197,323,324],{},"Абзацы"," — выравнивание (по левому краю, по центру, по правому краю, по ширине, распределённое), интервалы, отступы, табуляция (в том числе десятичная, с чертой и с абсолютной позицией), границы, заливка, «не отрывать от следующего», «не разрывать абзац», контроль висячих строк",[194,327,328,331],{},[197,329,330],{},"Таблицы"," — ширина столбцов, отступы ячеек с 3-уровневым каскадированием, объединённые ячейки, высота строк, границы, заливка ячеек, стили таблиц с условным форматированием, вложенные и плавающие таблицы, разрыв строк между страницами",[194,333,334,337],{},[197,335,336],{},"Изображения"," — встроенные (PNG, JPEG, GIF, BMP, WebP) и плавающие\u002Fпривязанные с выравниванием, обтеканием, кадрированием и процентным позиционированием",[194,339,340,343],{},[197,341,342],{},"Фигуры и надписи"," — фигуры DrawingML и VML, текстовые блоки фигур с внутренними полями, привязкой, автоподбором и произвольной геометрией",[194,345,346,349,350,353],{},[197,347,348],{},"Стили"," — стили абзацев и символов с наследованием ",[183,351,352],{},"basedOn",", настройки документа по умолчанию, шрифты темы",[194,355,356,359],{},[197,357,358],{},"Колонтитулы"," — текст, изображения, номера страниц (коды полей PAGE\u002FNUMPAGES), варианты для первой страницы и чётных\u002Fнечётных",[194,361,362,365],{},[197,363,364],{},"Списки"," — многоуровневая нумерация: маркеры, десятичные, буквенные, римские, порядковые и прописью, а также нелатинские последовательности и графические маркеры",[194,367,368,371],{},[197,369,370],{},"Навигация"," — кликабельные аннотации ссылок, закладки и перекрёстные ссылки как именованные назначения, оглавление PDF по уровням заголовков",[194,373,374,377],{},[197,375,376],{},"Разделы"," — несколько размеров страниц и полей, разрывы разделов, многоколоночная вёрстка, книжная и альбомная ориентация",[194,379,380,383,384,387],{},[197,381,382],{},"Формулы"," — встроенная математика OMML (",[183,385,386],{},"m:oMath","): математические раны, верхние индексы и дроби, набираемые математическим шрифтом Word по умолчанию; формула может нести ссылку и попадать в заголовок оглавления",[194,389,390,393],{},[197,391,392],{},"Вёрстка"," — автоматическая пагинация, сноски и концевые сноски, перенос слов, режимы межстрочного интервала, обтекание плавающих изображений",[194,395,396,399,400],{},[197,397,398],{},"Интернационализация"," — переносы по UAX #14 (включая тайский, лаосский, кхмерский и бирманский), двунаправленный текст по UAX #9 с зеркалированием, шейпинг через HarfBuzz для письменностей с курсивным соединением, а также десятичные разделители, маски дат и числительные прописью по атрибуту ",[183,401,402],{},"w:lang",[194,404,405,408],{},[197,406,407],{},"Текст и эмодзи"," — сегментация по графемным кластерам и полноцветные эмодзи, включая последовательности ZWJ, модификаторы, клавиши и флаги",[174,410,412],{"id":411},"четыре-способа-использования","Четыре способа использования",[414,415,417],"h3",{"id":416},"инструмент-командной-строки","Инструмент командной строки",[179,419,420],{},"Установите и запустите одной командой:",[243,422,426],{"className":423,"code":424,"language":425,"meta":251,"style":251},"language-shell shiki shiki-themes material-theme-lighter github-light github-dark","cargo install dxpdf\ndxpdf input.docx -o output.pdf\n","shell",[183,427,428,444],{"__ignoreMap":251},[429,430,433,437,441],"span",{"class":431,"line":432},"line",1,[429,434,436],{"class":435},"sbgvK","cargo",[429,438,440],{"class":439},"s_sjI"," install",[429,442,443],{"class":439}," dxpdf\n",[429,445,447,449,452,456],{"class":431,"line":446},2,[429,448,169],{"class":435},[429,450,451],{"class":439}," input.docx",[429,453,455],{"class":454},"stzsN"," -o",[429,457,458],{"class":439}," output.pdf\n",[414,460,462],{"id":461},"rust-библиотека","Rust-библиотека",[179,464,465],{},"Один вызов функции — байты на вход, байты на выход:",[243,467,470],{"className":468,"code":469,"language":126,"meta":251,"style":251},"language-rust shiki shiki-themes material-theme-lighter github-light github-dark","let docx_bytes = std::fs::read(\"document.docx\")?;\nlet pdf_bytes = dxpdf::convert(&docx_bytes)?;\nstd::fs::write(\"output.pdf\", &pdf_bytes)?;\n",[183,471,472,523,554],{"__ignoreMap":251},[429,473,474,478,482,486,489,492,495,497,501,505,509,512,514,517,520],{"class":431,"line":432},[429,475,477],{"class":476},"sbsja","let",[429,479,481],{"class":480},"su5hD"," docx_bytes ",[429,483,485],{"class":484},"smGrS","=",[429,487,488],{"class":435}," std",[429,490,491],{"class":484},"::",[429,493,494],{"class":435},"fs",[429,496,491],{"class":484},[429,498,500],{"class":499},"sGLFI","read",[429,502,504],{"class":503},"sP7_E","(",[429,506,508],{"class":507},"sjJ54","\"",[429,510,511],{"class":439},"document.docx",[429,513,508],{"class":507},[429,515,516],{"class":503},")",[429,518,519],{"class":484},"?",[429,521,522],{"class":503},";\n",[429,524,525,527,530,532,535,537,540,542,545,548,550,552],{"class":431,"line":446},[429,526,477],{"class":476},[429,528,529],{"class":480}," pdf_bytes ",[429,531,485],{"class":484},[429,533,534],{"class":435}," dxpdf",[429,536,491],{"class":484},[429,538,539],{"class":499},"convert",[429,541,504],{"class":503},[429,543,544],{"class":484},"&",[429,546,547],{"class":480},"docx_bytes",[429,549,516],{"class":503},[429,551,519],{"class":484},[429,553,522],{"class":503},[429,555,557,560,562,564,566,569,571,573,576,578,581,584,587,589,591],{"class":431,"line":556},3,[429,558,559],{"class":435},"std",[429,561,491],{"class":484},[429,563,494],{"class":435},[429,565,491],{"class":484},[429,567,568],{"class":499},"write",[429,570,504],{"class":503},[429,572,508],{"class":507},[429,574,575],{"class":439},"output.pdf",[429,577,508],{"class":507},[429,579,580],{"class":503},",",[429,582,583],{"class":484}," &",[429,585,586],{"class":480},"pdf_bytes",[429,588,516],{"class":503},[429,590,519],{"class":484},[429,592,522],{"class":503},[179,594,595],{},"Для большего контроля можно просмотреть модель документа перед рендерингом:",[243,597,599],{"className":468,"code":598,"language":126,"meta":251,"style":251},"use dxpdf::{docx, model, render};\n\nlet document = docx::parse(&std::fs::read(\"document.docx\")?)?;\n\nfor block in &document.body {\n    match block {\n        model::Block::Paragraph(p) => { \u002F* разбор абзаца *\u002F }\n        model::Block::Table(t) => { \u002F* разбор таблицы *\u002F }\n        model::Block::SectionBreak(props) => { \u002F* разбор свойств секции *\u002F }\n    }\n}\n\nlet pdf_bytes = render::render(document, &dxpdf::RenderOptions::default())?;\n",[183,600,601,631,637,686,691,718,728,763,793,823,829,835,840],{"__ignoreMap":251},[429,602,603,607,609,611,614,618,620,623,625,628],{"class":431,"line":432},[429,604,606],{"class":605},"sw1J6","use",[429,608,534],{"class":435},[429,610,491],{"class":484},[429,612,613],{"class":503},"{",[429,615,617],{"class":616},"s3--O","docx",[429,619,580],{"class":503},[429,621,622],{"class":616}," model",[429,624,580],{"class":503},[429,626,627],{"class":616}," render",[429,629,630],{"class":503},"};\n",[429,632,633],{"class":431,"line":446},[429,634,636],{"emptyLinePlaceholder":635},true,"\n",[429,638,639,641,644,646,649,651,654,656,658,660,662,664,666,668,670,672,674,676,678,680,682,684],{"class":431,"line":556},[429,640,477],{"class":476},[429,642,643],{"class":480}," document ",[429,645,485],{"class":484},[429,647,648],{"class":435}," docx",[429,650,491],{"class":484},[429,652,653],{"class":499},"parse",[429,655,504],{"class":503},[429,657,544],{"class":484},[429,659,559],{"class":435},[429,661,491],{"class":484},[429,663,494],{"class":435},[429,665,491],{"class":484},[429,667,500],{"class":499},[429,669,504],{"class":503},[429,671,508],{"class":507},[429,673,511],{"class":439},[429,675,508],{"class":507},[429,677,516],{"class":503},[429,679,519],{"class":484},[429,681,516],{"class":503},[429,683,519],{"class":484},[429,685,522],{"class":503},[429,687,689],{"class":431,"line":688},4,[429,690,636],{"emptyLinePlaceholder":635},[429,692,694,698,701,704,706,709,712,715],{"class":431,"line":693},5,[429,695,697],{"class":696},"sVHd0","for",[429,699,700],{"class":480}," block ",[429,702,703],{"class":605},"in",[429,705,583],{"class":484},[429,707,708],{"class":480},"document",[429,710,711],{"class":484},".",[429,713,714],{"class":480},"body ",[429,716,717],{"class":503},"{\n",[429,719,721,724,726],{"class":431,"line":720},6,[429,722,723],{"class":696},"    match",[429,725,700],{"class":480},[429,727,717],{"class":503},[429,729,731,734,736,739,741,744,746,748,750,753,756,760],{"class":431,"line":730},7,[429,732,733],{"class":435},"        model",[429,735,491],{"class":484},[429,737,738],{"class":435},"Block",[429,740,491],{"class":484},[429,742,743],{"class":499},"Paragraph",[429,745,504],{"class":503},[429,747,179],{"class":480},[429,749,516],{"class":503},[429,751,752],{"class":484}," =>",[429,754,755],{"class":503}," {",[429,757,759],{"class":758},"sutJx"," \u002F* разбор абзаца *\u002F",[429,761,762],{"class":503}," }\n",[429,764,766,768,770,772,774,777,779,782,784,786,788,791],{"class":431,"line":765},8,[429,767,733],{"class":435},[429,769,491],{"class":484},[429,771,738],{"class":435},[429,773,491],{"class":484},[429,775,776],{"class":499},"Table",[429,778,504],{"class":503},[429,780,781],{"class":480},"t",[429,783,516],{"class":503},[429,785,752],{"class":484},[429,787,755],{"class":503},[429,789,790],{"class":758}," \u002F* разбор таблицы *\u002F",[429,792,762],{"class":503},[429,794,796,798,800,802,804,807,809,812,814,816,818,821],{"class":431,"line":795},9,[429,797,733],{"class":435},[429,799,491],{"class":484},[429,801,738],{"class":435},[429,803,491],{"class":484},[429,805,806],{"class":499},"SectionBreak",[429,808,504],{"class":503},[429,810,811],{"class":480},"props",[429,813,516],{"class":503},[429,815,752],{"class":484},[429,817,755],{"class":503},[429,819,820],{"class":758}," \u002F* разбор свойств секции *\u002F",[429,822,762],{"class":503},[429,824,826],{"class":431,"line":825},10,[429,827,828],{"class":503},"    }\n",[429,830,832],{"class":431,"line":831},11,[429,833,834],{"class":503},"}\n",[429,836,838],{"class":431,"line":837},12,[429,839,636],{"emptyLinePlaceholder":635},[429,841,843,845,847,849,851,853,856,858,860,862,864,866,868,871,873,876,879,881],{"class":431,"line":842},13,[429,844,477],{"class":476},[429,846,529],{"class":480},[429,848,485],{"class":484},[429,850,627],{"class":435},[429,852,491],{"class":484},[429,854,855],{"class":499},"render",[429,857,504],{"class":503},[429,859,708],{"class":480},[429,861,580],{"class":503},[429,863,583],{"class":484},[429,865,169],{"class":435},[429,867,491],{"class":484},[429,869,870],{"class":435},"RenderOptions",[429,872,491],{"class":484},[429,874,875],{"class":499},"default",[429,877,878],{"class":503},"())",[429,880,519],{"class":484},[429,882,522],{"class":503},[414,884,886],{"id":885},"python-пакет","Python-пакет",[179,888,889],{},"Установите с PyPI и используйте в любом Python-приложении:",[243,891,893],{"className":423,"code":892,"language":425,"meta":251,"style":251},"pip install dxpdf\n",[183,894,895],{"__ignoreMap":251},[429,896,897,900,902],{"class":431,"line":432},[429,898,899],{"class":435},"pip",[429,901,440],{"class":439},[429,903,443],{"class":439},[243,905,908],{"className":906,"code":907,"language":106,"meta":251,"style":251},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import dxpdf\n\n# Байты на вход, байты на выход\npdf_bytes = dxpdf.convert(open(\"input.docx\", \"rb\").read())\n\n# Файл в файл\ndxpdf.convert_file(\"input.docx\", \"output.pdf\")\n",[183,909,910,915,919,924,929,933,938],{"__ignoreMap":251},[429,911,912],{"class":431,"line":432},[429,913,914],{},"import dxpdf\n",[429,916,917],{"class":431,"line":446},[429,918,636],{"emptyLinePlaceholder":635},[429,920,921],{"class":431,"line":556},[429,922,923],{},"# Байты на вход, байты на выход\n",[429,925,926],{"class":431,"line":688},[429,927,928],{},"pdf_bytes = dxpdf.convert(open(\"input.docx\", \"rb\").read())\n",[429,930,931],{"class":431,"line":693},[429,932,636],{"emptyLinePlaceholder":635},[429,934,935],{"class":431,"line":720},[429,936,937],{},"# Файл в файл\n",[429,939,940],{"class":431,"line":730},[429,941,942],{},"dxpdf.convert_file(\"input.docx\", \"output.pdf\")\n",[179,944,945],{},"Начиная с 0.8.1 оба вызова освобождают GIL на время работы Rust-ядра, поэтому пул потоков, конвертирующий несколько документов сразу, действительно выполняет их параллельно, а не выстраивает в очередь на интерпретаторе.",[414,947,949],{"id":948},"go-пакет","Go-пакет",[179,951,952,953,956],{},"Установите через ",[183,954,955],{},"go get"," и вызывайте как любой другой пакет:",[243,958,960],{"className":423,"code":959,"language":425,"meta":251,"style":251},"go get github.com\u002Fnerdy-pro\u002Fdxpdf\u002Fgo\n",[183,961,962],{"__ignoreMap":251},[429,963,964,966,969],{"class":431,"line":432},[429,965,51],{"class":435},[429,967,968],{"class":439}," get",[429,970,971],{"class":439}," github.com\u002Fnerdy-pro\u002Fdxpdf\u002Fgo\n",[243,973,976],{"className":974,"code":975,"language":51,"meta":251,"style":251},"language-go shiki shiki-themes material-theme-lighter github-light github-dark","import \"github.com\u002Fnerdy-pro\u002Fdxpdf\u002Fgo\"\n\n\u002F\u002F Байты на вход, байты на выход\npdfBytes, err := dxpdf.Convert(docxBytes)\n\n\u002F\u002F Файл в файл\nerr := dxpdf.ConvertFile(\"input.docx\", \"output.pdf\")\n\n\u002F\u002F Переопределить разрешение встроенных изображений (по умолчанию 220 DPI)\npdfBytes, err := dxpdf.ConvertWithOptions(docxBytes, 300)\n",[183,977,978,992,996,1001,1029,1033,1038,1071,1075,1080],{"__ignoreMap":251},[429,979,980,983,986,989],{"class":431,"line":432},[429,981,982],{"class":696},"import",[429,984,985],{"class":507}," \"",[429,987,988],{"class":435},"github.com\u002Fnerdy-pro\u002Fdxpdf\u002Fgo",[429,990,991],{"class":507},"\"\n",[429,993,994],{"class":431,"line":446},[429,995,636],{"emptyLinePlaceholder":635},[429,997,998],{"class":431,"line":556},[429,999,1000],{"class":758},"\u002F\u002F Байты на вход, байты на выход\n",[429,1002,1003,1006,1008,1011,1014,1016,1018,1021,1023,1026],{"class":431,"line":688},[429,1004,1005],{"class":480},"pdfBytes",[429,1007,580],{"class":503},[429,1009,1010],{"class":480}," err ",[429,1012,1013],{"class":484},":=",[429,1015,534],{"class":480},[429,1017,711],{"class":503},[429,1019,1020],{"class":499},"Convert",[429,1022,504],{"class":503},[429,1024,1025],{"class":480},"docxBytes",[429,1027,1028],{"class":503},")\n",[429,1030,1031],{"class":431,"line":693},[429,1032,636],{"emptyLinePlaceholder":635},[429,1034,1035],{"class":431,"line":720},[429,1036,1037],{"class":758},"\u002F\u002F Файл в файл\n",[429,1039,1040,1043,1045,1047,1049,1052,1054,1056,1059,1061,1063,1065,1067,1069],{"class":431,"line":730},[429,1041,1042],{"class":480},"err ",[429,1044,1013],{"class":484},[429,1046,534],{"class":480},[429,1048,711],{"class":503},[429,1050,1051],{"class":499},"ConvertFile",[429,1053,504],{"class":503},[429,1055,508],{"class":507},[429,1057,1058],{"class":439},"input.docx",[429,1060,508],{"class":507},[429,1062,580],{"class":503},[429,1064,985],{"class":507},[429,1066,575],{"class":439},[429,1068,508],{"class":507},[429,1070,1028],{"class":503},[429,1072,1073],{"class":431,"line":765},[429,1074,636],{"emptyLinePlaceholder":635},[429,1076,1077],{"class":431,"line":795},[429,1078,1079],{"class":758},"\u002F\u002F Переопределить разрешение встроенных изображений (по умолчанию 220 DPI)\n",[429,1081,1082,1084,1086,1088,1090,1092,1094,1097,1099,1101,1103,1107],{"class":431,"line":825},[429,1083,1005],{"class":480},[429,1085,580],{"class":503},[429,1087,1010],{"class":480},[429,1089,1013],{"class":484},[429,1091,534],{"class":480},[429,1093,711],{"class":503},[429,1095,1096],{"class":499},"ConvertWithOptions",[429,1098,504],{"class":503},[429,1100,1025],{"class":480},[429,1102,580],{"class":503},[429,1104,1106],{"class":1105},"srdBf"," 300",[429,1108,1028],{"class":503},[179,1110,1111,1112,1115],{},"Go-пакет — это тонкая cgo-прослойка над тем же Rust-ядром, которое используют CLI и Python-пакет, поэтому ему нужны ",[183,1113,1114],{},"CGO_ENABLED=1"," и компилятор C. Собранная библиотека для каждой поддерживаемой платформы закоммичена в репозиторий, так что отдельного шага загрузки или сборки нет. Работает на linux\u002Famd64, linux\u002Farm64, darwin\u002Famd64, darwin\u002Farm64 и — начиная с 0.8.1 — windows\u002Famd64.",[179,1117,1118,1119,1122,1123,1126,1127,1130,1131,258,1133,1136],{},"Windows единственный разворачивается иначе: остальные четыре платформы линкуют статический архив, который полностью попадает в ваш бинарник, а Windows загружает ",[183,1120,1121],{},"dxpdf.dll"," динамически, поэтому собранному исполняемому файлу нужен этот DLL рядом с ним или в ",[183,1124,1125],{},"PATH"," во время выполнения — скопируйте его из кэша модулей в каталог сборки. Кроме того, у модуля нет собственных тегов, поэтому ",[183,1128,1129],{},"go get ...\u002Fgo@v0.8.1"," не разрешится; работает обычный ",[183,1132,955],{},[183,1134,1135],{},"@main"," или коммит по SHA.",[174,1138,1140],{"id":1139},"производительность","Производительность",[179,1142,1143,1144,1149],{},"Бенчмарк на Apple M3 Max с ",[305,1145,1148],{"href":1146,"rel":1147},"https:\u002F\u002Fgithub.com\u002Fsharkdp\u002Fhyperfine",[309],"hyperfine"," (30 запусков, 5 прогревочных) на версии 0.5.1, на фикстурах, закоммиченных в репозиторий. Время округлено до 5 мс, а разброс между запусками на обычно загруженной машине — около ±10 мс, поэтому меньшие различия не значимы:",[1151,1152,1153,1175],"table",{},[1154,1155,1156],"thead",{},[1157,1158,1159,1163,1166,1169,1172],"tr",{},[1160,1161,1162],"th",{},"Фикстура",[1160,1164,1165],{},"Страниц",[1160,1167,1168],{},"Вход",[1160,1170,1171],{},"Время конвертации",[1160,1173,1174],{},"Пик RSS",[1176,1177,1178,1197,1215,1234],"tbody",{},[1157,1179,1180,1184,1187,1190,1194],{},[1181,1182,1183],"td",{},"Деловой документ на 3 страницы",[1181,1185,1186],{},"3",[1181,1188,1189],{},"34 КБ",[1181,1191,1192],{},[197,1193,283],{},[1181,1195,1196],{},"54 МБ",[1157,1198,1199,1202,1205,1208,1212],{},[1181,1200,1201],{},"Документ на 7 страниц",[1181,1203,1204],{},"7",[1181,1206,1207],{},"10 КБ",[1181,1209,1210],{},[197,1211,283],{},[1181,1213,1214],{},"51 МБ",[1157,1216,1217,1220,1223,1226,1231],{},[1181,1218,1219],{},"Документ на 9 страниц с изображениями",[1181,1221,1222],{},"9",[1181,1224,1225],{},"1,3 МБ",[1181,1227,1228],{},[197,1229,1230],{},"55 мс",[1181,1232,1233],{},"40 МБ",[1157,1235,1236,1239,1242,1245,1249],{},[1181,1237,1238],{},"Отчёт на 171 страницу",[1181,1240,1241],{},"171",[1181,1243,1244],{},"14 МБ",[1181,1246,1247],{},[197,1248,291],{},[1181,1250,1251],{},"145 МБ",[179,1253,1254,1257],{},[197,1255,1256],{},"Стоимость конвертации определяется тем, как разрешаются шрифты, а не размером документа."," Девятистраничная фикстура несёт в сорок раз больше данных, чем трёхстраничная, и конвертируется втрое быстрее, потому что её шрифты встроены или уже есть в системе: этот путь стоит около 4 мс, а откат к системному индексу метаданных — 120–185 мс, один раз. Для пакетной нагрузки важен не размер документов, а то, указывают ли они шрифты, которые на хосте уже есть.",[179,1259,1260],{},"Корректность конвертации закреплена тестами на фикстурах, включая визуальные регрессионные тесты, сравнивающие отрендеренные PDF с эталонными документами, сгенерированными Word.",[174,1262,1264],{"id":1263},"сценарии-использования","Сценарии использования",[414,1266,1268],{"id":1267},"автоматизированные-пайплайны-документов","Автоматизированные пайплайны документов",[179,1270,1271,1272,1274],{},"CI\u002FCD-системы или пакетные процессоры, генерирующие договоры, счета или отчёты из ",[183,1273,185],{},"-шаблонов. dxpdf запускается как один бинарник — без установки LibreOffice, без Docker-образа с полным десктопным окружением, без платы за каждый документ.",[414,1276,1278],{"id":1277},"регулируемые-среды","Регулируемые среды",[179,1280,1281],{},"Приложения в здравоохранении, юриспруденции и финансах, где документы не могут покидать сеть. dxpdf работает полностью офлайн без внешних вызовов, что делает его подходящим для изолированных и локальных развёртываний.",[414,1283,1285],{"id":1284},"встраиваемые-системы-и-edge-вычисления","Встраиваемые системы и edge-вычисления",[179,1287,1288],{},"IoT-устройства, киоски или лёгкие контейнеры, где установка офисного пакета на 500 МБ нецелесообразна. Потребление памяти dxpdf в десятки мегабайт и субсекундное время конвертации делают его пригодным для сред с ограниченными ресурсами.",[414,1290,1292],{"id":1291},"бэкенды-на-python-и-go","Бэкенды на Python и Go",[179,1294,1295],{},"Сервисы на Django, Flask или FastAPI, которым нужно конвертировать загруженные DOCX-файлы на лету. Python-биндинги оборачивают Rust-ядро через PyO3, обеспечивая нативную производительность без подпроцессов и внешних сервисов.",[179,1297,1298,1299,1302],{},"Go-сервисы получают то же ядро через cgo: хендлер вызывает ",[183,1300,1301],{},"dxpdf.Convert"," напрямую, вместо запуска бинарника или обращения к сайдкару, — конвертация остаётся внутри собственной горутины запроса и его обработки ошибок.",[174,1304,1306],{"id":1305},"о-последнем-релизе","О последнем релизе",[179,1308,1309,1310,1313],{},"Свежая версия — ",[197,1311,1312],{},"0.8.1",". После 0.5.0 вышло четыре релиза, и вместе они добавили ещё один язык и новый класс содержимого:",[191,1315,1316,1338,1344,1350],{},[194,1317,1318,1321,1322,1325,1326,1329,1330,1333,1334,1337],{},[197,1319,1320],{},"0.6.0"," — Go-биндинги поверх нового C ABI, а также исправления в таблицах: внешняя граница таблицы с межклеточными отступами, перенос излишка ",[183,1323,1324],{},"vMerge"," в последнюю строку объединения, зеркалирование вертикальных границ ",[183,1327,1328],{},"inside","\u002F",[183,1331,1332],{},"outside"," по чётности страницы и удаление скрытых ранов ",[183,1335,1336],{},"w:vanish"," из вёрстки вместо их отрисовки.",[194,1339,1340,1343],{},[197,1341,1342],{},"0.7.0"," — рендеринг формул OMML, а вместе с ним исправления наложения колонок при непрерывном разрыве, переноса токенов по правилу LB25 из UAX #14 и таблицы PUA шрифта Symbol. Формулы несут ссылки и попадают в заголовки оглавления.",[194,1345,1346,1349],{},[197,1347,1348],{},"0.8.0"," — доработка математики: согласованная геометрия дробей, верхние индексы над дробью, шрифт номера сноски по шрифту открывающей формулы и исправленная обработка дефиса с нелатинскими цифрами. Плюс чтение универсальных мер по §22.9.2.15 и записей процентов по §22.9.2.9.",[194,1351,1352,1354],{},[197,1353,1312],{}," — к Go-биндингам добавился windows\u002Famd64, а Python-биндинги освобождают GIL на время конвертации.",[179,1356,1357,1358,1362],{},"Подробный разбор 0.5.0 — ",[305,1359,1361],{"href":1360},"\u002Fblog\u002Fdxpdf-0-5-0-release","dxpdf 0.5.0: как мы научили конвертер DOCX читать не только по-английски"," — по-прежнему описывает работу по интернационализации, на которой всё это стоит: переносы строк по UAX #14, двунаправленный текст по UAX #9 и числа и даты из CLDR по языку самого документа.",[1364,1365],"questions",{":items":1366},"[{\"title\":\"Требуется ли dxpdf Microsoft Office или LibreOffice?\",\"text\":\"Нет. dxpdf — это автономный конвертер, который читает DOCX-файлы напрямую и рендерит PDF с помощью графического движка Google Skia. Он не зависит ни от какого офисного пакета.\"},{\"title\":\"Какие языки и платформы поддерживает dxpdf?\",\"text\":\"dxpdf написан на Rust и доступен как CLI-инструмент (через cargo install), Rust-библиотека (через crates.io), Python-пакет (через PyPI) и Go-биндинги (через go get github.com\u002Fnerdy-pro\u002Fdxpdf\u002Fgo). Все четыре работают на macOS, Linux и Windows; Go-биндинги поддерживают linux\u002Famd64, linux\u002Farm64, darwin\u002Famd64, darwin\u002Farm64 и, начиная с 0.8.1, windows\u002Famd64.\"},{\"title\":\"Насколько точна конвертация?\",\"text\":\"dxpdf использует заимствованный у Flutter пайплайн «сначала измерить, потом разместить», спроектированный для пиксельной точности. Соответствие проверено по ISO 29500: 75 позиций реализованы полностью, 12 — частично, 11 пока не поддерживаются. Визуальные регрессионные тесты сравнивают вывод с эталонами, сгенерированными Word.\"},{\"title\":\"Насколько быстр dxpdf?\",\"text\":\"На Apple M3 Max закоммиченные фикстуры конвертируются за 55–170 мс, а документ на 171 страницу и 14 МБ — примерно за 420 мс. Разрешение шрифтов важнее размера документа: встроенные или уже установленные шрифты разрешаются примерно за 4 мс, а откат к системному индексу метаданных стоит 120–185 мс, один раз. Это достаточно быстро для запуска внутри обработчиков веб-запросов.\"},{\"title\":\"Можно ли использовать dxpdf в Python-приложении?\",\"text\":\"Да. Установите через pip install dxpdf. Python-пакет оборачивает Rust-ядро через PyO3, обеспечивая нативную производительность. Используйте dxpdf.convert() для работы с байтами или dxpdf.convert_file() для конвертации файл-в-файл.\"},{\"title\":\"Можно ли использовать dxpdf из Go?\",\"text\":\"Да, начиная с 0.6.0. Выполните go get github.com\u002Fnerdy-pro\u002Fdxpdf\u002Fgo и вызывайте dxpdf.Convert для работы с байтами или dxpdf.ConvertFile для конвертации файл-в-файл; ConvertWithOptions и ConvertFileWithOptions принимают DPI изображений. Это cgo-прослойка над тем же Rust-ядром, поэтому нужны CGO_ENABLED=1 и компилятор C. Поддерживаются linux и macOS на amd64 и arm64, а с 0.8.1 ещё и windows\u002Famd64 — на Windows биндинг загружает dxpdf.dll динамически, так что поставляйте этот DLL вместе с исполняемым файлом. У Go-модуля нет собственных тегов, поэтому фиксируйте версию по SHA коммита, а не по тегу.\"},{\"title\":\"Какие функции DOCX ещё не поддерживаются?\",\"text\":\"Пока не поддерживаются: переупорядочивание индийских письменностей, автоматический перенос по слогам, исправления и комментарии, SmartArt и диаграммы, границы страницы и сетка документа, изображения WMF и SVG, эффекты текста «тень», «контур», «с приподнятым рельефом» и «с утопленным рельефом», узорная заливка ячеек, зеркалирование табуляций и меток нумерации при w:bidi, а также счётные форматы нумерации вроде chineseCounting. Частично поддерживаются: зачёркивание и малые прописные разбираются, но не отрисовываются, большинство стилей границ аппроксимируется сплошной линией, обтекание tight и through использует ограничивающий прямоугольник вместо полигона, из EMF декодируется только одиночный встроенный растр, разрывы разделов even, odd и nextColumn трактуются как nextPage, процентные и автоматические ширины ячеек откатываются к сетке таблицы, а подстановка шрифта для отдельных глифов берёт отсутствующий символ из любой покрывающей его системной гарнитуры, поэтому результат зависит от хоста, и подсказка w:lang пока не передаётся — ханьский текст может получить начертания не того языка.\"}]",[1368,1369,1370],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sw1J6, html code.shiki .sw1J6{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s3--O, html code.shiki .s3--O{--shiki-light:#E2931D;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":251,"searchDepth":446,"depth":446,"links":1372},[1373,1374,1375,1376,1382,1383,1389],{"id":176,"depth":446,"text":177},{"id":223,"depth":446,"text":224},{"id":295,"depth":446,"text":296},{"id":411,"depth":446,"text":412,"children":1377},[1378,1379,1380,1381],{"id":416,"depth":556,"text":417},{"id":461,"depth":556,"text":462},{"id":885,"depth":556,"text":886},{"id":948,"depth":556,"text":949},{"id":1139,"depth":446,"text":1140},{"id":1263,"depth":446,"text":1264,"children":1384},[1385,1386,1387,1388],{"id":1267,"depth":556,"text":1268},{"id":1277,"depth":556,"text":1278},{"id":1284,"depth":556,"text":1285},{"id":1291,"depth":556,"text":1292},{"id":1305,"depth":446,"text":1306},"Быстрый автономный конвертер DOCX в PDF, написанный на Rust и использующий Skia — без Microsoft Office, LibreOffice или облачных API. Доступен как CLI-инструмент, Rust-библиотека, Python-пакет и Go-биндинги.","md",[1393,1396],{"type":1394,"url":1395},"crates_io","https:\u002F\u002Fcrates.io\u002Fcrates\u002Fdxpdf",{"type":1397,"url":1398},"pypi","https:\u002F\u002Fpypi.org\u002Fproject\u002Fdxpdf\u002F",{},"Быстрый автономный конвертер DOCX в PDF на Rust с использованием Skia — без Office и облачных API. Доступен как CLI, библиотека Rust или Go и пакет Python.",null,"Документы Word в PDF без Office, LibreOffice и облачных API — один бинарник на Rust, который читает OOXML напрямую и рисует через Skia.","\u002Fopen-source\u002Fdxpdf",{"type":1405,"company":1406,"name":169},"github","nerdy-pro",{"title":169,"description":1390},"open-source\u002Fdxpdf",[126,106,51],"2026-09-14","-BzKufMBsbVDsBYTzRBiVvqw4kCfbdZODxOxnqn5cQ4",{"forks":825,"stars":1413,"contributors":1414,"last_release":1433,"issues":1434,"has_contribution_guide":1435,"license":1436,"last_updated":1437,"watchers":1413},39,[1415,1420,1425,1429],{"login":1416,"profile_url":1417,"avatar_url":1418,"contributions":1419},"thenixan","https:\u002F\u002Fgithub.com\u002Fthenixan","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F3602098?v=4",1042,{"login":1421,"profile_url":1422,"avatar_url":1423,"contributions":1424},"markovdigital","https:\u002F\u002Fgithub.com\u002Fmarkovdigital","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F15268617?v=4",29,{"login":1426,"profile_url":1427,"avatar_url":1428,"contributions":837},"ikashapov","https:\u002F\u002Fgithub.com\u002Fikashapov","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F3253046?v=4",{"login":1430,"profile_url":1431,"avatar_url":1432,"contributions":446},"denizsafak","https:\u002F\u002Fgithub.com\u002Fdenizsafak","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F39929354?v=4","v0.8.1",18,false,"MIT","2026-09-17T15:34:19Z",[1439,1453,1466,1481,1494,1509,1525,1538,1551,1568,1581,1592,1602,1615,1627,1637,1646,1660,1673,1680,1694,1709,1722,1735,1748,1759,1770,1781,1794,1804,1817,1829,1843,1854,1868,1877,1888,1901,1914,1927,1940,1952,1964,1976,1988,2000,2011,2025,2036,2048,2059,2072,2084],{"slug":1440,"term":1441,"definition":1442,"category":1443,"aliases":1444,"links":1446,"related":1450,"readMore":-1,"target":1452,"hasArticle":1435},"aosp","AOSP","Android Open Source Project — Android без надстройки Google, который может форкнуть кто угодно. На его форках работают кассовые терминалы, киоски и автомобильные системы, а работа на этом уровне открывает части ОС, которых прикладной разработчик не видит.","platform",[1445],"Android Open Source Project",[1447],{"kind":1448,"url":1449},"website","https:\u002F\u002Fsource.android.com\u002F",[1451],"host-card-emulation","\u002Fglossary#aosp",{"slug":1454,"term":1455,"definition":1456,"category":1443,"aliases":1457,"links":1458,"related":1462,"readMore":-1,"target":1465,"hasArticle":1435},"app-clips","App Clips","Функция Apple, позволяющая запустить небольшую часть iOS-приложения — до 15 МБ — не устанавливая его целиком. Вызывается по QR-коду, NFC-метке или ссылке: для случаев, когда первое действие пользователя не должно требовать похода в App Store.",[],[1459],{"kind":1460,"url":1461},"documentation","https:\u002F\u002Fdeveloper.apple.com\u002Fapp-clips\u002F",[1463,1464],"deep-linking","install-referrer","\u002Fglossary#app-clips",{"slug":1467,"term":1468,"definition":1469,"category":1443,"aliases":1470,"links":1471,"related":1477,"readMore":-1,"target":1480,"hasArticle":1435},"bigquery","BigQuery","Аналитическое хранилище Google Cloud. Вы запускаете SQL по миллиардам строк, и они сканируются за секунды, а данные при этом лежат отдельно от машин, выполняющих запросы. Именно это снимает отчётность и исследование данных с базы, обслуживающей живой трафик.",[],[1472,1474],{"kind":1448,"url":1473},"https:\u002F\u002Fcloud.google.com\u002Fbigquery",{"kind":1475,"url":1476},"wikipedia","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FBigQuery",[1478,1479],"object-storage","elasticsearch","\u002Fglossary#bigquery",{"slug":219,"term":1482,"definition":1483,"category":1484,"aliases":1485,"links":1489,"related":1492,"readMore":-1,"target":1493,"hasArticle":1435},"CI\u002FCD","Автоматизация, которая собирает, тестирует и выкладывает каждое изменение без ручного запуска команд. В мобильной разработке это то, что превращает релиз в нажатие кнопки вместо полудня ожидания, пока освободится нужный человек.","practice",[1486,1487,1488],"CI","непрерывная интеграция","непрерывная поставка",[1490],{"kind":1475,"url":1491},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCI\u002FCD",[],"\u002Fglossary#ci-cd",{"slug":1495,"term":1496,"definition":1497,"category":1498,"aliases":1499,"links":1502,"related":1505,"readMore":-1,"target":1508,"hasArticle":1435},"crud","CRUD","Create, read, update, delete — четыре операции, стоящие почти за каждой формой и админкой. Собирательное название для рутинной половины приложения, которая управляет данными, в отличие от частей с реальной предметной логикой.","architecture",[1500,1501],"Create, Read, Update, Delete","создание, чтение, обновление, удаление",[1503],{"kind":1475,"url":1504},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCreate,_read,_update_and_delete",[1506,1507],"rest","graphql","\u002Fglossary#crud",{"slug":1510,"term":1511,"definition":1512,"category":1484,"aliases":1513,"links":1517,"related":1522,"readMore":-1,"target":1524,"hasArticle":1435},"dev-container","Dev Container","Среда разработки, описанная один раз в devcontainer.json — ОС, инструменты и версии рантаймов, которые нужны проекту, — и открываемая одинаково внутри контейнера в редакторе любого участника, вместо инструкции по установке, которую каждый понимает по-своему.",[1514,1515,1516],"devcontainer.json","Dev Containers","VS Code Dev Containers",[1518,1520],{"kind":1448,"url":1519},"https:\u002F\u002Fcontainers.dev\u002F",{"kind":1460,"url":1521},"https:\u002F\u002Fcode.visualstudio.com\u002Fdocs\u002Fdevcontainers\u002Fcontainers",[1523],"container-registry","\u002Fglossary#dev-container",{"slug":1479,"term":1526,"definition":1527,"category":1443,"aliases":1528,"links":1531,"related":1536,"readMore":-1,"target":1537,"hasArticle":1435},"Elasticsearch","Поисковый и аналитический движок, который индексирует записи, чтобы их можно было интерактивно фильтровать и искать, а не сканировать. К нему обращаются, когда вопрос звучит как «покажи вот эти сессии с шестью фильтрами», а не «просуммируй колонку».",[1529,1530],"Elastic","ELK",[1532,1534],{"kind":1448,"url":1533},"https:\u002F\u002Fwww.elastic.co\u002Felasticsearch",{"kind":1475,"url":1535},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FElasticsearch",[1467],"\u002Fglossary#elasticsearch",{"slug":1539,"term":1540,"definition":1541,"category":1498,"aliases":1542,"links":1545,"related":1546,"readMore":-1,"target":1550,"hasArticle":1435},"fan-out","Fan-out","Чтение источника один раз и доставка каждого обновления всем подписанным на него клиентам. Наивная версия пишет подписчикам в цикле и встаёт, как только один из сокетов начинает тормозить; рабочая — держит отдельный буфер на каждого клиента и отключает тех, кто не успевает.",[1543,1544],"веерная рассылка","фан-аут",[],[1547,1548,1549],"websocket","pub-sub","server-sent-events","\u002Fglossary#fan-out",{"slug":1552,"term":1553,"definition":1554,"category":1484,"aliases":1555,"links":1558,"related":1563,"readMore":-1,"target":1567,"hasArticle":1435},"gdpr","GDPR","Регламент ЕС о персональных данных людей в ЕС: законное основание для сбора, настоящее согласие на трекинг, право увидеть и удалить свои данные. Он следует за вашими пользователями, а не за вашими серверами: где зарегистрирована компания, значения не имеет.",[1556,1557],"Общий регламент по защите данных","General Data Protection Regulation",[1559,1561],{"kind":1448,"url":1560},"https:\u002F\u002Fgdpr.eu\u002F",{"kind":1475,"url":1562},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGeneral_Data_Protection_Regulation",[1564,1565,1566],"pci-dss","soc-2","hipaa","\u002Fglossary#gdpr",{"slug":1569,"term":1570,"definition":1571,"category":1484,"aliases":1572,"links":1576,"related":1579,"readMore":-1,"target":1580,"hasArticle":1435},"golden-test","Golden-тест","Тест, который отрисовывает виджет и сравнивает результат попиксельно с эталонным изображением. Во Flutter это самый дешёвый способ узнать, не сломал ли редизайн пустое состояние на 320pt, в тёмной теме, при 200% масштабе текста.",[1573,1574,1575],"golden test","золотой тест","скриншотный тест",[1577],{"kind":1460,"url":1578},"https:\u002F\u002Fapi.flutter.dev\u002Fflutter\u002Fflutter_test\u002FmatchesGoldenFile.html",[219],"\u002Fglossary#golden-test",{"slug":1507,"term":1582,"definition":1583,"category":1498,"aliases":1584,"links":1585,"related":1590,"readMore":-1,"target":1591,"hasArticle":1435},"GraphQL","Язык запросов к API, где клиент сам перечисляет нужные поля и получает один ответ ровно такой формы. Он снимает избыточную выдачу, к которой дрейфуют REST-эндпоинты, и добавляет собственный режим отказа: неограниченный запрос, обходящий всю модель данных.",[],[1586,1588],{"kind":1448,"url":1587},"https:\u002F\u002Fgraphql.org\u002F",{"kind":1475,"url":1589},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGraphQL",[1506],"\u002Fglossary#graphql",{"slug":1566,"term":1593,"definition":1594,"category":1484,"aliases":1595,"links":1597,"related":1600,"readMore":-1,"target":1601,"hasArticle":1435},"HIPAA","Закон США о защищённой медицинской информации: как её можно хранить, передавать, логировать и раскрывать. Как и PCI-DSS, это архитектурное ограничение, которое выбирают в начале, а не документ, который дописывают перед запуском.",[1596],"Health Insurance Portability and Accountability Act",[1598],{"kind":1475,"url":1599},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHealth_Insurance_Portability_and_Accountability_Act",[1564,1552,1565],"\u002Fglossary#hipaa",{"slug":1603,"term":1604,"definition":1605,"category":1498,"aliases":1606,"links":1609,"related":1612,"readMore":-1,"target":1614,"hasArticle":1435},"headless-cms","Headless CMS","Система управления контентом с админкой и API, но без собственного фронтенда. Редакторы публикуют в одном месте, а сайт или приложение отрисовывает контент само — слой представления принадлежит вам, а не вендору CMS.",[1607,1608],"безголовая CMS","контентное API",[1610],{"kind":1475,"url":1611},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHeadless_content_management_system",[1613,1506],"server-side-rendering","\u002Fglossary#headless-cms",{"slug":1451,"term":1616,"definition":1617,"category":1443,"aliases":1618,"links":1622,"related":1625,"readMore":-1,"target":1626,"hasArticle":1435},"Host Card Emulation","Режим, в котором Android-телефон программно эмулирует бесконтактную карту по NFC, без аппаратного защищённого элемента. Так платит приложение-кошелёк на терминале: телефон говорит с ним по тому же протоколу EMV Contactless, что и пластиковая карта.",[1619,1620,1621],"HCE","EMV Contactless","бесконтактные платежи",[1623],{"kind":1460,"url":1624},"https:\u002F\u002Fdeveloper.android.com\u002Fdevelop\u002Fconnectivity\u002Fnfc\u002Fhce",[1564,1440],"\u002Fglossary#host-card-emulation",{"slug":1628,"term":1629,"definition":1630,"category":1443,"aliases":1631,"links":1632,"related":1635,"readMore":-1,"target":1636,"hasArticle":1435},"impeller","Impeller","Движок рендеринга, на котором Flutter работает сегодня: по умолчанию на iOS с 2023 года и на Android с 2024-го. Он компилирует шейдеры заранее, а не во время первой анимации, что убрало главную видимую проблему Flutter в проде — джанк на компиляции шейдеров.",[],[1633],{"kind":1460,"url":1634},"https:\u002F\u002Fdocs.flutter.dev\u002Fperf\u002Fimpeller",[230],"\u002Fglossary#impeller",{"slug":1464,"term":1638,"definition":1639,"category":1443,"aliases":1640,"links":1641,"related":1644,"readMore":-1,"target":1645,"hasArticle":1435},"Install Referrer","API Google Play, который передаёт только что установленному Android-приложению параметры кампании из ссылки, приведшей к установке. Android-половина отложенного диплинкинга и надёжный способ понять, откуда пришёл пользователь.",[],[1642],{"kind":1460,"url":1643},"https:\u002F\u002Fdeveloper.android.com\u002Fgoogle\u002Fplay\u002Finstallreferrer",[1463,1454],"\u002Fglossary#install-referrer",{"slug":1647,"term":1648,"definition":1649,"category":1650,"aliases":1651,"links":1653,"related":1658,"readMore":-1,"target":1659,"hasArticle":1435},"jwt","JWT","Подписанный токен, несущий свои данные внутри: сервер понимает, кому принадлежит запрос, не обращаясь к хранилищу сессий. Стандарт мобильной аутентификации. Подпись доказывает, что токен не меняли, но не скрывает его содержимое.","protocol",[1652],"JSON Web Token",[1654,1656],{"kind":1448,"url":1655},"https:\u002F\u002Fjwt.io\u002F",{"kind":1475,"url":1657},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FJSON_Web_Token",[1564],"\u002Fglossary#jwt",{"slug":1661,"term":1662,"definition":1663,"category":1484,"aliases":1664,"links":1668,"related":1671,"readMore":-1,"target":1672,"hasArticle":1435},"kyc","KYC","Know Your Customer — проверки личности, которые регулируемый финансовый продукт проводит, прежде чем разрешить переводить деньги: съёмка документов, liveness, санкционный и антиотмывочный скрининг. На онбординг это влияет сильнее любого дизайн-решения.",[1665,1666,1667],"Know Your Customer","AML","KYC\u002FAML",[1669],{"kind":1475,"url":1670},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FKnow_your_customer",[1564,1552],"\u002Fglossary#kyc",{"slug":76,"term":74,"definition":1674,"category":1443,"aliases":1675,"links":1677,"related":1678,"readMore":1679,"target":1679,"hasArticle":1435},"Переиспользование бизнес-логики на Kotlin между Android, iOS и сервером, при этом интерфейс на каждой платформе остаётся нативным. Альтернатива Flutter, когда UI обязан быть нативным, а правила за ним — нет.",[1676],"KMP",[],[],"\u002Ftechnologies\u002Fkmp",{"slug":1681,"term":1682,"definition":1683,"category":1684,"aliases":1685,"links":1688,"related":1691,"readMore":-1,"target":1693,"hasArticle":1435},"mvp","MVP","Минимальная версия продукта, которую можно показать реальным пользователям и которая при этом отвечает на вопрос, ради которого его делали. Решение об объёме, а не о качестве: MVP всё равно обязан работать.","business",[1686,1687],"минимально жизнеспособный продукт","minimum viable product",[1689],{"kind":1475,"url":1690},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMinimum_viable_product",[1692],"white-label","\u002Fglossary#mvp",{"slug":1695,"term":1696,"definition":1697,"category":1650,"aliases":1698,"links":1702,"related":1707,"readMore":-1,"target":1708,"hasArticle":1435},"oauth","OAuth","Стандарт, на котором держатся «Вход через Apple», Google и остальные: пользователь авторизует ваше приложение у провайдера, которому уже доверяет, а приложение получает токен вместо пароля. Никто не заводит новый пароль, и вы его не храните.",[1699,1700,1701],"OAuth 2.0","вход через соцсети","Sign in with Apple",[1703,1705],{"kind":1448,"url":1704},"https:\u002F\u002Foauth.net\u002F2\u002F",{"kind":1475,"url":1706},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FOAuth",[1647],"\u002Fglossary#oauth",{"slug":1564,"term":1710,"definition":1711,"category":1484,"aliases":1712,"links":1715,"related":1720,"readMore":-1,"target":1721,"hasArticle":1435},"PCI-DSS","Стандарт безопасности карточной индустрии, обязательный для всех, кто хранит, обрабатывает или передаёт данные карт. Большинство приложений намеренно остаются вне зоны его действия, отдавая ввод карты сертифицированному платёжному провайдеру.",[1713,1714],"PCI DSS","Payment Card Industry Data Security Standard",[1716,1718],{"kind":1448,"url":1717},"https:\u002F\u002Fwww.pcisecuritystandards.org\u002F",{"kind":1475,"url":1719},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPayment_Card_Industry_Data_Security_Standard",[1647],"\u002Fglossary#pci-dss",{"slug":1723,"term":1724,"definition":1725,"category":1684,"aliases":1726,"links":1729,"related":1732,"readMore":-1,"target":1734,"hasArticle":1435},"product-market-fit","Product-market fit","Момент, когда продукт доказуемо нашёл своих людей: они им пользуются, возвращаются и платят. До него разработка отвечает на вопрос, после — на спрос.",[1727,1728],"PMF","соответствие продукта рынку",[1730],{"kind":1475,"url":1731},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FProduct-market_fit",[1681,1733],"time-to-market","\u002Fglossary#product-market-fit",{"slug":1736,"term":1737,"definition":1738,"category":1484,"aliases":1739,"links":1742,"related":1745,"readMore":-1,"target":1747,"hasArticle":1435},"prompt-injection","Prompt injection","Атака, при которой текст от пользователя языковая модель читает как инструкции, а не как данные, и уходит в обход собственных правил. Родственник SQL-инъекции в эпоху LLM: возникает везде, где пользовательский ввод склеивается в промпт.",[1740,1741],"инъекция промпта","инъекция в промпт",[1743],{"kind":1475,"url":1744},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPrompt_injection",[1746],"rate-limiting","\u002Fglossary#prompt-injection",{"slug":1548,"term":1749,"definition":1750,"category":1498,"aliases":1751,"links":1754,"related":1757,"readMore":-1,"target":1758,"hasArticle":1435},"Pub\u002FSub","Шаблон обмена сообщениями: производитель публикует событие, а любое число потребителей независимо читает его через стоящий между ними брокер. Производитель никогда их не ждёт — так путь запроса остаётся быстрым, а более медленная работа выполняется в фоне.",[1752,1753],"публикация\u002Fподписка","Google Cloud Pub\u002FSub",[1755],{"kind":1475,"url":1756},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPublish%E2%80%93subscribe_pattern",[],"\u002Fglossary#pub-sub",{"slug":1506,"term":1760,"definition":1761,"category":1498,"aliases":1762,"links":1765,"related":1768,"readMore":-1,"target":1769,"hasArticle":1435},"REST","Общепринятый стиль HTTP-API: URL называет ресурс, а HTTP-метод говорит, что с ним сделать. Способ по умолчанию, которым приложение общается с бэкендом, и то, что ожидает найти большинство сторонних интеграций.",[1763,1764],"REST API","Representational State Transfer",[1766],{"kind":1475,"url":1767},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FREST",[1547,1549],"\u002Fglossary#rest",{"slug":1565,"term":1771,"definition":1772,"category":1484,"aliases":1773,"links":1776,"related":1779,"readMore":-1,"target":1780,"hasArticle":1435},"SOC 2","Отчёт внешнего аудитора о том, как компания обращается с данными клиентов — безопасность, доступность, конфиденциальность, — а не сертификат, который можно купить. Корпоративные заказчики его требуют, а архитектуру он ограничивает задолго до самого аудита.",[1774,1775],"SOC2","System and Organization Controls",[1777],{"kind":1475,"url":1778},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSystem_and_Organization_Controls",[1564,1552,1566],"\u002Fglossary#soc-2",{"slug":1782,"term":1783,"definition":1784,"category":1684,"aliases":1785,"links":1788,"related":1791,"readMore":-1,"target":1793,"hasArticle":1435},"saas","SaaS","Софт, который продают как постоянную подписку на размещённый у поставщика продукт, а не как разовую лицензию для установки у себя. Поставщик держит серверы, непрерывно выкатывает обновления и берёт плату за пользователя или за объём.",[1786,1787],"Software as a Service","ПО как услуга",[1789],{"kind":1475,"url":1790},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSoftware_as_a_service",[1792,1692],"multi-tenancy","\u002Fglossary#saas",{"slug":1549,"term":1795,"definition":1796,"category":1650,"aliases":1797,"links":1799,"related":1802,"readMore":-1,"target":1803,"hasArticle":1435},"Server-Sent Events","Односторонний поток от сервера к клиенту поверх обычного HTTP-соединения. Проще, чем WebSocket, и достаточен там, где только серверу есть что сказать: прогресс операции, ответ AI, приходящий токен за токеном.",[1798],"SSE",[1800],{"kind":1475,"url":1801},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FServer-sent_events",[1547,1506],"\u002Fglossary#server-sent-events",{"slug":230,"term":1805,"definition":1806,"category":1443,"aliases":1807,"links":1810,"related":1815,"readMore":-1,"target":1816,"hasArticle":1435},"Skia","Открытая 2D-графическая библиотека Google, которая рисует Chrome, Android и — до появления Impeller — каждый кадр Flutter. Она умеет выводить не только на экран, но и в PDF: именно это делает «печать в PDF» в Chrome.",[1808,1809],"Skia Graphics Engine","skia-safe",[1811,1813],{"kind":1448,"url":1812},"https:\u002F\u002Fskia.org\u002F",{"kind":1475,"url":1814},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSkia_Graphics_Engine",[1628],"\u002Fglossary#skia",{"slug":1818,"term":1819,"definition":1820,"category":1684,"aliases":1821,"links":1825,"related":1826,"readMore":-1,"target":1828,"hasArticle":1435},"staff-augmentation","Staff augmentation","Модель найма, при которой инженеры внешнего партнёра входят в вашу команду и работают под вашим управлением — в вашем репозитории, ваших спринтах, вашем процессе, — а не сдают отдельный проект. Вы покупаете ресурс; код и контекст остаются у вас.",[1822,1823,1824],"аутстаффинг","расширение команды","выделенные разработчики",[],[1827,1733],"total-cost-of-ownership","\u002Fglossary#staff-augmentation",{"slug":1830,"term":1831,"definition":1832,"category":1650,"aliases":1833,"links":1837,"related":1840,"readMore":-1,"target":1842,"hasArticle":1435},"tls","TLS","Слой шифрования под HTTPS. Он подтверждает, что сервер именно тот, о ком говорит его сертификат, согласует свежий ключ на сессию и шифрует всё дальнейшее — сеть между вами видит шифртекст и не может незаметно его изменить.",[1834,1835,1836],"SSL","HTTPS","Transport Layer Security",[1838],{"kind":1475,"url":1839},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FTransport_Layer_Security",[1841,1647],"end-to-end-encryption","\u002Fglossary#tls",{"slug":1733,"term":1844,"definition":1845,"category":1684,"aliases":1846,"links":1849,"related":1852,"readMore":-1,"target":1853,"hasArticle":1435},"Time to market","Время от решения строить продукт до момента, когда им пользуются настоящие люди. Большинство споров о стеке и объёме работ — на самом деле споры об этом числе: каждая сэкономленная неделя — это неделя выручки, обратной связи и позиции на рынке.",[1847,1848],"TTM","время выхода на рынок",[1850],{"kind":1475,"url":1851},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FTime_to_market",[1681,1827],"\u002Fglossary#time-to-market",{"slug":1855,"term":1856,"definition":1857,"category":1650,"aliases":1858,"links":1860,"related":1865,"readMore":-1,"target":1867,"hasArticle":1435},"webrtc","WebRTC","Браузерный и мобильный стандарт для передачи аудио, видео и данных напрямую между двумя устройствами; серверы участвуют только в том, чтобы их познакомить. На нём строят видеозвонок внутри приложения, когда не берут готовый SDK.",[1859],"Web Real-Time Communication",[1861,1863],{"kind":1448,"url":1862},"https:\u002F\u002Fwebrtc.org\u002F",{"kind":1475,"url":1864},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWebRTC",[1866,1547],"xmpp","\u002Fglossary#webrtc",{"slug":1547,"term":1869,"definition":1870,"category":1650,"aliases":1871,"links":1872,"related":1875,"readMore":-1,"target":1876,"hasArticle":1435},"WebSocket","Протокол, который держит одно соединение между клиентом и сервером открытым, чтобы любая сторона могла отправить данные в любой момент, а не клиент спрашивал снова и снова. На нём работают живые котировки, чаты и статусы присутствия.",[],[1873],{"kind":1475,"url":1874},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWebSocket",[1549,1506],"\u002Fglossary#websocket",{"slug":1692,"term":1878,"definition":1879,"category":1684,"aliases":1880,"links":1883,"related":1886,"readMore":1887,"target":1887,"hasArticle":635},"White-label","Один продукт, выпускаемый под многими брендами. White-label платформа собирает каждому клиенту готовое к публикации приложение со своим названием, оформлением и контентом из общей кодовой базы, а не форкает проект под заказчика.",[1881,1882],"белый лейбл","мультитенантное приложение",[1884],{"kind":1475,"url":1885},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWhite-label_product",[1681],"\u002Fglossary\u002Fwhite-label",{"slug":1866,"term":1889,"definition":1890,"category":1650,"aliases":1891,"links":1894,"related":1899,"readMore":-1,"target":1900,"hasArticle":1435},"XMPP","Открытый федеративный протокол обмена сообщениями и давняя альтернатива тому, чтобы писать чат-бэкенд самому или арендовать чужой. Он покрывает статусы присутствия, индикаторы набора и передачу файлов, а зрелые клиентские библиотеки есть под любую платформу.",[1892,1893],"Jabber","Extensible Messaging and Presence Protocol",[1895,1897],{"kind":1448,"url":1896},"https:\u002F\u002Fxmpp.org\u002F",{"kind":1475,"url":1898},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FXMPP",[1855,1547],"\u002Fglossary#xmpp",{"slug":1902,"term":1903,"definition":1904,"category":1684,"aliases":1905,"links":1909,"related":1912,"readMore":-1,"target":1913,"hasArticle":1435},"in-app-purchase","Встроенные покупки","Продажа цифровых товаров и подписок через биллинг Apple и Google, который оба стора требуют для цифрового контента и с которого берут комиссию. Сложность никогда не в самой покупке, а в её восстановлении на новом устройстве и в честном учёте прав доступа.",[1906,1907,1908],"in-app purchase","IAP","внутренние покупки",[1910],{"kind":1460,"url":1911},"https:\u002F\u002Fdeveloper.apple.com\u002Fin-app-purchase\u002F",[1723],"\u002Fglossary#in-app-purchase",{"slug":1463,"term":1915,"definition":1916,"category":1443,"aliases":1917,"links":1922,"related":1925,"readMore":1926,"target":1926,"hasArticle":635},"Диплинкинг","Ссылка, которая открывает конкретный экран внутри установленного приложения, а не его главную или веб-страницу. Отложенный диплинкинг переживает установку: нажатие, прошедшее через магазин приложений, всё равно приводит на нужный экран.",[1918,1919,1920,1921],"deep linking","отложенный диплинкинг","Universal Links","Android App Links",[1923],{"kind":1475,"url":1924},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMobile_deep_linking",[1454,1464],"\u002Fglossary\u002Fdeep-linking",{"slug":1928,"term":1929,"definition":1930,"category":1498,"aliases":1931,"links":1935,"related":1938,"readMore":-1,"target":1939,"hasArticle":1435},"multi-arch-image","Мультиархитектурный образ","Один тег образа, который разрешается в разные бинарники для каждой архитектуры процессора — обычно это пара linux\u002Famd64 и linux\u002Farm64, — так что один и тот же docker pull работает без изменений и на серверах Intel\u002FAMD, и на ноутбуках с Apple Silicon.",[1932,1933,1934],"мультиарх-сборка","multi-arch build","linux\u002Famd64 + linux\u002Farm64",[1936],{"kind":1460,"url":1937},"https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fmulti-platform\u002F",[1523],"\u002Fglossary#multi-arch-image",{"slug":1792,"term":1941,"definition":1942,"category":1498,"aliases":1943,"links":1946,"related":1949,"readMore":-1,"target":1951,"hasArticle":1435},"Мультитенантность","Один развёрнутый бэкенд обслуживает много клиентов, и каждый видит только свои данные, конфигурацию и включённые функции, потому что контекст тенанта определяется для каждого запроса. Именно это делает линейку брендированных приложений одним продуктом, а не набором форков.",[1792,1944,1945],"мультиарендность","тенант",[1947],{"kind":1475,"url":1948},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMultitenancy",[1692,1950],"feature-flags","\u002Fglossary#multi-tenancy",{"slug":1478,"term":1953,"definition":1954,"category":1498,"aliases":1955,"links":1959,"related":1962,"readMore":-1,"target":1963,"hasArticle":1435},"Объектное хранилище","Хранилище, которое держит файл целиком под ключом, а не в дереве файловой системы, — Amazon S3 и множество сервисов, совместимых с его API. Дешёвое, практически безграничное, привычное место для сырых событий, бэкапов и медиа: пишется один раз, читается редко, хранится вечно.",[1956,1957,1958],"S3","S3-совместимое хранилище","блоб-хранилище",[1960],{"kind":1475,"url":1961},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FObject_storage",[1467],"\u002Fglossary#object-storage",{"slug":1746,"term":1965,"definition":1966,"category":1484,"aliases":1967,"links":1971,"related":1974,"readMore":-1,"target":1975,"hasArticle":1435},"Ограничение частоты запросов","Предел на число запросов от одного клиента за заданный интервал. Именно он не даёт одному увлечённому пользователю, скраперу или боту потратить месячный бюджет платного API за вечер, и стоять он должен на вашей стороне интеграции.",[1968,1969,1970],"rate limiting","рейт-лимит","троттлинг",[1972],{"kind":1475,"url":1973},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FRate_limiting",[1736],"\u002Fglossary#rate-limiting",{"slug":1977,"term":1978,"definition":1979,"category":1443,"aliases":1980,"links":1983,"related":1986,"readMore":-1,"target":1987,"hasArticle":1435},"platform-channels","Платформенные каналы","Мост, через который Flutter-приложение вызывает нативный код iOS и Android — Keychain и Keystore, биометрию, платёжные шторки, любой SDK без Dart-пакета. Работа рутинная, но настоящая, и первое место, где споткнётся инженер, не выходивший за пределы Dart.",[1981,1982],"platform channels","method channel",[1984],{"kind":1460,"url":1985},"https:\u002F\u002Fdocs.flutter.dev\u002Fplatform-integration\u002Fplatform-channels",[76],"\u002Fglossary#platform-channels",{"slug":1989,"term":1990,"definition":1991,"category":1650,"aliases":1992,"links":1995,"related":1998,"readMore":-1,"target":1999,"hasArticle":1435},"post-quantum-cryptography","Постквантовая криптография","Алгоритмы шифрования, рассчитанные на устойчивость к будущему квантовому компьютеру; стандарты уже финализированы NIST. Мигрировать нужно до появления железа: трафик, записанный сегодня, расшифруют, когда такая машина появится.",[1993,1994],"PQC","постквантовое шифрование",[1996],{"kind":1475,"url":1997},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPost-quantum_cryptography",[1830,1841],"\u002Fglossary#post-quantum-cryptography",{"slug":2001,"term":2002,"definition":2003,"category":1484,"aliases":2004,"links":2008,"related":2009,"readMore":-1,"target":2010,"hasArticle":1435},"staged-rollout","Поэтапная раскатка","Релиз сначала на небольшой процент пользователей и расширение только тогда, когда доля сессий без падений держится. Плохая сборка, пойманная на десяти процентах, — испорченный вечер; она же на ста процентах — испорченная неделя.",[2005,2006,2007],"staged rollout","phased release","канареечный релиз",[],[1950,219],"\u002Fglossary#staged-rollout",{"slug":1523,"term":2012,"definition":2013,"category":1498,"aliases":2014,"links":2020,"related":2023,"readMore":-1,"target":2024,"hasArticle":1435},"Реестр контейнеров","Хранилище образов контейнеров, адресуемых по имени и тегу, — Docker Hub, GitHub Container Registry или собственный реестр облачного провайдера. Публикация сборки в реестр превращает «у меня работает» в образ, который любой может скачать и запустить без изменений.",[2015,2016,2017,2018,2019],"реестр образов","Docker registry","GHCR","ghcr.io","container registry",[2021],{"kind":1460,"url":2022},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Fpackages\u002Fworking-with-a-github-packages-registry\u002Fworking-with-the-container-registry",[1510,1928],"\u002Fglossary#container-registry",{"slug":1613,"term":2026,"definition":2027,"category":1498,"aliases":2028,"links":2031,"related":2034,"readMore":-1,"target":2035,"hasArticle":1435},"Серверный рендеринг","Сборка страницы в готовый HTML на сервере, чтобы первый же ответ содержал контент, заголовки, метатеги и структурированные данные. Краулеры, превью ссылок и медленные устройства читают это, не выполняя JavaScript.",[2029,2030],"SSR","server-side rendering",[2032],{"kind":1475,"url":2033},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FServer-side_scripting",[1603],"\u002Fglossary#server-side-rendering",{"slug":1841,"term":2037,"definition":2038,"category":1498,"aliases":2039,"links":2043,"related":2046,"readMore":-1,"target":2047,"hasArticle":1435},"Сквозное шифрование","Шифрование, которое накладывается на устройстве отправителя и снимается только на устройстве получателя, так что сервис, передающий сообщение, не может его прочитать — ни по решению суда, ни после взлома. Оно защищает содержимое, но никогда — метаданные.",[2040,2041,2042],"E2EE","end-to-end encryption","оконечное шифрование",[2044],{"kind":1475,"url":2045},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FEnd-to-end_encryption",[1830,1647],"\u002Fglossary#end-to-end-encryption",{"slug":1827,"term":2049,"definition":2050,"category":1684,"aliases":2051,"links":2054,"related":2057,"readMore":-1,"target":2058,"hasArticle":1435},"Совокупная стоимость владения","Во что продукт обходится за всю жизнь, а не только на этапе разработки: поддержка, обновления, ежегодные миграции на новые ОС и правила сторов, вторая команда, чтобы две кодовые базы не расходились. Обычно больше сметы на разработку и почти никогда в неё не входит.",[2052,2053],"TCO","total cost of ownership",[2055],{"kind":1475,"url":2056},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FTotal_cost_of_ownership",[1733],"\u002Fglossary#total-cost-of-ownership",{"slug":2060,"term":2061,"definition":2062,"category":1498,"aliases":2063,"links":2067,"related":2070,"readMore":-1,"target":2071,"hasArticle":1435},"state-management","Управление состоянием","То, как приложение решает, где живёт значение, кому позволено его менять и какие части экрана перерисовываются, когда оно меняется. Во Flutter выбор между Riverpod, BLoC и Provider — одно из первых архитектурных решений и одно из самых трудных для пересмотра.",[2064,2065,2066],"state management","BLoC","Riverpod",[2068],{"kind":1460,"url":2069},"https:\u002F\u002Fdocs.flutter.dev\u002Fdata-and-backend\u002Fstate-mgmt\u002Foptions",[1569],"\u002Fglossary#state-management",{"slug":1950,"term":2073,"definition":2074,"category":1484,"aliases":2075,"links":2079,"related":2082,"readMore":-1,"target":2083,"hasArticle":1435},"Фиче-флаги","Переключатели, которые включают и выключают функциональность из конфигурации, а не из релиза. Один бинарник ведёт себя по-разному для разных брендов, рынков и пользователей, а рискованную фичу можно погасить, не отправляя новую сборку на ревью.",[2076,2077,2078],"feature flags","фиче-флаги","feature toggle",[2080],{"kind":1475,"url":2081},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFeature_toggle",[2001,1692,1792],"\u002Fglossary#feature-flags",{"slug":2085,"term":2086,"definition":2087,"category":1498,"aliases":2088,"links":2092,"related":2095,"readMore":-1,"target":2096,"hasArticle":1435},"floating-point","Числа с плавающей точкой","Двоичный формат IEEE 754, стоящий за double и float. Он не хранит 0.1 точно, поэтому 0.1 + 0.2 даёт 0.30000000000000004 — незаметно в графике и фатально в деньгах, которым место в целых минорных единицах или в decimal-типе.",[2089,2090,2091],"IEEE 754","double","плавающая запятая",[2093],{"kind":1475,"url":2094},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FIEEE_754",[],"\u002Fglossary#floating-point"]